@botpress/cli 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -37,26 +37,23 @@ import type { Configuration } from './configuration'
37
37
 
38
38
 
39
39
  export type ${propsName} = {
40
- enabled: true
41
- config: Configuration
42
- } | {
43
- enabled: false
40
+ enabled?: boolean
44
41
  config?: Configuration
45
42
  }
46
43
 
47
44
  export class ${className} implements IntegrationInstance {
48
45
 
49
- public readonly enabled: boolean
50
-
46
+
51
47
  public readonly name = '${name}'
52
48
  public readonly version = '${version}'
53
49
  public readonly id = '${id}'
54
-
55
- public readonly configuration: Configuration
50
+
51
+ public readonly enabled?: boolean
52
+ public readonly configuration?: Configuration
56
53
 
57
54
  constructor(props?: ${propsName}) {
58
- this.enabled = props?.enabled ?? false
59
- this.configuration = props?.config ?? <Configuration>{}
55
+ this.enabled = props?.enabled
56
+ this.configuration = props?.config
60
57
  }
61
58
  }
62
59
  `;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/code-generation/integration-instance.ts"],
4
- "sourcesContent": ["import type { Integration } from '@botpress/client'\nimport { casing } from '../utils'\nimport { ConfigurationModule } from './configuration'\nimport { INDEX_FILE } from './const'\nimport { Module, ModuleDef } from './module'\n\nconst CONTENT = ({\n name,\n className,\n propsName,\n version,\n id,\n}: {\n name: string\n className: string\n propsName: string\n version: string\n id: string\n}) => `\nimport type { IntegrationInstance } from '@botpress/sdk'\nimport type { Configuration } from './configuration'\n\n\nexport type ${propsName} = {\n enabled: true\n config: Configuration\n} | {\n enabled: false\n config?: Configuration\n}\n\nexport class ${className} implements IntegrationInstance {\n \n public readonly enabled: boolean\n\n public readonly name = '${name}'\n public readonly version = '${version}'\n public readonly id = '${id}'\n\n public readonly configuration: Configuration\n\n constructor(props?: ${propsName}) {\n this.enabled = props?.enabled ?? false\n this.configuration = props?.config ?? <Configuration>{}\n }\n}\n`\n\nexport class IntegrationInstanceIndexModule extends Module {\n public static async create(integration: Integration): Promise<IntegrationInstanceIndexModule> {\n const { name, version, id } = integration\n\n const configModule = await ConfigurationModule.create(integration.configuration ?? { schema: {} })\n\n const exportName = casing.to.pascalCase(name)\n\n const content = CONTENT({ name, className: exportName, propsName: `${exportName}Props`, version, id })\n const inst = new IntegrationInstanceIndexModule({ path: INDEX_FILE, content, exportName })\n\n inst.pushDep(configModule)\n\n return inst\n }\n\n private constructor(def: ModuleDef) {\n super(def)\n }\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,mBAAuB;AACvB,2BAAoC;AACpC,mBAA2B;AAC3B,oBAAkC;AAElC,MAAM,UAAU,CAAC;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAMM;AAAA;AAAA;AAAA;AAAA;AAAA,cAKQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,eAQC;AAAA;AAAA;AAAA;AAAA,4BAIa;AAAA,+BACG;AAAA,0BACL;AAAA;AAAA;AAAA;AAAA,wBAIF;AAAA;AAAA;AAAA;AAAA;AAAA;AAOjB,MAAM,uCAAuC,qBAAO;AAAA,EACzD,aAAoB,OAAO,aAAmE;AAC5F,UAAM,EAAE,MAAM,SAAS,GAAG,IAAI;AAE9B,UAAM,eAAe,MAAM,yCAAoB,OAAO,YAAY,iBAAiB,EAAE,QAAQ,CAAC,EAAE,CAAC;AAEjG,UAAM,aAAa,oBAAO,GAAG,WAAW,IAAI;AAE5C,UAAM,UAAU,QAAQ,EAAE,MAAM,WAAW,YAAY,WAAW,GAAG,mBAAmB,SAAS,GAAG,CAAC;AACrG,UAAM,OAAO,IAAI,+BAA+B,EAAE,MAAM,yBAAY,SAAS,WAAW,CAAC;AAEzF,SAAK,QAAQ,YAAY;AAEzB,WAAO;AAAA,EACT;AAAA,EAEQ,YAAY,KAAgB;AAClC,UAAM,GAAG;AAAA,EACX;AACF;",
4
+ "sourcesContent": ["import type { Integration } from '@botpress/client'\nimport { casing } from '../utils'\nimport { ConfigurationModule } from './configuration'\nimport { INDEX_FILE } from './const'\nimport { Module, ModuleDef } from './module'\n\nconst CONTENT = ({\n name,\n className,\n propsName,\n version,\n id,\n}: {\n name: string\n className: string\n propsName: string\n version: string\n id: string\n}) => `\nimport type { IntegrationInstance } from '@botpress/sdk'\nimport type { Configuration } from './configuration'\n\n\nexport type ${propsName} = {\n enabled?: boolean\n config?: Configuration\n}\n\nexport class ${className} implements IntegrationInstance {\n \n \n public readonly name = '${name}'\n public readonly version = '${version}'\n public readonly id = '${id}'\n \n public readonly enabled?: boolean\n public readonly configuration?: Configuration\n\n constructor(props?: ${propsName}) {\n this.enabled = props?.enabled\n this.configuration = props?.config\n }\n}\n`\n\nexport class IntegrationInstanceIndexModule extends Module {\n public static async create(integration: Integration): Promise<IntegrationInstanceIndexModule> {\n const { name, version, id } = integration\n\n const configModule = await ConfigurationModule.create(integration.configuration ?? { schema: {} })\n\n const exportName = casing.to.pascalCase(name)\n\n const content = CONTENT({ name, className: exportName, propsName: `${exportName}Props`, version, id })\n const inst = new IntegrationInstanceIndexModule({ path: INDEX_FILE, content, exportName })\n\n inst.pushDep(configModule)\n\n return inst\n }\n\n private constructor(def: ModuleDef) {\n super(def)\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,mBAAuB;AACvB,2BAAoC;AACpC,mBAA2B;AAC3B,oBAAkC;AAElC,MAAM,UAAU,CAAC;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAMM;AAAA;AAAA;AAAA;AAAA;AAAA,cAKQ;AAAA;AAAA;AAAA;AAAA;AAAA,eAKC;AAAA;AAAA;AAAA,4BAGa;AAAA,+BACG;AAAA,0BACL;AAAA;AAAA;AAAA;AAAA;AAAA,wBAKF;AAAA;AAAA;AAAA;AAAA;AAAA;AAOjB,MAAM,uCAAuC,qBAAO;AAAA,EACzD,aAAoB,OAAO,aAAmE;AAC5F,UAAM,EAAE,MAAM,SAAS,GAAG,IAAI;AAE9B,UAAM,eAAe,MAAM,yCAAoB,OAAO,YAAY,iBAAiB,EAAE,QAAQ,CAAC,EAAE,CAAC;AAEjG,UAAM,aAAa,oBAAO,GAAG,WAAW,IAAI;AAE5C,UAAM,UAAU,QAAQ,EAAE,MAAM,WAAW,YAAY,WAAW,GAAG,mBAAmB,SAAS,GAAG,CAAC;AACrG,UAAM,OAAO,IAAI,+BAA+B,EAAE,MAAM,yBAAY,SAAS,WAAW,CAAC;AAEzF,SAAK,QAAQ,YAAY;AAEzB,WAAO;AAAA,EACT;AAAA,EAEQ,YAAY,KAAgB;AAClC,UAAM,GAAG;AAAA,EACX;AACF;",
6
6
  "names": []
7
7
  }
@@ -113,15 +113,15 @@ class DeployCommand extends import_project_command.ProjectCommand {
113
113
  ...acc,
114
114
  [channelName]: {
115
115
  ...channelDef,
116
- messages: utils.records.setOnNullMissingValues(channelDef.messages, currentChannel?.messages),
116
+ messages: utils.records.setOnNullMissingValues(channelDef?.messages, currentChannel?.messages),
117
117
  message: {
118
- ...channelDef.message,
119
- tags: utils.records.setOnNullMissingValues(channelDef.message?.tags, currentChannel?.message.tags)
118
+ ...channelDef?.message,
119
+ tags: utils.records.setOnNullMissingValues(channelDef?.message?.tags, currentChannel?.message.tags)
120
120
  },
121
121
  conversation: {
122
- ...channelDef.conversation,
122
+ ...channelDef?.conversation,
123
123
  tags: utils.records.setOnNullMissingValues(
124
- channelDef.conversation?.tags,
124
+ channelDef?.conversation?.tags,
125
125
  currentChannel?.conversation.tags
126
126
  )
127
127
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/command-implementations/deploy-command.ts"],
4
- "sourcesContent": ["import type * as bpclient from '@botpress/client'\nimport type { Bot as BotImpl, IntegrationDefinition } from '@botpress/sdk'\nimport chalk from 'chalk'\nimport * as fs from 'fs'\nimport type { ApiClient } from 'src/api-client'\nimport type commandDefinitions from '../command-definitions'\nimport * as consts from '../consts'\nimport * as errors from '../errors'\nimport * as utils from '../utils'\nimport { BuildCommand } from './build-command'\nimport { ProjectCommand } from './project-command'\n\ntype CreateIntegrationBody = Parameters<bpclient.Client['createIntegration']>[0]\ntype UpdateIntegrationBody = Parameters<bpclient.Client['updateIntegration']>[0]\ntype UpdateBotBody = Parameters<bpclient.Client['updateBot']>[0]\n\nexport type DeployCommandDefinition = typeof commandDefinitions.deploy\nexport class DeployCommand extends ProjectCommand<DeployCommandDefinition> {\n public async run(): Promise<void> {\n const api = await this.ensureLoginAndCreateClient(this.argv)\n if (api.url !== consts.defaultBotpressApiUrl) {\n this.logger.log(`Using custom url ${api.url}`)\n }\n\n if (!this.argv.noBuild) {\n await this._runBuild() // This ensures the bundle is always synced with source code\n }\n\n const integrationDef = await this.readIntegrationDefinitionFromFS()\n if (integrationDef) {\n return this._deployIntegration(api, integrationDef)\n }\n return this._deployBot(api, this.argv.botId, this.argv.createNewBot)\n }\n\n private async _runBuild() {\n return new BuildCommand(this.api, this.prompt, this.logger, this.argv).run()\n }\n\n private async _deployIntegration(api: ApiClient, integrationDef: IntegrationDefinition) {\n const outfile = this.projectPaths.abs.outFile\n let code = await fs.promises.readFile(outfile, 'utf-8')\n\n const secrets = await this.promptSecrets(integrationDef, this.argv)\n // TODO: provide these secrets to the backend by API and remove this string replacement hack\n for (const [secretName, secretValue] of Object.entries(secrets)) {\n code = code.replace(new RegExp(`process\\\\.env\\\\.${secretName}`, 'g'), `\"${secretValue}\"`)\n }\n\n const { name, version, icon: iconRelativeFilePath, readme: readmeRelativeFilePath } = integrationDef\n\n const iconFileContent = await this._readMediaFile('icon', iconRelativeFilePath)\n const readmeFileContent = await this._readMediaFile('readme', readmeRelativeFilePath)\n\n const integration = await api.findIntegration({ type: 'name', name, version })\n\n let message: string\n if (integration) {\n this.logger.warn('Integration already exists. If you decide to deploy, it will overwrite the existing one.')\n message = `Are you sure you want to override integration ${integrationDef.name} v${integrationDef.version}?`\n } else {\n message = `Are you sure you want to deploy integration ${integrationDef.name} v${integrationDef.version}?`\n }\n\n const confirm = await this.prompt.confirm(message)\n if (!confirm) {\n this.logger.log('Aborted')\n return\n }\n\n const publishBody: CreateIntegrationBody = {\n ...integrationDef,\n icon: iconFileContent,\n readme: readmeFileContent,\n code,\n }\n\n const line = this.logger.line()\n line.started(`Deploying integration ${chalk.bold(integrationDef.name)} v${integrationDef.version}...`)\n if (integration) {\n const publishUpdateBody: UpdateIntegrationBody = this._prepareUpdateIntegrationBody(integration, {\n id: integration.id,\n ...publishBody,\n })\n\n await api.client.updateIntegration(publishUpdateBody).catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, `Could not update integration \"${integrationDef.name}\"`)\n })\n } else {\n await api.client.createIntegration(publishBody).catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, `Could not create integration \"${integrationDef.name}\"`)\n })\n }\n line.success('Integration deployed')\n }\n\n // all fields that were removed are replaced by null for the API to remove them\n private _prepareUpdateIntegrationBody = (\n integration: bpclient.Integration,\n body: UpdateIntegrationBody\n ): UpdateIntegrationBody => ({\n ...body,\n actions: utils.records.setOnNullMissingValues(body.actions, integration.actions),\n events: utils.records.setOnNullMissingValues(body.events, integration.events),\n states: utils.records.setOnNullMissingValues(body.states, integration.states),\n user: {\n ...body.user,\n tags: utils.records.setOnNullMissingValues(body.user?.tags, integration.user?.tags),\n },\n channels: Object.entries(body.channels ?? {}).reduce((acc, [channelName, channelDef]) => {\n const currentChannel = integration.channels[channelName]\n return {\n ...acc,\n [channelName]: {\n ...channelDef,\n messages: utils.records.setOnNullMissingValues(channelDef.messages, currentChannel?.messages),\n message: {\n ...channelDef.message,\n tags: utils.records.setOnNullMissingValues(channelDef.message?.tags, currentChannel?.message.tags),\n },\n conversation: {\n ...channelDef.conversation,\n tags: utils.records.setOnNullMissingValues(\n channelDef.conversation?.tags,\n currentChannel?.conversation.tags\n ),\n },\n },\n }\n }, {} as UpdateIntegrationBody['channels']),\n })\n\n private _readMediaFile = async (\n filePurpose: 'icon' | 'readme',\n filePath: string | undefined\n ): Promise<string | undefined> => {\n if (!filePath) {\n return undefined\n }\n\n const absoluteFilePath = utils.path.absoluteFrom(this.projectPaths.abs.workDir, filePath)\n return fs.promises.readFile(absoluteFilePath, 'base64').catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, `Could not read ${filePurpose} file \"${absoluteFilePath}\"`)\n })\n }\n\n private async _deployBot(api: ApiClient, argvBotId: string | undefined, argvCreateNew: boolean | undefined) {\n const outfile = this.projectPaths.abs.outFile\n const code = await fs.promises.readFile(outfile, 'utf-8')\n const { default: botImpl } = utils.require.requireJsFile<{ default: BotImpl }>(outfile)\n\n const {\n states,\n events,\n recurringEvents,\n configuration: botConfiguration,\n user,\n conversation,\n message,\n } = botImpl.definition\n\n let bot: bpclient.Bot\n if (argvBotId && argvCreateNew) {\n throw new errors.BotpressCLIError('Cannot specify both --botId and --createNew')\n } else if (argvCreateNew) {\n const confirm = await this.prompt.confirm('Are you sure you want to create a new bot ?')\n if (!confirm) {\n this.logger.log('Aborted')\n return\n }\n\n bot = await this._createNewBot(api)\n } else {\n bot = await this._getExistingBot(api, argvBotId)\n\n const confirm = await this.prompt.confirm(`Are you sure you want to deploy the bot \"${bot.name}\"?`)\n if (!confirm) {\n this.logger.log('Aborted')\n return\n }\n }\n\n const integrations = this.prepareIntegrations(botImpl, bot)\n\n const line = this.logger.line()\n line.started(`Deploying bot ${chalk.bold(bot.name)}...`)\n\n const updateBotBody: UpdateBotBody = this._prepareUpdateBotBody(bot, {\n id: bot.id,\n code,\n states,\n recurringEvents,\n configuration: botConfiguration,\n events,\n user,\n conversation,\n message,\n integrations,\n })\n\n const { bot: updatedBot } = await api.client.updateBot(updateBotBody).catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, `Could not update bot \"${bot.name}\"`)\n })\n line.success('Bot deployed')\n this.displayWebhookUrls(updatedBot)\n }\n\n // all fields that were removed are replaced by null for the API to remove them\n private _prepareUpdateBotBody = (bot: bpclient.Bot, body: UpdateBotBody): UpdateBotBody => ({\n ...body,\n states: utils.records.setOnNullMissingValues(body.states, bot.states),\n recurringEvents: utils.records.setOnNullMissingValues(body.recurringEvents, bot.recurringEvents),\n events: utils.records.setOnNullMissingValues(body.events, bot.events),\n user: {\n ...body.user,\n tags: utils.records.setOnNullMissingValues(body.user?.tags, bot.user?.tags),\n },\n conversation: {\n ...body.conversation,\n tags: utils.records.setOnNullMissingValues(body.conversation?.tags, bot.conversation?.tags),\n },\n message: {\n ...body.message,\n tags: utils.records.setOnNullMissingValues(body.message?.tags, bot.message?.tags),\n },\n })\n\n private async _createNewBot(api: ApiClient): Promise<bpclient.Bot> {\n const line = this.logger.line()\n const { bot: createdBot } = await api.client.createBot({}).catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, 'Could not create bot')\n })\n line.success(`Bot created with ID \"${createdBot.id}\" and name \"${createdBot.name}\"`)\n await this.projectCache.set('botId', createdBot.id)\n return createdBot\n }\n\n private async _getExistingBot(api: ApiClient, botId: string | undefined): Promise<bpclient.Bot> {\n const promptedBotId = await this.projectCache.sync('botId', botId, async (defaultId) => {\n const userBots = await api\n .listAllPages(api.client.listBots, (r) => r.bots)\n .catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, 'Could not fetch existing bots')\n })\n\n if (!userBots.length) {\n throw new errors.NoBotsFoundError()\n }\n\n const initial = userBots.find((bot) => bot.id === defaultId)\n\n const prompted = await this.prompt.select('Which bot do you want to deploy?', {\n initial: initial && { title: initial.name, value: initial.id },\n choices: userBots.map((bot) => ({ title: bot.name, value: bot.id })),\n })\n\n if (!prompted) {\n throw new errors.ParamRequiredError('Bot Id')\n }\n\n return prompted\n })\n\n const { bot: fetchedBot } = await api.client.getBot({ id: promptedBotId }).catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, 'Could not get bot info')\n })\n\n return fetchedBot\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type * as bpclient from '@botpress/client'\nimport type { Bot as BotImpl, IntegrationDefinition } from '@botpress/sdk'\nimport chalk from 'chalk'\nimport * as fs from 'fs'\nimport type { ApiClient } from 'src/api-client'\nimport type commandDefinitions from '../command-definitions'\nimport * as consts from '../consts'\nimport * as errors from '../errors'\nimport * as utils from '../utils'\nimport { BuildCommand } from './build-command'\nimport { ProjectCommand } from './project-command'\n\ntype CreateIntegrationBody = Parameters<bpclient.Client['createIntegration']>[0]\ntype UpdateIntegrationBody = Parameters<bpclient.Client['updateIntegration']>[0]\ntype UpdateBotBody = Parameters<bpclient.Client['updateBot']>[0]\n\nexport type DeployCommandDefinition = typeof commandDefinitions.deploy\nexport class DeployCommand extends ProjectCommand<DeployCommandDefinition> {\n public async run(): Promise<void> {\n const api = await this.ensureLoginAndCreateClient(this.argv)\n if (api.url !== consts.defaultBotpressApiUrl) {\n this.logger.log(`Using custom url ${api.url}`)\n }\n\n if (!this.argv.noBuild) {\n await this._runBuild() // This ensures the bundle is always synced with source code\n }\n\n const integrationDef = await this.readIntegrationDefinitionFromFS()\n if (integrationDef) {\n return this._deployIntegration(api, integrationDef)\n }\n return this._deployBot(api, this.argv.botId, this.argv.createNewBot)\n }\n\n private async _runBuild() {\n return new BuildCommand(this.api, this.prompt, this.logger, this.argv).run()\n }\n\n private async _deployIntegration(api: ApiClient, integrationDef: IntegrationDefinition) {\n const outfile = this.projectPaths.abs.outFile\n let code = await fs.promises.readFile(outfile, 'utf-8')\n\n const secrets = await this.promptSecrets(integrationDef, this.argv)\n // TODO: provide these secrets to the backend by API and remove this string replacement hack\n for (const [secretName, secretValue] of Object.entries(secrets)) {\n code = code.replace(new RegExp(`process\\\\.env\\\\.${secretName}`, 'g'), `\"${secretValue}\"`)\n }\n\n const { name, version, icon: iconRelativeFilePath, readme: readmeRelativeFilePath } = integrationDef\n\n const iconFileContent = await this._readMediaFile('icon', iconRelativeFilePath)\n const readmeFileContent = await this._readMediaFile('readme', readmeRelativeFilePath)\n\n const integration = await api.findIntegration({ type: 'name', name, version })\n\n let message: string\n if (integration) {\n this.logger.warn('Integration already exists. If you decide to deploy, it will overwrite the existing one.')\n message = `Are you sure you want to override integration ${integrationDef.name} v${integrationDef.version}?`\n } else {\n message = `Are you sure you want to deploy integration ${integrationDef.name} v${integrationDef.version}?`\n }\n\n const confirm = await this.prompt.confirm(message)\n if (!confirm) {\n this.logger.log('Aborted')\n return\n }\n\n const publishBody: CreateIntegrationBody = {\n ...integrationDef,\n icon: iconFileContent,\n readme: readmeFileContent,\n code,\n }\n\n const line = this.logger.line()\n line.started(`Deploying integration ${chalk.bold(integrationDef.name)} v${integrationDef.version}...`)\n if (integration) {\n const publishUpdateBody: UpdateIntegrationBody = this._prepareUpdateIntegrationBody(integration, {\n id: integration.id,\n ...publishBody,\n })\n\n await api.client.updateIntegration(publishUpdateBody).catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, `Could not update integration \"${integrationDef.name}\"`)\n })\n } else {\n await api.client.createIntegration(publishBody).catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, `Could not create integration \"${integrationDef.name}\"`)\n })\n }\n line.success('Integration deployed')\n }\n\n // all fields that were removed are replaced by null for the API to remove them\n private _prepareUpdateIntegrationBody = (\n integration: bpclient.Integration,\n body: UpdateIntegrationBody\n ): UpdateIntegrationBody => ({\n ...body,\n actions: utils.records.setOnNullMissingValues(body.actions, integration.actions),\n events: utils.records.setOnNullMissingValues(body.events, integration.events),\n states: utils.records.setOnNullMissingValues(body.states, integration.states),\n user: {\n ...body.user,\n tags: utils.records.setOnNullMissingValues(body.user?.tags, integration.user?.tags),\n },\n channels: Object.entries(body.channels ?? {}).reduce((acc, [channelName, channelDef]) => {\n const currentChannel = integration.channels[channelName]\n return {\n ...acc,\n [channelName]: {\n ...channelDef,\n messages: utils.records.setOnNullMissingValues(channelDef?.messages, currentChannel?.messages),\n message: {\n ...channelDef?.message,\n tags: utils.records.setOnNullMissingValues(channelDef?.message?.tags, currentChannel?.message.tags),\n },\n conversation: {\n ...channelDef?.conversation,\n tags: utils.records.setOnNullMissingValues(\n channelDef?.conversation?.tags,\n currentChannel?.conversation.tags\n ),\n },\n },\n }\n }, {} as UpdateIntegrationBody['channels']),\n })\n\n private _readMediaFile = async (\n filePurpose: 'icon' | 'readme',\n filePath: string | undefined\n ): Promise<string | undefined> => {\n if (!filePath) {\n return undefined\n }\n\n const absoluteFilePath = utils.path.absoluteFrom(this.projectPaths.abs.workDir, filePath)\n return fs.promises.readFile(absoluteFilePath, 'base64').catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, `Could not read ${filePurpose} file \"${absoluteFilePath}\"`)\n })\n }\n\n private async _deployBot(api: ApiClient, argvBotId: string | undefined, argvCreateNew: boolean | undefined) {\n const outfile = this.projectPaths.abs.outFile\n const code = await fs.promises.readFile(outfile, 'utf-8')\n const { default: botImpl } = utils.require.requireJsFile<{ default: BotImpl }>(outfile)\n\n const {\n states,\n events,\n recurringEvents,\n configuration: botConfiguration,\n user,\n conversation,\n message,\n } = botImpl.definition\n\n let bot: bpclient.Bot\n if (argvBotId && argvCreateNew) {\n throw new errors.BotpressCLIError('Cannot specify both --botId and --createNew')\n } else if (argvCreateNew) {\n const confirm = await this.prompt.confirm('Are you sure you want to create a new bot ?')\n if (!confirm) {\n this.logger.log('Aborted')\n return\n }\n\n bot = await this._createNewBot(api)\n } else {\n bot = await this._getExistingBot(api, argvBotId)\n\n const confirm = await this.prompt.confirm(`Are you sure you want to deploy the bot \"${bot.name}\"?`)\n if (!confirm) {\n this.logger.log('Aborted')\n return\n }\n }\n\n const integrations = this.prepareIntegrations(botImpl, bot)\n\n const line = this.logger.line()\n line.started(`Deploying bot ${chalk.bold(bot.name)}...`)\n\n const updateBotBody: UpdateBotBody = this._prepareUpdateBotBody(bot, {\n id: bot.id,\n code,\n states,\n recurringEvents,\n configuration: botConfiguration,\n events,\n user,\n conversation,\n message,\n integrations,\n })\n\n const { bot: updatedBot } = await api.client.updateBot(updateBotBody).catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, `Could not update bot \"${bot.name}\"`)\n })\n line.success('Bot deployed')\n this.displayWebhookUrls(updatedBot)\n }\n\n // all fields that were removed are replaced by null for the API to remove them\n private _prepareUpdateBotBody = (bot: bpclient.Bot, body: UpdateBotBody): UpdateBotBody => ({\n ...body,\n states: utils.records.setOnNullMissingValues(body.states, bot.states),\n recurringEvents: utils.records.setOnNullMissingValues(body.recurringEvents, bot.recurringEvents),\n events: utils.records.setOnNullMissingValues(body.events, bot.events),\n user: {\n ...body.user,\n tags: utils.records.setOnNullMissingValues(body.user?.tags, bot.user?.tags),\n },\n conversation: {\n ...body.conversation,\n tags: utils.records.setOnNullMissingValues(body.conversation?.tags, bot.conversation?.tags),\n },\n message: {\n ...body.message,\n tags: utils.records.setOnNullMissingValues(body.message?.tags, bot.message?.tags),\n },\n })\n\n private async _createNewBot(api: ApiClient): Promise<bpclient.Bot> {\n const line = this.logger.line()\n const { bot: createdBot } = await api.client.createBot({}).catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, 'Could not create bot')\n })\n line.success(`Bot created with ID \"${createdBot.id}\" and name \"${createdBot.name}\"`)\n await this.projectCache.set('botId', createdBot.id)\n return createdBot\n }\n\n private async _getExistingBot(api: ApiClient, botId: string | undefined): Promise<bpclient.Bot> {\n const promptedBotId = await this.projectCache.sync('botId', botId, async (defaultId) => {\n const userBots = await api\n .listAllPages(api.client.listBots, (r) => r.bots)\n .catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, 'Could not fetch existing bots')\n })\n\n if (!userBots.length) {\n throw new errors.NoBotsFoundError()\n }\n\n const initial = userBots.find((bot) => bot.id === defaultId)\n\n const prompted = await this.prompt.select('Which bot do you want to deploy?', {\n initial: initial && { title: initial.name, value: initial.id },\n choices: userBots.map((bot) => ({ title: bot.name, value: bot.id })),\n })\n\n if (!prompted) {\n throw new errors.ParamRequiredError('Bot Id')\n }\n\n return prompted\n })\n\n const { bot: fetchedBot } = await api.client.getBot({ id: promptedBotId }).catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, 'Could not get bot info')\n })\n\n return fetchedBot\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["chalk"]
7
7
  }
@@ -27,7 +27,6 @@ __export(dev_command_exports, {
27
27
  DevCommand: () => DevCommand
28
28
  });
29
29
  module.exports = __toCommonJS(dev_command_exports);
30
- var import_tunnel = require("@bpinternal/tunnel");
31
30
  var import_axios = __toESM(require("axios"));
32
31
  var import_chalk = __toESM(require("chalk"));
33
32
  var pathlib = __toESM(require("path"));
@@ -46,6 +45,7 @@ class DevCommand extends import_project_command.ProjectCommand {
46
45
  const api = await this.ensureLoginAndCreateClient(this.argv);
47
46
  this._initialDef = await this.readIntegrationDefinitionFromFS();
48
47
  let env = {
48
+ ...process.env,
49
49
  BP_API_URL: api.url,
50
50
  BP_TOKEN: api.token
51
51
  };
@@ -69,21 +69,24 @@ class DevCommand extends import_project_command.ProjectCommand {
69
69
  protocol: isSecured ? "https" : "http",
70
70
  path: `/${tunnelId}`
71
71
  });
72
- const tunnel = await import_tunnel.TunnelTail.new(wsTunnelUrl, tunnelId);
73
- tunnel.events.on(
74
- "request",
75
- (req) => void this._forwardTunnelRequest(`http://localhost:${port}`, req).then((res) => {
76
- tunnel.send(res);
77
- }).catch((thrown) => {
78
- const err = errors.BotpressCLIError.wrap(thrown, "An error occurred while handling request");
79
- this.logger.error(err.message);
80
- tunnel.send({
81
- requestId: req.id,
82
- status: 500,
83
- body: err.message
84
- });
85
- })
86
- );
72
+ const supervisor = new utils.tunnel.TunnelSupervisor(wsTunnelUrl, tunnelId, this.logger);
73
+ supervisor.events.on("connected", ({ tunnel }) => {
74
+ tunnel.events.on(
75
+ "request",
76
+ (req) => void this._forwardTunnelRequest(`http://localhost:${port}`, req).then((res) => {
77
+ tunnel.send(res);
78
+ }).catch((thrown) => {
79
+ const err = errors.BotpressCLIError.wrap(thrown, "An error occurred while handling request");
80
+ this.logger.error(err.message);
81
+ tunnel.send({
82
+ requestId: req.id,
83
+ status: 500,
84
+ body: err.message
85
+ });
86
+ })
87
+ );
88
+ });
89
+ await supervisor.start();
87
90
  await this._deploy(api, httpTunnelUrl);
88
91
  await this._runBuild();
89
92
  const worker = await this._spawnWorker(env, port);
@@ -102,8 +105,12 @@ class DevCommand extends import_project_command.ProjectCommand {
102
105
  ignore: [this.projectPaths.abs.outDir]
103
106
  }
104
107
  );
105
- await Promise.race([worker.wait(), watcher.wait(), tunnel.wait()]);
108
+ await Promise.race([worker.wait(), watcher.wait(), supervisor.wait()]);
109
+ if (worker.running) {
110
+ await worker.kill();
111
+ }
106
112
  await watcher.close();
113
+ supervisor.close();
107
114
  } catch (thrown) {
108
115
  throw errors.BotpressCLIError.wrap(thrown, "An error occurred while running the dev server");
109
116
  } finally {
@@ -224,7 +231,12 @@ class DevCommand extends import_project_command.ProjectCommand {
224
231
  const integrations = this.prepareIntegrations(botImpl, bot);
225
232
  const updateLine = this.logger.line();
226
233
  updateLine.started("Deploying dev bot...");
227
- const { bot: updatedBot } = await api.client.updateBot({ id: bot.id, integrations, url: externalUrl }).catch((thrown) => {
234
+ const { bot: updatedBot } = await api.client.updateBot({
235
+ ...botImpl.definition,
236
+ id: bot.id,
237
+ integrations,
238
+ url: externalUrl
239
+ }).catch((thrown) => {
228
240
  throw errors.BotpressCLIError.wrap(thrown, "Could not deploy dev bot");
229
241
  });
230
242
  updateLine.success(`Dev Bot deployed with id "${updatedBot.id}"`);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/command-implementations/dev-command.ts"],
4
- "sourcesContent": ["import type * as bpclient from '@botpress/client'\nimport type { Bot as BotImpl, IntegrationDefinition } from '@botpress/sdk'\nimport { TunnelRequest, TunnelResponse, TunnelTail } from '@bpinternal/tunnel'\nimport axios, { AxiosRequestConfig, AxiosResponse } from 'axios'\nimport chalk from 'chalk'\nimport * as pathlib from 'path'\nimport * as uuid from 'uuid'\nimport type { ApiClient } from '../api-client'\nimport type commandDefinitions from '../command-definitions'\nimport * as errors from '../errors'\nimport * as utils from '../utils'\nimport { Worker } from '../worker'\nimport { BuildCommand } from './build-command'\nimport { ProjectCommand } from './project-command'\n\nconst DEFAULT_BOT_PORT = 8075\nconst DEFAULT_INTEGRATION_PORT = 8076\n\nexport type DevCommandDefinition = typeof commandDefinitions.dev\nexport class DevCommand extends ProjectCommand<DevCommandDefinition> {\n private _initialDef: IntegrationDefinition | undefined = undefined\n\n public async run(): Promise<void> {\n this.logger.warn('This command is experimental and subject to breaking changes without notice.')\n\n const api = await this.ensureLoginAndCreateClient(this.argv)\n\n this._initialDef = await this.readIntegrationDefinitionFromFS()\n\n let env: Record<string, string> = {\n BP_API_URL: api.url,\n BP_TOKEN: api.token,\n }\n\n let defaultPort = DEFAULT_BOT_PORT\n if (this._initialDef) {\n defaultPort = DEFAULT_INTEGRATION_PORT\n const secrets = await this.promptSecrets(this._initialDef, this.argv)\n env = { ...env, ...secrets }\n }\n\n const port = this.argv.port ?? defaultPort\n\n const urlParseResult = utils.url.parse(this.argv.tunnelUrl)\n if (urlParseResult.status === 'error') {\n throw new errors.BotpressCLIError(`Invalid tunnel URL: ${urlParseResult.error}`)\n }\n\n const tunnelId = uuid.v4()\n\n const { url: parsedTunnelUrl } = urlParseResult\n const isSecured = parsedTunnelUrl.protocol === 'https' || parsedTunnelUrl.protocol === 'wss'\n\n const wsTunnelUrl: string = utils.url.format({ ...parsedTunnelUrl, protocol: isSecured ? 'wss' : 'ws' })\n const httpTunnelUrl: string = utils.url.format({\n ...parsedTunnelUrl,\n protocol: isSecured ? 'https' : 'http',\n path: `/${tunnelId}`,\n })\n\n const tunnel = await TunnelTail.new(wsTunnelUrl, tunnelId)\n tunnel.events.on(\n 'request',\n (req) =>\n void this._forwardTunnelRequest(`http://localhost:${port}`, req)\n .then((res) => {\n tunnel.send(res)\n })\n .catch((thrown) => {\n const err = errors.BotpressCLIError.wrap(thrown, 'An error occurred while handling request')\n this.logger.error(err.message)\n tunnel.send({\n requestId: req.id,\n status: 500,\n body: err.message,\n })\n })\n )\n\n await this._deploy(api, httpTunnelUrl)\n await this._runBuild()\n const worker = await this._spawnWorker(env, port)\n\n try {\n const watcher = await utils.filewatcher.FileWatcher.watch(\n this.argv.workDir,\n async (events) => {\n const typescriptEvents = events.filter((e) => pathlib.extname(e.path) === '.ts')\n if (typescriptEvents.length === 0) {\n return\n }\n\n this.logger.log('Changes detected, rebuilding')\n await this._restart(api, worker, httpTunnelUrl)\n },\n {\n ignore: [this.projectPaths.abs.outDir],\n }\n )\n\n await Promise.race([worker.wait(), watcher.wait(), tunnel.wait()])\n await watcher.close()\n // TODO: ensure all processes are closed\n } catch (thrown) {\n throw errors.BotpressCLIError.wrap(thrown, 'An error occurred while running the dev server')\n } finally {\n if (worker.running) {\n await worker.kill()\n }\n }\n }\n\n private _restart = async (api: ApiClient, worker: Worker, tunnelUrl: string) => {\n await this._deploy(api, tunnelUrl)\n\n try {\n await this._runBuild()\n } catch (thrown) {\n const error = errors.BotpressCLIError.wrap(thrown, 'Build failed')\n this.logger.error(error.message)\n return\n }\n\n await worker.reload()\n }\n\n private _deploy = async (api: ApiClient, tunnelUrl: string) => {\n const integrationDef = await this.readIntegrationDefinitionFromFS()\n if (integrationDef) {\n this._checkSecrets(integrationDef)\n await this._deployDevIntegration(api, tunnelUrl, integrationDef)\n } else {\n await this._deployDevBot(api, tunnelUrl)\n }\n }\n\n private _checkSecrets(integrationDef: IntegrationDefinition) {\n const initialSecrets = this._initialDef?.secrets ?? []\n const currentSecrets = integrationDef.secrets ?? []\n const newSecrets = currentSecrets.filter((s) => !initialSecrets.includes(s))\n if (newSecrets.length > 0) {\n throw new errors.BotpressCLIError('Secrets were added while the server was running. A restart is required.')\n }\n }\n\n private _spawnWorker = async (env: Record<string, string>, port: number) => {\n const outfile = this.projectPaths.abs.outFile\n const importPath = utils.path.toUnix(outfile)\n const requireFrom = utils.path.rmExtension(importPath)\n const code = `require('${requireFrom}').default.start(${port})`\n const worker = await Worker.spawn(\n {\n type: 'code',\n code,\n env,\n },\n this.logger\n ).catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, 'Could not start dev worker')\n })\n\n return worker\n }\n\n private _runBuild() {\n return new BuildCommand(this.api, this.prompt, this.logger, this.argv).run()\n }\n\n private async _deployDevIntegration(\n api: ApiClient,\n externalUrl: string,\n integrationDef: IntegrationDefinition\n ): Promise<void> {\n const devId = await this.projectCache.get('devId')\n\n let integration: bpclient.Integration | undefined = undefined\n\n if (devId) {\n const resp = await api.client.getIntegration({ id: devId }).catch(async (thrown) => {\n const err = errors.BotpressCLIError.wrap(thrown, `Could not find existing dev integration with id \"${devId}\"`)\n this.logger.warn(err.message)\n return { integration: undefined }\n })\n\n if (resp.integration?.dev) {\n integration = resp.integration\n } else {\n await this.projectCache.rm('devId')\n }\n }\n\n const line = this.logger.line()\n line.started(`Deploying dev integration ${chalk.bold(integrationDef.name)}...`)\n if (integration) {\n const resp = await api.client\n .updateIntegration({ ...integrationDef, id: integration.id, url: externalUrl })\n .catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, `Could not update dev integration \"${integrationDef.name}\"`)\n })\n integration = resp.integration\n } else {\n const resp = await api.client\n .createIntegration({ ...integrationDef, dev: true, url: externalUrl })\n .catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, `Could not deploy dev integration \"${integrationDef.name}\"`)\n })\n integration = resp.integration\n }\n\n line.success(`Dev Integration deployed with id \"${integration.id}\"`)\n await this.projectCache.set('devId', integration.id)\n }\n\n private async _deployDevBot(api: ApiClient, externalUrl: string): Promise<void> {\n const devId = await this.projectCache.get('devId')\n\n let bot: bpclient.Bot | undefined = undefined\n\n if (devId) {\n const resp = await api.client.getBot({ id: devId }).catch(async (thrown) => {\n const err = errors.BotpressCLIError.wrap(thrown, `Could not find existing dev bot with id \"${devId}\"`)\n this.logger.warn(err.message)\n return { bot: undefined }\n })\n\n if (resp.bot?.dev) {\n bot = resp.bot\n } else {\n await this.projectCache.rm('devId')\n }\n }\n\n if (!bot) {\n const createLine = this.logger.line()\n createLine.started('Creating dev bot...')\n const resp = await api.client\n .createBot({\n dev: true,\n url: externalUrl,\n })\n .catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, 'Could not deploy dev bot')\n })\n\n bot = resp.bot\n createLine.success(`Dev Bot created with id \"${bot.id}\"`)\n await this.projectCache.set('devId', bot.id)\n }\n\n const outfile = this.projectPaths.abs.outFile\n const { default: botImpl } = utils.require.requireJsFile<{ default: BotImpl }>(outfile)\n\n const integrations = this.prepareIntegrations(botImpl, bot)\n\n const updateLine = this.logger.line()\n updateLine.started('Deploying dev bot...')\n\n const { bot: updatedBot } = await api.client\n .updateBot({ id: bot.id, integrations, url: externalUrl })\n .catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, 'Could not deploy dev bot')\n })\n updateLine.success(`Dev Bot deployed with id \"${updatedBot.id}\"`)\n\n this.displayWebhookUrls(updatedBot)\n }\n\n private _forwardTunnelRequest = async (baseUrl: string, request: TunnelRequest): Promise<TunnelResponse> => {\n const axiosConfig = {\n method: request.method,\n url: this._formatLocalUrl(baseUrl, request),\n headers: request.headers,\n data: request.body,\n responseType: 'text',\n validateStatus: () => true,\n } satisfies AxiosRequestConfig\n\n this.logger.debug(`Forwarding request to ${axiosConfig.url}`)\n const response = await axios(axiosConfig)\n this.logger.debug('Sending back response up the tunnel')\n\n return {\n requestId: request.id,\n status: response.status,\n headers: this._getHeaders(response.headers),\n body: response.data,\n }\n }\n\n private _formatLocalUrl = (baseUrl: string, req: TunnelRequest): string => {\n if (req.query) {\n return `${baseUrl}${req.path}?${req.query}`\n }\n return `${baseUrl}${req.path}`\n }\n\n private _getHeaders = (res: AxiosResponse['headers']): TunnelResponse['headers'] => {\n const headers: TunnelResponse['headers'] = {}\n for (const key in res) {\n if (typeof res[key] === 'string' || typeof res[key] === 'number') {\n headers[key] = res[key]\n }\n }\n return headers\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type * as bpclient from '@botpress/client'\nimport type { Bot as BotImpl, IntegrationDefinition } from '@botpress/sdk'\nimport { TunnelRequest, TunnelResponse } from '@bpinternal/tunnel'\nimport axios, { AxiosRequestConfig, AxiosResponse } from 'axios'\nimport chalk from 'chalk'\nimport * as pathlib from 'path'\nimport * as uuid from 'uuid'\nimport type { ApiClient } from '../api-client'\nimport type commandDefinitions from '../command-definitions'\nimport * as errors from '../errors'\nimport * as utils from '../utils'\nimport { Worker } from '../worker'\nimport { BuildCommand } from './build-command'\nimport { ProjectCommand } from './project-command'\n\nconst DEFAULT_BOT_PORT = 8075\nconst DEFAULT_INTEGRATION_PORT = 8076\n\nexport type DevCommandDefinition = typeof commandDefinitions.dev\nexport class DevCommand extends ProjectCommand<DevCommandDefinition> {\n private _initialDef: IntegrationDefinition | undefined = undefined\n\n public async run(): Promise<void> {\n this.logger.warn('This command is experimental and subject to breaking changes without notice.')\n\n const api = await this.ensureLoginAndCreateClient(this.argv)\n\n this._initialDef = await this.readIntegrationDefinitionFromFS()\n\n let env: Record<string, string> = {\n ...process.env,\n BP_API_URL: api.url,\n BP_TOKEN: api.token,\n }\n\n let defaultPort = DEFAULT_BOT_PORT\n if (this._initialDef) {\n defaultPort = DEFAULT_INTEGRATION_PORT\n const secrets = await this.promptSecrets(this._initialDef, this.argv)\n env = { ...env, ...secrets }\n }\n\n const port = this.argv.port ?? defaultPort\n\n const urlParseResult = utils.url.parse(this.argv.tunnelUrl)\n if (urlParseResult.status === 'error') {\n throw new errors.BotpressCLIError(`Invalid tunnel URL: ${urlParseResult.error}`)\n }\n\n const tunnelId = uuid.v4()\n\n const { url: parsedTunnelUrl } = urlParseResult\n const isSecured = parsedTunnelUrl.protocol === 'https' || parsedTunnelUrl.protocol === 'wss'\n\n const wsTunnelUrl: string = utils.url.format({ ...parsedTunnelUrl, protocol: isSecured ? 'wss' : 'ws' })\n const httpTunnelUrl: string = utils.url.format({\n ...parsedTunnelUrl,\n protocol: isSecured ? 'https' : 'http',\n path: `/${tunnelId}`,\n })\n\n const supervisor = new utils.tunnel.TunnelSupervisor(wsTunnelUrl, tunnelId, this.logger)\n supervisor.events.on('connected', ({ tunnel }) => {\n tunnel.events.on(\n 'request',\n (req) =>\n void this._forwardTunnelRequest(`http://localhost:${port}`, req)\n .then((res) => {\n tunnel.send(res)\n })\n .catch((thrown) => {\n const err = errors.BotpressCLIError.wrap(thrown, 'An error occurred while handling request')\n this.logger.error(err.message)\n tunnel.send({\n requestId: req.id,\n status: 500,\n body: err.message,\n })\n })\n )\n })\n await supervisor.start()\n\n await this._deploy(api, httpTunnelUrl)\n await this._runBuild()\n const worker = await this._spawnWorker(env, port)\n\n try {\n const watcher = await utils.filewatcher.FileWatcher.watch(\n this.argv.workDir,\n async (events) => {\n const typescriptEvents = events.filter((e) => pathlib.extname(e.path) === '.ts')\n if (typescriptEvents.length === 0) {\n return\n }\n\n this.logger.log('Changes detected, rebuilding')\n await this._restart(api, worker, httpTunnelUrl)\n },\n {\n ignore: [this.projectPaths.abs.outDir],\n }\n )\n\n await Promise.race([worker.wait(), watcher.wait(), supervisor.wait()])\n\n if (worker.running) {\n await worker.kill()\n }\n await watcher.close()\n supervisor.close()\n } catch (thrown) {\n throw errors.BotpressCLIError.wrap(thrown, 'An error occurred while running the dev server')\n } finally {\n if (worker.running) {\n await worker.kill()\n }\n }\n }\n\n private _restart = async (api: ApiClient, worker: Worker, tunnelUrl: string) => {\n await this._deploy(api, tunnelUrl)\n\n try {\n await this._runBuild()\n } catch (thrown) {\n const error = errors.BotpressCLIError.wrap(thrown, 'Build failed')\n this.logger.error(error.message)\n return\n }\n\n await worker.reload()\n }\n\n private _deploy = async (api: ApiClient, tunnelUrl: string) => {\n const integrationDef = await this.readIntegrationDefinitionFromFS()\n if (integrationDef) {\n this._checkSecrets(integrationDef)\n await this._deployDevIntegration(api, tunnelUrl, integrationDef)\n } else {\n await this._deployDevBot(api, tunnelUrl)\n }\n }\n\n private _checkSecrets(integrationDef: IntegrationDefinition) {\n const initialSecrets = this._initialDef?.secrets ?? []\n const currentSecrets = integrationDef.secrets ?? []\n const newSecrets = currentSecrets.filter((s) => !initialSecrets.includes(s))\n if (newSecrets.length > 0) {\n throw new errors.BotpressCLIError('Secrets were added while the server was running. A restart is required.')\n }\n }\n\n private _spawnWorker = async (env: Record<string, string>, port: number) => {\n const outfile = this.projectPaths.abs.outFile\n const importPath = utils.path.toUnix(outfile)\n const requireFrom = utils.path.rmExtension(importPath)\n const code = `require('${requireFrom}').default.start(${port})`\n const worker = await Worker.spawn(\n {\n type: 'code',\n code,\n env,\n },\n this.logger\n ).catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, 'Could not start dev worker')\n })\n\n return worker\n }\n\n private _runBuild() {\n return new BuildCommand(this.api, this.prompt, this.logger, this.argv).run()\n }\n\n private async _deployDevIntegration(\n api: ApiClient,\n externalUrl: string,\n integrationDef: IntegrationDefinition\n ): Promise<void> {\n const devId = await this.projectCache.get('devId')\n\n let integration: bpclient.Integration | undefined = undefined\n\n if (devId) {\n const resp = await api.client.getIntegration({ id: devId }).catch(async (thrown) => {\n const err = errors.BotpressCLIError.wrap(thrown, `Could not find existing dev integration with id \"${devId}\"`)\n this.logger.warn(err.message)\n return { integration: undefined }\n })\n\n if (resp.integration?.dev) {\n integration = resp.integration\n } else {\n await this.projectCache.rm('devId')\n }\n }\n\n const line = this.logger.line()\n line.started(`Deploying dev integration ${chalk.bold(integrationDef.name)}...`)\n if (integration) {\n const resp = await api.client\n .updateIntegration({ ...integrationDef, id: integration.id, url: externalUrl })\n .catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, `Could not update dev integration \"${integrationDef.name}\"`)\n })\n integration = resp.integration\n } else {\n const resp = await api.client\n .createIntegration({ ...integrationDef, dev: true, url: externalUrl })\n .catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, `Could not deploy dev integration \"${integrationDef.name}\"`)\n })\n integration = resp.integration\n }\n\n line.success(`Dev Integration deployed with id \"${integration.id}\"`)\n await this.projectCache.set('devId', integration.id)\n }\n\n private async _deployDevBot(api: ApiClient, externalUrl: string): Promise<void> {\n const devId = await this.projectCache.get('devId')\n\n let bot: bpclient.Bot | undefined = undefined\n\n if (devId) {\n const resp = await api.client.getBot({ id: devId }).catch(async (thrown) => {\n const err = errors.BotpressCLIError.wrap(thrown, `Could not find existing dev bot with id \"${devId}\"`)\n this.logger.warn(err.message)\n return { bot: undefined }\n })\n\n if (resp.bot?.dev) {\n bot = resp.bot\n } else {\n await this.projectCache.rm('devId')\n }\n }\n\n if (!bot) {\n const createLine = this.logger.line()\n createLine.started('Creating dev bot...')\n const resp = await api.client\n .createBot({\n dev: true,\n url: externalUrl,\n })\n .catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, 'Could not deploy dev bot')\n })\n\n bot = resp.bot\n createLine.success(`Dev Bot created with id \"${bot.id}\"`)\n await this.projectCache.set('devId', bot.id)\n }\n\n const outfile = this.projectPaths.abs.outFile\n const { default: botImpl } = utils.require.requireJsFile<{ default: BotImpl }>(outfile)\n\n const integrations = this.prepareIntegrations(botImpl, bot)\n\n const updateLine = this.logger.line()\n updateLine.started('Deploying dev bot...')\n\n const { bot: updatedBot } = await api.client\n .updateBot({\n ...botImpl.definition,\n id: bot.id,\n integrations,\n url: externalUrl,\n })\n .catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, 'Could not deploy dev bot')\n })\n updateLine.success(`Dev Bot deployed with id \"${updatedBot.id}\"`)\n\n this.displayWebhookUrls(updatedBot)\n }\n\n private _forwardTunnelRequest = async (baseUrl: string, request: TunnelRequest): Promise<TunnelResponse> => {\n const axiosConfig = {\n method: request.method,\n url: this._formatLocalUrl(baseUrl, request),\n headers: request.headers,\n data: request.body,\n responseType: 'text',\n validateStatus: () => true,\n } satisfies AxiosRequestConfig\n\n this.logger.debug(`Forwarding request to ${axiosConfig.url}`)\n const response = await axios(axiosConfig)\n this.logger.debug('Sending back response up the tunnel')\n\n return {\n requestId: request.id,\n status: response.status,\n headers: this._getHeaders(response.headers),\n body: response.data,\n }\n }\n\n private _formatLocalUrl = (baseUrl: string, req: TunnelRequest): string => {\n if (req.query) {\n return `${baseUrl}${req.path}?${req.query}`\n }\n return `${baseUrl}${req.path}`\n }\n\n private _getHeaders = (res: AxiosResponse['headers']): TunnelResponse['headers'] => {\n const headers: TunnelResponse['headers'] = {}\n for (const key in res) {\n if (typeof res[key] === 'string' || typeof res[key] === 'number') {\n headers[key] = res[key]\n }\n }\n return headers\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["chalk", "axios"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/command-implementations/project-command.ts"],
4
- "sourcesContent": ["import type * as bpclient from '@botpress/client'\nimport type { IntegrationDefinition, Bot as BotImpl } from '@botpress/sdk'\nimport type { YargsConfig } from '@bpinternal/yargs-extra'\nimport chalk from 'chalk'\nimport fs from 'fs'\nimport _ from 'lodash'\nimport pathlib from 'path'\nimport * as codegen from '../code-generation'\nimport type * as config from '../config'\nimport * as consts from '../consts'\nimport * as errors from '../errors'\nimport type { CommandArgv, CommandDefinition } from '../typings'\nimport * as utils from '../utils'\nimport { GlobalCommand } from './global-command'\n\nexport type ProjectCommandDefinition = CommandDefinition<typeof config.schemas.project>\nexport type ProjectCache = { botId: string; devId: string }\n\ntype ConfigurableProjectPaths = { entryPoint: string; outDir: string; workDir: string }\ntype ConstantProjectPaths = typeof consts.fromOutDir & typeof consts.fromWorkDir\ntype AllProjectPaths = ConfigurableProjectPaths & ConstantProjectPaths\n\nclass ProjectPaths extends utils.path.PathStore<keyof AllProjectPaths> {\n public constructor(argv: CommandArgv<ProjectCommandDefinition>) {\n const absWorkDir = utils.path.absoluteFrom(utils.path.cwd(), argv.workDir)\n const absEntrypoint = utils.path.absoluteFrom(absWorkDir, argv.entryPoint)\n const absOutDir = utils.path.absoluteFrom(absWorkDir, argv.outDir)\n super({\n workDir: absWorkDir,\n entryPoint: absEntrypoint,\n outDir: absOutDir,\n ..._.mapValues(consts.fromOutDir, (p) => utils.path.absoluteFrom(absOutDir, p)),\n ..._.mapValues(consts.fromWorkDir, (p) => utils.path.absoluteFrom(absWorkDir, p)),\n })\n }\n}\n\nexport abstract class ProjectCommand<C extends ProjectCommandDefinition> extends GlobalCommand<C> {\n protected get projectPaths() {\n return new ProjectPaths(this.argv)\n }\n\n protected get projectCache() {\n return new utils.cache.FSKeyValueCache<ProjectCache>(this.projectPaths.abs.projectCacheFile)\n }\n\n protected async readIntegrationDefinitionFromFS(): Promise<IntegrationDefinition | undefined> {\n const abs = this.projectPaths.abs\n const rel = this.projectPaths.rel('workDir')\n\n if (!fs.existsSync(abs.definition)) {\n this.logger.debug(`Integration definition not found at ${rel.definition}`)\n return\n }\n\n const { outputFiles } = await utils.esbuild.buildEntrypoint({\n cwd: abs.workDir,\n outfile: '',\n entrypoint: rel.definition,\n write: false,\n })\n\n const artifact = outputFiles[0]\n if (!artifact) {\n throw new errors.BotpressCLIError('Could not read integration definition')\n }\n\n const { default: definition } = utils.require.requireJsCode<{ default: IntegrationDefinition }>(artifact.text)\n return definition\n }\n\n protected async writeGeneratedFilesToOutFolder(files: codegen.File[]) {\n for (const file of files) {\n const filePath = utils.path.absoluteFrom(this.projectPaths.abs.outDir, file.path)\n const dirPath = pathlib.dirname(filePath)\n await fs.promises.mkdir(dirPath, { recursive: true })\n await fs.promises.writeFile(filePath, file.content)\n }\n }\n\n protected prepareIntegrations(\n botImpl: BotImpl,\n botInfo: bpclient.Bot\n ): Parameters<bpclient.Client['updateBot']>[0]['integrations'] {\n const { integrations: integrationList } = botImpl.definition\n\n const integrationsToUninstall = _(botInfo.integrations)\n .keys()\n .filter((key) => !integrationList?.map((i) => i.id).includes(key))\n .zipObject()\n .mapValues(() => null)\n .value()\n\n const integrationsToInstall = _(integrationList ?? [])\n .keyBy((i) => i.id)\n .mapValues(({ enabled, configuration }) => ({ enabled, configuration }))\n .value()\n\n return { ...integrationsToUninstall, ...integrationsToInstall } as Record<string, any> // TODO: fix client typings\n }\n\n protected displayWebhookUrls(bot: bpclient.Bot) {\n if (!_.keys(bot.integrations).length) {\n this.logger.debug('No integrations in bot')\n return\n }\n\n this.logger.log('Integrations:')\n for (const integration of Object.values(bot.integrations)) {\n if (!integration.enabled) {\n this.logger.log(`${chalk.grey(integration.name)} ${chalk.italic('(disabled)')}: ${integration.webhookUrl}`, {\n prefix: { symbol: '\u25CB', indent: 2 },\n })\n } else {\n this.logger.log(`${chalk.bold(integration.name)} : ${integration.webhookUrl}`, {\n prefix: { symbol: '\u25CF', indent: 2 },\n })\n }\n }\n }\n\n protected async promptSecrets(\n integrationDef: IntegrationDefinition,\n argv: YargsConfig<typeof config.schemas.secrets>\n ): Promise<Record<string, string>> {\n const { secrets: secretDefinitions } = integrationDef\n if (!secretDefinitions) {\n return {}\n }\n\n const secretArgv = this._parseArgvSecrets(argv.secrets)\n const invalidSecret = Object.keys(secretArgv).find((s) => !secretDefinitions.includes(s))\n if (invalidSecret) {\n throw new errors.BotpressCLIError(`Secret ${invalidSecret} is not defined in integration definition`)\n }\n\n const values: Record<string, string> = {}\n for (const secretDef of secretDefinitions) {\n const argvSecret = secretArgv[secretDef]\n if (argvSecret) {\n this.logger.debug(`Using secret \"${secretDef}\" from argv`)\n values[secretDef] = argvSecret\n continue\n }\n\n const prompted = await this.prompt.text(`Enter value for secret \"${secretDef}\"`)\n if (!prompted) {\n throw new errors.BotpressCLIError('Secret is required')\n }\n values[secretDef] = prompted\n }\n\n const envVariables = _.mapKeys(values, (_v, k) => codegen.secretEnvVariableName(k))\n return envVariables\n }\n\n private _parseArgvSecrets(argvSecrets: string[]): Record<string, string> {\n const parsed: Record<string, string> = {}\n for (const secret of argvSecrets) {\n const [key, value] = this._splitOnce(secret, '=')\n if (!value) {\n throw new errors.BotpressCLIError(\n `Secret \"${key}\" is missing a value. Expected format: \"SECRET_NAME=secretValue\"`\n )\n }\n parsed[key!] = value\n }\n\n return parsed\n }\n\n private _splitOnce = (text: string, separator: string): [string, string | undefined] => {\n const index = text.indexOf(separator)\n if (index === -1) {\n return [text, undefined]\n }\n return [text.slice(0, index), text.slice(index + 1)]\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type * as bpclient from '@botpress/client'\nimport type { IntegrationDefinition, Bot as BotImpl } from '@botpress/sdk'\nimport type { YargsConfig } from '@bpinternal/yargs-extra'\nimport chalk from 'chalk'\nimport fs from 'fs'\nimport _ from 'lodash'\nimport pathlib from 'path'\nimport * as codegen from '../code-generation'\nimport type * as config from '../config'\nimport * as consts from '../consts'\nimport * as errors from '../errors'\nimport type { CommandArgv, CommandDefinition } from '../typings'\nimport * as utils from '../utils'\nimport { GlobalCommand } from './global-command'\n\ntype IntegrationInstances = Parameters<bpclient.Client['updateBot']>[0]['integrations']\n\nexport type ProjectCommandDefinition = CommandDefinition<typeof config.schemas.project>\nexport type ProjectCache = { botId: string; devId: string }\n\ntype ConfigurableProjectPaths = { entryPoint: string; outDir: string; workDir: string }\ntype ConstantProjectPaths = typeof consts.fromOutDir & typeof consts.fromWorkDir\ntype AllProjectPaths = ConfigurableProjectPaths & ConstantProjectPaths\n\nclass ProjectPaths extends utils.path.PathStore<keyof AllProjectPaths> {\n public constructor(argv: CommandArgv<ProjectCommandDefinition>) {\n const absWorkDir = utils.path.absoluteFrom(utils.path.cwd(), argv.workDir)\n const absEntrypoint = utils.path.absoluteFrom(absWorkDir, argv.entryPoint)\n const absOutDir = utils.path.absoluteFrom(absWorkDir, argv.outDir)\n super({\n workDir: absWorkDir,\n entryPoint: absEntrypoint,\n outDir: absOutDir,\n ..._.mapValues(consts.fromOutDir, (p) => utils.path.absoluteFrom(absOutDir, p)),\n ..._.mapValues(consts.fromWorkDir, (p) => utils.path.absoluteFrom(absWorkDir, p)),\n })\n }\n}\n\nexport abstract class ProjectCommand<C extends ProjectCommandDefinition> extends GlobalCommand<C> {\n protected get projectPaths() {\n return new ProjectPaths(this.argv)\n }\n\n protected get projectCache() {\n return new utils.cache.FSKeyValueCache<ProjectCache>(this.projectPaths.abs.projectCacheFile)\n }\n\n protected async readIntegrationDefinitionFromFS(): Promise<IntegrationDefinition | undefined> {\n const abs = this.projectPaths.abs\n const rel = this.projectPaths.rel('workDir')\n\n if (!fs.existsSync(abs.definition)) {\n this.logger.debug(`Integration definition not found at ${rel.definition}`)\n return\n }\n\n const { outputFiles } = await utils.esbuild.buildEntrypoint({\n cwd: abs.workDir,\n outfile: '',\n entrypoint: rel.definition,\n write: false,\n })\n\n const artifact = outputFiles[0]\n if (!artifact) {\n throw new errors.BotpressCLIError('Could not read integration definition')\n }\n\n const { default: definition } = utils.require.requireJsCode<{ default: IntegrationDefinition }>(artifact.text)\n return definition\n }\n\n protected async writeGeneratedFilesToOutFolder(files: codegen.File[]) {\n for (const file of files) {\n const filePath = utils.path.absoluteFrom(this.projectPaths.abs.outDir, file.path)\n const dirPath = pathlib.dirname(filePath)\n await fs.promises.mkdir(dirPath, { recursive: true })\n await fs.promises.writeFile(filePath, file.content)\n }\n }\n\n protected prepareIntegrations(botImpl: BotImpl, botInfo: bpclient.Bot): IntegrationInstances {\n const { integrations: integrationList } = botImpl.definition\n\n const integrationsToUninstall: IntegrationInstances = _(botInfo.integrations)\n .keys()\n .filter((key) => !integrationList?.map((i) => i.id).includes(key))\n .zipObject()\n .mapValues(() => null)\n .value()\n\n const integrationsToInstall: IntegrationInstances = _(integrationList ?? [])\n .keyBy((i) => i.id)\n .mapValues(({ enabled, configuration }) => ({ enabled, configuration }))\n .value()\n\n return { ...integrationsToUninstall, ...integrationsToInstall }\n }\n\n protected displayWebhookUrls(bot: bpclient.Bot) {\n if (!_.keys(bot.integrations).length) {\n this.logger.debug('No integrations in bot')\n return\n }\n\n this.logger.log('Integrations:')\n for (const integration of Object.values(bot.integrations)) {\n if (!integration.enabled) {\n this.logger.log(`${chalk.grey(integration.name)} ${chalk.italic('(disabled)')}: ${integration.webhookUrl}`, {\n prefix: { symbol: '\u25CB', indent: 2 },\n })\n } else {\n this.logger.log(`${chalk.bold(integration.name)} : ${integration.webhookUrl}`, {\n prefix: { symbol: '\u25CF', indent: 2 },\n })\n }\n }\n }\n\n protected async promptSecrets(\n integrationDef: IntegrationDefinition,\n argv: YargsConfig<typeof config.schemas.secrets>\n ): Promise<Record<string, string>> {\n const { secrets: secretDefinitions } = integrationDef\n if (!secretDefinitions) {\n return {}\n }\n\n const secretArgv = this._parseArgvSecrets(argv.secrets)\n const invalidSecret = Object.keys(secretArgv).find((s) => !secretDefinitions.includes(s))\n if (invalidSecret) {\n throw new errors.BotpressCLIError(`Secret ${invalidSecret} is not defined in integration definition`)\n }\n\n const values: Record<string, string> = {}\n for (const secretDef of secretDefinitions) {\n const argvSecret = secretArgv[secretDef]\n if (argvSecret) {\n this.logger.debug(`Using secret \"${secretDef}\" from argv`)\n values[secretDef] = argvSecret\n continue\n }\n\n const prompted = await this.prompt.text(`Enter value for secret \"${secretDef}\"`)\n if (!prompted) {\n throw new errors.BotpressCLIError('Secret is required')\n }\n values[secretDef] = prompted\n }\n\n const envVariables = _.mapKeys(values, (_v, k) => codegen.secretEnvVariableName(k))\n return envVariables\n }\n\n private _parseArgvSecrets(argvSecrets: string[]): Record<string, string> {\n const parsed: Record<string, string> = {}\n for (const secret of argvSecrets) {\n const [key, value] = this._splitOnce(secret, '=')\n if (!value) {\n throw new errors.BotpressCLIError(\n `Secret \"${key}\" is missing a value. Expected format: \"SECRET_NAME=secretValue\"`\n )\n }\n parsed[key!] = value\n }\n\n return parsed\n }\n\n private _splitOnce = (text: string, separator: string): [string, string | undefined] => {\n const index = text.indexOf(separator)\n if (index === -1) {\n return [text, undefined]\n }\n return [text.slice(0, index), text.slice(index + 1)]\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["_", "fs", "pathlib", "chalk"]
7
7
  }
@@ -33,6 +33,7 @@ __export(utils_exports, {
33
33
  prompt: () => prompt,
34
34
  records: () => records,
35
35
  require: () => require2,
36
+ tunnel: () => tunnel,
36
37
  url: () => url
37
38
  });
38
39
  module.exports = __toCommonJS(utils_exports);
@@ -46,6 +47,7 @@ var casing = __toESM(require("./case-utils"));
46
47
  var prompt = __toESM(require("./prompt-utils"));
47
48
  var records = __toESM(require("./record-utils"));
48
49
  var url = __toESM(require("./url-utils"));
50
+ var tunnel = __toESM(require("./tunnel-utils"));
49
51
  // Annotate the CommonJS export names for ESM import in node:
50
52
  0 && (module.exports = {
51
53
  cache,
@@ -57,6 +59,7 @@ var url = __toESM(require("./url-utils"));
57
59
  prompt,
58
60
  records,
59
61
  require,
62
+ tunnel,
60
63
  url
61
64
  });
62
65
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/index.ts"],
4
- "sourcesContent": ["export * as esbuild from './esbuild-utils'\nexport * as path from './path-utils'\nexport * as require from './require-utils'\nexport * as filewatcher from './file-watcher'\nexport * as emitter from './event-emitter'\nexport * as cache from './cache-utils'\nexport * as casing from './case-utils'\nexport * as prompt from './prompt-utils'\nexport * as records from './record-utils'\nexport * as url from './url-utils'\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAAA;AAAA,EAAA;AAAA;AAAA;AAAA,cAAyB;AACzB,WAAsB;AACtB,IAAAA,WAAyB;AACzB,kBAA6B;AAC7B,cAAyB;AACzB,YAAuB;AACvB,aAAwB;AACxB,aAAwB;AACxB,cAAyB;AACzB,UAAqB;",
4
+ "sourcesContent": ["export * as esbuild from './esbuild-utils'\nexport * as path from './path-utils'\nexport * as require from './require-utils'\nexport * as filewatcher from './file-watcher'\nexport * as emitter from './event-emitter'\nexport * as cache from './cache-utils'\nexport * as casing from './case-utils'\nexport * as prompt from './prompt-utils'\nexport * as records from './record-utils'\nexport * as url from './url-utils'\nexport * as tunnel from './tunnel-utils'\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,cAAyB;AACzB,WAAsB;AACtB,IAAAA,WAAyB;AACzB,kBAA6B;AAC7B,cAAyB;AACzB,YAAuB;AACvB,aAAwB;AACxB,aAAwB;AACxB,cAAyB;AACzB,UAAqB;AACrB,aAAwB;",
6
6
  "names": ["require"]
7
7
  }
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var tunnel_utils_exports = {};
20
+ __export(tunnel_utils_exports, {
21
+ ReconnectionFailedError: () => ReconnectionFailedError,
22
+ TunnelSupervisor: () => TunnelSupervisor
23
+ });
24
+ module.exports = __toCommonJS(tunnel_utils_exports);
25
+ var import_tunnel = require("@bpinternal/tunnel");
26
+ var import_event_emitter = require("./event-emitter");
27
+ class ReconnectionFailedError extends Error {
28
+ constructor(event) {
29
+ const reason = ReconnectionFailedError._reason(event);
30
+ super(`Reconnection failed: ${reason}`);
31
+ this.event = event;
32
+ }
33
+ static _reason(event) {
34
+ if (event.type === "error") {
35
+ return "error";
36
+ }
37
+ if (event.type === "close") {
38
+ return `${event.ev.code} ${event.ev.reason}`;
39
+ }
40
+ return "init";
41
+ }
42
+ }
43
+ class TunnelSupervisor {
44
+ constructor(_tunnelUrl, _tunnelId, _logger) {
45
+ this._tunnelUrl = _tunnelUrl;
46
+ this._tunnelId = _tunnelId;
47
+ this._logger = _logger;
48
+ }
49
+ _tunnel;
50
+ _closed = false;
51
+ _started = false;
52
+ events = new import_event_emitter.EventEmitter();
53
+ async start() {
54
+ if (this._closed) {
55
+ throw new Error("Tunnel is closed");
56
+ }
57
+ if (this._started) {
58
+ throw new Error("Tunnel is already started");
59
+ }
60
+ this._started = true;
61
+ const tunnel = await this._reconnect({ type: "init", ev: null });
62
+ this._tunnel = tunnel;
63
+ }
64
+ get closed() {
65
+ return this._closed;
66
+ }
67
+ async wait() {
68
+ if (this._closed) {
69
+ throw new Error("Tunnel is closed");
70
+ }
71
+ return new Promise((resolve, reject) => {
72
+ this.events.on("connectionFailed", (ev) => {
73
+ reject(new ReconnectionFailedError(ev));
74
+ });
75
+ this.events.on("manuallyClosed", () => {
76
+ resolve();
77
+ });
78
+ });
79
+ }
80
+ close() {
81
+ if (this._closed) {
82
+ return;
83
+ }
84
+ this._closed = true;
85
+ this._tunnel?.close();
86
+ this.events.emit("manuallyClosed", null);
87
+ }
88
+ _reconnectSync(ev) {
89
+ void this._reconnect(ev).then((t) => {
90
+ this._tunnel = t;
91
+ }).catch(() => this.events.emit("connectionFailed", ev));
92
+ }
93
+ async _reconnect(ev) {
94
+ const newTunnel = async () => {
95
+ const tunnel2 = await import_tunnel.TunnelTail.new(this._tunnelUrl, this._tunnelId);
96
+ this._registerListeners(tunnel2);
97
+ this.events.emit("connected", { tunnel: tunnel2, ev });
98
+ return tunnel2;
99
+ };
100
+ if (ev.type === "init") {
101
+ return newTunnel();
102
+ }
103
+ const line = this._logger.line();
104
+ line.started("Reconnecting tunnel...");
105
+ const tunnel = await newTunnel();
106
+ line.success("Reconnected");
107
+ line.commit();
108
+ return tunnel;
109
+ }
110
+ _registerListeners(tunnel) {
111
+ tunnel.events.on("error", ({ target, type }) => {
112
+ this._logger.error(`Tunnel error: ${type}`);
113
+ this._reconnectSync({ type: "error", ev: { target, type } });
114
+ });
115
+ tunnel.events.on("close", ({ code, reason, target, type, wasClean }) => {
116
+ this._logger.error(`Tunnel closed: ${code} ${reason}`);
117
+ this._reconnectSync({ type: "close", ev: { code, reason, target, type, wasClean } });
118
+ });
119
+ }
120
+ }
121
+ // Annotate the CommonJS export names for ESM import in node:
122
+ 0 && (module.exports = {
123
+ ReconnectionFailedError,
124
+ TunnelSupervisor
125
+ });
126
+ //# sourceMappingURL=tunnel-utils.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils/tunnel-utils.ts"],
4
+ "sourcesContent": ["import { TunnelTail, ClientCloseEvent, ClientErrorEvent } from '@bpinternal/tunnel'\nimport { Logger } from '../logger'\nimport { EventEmitter } from './event-emitter'\n\nexport type ReconnectionTriggerEvent =\n | {\n type: 'init'\n ev: null\n }\n | {\n type: 'error'\n ev: ClientErrorEvent\n }\n | {\n type: 'close'\n ev: ClientCloseEvent\n }\n\nexport type ReconnectedEvent = {\n tunnel: TunnelTail\n ev: ReconnectionTriggerEvent\n}\n\nexport class ReconnectionFailedError extends Error {\n public constructor(public readonly event: ReconnectionTriggerEvent) {\n const reason = ReconnectionFailedError._reason(event)\n super(`Reconnection failed: ${reason}`)\n }\n\n private static _reason(event: ReconnectionTriggerEvent): string {\n if (event.type === 'error') {\n return 'error'\n }\n\n if (event.type === 'close') {\n return `${event.ev.code} ${event.ev.reason}`\n }\n\n return 'init'\n }\n}\n\nexport class TunnelSupervisor {\n private _tunnel?: TunnelTail\n private _closed = false\n private _started = false\n\n public readonly events = new EventEmitter<{\n connectionFailed: ReconnectionTriggerEvent\n manuallyClosed: null\n connected: {\n tunnel: TunnelTail\n ev: ReconnectionTriggerEvent\n }\n }>()\n\n constructor(private _tunnelUrl: string, private _tunnelId: string, private _logger: Logger) {}\n\n public async start(): Promise<void> {\n if (this._closed) {\n throw new Error('Tunnel is closed')\n }\n if (this._started) {\n throw new Error('Tunnel is already started')\n }\n\n this._started = true\n const tunnel = await this._reconnect({ type: 'init', ev: null })\n this._tunnel = tunnel\n }\n\n public get closed(): boolean {\n return this._closed\n }\n\n /**\n * @returns Promise that rejects when a reconnection attempt fails and resolves when the tunnel is closed manually\n */\n public async wait(): Promise<void> {\n if (this._closed) {\n throw new Error('Tunnel is closed')\n }\n\n return new Promise((resolve, reject) => {\n this.events.on('connectionFailed', (ev) => {\n reject(new ReconnectionFailedError(ev))\n })\n\n this.events.on('manuallyClosed', () => {\n resolve()\n })\n })\n }\n\n public close(): void {\n if (this._closed) {\n return\n }\n\n this._closed = true\n this._tunnel?.close()\n this.events.emit('manuallyClosed', null)\n }\n\n private _reconnectSync(ev: ReconnectionTriggerEvent): void {\n void this._reconnect(ev)\n .then((t) => {\n this._tunnel = t\n })\n .catch(() => this.events.emit('connectionFailed', ev))\n }\n\n private async _reconnect(ev: ReconnectionTriggerEvent): Promise<TunnelTail> {\n const newTunnel = async () => {\n const tunnel = await TunnelTail.new(this._tunnelUrl, this._tunnelId)\n this._registerListeners(tunnel)\n this.events.emit('connected', { tunnel, ev })\n return tunnel\n }\n\n if (ev.type === 'init') {\n // skip logging on the first connection attempt\n return newTunnel()\n }\n\n const line = this._logger.line()\n line.started('Reconnecting tunnel...')\n const tunnel = await newTunnel()\n line.success('Reconnected')\n line.commit()\n return tunnel\n }\n\n private _registerListeners(tunnel: TunnelTail) {\n tunnel.events.on('error', ({ target, type }) => {\n this._logger.error(`Tunnel error: ${type}`)\n this._reconnectSync({ type: 'error', ev: { target, type } })\n })\n tunnel.events.on('close', ({ code, reason, target, type, wasClean }) => {\n this._logger.error(`Tunnel closed: ${code} ${reason}`)\n this._reconnectSync({ type: 'close', ev: { code, reason, target, type, wasClean } })\n })\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["tunnel"]
7
+ }
@@ -31,6 +31,9 @@ var childProcess = __toESM(require("child_process"));
31
31
  var import_child_entrypoint = require("./child-entrypoint");
32
32
  var import_config = require("./config");
33
33
  var import_is_child = require("./is-child");
34
+ const SPAWN_SHELL_ENV = {
35
+ FORCE_COLOR: "true"
36
+ };
34
37
  const listenForChildSpawn = (child, logger) => new Promise((resolve, reject) => {
35
38
  child.on("spawn", () => {
36
39
  logger.debug(`Child process spawned with pid ${child.pid}`);
@@ -72,6 +75,7 @@ class ChildProcessWrapper {
72
75
  const child = childProcess.fork(import_child_entrypoint.ENTRY_POINT, [], {
73
76
  stdio: "inherit",
74
77
  env: {
78
+ ...SPAWN_SHELL_ENV,
75
79
  [import_is_child.CHILD_ENV_KEY]: import_is_child.CHILD_ENV_VALUE,
76
80
  [import_config.CONFIG_ENV_KEY]: JSON.stringify(config),
77
81
  ...config.env
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/worker/child-wrapper.ts"],
4
- "sourcesContent": ["import * as childProcess from 'child_process'\nimport type { Logger } from '../logger'\nimport { ENTRY_POINT } from './child-entrypoint'\nimport { CONFIG_ENV_KEY, Config } from './config'\nimport { CHILD_ENV_KEY, CHILD_ENV_VALUE, isChildProcess } from './is-child'\n\nexport type ChildOutput = {\n exitCode: number | null\n signal: NodeJS.Signals | null\n}\n\nconst listenForChildSpawn = (child: childProcess.ChildProcess, logger: Logger) =>\n new Promise<void>((resolve, reject) => {\n child.on('spawn', () => {\n logger.debug(`Child process spawned with pid ${child.pid}`)\n resolve()\n })\n child.on('error', (err: Error) => {\n /**\n * The 'error' event is emitted whenever:\n * - The process could not be spawned.\n * - The child process was aborted via the signal option.\n */\n logger.debug(`Child process error: ${err.message}`)\n reject(err)\n })\n })\n\nconst listenForChildExit = (child: childProcess.ChildProcess, logger: Logger) =>\n new Promise<ChildOutput>((resolve, reject) => {\n child.on('disconnect', () => {\n logger.debug('Child process disconnected')\n })\n child.on('close', (exitCode: number | null, signal: NodeJS.Signals | null) => {\n /**\n * this event usually fires after exit unless stdio streams are shared across multiple processes.\n * see https://stackoverflow.com/questions/37522010/difference-between-childprocess-close-exit-events\n */\n logger.debug(`Child process closed with code ${exitCode} and signal ${signal}`)\n })\n child.on('exit', (exitCode: number | null, signal: NodeJS.Signals | null) => {\n logger.debug(`Child process exited with code ${exitCode} and signal ${signal}`)\n resolve({ exitCode, signal })\n })\n child.on('error', (err: Error) => {\n /**\n * The 'error' event is emitted whenever:\n * - The process could not be killed.\n * - The child process was aborted via the signal option.\n */\n logger.debug(`Child process error: ${err.message}`)\n reject(err)\n })\n child.on('message', (message) => {\n logger.debug(`Child process message: ${message}`)\n })\n })\n\n/**\n * Wrapper above child_process.ChildProcess to simplify usage\n */\nexport class ChildProcessWrapper {\n public static async spawn(config: Config, logger: Logger): Promise<ChildProcessWrapper> {\n if (isChildProcess) {\n throw new Error('Cannot spawn child process from child process')\n }\n\n const child = childProcess.fork(ENTRY_POINT, [], {\n stdio: 'inherit',\n env: {\n [CHILD_ENV_KEY]: CHILD_ENV_VALUE,\n [CONFIG_ENV_KEY]: JSON.stringify(config),\n ...config.env,\n },\n })\n\n const childSpawnPromise = listenForChildSpawn(child, logger)\n const childExitPromise = listenForChildExit(child, logger)\n\n const instance = new ChildProcessWrapper(child, childExitPromise)\n\n childExitPromise.finally(() => {\n instance._exited = true\n })\n\n await childSpawnPromise\n\n return instance\n }\n\n private _exited = false\n private constructor(private _child: childProcess.ChildProcess, private _exitPromise: Promise<ChildOutput>) {}\n\n public async kill(): Promise<ChildOutput> {\n if (this._exited) {\n throw new Error('Child process already exited and cannot be killed')\n }\n this._child.kill()\n const res = await this._exitPromise\n return res\n }\n\n public async listen(): Promise<ChildOutput> {\n if (this._exited) {\n throw new Error('Child process already exited and cannot be listened on')\n }\n const res = await this._exitPromise\n return res\n }\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA8B;AAE9B,8BAA4B;AAC5B,oBAAuC;AACvC,sBAA+D;AAO/D,MAAM,sBAAsB,CAAC,OAAkC,WAC7D,IAAI,QAAc,CAAC,SAAS,WAAW;AACrC,QAAM,GAAG,SAAS,MAAM;AACtB,WAAO,MAAM,kCAAkC,MAAM,KAAK;AAC1D,YAAQ;AAAA,EACV,CAAC;AACD,QAAM,GAAG,SAAS,CAAC,QAAe;AAMhC,WAAO,MAAM,wBAAwB,IAAI,SAAS;AAClD,WAAO,GAAG;AAAA,EACZ,CAAC;AACH,CAAC;AAEH,MAAM,qBAAqB,CAAC,OAAkC,WAC5D,IAAI,QAAqB,CAAC,SAAS,WAAW;AAC5C,QAAM,GAAG,cAAc,MAAM;AAC3B,WAAO,MAAM,4BAA4B;AAAA,EAC3C,CAAC;AACD,QAAM,GAAG,SAAS,CAAC,UAAyB,WAAkC;AAK5E,WAAO,MAAM,kCAAkC,uBAAuB,QAAQ;AAAA,EAChF,CAAC;AACD,QAAM,GAAG,QAAQ,CAAC,UAAyB,WAAkC;AAC3E,WAAO,MAAM,kCAAkC,uBAAuB,QAAQ;AAC9E,YAAQ,EAAE,UAAU,OAAO,CAAC;AAAA,EAC9B,CAAC;AACD,QAAM,GAAG,SAAS,CAAC,QAAe;AAMhC,WAAO,MAAM,wBAAwB,IAAI,SAAS;AAClD,WAAO,GAAG;AAAA,EACZ,CAAC;AACD,QAAM,GAAG,WAAW,CAAC,YAAY;AAC/B,WAAO,MAAM,0BAA0B,SAAS;AAAA,EAClD,CAAC;AACH,CAAC;AAKI,MAAM,oBAAoB;AAAA,EA8BvB,YAAoB,QAA2C,cAAoC;AAA/E;AAA2C;AAAA,EAAqC;AAAA,EA7B5G,aAAoB,MAAM,QAAgB,QAA8C;AACtF,QAAI,gCAAgB;AAClB,YAAM,IAAI,MAAM,+CAA+C;AAAA,IACjE;AAEA,UAAM,QAAQ,aAAa,KAAK,qCAAa,CAAC,GAAG;AAAA,MAC/C,OAAO;AAAA,MACP,KAAK;AAAA,QACH,CAAC,gCAAgB;AAAA,QACjB,CAAC,+BAAiB,KAAK,UAAU,MAAM;AAAA,QACvC,GAAG,OAAO;AAAA,MACZ;AAAA,IACF,CAAC;AAED,UAAM,oBAAoB,oBAAoB,OAAO,MAAM;AAC3D,UAAM,mBAAmB,mBAAmB,OAAO,MAAM;AAEzD,UAAM,WAAW,IAAI,oBAAoB,OAAO,gBAAgB;AAEhE,qBAAiB,QAAQ,MAAM;AAC7B,eAAS,UAAU;AAAA,IACrB,CAAC;AAED,UAAM;AAEN,WAAO;AAAA,EACT;AAAA,EAEQ,UAAU;AAAA,EAGlB,MAAa,OAA6B;AACxC,QAAI,KAAK,SAAS;AAChB,YAAM,IAAI,MAAM,mDAAmD;AAAA,IACrE;AACA,SAAK,OAAO,KAAK;AACjB,UAAM,MAAM,MAAM,KAAK;AACvB,WAAO;AAAA,EACT;AAAA,EAEA,MAAa,SAA+B;AAC1C,QAAI,KAAK,SAAS;AAChB,YAAM,IAAI,MAAM,wDAAwD;AAAA,IAC1E;AACA,UAAM,MAAM,MAAM,KAAK;AACvB,WAAO;AAAA,EACT;AACF;",
4
+ "sourcesContent": ["import * as childProcess from 'child_process'\nimport type { Logger } from '../logger'\nimport { ENTRY_POINT } from './child-entrypoint'\nimport { CONFIG_ENV_KEY, Config } from './config'\nimport { CHILD_ENV_KEY, CHILD_ENV_VALUE, isChildProcess } from './is-child'\n\nexport type ChildOutput = {\n exitCode: number | null\n signal: NodeJS.Signals | null\n}\n\nconst SPAWN_SHELL_ENV: Record<string, string> = {\n FORCE_COLOR: 'true', // well-known env var used by most shells to enable color output in child processes\n} as const\n\nconst listenForChildSpawn = (child: childProcess.ChildProcess, logger: Logger) =>\n new Promise<void>((resolve, reject) => {\n child.on('spawn', () => {\n logger.debug(`Child process spawned with pid ${child.pid}`)\n resolve()\n })\n child.on('error', (err: Error) => {\n /**\n * The 'error' event is emitted whenever:\n * - The process could not be spawned.\n * - The child process was aborted via the signal option.\n */\n logger.debug(`Child process error: ${err.message}`)\n reject(err)\n })\n })\n\nconst listenForChildExit = (child: childProcess.ChildProcess, logger: Logger) =>\n new Promise<ChildOutput>((resolve, reject) => {\n child.on('disconnect', () => {\n logger.debug('Child process disconnected')\n })\n child.on('close', (exitCode: number | null, signal: NodeJS.Signals | null) => {\n /**\n * this event usually fires after exit unless stdio streams are shared across multiple processes.\n * see https://stackoverflow.com/questions/37522010/difference-between-childprocess-close-exit-events\n */\n logger.debug(`Child process closed with code ${exitCode} and signal ${signal}`)\n })\n child.on('exit', (exitCode: number | null, signal: NodeJS.Signals | null) => {\n logger.debug(`Child process exited with code ${exitCode} and signal ${signal}`)\n resolve({ exitCode, signal })\n })\n child.on('error', (err: Error) => {\n /**\n * The 'error' event is emitted whenever:\n * - The process could not be killed.\n * - The child process was aborted via the signal option.\n */\n logger.debug(`Child process error: ${err.message}`)\n reject(err)\n })\n child.on('message', (message) => {\n logger.debug(`Child process message: ${message}`)\n })\n })\n\n/**\n * Wrapper above child_process.ChildProcess to simplify usage\n */\nexport class ChildProcessWrapper {\n public static async spawn(config: Config, logger: Logger): Promise<ChildProcessWrapper> {\n if (isChildProcess) {\n throw new Error('Cannot spawn child process from child process')\n }\n\n const child = childProcess.fork(ENTRY_POINT, [], {\n stdio: 'inherit',\n env: {\n ...SPAWN_SHELL_ENV,\n [CHILD_ENV_KEY]: CHILD_ENV_VALUE,\n [CONFIG_ENV_KEY]: JSON.stringify(config),\n ...config.env,\n },\n })\n\n const childSpawnPromise = listenForChildSpawn(child, logger)\n const childExitPromise = listenForChildExit(child, logger)\n\n const instance = new ChildProcessWrapper(child, childExitPromise)\n\n childExitPromise.finally(() => {\n instance._exited = true\n })\n\n await childSpawnPromise\n\n return instance\n }\n\n private _exited = false\n private constructor(private _child: childProcess.ChildProcess, private _exitPromise: Promise<ChildOutput>) {}\n\n public async kill(): Promise<ChildOutput> {\n if (this._exited) {\n throw new Error('Child process already exited and cannot be killed')\n }\n this._child.kill()\n const res = await this._exitPromise\n return res\n }\n\n public async listen(): Promise<ChildOutput> {\n if (this._exited) {\n throw new Error('Child process already exited and cannot be listened on')\n }\n const res = await this._exitPromise\n return res\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA8B;AAE9B,8BAA4B;AAC5B,oBAAuC;AACvC,sBAA+D;AAO/D,MAAM,kBAA0C;AAAA,EAC9C,aAAa;AACf;AAEA,MAAM,sBAAsB,CAAC,OAAkC,WAC7D,IAAI,QAAc,CAAC,SAAS,WAAW;AACrC,QAAM,GAAG,SAAS,MAAM;AACtB,WAAO,MAAM,kCAAkC,MAAM,KAAK;AAC1D,YAAQ;AAAA,EACV,CAAC;AACD,QAAM,GAAG,SAAS,CAAC,QAAe;AAMhC,WAAO,MAAM,wBAAwB,IAAI,SAAS;AAClD,WAAO,GAAG;AAAA,EACZ,CAAC;AACH,CAAC;AAEH,MAAM,qBAAqB,CAAC,OAAkC,WAC5D,IAAI,QAAqB,CAAC,SAAS,WAAW;AAC5C,QAAM,GAAG,cAAc,MAAM;AAC3B,WAAO,MAAM,4BAA4B;AAAA,EAC3C,CAAC;AACD,QAAM,GAAG,SAAS,CAAC,UAAyB,WAAkC;AAK5E,WAAO,MAAM,kCAAkC,uBAAuB,QAAQ;AAAA,EAChF,CAAC;AACD,QAAM,GAAG,QAAQ,CAAC,UAAyB,WAAkC;AAC3E,WAAO,MAAM,kCAAkC,uBAAuB,QAAQ;AAC9E,YAAQ,EAAE,UAAU,OAAO,CAAC;AAAA,EAC9B,CAAC;AACD,QAAM,GAAG,SAAS,CAAC,QAAe;AAMhC,WAAO,MAAM,wBAAwB,IAAI,SAAS;AAClD,WAAO,GAAG;AAAA,EACZ,CAAC;AACD,QAAM,GAAG,WAAW,CAAC,YAAY;AAC/B,WAAO,MAAM,0BAA0B,SAAS;AAAA,EAClD,CAAC;AACH,CAAC;AAKI,MAAM,oBAAoB;AAAA,EA+BvB,YAAoB,QAA2C,cAAoC;AAA/E;AAA2C;AAAA,EAAqC;AAAA,EA9B5G,aAAoB,MAAM,QAAgB,QAA8C;AACtF,QAAI,gCAAgB;AAClB,YAAM,IAAI,MAAM,+CAA+C;AAAA,IACjE;AAEA,UAAM,QAAQ,aAAa,KAAK,qCAAa,CAAC,GAAG;AAAA,MAC/C,OAAO;AAAA,MACP,KAAK;AAAA,QACH,GAAG;AAAA,QACH,CAAC,gCAAgB;AAAA,QACjB,CAAC,+BAAiB,KAAK,UAAU,MAAM;AAAA,QACvC,GAAG,OAAO;AAAA,MACZ;AAAA,IACF,CAAC;AAED,UAAM,oBAAoB,oBAAoB,OAAO,MAAM;AAC3D,UAAM,mBAAmB,mBAAmB,OAAO,MAAM;AAEzD,UAAM,WAAW,IAAI,oBAAoB,OAAO,gBAAgB;AAEhE,qBAAiB,QAAQ,MAAM;AAC7B,eAAS,UAAU;AAAA,IACrB,CAAC;AAED,UAAM;AAEN,WAAO;AAAA,EACT;AAAA,EAEQ,UAAU;AAAA,EAGlB,MAAa,OAA6B;AACxC,QAAI,KAAK,SAAS;AAChB,YAAM,IAAI,MAAM,mDAAmD;AAAA,IACrE;AACA,SAAK,OAAO,KAAK;AACjB,UAAM,MAAM,MAAM,KAAK;AACvB,WAAO;AAAA,EACT;AAAA,EAEA,MAAa,SAA+B;AAC1C,QAAI,KAAK,SAAS;AAChB,YAAM,IAAI,MAAM,wDAAwD;AAAA,IAC1E;AACA,UAAM,MAAM,MAAM,KAAK;AACvB,WAAO;AAAA,EACT;AACF;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botpress/cli",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Botpress CLI",
5
5
  "scripts": {
6
6
  "build": "pnpm run bundle && pnpm run template:gen",
@@ -18,7 +18,7 @@
18
18
  },
19
19
  "main": "dist/index.js",
20
20
  "dependencies": {
21
- "@botpress/client": "0.1.1",
21
+ "@botpress/client": "0.1.2",
22
22
  "@bpinternal/tunnel": "^0.0.2",
23
23
  "@bpinternal/yargs-extra": "^0.0.3",
24
24
  "@parcel/watcher": "^2.1.0",
@@ -45,7 +45,7 @@
45
45
  "zod-to-json-schema": "^3.20.1"
46
46
  },
47
47
  "devDependencies": {
48
- "@botpress/sdk": "0.1.3",
48
+ "@botpress/sdk": "0.1.4",
49
49
  "@types/bluebird": "^3.5.38",
50
50
  "@types/prompts": "^2.0.14",
51
51
  "@types/semver": "^7.3.11",
@@ -8,8 +8,8 @@
8
8
  "author": "",
9
9
  "license": "MIT",
10
10
  "dependencies": {
11
- "@botpress/client": "0.1.1",
12
- "@botpress/sdk": "0.1.3",
11
+ "@botpress/client": "0.1.2",
12
+ "@botpress/sdk": "0.1.4",
13
13
  "zod": "^3.20.6"
14
14
  },
15
15
  "devDependencies": {
@@ -8,8 +8,8 @@
8
8
  "author": "",
9
9
  "license": "MIT",
10
10
  "dependencies": {
11
- "@botpress/client": "0.1.1",
12
- "@botpress/sdk": "0.1.3",
11
+ "@botpress/client": "0.1.2",
12
+ "@botpress/sdk": "0.1.4",
13
13
  "zod": "^3.20.6"
14
14
  },
15
15
  "devDependencies": {