chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:34:48 +08:00
commit 77bb5bf71f
3762 changed files with 353249 additions and 0 deletions
+37
View File
@@ -0,0 +1,37 @@
import * as sdk from '@botpress/sdk'
import * as genenv from './.genenv'
import gsheets from './bp_modules/gsheets'
import telegram from './bp_modules/telegram'
export default new sdk.BotDefinition({
events: {},
recurringEvents: {},
conversation: {
tags: {
downstream: {
title: 'Downstream Conversation ID',
description: 'ID of the downstream conversation binded to the upstream one',
},
upstream: {
title: 'Upstream Conversation ID',
description: 'ID of the upstream conversation binded to the downstream one',
},
},
},
})
.addIntegration(gsheets, {
enabled: true,
configurationType: 'serviceAccountKey',
configuration: {
clientEmail: genenv.SHEETZY_GSHEETS_CLIENT_EMAIL,
privateKey: genenv.SHEETZY_GSHEETS_PRIVATE_KEY,
spreadsheetId: genenv.SHEETZY_GSHEETS_SPREADSHEET_ID,
},
})
.addIntegration(telegram, {
enabled: true,
configuration: {
botToken: genenv.SHEETZY_TELEGRAM_BOT_TOKEN,
typingIndicatorEmoji: true,
},
})
+13
View File
@@ -0,0 +1,13 @@
import rootConfig from '../../eslint.config.mjs'
export default [
...rootConfig,
{
languageOptions: {
parserOptions: {
project: ['./tsconfig.json'],
tsconfigRootDir: import.meta.dirname,
},
},
},
]
+26
View File
@@ -0,0 +1,26 @@
{
"name": "@bp-bots/sheetzy",
"scripts": {
"postinstall": "genenv -o ./.genenv/index.ts -e SHEETZY_TELEGRAM_BOT_TOKEN -e SHEETZY_GSHEETS_CLIENT_EMAIL -e SHEETZY_GSHEETS_PRIVATE_KEY -e SHEETZY_GSHEETS_SPREADSHEET_ID",
"check:type": "tsc --noEmit",
"check:bplint": "bp lint",
"build": "bp add -y && bp build"
},
"private": true,
"dependencies": {
"@botpress/client": "workspace:*",
"@botpress/sdk": "workspace:*"
},
"devDependencies": {
"@botpress/cli": "workspace:*",
"@botpress/common": "workspace:*",
"@botpress/sdk": "workspace:*",
"@botpresshub/gsheets": "workspace:*",
"@botpresshub/telegram": "workspace:*",
"@bpinternal/genenv": "0.0.1"
},
"bpDependencies": {
"telegram": "../../integrations/telegram",
"gsheets": "../../integrations/gsheets"
}
}
+14
View File
@@ -0,0 +1,14 @@
# Sheetzy
## Description
This is a bot that allows you to read and write data to a Google Sheet while chatting on Telegram.
## Usage
1. Create a new bot using the Botpress Dashboard or the Botpress CLI.
2. Install the Telegram and GSheets integrations using the command `bp add telegram && bp add gsheets`.
3. Build the bot using command `bp build`.
4. Deploy the bot using command `bp deploy`.
5. In the botpress Dashboard, enable and configure the integrations Telegram and Google Sheets.
6. Talk to the bot in Telegram and send the message `/help`. You should receive a message with the list of available commands.
+2
View File
@@ -0,0 +1,2 @@
import * as bp from '.botpress'
export const bot = new bp.Bot({ actions: {} })
+177
View File
@@ -0,0 +1,177 @@
import { z } from '@botpress/sdk'
import { MessageHandlerProps } from './types'
import { ApiUtils } from './utils'
const valuesSchema = z.array(z.array(z.union([z.string(), z.number()])))
export class CommandError extends Error {}
export type Command = (props: MessageHandlerProps, args: string[]) => Promise<void>
const help: Command = async (props) => {
const utils = new ApiUtils(props)
const commandNames = Object.keys(commands)
await utils.respond(`Available commands\n${commandNames.map((name) => `- ${name}`).join('\n')}`)
}
const info: Command = async (props) => {
const utils = new ApiUtils(props)
const { output } = await props.client.callAction({
type: 'gsheets:getInfoSpreadsheet',
input: {
fields: [
'sheets.properties.sheetId',
'sheets.properties.title',
'sheets.properties.gridProperties.rowCount',
'sheets.properties.gridProperties.columnCount',
],
},
})
await utils.respond(JSON.stringify(output, null, 2))
}
const get: Command = async (props, args) => {
const utils = new ApiUtils(props)
const [range] = args
if (!range) {
throw new CommandError('Missing range')
}
const {
output: { values },
} = await props.client.callAction({
type: 'gsheets:getValues',
input: {
range,
},
})
await utils.respond(JSON.stringify(values, null, 2))
}
const set: Command = async (props, args) => {
const utils = new ApiUtils(props)
const [range, ...body] = args
const jsonValues = body.join(' ')
if (!range) {
throw new CommandError('Missing range')
}
const parseResult = valuesSchema.safeParse(JSON.parse(jsonValues))
if (!parseResult.success) {
throw new CommandError('Invalid values')
}
const values = parseResult.data
await props.client.callAction({
type: 'gsheets:setValues',
input: {
range,
values: _stringifyValues(values),
},
})
await utils.respond('Done')
}
const append: Command = async (props, args) => {
const utils = new ApiUtils(props)
const [firstArg, secondArg, ...body] = args
const jsonValues = body.join(' ')
if (!firstArg) {
throw new CommandError('Missing startColumn')
}
let sheetName: string | undefined
let startColumn: string
if (secondArg && !secondArg.startsWith('[') && !secondArg.startsWith('{')) {
sheetName = firstArg
startColumn = secondArg
} else {
startColumn = firstArg
if (firstArg.includes('!')) {
const parts = firstArg.split('!')
if (parts.length > 1 && parts[1]) {
sheetName = parts[0]
startColumn = parts[1]
}
}
}
if (!startColumn) {
throw new CommandError('Missing startColumn')
}
const parseResult = valuesSchema.safeParse(JSON.parse(jsonValues))
if (!parseResult.success) {
throw new CommandError('Invalid values')
}
const values = parseResult.data
await props.client.callAction({
type: 'gsheets:appendValues',
input: {
sheetName,
startColumn,
values: _stringifyValues(values),
},
})
await utils.respond('Done')
}
const clear: Command = async (props, args) => {
const utils = new ApiUtils(props)
const [range] = args
if (!range) {
throw new CommandError('Missing range')
}
await props.client.callAction({
type: 'gsheets:clearValues',
input: {
range,
},
})
await utils.respond('Done')
}
const addSheet: Command = async (props, args) => {
const utils = new ApiUtils(props)
const [title] = args
if (!title) {
throw new CommandError('Missing title')
}
await props.client.callAction({
type: 'gsheets:addSheet',
input: {
title,
},
})
await utils.respond('Done')
}
const _stringifyValues = (values: any[][]): string[][] =>
values.map((majorDimension) => majorDimension.map((cell) => cell.toString()))
export const commands = {
'/help': help,
'/info': info,
'/get': get,
'/set': set,
'/append': append,
'/clear': clear,
'/addSheet': addSheet,
} satisfies Record<`/${string}`, Command>
+39
View File
@@ -0,0 +1,39 @@
import { bot } from './bot'
import { CommandError, commands } from './commands'
import { ApiUtils } from './utils'
bot.on.message('*', async (props) => {
const utils = new ApiUtils(props)
if (props.message.type !== 'text') {
await utils.respond('I only understand text messages')
return
}
const text = props.message.payload.text as string
const [command, ...args] = text.split(' ')
if (!command) {
await utils.respond('Please provide a command')
await commands['/help'](props, [])
return
}
const commandHandler = commands[command as keyof typeof commands]
if (!commandHandler) {
await utils.respond('Unknown command')
await commands['/help'](props, [])
return
}
try {
await commandHandler(props, args)
} catch (error) {
if (error instanceof CommandError) {
await utils.respond(error.message)
} else {
throw error
}
}
})
export default bot
+1
View File
@@ -0,0 +1 @@
export * from '.botpress'
+16
View File
@@ -0,0 +1,16 @@
import { MessageHandlerProps } from './types'
export class ApiUtils {
public constructor(private readonly _props: MessageHandlerProps) {}
public readonly respond = async (text: string) => {
await this._props.client.createMessage({
type: 'text',
conversationId: this._props.message.conversationId,
userId: this._props.ctx.botId,
tags: {},
payload: {
text,
},
})
}
}
+8
View File
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"paths": { "*": ["./*"] },
"outDir": "dist"
},
"include": [".botpress/**/*", "src/**/*", "*.ts"]
}