import 'dotenv/config' import { Client } from '@botpress/client' import axios from 'axios' import { spawnSync } from 'child_process' import fs from 'fs' type Args = Record const DEFAULT_API_URL = 'https://api.botpress.cloud' function readIntegrationDefinition(integrationPath: string): any { const readCmdResult = spawnSync('pnpm', ['exec', 'bp', 'read', '--json', '--workDir', integrationPath]) if (readCmdResult.status !== 0) { throw new Error( `Failed to read integration definition: ${readCmdResult.error?.message || readCmdResult.stderr.toString() || 'Unknown error'}` ) } return JSON.parse(readCmdResult.stdout.toString()) } const _fallbackProfileArgs = () => ({ apiUrl: undefined, workspaceId: undefined, token: undefined, }) function getProfileArgs(): any { const activeProfileCmdResult = spawnSync('pnpm', ['exec', 'bp', 'profiles', 'active', '--json', '--displayToken']) if (activeProfileCmdResult.status !== 0) { console.debug( `Failed to get active profile: ${activeProfileCmdResult.error?.message || activeProfileCmdResult.stderr.toString() || 'Unknown error'}` ) return _fallbackProfileArgs() } try { return JSON.parse(activeProfileCmdResult.stdout.toString()) } catch { return _fallbackProfileArgs() } } function parseArgs(): Args { return process.argv.slice(2).reduce>((acc, arg) => { const [key, value] = arg.split('=') if (key && value) acc[key.replace(/^--/, '')] = value return acc }, {}) } async function uploadScripts({ apiUrl, token, workspaceId, userEmail, integrationId, integrationPath, }: { apiUrl: string token: string workspaceId: string userEmail: string integrationId?: string integrationPath?: string }) { if (apiUrl !== DEFAULT_API_URL) { console.debug(`🔗 Using custom url ${apiUrl}`) } if (integrationId) { console.debug(`🧩 Using custom integration ID ${integrationId}`) } integrationPath ||= '.' console.info('Reading integration definition...') const { name, version } = readIntegrationDefinition(integrationPath) const client = new Client({ apiUrl, token, workspaceId }) let integration: Awaited>['integration'] console.info(`Fetching remote integration definition ${name} ${version}...`) if (!integrationId) { console.debug('No integration ID provided, searching by name and version') const getIntegrationResponse = await client.getIntegrationByName({ name, version, }) integration = getIntegrationResponse.integration } else { console.debug('Integration ID provided, fetching by ID') const getIntegrationResponse = await client.getIntegration({ id: integrationId, }) integration = getIntegrationResponse.integration } integrationId = integration.id console.info(`Integration ID: ${integrationId}`) if (!integration.configurations['sandbox']) { console.info('Integration does not implement the sandbox feature, no scripts to upload') process.exit(0) } const identifierExtractScriptPath = `${integrationPath}/sandboxIdentifierExtract.vrl` const messageExtractScriptPath = `${integrationPath}/sandboxShareableIdExtract.vrl` const identifierExtractScript = fs.readFileSync(identifierExtractScriptPath, 'utf8') const messageExtractScript = fs.readFileSync(messageExtractScriptPath, 'utf8') return await await axios.put( `${apiUrl}/v1/corporate/integrations/${integrationId}/sandbox`, { identifierExtractScript, messageExtractScript, }, { headers: { Authorization: `Bearer ${token}`, 'x-user-email': userEmail, }, } ) } const args = parseArgs() const profileArgs = getProfileArgs() const apiUrl = args.apiUrl || profileArgs.apiUrl || process.env.BP_API_URL || DEFAULT_API_URL const token = args.token || profileArgs.token || process.env.BP_TOKEN const workspaceId = args.workspaceId || profileArgs.workspaceId || process.env.BP_WORKSPACE_ID const userEmail = args.userEmail const integrationId = args.integrationId || process.env.BP_INTEGRATION_ID const integrationPath = args.integrationPath if (!userEmail || !token || !workspaceId) { const missingArgs: string[] = [ !userEmail ? 'userEmail' : null, !token ? 'token' : null, !workspaceId ? 'workspaceId' : null, ].filter((value) => value !== null) console.error(`Missing required arguments: ${missingArgs.join(', ')}`) console.error( 'Usage: pnpm run ts-node -T upload-sandbox-scripts.ts --userEmail= --token= --workspaceId= [--apiUrl=] [--integrationId=] [--integrationPath=]\n' + 'integrationId, apiUrl, token, and workspaceId can also be set in the environment variables BP_INTEGRATION_ID, BP_API_URL, BP_TOKEN, BP_WORKSPACE_ID' ) process.exit(1) } uploadScripts({ apiUrl, token, workspaceId, userEmail, integrationId, integrationPath, }) .then((res) => { console.info('Sandbox scripts updated successfully:', res.data) }) .catch((error) => { console.error('Failed to update sandbox scripts') if (error.response) { console.error('Error Data:', error.response.data) console.error('Error Status:', error.response.status) console.error('Error Headers:', error.response.headers) } else if (error.request) { console.error('Error Request:', error.request) } else { console.error('Error Message:', error.message) } })