@botonic/nx-plugin 2.31.0 → 2.32.0-alpha.0

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 (78) hide show
  1. package/migrations.json +1 -8
  2. package/package.json +7 -4
  3. package/src/executors/build-node-app/executor-impl.d.ts +5 -0
  4. package/src/executors/build-node-app/executor-impl.js +65 -0
  5. package/src/executors/build-node-app/executor.d.ts +4 -2
  6. package/src/executors/build-node-app/executor.js +3 -41
  7. package/src/executors/delete-bot/executor-impl.d.ts +5 -0
  8. package/src/executors/delete-bot/executor-impl.js +110 -0
  9. package/src/executors/delete-bot/executor.d.ts +4 -2
  10. package/src/executors/delete-bot/executor.js +3 -86
  11. package/src/executors/deploy-netlify-snapshot/executor-impl.d.ts +8 -0
  12. package/src/executors/deploy-netlify-snapshot/executor-impl.js +79 -0
  13. package/src/executors/deploy-netlify-snapshot/executor.d.ts +4 -5
  14. package/src/executors/deploy-netlify-snapshot/executor.js +3 -55
  15. package/src/executors/deploy-to-hubtype/executor-impl.d.ts +5 -0
  16. package/src/executors/deploy-to-hubtype/executor-impl.js +172 -0
  17. package/src/executors/deploy-to-hubtype/executor.d.ts +4 -2
  18. package/src/executors/deploy-to-hubtype/executor.js +3 -148
  19. package/src/executors/e2e-webchat/executor-impl.d.ts +5 -0
  20. package/src/executors/e2e-webchat/executor-impl.js +134 -0
  21. package/src/executors/e2e-webchat/executor.d.ts +4 -2
  22. package/src/executors/e2e-webchat/executor.js +4 -111
  23. package/src/executors/integrate-provider/executor-impl.d.ts +5 -0
  24. package/src/executors/integrate-provider/executor-impl.js +153 -0
  25. package/src/executors/integrate-provider/executor.d.ts +4 -2
  26. package/src/executors/integrate-provider/executor.js +3 -129
  27. package/src/executors/login-to-hubtype/executor-impl.d.ts +5 -0
  28. package/src/executors/login-to-hubtype/executor-impl.js +77 -0
  29. package/src/executors/login-to-hubtype/executor.d.ts +4 -2
  30. package/src/executors/login-to-hubtype/executor.js +3 -53
  31. package/src/executors/logout-from-hubtype/executor-impl.d.ts +3 -0
  32. package/src/executors/logout-from-hubtype/executor-impl.js +54 -0
  33. package/src/executors/logout-from-hubtype/executor.d.ts +5 -1
  34. package/src/executors/logout-from-hubtype/executor.js +3 -30
  35. package/src/executors/run-lambda/executor-impl.d.ts +5 -0
  36. package/src/executors/run-lambda/executor-impl.js +65 -0
  37. package/src/executors/run-lambda/executor.d.ts +4 -2
  38. package/src/executors/run-lambda/executor.js +3 -41
  39. package/src/executors/serve-bot/executor-impl.d.ts +5 -0
  40. package/src/executors/serve-bot/executor-impl.js +530 -0
  41. package/src/executors/serve-bot/executor.d.ts +4 -2
  42. package/src/executors/serve-bot/executor.js +3 -506
  43. package/src/generators/action/generator-impl.d.ts +4 -0
  44. package/src/generators/action/generator-impl.js +112 -0
  45. package/src/generators/action/generator.d.ts +2 -3
  46. package/src/generators/action/generator.js +2 -87
  47. package/src/generators/bot-app/files/vite/webchat.config.ts.template +10 -2
  48. package/src/generators/bot-app/generator-impl.d.ts +4 -0
  49. package/src/generators/bot-app/generator-impl.js +328 -0
  50. package/src/generators/bot-app/generator.d.ts +2 -4
  51. package/src/generators/bot-app/generator.js +2 -295
  52. package/src/generators/custom-message/generator-impl.d.ts +4 -0
  53. package/src/generators/custom-message/generator-impl.js +235 -0
  54. package/src/generators/custom-message/generator.d.ts +2 -3
  55. package/src/generators/custom-message/generator.js +2 -210
  56. package/src/generators/preset/generator-impl.d.ts +4 -0
  57. package/src/generators/preset/generator-impl.js +127 -0
  58. package/src/generators/preset/generator.d.ts +2 -4
  59. package/src/generators/preset/generator.js +2 -95
  60. package/src/generators/remove-custom-message/generator-impl.d.ts +4 -0
  61. package/src/generators/remove-custom-message/generator-impl.js +259 -0
  62. package/src/generators/remove-custom-message/generator.d.ts +2 -3
  63. package/src/generators/remove-custom-message/generator.js +2 -234
  64. package/src/generators/webview/generator-impl.d.ts +4 -0
  65. package/src/generators/webview/generator-impl.js +179 -0
  66. package/src/generators/webview/generator.d.ts +2 -3
  67. package/src/generators/webview/generator.js +2 -154
  68. package/src/index.d.ts +1 -0
  69. package/src/index.js +3 -1
  70. package/src/lib/delegate/delegate-executor.d.ts +6 -0
  71. package/src/lib/delegate/delegate-executor.js +119 -0
  72. package/src/lib/delegate/delegate-generator.d.ts +2 -0
  73. package/src/lib/delegate/delegate-generator.js +128 -0
  74. package/src/lib/serve-mode/index.d.ts +25 -0
  75. package/src/lib/serve-mode/index.js +183 -0
  76. package/src/generators/bot-app/files/vite/plugins/dev-log-viewer-html.plugin.ts.template +0 -65
  77. package/src/migrations/install-claude-update-skills/install-claude-update-skills.migration.d.ts +0 -2
  78. package/src/migrations/install-claude-update-skills/install-claude-update-skills.migration.js +0 -290
@@ -21,45 +21,7 @@ __export(executor_exports, {
21
21
  default: () => runLambdaExecutor
22
22
  });
23
23
  module.exports = __toCommonJS(executor_exports);
24
- var import_child_process = require("child_process");
25
- var import_path = require("path");
26
- var import_executor_helpers = require("../../lib/util/executor-helpers");
27
- async function runLambdaExecutor(options, context) {
28
- const projectRoot = (0, import_executor_helpers.resolveProjectPath)(context);
29
- const lambdaPath = options.lambdaPath || "src/server/lambda";
30
- const samCommand = options.samCommand || "sam local start-lambda";
31
- const fullLambdaPath = (0, import_path.join)(projectRoot, lambdaPath);
32
- console.info(`\u{1F680} Starting AWS SAM local lambda server...`);
33
- console.info(`\u{1F4C1} Lambda directory: ${fullLambdaPath}`);
34
- console.info(`\u{1F527} Command: ${samCommand}`);
35
- return new Promise((resolve) => {
36
- const [executable, ...args] = samCommand.split(" ");
37
- const child = (0, import_child_process.spawn)(executable, args, {
38
- cwd: fullLambdaPath,
39
- stdio: "inherit",
40
- // This will pipe stdout/stderr directly to the console
41
- shell: true
42
- });
43
- child.on("error", (error) => {
44
- console.error(`\u274C Error running lambda server:`, error.message);
45
- resolve({ success: false });
46
- });
47
- child.on("close", (code) => {
48
- if (code === 0) {
49
- console.log("\u2705 Lambda server stopped successfully");
50
- resolve({ success: true });
51
- } else {
52
- console.error(`\u274C Lambda server exited with code ${code}`);
53
- resolve({ success: false });
54
- }
55
- });
56
- process.on("SIGINT", () => {
57
- console.log("\n\u{1F6D1} Stopping lambda server...");
58
- child.kill("SIGINT");
59
- });
60
- process.on("SIGTERM", () => {
61
- console.log("\n\u{1F6D1} Stopping lambda server...");
62
- child.kill("SIGTERM");
63
- });
64
- });
24
+ var import_delegate_executor = require("../../lib/delegate/delegate-executor");
25
+ async function runLambdaExecutor(options, ctx) {
26
+ return (0, import_delegate_executor.runLocalExecutor)(__filename, "run-lambda", options, ctx);
65
27
  }
@@ -0,0 +1,5 @@
1
+ import type { ExecutorContext } from '@nx/devkit';
2
+ import type { ServeBotExecutorSchema } from './schema';
3
+ export default function serveBotExecutor(options: ServeBotExecutorSchema, context: ExecutorContext): Promise<{
4
+ success: boolean;
5
+ }>;
@@ -0,0 +1,530 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var executor_impl_exports = {};
30
+ __export(executor_impl_exports, {
31
+ default: () => serveBotExecutor
32
+ });
33
+ module.exports = __toCommonJS(executor_impl_exports);
34
+ var import_child_process = require("child_process");
35
+ var import_fs = require("fs");
36
+ var import_path = require("path");
37
+ var readline = __toESM(require("readline"));
38
+ var import_cloudflared_tunnel = require("../../lib/cloudflared-tunnel");
39
+ var import_executor_helpers = require("../../lib/util/executor-helpers");
40
+ var import_sam_container_cleanup = require("../../lib/util/sam-container-cleanup");
41
+ const colors = {
42
+ bot: "\x1B[36m",
43
+ // Cyan
44
+ lambda: "\x1B[33m",
45
+ // Yellow
46
+ webchat: "\x1B[32m",
47
+ // Green
48
+ webviews: "\x1B[35m",
49
+ // Magenta
50
+ reset: "\x1B[0m",
51
+ dim: "\x1B[2m",
52
+ bold: "\x1B[1m"
53
+ };
54
+ let logFilePath = null;
55
+ function initLogFile(projectRoot) {
56
+ const logsDir = (0, import_path.join)(projectRoot, ".botonic", "logs");
57
+ (0, import_fs.mkdirSync)(logsDir, { recursive: true });
58
+ const logPath = (0, import_path.join)(logsDir, "serve-bot.log");
59
+ (0, import_fs.writeFileSync)(logPath, "");
60
+ return logPath;
61
+ }
62
+ function writeToLogFile(line) {
63
+ if (logFilePath) {
64
+ try {
65
+ (0, import_fs.appendFileSync)(logFilePath, `${line}
66
+ `);
67
+ } catch {
68
+ }
69
+ }
70
+ }
71
+ function checkFrontailInstalled(cwd) {
72
+ try {
73
+ (0, import_child_process.execSync)(`${cwd}/node_modules/.bin/frontail --help`, {
74
+ stdio: "pipe",
75
+ cwd
76
+ });
77
+ return true;
78
+ } catch {
79
+ return false;
80
+ }
81
+ }
82
+ function startFrontail(logPath, port, cwd) {
83
+ if (!checkFrontailInstalled(cwd)) {
84
+ console.warn(`${colors.bold}\u26A0\uFE0F frontail is not installed.${colors.reset}`);
85
+ console.warn(
86
+ ` Run: ${colors.dim}pnpm install${colors.reset} to install dependencies
87
+ `
88
+ );
89
+ return null;
90
+ }
91
+ const frontailProcess = (0, import_child_process.spawn)(
92
+ `${cwd}/node_modules/.bin/frontail`,
93
+ [
94
+ "--port",
95
+ port.toString(),
96
+ "--theme",
97
+ "dark",
98
+ "--lines",
99
+ "500",
100
+ "--ui-hide-topbar",
101
+ logPath
102
+ ],
103
+ {
104
+ cwd,
105
+ stdio: ["ignore", "pipe", "pipe"],
106
+ detached: false
107
+ }
108
+ );
109
+ frontailProcess.on("error", (error) => {
110
+ console.error(
111
+ `${colors.dim}[log-viewer]${colors.reset} Error: ${error.message}`
112
+ );
113
+ });
114
+ return frontailProcess;
115
+ }
116
+ function tryReadWebchatDevPort(projectRoot) {
117
+ try {
118
+ const configPath = (0, import_path.join)(projectRoot, "vite", "build.config.ts");
119
+ const content = (0, import_fs.readFileSync)(configPath, "utf8");
120
+ const match = content.match(/webchat:\s*\{\s*port:\s*(\d+)/);
121
+ if (match) return parseInt(match[1], 10);
122
+ } catch {
123
+ }
124
+ return 4201;
125
+ }
126
+ function getAppIdFromEnvFile(projectRoot) {
127
+ const envFilePath = (0, import_path.join)(projectRoot, ".env.local");
128
+ if (!(0, import_fs.existsSync)(envFilePath)) {
129
+ return null;
130
+ }
131
+ try {
132
+ const envContent = (0, import_fs.readFileSync)(envFilePath, "utf8");
133
+ const lines = envContent.split("\n");
134
+ const appIdKey = "VITE_HUBTYPE_APP_ID";
135
+ for (const line of lines) {
136
+ if (line.startsWith(`${appIdKey}=`)) {
137
+ return line.split("=")[1]?.trim();
138
+ }
139
+ }
140
+ return null;
141
+ } catch (error) {
142
+ const errorMessage = error instanceof Error ? error.message : String(error);
143
+ console.warn(`\u26A0\uFE0F Could not read .env.local file: ${errorMessage}`);
144
+ return null;
145
+ }
146
+ }
147
+ function prefixOutput(stream, prefix, color) {
148
+ if (!stream) return;
149
+ const rl = readline.createInterface({ input: stream });
150
+ rl.on("line", (line) => {
151
+ const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false });
152
+ const formattedLine = `${colors.dim}${timestamp}${colors.reset} ${color}[${prefix}]${colors.reset} ${line}`;
153
+ console.log(formattedLine);
154
+ writeToLogFile(`${timestamp} [${prefix}] ${line}`);
155
+ });
156
+ }
157
+ function spawnProcess(command, name, color, cwd) {
158
+ const child = (0, import_child_process.spawn)("sh", ["-c", command], {
159
+ cwd,
160
+ stdio: ["ignore", "pipe", "pipe"],
161
+ env: { ...process.env, FORCE_COLOR: "1" }
162
+ });
163
+ prefixOutput(child.stdout, name, color);
164
+ prefixOutput(child.stderr, name, color);
165
+ return { name, color, process: child };
166
+ }
167
+ async function serveBotExecutor(options, context) {
168
+ if (!context.projectName) {
169
+ throw new Error("Project name is required");
170
+ }
171
+ const projectRoot = context.projectsConfigurations?.projects?.[context.projectName]?.root;
172
+ if (!projectRoot) {
173
+ throw new Error(`Could not find project root for ${context.projectName}`);
174
+ }
175
+ const configuration = options.configuration || "prod";
176
+ const fullProjectRoot = (0, import_path.join)(context.root, projectRoot);
177
+ const configPath = (0, import_path.join)(context.root, projectRoot, "vite.config.ts");
178
+ const appId = getAppIdFromEnvFile(fullProjectRoot);
179
+ if (!appId) {
180
+ console.warn(
181
+ `\u26A0\uFE0F VITE_HUBTYPE_APP_ID not found in .env.local \u2014 will be set automatically after deploy`
182
+ );
183
+ }
184
+ console.log(`${colors.dim}Clearing Vite cache...${colors.reset}`);
185
+ const viteCacheDirs = [
186
+ (0, import_path.join)(context.root, "node_modules", ".vite"),
187
+ (0, import_path.join)(fullProjectRoot, "node_modules", ".vite"),
188
+ (0, import_path.join)(fullProjectRoot, ".vite")
189
+ ];
190
+ for (const dir of viteCacheDirs) {
191
+ try {
192
+ if ((0, import_fs.existsSync)(dir)) {
193
+ (0, import_child_process.execSync)(`rm -rf "${dir}"`, { stdio: "pipe" });
194
+ }
195
+ } catch {
196
+ }
197
+ }
198
+ console.log(`${colors.dim}Vite cache cleared.${colors.reset}`);
199
+ const cleanupResult = (0, import_sam_container_cleanup.cleanupPreviousSamContainersByLabel)(fullProjectRoot);
200
+ if (cleanupResult === "removed") {
201
+ console.log(
202
+ `${colors.dim}[lambda] Removed previous run's container (reused slot).${colors.reset}`
203
+ );
204
+ } else if (cleanupResult === "none") {
205
+ console.log(
206
+ `${colors.dim}[lambda] No previous Lambda container to clean up.${colors.reset}`
207
+ );
208
+ }
209
+ logFilePath = null;
210
+ const logViewerPort = options.logViewerPort ?? 9001;
211
+ const webchatDevPort = tryReadWebchatDevPort(fullProjectRoot);
212
+ logFilePath = initLogFile(fullProjectRoot);
213
+ const frontailProcess = startFrontail(
214
+ logFilePath,
215
+ logViewerPort,
216
+ context.root
217
+ );
218
+ const logViewerInfo = `${colors.dim}Webchat:${colors.reset} ${colors.bold}http://localhost:${webchatDevPort}/?logs=${logViewerPort}${colors.reset} (with logs panel)
219
+ ${colors.dim}Log viewer:${colors.reset} http://localhost:${logViewerPort}`;
220
+ const useTunnel = true;
221
+ const tunnelPort = options.tunnelPort ?? 3001;
222
+ let effectiveLambdaEndpoint = options.lambdaEndpoint;
223
+ let startLambda = !options.skipLambda && !effectiveLambdaEndpoint;
224
+ let tunnelDeployResult;
225
+ let devSessionLambdaFunctionName;
226
+ let registeredTunnelUrl;
227
+ let deployedBotId;
228
+ let selectedBotId;
229
+ let deployedApiUrl;
230
+ let deployedAccessToken;
231
+ let deployedRefreshToken;
232
+ let deployedClientId;
233
+ if (useTunnel) {
234
+ await (0, import_executor_helpers.ensureHubtypeLoginBeforeTunnel)(context, fullProjectRoot, {
235
+ env: options.env,
236
+ configuration
237
+ });
238
+ try {
239
+ selectedBotId = await (0, import_executor_helpers.selectBotForServe)(context, fullProjectRoot, {
240
+ env: options.env,
241
+ configuration,
242
+ botName: options.botName
243
+ });
244
+ } catch (botDeployErr) {
245
+ if ((0, import_executor_helpers.isBotDeployedRestartRequired)(botDeployErr)) {
246
+ if (frontailProcess) {
247
+ frontailProcess.kill("SIGTERM");
248
+ }
249
+ if (process.stdin.isTTY) {
250
+ try {
251
+ process.stdin.setRawMode(false);
252
+ } catch {
253
+ }
254
+ }
255
+ process.stdin.pause();
256
+ process.stdin.unref();
257
+ return { success: true };
258
+ }
259
+ throw botDeployErr;
260
+ }
261
+ console.log(
262
+ `${colors.dim}Starting tunnel flow (Lambda + cloudflared + dev session registration)...${colors.reset}
263
+ `
264
+ );
265
+ }
266
+ const processes = [];
267
+ try {
268
+ if (useTunnel) {
269
+ const lambdaPath = (0, import_path.join)(fullProjectRoot, "src/server/lambda");
270
+ const lambdaCommand = "sam local start-lambda --warm-containers EAGER --skip-pull-image";
271
+ processes.push(
272
+ spawnProcess(lambdaCommand, "lambda", colors.lambda, lambdaPath)
273
+ );
274
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
275
+ console.log(
276
+ `${colors.dim}Starting Cloudflare tunnel (cloudflared)...${colors.reset}`
277
+ );
278
+ const { url: tunnelUrl, process: cloudflaredProcess } = await (0, import_cloudflared_tunnel.startCloudflaredTunnel)(tunnelPort);
279
+ processes.push({
280
+ name: "tunnel",
281
+ color: colors.lambda,
282
+ process: cloudflaredProcess
283
+ });
284
+ console.log(`${colors.dim}Tunnel URL: ${tunnelUrl}${colors.reset}
285
+ `);
286
+ console.log(
287
+ `${colors.dim}Setting up dev bot and writing dev session env vars...${colors.reset}`
288
+ );
289
+ const deployResult = await (0, import_executor_helpers.performDeployLocalRuntimeWithEndpoint)(
290
+ context,
291
+ fullProjectRoot,
292
+ tunnelUrl,
293
+ {
294
+ env: options.env,
295
+ configuration,
296
+ whatsappPhone: options.phone,
297
+ selectedBotId
298
+ }
299
+ );
300
+ tunnelDeployResult = {
301
+ targetEnvironment: deployResult.targetEnvironment,
302
+ environmentVariables: deployResult.environmentVariables,
303
+ teardownWebchat: deployResult.teardownWebchat
304
+ };
305
+ devSessionLambdaFunctionName = deployResult.lambdaFunctionName;
306
+ registeredTunnelUrl = tunnelUrl;
307
+ deployedBotId = deployResult.botId ?? "";
308
+ deployedApiUrl = deployResult.apiUrl ?? "https://api.hubtype.com";
309
+ deployedAccessToken = deployResult.accessToken ?? "";
310
+ deployedRefreshToken = deployResult.refreshToken ?? "";
311
+ deployedClientId = deployResult.clientId ?? "";
312
+ const resolvedEnv = ["local", "dev", "dev2", "qa", "prod"].includes(deployResult.targetEnvironment) ? deployResult.targetEnvironment : "local";
313
+ (0, import_executor_helpers.writeEnvVarToEnvFile)(
314
+ fullProjectRoot,
315
+ "VITE_DEV_SESSION_URL",
316
+ tunnelUrl,
317
+ resolvedEnv
318
+ );
319
+ if (devSessionLambdaFunctionName) {
320
+ (0, import_executor_helpers.writeEnvVarToEnvFile)(
321
+ fullProjectRoot,
322
+ "VITE_DEV_LAMBDA_FUNCTION_NAME",
323
+ devSessionLambdaFunctionName,
324
+ resolvedEnv
325
+ );
326
+ }
327
+ (0, import_executor_helpers.writeEnvVarToEnvFile)(
328
+ fullProjectRoot,
329
+ "VITE_DEV_BOT_ID",
330
+ deployResult.botId ?? "",
331
+ resolvedEnv
332
+ );
333
+ (0, import_executor_helpers.writeEnvVarToEnvFile)(
334
+ fullProjectRoot,
335
+ "VITE_DEV_API_URL",
336
+ deployResult.apiUrl ?? "https://api.hubtype.com",
337
+ resolvedEnv
338
+ );
339
+ (0, import_executor_helpers.writeEnvVarToEnvFile)(
340
+ fullProjectRoot,
341
+ "VITE_DEV_ACCESS_TOKEN",
342
+ deployResult.accessToken ?? "",
343
+ resolvedEnv
344
+ );
345
+ (0, import_executor_helpers.writeEnvVarToEnvFile)(
346
+ fullProjectRoot,
347
+ "VITE_DEV_REFRESH_TOKEN",
348
+ deployResult.refreshToken ?? "",
349
+ resolvedEnv
350
+ );
351
+ (0, import_executor_helpers.writeEnvVarToEnvFile)(
352
+ fullProjectRoot,
353
+ "VITE_DEV_CLIENT_ID",
354
+ deployResult.clientId ?? "",
355
+ resolvedEnv
356
+ );
357
+ console.log(
358
+ `${colors.dim}VITE_DEV_SESSION_URL written to .env.${resolvedEnv}${colors.reset}`
359
+ );
360
+ effectiveLambdaEndpoint = tunnelUrl;
361
+ startLambda = false;
362
+ }
363
+ } catch (tunnelError) {
364
+ const msg = tunnelError instanceof Error ? tunnelError.message : String(tunnelError);
365
+ console.error(`\u274C Tunnel flow failed: ${msg}`);
366
+ if (frontailProcess) {
367
+ frontailProcess.kill("SIGTERM");
368
+ }
369
+ return { success: false };
370
+ }
371
+ let effectiveAppId = appId;
372
+ if (useTunnel) {
373
+ const latestAppId = (0, import_executor_helpers.getAppIdFromEnvFileForConfig)(
374
+ fullProjectRoot,
375
+ configuration
376
+ );
377
+ if (latestAppId) effectiveAppId = latestAppId;
378
+ }
379
+ if (configuration !== "local" && effectiveAppId) {
380
+ await (0, import_executor_helpers.writeAppIdToEnvFile)(fullProjectRoot, effectiveAppId, configuration);
381
+ }
382
+ const useExternalLambda = Boolean(effectiveLambdaEndpoint);
383
+ if (!useTunnel) {
384
+ startLambda = !options.skipLambda && !useExternalLambda;
385
+ }
386
+ console.log(`
387
+ ${colors.bold}\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
388
+ \u2551 \u{1F680} Botonic Dev Server \u2551
389
+ \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D${colors.reset}
390
+
391
+ ${colors.dim}Project:${colors.reset} ${context.projectName}
392
+ ${colors.dim}Configuration:${colors.reset} ${configuration}
393
+ ${colors.dim}App ID:${colors.reset} ${effectiveAppId}
394
+ ${logViewerInfo}
395
+ ${useExternalLambda ? `${colors.dim}Lambda (external):${colors.reset} ${effectiveLambdaEndpoint}
396
+ ` : ""}
397
+ ${colors.bot}[bot]${colors.reset} - Node/Lambda build watcher
398
+ ${startLambda ? `${colors.lambda}[lambda]${colors.reset} - AWS SAM local lambda server` : useExternalLambda ? `${colors.lambda}[lambda]${colors.reset} - Using external endpoint (no Docker)` : ""}
399
+ ${colors.webchat}[webchat]${colors.reset} - Webchat Vite dev server
400
+ ${colors.webviews}[webviews]${colors.reset} - Webviews Vite dev server
401
+ `);
402
+ if (useExternalLambda && !useTunnel) {
403
+ console.log(
404
+ `${colors.dim}\u{1F4A1} Ensure you have run the serve target first to register your dev session.${colors.reset}
405
+ `
406
+ );
407
+ }
408
+ for (const dir of viteCacheDirs) {
409
+ try {
410
+ if ((0, import_fs.existsSync)(dir)) {
411
+ (0, import_child_process.execSync)(`rm -rf "${dir}"`, { stdio: "pipe" });
412
+ }
413
+ } catch {
414
+ }
415
+ }
416
+ try {
417
+ const buildCommand = `VITE_CJS_IGNORE_WARNING=true BUILD_TARGET=node vite build --config ${configPath} --watch`;
418
+ processes.push(
419
+ spawnProcess(buildCommand, "bot", colors.bot, fullProjectRoot)
420
+ );
421
+ await new Promise((resolve) => setTimeout(resolve, 3e3));
422
+ if (startLambda) {
423
+ const lambdaPath = (0, import_path.join)(fullProjectRoot, "src/server/lambda");
424
+ const lambdaCommand = "sam local start-lambda --warm-containers EAGER --skip-pull-image";
425
+ processes.push(
426
+ spawnProcess(lambdaCommand, "lambda", colors.lambda, lambdaPath)
427
+ );
428
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
429
+ }
430
+ const noOpenEnv = options.open === false ? "VITE_SERVE_OPEN=false " : "";
431
+ const viteEnvAppId = `VITE_HUBTYPE_APP_ID=${effectiveAppId}`;
432
+ const viteDevSessionEnv = registeredTunnelUrl && devSessionLambdaFunctionName ? `VITE_DEV_SESSION_URL=${registeredTunnelUrl} VITE_DEV_LAMBDA_FUNCTION_NAME=${devSessionLambdaFunctionName} ` : "";
433
+ const viteDevCredentialsEnv = deployedBotId ? [
434
+ `VITE_DEV_BOT_ID=${deployedBotId}`,
435
+ `VITE_DEV_API_URL=${deployedApiUrl ?? "https://api.hubtype.com"}`,
436
+ `VITE_DEV_ACCESS_TOKEN=${deployedAccessToken ?? ""}`,
437
+ `VITE_DEV_REFRESH_TOKEN=${deployedRefreshToken ?? ""}`,
438
+ `VITE_DEV_CLIENT_ID=${deployedClientId ?? ""}`
439
+ ].join(" ") + " " : "";
440
+ const logViewerEnv = `LOG_VIEWER_PORT=${logViewerPort} `;
441
+ const botHasWhatsapp = deployedBotId ? (0, import_executor_helpers.selectedBotHasActiveWhatsapp)(deployedBotId) : false;
442
+ const whatsappPanelEnv = botHasWhatsapp ? `BOT_HAS_WHATSAPP=1 ${options.phone ? `WHATSAPP_PANEL_PHONE=${options.phone} ` : ""}` : "";
443
+ const webchatCommand = `${noOpenEnv}${logViewerEnv}${viteDevSessionEnv}${viteDevCredentialsEnv}${whatsappPanelEnv}${viteEnvAppId} TARGET_APP=webchat MODE=${configuration} vite --config ${configPath}`;
444
+ processes.push(
445
+ spawnProcess(webchatCommand, "webchat", colors.webchat, fullProjectRoot)
446
+ );
447
+ if (!options.skipWebviews) {
448
+ const webviewsCommand = `${noOpenEnv}${viteDevSessionEnv}${viteEnvAppId} TARGET_APP=webviews MODE=${configuration} vite --config ${configPath}`;
449
+ processes.push(
450
+ spawnProcess(
451
+ webviewsCommand,
452
+ "webviews",
453
+ colors.webviews,
454
+ fullProjectRoot
455
+ )
456
+ );
457
+ }
458
+ let cleanupCalled = false;
459
+ const cleanup = () => {
460
+ if (cleanupCalled) return;
461
+ cleanupCalled = true;
462
+ console.log(
463
+ `
464
+ ${colors.bold}\u{1F6D1} Shutting down all processes...${colors.reset}`
465
+ );
466
+ try {
467
+ const envConfig = ["local", "dev", "dev2", "qa", "prod"].includes(tunnelDeployResult?.targetEnvironment ?? "") ? tunnelDeployResult.targetEnvironment : "local";
468
+ (0, import_executor_helpers.writeEnvVarToEnvFile)(
469
+ fullProjectRoot,
470
+ "VITE_DEV_SESSION_URL",
471
+ "",
472
+ envConfig
473
+ );
474
+ (0, import_executor_helpers.writeEnvVarToEnvFile)(
475
+ fullProjectRoot,
476
+ "VITE_DEV_LAMBDA_FUNCTION_NAME",
477
+ "",
478
+ envConfig
479
+ );
480
+ } catch {
481
+ }
482
+ processes.forEach(({ name, color, process: proc }) => {
483
+ console.log(`${color}[${name}]${colors.reset} Stopping...`);
484
+ proc.kill("SIGTERM");
485
+ });
486
+ if (frontailProcess) {
487
+ console.log(
488
+ `${colors.dim}[log-viewer]${colors.reset} Stopping log viewer...`
489
+ );
490
+ frontailProcess.kill("SIGTERM");
491
+ }
492
+ };
493
+ process.on("SIGINT", cleanup);
494
+ process.on("SIGTERM", cleanup);
495
+ process.on("exit", cleanup);
496
+ return new Promise((resolve) => {
497
+ let exitCount = 0;
498
+ const totalProcesses = processes.length;
499
+ processes.forEach(({ name, color, process: proc }) => {
500
+ proc.on("exit", (code) => {
501
+ console.log(
502
+ `${color}[${name}]${colors.reset} Process exited with code ${code}`
503
+ );
504
+ exitCount++;
505
+ if (code !== 0 && code !== null) {
506
+ cleanup();
507
+ resolve({ success: false });
508
+ }
509
+ if (exitCount === totalProcesses) {
510
+ resolve({ success: true });
511
+ }
512
+ });
513
+ proc.on("error", (error) => {
514
+ console.error(
515
+ `${color}[${name}]${colors.reset} Error: ${error.message}`
516
+ );
517
+ cleanup();
518
+ resolve({ success: false });
519
+ });
520
+ });
521
+ });
522
+ } catch (error) {
523
+ if ((0, import_executor_helpers.isBotDeployedRestartRequired)(error)) {
524
+ return { success: true };
525
+ }
526
+ const errorMessage = error instanceof Error ? error.message : String(error);
527
+ console.error(`\u274C Error starting dev server:`, errorMessage);
528
+ return { success: false };
529
+ }
530
+ }
@@ -1,5 +1,7 @@
1
1
  import type { ExecutorContext } from '@nx/devkit';
2
2
  import type { ServeBotExecutorSchema } from './schema';
3
- export default function serveBotExecutor(options: ServeBotExecutorSchema, context: ExecutorContext): Promise<{
3
+ export default function serveBotExecutor(options: ServeBotExecutorSchema, ctx: ExecutorContext): Promise<{
4
4
  success: boolean;
5
- }>;
5
+ } | AsyncIterableIterator<{
6
+ success: boolean;
7
+ }>>;