@botpress/cli 6.8.1 → 6.8.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.
@@ -1,36 +1,36 @@
1
1
 
2
- > @botpress/cli@6.8.1 build /home/runner/work/botpress/botpress/packages/cli
2
+ > @botpress/cli@6.8.2 build /home/runner/work/botpress/botpress/packages/cli
3
3
  > pnpm run build:types && pnpm run bundle && pnpm run template:gen
4
4
 
5
5
 
6
- > @botpress/cli@6.8.1 build:types /home/runner/work/botpress/botpress/packages/cli
6
+ > @botpress/cli@6.8.2 build:types /home/runner/work/botpress/botpress/packages/cli
7
7
  > tsc -p ./tsconfig.build.json
8
8
 
9
9
 
10
- > @botpress/cli@6.8.1 bundle /home/runner/work/botpress/botpress/packages/cli
10
+ > @botpress/cli@6.8.2 bundle /home/runner/work/botpress/botpress/packages/cli
11
11
  > ts-node -T build.ts
12
12
 
13
13
 
14
- > @botpress/cli@6.8.1 template:gen /home/runner/work/botpress/botpress/packages/cli
14
+ > @botpress/cli@6.8.2 template:gen /home/runner/work/botpress/botpress/packages/cli
15
15
  > pnpm -r --stream -F @bp-templates/* exec bp gen
16
16
 
17
- 🤖 Botpress CLI v6.8.1
17
+ 🤖 Botpress CLI v6.8.2
18
18
  ● Checking if cli is up to date
19
- 🤖 Botpress CLI v6.8.1
19
+ 🤖 Botpress CLI v6.8.2
20
20
  ● Checking if cli is up to date
21
- 🤖 Botpress CLI v6.8.1
21
+ 🤖 Botpress CLI v6.8.2
22
22
  ● Checking if cli is up to date
23
- 🤖 Botpress CLI v6.8.1
23
+ 🤖 Botpress CLI v6.8.2
24
24
  ● Checking if cli is up to date
25
25
  ● Checking if sdk is up to date
26
26
  ● Checking if sdk is up to date
27
27
  ● Checking if sdk is up to date
28
28
  ● Checking if sdk is up to date
29
+ ○ Generating typings for plugin empty-plugin...
29
30
  ○ Generating typings for integration empty-integration...
31
+ ○ Generating typings for integration hello-world...
30
32
  ✓ Typings available at .botpress
31
33
 
32
- ○ Generating typings for integration hello-world...
33
- ○ Generating typings for plugin empty-plugin...
34
34
  ✓ Typings available at .botpress
35
35
 
36
36
  ○ Generating typings for bot...
@@ -38,7 +38,7 @@
38
38
 
39
39
  ✓ Typings available at .botpress
40
40
 
41
- 🤖 Botpress CLI v6.8.1
41
+ 🤖 Botpress CLI v6.8.2
42
42
  ● Checking if cli is up to date
43
43
  ● Checking if sdk is up to date
44
44
  ○ Generating typings for integration webhook-message...
package/dist/cli.js CHANGED
@@ -31,14 +31,14 @@ var import_logger = require("./logger");
31
31
  var import_register_yargs = require("./register-yargs");
32
32
  const logError = (thrown) => {
33
33
  const error = errors.BotpressCLIError.map(thrown);
34
- new import_logger.Logger().error(error.message);
34
+ new import_logger.Logger().error(errors.BotpressCLIError.fullStack(error));
35
35
  };
36
36
  const onError = (thrown) => {
37
37
  logError(thrown);
38
38
  process.exit(1);
39
39
  };
40
40
  const yargsFail = (msg) => {
41
- logError(`${msg}
41
+ new import_logger.Logger().error(`${msg}
42
42
  `);
43
43
  import_yargs_extra.default.showHelp();
44
44
  process.exit(1);
package/dist/cli.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/cli.ts"],
4
- "sourcesContent": ["import 'dotenv/config'\nimport yargs from '@bpinternal/yargs-extra'\nimport commandDefinitions from './command-definitions'\nimport commandImplementations from './command-implementations'\nimport * as tree from './command-tree'\nimport * as errors from './errors'\nimport { Logger } from './logger'\nimport { registerYargs } from './register-yargs'\n\nconst logError = (thrown: unknown) => {\n const error = errors.BotpressCLIError.map(thrown)\n new Logger().error(error.message)\n}\n\nconst onError = (thrown: unknown) => {\n logError(thrown)\n process.exit(1)\n}\n\nconst yargsFail = (msg: string) => {\n logError(`${msg}\\n`)\n yargs.showHelp()\n process.exit(1)\n}\n\nprocess.on('uncaughtException', (thrown: unknown) => onError(thrown))\nprocess.on('unhandledRejection', (thrown: unknown) => onError(thrown))\n\nconst commands = tree.zipTree(commandDefinitions, commandImplementations)\n\nregisterYargs(yargs, commands)\n\nvoid yargs\n .version()\n .scriptName('bp')\n .demandCommand(1, \"You didn't provide any command. Use the --help flag to see the list of available commands.\")\n .recommendCommands()\n .strict()\n .help()\n .fail(yargsFail)\n .parse()\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA,oBAAO;AACP,yBAAkB;AAClB,iCAA+B;AAC/B,qCAAmC;AACnC,WAAsB;AACtB,aAAwB;AACxB,oBAAuB;AACvB,4BAA8B;AAE9B,MAAM,WAAW,CAAC,WAAoB;AACpC,QAAM,QAAQ,OAAO,iBAAiB,IAAI,MAAM;AAChD,MAAI,qBAAO,EAAE,MAAM,MAAM,OAAO;AAClC;AAEA,MAAM,UAAU,CAAC,WAAoB;AACnC,WAAS,MAAM;AACf,UAAQ,KAAK,CAAC;AAChB;AAEA,MAAM,YAAY,CAAC,QAAgB;AACjC,WAAS,GAAG,GAAG;AAAA,CAAI;AACnB,qBAAAA,QAAM,SAAS;AACf,UAAQ,KAAK,CAAC;AAChB;AAEA,QAAQ,GAAG,qBAAqB,CAAC,WAAoB,QAAQ,MAAM,CAAC;AACpE,QAAQ,GAAG,sBAAsB,CAAC,WAAoB,QAAQ,MAAM,CAAC;AAErE,MAAM,WAAW,KAAK,QAAQ,2BAAAC,SAAoB,+BAAAC,OAAsB;AAAA,IAExE,qCAAc,mBAAAF,SAAO,QAAQ;AAE7B,KAAK,mBAAAA,QACF,QAAQ,EACR,WAAW,IAAI,EACf,cAAc,GAAG,4FAA4F,EAC7G,kBAAkB,EAClB,OAAO,EACP,KAAK,EACL,KAAK,SAAS,EACd,MAAM;",
4
+ "sourcesContent": ["import 'dotenv/config'\nimport yargs from '@bpinternal/yargs-extra'\nimport commandDefinitions from './command-definitions'\nimport commandImplementations from './command-implementations'\nimport * as tree from './command-tree'\nimport * as errors from './errors'\nimport { Logger } from './logger'\nimport { registerYargs } from './register-yargs'\n\nconst logError = (thrown: unknown) => {\n const error = errors.BotpressCLIError.map(thrown)\n // genuine crashes only: print the full chain so headless callers (no -v) still get the reason.\n new Logger().error(errors.BotpressCLIError.fullStack(error))\n}\n\nconst onError = (thrown: unknown) => {\n logError(thrown)\n process.exit(1)\n}\n\nconst yargsFail = (msg: string) => {\n // usage errors are bad input, not crashes; show the clean message and help, never a stack.\n new Logger().error(`${msg}\\n`)\n yargs.showHelp()\n process.exit(1)\n}\n\nprocess.on('uncaughtException', (thrown: unknown) => onError(thrown))\nprocess.on('unhandledRejection', (thrown: unknown) => onError(thrown))\n\nconst commands = tree.zipTree(commandDefinitions, commandImplementations)\n\nregisterYargs(yargs, commands)\n\nvoid yargs\n .version()\n .scriptName('bp')\n .demandCommand(1, \"You didn't provide any command. Use the --help flag to see the list of available commands.\")\n .recommendCommands()\n .strict()\n .help()\n .fail(yargsFail)\n .parse()\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA,oBAAO;AACP,yBAAkB;AAClB,iCAA+B;AAC/B,qCAAmC;AACnC,WAAsB;AACtB,aAAwB;AACxB,oBAAuB;AACvB,4BAA8B;AAE9B,MAAM,WAAW,CAAC,WAAoB;AACpC,QAAM,QAAQ,OAAO,iBAAiB,IAAI,MAAM;AAEhD,MAAI,qBAAO,EAAE,MAAM,OAAO,iBAAiB,UAAU,KAAK,CAAC;AAC7D;AAEA,MAAM,UAAU,CAAC,WAAoB;AACnC,WAAS,MAAM;AACf,UAAQ,KAAK,CAAC;AAChB;AAEA,MAAM,YAAY,CAAC,QAAgB;AAEjC,MAAI,qBAAO,EAAE,MAAM,GAAG,GAAG;AAAA,CAAI;AAC7B,qBAAAA,QAAM,SAAS;AACf,UAAQ,KAAK,CAAC;AAChB;AAEA,QAAQ,GAAG,qBAAqB,CAAC,WAAoB,QAAQ,MAAM,CAAC;AACpE,QAAQ,GAAG,sBAAsB,CAAC,WAAoB,QAAQ,MAAM,CAAC;AAErE,MAAM,WAAW,KAAK,QAAQ,2BAAAC,SAAoB,+BAAAC,OAAsB;AAAA,IAExE,qCAAc,mBAAAF,SAAO,QAAQ;AAE7B,KAAK,mBAAAA,QACF,QAAQ,EACR,WAAW,IAAI,EACf,cAAc,GAAG,4FAA4F,EAC7G,kBAAkB,EAClB,OAAO,EACP,KAAK,EACL,KAAK,SAAS,EACd,MAAM;",
6
6
  "names": ["yargs", "commandDefinitions", "commandImplementations"]
7
7
  }
@@ -50,8 +50,7 @@ class BaseCommand {
50
50
  } catch (thrown) {
51
51
  const error = errors.BotpressCLIError.map(thrown);
52
52
  this.logger.error(error.message);
53
- const stack = error.stack ?? "No stack trace available";
54
- this.logger.debug(`[${this._cmdName}] ${stack}`);
53
+ this.logger.debug(`[${this._cmdName}] ${errors.BotpressCLIError.fullStack(error)}`);
55
54
  exitCode = 1;
56
55
  } finally {
57
56
  if (this.teardown) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/command-implementations/base-command.ts"],
4
- "sourcesContent": ["import * as errors from '../errors'\nimport type { Logger } from '../logger'\nimport type { CommandArgv, CommandDefinition } from '../typings'\n\nexport abstract class BaseCommand<C extends CommandDefinition> {\n public constructor(\n protected readonly logger: Logger,\n protected readonly argv: CommandArgv<C>\n ) {}\n\n protected abstract run(): Promise<void>\n protected bootstrap?(): Promise<void>\n protected teardown?(): Promise<void>\n\n private get _cmdName(): string {\n return this.constructor.name\n }\n\n public async handler(): Promise<{ exitCode: number }> {\n let exitCode = 0\n try {\n if (this.bootstrap) {\n await this.bootstrap()\n }\n await this.run()\n } catch (thrown) {\n const error = errors.BotpressCLIError.map(thrown)\n\n this.logger.error(error.message)\n\n const stack = error.stack ?? 'No stack trace available'\n this.logger.debug(`[${this._cmdName}] ${stack}`)\n\n exitCode = 1\n } finally {\n if (this.teardown) {\n await this.teardown()\n }\n }\n\n return { exitCode }\n }\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,aAAwB;AAIjB,MAAe,YAAyC;AAAA,EACtD,YACc,QACA,MACnB;AAFmB;AACA;AAAA,EAClB;AAAA,EAMH,IAAY,WAAmB;AAC7B,WAAO,KAAK,YAAY;AAAA,EAC1B;AAAA,EAEA,MAAa,UAAyC;AACpD,QAAI,WAAW;AACf,QAAI;AACF,UAAI,KAAK,WAAW;AAClB,cAAM,KAAK,UAAU;AAAA,MACvB;AACA,YAAM,KAAK,IAAI;AAAA,IACjB,SAAS,QAAQ;AACf,YAAM,QAAQ,OAAO,iBAAiB,IAAI,MAAM;AAEhD,WAAK,OAAO,MAAM,MAAM,OAAO;AAE/B,YAAM,QAAQ,MAAM,SAAS;AAC7B,WAAK,OAAO,MAAM,IAAI,KAAK,QAAQ,KAAK,KAAK,EAAE;AAE/C,iBAAW;AAAA,IACb,UAAE;AACA,UAAI,KAAK,UAAU;AACjB,cAAM,KAAK,SAAS;AAAA,MACtB;AAAA,IACF;AAEA,WAAO,EAAE,SAAS;AAAA,EACpB;AACF;",
4
+ "sourcesContent": ["import * as errors from '../errors'\nimport type { Logger } from '../logger'\nimport type { CommandArgv, CommandDefinition } from '../typings'\n\nexport abstract class BaseCommand<C extends CommandDefinition> {\n public constructor(\n protected readonly logger: Logger,\n protected readonly argv: CommandArgv<C>\n ) {}\n\n protected abstract run(): Promise<void>\n protected bootstrap?(): Promise<void>\n protected teardown?(): Promise<void>\n\n private get _cmdName(): string {\n return this.constructor.name\n }\n\n public async handler(): Promise<{ exitCode: number }> {\n let exitCode = 0\n try {\n if (this.bootstrap) {\n await this.bootstrap()\n }\n await this.run()\n } catch (thrown) {\n const error = errors.BotpressCLIError.map(thrown)\n\n this.logger.error(error.message)\n this.logger.debug(`[${this._cmdName}] ${errors.BotpressCLIError.fullStack(error)}`)\n\n exitCode = 1\n } finally {\n if (this.teardown) {\n await this.teardown()\n }\n }\n\n return { exitCode }\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,aAAwB;AAIjB,MAAe,YAAyC;AAAA,EACtD,YACc,QACA,MACnB;AAFmB;AACA;AAAA,EAClB;AAAA,EAMH,IAAY,WAAmB;AAC7B,WAAO,KAAK,YAAY;AAAA,EAC1B;AAAA,EAEA,MAAa,UAAyC;AACpD,QAAI,WAAW;AACf,QAAI;AACF,UAAI,KAAK,WAAW;AAClB,cAAM,KAAK,UAAU;AAAA,MACvB;AACA,YAAM,KAAK,IAAI;AAAA,IACjB,SAAS,QAAQ;AACf,YAAM,QAAQ,OAAO,iBAAiB,IAAI,MAAM;AAEhD,WAAK,OAAO,MAAM,MAAM,OAAO;AAC/B,WAAK,OAAO,MAAM,IAAI,KAAK,QAAQ,KAAK,OAAO,iBAAiB,UAAU,KAAK,CAAC,EAAE;AAElF,iBAAW;AAAA,IACb,UAAE;AACA,UAAI,KAAK,UAAU;AACjB,cAAM,KAAK,SAAS;AAAA,MACtB;AAAA,IACF;AAEA,WAAO,EAAE,SAAS;AAAA,EACpB;AACF;",
6
6
  "names": []
7
7
  }
@@ -139,12 +139,16 @@ class DevCommand extends import_project_command.ProjectCommand {
139
139
  void this._forwardTunnelRequest(`http://localhost:${port}`, req).then((res) => {
140
140
  tunnel.send(res);
141
141
  }).catch((thrown) => {
142
- const err = errors.BotpressCLIError.wrap(thrown, "An error occurred while handling request");
142
+ const err = errors.BotpressCLIError.wrap(
143
+ thrown,
144
+ `An error occurred while handling request ${req.method} ${req.path}`
145
+ );
143
146
  this.logger.error(err.message);
147
+ this.logger.debug(errors.BotpressCLIError.fullStack(err));
144
148
  tunnel.send({
145
149
  requestId: req.id,
146
150
  status: 500,
147
- body: err.message
151
+ body: "Internal error while handling request"
148
152
  });
149
153
  });
150
154
  });
@@ -199,6 +203,7 @@ class DevCommand extends import_project_command.ProjectCommand {
199
203
  } catch (thrown) {
200
204
  const error = errors.BotpressCLIError.wrap(thrown, "Build failed");
201
205
  this.logger.error(error.message);
206
+ this.logger.debug(errors.BotpressCLIError.fullStack(error));
202
207
  return;
203
208
  }
204
209
  await worker.reload();
@@ -276,7 +281,7 @@ class DevCommand extends import_project_command.ProjectCommand {
276
281
  },
277
282
  this.logger
278
283
  ).catch((thrown) => {
279
- throw errors.BotpressCLIError.wrap(thrown, "Could not start dev worker");
284
+ throw errors.BotpressCLIError.wrap(thrown, `Could not start dev worker on port ${port}`);
280
285
  });
281
286
  return worker;
282
287
  };
@@ -290,6 +295,7 @@ class DevCommand extends import_project_command.ProjectCommand {
290
295
  const resp = await api.client.getIntegration({ id: devId }).catch(async (thrown) => {
291
296
  const err = errors.BotpressCLIError.wrap(thrown, `Could not find existing dev integration with id "${devId}"`);
292
297
  this.logger.warn(err.message);
298
+ this.logger.debug(errors.BotpressCLIError.fullStack(err));
293
299
  return { integration: void 0 };
294
300
  });
295
301
  if (resp.integration?.dev) {
@@ -331,6 +337,7 @@ class DevCommand extends import_project_command.ProjectCommand {
331
337
  const resp = await api.client.getBot({ id: devId }).catch(async (thrown) => {
332
338
  const err = errors.BotpressCLIError.wrap(thrown, `Could not find existing dev bot with id "${devId}"`);
333
339
  this.logger.warn(err.message);
340
+ this.logger.debug(errors.BotpressCLIError.fullStack(err));
334
341
  return { bot: void 0 };
335
342
  });
336
343
  if (resp.bot?.dev) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/command-implementations/dev-command.ts"],
4
- "sourcesContent": ["import type * as client from '@botpress/client'\nimport * as sdk from '@botpress/sdk'\nimport { TunnelRequest, TunnelResponse } from '@bpinternal/tunnel'\nimport axios, { AxiosRequestConfig, AxiosResponse } from 'axios'\nimport chalk from 'chalk'\nimport { isEqual } from 'lodash'\nimport * as pathlib from 'path'\nimport * as uuid from 'uuid'\nimport * as apiUtils from '../api'\nimport { secretEnvVariableName, stripSecretEnvVariablePrefix } from '../code-generation/secret-module'\nimport type commandDefinitions from '../command-definitions'\nimport * as errors from '../errors'\nimport * as tables from '../tables'\nimport * as utils from '../utils'\nimport { Worker } from '../worker'\nimport { BuildCommand } from './build-command'\nimport { ProjectCommand, ProjectDefinition } from './project-command'\n\nconst DEFAULT_BOT_PORT = 8075\nconst DEFAULT_INTEGRATION_PORT = 8076\nconst TUNNEL_HELLO_INTERVAL = 5000\nconst FILEWATCHER_DEBOUNCE_MS = 500\n\nexport type DevCommandDefinition = typeof commandDefinitions.dev\nexport class DevCommand extends ProjectCommand<DevCommandDefinition> {\n private _initialDef: ProjectDefinition | undefined = undefined\n private _deployedIntegrationName: string | undefined = undefined\n private _cacheDevRequestBody: apiUtils.UpdateBotRequestBody | apiUtils.UpdateIntegrationRequestBody | undefined\n private _buildContext: utils.esbuild.BuildCodeContext\n\n public constructor(...args: ConstructorParameters<typeof ProjectCommand<DevCommandDefinition>>) {\n super(...args)\n this._buildContext = new utils.esbuild.BuildCodeContext()\n }\n\n public async run(): Promise<void> {\n this.logger.warn('This command is experimental and subject to breaking changes without notice.')\n\n let api = await this.ensureLoginAndCreateClient(this.argv)\n\n const { projectType, resolveProjectDefinition } = this.readProjectDefinitionFromFS()\n if (projectType === 'interface') {\n throw new errors.BotpressCLIError('This feature is not available for interfaces.')\n }\n const projectDef = await resolveProjectDefinition()\n this._initialDef = projectDef\n\n if (projectDef.type === 'integration') {\n const handleResult = await this.manageWorkspaceHandle(api, projectDef.definition)\n if (!handleResult) return\n if (handleResult.workspaceId) {\n api = api.switchWorkspace(handleResult.workspaceId)\n }\n this._deployedIntegrationName = handleResult.integration.name\n }\n\n let env: Record<string, string> = {\n ...process.env,\n BP_API_URL: api.url,\n BP_TOKEN: api.token,\n }\n\n const defaultPort = this._initialDef.type === 'integration' ? DEFAULT_INTEGRATION_PORT : DEFAULT_BOT_PORT\n if (this._initialDef.type === 'integration' || this._initialDef.type === 'bot') {\n const knownSecrets = await this._readKnownSecretsFromCache()\n let secretEnvVariables = await this.promptSecrets(this._initialDef.definition, this.argv, {\n knownSecrets: Object.keys(knownSecrets),\n formatEnv: true,\n })\n secretEnvVariables = { ...this._applyPrefixToSecrets(knownSecrets), ...secretEnvVariables }\n const nonNullSecretEnvVariables = utils.records.filterValues(secretEnvVariables, utils.guards.is.notNull)\n\n if (!this.argv.noSecretCaching) {\n await this._writeKnownSecretsToCache(secretEnvVariables)\n }\n\n env = { ...env, ...nonNullSecretEnvVariables }\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 cachedTunnelId = await this.projectCache.get('tunnelId')\n\n let tunnelId: string\n if (this.argv.tunnelId) {\n tunnelId = this.argv.tunnelId\n } else if (cachedTunnelId) {\n tunnelId = cachedTunnelId\n } else {\n tunnelId = uuid.v4()\n }\n\n if (cachedTunnelId !== tunnelId) {\n await this.projectCache.set('tunnelId', tunnelId)\n }\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 let worker: Worker | undefined = undefined\n\n const supervisor = new utils.tunnel.TunnelSupervisor(wsTunnelUrl, tunnelId, this.logger)\n supervisor.events.on('connected', ({ tunnel }) => {\n // prevents the tunnel from closing due to inactivity\n const timer = setInterval(() => {\n if (tunnel.closed) {\n return handleClose()\n }\n tunnel.hello()\n }, TUNNEL_HELLO_INTERVAL)\n const handleClose = (): void => clearInterval(timer)\n tunnel.events.on('close', handleClose)\n\n tunnel.events.on('request', (req) => {\n if (!worker) {\n this.logger.debug('Worker not ready yet, ignoring request')\n tunnel.send({ requestId: req.id, status: 503, body: 'Worker not ready yet' })\n return\n }\n\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\n supervisor.events.on('manuallyClosed', () => {\n this.logger.debug('Tunnel manually closed')\n })\n\n await supervisor.start()\n\n await this._runBuild()\n worker = await this._spawnWorker(env, port)\n await this._deploy(api, httpTunnelUrl)\n\n try {\n const watcher = await utils.filewatcher.FileWatcher.watch(\n this.argv.workDir,\n async (events) => {\n if (!worker) {\n this.logger.debug('Worker not ready yet, ignoring file change event')\n return\n }\n\n const typescriptEvents = events\n .filter((e) => !e.path.startsWith(this.projectPaths.abs.outDir))\n .filter((e) => pathlib.extname(e.path) === '.ts')\n\n const packageJsonEvents = events\n .filter((e) => !e.path.startsWith(this.projectPaths.abs.outDir))\n .filter((e) => pathlib.basename(e.path) === 'package.json')\n\n const distEvents = events.filter((e) => e.path.startsWith(this.projectPaths.abs.distDir))\n\n if (typescriptEvents.length > 0 || packageJsonEvents.length > 0) {\n this.logger.log('Changes detected, rebuilding')\n await this._restart(api, worker, httpTunnelUrl)\n } else if (distEvents.length > 0) {\n this.logger.log('Changes detected in output directory, reloading worker')\n await worker.reload()\n }\n },\n {\n debounceMs: FILEWATCHER_DEBOUNCE_MS,\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: apiUtils.ApiClient, worker: Worker, tunnelUrl: string) => {\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 await this._deploy(api, tunnelUrl)\n }\n\n private _deploy = async (api: apiUtils.ApiClient, tunnelUrl: string) => {\n const { projectType, resolveProjectDefinition } = this.readProjectDefinitionFromFS()\n\n if (projectType === 'interface') {\n throw new errors.BotpressCLIError('This feature is not available for interfaces.')\n }\n if (projectType === 'integration' && this._initialDef?.type === 'integration') {\n const projectDef = await resolveProjectDefinition()\n this._checkSecrets(projectDef.definition)\n if (projectDef.definition.name !== this._initialDef.definition.name) {\n throw new errors.BotpressCLIError(\n `Integration name changed from \"${this._initialDef.definition.name}\" to \"${projectDef.definition.name}\". Renaming integrations during bp dev is not supported. Please restart bp dev.`\n )\n }\n const integrationDef = new sdk.IntegrationDefinition({\n ...projectDef.definition,\n name: this._deployedIntegrationName ?? this._initialDef.definition.name,\n })\n return await this._deployDevIntegration(api, tunnelUrl, integrationDef)\n }\n if (projectType === 'bot') {\n const projectDef = await resolveProjectDefinition()\n this._checkSecrets(projectDef.definition)\n return await this._deployDevBot(api, tunnelUrl, projectDef.definition)\n }\n throw new errors.UnsupportedProjectType()\n }\n\n private async _writeKnownSecretsToCache(secretEnvVariables: Record<string, string | null>) {\n const knownSecrets: Record<string, string | null> = {}\n for (const [prefixedSecretName, secretValue] of Object.entries(secretEnvVariables)) {\n const secretName = stripSecretEnvVariablePrefix(prefixedSecretName)\n knownSecrets[secretName] = secretValue\n }\n\n const nonNullKnownSecrets = utils.records.filterValues(knownSecrets, utils.guards.is.notNull)\n if (Object.keys(nonNullKnownSecrets).length === 0) {\n await this.projectCache.rm('secrets')\n return\n }\n await this.projectCache.set('secrets', nonNullKnownSecrets)\n }\n\n private async _readKnownSecretsFromCache() {\n return (await this.projectCache.get('secrets')) ?? {}\n }\n\n private _applyPrefixToSecrets(secrets: Record<string, string>): Record<string, string> {\n const prefixedSecretEntries = Object.entries(secrets).map(([secretName, secretValue]) => [\n secretEnvVariableName(secretName),\n secretValue,\n ])\n return Object.fromEntries(prefixedSecretEntries)\n }\n\n private _checkSecrets(projectDef: sdk.IntegrationDefinition | sdk.BotDefinition) {\n if (this._initialDef?.type !== 'integration' && this._initialDef?.type !== 'bot') {\n return\n }\n const initialSecrets = this._initialDef?.definition.secrets ?? {}\n const currentSecrets = projectDef.secrets ?? {}\n const newSecrets = Object.keys(currentSecrets).filter((s) => !initialSecrets[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.outFileCJS\n const importPath = utils.path.toUnix(outfile)\n const code = `require('${importPath}').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)\n .setProjectContext(this.projectContext)\n .run(this._buildContext)\n }\n\n private async _deployDevIntegration(\n api: apiUtils.ApiClient,\n externalUrl: string,\n integrationDef: sdk.IntegrationDefinition\n ): Promise<void> {\n const devId = await this.projectCache.get('devId')\n\n let integration: client.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\n const createIntegrationBody = {\n ...(await this.prepareCreateIntegrationBody(integrationDef)),\n ...(await this.prepareIntegrationDependencies(integrationDef, api)),\n url: externalUrl,\n }\n\n if (integration) {\n const updateIntegrationBody = apiUtils.prepareUpdateIntegrationBody(\n { ...createIntegrationBody, id: integration.id },\n integration\n )\n\n const resp = await api.client.updateIntegration(updateIntegrationBody).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.createIntegration({ ...createIntegrationBody, dev: true }).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}\" at \"${externalUrl}\"`)\n line.commit()\n\n await this.projectCache.set('devId', integration.id)\n }\n\n private async _deployDevBot(api: apiUtils.ApiClient, externalUrl: string, botDef: sdk.BotDefinition): Promise<void> {\n const devId = await this.projectCache.get('devId')\n\n let bot: client.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.log('Dev Bot created')\n createLine.commit()\n await this.projectCache.set('devId', bot.id)\n }\n\n const updateBotBody = apiUtils.prepareUpdateBotBody(\n {\n ...(await apiUtils.prepareCreateBotBody(botDef)),\n ...(await this.prepareBotDependencies(botDef, api)),\n id: bot.id,\n url: externalUrl,\n },\n bot\n )\n\n if (!(await this._didDefinitionChange(updateBotBody))) {\n this.logger.log('Skipping deployment step. No changes found in bot.definition.ts')\n return\n }\n const updateLine = this.logger.line()\n updateLine.started('Deploying dev bot...')\n\n const { bot: updatedBot } = await api.client.updateBot(updateBotBody).catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, 'Could not deploy dev bot')\n })\n\n this.validateIntegrationRegistration(updatedBot, (failedIntegrations) => {\n throw new errors.BotpressCLIError(\n `Some integrations failed to register:\\n${Object.entries(failedIntegrations)\n .map(([key, int]) => `\u2022 ${key}: ${int.statusReason}`)\n .join('\\n')}`\n )\n })\n\n updateLine.success(`Dev Bot deployed with id \"${updatedBot.id}\" at \"${externalUrl}\"`)\n updateLine.commit()\n\n const tablesPublisher = new tables.TablesPublisher({ api, logger: this.logger, prompt: this.prompt })\n await tablesPublisher.deployTables({ botId: updatedBot.id, botDefinition: botDef })\n\n await this.displayIntegrationUrls({ api, bot: updatedBot })\n }\n\n private async _didDefinitionChange(body: apiUtils.UpdateBotRequestBody | apiUtils.UpdateIntegrationRequestBody) {\n const didChange = !isEqual(body, this._cacheDevRequestBody)\n this._cacheDevRequestBody = { ...body }\n return didChange\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] = String(res[key])\n }\n }\n return headers\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type * as client from '@botpress/client'\nimport * as sdk from '@botpress/sdk'\nimport { TunnelRequest, TunnelResponse } from '@bpinternal/tunnel'\nimport axios, { AxiosRequestConfig, AxiosResponse } from 'axios'\nimport chalk from 'chalk'\nimport { isEqual } from 'lodash'\nimport * as pathlib from 'path'\nimport * as uuid from 'uuid'\nimport * as apiUtils from '../api'\nimport { secretEnvVariableName, stripSecretEnvVariablePrefix } from '../code-generation/secret-module'\nimport type commandDefinitions from '../command-definitions'\nimport * as errors from '../errors'\nimport * as tables from '../tables'\nimport * as utils from '../utils'\nimport { Worker } from '../worker'\nimport { BuildCommand } from './build-command'\nimport { ProjectCommand, ProjectDefinition } from './project-command'\n\nconst DEFAULT_BOT_PORT = 8075\nconst DEFAULT_INTEGRATION_PORT = 8076\nconst TUNNEL_HELLO_INTERVAL = 5000\nconst FILEWATCHER_DEBOUNCE_MS = 500\n\nexport type DevCommandDefinition = typeof commandDefinitions.dev\nexport class DevCommand extends ProjectCommand<DevCommandDefinition> {\n private _initialDef: ProjectDefinition | undefined = undefined\n private _deployedIntegrationName: string | undefined = undefined\n private _cacheDevRequestBody: apiUtils.UpdateBotRequestBody | apiUtils.UpdateIntegrationRequestBody | undefined\n private _buildContext: utils.esbuild.BuildCodeContext\n\n public constructor(...args: ConstructorParameters<typeof ProjectCommand<DevCommandDefinition>>) {\n super(...args)\n this._buildContext = new utils.esbuild.BuildCodeContext()\n }\n\n public async run(): Promise<void> {\n this.logger.warn('This command is experimental and subject to breaking changes without notice.')\n\n let api = await this.ensureLoginAndCreateClient(this.argv)\n\n const { projectType, resolveProjectDefinition } = this.readProjectDefinitionFromFS()\n if (projectType === 'interface') {\n throw new errors.BotpressCLIError('This feature is not available for interfaces.')\n }\n const projectDef = await resolveProjectDefinition()\n this._initialDef = projectDef\n\n if (projectDef.type === 'integration') {\n const handleResult = await this.manageWorkspaceHandle(api, projectDef.definition)\n if (!handleResult) return\n if (handleResult.workspaceId) {\n api = api.switchWorkspace(handleResult.workspaceId)\n }\n this._deployedIntegrationName = handleResult.integration.name\n }\n\n let env: Record<string, string> = {\n ...process.env,\n BP_API_URL: api.url,\n BP_TOKEN: api.token,\n }\n\n const defaultPort = this._initialDef.type === 'integration' ? DEFAULT_INTEGRATION_PORT : DEFAULT_BOT_PORT\n if (this._initialDef.type === 'integration' || this._initialDef.type === 'bot') {\n const knownSecrets = await this._readKnownSecretsFromCache()\n let secretEnvVariables = await this.promptSecrets(this._initialDef.definition, this.argv, {\n knownSecrets: Object.keys(knownSecrets),\n formatEnv: true,\n })\n secretEnvVariables = { ...this._applyPrefixToSecrets(knownSecrets), ...secretEnvVariables }\n const nonNullSecretEnvVariables = utils.records.filterValues(secretEnvVariables, utils.guards.is.notNull)\n\n if (!this.argv.noSecretCaching) {\n await this._writeKnownSecretsToCache(secretEnvVariables)\n }\n\n env = { ...env, ...nonNullSecretEnvVariables }\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 cachedTunnelId = await this.projectCache.get('tunnelId')\n\n let tunnelId: string\n if (this.argv.tunnelId) {\n tunnelId = this.argv.tunnelId\n } else if (cachedTunnelId) {\n tunnelId = cachedTunnelId\n } else {\n tunnelId = uuid.v4()\n }\n\n if (cachedTunnelId !== tunnelId) {\n await this.projectCache.set('tunnelId', tunnelId)\n }\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 let worker: Worker | undefined = undefined\n\n const supervisor = new utils.tunnel.TunnelSupervisor(wsTunnelUrl, tunnelId, this.logger)\n supervisor.events.on('connected', ({ tunnel }) => {\n // prevents the tunnel from closing due to inactivity\n const timer = setInterval(() => {\n if (tunnel.closed) {\n return handleClose()\n }\n tunnel.hello()\n }, TUNNEL_HELLO_INTERVAL)\n const handleClose = (): void => clearInterval(timer)\n tunnel.events.on('close', handleClose)\n\n tunnel.events.on('request', (req) => {\n if (!worker) {\n this.logger.debug('Worker not ready yet, ignoring request')\n tunnel.send({ requestId: req.id, status: 503, body: 'Worker not ready yet' })\n return\n }\n\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(\n thrown,\n `An error occurred while handling request ${req.method} ${req.path}`\n )\n this.logger.error(err.message)\n this.logger.debug(errors.BotpressCLIError.fullStack(err))\n tunnel.send({\n requestId: req.id,\n status: 500,\n body: 'Internal error while handling request',\n })\n })\n })\n })\n\n supervisor.events.on('manuallyClosed', () => {\n this.logger.debug('Tunnel manually closed')\n })\n\n await supervisor.start()\n\n await this._runBuild()\n worker = await this._spawnWorker(env, port)\n await this._deploy(api, httpTunnelUrl)\n\n try {\n const watcher = await utils.filewatcher.FileWatcher.watch(\n this.argv.workDir,\n async (events) => {\n if (!worker) {\n this.logger.debug('Worker not ready yet, ignoring file change event')\n return\n }\n\n const typescriptEvents = events\n .filter((e) => !e.path.startsWith(this.projectPaths.abs.outDir))\n .filter((e) => pathlib.extname(e.path) === '.ts')\n\n const packageJsonEvents = events\n .filter((e) => !e.path.startsWith(this.projectPaths.abs.outDir))\n .filter((e) => pathlib.basename(e.path) === 'package.json')\n\n const distEvents = events.filter((e) => e.path.startsWith(this.projectPaths.abs.distDir))\n\n if (typescriptEvents.length > 0 || packageJsonEvents.length > 0) {\n this.logger.log('Changes detected, rebuilding')\n await this._restart(api, worker, httpTunnelUrl)\n } else if (distEvents.length > 0) {\n this.logger.log('Changes detected in output directory, reloading worker')\n await worker.reload()\n }\n },\n {\n debounceMs: FILEWATCHER_DEBOUNCE_MS,\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: apiUtils.ApiClient, worker: Worker, tunnelUrl: string) => {\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 this.logger.debug(errors.BotpressCLIError.fullStack(error))\n return\n }\n\n await worker.reload()\n await this._deploy(api, tunnelUrl)\n }\n\n private _deploy = async (api: apiUtils.ApiClient, tunnelUrl: string) => {\n const { projectType, resolveProjectDefinition } = this.readProjectDefinitionFromFS()\n\n if (projectType === 'interface') {\n throw new errors.BotpressCLIError('This feature is not available for interfaces.')\n }\n if (projectType === 'integration' && this._initialDef?.type === 'integration') {\n const projectDef = await resolveProjectDefinition()\n this._checkSecrets(projectDef.definition)\n if (projectDef.definition.name !== this._initialDef.definition.name) {\n throw new errors.BotpressCLIError(\n `Integration name changed from \"${this._initialDef.definition.name}\" to \"${projectDef.definition.name}\". Renaming integrations during bp dev is not supported. Please restart bp dev.`\n )\n }\n const integrationDef = new sdk.IntegrationDefinition({\n ...projectDef.definition,\n name: this._deployedIntegrationName ?? this._initialDef.definition.name,\n })\n return await this._deployDevIntegration(api, tunnelUrl, integrationDef)\n }\n if (projectType === 'bot') {\n const projectDef = await resolveProjectDefinition()\n this._checkSecrets(projectDef.definition)\n return await this._deployDevBot(api, tunnelUrl, projectDef.definition)\n }\n throw new errors.UnsupportedProjectType()\n }\n\n private async _writeKnownSecretsToCache(secretEnvVariables: Record<string, string | null>) {\n const knownSecrets: Record<string, string | null> = {}\n for (const [prefixedSecretName, secretValue] of Object.entries(secretEnvVariables)) {\n const secretName = stripSecretEnvVariablePrefix(prefixedSecretName)\n knownSecrets[secretName] = secretValue\n }\n\n const nonNullKnownSecrets = utils.records.filterValues(knownSecrets, utils.guards.is.notNull)\n if (Object.keys(nonNullKnownSecrets).length === 0) {\n await this.projectCache.rm('secrets')\n return\n }\n await this.projectCache.set('secrets', nonNullKnownSecrets)\n }\n\n private async _readKnownSecretsFromCache() {\n return (await this.projectCache.get('secrets')) ?? {}\n }\n\n private _applyPrefixToSecrets(secrets: Record<string, string>): Record<string, string> {\n const prefixedSecretEntries = Object.entries(secrets).map(([secretName, secretValue]) => [\n secretEnvVariableName(secretName),\n secretValue,\n ])\n return Object.fromEntries(prefixedSecretEntries)\n }\n\n private _checkSecrets(projectDef: sdk.IntegrationDefinition | sdk.BotDefinition) {\n if (this._initialDef?.type !== 'integration' && this._initialDef?.type !== 'bot') {\n return\n }\n const initialSecrets = this._initialDef?.definition.secrets ?? {}\n const currentSecrets = projectDef.secrets ?? {}\n const newSecrets = Object.keys(currentSecrets).filter((s) => !initialSecrets[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.outFileCJS\n const importPath = utils.path.toUnix(outfile)\n const code = `require('${importPath}').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 on port ${port}`)\n })\n\n return worker\n }\n\n private _runBuild() {\n return new BuildCommand(this.api, this.prompt, this.logger, this.argv)\n .setProjectContext(this.projectContext)\n .run(this._buildContext)\n }\n\n private async _deployDevIntegration(\n api: apiUtils.ApiClient,\n externalUrl: string,\n integrationDef: sdk.IntegrationDefinition\n ): Promise<void> {\n const devId = await this.projectCache.get('devId')\n\n let integration: client.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 this.logger.debug(errors.BotpressCLIError.fullStack(err))\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\n const createIntegrationBody = {\n ...(await this.prepareCreateIntegrationBody(integrationDef)),\n ...(await this.prepareIntegrationDependencies(integrationDef, api)),\n url: externalUrl,\n }\n\n if (integration) {\n const updateIntegrationBody = apiUtils.prepareUpdateIntegrationBody(\n { ...createIntegrationBody, id: integration.id },\n integration\n )\n\n const resp = await api.client.updateIntegration(updateIntegrationBody).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.createIntegration({ ...createIntegrationBody, dev: true }).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}\" at \"${externalUrl}\"`)\n line.commit()\n\n await this.projectCache.set('devId', integration.id)\n }\n\n private async _deployDevBot(api: apiUtils.ApiClient, externalUrl: string, botDef: sdk.BotDefinition): Promise<void> {\n const devId = await this.projectCache.get('devId')\n\n let bot: client.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 this.logger.debug(errors.BotpressCLIError.fullStack(err))\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.log('Dev Bot created')\n createLine.commit()\n await this.projectCache.set('devId', bot.id)\n }\n\n const updateBotBody = apiUtils.prepareUpdateBotBody(\n {\n ...(await apiUtils.prepareCreateBotBody(botDef)),\n ...(await this.prepareBotDependencies(botDef, api)),\n id: bot.id,\n url: externalUrl,\n },\n bot\n )\n\n if (!(await this._didDefinitionChange(updateBotBody))) {\n this.logger.log('Skipping deployment step. No changes found in bot.definition.ts')\n return\n }\n const updateLine = this.logger.line()\n updateLine.started('Deploying dev bot...')\n\n const { bot: updatedBot } = await api.client.updateBot(updateBotBody).catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, 'Could not deploy dev bot')\n })\n\n this.validateIntegrationRegistration(updatedBot, (failedIntegrations) => {\n throw new errors.BotpressCLIError(\n `Some integrations failed to register:\\n${Object.entries(failedIntegrations)\n .map(([key, int]) => `\u2022 ${key}: ${int.statusReason}`)\n .join('\\n')}`\n )\n })\n\n updateLine.success(`Dev Bot deployed with id \"${updatedBot.id}\" at \"${externalUrl}\"`)\n updateLine.commit()\n\n const tablesPublisher = new tables.TablesPublisher({ api, logger: this.logger, prompt: this.prompt })\n await tablesPublisher.deployTables({ botId: updatedBot.id, botDefinition: botDef })\n\n await this.displayIntegrationUrls({ api, bot: updatedBot })\n }\n\n private async _didDefinitionChange(body: apiUtils.UpdateBotRequestBody | apiUtils.UpdateIntegrationRequestBody) {\n const didChange = !isEqual(body, this._cacheDevRequestBody)\n this._cacheDevRequestBody = { ...body }\n return didChange\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] = String(res[key])\n }\n }\n return headers\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["chalk", "axios"]
7
7
  }
package/dist/errors.d.ts CHANGED
@@ -7,6 +7,12 @@ export declare class BotpressCLIError extends VError {
7
7
  static map(thrown: unknown): BotpressCLIError;
8
8
  constructor(error: BotpressCLIError, message: string);
9
9
  constructor(message: string);
10
+ constructor(message: string, opts: {
11
+ cause?: Error;
12
+ });
13
+ static fullStack(err: Error): string;
14
+ private static _fullStack;
15
+ private static _cause;
10
16
  }
11
17
  export declare class ExclusiveBotFeatureError extends BotpressCLIError {
12
18
  constructor();
@@ -16,7 +22,9 @@ export declare class ExclusiveIntegrationFeatureError extends BotpressCLIError {
16
22
  }
17
23
  export declare class HTTPError extends BotpressCLIError {
18
24
  readonly status: number | undefined;
19
- constructor(status: number | undefined, message: string);
25
+ constructor(status: number | undefined, message: string, opts?: {
26
+ cause?: Error;
27
+ });
20
28
  static fromAxios(e: AxiosError<{
21
29
  message?: string;
22
30
  }>): HTTPError;
package/dist/errors.js CHANGED
@@ -52,6 +52,9 @@ const isKnownApiError = (e) => client.isApiError(e) && e.type !== "Unknown";
52
52
  class BotpressCLIError extends import_verror.VError {
53
53
  static wrap(thrown, message) {
54
54
  const err = BotpressCLIError.map(thrown);
55
+ if (!err.message.trim()) {
56
+ return new BotpressCLIError(message ?? "", { cause: err });
57
+ }
55
58
  return new BotpressCLIError(err, message ?? "");
56
59
  }
57
60
  static map(thrown) {
@@ -78,18 +81,47 @@ class BotpressCLIError extends import_verror.VError {
78
81
  return HTTPError.fromAxios(thrown);
79
82
  }
80
83
  if (thrown instanceof Error) {
81
- const { message } = thrown;
82
- return new BotpressCLIError(message);
84
+ return new BotpressCLIError(thrown.message, { cause: thrown });
83
85
  }
84
86
  return new BotpressCLIError(String(thrown));
85
87
  }
86
88
  constructor(first, second) {
87
89
  if (typeof first === "string") {
90
+ if (typeof second === "object") {
91
+ super({ cause: second.cause, skipCauseMessage: true }, first);
92
+ return;
93
+ }
88
94
  super(first);
89
95
  return;
90
96
  }
91
97
  super(first, second);
92
98
  }
99
+ // VError.fullStack only follows VError causes; this also follows native `Error.cause`/axios
100
+ // causes (with a cycle guard). static to mirror VError's own `fullStack(err)`.
101
+ static fullStack(err) {
102
+ return BotpressCLIError._fullStack(err, /* @__PURE__ */ new Set());
103
+ }
104
+ static _fullStack(err, seen) {
105
+ if (seen.has(err)) {
106
+ return "[Circular error cause]";
107
+ }
108
+ seen.add(err);
109
+ const stack = err.stack || err.message;
110
+ const cause = BotpressCLIError._cause(err);
111
+ if (!cause) {
112
+ return stack;
113
+ }
114
+ return `${stack}
115
+ caused by: ${BotpressCLIError._fullStack(cause, seen)}`;
116
+ }
117
+ static _cause(err) {
118
+ const vErrorCause = import_verror.VError.cause(err);
119
+ if (vErrorCause) {
120
+ return vErrorCause;
121
+ }
122
+ const nativeCause = err.cause;
123
+ return nativeCause instanceof Error ? nativeCause : void 0;
124
+ }
93
125
  }
94
126
  class ExclusiveBotFeatureError extends BotpressCLIError {
95
127
  constructor() {
@@ -104,13 +136,21 @@ class ExclusiveIntegrationFeatureError extends BotpressCLIError {
104
136
  }
105
137
  }
106
138
  class HTTPError extends BotpressCLIError {
107
- constructor(status, message) {
108
- super(message);
109
- this.status = status;
139
+ constructor(status, message, opts) {
140
+ var __super = (...args) => {
141
+ super(...args);
142
+ this.status = status;
143
+ return this;
144
+ };
145
+ if (opts?.cause) {
146
+ __super(message, opts);
147
+ return;
148
+ }
149
+ __super(message);
110
150
  }
111
151
  static fromAxios(e) {
112
152
  const message = this._axiosMsg(e);
113
- return new HTTPError(e.response?.status, message);
153
+ return new HTTPError(e.response?.status, message, { cause: e });
114
154
  }
115
155
  static fromApi(e) {
116
156
  const { message, code } = e;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/errors.ts"],
4
- "sourcesContent": ["import * as client from '@botpress/client'\nimport axios, { AxiosError } from 'axios'\nimport { VError } from 'verror'\nimport * as consts from './consts'\n\ntype KnownApiError = Exclude<client.ApiError, client.UnknownError>\nconst isUnknownApiError = (e: unknown): e is client.UnknownError => client.isApiError(e) && e.type === 'Unknown'\nconst isKnownApiError = (e: unknown): e is KnownApiError => client.isApiError(e) && e.type !== 'Unknown'\n\nexport class BotpressCLIError extends VError {\n public static wrap(thrown: unknown, message: string): BotpressCLIError {\n const err = BotpressCLIError.map(thrown)\n return new BotpressCLIError(err, message ?? '')\n }\n\n public static map(thrown: unknown): BotpressCLIError {\n if (thrown instanceof BotpressCLIError) {\n return thrown\n }\n if (isUnknownApiError(thrown)) {\n const cause = thrown.error?.cause\n if (cause && typeof cause === 'object' && 'code' in cause && cause.code === 'ECONNREFUSED') {\n return new HTTPError(500, 'The connection was refused by the server')\n }\n\n const unknownMessage = 'An unknown API error occurred'\n const actualTrimmedMessage = thrown.message.trim()\n if (!actualTrimmedMessage) {\n return new HTTPError(500, unknownMessage)\n }\n\n const inner = new HTTPError(500, actualTrimmedMessage)\n return new BotpressCLIError(inner, unknownMessage)\n }\n if (isKnownApiError(thrown)) {\n return HTTPError.fromApi(thrown)\n }\n if (axios.isAxiosError(thrown)) {\n return HTTPError.fromAxios(thrown)\n }\n if (thrown instanceof Error) {\n const { message } = thrown\n return new BotpressCLIError(message)\n }\n return new BotpressCLIError(String(thrown))\n }\n\n public constructor(error: BotpressCLIError, message: string)\n public constructor(message: string)\n public constructor(first: BotpressCLIError | string, second?: string) {\n if (typeof first === 'string') {\n super(first)\n return\n }\n super(first, second!)\n }\n}\n\nexport class ExclusiveBotFeatureError extends BotpressCLIError {\n public constructor() {\n const message = 'This feature is only available for bots. This project is an integration or interface.'\n super(message)\n }\n}\n\nexport class ExclusiveIntegrationFeatureError extends BotpressCLIError {\n public constructor() {\n const message = 'This feature is only available for integration. This project is a bot or interface.'\n super(message)\n }\n}\n\nexport class HTTPError extends BotpressCLIError {\n public constructor(\n public readonly status: number | undefined,\n message: string\n ) {\n super(message)\n }\n\n public static fromAxios(e: AxiosError<{ message?: string }>): HTTPError {\n const message = this._axiosMsg(e)\n return new HTTPError(e.response?.status, message)\n }\n\n public static fromApi(e: KnownApiError): HTTPError {\n const { message, code } = e\n return new HTTPError(code, message)\n }\n\n private static _axiosMsg(e: AxiosError<{ message?: string }>): string {\n let message = e.message\n if (e.response?.statusText) {\n message += `\\n ${e.response?.statusText}`\n }\n if (e.response?.status && e.request?.method && e.request?.path) {\n message += `\\n (${e.response?.status}) ${e.request.method} ${e.request.path}`\n }\n if (e.response?.data?.message) {\n message += `\\n ${e.response?.data?.message}`\n }\n return message\n }\n}\n\nexport class NoBundleFoundError extends BotpressCLIError {\n public constructor() {\n const message = 'No bundle found. Please run `bp bundle` first.'\n super(message)\n }\n}\n\nexport class NoBotsFoundError extends BotpressCLIError {\n public constructor() {\n const message = `No Bot found in your Workspace. Please create one first at ${consts.defaultBotpressAppUrl}.`\n super(message)\n }\n}\n\nexport class NoWorkspacesFoundError extends BotpressCLIError {\n public constructor() {\n const message = 'No Workspace found. Please create one first.'\n super(message)\n }\n}\n\nexport class NotLoggedInError extends BotpressCLIError {\n public constructor() {\n const message = 'Not logged in. Please run `bp login` first.'\n super(message)\n }\n}\n\nexport class ParamRequiredError extends BotpressCLIError {\n public constructor(param: string) {\n const message = `${param} is required.`\n super(message)\n }\n}\n\nexport class InvalidPackageReferenceError extends BotpressCLIError {\n public constructor(ref: string) {\n const message = `Invalid package reference \"${ref}\".`\n super(message)\n }\n}\n\nexport class UnsupportedProjectType extends BotpressCLIError {\n public constructor() {\n const message = 'Unsupported project type.'\n super(message)\n }\n}\n\nexport class ProjectDefinitionNotFoundError extends BotpressCLIError {\n public constructor(workdir: string) {\n const message = `No project definition found at \"${workdir}\".`\n super(message)\n }\n}\n\nexport class AbortedOperationError extends BotpressCLIError {\n public constructor() {\n super('Aborted')\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import * as client from '@botpress/client'\nimport axios, { AxiosError } from 'axios'\nimport { VError } from 'verror'\nimport * as consts from './consts'\n\ntype KnownApiError = Exclude<client.ApiError, client.UnknownError>\nconst isUnknownApiError = (e: unknown): e is client.UnknownError => client.isApiError(e) && e.type === 'Unknown'\nconst isKnownApiError = (e: unknown): e is KnownApiError => client.isApiError(e) && e.type !== 'Unknown'\n\nexport class BotpressCLIError extends VError {\n public static wrap(thrown: unknown, message: string): BotpressCLIError {\n const err = BotpressCLIError.map(thrown)\n if (!err.message.trim()) {\n // the cause carries no message of its own; avoid rendering a dangling \"<message>: \"\n // while still keeping it as a cause so fullStack can surface the deeper chain under --verbose\n return new BotpressCLIError(message ?? '', { cause: err })\n }\n return new BotpressCLIError(err, message ?? '')\n }\n\n public static map(thrown: unknown): BotpressCLIError {\n if (thrown instanceof BotpressCLIError) {\n return thrown\n }\n if (isUnknownApiError(thrown)) {\n const cause = thrown.error?.cause\n if (cause && typeof cause === 'object' && 'code' in cause && cause.code === 'ECONNREFUSED') {\n return new HTTPError(500, 'The connection was refused by the server')\n }\n\n const unknownMessage = 'An unknown API error occurred'\n const actualTrimmedMessage = thrown.message.trim()\n if (!actualTrimmedMessage) {\n return new HTTPError(500, unknownMessage)\n }\n\n const inner = new HTTPError(500, actualTrimmedMessage)\n return new BotpressCLIError(inner, unknownMessage)\n }\n if (isKnownApiError(thrown)) {\n return HTTPError.fromApi(thrown)\n }\n if (axios.isAxiosError(thrown)) {\n return HTTPError.fromAxios(thrown)\n }\n if (thrown instanceof Error) {\n return new BotpressCLIError(thrown.message, { cause: thrown })\n }\n return new BotpressCLIError(String(thrown))\n }\n\n public constructor(error: BotpressCLIError, message: string)\n public constructor(message: string)\n public constructor(message: string, opts: { cause?: Error })\n public constructor(first: BotpressCLIError | string, second?: string | { cause?: Error }) {\n if (typeof first === 'string') {\n if (typeof second === 'object') {\n // preserve the original error as a cause without duplicating its message into ours.\n // `skipCauseMessage` is supported by verror at runtime (validated against verror@1.10.1)\n // but missing from @types/verror, so the option object is typed inline rather than as\n // VError.Options. The message-neutrality this relies on is guarded by errors.test.ts.\n super({ cause: second.cause, skipCauseMessage: true } as { cause?: Error; skipCauseMessage: boolean }, first)\n return\n }\n super(first)\n return\n }\n super(first, second as string)\n }\n\n // VError.fullStack only follows VError causes; this also follows native `Error.cause`/axios\n // causes (with a cycle guard). static to mirror VError's own `fullStack(err)`.\n public static fullStack(err: Error): string {\n return BotpressCLIError._fullStack(err, new Set())\n }\n\n private static _fullStack(err: Error, seen: Set<Error>): string {\n if (seen.has(err)) {\n return '[Circular error cause]'\n }\n seen.add(err)\n\n const stack = err.stack || err.message\n const cause = BotpressCLIError._cause(err)\n\n if (!cause) {\n return stack\n }\n\n return `${stack}\\ncaused by: ${BotpressCLIError._fullStack(cause, seen)}`\n }\n\n private static _cause(err: Error): Error | undefined {\n const vErrorCause = VError.cause(err)\n if (vErrorCause) {\n return vErrorCause\n }\n\n const nativeCause = (err as { cause?: unknown }).cause\n return nativeCause instanceof Error ? nativeCause : undefined\n }\n}\n\nexport class ExclusiveBotFeatureError extends BotpressCLIError {\n public constructor() {\n const message = 'This feature is only available for bots. This project is an integration or interface.'\n super(message)\n }\n}\n\nexport class ExclusiveIntegrationFeatureError extends BotpressCLIError {\n public constructor() {\n const message = 'This feature is only available for integration. This project is a bot or interface.'\n super(message)\n }\n}\n\nexport class HTTPError extends BotpressCLIError {\n public constructor(\n public readonly status: number | undefined,\n message: string,\n opts?: { cause?: Error }\n ) {\n if (opts?.cause) {\n super(message, opts)\n return\n }\n super(message)\n }\n\n public static fromAxios(e: AxiosError<{ message?: string }>): HTTPError {\n const message = this._axiosMsg(e)\n // keep the axios error as a cause so fullStack can show the transport-level chain under --verbose.\n // only its message/stack are ever rendered; never serialize this cause \u2014 its config holds auth headers.\n return new HTTPError(e.response?.status, message, { cause: e })\n }\n\n public static fromApi(e: KnownApiError): HTTPError {\n const { message, code } = e\n return new HTTPError(code, message)\n }\n\n private static _axiosMsg(e: AxiosError<{ message?: string }>): string {\n let message = e.message\n if (e.response?.statusText) {\n message += `\\n ${e.response?.statusText}`\n }\n if (e.response?.status && e.request?.method && e.request?.path) {\n message += `\\n (${e.response?.status}) ${e.request.method} ${e.request.path}`\n }\n if (e.response?.data?.message) {\n message += `\\n ${e.response?.data?.message}`\n }\n return message\n }\n}\n\nexport class NoBundleFoundError extends BotpressCLIError {\n public constructor() {\n const message = 'No bundle found. Please run `bp bundle` first.'\n super(message)\n }\n}\n\nexport class NoBotsFoundError extends BotpressCLIError {\n public constructor() {\n const message = `No Bot found in your Workspace. Please create one first at ${consts.defaultBotpressAppUrl}.`\n super(message)\n }\n}\n\nexport class NoWorkspacesFoundError extends BotpressCLIError {\n public constructor() {\n const message = 'No Workspace found. Please create one first.'\n super(message)\n }\n}\n\nexport class NotLoggedInError extends BotpressCLIError {\n public constructor() {\n const message = 'Not logged in. Please run `bp login` first.'\n super(message)\n }\n}\n\nexport class ParamRequiredError extends BotpressCLIError {\n public constructor(param: string) {\n const message = `${param} is required.`\n super(message)\n }\n}\n\nexport class InvalidPackageReferenceError extends BotpressCLIError {\n public constructor(ref: string) {\n const message = `Invalid package reference \"${ref}\".`\n super(message)\n }\n}\n\nexport class UnsupportedProjectType extends BotpressCLIError {\n public constructor() {\n const message = 'Unsupported project type.'\n super(message)\n }\n}\n\nexport class ProjectDefinitionNotFoundError extends BotpressCLIError {\n public constructor(workdir: string) {\n const message = `No project definition found at \"${workdir}\".`\n super(message)\n }\n}\n\nexport class AbortedOperationError extends BotpressCLIError {\n public constructor() {\n super('Aborted')\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["axios"]
7
7
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ var import_axios = require("axios");
3
+ var import_vitest = require("vitest");
4
+ var import_errors = require("./errors");
5
+ (0, import_vitest.describe)("BotpressCLIError.map", () => {
6
+ (0, import_vitest.it)("maps a bare Error without duplicating its message", () => {
7
+ const mapped = import_errors.BotpressCLIError.map(new Error("boom"));
8
+ (0, import_vitest.expect)(mapped).toBeInstanceOf(import_errors.BotpressCLIError);
9
+ (0, import_vitest.expect)(mapped.message).toBe("boom");
10
+ });
11
+ (0, import_vitest.it)("preserves the original thrown error as the cause", () => {
12
+ const original = new Error("boom");
13
+ const mapped = import_errors.BotpressCLIError.map(original);
14
+ (0, import_vitest.expect)(mapped.cause()).toBe(original);
15
+ });
16
+ (0, import_vitest.it)("returns a BotpressCLIError unchanged (idempotent)", () => {
17
+ const err = new import_errors.BotpressCLIError("already mapped");
18
+ (0, import_vitest.expect)(import_errors.BotpressCLIError.map(err)).toBe(err);
19
+ });
20
+ });
21
+ (0, import_vitest.describe)("BotpressCLIError.wrap", () => {
22
+ (0, import_vitest.it)("chains the cause message when the cause has one", () => {
23
+ const wrapped = import_errors.BotpressCLIError.wrap(new Error("real cause"), "Build failed");
24
+ (0, import_vitest.expect)(wrapped.message).toBe("Build failed: real cause");
25
+ });
26
+ (0, import_vitest.it)("omits the dangling colon when the cause has no message, but keeps it for fullStack", () => {
27
+ const wrapped = import_errors.BotpressCLIError.wrap(new Error("", { cause: new Error("DEEP_CAUSE_MARKER") }), "Build failed");
28
+ (0, import_vitest.expect)(wrapped.message).toBe("Build failed");
29
+ (0, import_vitest.expect)(import_errors.BotpressCLIError.fullStack(wrapped)).toContain("DEEP_CAUSE_MARKER");
30
+ });
31
+ });
32
+ (0, import_vitest.describe)("BotpressCLIError.fullStack", () => {
33
+ (0, import_vitest.it)("walks the preserved cause so the original throw site is included", () => {
34
+ const mapped = import_errors.BotpressCLIError.map(new Error("boom"));
35
+ (0, import_vitest.expect)(import_errors.BotpressCLIError.fullStack(mapped)).toContain("caused by:");
36
+ });
37
+ (0, import_vitest.it)("recursively follows native Error.cause", () => {
38
+ const inner = new Error("INNER_CAUSE_MARKER");
39
+ const outer = new Error("outer", { cause: inner });
40
+ const mapped = import_errors.BotpressCLIError.map(outer);
41
+ (0, import_vitest.expect)(mapped.cause()).toBe(outer);
42
+ (0, import_vitest.expect)(import_errors.BotpressCLIError.fullStack(mapped)).toContain("INNER_CAUSE_MARKER");
43
+ });
44
+ (0, import_vitest.it)("follows axios transport causes without changing the mapped message", () => {
45
+ const cause = new Error("AXIOS_CAUSE_MARKER");
46
+ const axiosError = new import_axios.AxiosError("");
47
+ axiosError.cause = cause;
48
+ const mapped = import_errors.BotpressCLIError.map(axiosError);
49
+ (0, import_vitest.expect)(mapped.message).toBe("");
50
+ (0, import_vitest.expect)(import_errors.BotpressCLIError.fullStack(mapped)).toContain("AXIOS_CAUSE_MARKER");
51
+ });
52
+ });
53
+ //# sourceMappingURL=errors.test.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/errors.test.ts"],
4
+ "sourcesContent": ["import { AxiosError } from 'axios'\nimport { describe, expect, it } from 'vitest'\nimport { BotpressCLIError } from './errors'\n\ndescribe('BotpressCLIError.map', () => {\n it('maps a bare Error without duplicating its message', () => {\n const mapped = BotpressCLIError.map(new Error('boom'))\n expect(mapped).toBeInstanceOf(BotpressCLIError)\n expect(mapped.message).toBe('boom')\n })\n\n it('preserves the original thrown error as the cause', () => {\n const original = new Error('boom')\n const mapped = BotpressCLIError.map(original)\n expect(mapped.cause()).toBe(original)\n })\n\n it('returns a BotpressCLIError unchanged (idempotent)', () => {\n const err = new BotpressCLIError('already mapped')\n expect(BotpressCLIError.map(err)).toBe(err)\n })\n})\n\ndescribe('BotpressCLIError.wrap', () => {\n it('chains the cause message when the cause has one', () => {\n const wrapped = BotpressCLIError.wrap(new Error('real cause'), 'Build failed')\n expect(wrapped.message).toBe('Build failed: real cause')\n })\n\n it('omits the dangling colon when the cause has no message, but keeps it for fullStack', () => {\n const wrapped = BotpressCLIError.wrap(new Error('', { cause: new Error('DEEP_CAUSE_MARKER') }), 'Build failed')\n expect(wrapped.message).toBe('Build failed')\n expect(BotpressCLIError.fullStack(wrapped)).toContain('DEEP_CAUSE_MARKER')\n })\n})\n\ndescribe('BotpressCLIError.fullStack', () => {\n it('walks the preserved cause so the original throw site is included', () => {\n const mapped = BotpressCLIError.map(new Error('boom'))\n // 'caused by:' only appears when a cause is preserved; it would be absent if map() severed it\n expect(BotpressCLIError.fullStack(mapped)).toContain('caused by:')\n })\n\n it('recursively follows native Error.cause', () => {\n const inner = new Error('INNER_CAUSE_MARKER')\n const outer = new Error('outer', { cause: inner })\n\n const mapped = BotpressCLIError.map(outer)\n expect(mapped.cause()).toBe(outer) // outer is preserved (one level)\n expect(BotpressCLIError.fullStack(mapped)).toContain('INNER_CAUSE_MARKER')\n })\n\n it('follows axios transport causes without changing the mapped message', () => {\n const cause = new Error('AXIOS_CAUSE_MARKER')\n const axiosError = new AxiosError('')\n axiosError.cause = cause\n\n const mapped = BotpressCLIError.map(axiosError)\n\n expect(mapped.message).toBe('')\n expect(BotpressCLIError.fullStack(mapped)).toContain('AXIOS_CAUSE_MARKER')\n })\n})\n"],
5
+ "mappings": ";AAAA,mBAA2B;AAC3B,oBAAqC;AACrC,oBAAiC;AAAA,IAEjC,wBAAS,wBAAwB,MAAM;AACrC,wBAAG,qDAAqD,MAAM;AAC5D,UAAM,SAAS,+BAAiB,IAAI,IAAI,MAAM,MAAM,CAAC;AACrD,8BAAO,MAAM,EAAE,eAAe,8BAAgB;AAC9C,8BAAO,OAAO,OAAO,EAAE,KAAK,MAAM;AAAA,EACpC,CAAC;AAED,wBAAG,oDAAoD,MAAM;AAC3D,UAAM,WAAW,IAAI,MAAM,MAAM;AACjC,UAAM,SAAS,+BAAiB,IAAI,QAAQ;AAC5C,8BAAO,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ;AAAA,EACtC,CAAC;AAED,wBAAG,qDAAqD,MAAM;AAC5D,UAAM,MAAM,IAAI,+BAAiB,gBAAgB;AACjD,8BAAO,+BAAiB,IAAI,GAAG,CAAC,EAAE,KAAK,GAAG;AAAA,EAC5C,CAAC;AACH,CAAC;AAAA,IAED,wBAAS,yBAAyB,MAAM;AACtC,wBAAG,mDAAmD,MAAM;AAC1D,UAAM,UAAU,+BAAiB,KAAK,IAAI,MAAM,YAAY,GAAG,cAAc;AAC7E,8BAAO,QAAQ,OAAO,EAAE,KAAK,0BAA0B;AAAA,EACzD,CAAC;AAED,wBAAG,sFAAsF,MAAM;AAC7F,UAAM,UAAU,+BAAiB,KAAK,IAAI,MAAM,IAAI,EAAE,OAAO,IAAI,MAAM,mBAAmB,EAAE,CAAC,GAAG,cAAc;AAC9G,8BAAO,QAAQ,OAAO,EAAE,KAAK,cAAc;AAC3C,8BAAO,+BAAiB,UAAU,OAAO,CAAC,EAAE,UAAU,mBAAmB;AAAA,EAC3E,CAAC;AACH,CAAC;AAAA,IAED,wBAAS,8BAA8B,MAAM;AAC3C,wBAAG,oEAAoE,MAAM;AAC3E,UAAM,SAAS,+BAAiB,IAAI,IAAI,MAAM,MAAM,CAAC;AAErD,8BAAO,+BAAiB,UAAU,MAAM,CAAC,EAAE,UAAU,YAAY;AAAA,EACnE,CAAC;AAED,wBAAG,0CAA0C,MAAM;AACjD,UAAM,QAAQ,IAAI,MAAM,oBAAoB;AAC5C,UAAM,QAAQ,IAAI,MAAM,SAAS,EAAE,OAAO,MAAM,CAAC;AAEjD,UAAM,SAAS,+BAAiB,IAAI,KAAK;AACzC,8BAAO,OAAO,MAAM,CAAC,EAAE,KAAK,KAAK;AACjC,8BAAO,+BAAiB,UAAU,MAAM,CAAC,EAAE,UAAU,oBAAoB;AAAA,EAC3E,CAAC;AAED,wBAAG,sEAAsE,MAAM;AAC7E,UAAM,QAAQ,IAAI,MAAM,oBAAoB;AAC5C,UAAM,aAAa,IAAI,wBAAW,EAAE;AACpC,eAAW,QAAQ;AAEnB,UAAM,SAAS,+BAAiB,IAAI,UAAU;AAE9C,8BAAO,OAAO,OAAO,EAAE,KAAK,EAAE;AAC9B,8BAAO,+BAAiB,UAAU,MAAM,CAAC,EAAE,UAAU,oBAAoB;AAAA,EAC3E,CAAC;AACH,CAAC;",
6
+ "names": []
7
+ }
@@ -17,7 +17,7 @@ export type ReconnectedEvent = {
17
17
  };
18
18
  export declare class ReconnectionFailedError extends Error {
19
19
  readonly event: ReconnectionTriggerEvent;
20
- constructor(event: ReconnectionTriggerEvent);
20
+ constructor(event: ReconnectionTriggerEvent, cause?: Error);
21
21
  private static _reason;
22
22
  }
23
23
  export declare class TunnelSupervisor {
@@ -28,7 +28,10 @@ export declare class TunnelSupervisor {
28
28
  private _closed;
29
29
  private _started;
30
30
  readonly events: EventEmitter<{
31
- connectionFailed: ReconnectionTriggerEvent;
31
+ connectionFailed: {
32
+ ev: ReconnectionTriggerEvent;
33
+ cause: Error;
34
+ };
32
35
  manuallyClosed: null;
33
36
  connected: {
34
37
  tunnel: TunnelTail;
@@ -23,11 +23,14 @@ __export(tunnel_utils_exports, {
23
23
  });
24
24
  module.exports = __toCommonJS(tunnel_utils_exports);
25
25
  var import_tunnel = require("@bpinternal/tunnel");
26
+ var import_errors = require("../errors");
26
27
  var import_event_emitter = require("./event-emitter");
27
28
  class ReconnectionFailedError extends Error {
28
- constructor(event) {
29
+ constructor(event, cause) {
29
30
  const reason = ReconnectionFailedError._reason(event);
30
- super(`Reconnection failed: ${reason}`);
31
+ const message = cause ? `Reconnection failed: ${reason}: ${cause.message}` : `Reconnection failed: ${reason}`;
32
+ const options = cause ? { cause } : void 0;
33
+ super(message, options);
31
34
  this.event = event;
32
35
  }
33
36
  static _reason(event) {
@@ -72,8 +75,8 @@ class TunnelSupervisor {
72
75
  throw new Error("Cannot wait: Tunnel is closed");
73
76
  }
74
77
  return new Promise((resolve, reject) => {
75
- this.events.on("connectionFailed", (ev) => {
76
- reject(new ReconnectionFailedError(ev));
78
+ this.events.on("connectionFailed", ({ ev, cause }) => {
79
+ reject(new ReconnectionFailedError(ev, cause));
77
80
  });
78
81
  this.events.on("manuallyClosed", () => {
79
82
  resolve();
@@ -91,7 +94,9 @@ class TunnelSupervisor {
91
94
  _reconnectSync(ev) {
92
95
  void this._reconnect(ev).then((t) => {
93
96
  this._tunnel = t;
94
- }).catch(() => this.events.emit("connectionFailed", ev));
97
+ }).catch((thrown) => {
98
+ this.events.emit("connectionFailed", { ev, cause: import_errors.BotpressCLIError.map(thrown) });
99
+ });
95
100
  }
96
101
  async _reconnect(ev) {
97
102
  const newTunnel = async () => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/tunnel-utils.ts"],
4
- "sourcesContent": ["import { TunnelTail, ClientCloseEvent, ClientErrorEvent, errors } 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 public constructor(\n private _tunnelUrl: string,\n private _tunnelId: string,\n private _logger: Logger\n ) {}\n\n public async start(): Promise<void> {\n if (this._closed) {\n throw new Error('Cannot start: Tunnel is closed')\n }\n if (this._started) {\n throw new Error('Cannot start: 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('Cannot wait: 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\n if (code === errors.CLOSE_CODES.TUNNEL_ID_CONFLICT) {\n throw new Error('Cannot start: Tunnel Id is already used, choose a different tunnel id.')\n }\n\n this._reconnectSync({ type: 'close', ev: { code, reason, target, type, wasClean } })\n })\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { TunnelTail, ClientCloseEvent, ClientErrorEvent, errors } from '@bpinternal/tunnel'\nimport { BotpressCLIError } from '../errors'\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(\n public readonly event: ReconnectionTriggerEvent,\n cause?: Error\n ) {\n const reason = ReconnectionFailedError._reason(event)\n const message = cause ? `Reconnection failed: ${reason}: ${cause.message}` : `Reconnection failed: ${reason}`\n const options = cause ? { cause } : undefined\n super(message, options)\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: { ev: ReconnectionTriggerEvent; cause: Error }\n manuallyClosed: null\n connected: {\n tunnel: TunnelTail\n ev: ReconnectionTriggerEvent\n }\n }>()\n\n public constructor(\n private _tunnelUrl: string,\n private _tunnelId: string,\n private _logger: Logger\n ) {}\n\n public async start(): Promise<void> {\n if (this._closed) {\n throw new Error('Cannot start: Tunnel is closed')\n }\n if (this._started) {\n throw new Error('Cannot start: 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('Cannot wait: Tunnel is closed')\n }\n\n return new Promise((resolve, reject) => {\n this.events.on('connectionFailed', ({ ev, cause }) => {\n reject(new ReconnectionFailedError(ev, cause))\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((thrown) => {\n // carry the real failure as the cause; the dev server then tears down and the single\n // \"running the dev server\" error surfaces this reason (avoids a duplicate log line here)\n this.events.emit('connectionFailed', { ev, cause: BotpressCLIError.map(thrown) })\n })\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\n if (code === errors.CLOSE_CODES.TUNNEL_ID_CONFLICT) {\n throw new Error('Cannot start: Tunnel Id is already used, choose a different tunnel id.')\n }\n\n this._reconnectSync({ type: 'close', ev: { code, reason, target, type, wasClean } })\n })\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["tunnel"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botpress/cli",
3
- "version": "6.8.1",
3
+ "version": "6.8.2",
4
4
  "description": "Botpress CLI",
5
5
  "scripts": {
6
6
  "build": "pnpm run build:types && pnpm run bundle && pnpm run template:gen",