@botpress/cli 0.2.9 → 0.3.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.
Files changed (76) hide show
  1. package/dist/api/client.js +1 -1
  2. package/dist/api/client.js.map +2 -2
  3. package/dist/code-generation/const.js +1 -1
  4. package/dist/code-generation/const.js.map +1 -1
  5. package/dist/code-generation/{event.js → generators.js} +15 -19
  6. package/dist/code-generation/generators.js.map +7 -0
  7. package/dist/code-generation/index.js +40 -8
  8. package/dist/code-generation/index.js.map +2 -2
  9. package/dist/code-generation/integration-implementation.js +157 -0
  10. package/dist/code-generation/integration-implementation.js.map +7 -0
  11. package/dist/code-generation/integration-instance.js +101 -39
  12. package/dist/code-generation/integration-instance.js.map +2 -2
  13. package/dist/code-generation/{action.js → integration-schemas/actions-module.js} +41 -19
  14. package/dist/code-generation/integration-schemas/actions-module.js.map +7 -0
  15. package/dist/code-generation/integration-schemas/channels-module.js +114 -0
  16. package/dist/code-generation/integration-schemas/channels-module.js.map +7 -0
  17. package/dist/code-generation/{configuration.js → integration-schemas/configuration-module.js} +11 -10
  18. package/dist/code-generation/integration-schemas/configuration-module.js.map +7 -0
  19. package/dist/code-generation/integration-schemas/events-module.js +64 -0
  20. package/dist/code-generation/integration-schemas/events-module.js.map +7 -0
  21. package/dist/code-generation/integration-schemas/states-module.js +64 -0
  22. package/dist/code-generation/integration-schemas/states-module.js.map +7 -0
  23. package/dist/code-generation/module.js +5 -5
  24. package/dist/code-generation/module.js.map +2 -2
  25. package/dist/code-generation/typings.js.map +1 -1
  26. package/dist/command-implementations/deploy-command.js +2 -20
  27. package/dist/command-implementations/deploy-command.js.map +3 -3
  28. package/dist/command-implementations/dev-command.js +26 -13
  29. package/dist/command-implementations/dev-command.js.map +3 -3
  30. package/dist/command-implementations/project-command.js +54 -1
  31. package/dist/command-implementations/project-command.js.map +2 -2
  32. package/dist/{code-generation/message.js → utils/guard-utils.js} +9 -20
  33. package/dist/utils/guard-utils.js.map +7 -0
  34. package/dist/utils/index.js +9 -0
  35. package/dist/utils/index.js.map +2 -2
  36. package/dist/utils/record-utils.js +9 -0
  37. package/dist/utils/record-utils.js.map +2 -2
  38. package/dist/{code-generation/channel.js → utils/schema-utils.js} +25 -22
  39. package/dist/utils/schema-utils.js.map +7 -0
  40. package/dist/utils/type-utils.js +17 -0
  41. package/dist/utils/type-utils.js.map +7 -0
  42. package/e2e/api.ts +4 -4
  43. package/e2e/tests/create-deploy-bot.ts +1 -1
  44. package/e2e/tests/create-deploy-integration.ts +1 -1
  45. package/e2e/tests/dev-bot.ts +5 -4
  46. package/package.json +6 -5
  47. package/templates/echo-bot/package.json +2 -2
  48. package/templates/echo-bot/src/index.ts +7 -20
  49. package/templates/empty-integration/.botpress/implementation/actions/index.ts +0 -1
  50. package/templates/empty-integration/.botpress/implementation/channels/channel/index.ts +6 -34
  51. package/templates/empty-integration/.botpress/implementation/channels/channel/{audio.ts → messages/audio.ts} +1 -1
  52. package/templates/empty-integration/.botpress/implementation/channels/channel/{card.ts → messages/card.ts} +1 -1
  53. package/templates/empty-integration/.botpress/implementation/channels/channel/{carousel.ts → messages/carousel.ts} +1 -1
  54. package/templates/empty-integration/.botpress/implementation/channels/channel/{choice.ts → messages/choice.ts} +1 -1
  55. package/templates/empty-integration/.botpress/implementation/channels/channel/{dropdown.ts → messages/dropdown.ts} +1 -1
  56. package/templates/empty-integration/.botpress/implementation/channels/channel/{file.ts → messages/file.ts} +1 -1
  57. package/templates/empty-integration/.botpress/implementation/channels/channel/{image.ts → messages/image.ts} +1 -1
  58. package/templates/empty-integration/.botpress/implementation/channels/channel/messages/index.ts +39 -0
  59. package/templates/empty-integration/.botpress/implementation/channels/channel/{location.ts → messages/location.ts} +1 -1
  60. package/templates/empty-integration/.botpress/implementation/channels/channel/{markdown.ts → messages/markdown.ts} +1 -1
  61. package/templates/empty-integration/.botpress/implementation/channels/channel/{text.ts → messages/text.ts} +1 -1
  62. package/templates/empty-integration/.botpress/implementation/channels/channel/{video.ts → messages/video.ts} +1 -1
  63. package/templates/empty-integration/.botpress/implementation/channels/index.ts +1 -2
  64. package/templates/empty-integration/.botpress/implementation/{configuration.ts → configuration/index.ts} +2 -2
  65. package/templates/empty-integration/.botpress/implementation/events/index.ts +0 -1
  66. package/templates/empty-integration/.botpress/implementation/index.ts +30 -12
  67. package/templates/empty-integration/.botpress/implementation/states/index.ts +6 -0
  68. package/templates/empty-integration/.botpress/secrets/index.ts +0 -1
  69. package/templates/empty-integration/package.json +2 -2
  70. package/dist/code-generation/action.js.map +0 -7
  71. package/dist/code-generation/channel.js.map +0 -7
  72. package/dist/code-generation/configuration.js.map +0 -7
  73. package/dist/code-generation/event.js.map +0 -7
  74. package/dist/code-generation/integration-impl.js +0 -147
  75. package/dist/code-generation/integration-impl.js.map +0 -7
  76. package/dist/code-generation/message.js.map +0 -7
@@ -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 _ from 'lodash'\nimport { prepareUpdateBotBody } from '../api/bot-body'\nimport type { ApiClient } from '../api/client'\nimport { prepareUpdateIntegrationBody, CreateIntegrationBody } from '../api/integration-body'\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\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 createBody: 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 updateBody = prepareUpdateIntegrationBody(\n {\n id: integration.id,\n ...createBody,\n },\n integration\n )\n\n await api.client.updateIntegration(updateBody).catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, `Could not update integration \"${integrationDef.name}\"`)\n })\n } else {\n await api.client.createIntegration(createBody).catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, `Could not create integration \"${integrationDef.name}\"`)\n })\n }\n line.success('Integration deployed')\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 line = this.logger.line()\n line.started(`Deploying bot ${chalk.bold(bot.name)}...`)\n\n const integrations = _(botImpl.definition.integrations ?? [])\n .keyBy((i) => i.id)\n .mapValues(({ enabled, configuration }) => ({ enabled, configuration }))\n .value()\n\n const updateBotBody = prepareUpdateBotBody(\n {\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 bot\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 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
- "names": ["chalk", "_"]
4
+ "sourcesContent": ["import type * as bpclient from '@botpress/client'\nimport type * as bpsdk from '@botpress/sdk'\nimport chalk from 'chalk'\nimport * as fs from 'fs'\nimport { prepareUpdateBotBody } from '../api/bot-body'\nimport type { ApiClient } from '../api/client'\nimport { prepareUpdateIntegrationBody, CreateIntegrationBody } from '../api/integration-body'\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\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: bpsdk.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 createBody: CreateIntegrationBody = {\n ...this.parseIntegrationDefinition(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 updateBody = prepareUpdateIntegrationBody(\n {\n id: integration.id,\n ...createBody,\n },\n integration\n )\n\n await api.client.updateIntegration(updateBody).catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, `Could not update integration \"${integrationDef.name}\"`)\n })\n } else {\n await api.client.createIntegration(createBody).catch((thrown) => {\n throw errors.BotpressCLIError.wrap(thrown, `Could not create integration \"${integrationDef.name}\"`)\n })\n }\n line.success('Integration deployed')\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: bpsdk.Bot }>(outfile)\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 line = this.logger.line()\n line.started(`Deploying bot ${chalk.bold(bot.name)}...`)\n\n const updateBotBody = prepareUpdateBotBody(\n {\n id: bot.id,\n code,\n ...this.parseBot(botImpl),\n },\n bot\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 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
+ "names": ["chalk"]
7
7
  }
@@ -29,7 +29,6 @@ __export(dev_command_exports, {
29
29
  module.exports = __toCommonJS(dev_command_exports);
30
30
  var import_axios = __toESM(require("axios"));
31
31
  var import_chalk = __toESM(require("chalk"));
32
- var import_lodash = __toESM(require("lodash"));
33
32
  var pathlib = __toESM(require("path"));
34
33
  var uuid = __toESM(require("uuid"));
35
34
  var import_bot_body = require("../api/bot-body");
@@ -73,13 +72,18 @@ class DevCommand extends import_project_command.ProjectCommand {
73
72
  protocol: isSecured ? "https" : "http",
74
73
  path: `/${tunnelId}`
75
74
  });
75
+ let worker = void 0;
76
76
  const supervisor = new utils.tunnel.TunnelSupervisor(wsTunnelUrl, tunnelId, this.logger);
77
77
  supervisor.events.on("connected", ({ tunnel }) => {
78
78
  const timer = setInterval(() => tunnel.hello(), TUNNEL_HELLO_INTERVAL);
79
79
  tunnel.events.on("close", () => clearInterval(timer));
80
- tunnel.events.on(
81
- "request",
82
- (req) => void this._forwardTunnelRequest(`http://localhost:${port}`, req).then((res) => {
80
+ tunnel.events.on("request", (req) => {
81
+ if (!worker) {
82
+ this.logger.debug("Worker not ready yet, ignoring request");
83
+ tunnel.send({ requestId: req.id, status: 503, body: "Worker not ready yet" });
84
+ return;
85
+ }
86
+ void this._forwardTunnelRequest(`http://localhost:${port}`, req).then((res) => {
83
87
  tunnel.send(res);
84
88
  }).catch((thrown) => {
85
89
  const err = errors.BotpressCLIError.wrap(thrown, "An error occurred while handling request");
@@ -89,17 +93,21 @@ class DevCommand extends import_project_command.ProjectCommand {
89
93
  status: 500,
90
94
  body: err.message
91
95
  });
92
- })
93
- );
96
+ });
97
+ });
94
98
  });
95
99
  await supervisor.start();
96
100
  await this._runBuild();
97
101
  await this._deploy(api, httpTunnelUrl);
98
- const worker = await this._spawnWorker(env, port);
102
+ worker = await this._spawnWorker(env, port);
99
103
  try {
100
104
  const watcher = await utils.filewatcher.FileWatcher.watch(
101
105
  this.argv.workDir,
102
106
  async (events) => {
107
+ if (!worker) {
108
+ this.logger.debug("Worker not ready yet, ignoring file change event");
109
+ return;
110
+ }
103
111
  const typescriptEvents = events.filter((e) => pathlib.extname(e.path) === ".ts");
104
112
  if (typescriptEvents.length === 0) {
105
113
  return;
@@ -190,9 +198,13 @@ class DevCommand extends import_project_command.ProjectCommand {
190
198
  }
191
199
  const line = this.logger.line();
192
200
  line.started(`Deploying dev integration ${import_chalk.default.bold(integrationDef.name)}...`);
201
+ const integrationBody = {
202
+ ...this.parseIntegrationDefinition(integrationDef),
203
+ url: externalUrl
204
+ };
193
205
  if (integration) {
194
206
  const updateIntegrationBody = (0, import_integration_body.prepareUpdateIntegrationBody)(
195
- { ...integrationDef, id: integration.id, url: externalUrl },
207
+ { ...integrationBody, id: integration.id },
196
208
  integration
197
209
  );
198
210
  const resp = await api.client.updateIntegration(updateIntegrationBody).catch((thrown) => {
@@ -200,12 +212,13 @@ class DevCommand extends import_project_command.ProjectCommand {
200
212
  });
201
213
  integration = resp.integration;
202
214
  } else {
203
- const resp = await api.client.createIntegration({ ...integrationDef, dev: true, url: externalUrl }).catch((thrown) => {
215
+ const resp = await api.client.createIntegration({ ...integrationBody, dev: true }).catch((thrown) => {
204
216
  throw errors.BotpressCLIError.wrap(thrown, `Could not deploy dev integration "${integrationDef.name}"`);
205
217
  });
206
218
  integration = resp.integration;
207
219
  }
208
220
  line.success(`Dev Integration deployed with id "${integration.id}"`);
221
+ line.commit();
209
222
  await this.projectCache.set("devId", integration.id);
210
223
  }
211
224
  async _deployDevBot(api, externalUrl) {
@@ -234,19 +247,18 @@ class DevCommand extends import_project_command.ProjectCommand {
234
247
  });
235
248
  bot = resp.bot;
236
249
  createLine.success(`Dev Bot created with id "${bot.id}"`);
250
+ createLine.commit();
237
251
  await this.projectCache.set("devId", bot.id);
238
252
  }
239
253
  const outfile = this.projectPaths.abs.outFile;
240
254
  const { default: botImpl } = utils.require.requireJsFile(outfile);
241
255
  const updateLine = this.logger.line();
242
256
  updateLine.started("Deploying dev bot...");
243
- const integrations = (0, import_lodash.default)(botImpl.definition.integrations ?? []).keyBy((i) => i.id).mapValues(({ enabled, configuration }) => ({ enabled, configuration })).value();
244
257
  const updateBotBody = (0, import_bot_body.prepareUpdateBotBody)(
245
258
  {
246
- ...botImpl.definition,
247
259
  id: bot.id,
248
- integrations,
249
- url: externalUrl
260
+ url: externalUrl,
261
+ ...this.parseBot(botImpl)
250
262
  },
251
263
  bot
252
264
  );
@@ -254,6 +266,7 @@ class DevCommand extends import_project_command.ProjectCommand {
254
266
  throw errors.BotpressCLIError.wrap(thrown, "Could not deploy dev bot");
255
267
  });
256
268
  updateLine.success(`Dev Bot deployed with id "${updatedBot.id}"`);
269
+ updateLine.commit();
257
270
  this.displayWebhookUrls(updatedBot);
258
271
  }
259
272
  _forwardTunnelRequest = async (baseUrl, request) => {
@@ -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 } from '@bpinternal/tunnel'\nimport axios, { AxiosRequestConfig, AxiosResponse } from 'axios'\nimport chalk from 'chalk'\nimport _ from 'lodash'\nimport * as pathlib from 'path'\nimport * as uuid from 'uuid'\nimport { prepareUpdateBotBody } from '../api/bot-body'\nimport type { ApiClient } from '../api/client'\nimport { prepareUpdateIntegrationBody } from '../api/integration-body'\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\nconst TUNNEL_HELLO_INTERVAL = 5000\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 // prevents the tunnel from closing due to inactivity\n const timer = setInterval(() => tunnel.hello(), TUNNEL_HELLO_INTERVAL)\n tunnel.events.on('close', () => clearInterval(timer))\n\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._runBuild()\n await this._deploy(api, httpTunnelUrl)\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 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 this._deploy(api, tunnelUrl)\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\n if (integration) {\n const updateIntegrationBody = prepareUpdateIntegrationBody(\n { ...integrationDef, id: integration.id, url: externalUrl },\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\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 updateLine = this.logger.line()\n updateLine.started('Deploying dev bot...')\n\n const integrations = _(botImpl.definition.integrations ?? [])\n .keyBy((i) => i.id)\n .mapValues(({ enabled, configuration }) => ({ enabled, configuration }))\n .value()\n\n const updateBotBody = prepareUpdateBotBody(\n {\n ...botImpl.definition,\n id: bot.id,\n integrations,\n url: externalUrl,\n },\n bot\n )\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 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
- "names": ["chalk", "_", "axios"]
4
+ "sourcesContent": ["import type * as bpclient from '@botpress/client'\nimport type * as bpsdk 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 { prepareUpdateBotBody } from '../api/bot-body'\nimport type { ApiClient } from '../api/client'\nimport { prepareUpdateIntegrationBody, CreateIntegrationBody } from '../api/integration-body'\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\nconst TUNNEL_HELLO_INTERVAL = 5000\n\nexport type DevCommandDefinition = typeof commandDefinitions.dev\nexport class DevCommand extends ProjectCommand<DevCommandDefinition> {\n private _initialDef: bpsdk.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 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(() => tunnel.hello(), TUNNEL_HELLO_INTERVAL)\n tunnel.events.on('close', () => clearInterval(timer))\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 await supervisor.start()\n\n await this._runBuild()\n await this._deploy(api, httpTunnelUrl)\n 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 if (!worker) {\n this.logger.debug('Worker not ready yet, ignoring file change event')\n return\n }\n\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 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 this._deploy(api, tunnelUrl)\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: bpsdk.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: bpsdk.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\n const integrationBody: CreateIntegrationBody = {\n ...this.parseIntegrationDefinition(integrationDef),\n url: externalUrl,\n }\n\n if (integration) {\n const updateIntegrationBody = prepareUpdateIntegrationBody(\n { ...integrationBody, 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({ ...integrationBody, 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}\"`)\n line.commit()\n\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 createLine.commit()\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: bpsdk.Bot }>(outfile)\n\n const updateLine = this.logger.line()\n updateLine.started('Deploying dev bot...')\n\n const updateBotBody = prepareUpdateBotBody(\n {\n id: bot.id,\n url: externalUrl,\n ...this.parseBot(botImpl),\n },\n bot\n )\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 updateLine.success(`Dev Bot deployed with id \"${updatedBot.id}\"`)\n updateLine.commit()\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
+ "names": ["chalk", "axios"]
7
7
  }
@@ -57,6 +57,59 @@ class ProjectCommand extends import_global_command.GlobalCommand {
57
57
  get projectCache() {
58
58
  return new utils.cache.FSKeyValueCache(this.projectPaths.abs.projectCacheFile);
59
59
  }
60
+ parseBot(bot) {
61
+ return {
62
+ ...bot.props,
63
+ integrations: (0, import_lodash.default)(bot.props.integrations).values().filter(utils.guards.is.defined).keyBy((i) => i.id).mapValues(({ enabled, configuration }) => ({ enabled, configuration })).value(),
64
+ configuration: bot.props.configuration ? {
65
+ ...bot.props.configuration,
66
+ schema: utils.schema.mapZodToJsonSchema(bot.props.configuration)
67
+ } : void 0,
68
+ events: bot.props.events ? import_lodash.default.mapValues(bot.props.events, (event) => ({
69
+ ...event,
70
+ schema: utils.schema.mapZodToJsonSchema(event)
71
+ })) : void 0,
72
+ states: bot.props.states ? import_lodash.default.mapValues(bot.props.states, (state) => ({
73
+ ...state,
74
+ schema: utils.schema.mapZodToJsonSchema(state)
75
+ })) : void 0
76
+ };
77
+ }
78
+ parseIntegrationDefinition(integration) {
79
+ return {
80
+ ...integration,
81
+ configuration: integration.configuration ? {
82
+ ...integration.configuration,
83
+ schema: utils.schema.mapZodToJsonSchema(integration.configuration)
84
+ } : void 0,
85
+ events: integration.events ? import_lodash.default.mapValues(integration.events, (event) => ({
86
+ ...event,
87
+ schema: utils.schema.mapZodToJsonSchema(event)
88
+ })) : void 0,
89
+ actions: integration.actions ? import_lodash.default.mapValues(integration.actions, (action) => ({
90
+ ...action,
91
+ input: {
92
+ ...action.input,
93
+ schema: utils.schema.mapZodToJsonSchema(action.input)
94
+ },
95
+ output: {
96
+ ...action.output,
97
+ schema: utils.schema.mapZodToJsonSchema(action.output)
98
+ }
99
+ })) : void 0,
100
+ channels: integration.channels ? import_lodash.default.mapValues(integration.channels, (channel) => ({
101
+ ...channel,
102
+ messages: import_lodash.default.mapValues(channel.messages, (message) => ({
103
+ ...message,
104
+ schema: utils.schema.mapZodToJsonSchema(message)
105
+ }))
106
+ })) : void 0,
107
+ states: integration.states ? import_lodash.default.mapValues(integration.states, (state) => ({
108
+ ...state,
109
+ schema: utils.schema.mapZodToJsonSchema(state)
110
+ })) : void 0
111
+ };
112
+ }
60
113
  async readIntegrationDefinitionFromFS() {
61
114
  const abs = this.projectPaths.abs;
62
115
  const rel = this.projectPaths.rel("workDir");
@@ -91,7 +144,7 @@ class ProjectCommand extends import_global_command.GlobalCommand {
91
144
  return;
92
145
  }
93
146
  this.logger.log("Integrations:");
94
- for (const integration of Object.values(bot.integrations)) {
147
+ for (const integration of Object.values(bot.integrations).filter(utils.guards.is.defined)) {
95
148
  if (!integration.enabled) {
96
149
  this.logger.log(`${import_chalk.default.grey(integration.name)} ${import_chalk.default.italic("(disabled)")}: ${integration.webhookUrl}`, {
97
150
  prefix: { symbol: "\u25CB", indent: 2 }
@@ -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 * as bpsdk 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<bpsdk.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: bpsdk.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 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: bpsdk.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 * as bpsdk 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 parseBot(bot: bpsdk.Bot) {\n return {\n ...bot.props,\n integrations: _(bot.props.integrations)\n .values()\n .filter(utils.guards.is.defined)\n .keyBy((i) => i.id)\n .mapValues(({ enabled, configuration }) => ({ enabled, configuration }))\n .value(),\n configuration: bot.props.configuration\n ? {\n ...bot.props.configuration,\n schema: utils.schema.mapZodToJsonSchema(bot.props.configuration),\n }\n : undefined,\n events: bot.props.events\n ? _.mapValues(bot.props.events, (event) => ({\n ...event,\n schema: utils.schema.mapZodToJsonSchema(event),\n }))\n : undefined,\n states: bot.props.states\n ? _.mapValues(bot.props.states, (state) => ({\n ...state,\n schema: utils.schema.mapZodToJsonSchema(state),\n }))\n : undefined,\n }\n }\n\n protected parseIntegrationDefinition(integration: bpsdk.IntegrationDefinition) {\n return {\n ...integration,\n configuration: integration.configuration\n ? {\n ...integration.configuration,\n schema: utils.schema.mapZodToJsonSchema(integration.configuration),\n }\n : undefined,\n events: integration.events\n ? _.mapValues(integration.events, (event) => ({\n ...event,\n schema: utils.schema.mapZodToJsonSchema(event),\n }))\n : undefined,\n actions: integration.actions\n ? _.mapValues(integration.actions, (action) => ({\n ...action,\n input: {\n ...action.input,\n schema: utils.schema.mapZodToJsonSchema(action.input),\n },\n output: {\n ...action.output,\n schema: utils.schema.mapZodToJsonSchema(action.output),\n },\n }))\n : undefined,\n channels: integration.channels\n ? _.mapValues(integration.channels, (channel) => ({\n ...channel,\n messages: _.mapValues(channel.messages, (message) => ({\n ...message,\n schema: utils.schema.mapZodToJsonSchema(message),\n })),\n }))\n : undefined,\n states: integration.states\n ? _.mapValues(integration.states, (state) => ({\n ...state,\n schema: utils.schema.mapZodToJsonSchema(state),\n }))\n : undefined,\n }\n }\n\n protected async readIntegrationDefinitionFromFS(): Promise<bpsdk.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: bpsdk.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 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).filter(utils.guards.is.defined)) {\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: bpsdk.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
  }
@@ -16,27 +16,16 @@ var __copyProps = (to, from, except, desc) => {
16
16
  return to;
17
17
  };
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var message_exports = {};
20
- __export(message_exports, {
21
- MessageModule: () => MessageModule
19
+ var guard_utils_exports = {};
20
+ __export(guard_utils_exports, {
21
+ is: () => is
22
22
  });
23
- module.exports = __toCommonJS(message_exports);
24
- var import_json_schema_to_typescript = require("json-schema-to-typescript");
25
- var import_utils = require("../utils");
26
- var import_module = require("./module");
27
- class MessageModule extends import_module.Module {
28
- static async create(name, message) {
29
- const schema = message.schema ?? {};
30
- const def = {
31
- path: `${name}.ts`,
32
- exportName: import_utils.casing.to.pascalCase(name),
33
- content: await (0, import_json_schema_to_typescript.compile)(schema, name)
34
- };
35
- return new MessageModule(def);
36
- }
37
- }
23
+ module.exports = __toCommonJS(guard_utils_exports);
24
+ const is = {
25
+ defined: (value) => value !== void 0
26
+ };
38
27
  // Annotate the CommonJS export names for ESM import in node:
39
28
  0 && (module.exports = {
40
- MessageModule
29
+ is
41
30
  });
42
- //# sourceMappingURL=message.js.map
31
+ //# sourceMappingURL=guard-utils.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils/guard-utils.ts"],
4
+ "sourcesContent": ["export const is = {\n defined: <T>(value: T | undefined): value is T => value !== undefined,\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,MAAM,KAAK;AAAA,EAChB,SAAS,CAAI,UAAqC,UAAU;AAC9D;",
6
+ "names": []
7
+ }
@@ -29,11 +29,14 @@ __export(utils_exports, {
29
29
  emitter: () => emitter,
30
30
  esbuild: () => esbuild,
31
31
  filewatcher: () => filewatcher,
32
+ guards: () => guards,
32
33
  path: () => path,
33
34
  prompt: () => prompt,
34
35
  records: () => records,
35
36
  require: () => require2,
37
+ schema: () => schema,
36
38
  tunnel: () => tunnel,
39
+ types: () => types,
37
40
  url: () => url
38
41
  });
39
42
  module.exports = __toCommonJS(utils_exports);
@@ -48,6 +51,9 @@ var prompt = __toESM(require("./prompt-utils"));
48
51
  var records = __toESM(require("./record-utils"));
49
52
  var url = __toESM(require("./url-utils"));
50
53
  var tunnel = __toESM(require("./tunnel-utils"));
54
+ var schema = __toESM(require("./schema-utils"));
55
+ var types = __toESM(require("./type-utils"));
56
+ var guards = __toESM(require("./guard-utils"));
51
57
  // Annotate the CommonJS export names for ESM import in node:
52
58
  0 && (module.exports = {
53
59
  cache,
@@ -55,11 +61,14 @@ var tunnel = __toESM(require("./tunnel-utils"));
55
61
  emitter,
56
62
  esbuild,
57
63
  filewatcher,
64
+ guards,
58
65
  path,
59
66
  prompt,
60
67
  records,
61
68
  require,
69
+ schema,
62
70
  tunnel,
71
+ types,
63
72
  url
64
73
  });
65
74
  //# 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'\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;",
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'\nexport * as schema from './schema-utils'\nexport * as types from './type-utils'\nexport * as guards from './guard-utils'\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAAA;AAAA,EAAA;AAAA;AAAA;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;AACxB,aAAwB;AACxB,YAAuB;AACvB,aAAwB;",
6
6
  "names": ["require"]
7
7
  }
@@ -18,6 +18,7 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var record_utils_exports = {};
20
20
  __export(record_utils_exports, {
21
+ mapValues: () => mapValues,
21
22
  setNullOnMissingValues: () => setNullOnMissingValues,
22
23
  zipObjects: () => zipObjects
23
24
  });
@@ -42,8 +43,16 @@ const zipObjects = (recordA, recordB) => {
42
43
  }
43
44
  return newRecord;
44
45
  };
46
+ const mapValues = (record, fn) => {
47
+ const newRecord = {};
48
+ for (const [key, value] of Object.entries(record)) {
49
+ newRecord[key] = fn(value);
50
+ }
51
+ return newRecord;
52
+ };
45
53
  // Annotate the CommonJS export names for ESM import in node:
46
54
  0 && (module.exports = {
55
+ mapValues,
47
56
  setNullOnMissingValues,
48
57
  zipObjects
49
58
  });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/record-utils.ts"],
4
- "sourcesContent": ["export const setNullOnMissingValues = <A, B>(\n record: Record<string, A> = {},\n oldRecord: Record<string, B> = {}\n): Record<string, A | null> => {\n const newRecord: Record<string, A | null> = {}\n\n for (const [key, value] of Object.entries(record)) {\n newRecord[key] = value\n }\n\n for (const value of Object.keys(oldRecord)) {\n if (!record[value]) {\n newRecord[value] = null\n }\n }\n\n return newRecord\n}\n\nexport const zipObjects = <A, B>(\n recordA: Record<string, A>,\n recordB: Record<string, B>\n): Record<string, [A | null, B | null]> => {\n const allKeys = new Set([...Object.keys(recordA), ...Object.keys(recordB)])\n const newRecord: Record<string, [A | null, B | null]> = {}\n\n for (const key of allKeys) {\n newRecord[key] = [recordA[key] ?? null, recordB[key] ?? null]\n }\n\n return newRecord\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,MAAM,yBAAyB,CACpC,SAA4B,CAAC,GAC7B,YAA+B,CAAC,MACH;AAC7B,QAAM,YAAsC,CAAC;AAE7C,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,cAAU,OAAO;AAAA,EACnB;AAEA,aAAW,SAAS,OAAO,KAAK,SAAS,GAAG;AAC1C,QAAI,CAAC,OAAO,QAAQ;AAClB,gBAAU,SAAS;AAAA,IACrB;AAAA,EACF;AAEA,SAAO;AACT;AAEO,MAAM,aAAa,CACxB,SACA,YACyC;AACzC,QAAM,UAAU,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAK,OAAO,GAAG,GAAG,OAAO,KAAK,OAAO,CAAC,CAAC;AAC1E,QAAM,YAAkD,CAAC;AAEzD,aAAW,OAAO,SAAS;AACzB,cAAU,OAAO,CAAC,QAAQ,QAAQ,MAAM,QAAQ,QAAQ,IAAI;AAAA,EAC9D;AAEA,SAAO;AACT;",
4
+ "sourcesContent": ["export const setNullOnMissingValues = <A, B>(\n record: Record<string, A> = {},\n oldRecord: Record<string, B> = {}\n): Record<string, A | null> => {\n const newRecord: Record<string, A | null> = {}\n\n for (const [key, value] of Object.entries(record)) {\n newRecord[key] = value\n }\n\n for (const value of Object.keys(oldRecord)) {\n if (!record[value]) {\n newRecord[value] = null\n }\n }\n\n return newRecord\n}\n\nexport const zipObjects = <A, B>(\n recordA: Record<string, A>,\n recordB: Record<string, B>\n): Record<string, [A | null, B | null]> => {\n const allKeys = new Set([...Object.keys(recordA), ...Object.keys(recordB)])\n const newRecord: Record<string, [A | null, B | null]> = {}\n\n for (const key of allKeys) {\n newRecord[key] = [recordA[key] ?? null, recordB[key] ?? null]\n }\n\n return newRecord\n}\n\nexport const mapValues = <A, B>(record: Record<string, A>, fn: (value: A) => B): Record<string, B> => {\n const newRecord: Record<string, B> = {}\n\n for (const [key, value] of Object.entries(record)) {\n newRecord[key] = fn(value)\n }\n\n return newRecord\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,MAAM,yBAAyB,CACpC,SAA4B,CAAC,GAC7B,YAA+B,CAAC,MACH;AAC7B,QAAM,YAAsC,CAAC;AAE7C,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,cAAU,OAAO;AAAA,EACnB;AAEA,aAAW,SAAS,OAAO,KAAK,SAAS,GAAG;AAC1C,QAAI,CAAC,OAAO,QAAQ;AAClB,gBAAU,SAAS;AAAA,IACrB;AAAA,EACF;AAEA,SAAO;AACT;AAEO,MAAM,aAAa,CACxB,SACA,YACyC;AACzC,QAAM,UAAU,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAK,OAAO,GAAG,GAAG,OAAO,KAAK,OAAO,CAAC,CAAC;AAC1E,QAAM,YAAkD,CAAC;AAEzD,aAAW,OAAO,SAAS;AACzB,cAAU,OAAO,CAAC,QAAQ,QAAQ,MAAM,QAAQ,QAAQ,IAAI;AAAA,EAC9D;AAEA,SAAO;AACT;AAEO,MAAM,YAAY,CAAO,QAA2B,OAA2C;AACpG,QAAM,YAA+B,CAAC;AAEtC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,cAAU,OAAO,GAAG,KAAK;AAAA,EAC3B;AAEA,SAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -22,31 +22,34 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
22
22
  mod
23
23
  ));
24
24
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
25
- var channel_exports = {};
26
- __export(channel_exports, {
27
- ChannelModule: () => ChannelModule
25
+ var schema_utils_exports = {};
26
+ __export(schema_utils_exports, {
27
+ mapZodToJsonSchema: () => mapZodToJsonSchema
28
28
  });
29
- module.exports = __toCommonJS(channel_exports);
30
- var import_bluebird = __toESM(require("bluebird"));
31
- var import_utils = require("../utils");
32
- var import_message = require("./message");
33
- var import_module = require("./module");
34
- class ChannelModule extends import_module.ReExportTypeModule {
35
- static async create(channelName, channel) {
36
- const messages = channel.messages ?? {};
37
- const messageModules = await import_bluebird.default.map(
38
- Object.entries(messages),
39
- ([messageName, message]) => import_message.MessageModule.create(messageName, message)
40
- );
41
- const inst = new ChannelModule({
42
- exportName: `Channel${import_utils.casing.to.pascalCase(channelName)}`
43
- });
44
- inst.pushDep(...messageModules);
45
- return inst;
29
+ module.exports = __toCommonJS(schema_utils_exports);
30
+ var import_zod_to_json_schema = __toESM(require("@bpinternal/zod-to-json-schema"));
31
+ const isObjectSchema = (schema) => schema?.type === "object";
32
+ function mapZodToJsonSchema(definition) {
33
+ const schema = (0, import_zod_to_json_schema.default)(definition.schema, { errorMessages: true });
34
+ if (!isObjectSchema(schema) || !definition.ui) {
35
+ return schema;
46
36
  }
37
+ for (const [key, value] of Object.entries(definition.ui ?? {})) {
38
+ const property = schema.properties?.[key];
39
+ if (!property) {
40
+ continue;
41
+ }
42
+ if (!!value?.title) {
43
+ property.title = value.title;
44
+ }
45
+ if (!!value?.examples) {
46
+ property.examples = value.examples;
47
+ }
48
+ }
49
+ return schema;
47
50
  }
48
51
  // Annotate the CommonJS export names for ESM import in node:
49
52
  0 && (module.exports = {
50
- ChannelModule
53
+ mapZodToJsonSchema
51
54
  });
52
- //# sourceMappingURL=channel.js.map
55
+ //# sourceMappingURL=schema-utils.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils/schema-utils.ts"],
4
+ "sourcesContent": ["import zodToJsonSchema from '@bpinternal/zod-to-json-schema'\nimport type { JsonSchema7Type } from '@bpinternal/zod-to-json-schema/src/parseDef'\nimport type { JsonSchema7ObjectType } from '@bpinternal/zod-to-json-schema/src/parsers/object'\nimport { z } from 'zod'\n\ntype SchemaOptions = {\n title?: string\n examples?: any[]\n}\n\ntype SchemaDefinition = {\n schema: z.ZodObject<any>\n ui?: Record<string, SchemaOptions | undefined>\n}\n\nconst isObjectSchema = (schema: JsonSchema7Type): schema is JsonSchema7ObjectType => (schema as any)?.type === 'object'\n\nexport function mapZodToJsonSchema(definition: SchemaDefinition): ReturnType<typeof zodToJsonSchema> {\n const schema = zodToJsonSchema(definition.schema, { errorMessages: true })\n if (!isObjectSchema(schema) || !definition.ui) {\n return schema\n }\n\n for (const [key, value] of Object.entries(definition.ui ?? {})) {\n const property = schema.properties?.[key] as (JsonSchema7Type & { title?: string; examples?: any[] }) | undefined\n\n if (!property) {\n continue\n }\n\n if (!!value?.title) {\n property.title = value.title\n }\n\n if (!!value?.examples) {\n property.examples = value.examples\n }\n }\n\n return schema\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gCAA4B;AAe5B,MAAM,iBAAiB,CAAC,WAA8D,QAAgB,SAAS;AAExG,SAAS,mBAAmB,YAAkE;AACnG,QAAM,aAAS,0BAAAA,SAAgB,WAAW,QAAQ,EAAE,eAAe,KAAK,CAAC;AACzE,MAAI,CAAC,eAAe,MAAM,KAAK,CAAC,WAAW,IAAI;AAC7C,WAAO;AAAA,EACT;AAEA,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,WAAW,MAAM,CAAC,CAAC,GAAG;AAC9D,UAAM,WAAW,OAAO,aAAa;AAErC,QAAI,CAAC,UAAU;AACb;AAAA,IACF;AAEA,QAAI,CAAC,CAAC,OAAO,OAAO;AAClB,eAAS,QAAQ,MAAM;AAAA,IACzB;AAEA,QAAI,CAAC,CAAC,OAAO,UAAU;AACrB,eAAS,WAAW,MAAM;AAAA,IAC5B;AAAA,EACF;AAEA,SAAO;AACT;",
6
+ "names": ["zodToJsonSchema"]
7
+ }