@walkeros/cli 2.2.0-next-1772811722420 → 2.2.0-next-1773136823705

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.
package/dist/index.js CHANGED
@@ -48,6 +48,87 @@ var init_cli_logger = __esm({
48
48
  }
49
49
  });
50
50
 
51
+ // src/core/timer.ts
52
+ function createTimer() {
53
+ let startTime = 0;
54
+ let endTime = 0;
55
+ return {
56
+ start() {
57
+ startTime = Date.now();
58
+ endTime = 0;
59
+ },
60
+ end() {
61
+ endTime = Date.now();
62
+ return endTime - startTime;
63
+ },
64
+ getElapsed() {
65
+ const currentTime = endTime || Date.now();
66
+ return currentTime - startTime;
67
+ },
68
+ format() {
69
+ const elapsed = this.getElapsed();
70
+ return (elapsed / 1e3).toFixed(2) + "s";
71
+ }
72
+ };
73
+ }
74
+ var init_timer = __esm({
75
+ "src/core/timer.ts"() {
76
+ "use strict";
77
+ }
78
+ });
79
+
80
+ // src/core/output.ts
81
+ import fs from "fs-extra";
82
+ import path from "path";
83
+ async function writeResult(content, options) {
84
+ if (options.output) {
85
+ const outputPath = path.resolve(options.output);
86
+ await fs.ensureDir(path.dirname(outputPath));
87
+ await fs.writeFile(outputPath, content);
88
+ } else {
89
+ process.stdout.write(content);
90
+ process.stdout.write("\n");
91
+ }
92
+ }
93
+ function createJsonOutput(success, data, error, duration) {
94
+ return {
95
+ success,
96
+ ...data && { data },
97
+ ...error && { error },
98
+ ...duration && { duration }
99
+ };
100
+ }
101
+ function createSuccessOutput(data, duration) {
102
+ return createJsonOutput(true, data, void 0, duration);
103
+ }
104
+ function createErrorOutput(error, duration) {
105
+ return createJsonOutput(false, void 0, error, duration);
106
+ }
107
+ function formatBytes(bytes) {
108
+ return (bytes / 1024).toFixed(2);
109
+ }
110
+ var init_output = __esm({
111
+ "src/core/output.ts"() {
112
+ "use strict";
113
+ }
114
+ });
115
+
116
+ // src/core/tmp.ts
117
+ import os from "os";
118
+ import path2 from "path";
119
+ function getTmpPath(tmpDir, ...segments) {
120
+ const root = tmpDir || DEFAULT_TMP_ROOT;
121
+ const absoluteRoot = path2.isAbsolute(root) ? root : path2.resolve(root);
122
+ return path2.join(absoluteRoot, ...segments);
123
+ }
124
+ var DEFAULT_TMP_ROOT;
125
+ var init_tmp = __esm({
126
+ "src/core/tmp.ts"() {
127
+ "use strict";
128
+ DEFAULT_TMP_ROOT = os.tmpdir();
129
+ }
130
+ });
131
+
51
132
  // src/lib/config-file.ts
52
133
  import {
53
134
  readFileSync,
@@ -143,6 +224,9 @@ async function deployAuthenticatedFetch(url, init) {
143
224
  headers: { ...existingHeaders, Authorization: `Bearer ${token}` }
144
225
  });
145
226
  }
227
+ function resolveRunToken() {
228
+ return resolveDeployToken() ?? resolveToken()?.token ?? null;
229
+ }
146
230
  function resolveBaseUrl() {
147
231
  return resolveAppUrl();
148
232
  }
@@ -158,220 +242,10 @@ var init_auth = __esm({
158
242
  }
159
243
  });
160
244
 
161
- // src/version.ts
162
- import { readFileSync as readFileSync2 } from "fs";
163
- import { fileURLToPath as fileURLToPath2 } from "url";
164
- import { dirname as dirname2, join as join2 } from "path";
165
- function findPackageJson() {
166
- const paths = [
167
- join2(versionDirname, "../package.json"),
168
- // dist/ or src/
169
- join2(versionDirname, "../../package.json")
170
- // src/core/ (not used, but safe)
171
- ];
172
- for (const p2 of paths) {
173
- try {
174
- return readFileSync2(p2, "utf-8");
175
- } catch {
176
- }
177
- }
178
- return JSON.stringify({ version: "0.0.0" });
179
- }
180
- var versionFilename, versionDirname, VERSION;
181
- var init_version = __esm({
182
- "src/version.ts"() {
183
- "use strict";
184
- versionFilename = fileURLToPath2(import.meta.url);
185
- versionDirname = dirname2(versionFilename);
186
- VERSION = JSON.parse(findPackageJson()).version;
187
- }
188
- });
189
-
190
- // src/commands/run/heartbeat.ts
191
- var heartbeat_exports = {};
192
- __export(heartbeat_exports, {
193
- startHeartbeat: () => startHeartbeat
194
- });
195
- import { randomUUID } from "crypto";
196
- async function startHeartbeat(options) {
197
- const projectId = options.projectId ?? requireProjectId();
198
- const base = resolveBaseUrl();
199
- const instanceId2 = randomUUID();
200
- const healthEndpoint = options.healthEndpoint ?? "/health";
201
- const intervalSec = options.heartbeatInterval ?? 60;
202
- const log = createCLILogger();
203
- const startTime = Date.now();
204
- const heartbeatUrl = `${base}/api/projects/${projectId}/deployments/${options.deployment}/heartbeat`;
205
- const initResponse = await deployAuthenticatedFetch(heartbeatUrl, {
206
- method: "POST",
207
- headers: { "Content-Type": "application/json" },
208
- body: JSON.stringify({
209
- url: options.url,
210
- healthEndpoint,
211
- instanceId: instanceId2,
212
- cliVersion: VERSION
213
- })
214
- });
215
- if (!initResponse.ok) {
216
- const err = await initResponse.json().catch(() => ({}));
217
- throw new Error(
218
- err.error?.message || `Initial heartbeat failed (${initResponse.status})`
219
- );
220
- }
221
- const initData = await initResponse.json();
222
- log.info(
223
- `Registered as ${instanceId2} on deployment ${options.deployment} (${initData.deploymentId})`
224
- );
225
- const heartbeatTimer = setInterval(async () => {
226
- try {
227
- const resp = await deployAuthenticatedFetch(heartbeatUrl, {
228
- method: "POST",
229
- headers: { "Content-Type": "application/json" },
230
- body: JSON.stringify({
231
- instanceId: instanceId2,
232
- uptime: Math.floor((Date.now() - startTime) / 1e3),
233
- cliVersion: VERSION,
234
- metadata: {
235
- nodeVersion: process.version,
236
- platform: process.platform
237
- }
238
- })
239
- });
240
- if (resp.ok) {
241
- const data = await resp.json();
242
- if (data.action === "update" && data.bundleUrl) {
243
- log.info(
244
- `Update available: version ${data.versionNumber}, downloading from ${data.bundleUrl}`
245
- );
246
- } else if (data.action === "stop") {
247
- log.info("Received stop signal from server, shutting down...");
248
- await cleanup();
249
- process.exit(0);
250
- }
251
- }
252
- } catch (err) {
253
- log.error(
254
- `Heartbeat failed: ${err instanceof Error ? err.message : "Unknown error"}`
255
- );
256
- }
257
- }, intervalSec * 1e3);
258
- const cleanup = async () => {
259
- clearInterval(heartbeatTimer);
260
- try {
261
- await deployAuthenticatedFetch(heartbeatUrl, {
262
- method: "POST",
263
- headers: { "Content-Type": "application/json" },
264
- body: JSON.stringify({
265
- instanceId: instanceId2,
266
- uptime: Math.floor((Date.now() - startTime) / 1e3),
267
- shutting_down: true
268
- })
269
- });
270
- } catch {
271
- }
272
- };
273
- process.on("SIGTERM", async () => {
274
- await cleanup();
275
- process.exit(0);
276
- });
277
- process.on("SIGINT", async () => {
278
- await cleanup();
279
- process.exit(0);
280
- });
281
- return { instanceId: instanceId2, deploymentId: initData.deploymentId, cleanup };
282
- }
283
- var init_heartbeat = __esm({
284
- "src/commands/run/heartbeat.ts"() {
285
- "use strict";
286
- init_auth();
287
- init_cli_logger();
288
- init_version();
289
- }
290
- });
291
-
292
- // src/commands/bundle/index.ts
293
- init_cli_logger();
294
- import path11 from "path";
295
- import fs11 from "fs-extra";
296
- import { getPlatform as getPlatform2 } from "@walkeros/core";
297
-
298
- // src/core/index.ts
299
- init_cli_logger();
300
-
301
- // src/core/timer.ts
302
- function createTimer() {
303
- let startTime = 0;
304
- let endTime = 0;
305
- return {
306
- start() {
307
- startTime = Date.now();
308
- endTime = 0;
309
- },
310
- end() {
311
- endTime = Date.now();
312
- return endTime - startTime;
313
- },
314
- getElapsed() {
315
- const currentTime = endTime || Date.now();
316
- return currentTime - startTime;
317
- },
318
- format() {
319
- const elapsed = this.getElapsed();
320
- return (elapsed / 1e3).toFixed(2) + "s";
321
- }
322
- };
323
- }
324
-
325
- // src/core/output.ts
326
- import fs from "fs-extra";
327
- import path from "path";
328
- async function writeResult(content, options) {
329
- if (options.output) {
330
- const outputPath = path.resolve(options.output);
331
- await fs.ensureDir(path.dirname(outputPath));
332
- await fs.writeFile(outputPath, content);
333
- } else {
334
- process.stdout.write(content);
335
- process.stdout.write("\n");
336
- }
337
- }
338
- function createJsonOutput(success, data, error, duration) {
339
- return {
340
- success,
341
- ...data && { data },
342
- ...error && { error },
343
- ...duration && { duration }
344
- };
345
- }
346
- function createSuccessOutput(data, duration) {
347
- return createJsonOutput(true, data, void 0, duration);
348
- }
349
- function createErrorOutput(error, duration) {
350
- return createJsonOutput(false, void 0, error, duration);
351
- }
352
- function formatBytes(bytes) {
353
- return (bytes / 1024).toFixed(2);
354
- }
355
-
356
- // src/core/tmp.ts
357
- import os from "os";
358
- import path2 from "path";
359
- var DEFAULT_TMP_ROOT = os.tmpdir();
360
- function getTmpPath(tmpDir, ...segments) {
361
- const root = tmpDir || DEFAULT_TMP_ROOT;
362
- const absoluteRoot = path2.isAbsolute(root) ? root : path2.resolve(root);
363
- return path2.join(absoluteRoot, ...segments);
364
- }
365
-
366
- // src/core/asset-resolver.ts
367
- import { fileURLToPath } from "url";
368
- import { existsSync as existsSync2 } from "fs";
369
- import path4 from "path";
370
-
371
245
  // src/config/utils.ts
246
+ import crypto from "crypto";
372
247
  import fs2 from "fs-extra";
373
248
  import path3 from "path";
374
- init_auth();
375
249
  function isUrl(str) {
376
250
  try {
377
251
  const url = new URL(str);
@@ -394,7 +268,8 @@ async function downloadFromUrl(url) {
394
268
  const content = await response.text();
395
269
  const downloadsDir = getTmpPath(void 0, "downloads");
396
270
  await fs2.ensureDir(downloadsDir);
397
- const tempPath = path3.join(downloadsDir, "flow.json");
271
+ const downloadId = crypto.randomUUID().slice(0, 8);
272
+ const tempPath = path3.join(downloadsDir, `flow-${downloadId}.json`);
398
273
  await fs2.writeFile(tempPath, content, "utf-8");
399
274
  return tempPath;
400
275
  } catch (error) {
@@ -485,9 +360,19 @@ async function loadJsonFromSource(source, options) {
485
360
  );
486
361
  }
487
362
  }
363
+ var init_utils = __esm({
364
+ "src/config/utils.ts"() {
365
+ "use strict";
366
+ init_core();
367
+ init_tmp();
368
+ init_auth();
369
+ }
370
+ });
488
371
 
489
372
  // src/core/asset-resolver.ts
490
- var cachedAssetDir;
373
+ import { fileURLToPath } from "url";
374
+ import { existsSync as existsSync2 } from "fs";
375
+ import path4 from "path";
491
376
  function getAssetDir() {
492
377
  if (cachedAssetDir) return cachedAssetDir;
493
378
  const currentFile = fileURLToPath(import.meta.url);
@@ -515,16 +400,28 @@ function resolveAsset(assetPath, assetType, baseDir) {
515
400
  }
516
401
  return path4.resolve(baseDir || process.cwd(), assetPath);
517
402
  }
403
+ var cachedAssetDir;
404
+ var init_asset_resolver = __esm({
405
+ "src/core/asset-resolver.ts"() {
406
+ "use strict";
407
+ init_utils();
408
+ }
409
+ });
518
410
 
519
411
  // src/core/utils.ts
520
412
  function getErrorMessage(error) {
521
413
  return error instanceof Error ? error.message : String(error);
522
414
  }
415
+ var init_utils2 = __esm({
416
+ "src/core/utils.ts"() {
417
+ "use strict";
418
+ }
419
+ });
523
420
 
524
421
  // src/core/local-packages.ts
525
422
  import path5 from "path";
526
423
  import fs3 from "fs-extra";
527
- async function resolveLocalPackage(packageName, localPath, configDir, logger2) {
424
+ async function resolveLocalPackage(packageName, localPath, configDir, logger) {
528
425
  const absolutePath = path5.isAbsolute(localPath) ? localPath : path5.resolve(configDir, localPath);
529
426
  if (!await fs3.pathExists(absolutePath)) {
530
427
  throw new Error(
@@ -540,7 +437,7 @@ async function resolveLocalPackage(packageName, localPath, configDir, logger2) {
540
437
  const distPath = path5.join(absolutePath, "dist");
541
438
  const hasDistFolder = await fs3.pathExists(distPath);
542
439
  if (!hasDistFolder) {
543
- logger2.warn(
440
+ logger.warn(
544
441
  `\u26A0\uFE0F ${packageName}: No dist/ folder found. Using package root.`
545
442
  );
546
443
  }
@@ -551,7 +448,7 @@ async function resolveLocalPackage(packageName, localPath, configDir, logger2) {
551
448
  hasDistFolder
552
449
  };
553
450
  }
554
- async function copyLocalPackage(localPkg, targetDir, logger2) {
451
+ async function copyLocalPackage(localPkg, targetDir, logger) {
555
452
  const packageDir = path5.join(targetDir, "node_modules", localPkg.name);
556
453
  await fs3.ensureDir(path5.dirname(packageDir));
557
454
  await fs3.copy(
@@ -571,13 +468,17 @@ async function copyLocalPackage(localPkg, targetDir, logger2) {
571
468
  }
572
469
  }
573
470
  }
574
- logger2.info(`\u{1F4E6} Using local: ${localPkg.name} from ${localPkg.absolutePath}`);
471
+ logger.info(`\u{1F4E6} Using local: ${localPkg.name} from ${localPkg.absolutePath}`);
575
472
  return packageDir;
576
473
  }
474
+ var init_local_packages = __esm({
475
+ "src/core/local-packages.ts"() {
476
+ "use strict";
477
+ }
478
+ });
577
479
 
578
480
  // src/core/input-detector.ts
579
481
  import fs4 from "fs-extra";
580
- init_auth();
581
482
  async function detectInput(inputPath, platformOverride) {
582
483
  const content = await loadContent(inputPath);
583
484
  try {
@@ -602,6 +503,13 @@ async function loadContent(inputPath) {
602
503
  }
603
504
  return fs4.readFile(inputPath, "utf8");
604
505
  }
506
+ var init_input_detector = __esm({
507
+ "src/core/input-detector.ts"() {
508
+ "use strict";
509
+ init_utils();
510
+ init_auth();
511
+ }
512
+ });
605
513
 
606
514
  // src/core/stdin.ts
607
515
  function isStdinPiped() {
@@ -618,9 +526,11 @@ async function readStdin() {
618
526
  }
619
527
  return content;
620
528
  }
621
-
622
- // src/core/index.ts
623
- init_auth();
529
+ var init_stdin = __esm({
530
+ "src/core/stdin.ts"() {
531
+ "use strict";
532
+ }
533
+ });
624
534
 
625
535
  // src/core/sse.ts
626
536
  function parseSSEEvents(buffer) {
@@ -644,15 +554,35 @@ function parseSSEEvents(buffer) {
644
554
  }
645
555
  return { parsed: events, remainder };
646
556
  }
557
+ var init_sse = __esm({
558
+ "src/core/sse.ts"() {
559
+ "use strict";
560
+ }
561
+ });
562
+
563
+ // src/core/index.ts
564
+ var init_core = __esm({
565
+ "src/core/index.ts"() {
566
+ "use strict";
567
+ init_cli_logger();
568
+ init_timer();
569
+ init_output();
570
+ init_tmp();
571
+ init_asset_resolver();
572
+ init_utils2();
573
+ init_local_packages();
574
+ init_input_detector();
575
+ init_stdin();
576
+ }
577
+ });
647
578
 
648
579
  // src/config/validators.ts
649
580
  import { schemas } from "@walkeros/core/dev";
650
- var { safeParseSetup } = schemas;
651
581
  function isObject(value) {
652
582
  return typeof value === "object" && value !== null && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]";
653
583
  }
654
- function validateFlowSetup(data) {
655
- const result = safeParseSetup(data);
584
+ function validateFlowConfig(data) {
585
+ const result = safeParseConfig(data);
656
586
  if (!result.success) {
657
587
  const errors = result.error.issues.map((issue) => {
658
588
  const path15 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
@@ -663,64 +593,76 @@ ${errors}`);
663
593
  }
664
594
  return result.data;
665
595
  }
666
- function getAvailableFlows(setup) {
667
- return Object.keys(setup.flows);
596
+ function getAvailableFlows(config) {
597
+ return Object.keys(config.flows);
668
598
  }
599
+ var safeParseConfig;
600
+ var init_validators = __esm({
601
+ "src/config/validators.ts"() {
602
+ "use strict";
603
+ ({ safeParseConfig } = schemas);
604
+ }
605
+ });
669
606
 
670
607
  // src/config/build-defaults.ts
671
- var WEB_BUILD_DEFAULTS = {
672
- format: "iife",
673
- platform: "browser",
674
- target: "es2020",
675
- minify: true,
676
- sourcemap: false,
677
- cache: true,
678
- windowCollector: "collector",
679
- windowElb: "elb"
680
- };
681
- var SERVER_BUILD_DEFAULTS = {
682
- format: "esm",
683
- platform: "node",
684
- target: "node20",
685
- minify: true,
686
- sourcemap: false,
687
- cache: true
688
- };
689
- var DEFAULT_OUTPUT_PATHS = {
690
- web: "./dist/walker.js",
691
- server: "./dist/bundle.mjs"
692
- };
693
608
  function getBuildDefaults(platform) {
694
609
  return platform === "web" ? WEB_BUILD_DEFAULTS : SERVER_BUILD_DEFAULTS;
695
610
  }
696
611
  function getDefaultOutput(platform) {
697
612
  return DEFAULT_OUTPUT_PATHS[platform];
698
613
  }
699
-
700
- // src/config/loader.ts
614
+ var WEB_BUILD_DEFAULTS, SERVER_BUILD_DEFAULTS, DEFAULT_OUTPUT_PATHS;
615
+ var init_build_defaults = __esm({
616
+ "src/config/build-defaults.ts"() {
617
+ "use strict";
618
+ WEB_BUILD_DEFAULTS = {
619
+ format: "iife",
620
+ platform: "browser",
621
+ target: "es2020",
622
+ minify: true,
623
+ sourcemap: false,
624
+ cache: true,
625
+ windowCollector: "collector",
626
+ windowElb: "elb"
627
+ };
628
+ SERVER_BUILD_DEFAULTS = {
629
+ format: "esm",
630
+ platform: "node",
631
+ target: "node20",
632
+ minify: true,
633
+ sourcemap: false,
634
+ cache: true
635
+ };
636
+ DEFAULT_OUTPUT_PATHS = {
637
+ web: "./dist/walker.js",
638
+ server: "./dist/bundle.mjs"
639
+ };
640
+ }
641
+ });
642
+
643
+ // src/config/loader.ts
701
644
  import path6 from "path";
702
645
  import fs5 from "fs-extra";
703
- import { getFlowConfig, getPlatform } from "@walkeros/core";
704
- var DEFAULT_INCLUDE_FOLDER = "./shared";
646
+ import { getFlowSettings, getPlatform } from "@walkeros/core";
705
647
  function loadBundleConfig(rawConfig, options) {
706
- const setup = validateFlowSetup(rawConfig);
707
- const availableFlows = getAvailableFlows(setup);
708
- const flowName = resolveFlow(setup, options.flowName, availableFlows);
709
- let flowConfig = getFlowConfig(setup, flowName, { deferred: true });
710
- const platform = getPlatform(flowConfig);
648
+ const config = validateFlowConfig(rawConfig);
649
+ const availableFlows = getAvailableFlows(config);
650
+ const flowName = resolveFlow(config, options.flowName, availableFlows);
651
+ let flowSettings = getFlowSettings(config, flowName, { deferred: true });
652
+ const platform = getPlatform(flowSettings);
711
653
  if (!platform) {
712
654
  throw new Error(
713
655
  `Invalid configuration: flow "${flowName}" must have a "web" or "server" key.`
714
656
  );
715
657
  }
716
658
  if (platform === "web") {
717
- flowConfig = getFlowConfig(setup, flowName);
659
+ flowSettings = getFlowSettings(config, flowName);
718
660
  }
719
661
  const buildDefaults = getBuildDefaults(platform);
720
- const packages = flowConfig.packages || {};
662
+ const packages = flowSettings.packages || {};
721
663
  const output = options.buildOverrides?.output || getDefaultOutput(platform);
722
664
  const configDir = isUrl(options.configPath) ? process.cwd() : path6.dirname(options.configPath);
723
- let includes = setup.include;
665
+ let includes = config.include;
724
666
  if (!includes) {
725
667
  const defaultIncludePath = path6.resolve(configDir, DEFAULT_INCLUDE_FOLDER);
726
668
  if (fs5.pathExistsSync(defaultIncludePath)) {
@@ -742,14 +684,14 @@ function loadBundleConfig(rawConfig, options) {
742
684
  );
743
685
  }
744
686
  return {
745
- flowConfig,
687
+ flowSettings,
746
688
  buildOptions,
747
689
  flowName,
748
690
  isMultiFlow,
749
691
  availableFlows
750
692
  };
751
693
  }
752
- function resolveFlow(setup, requestedFlow, available) {
694
+ function resolveFlow(config, requestedFlow, available) {
753
695
  if (available.length === 1) {
754
696
  return available[0];
755
697
  }
@@ -768,8 +710,8 @@ Available flows: ${available.join(", ")}`
768
710
  return requestedFlow;
769
711
  }
770
712
  function loadAllFlows(rawConfig, options) {
771
- const setup = validateFlowSetup(rawConfig);
772
- const flows = getAvailableFlows(setup);
713
+ const config = validateFlowConfig(rawConfig);
714
+ const flows = getAvailableFlows(config);
773
715
  if (options.logger) {
774
716
  options.logger.info(
775
717
  `\u{1F4E6} Loading all ${flows.length} flows: ${flows.join(", ")}`
@@ -786,21 +728,29 @@ async function loadFlowConfig(configPath, options) {
786
728
  const rawConfig = await loadJsonConfig(configPath);
787
729
  return loadBundleConfig(rawConfig, { configPath, ...options });
788
730
  }
731
+ var DEFAULT_INCLUDE_FOLDER;
732
+ var init_loader = __esm({
733
+ "src/config/loader.ts"() {
734
+ "use strict";
735
+ init_validators();
736
+ init_build_defaults();
737
+ init_utils();
738
+ DEFAULT_INCLUDE_FOLDER = "./shared";
739
+ }
740
+ });
789
741
 
790
- // src/commands/bundle/bundler.ts
791
- import esbuild from "esbuild";
792
- import path9 from "path";
793
- import fs8 from "fs-extra";
794
- import { packageNameToVariable, ENV_MARKER_PREFIX } from "@walkeros/core";
795
-
796
- // src/commands/bundle/package-manager.ts
797
- import pacote from "pacote";
798
- import path7 from "path";
799
- import fs6 from "fs-extra";
742
+ // src/config/index.ts
743
+ var init_config = __esm({
744
+ "src/config/index.ts"() {
745
+ "use strict";
746
+ init_validators();
747
+ init_utils();
748
+ init_loader();
749
+ }
750
+ });
800
751
 
801
752
  // src/core/cache-utils.ts
802
753
  import { getHashServer } from "@walkeros/server-core";
803
- var HASH_LENGTH = 12;
804
754
  function isMutableVersion(version) {
805
755
  return version === "latest" || version.includes("^") || version.includes("~") || version.includes("*") || version.includes("x");
806
756
  }
@@ -821,15 +771,25 @@ function normalizeJson(content) {
821
771
  const parsed = JSON.parse(content);
822
772
  return JSON.stringify(parsed);
823
773
  }
824
- async function getFlowConfigCacheKey(content, date) {
774
+ async function getFlowSettingsCacheKey(content, date) {
825
775
  const dateStr = date ?? getTodayDate();
826
776
  const normalized = normalizeJson(content);
827
777
  const input = `${normalized}:${dateStr}`;
828
778
  return getHashServer(input, HASH_LENGTH);
829
779
  }
780
+ var HASH_LENGTH;
781
+ var init_cache_utils = __esm({
782
+ "src/core/cache-utils.ts"() {
783
+ "use strict";
784
+ HASH_LENGTH = 12;
785
+ }
786
+ });
830
787
 
831
788
  // src/commands/bundle/package-manager.ts
832
- var PACKAGE_DOWNLOAD_TIMEOUT_MS = 6e4;
789
+ import pacote from "pacote";
790
+ import path7 from "path";
791
+ import fs6 from "fs-extra";
792
+ import semver from "semver";
833
793
  async function withTimeout(promise, ms, errorMessage) {
834
794
  let timer;
835
795
  const timeout = new Promise((_2, reject) => {
@@ -841,132 +801,199 @@ async function withTimeout(promise, ms, errorMessage) {
841
801
  clearTimeout(timer);
842
802
  }
843
803
  }
844
- function getPackageDirectory(baseDir, packageName, version) {
804
+ function getPackageDirectory(baseDir, packageName) {
845
805
  return path7.join(baseDir, "node_modules", packageName);
846
806
  }
847
- async function getCachedPackagePath(pkg, tmpDir) {
848
- const cacheDir = getTmpPath(tmpDir, "cache", "packages");
849
- const cacheKey = await getPackageCacheKey(pkg.name, pkg.version);
850
- return path7.join(cacheDir, cacheKey);
851
- }
852
- async function isPackageCached(pkg, tmpDir) {
853
- const cachedPath = await getCachedPackagePath(pkg, tmpDir);
854
- return fs6.pathExists(cachedPath);
855
- }
856
- function validateNoDuplicatePackages(packages) {
857
- const packageMap = /* @__PURE__ */ new Map();
858
- for (const pkg of packages) {
859
- if (!packageMap.has(pkg.name)) {
860
- packageMap.set(pkg.name, []);
807
+ async function collectAllSpecs(packages, logger, configDir) {
808
+ const allSpecs = /* @__PURE__ */ new Map();
809
+ const visited = /* @__PURE__ */ new Set();
810
+ const queue = packages.map((pkg) => ({
811
+ name: pkg.name,
812
+ spec: pkg.version,
813
+ source: "direct",
814
+ from: "flow.json",
815
+ optional: false,
816
+ localPath: pkg.path
817
+ }));
818
+ while (queue.length > 0) {
819
+ const item = queue.shift();
820
+ const visitKey = `${item.name}@${item.spec}`;
821
+ if (visited.has(visitKey)) continue;
822
+ visited.add(visitKey);
823
+ if (!allSpecs.has(item.name)) allSpecs.set(item.name, []);
824
+ allSpecs.get(item.name).push({
825
+ spec: item.spec,
826
+ source: item.source,
827
+ from: item.from,
828
+ optional: item.optional,
829
+ localPath: item.localPath
830
+ });
831
+ if (item.localPath) continue;
832
+ let manifest;
833
+ try {
834
+ manifest = await withTimeout(
835
+ pacote.manifest(`${item.name}@${item.spec}`, PACOTE_OPTS),
836
+ PACKAGE_DOWNLOAD_TIMEOUT_MS,
837
+ `Manifest fetch timed out: ${item.name}@${item.spec}`
838
+ );
839
+ } catch (error) {
840
+ logger.debug(
841
+ `Failed to fetch manifest for ${item.name}@${item.spec}: ${error}`
842
+ );
843
+ continue;
861
844
  }
862
- packageMap.get(pkg.name).push(pkg.version);
863
- }
864
- const conflicts = [];
865
- for (const [name, versions] of packageMap.entries()) {
866
- const uniqueVersions = [...new Set(versions)];
867
- if (uniqueVersions.length > 1) {
868
- conflicts.push(`${name}: [${uniqueVersions.join(", ")}]`);
845
+ const m2 = manifest;
846
+ const deps = m2.dependencies || {};
847
+ for (const [depName, depSpec] of Object.entries(deps)) {
848
+ if (typeof depSpec === "string") {
849
+ queue.push({
850
+ name: depName,
851
+ spec: depSpec,
852
+ source: "dependency",
853
+ from: item.name,
854
+ optional: false
855
+ });
856
+ }
857
+ }
858
+ const peerDeps = m2.peerDependencies || {};
859
+ const peerMeta = m2.peerDependenciesMeta || {};
860
+ for (const [depName, depSpec] of Object.entries(peerDeps)) {
861
+ if (typeof depSpec === "string") {
862
+ const isOptional = peerMeta[depName]?.optional === true;
863
+ queue.push({
864
+ name: depName,
865
+ spec: depSpec,
866
+ source: "peerDependency",
867
+ from: item.name,
868
+ optional: isOptional
869
+ });
870
+ }
869
871
  }
870
872
  }
871
- if (conflicts.length > 0) {
872
- throw new Error(
873
- `Version conflicts detected:
874
- ${conflicts.map((c2) => ` - ${c2}`).join("\n")}
875
-
876
- Each package must use the same version across all declarations. Please update your configuration to use consistent versions.`
877
- );
878
- }
873
+ return allSpecs;
879
874
  }
880
- async function resolveDependencies(pkg, packageDir, logger2, visited = /* @__PURE__ */ new Set()) {
881
- const dependencies = [];
882
- const pkgKey = `${pkg.name}@${pkg.version}`;
883
- if (visited.has(pkgKey)) {
884
- return dependencies;
885
- }
886
- visited.add(pkgKey);
887
- try {
888
- const packageJsonPath = path7.join(packageDir, "package.json");
889
- if (await fs6.pathExists(packageJsonPath)) {
890
- const packageJson = await fs6.readJson(packageJsonPath);
891
- const deps = {
892
- ...packageJson.dependencies,
893
- ...packageJson.peerDependencies
894
- };
895
- for (const [name, versionSpec] of Object.entries(deps)) {
896
- if (typeof versionSpec === "string") {
897
- dependencies.push({ name, version: versionSpec });
875
+ function resolveVersionConflicts(allSpecs, logger) {
876
+ const resolved = /* @__PURE__ */ new Map();
877
+ for (const [name, specs] of allSpecs) {
878
+ const localSpec = specs.find((s2) => s2.localPath);
879
+ if (localSpec) {
880
+ resolved.set(name, {
881
+ name,
882
+ version: "local",
883
+ localPath: localSpec.localPath
884
+ });
885
+ continue;
886
+ }
887
+ const nonPeerSpecs = specs.filter((s2) => s2.source !== "peerDependency");
888
+ const peerSpecs = specs.filter((s2) => s2.source === "peerDependency");
889
+ let activeSpecs;
890
+ if (nonPeerSpecs.length > 0) {
891
+ activeSpecs = nonPeerSpecs;
892
+ } else {
893
+ const requiredPeers = peerSpecs.filter((s2) => !s2.optional);
894
+ if (requiredPeers.length === 0) {
895
+ logger.debug(`Skipping optional peer dependency: ${name}`);
896
+ continue;
897
+ }
898
+ activeSpecs = requiredPeers;
899
+ }
900
+ activeSpecs.sort(
901
+ (a2, b2) => SOURCE_PRIORITY[a2.source] - SOURCE_PRIORITY[b2.source]
902
+ );
903
+ const directSpecs = activeSpecs.filter((s2) => s2.source === "direct");
904
+ const directExact = directSpecs.find((s2) => semver.valid(s2.spec) !== null);
905
+ let chosenVersion;
906
+ if (directExact) {
907
+ chosenVersion = directExact.spec;
908
+ } else if (directSpecs.length > 0) {
909
+ chosenVersion = directSpecs[0].spec;
910
+ } else {
911
+ const exactVersions = activeSpecs.filter((s2) => semver.valid(s2.spec) !== null).map((s2) => s2.spec);
912
+ const uniqueExact = [...new Set(exactVersions)];
913
+ if (uniqueExact.length > 1) {
914
+ throw new Error(
915
+ `Version conflict for ${name}: ${uniqueExact.join(" vs ")} (from ${activeSpecs.map((s2) => `${s2.spec} via ${s2.from}`).join(", ")})`
916
+ );
917
+ } else if (uniqueExact.length === 1) {
918
+ chosenVersion = uniqueExact[0];
919
+ } else {
920
+ chosenVersion = activeSpecs[0].spec;
921
+ }
922
+ }
923
+ if (semver.valid(chosenVersion)) {
924
+ for (const spec of specs) {
925
+ if (spec.localPath) continue;
926
+ if (semver.valid(spec.spec)) {
927
+ if (spec.spec !== chosenVersion) {
928
+ if (spec.source === "peerDependency") {
929
+ logger.warn(
930
+ `${name}@${chosenVersion} differs from peer constraint ${spec.spec} (from ${spec.from})`
931
+ );
932
+ }
933
+ }
934
+ } else {
935
+ if (!semver.satisfies(chosenVersion, spec.spec, {
936
+ includePrerelease: true
937
+ })) {
938
+ if (spec.source === "peerDependency") {
939
+ logger.warn(
940
+ `${name}@${chosenVersion} may not satisfy peer constraint ${spec.spec} (from ${spec.from})`
941
+ );
942
+ } else {
943
+ throw new Error(
944
+ `Version conflict: ${name}@${chosenVersion} does not satisfy ${spec.spec} required by ${spec.from}`
945
+ );
946
+ }
947
+ }
898
948
  }
899
949
  }
900
950
  }
901
- } catch (error) {
902
- logger2.debug(`Failed to read dependencies for ${pkgKey}: ${error}`);
951
+ resolved.set(name, { name, version: chosenVersion });
903
952
  }
904
- return dependencies;
953
+ return resolved;
905
954
  }
906
- async function downloadPackages(packages, targetDir, logger2, useCache = true, configDir, tmpDir) {
955
+ async function downloadPackages(packages, targetDir, logger, useCache = true, configDir, tmpDir) {
907
956
  const packagePaths = /* @__PURE__ */ new Map();
908
- const downloadQueue = [...packages];
909
- const processed = /* @__PURE__ */ new Set();
910
957
  const userSpecifiedPackages = new Set(packages.map((p2) => p2.name));
958
+ validateNoDuplicatePackages(packages);
959
+ logger.debug("Resolving dependencies");
960
+ const allSpecs = await collectAllSpecs(packages, logger, configDir);
961
+ const resolved = resolveVersionConflicts(allSpecs, logger);
962
+ await fs6.ensureDir(targetDir);
911
963
  const localPackageMap = /* @__PURE__ */ new Map();
912
964
  for (const pkg of packages) {
913
- if (pkg.path) {
914
- localPackageMap.set(pkg.name, pkg.path);
915
- }
965
+ if (pkg.path) localPackageMap.set(pkg.name, pkg.path);
916
966
  }
917
- validateNoDuplicatePackages(packages);
918
- await fs6.ensureDir(targetDir);
919
- while (downloadQueue.length > 0) {
920
- const pkg = downloadQueue.shift();
921
- const pkgKey = `${pkg.name}@${pkg.version}`;
922
- if (processed.has(pkgKey)) {
923
- continue;
924
- }
925
- processed.add(pkgKey);
926
- if (!pkg.path && localPackageMap.has(pkg.name)) {
927
- pkg.path = localPackageMap.get(pkg.name);
928
- }
929
- if (pkg.path) {
967
+ for (const [name, pkg] of resolved) {
968
+ if (pkg.localPath || localPackageMap.has(name)) {
969
+ const localPath = pkg.localPath || localPackageMap.get(name);
930
970
  const localPkg = await resolveLocalPackage(
931
- pkg.name,
932
- pkg.path,
971
+ name,
972
+ localPath,
933
973
  configDir || process.cwd(),
934
- logger2
974
+ logger
935
975
  );
936
- const installedPath = await copyLocalPackage(localPkg, targetDir, logger2);
937
- packagePaths.set(pkg.name, installedPath);
938
- const deps = await resolveDependencies(pkg, installedPath, logger2);
939
- for (const dep of deps) {
940
- const depKey = `${dep.name}@${dep.version}`;
941
- if (!processed.has(depKey)) {
942
- downloadQueue.push(dep);
943
- }
944
- }
976
+ const installedPath = await copyLocalPackage(localPkg, targetDir, logger);
977
+ packagePaths.set(name, installedPath);
945
978
  continue;
946
979
  }
947
- const packageSpec = `${pkg.name}@${pkg.version}`;
948
- const packageDir = getPackageDirectory(targetDir, pkg.name, pkg.version);
949
- const cachedPath = await getCachedPackagePath(pkg, tmpDir);
950
- if (useCache && await isPackageCached(pkg, tmpDir)) {
951
- if (userSpecifiedPackages.has(pkg.name)) {
952
- logger2.debug(`Downloading ${packageSpec} (cached)`);
980
+ const packageSpec = `${name}@${pkg.version}`;
981
+ const packageDir = getPackageDirectory(targetDir, name);
982
+ const cachedPath = await getCachedPackagePath(
983
+ { name, version: pkg.version },
984
+ tmpDir
985
+ );
986
+ if (useCache && await isPackageCached({ name, version: pkg.version }, tmpDir)) {
987
+ if (userSpecifiedPackages.has(name)) {
988
+ logger.debug(`Downloading ${packageSpec} (cached)`);
953
989
  }
954
990
  try {
955
991
  await fs6.ensureDir(path7.dirname(packageDir));
956
992
  await fs6.copy(cachedPath, packageDir);
957
- packagePaths.set(pkg.name, packageDir);
958
- const deps = await resolveDependencies(pkg, packageDir, logger2);
959
- for (const dep of deps) {
960
- const depKey = `${dep.name}@${dep.version}`;
961
- if (!processed.has(depKey)) {
962
- downloadQueue.push(dep);
963
- }
964
- }
993
+ packagePaths.set(name, packageDir);
965
994
  continue;
966
- } catch (error) {
967
- logger2.debug(
968
- `Failed to use cache for ${packageSpec}, downloading fresh: ${error}`
969
- );
995
+ } catch {
996
+ logger.debug(`Cache miss for ${packageSpec}, downloading fresh`);
970
997
  }
971
998
  }
972
999
  try {
@@ -974,52 +1001,87 @@ async function downloadPackages(packages, targetDir, logger2, useCache = true, c
974
1001
  const cacheDir = process.env.NPM_CACHE_DIR || getTmpPath(tmpDir, "cache", "npm");
975
1002
  await withTimeout(
976
1003
  pacote.extract(packageSpec, packageDir, {
977
- // Force npm registry download, prevent workspace resolution
978
- registry: "https://registry.npmjs.org",
979
- // Force online fetching from registry (don't use cached workspace packages)
980
- preferOnline: true,
981
- // Cache for performance
982
- cache: cacheDir,
983
- // Don't resolve relative to workspace context
984
- where: void 0
1004
+ ...PACOTE_OPTS,
1005
+ cache: cacheDir
985
1006
  }),
986
1007
  PACKAGE_DOWNLOAD_TIMEOUT_MS,
987
1008
  `Package download timed out after ${PACKAGE_DOWNLOAD_TIMEOUT_MS / 1e3}s: ${packageSpec}`
988
1009
  );
989
- if (userSpecifiedPackages.has(pkg.name)) {
990
- const pkgStats = await fs6.stat(path7.join(packageDir, "package.json"));
991
- const pkgJsonSize = pkgStats.size;
992
- const sizeKB = (pkgJsonSize / 1024).toFixed(1);
993
- logger2.debug(`Downloading ${packageSpec} (${sizeKB} KB)`);
1010
+ if (userSpecifiedPackages.has(name)) {
1011
+ logger.debug(`Downloading ${packageSpec}`);
994
1012
  }
995
1013
  if (useCache) {
996
1014
  try {
997
1015
  await fs6.ensureDir(path7.dirname(cachedPath));
998
1016
  await fs6.copy(packageDir, cachedPath);
999
- } catch (cacheError) {
1000
- }
1001
- }
1002
- packagePaths.set(pkg.name, packageDir);
1003
- const deps = await resolveDependencies(pkg, packageDir, logger2);
1004
- for (const dep of deps) {
1005
- const depKey = `${dep.name}@${dep.version}`;
1006
- if (!processed.has(depKey)) {
1007
- downloadQueue.push(dep);
1017
+ } catch {
1008
1018
  }
1009
1019
  }
1020
+ packagePaths.set(name, packageDir);
1010
1021
  } catch (error) {
1011
1022
  throw new Error(`Failed to download ${packageSpec}: ${error}`);
1012
1023
  }
1013
1024
  }
1014
1025
  return packagePaths;
1015
1026
  }
1027
+ async function getCachedPackagePath(pkg, tmpDir) {
1028
+ const cacheDir = getTmpPath(tmpDir, "cache", "packages");
1029
+ const cacheKey = await getPackageCacheKey(pkg.name, pkg.version);
1030
+ return path7.join(cacheDir, cacheKey);
1031
+ }
1032
+ async function isPackageCached(pkg, tmpDir) {
1033
+ const cachedPath = await getCachedPackagePath(pkg, tmpDir);
1034
+ return fs6.pathExists(cachedPath);
1035
+ }
1036
+ function validateNoDuplicatePackages(packages) {
1037
+ const packageMap = /* @__PURE__ */ new Map();
1038
+ for (const pkg of packages) {
1039
+ if (!packageMap.has(pkg.name)) packageMap.set(pkg.name, []);
1040
+ packageMap.get(pkg.name).push(pkg.version);
1041
+ }
1042
+ const conflicts = [];
1043
+ for (const [name, versions] of packageMap.entries()) {
1044
+ const uniqueVersions = [...new Set(versions)];
1045
+ if (uniqueVersions.length > 1) {
1046
+ conflicts.push(`${name}: [${uniqueVersions.join(", ")}]`);
1047
+ }
1048
+ }
1049
+ if (conflicts.length > 0) {
1050
+ throw new Error(
1051
+ `Version conflicts detected:
1052
+ ${conflicts.map((c2) => ` - ${c2}`).join("\n")}
1053
+
1054
+ Each package must use the same version across all declarations. Please update your configuration to use consistent versions.`
1055
+ );
1056
+ }
1057
+ }
1058
+ var PACKAGE_DOWNLOAD_TIMEOUT_MS, PACOTE_OPTS, SOURCE_PRIORITY;
1059
+ var init_package_manager = __esm({
1060
+ "src/commands/bundle/package-manager.ts"() {
1061
+ "use strict";
1062
+ init_core();
1063
+ init_cache_utils();
1064
+ init_tmp();
1065
+ PACKAGE_DOWNLOAD_TIMEOUT_MS = 6e4;
1066
+ PACOTE_OPTS = {
1067
+ registry: "https://registry.npmjs.org",
1068
+ preferOnline: true,
1069
+ where: void 0
1070
+ };
1071
+ SOURCE_PRIORITY = {
1072
+ direct: 0,
1073
+ dependency: 1,
1074
+ peerDependency: 2
1075
+ };
1076
+ }
1077
+ });
1016
1078
 
1017
1079
  // src/core/build-cache.ts
1018
1080
  import fs7 from "fs-extra";
1019
1081
  import path8 from "path";
1020
1082
  async function getBuildCachePath(configContent, tmpDir) {
1021
1083
  const cacheDir = getTmpPath(tmpDir, "cache", "builds");
1022
- const cacheKey = await getFlowConfigCacheKey(configContent);
1084
+ const cacheKey = await getFlowSettingsCacheKey(configContent);
1023
1085
  return path8.join(cacheDir, `${cacheKey}.js`);
1024
1086
  }
1025
1087
  async function isBuildCached(configContent, tmpDir) {
@@ -1038,8 +1100,20 @@ async function getCachedBuild(configContent, tmpDir) {
1038
1100
  }
1039
1101
  return null;
1040
1102
  }
1103
+ var init_build_cache = __esm({
1104
+ "src/core/build-cache.ts"() {
1105
+ "use strict";
1106
+ init_cache_utils();
1107
+ init_tmp();
1108
+ }
1109
+ });
1041
1110
 
1042
1111
  // src/commands/bundle/bundler.ts
1112
+ import crypto2 from "crypto";
1113
+ import esbuild from "esbuild";
1114
+ import path9 from "path";
1115
+ import fs8 from "fs-extra";
1116
+ import { packageNameToVariable, ENV_MARKER_PREFIX } from "@walkeros/core";
1043
1117
  function isInlineCode(code) {
1044
1118
  return code !== null && typeof code === "object" && !Array.isArray(code) && "push" in code;
1045
1119
  }
@@ -1085,7 +1159,7 @@ function generateInlineCode(inline, config, env, chain, chainPropertyName, isDes
1085
1159
  ${chainLine.slice(0, -1)}` : ""}
1086
1160
  }`;
1087
1161
  }
1088
- async function copyIncludes(includes, sourceDir, outputDir, logger2) {
1162
+ async function copyIncludes(includes, sourceDir, outputDir, logger) {
1089
1163
  for (const include of includes) {
1090
1164
  const sourcePath = path9.resolve(sourceDir, include);
1091
1165
  const folderName = path9.basename(include);
@@ -1099,15 +1173,15 @@ async function copyIncludes(includes, sourceDir, outputDir, logger2) {
1099
1173
  }
1100
1174
  if (await fs8.pathExists(sourcePath)) {
1101
1175
  await fs8.copy(sourcePath, destPath);
1102
- logger2.debug(`Copied ${include} to output`);
1176
+ logger.debug(`Copied ${include} to output`);
1103
1177
  } else {
1104
- logger2.warn(`Include folder not found: ${include}`);
1178
+ logger.warn(`Include folder not found: ${include}`);
1105
1179
  }
1106
1180
  }
1107
1181
  }
1108
- function generateCacheKeyContent(flowConfig, buildOptions) {
1182
+ function generateCacheKeyContent(flowSettings, buildOptions) {
1109
1183
  const configForCache = {
1110
- flow: flowConfig,
1184
+ flow: flowSettings,
1111
1185
  build: {
1112
1186
  ...buildOptions,
1113
1187
  // Exclude non-deterministic fields from cache key
@@ -1117,62 +1191,64 @@ function generateCacheKeyContent(flowConfig, buildOptions) {
1117
1191
  };
1118
1192
  return JSON.stringify(configForCache);
1119
1193
  }
1120
- function validateFlowConfig(flowConfig, logger2) {
1194
+ function validateFlowConfig2(flowSettings, logger) {
1121
1195
  let hasDeprecatedCodeTrue = false;
1122
- const sources = flowConfig.sources || {};
1196
+ const sources = flowSettings.sources || {};
1123
1197
  for (const [sourceId, source] of Object.entries(sources)) {
1124
1198
  if (source && typeof source === "object" && source.code === true) {
1125
- logger2.warn(
1199
+ logger.warn(
1126
1200
  `DEPRECATED: Source "${sourceId}" uses code: true which is no longer supported. Use $code: prefix in config values or create a source package instead.`
1127
1201
  );
1128
1202
  hasDeprecatedCodeTrue = true;
1129
1203
  }
1130
1204
  }
1131
- const destinations = flowConfig.destinations || {};
1205
+ const destinations = flowSettings.destinations || {};
1132
1206
  for (const [destId, dest] of Object.entries(destinations)) {
1133
1207
  if (dest && typeof dest === "object" && dest.code === true) {
1134
- logger2.warn(
1208
+ logger.warn(
1135
1209
  `DEPRECATED: Destination "${destId}" uses code: true which is no longer supported. Use $code: prefix in config values or create a destination package instead.`
1136
1210
  );
1137
1211
  hasDeprecatedCodeTrue = true;
1138
1212
  }
1139
1213
  }
1140
- const transformers = flowConfig.transformers || {};
1214
+ const transformers = flowSettings.transformers || {};
1141
1215
  for (const [transformerId, transformer] of Object.entries(transformers)) {
1142
1216
  if (transformer && typeof transformer === "object" && transformer.code === true) {
1143
- logger2.warn(
1217
+ logger.warn(
1144
1218
  `DEPRECATED: Transformer "${transformerId}" uses code: true which is no longer supported. Use $code: prefix in config values or create a transformer package instead.`
1145
1219
  );
1146
1220
  hasDeprecatedCodeTrue = true;
1147
1221
  }
1148
1222
  }
1149
1223
  if (hasDeprecatedCodeTrue) {
1150
- logger2.warn(
1224
+ logger.warn(
1151
1225
  `See https://www.elbwalker.com/docs/walkeros/getting-started/flow for migration guide.`
1152
1226
  );
1153
1227
  }
1154
1228
  return hasDeprecatedCodeTrue;
1155
1229
  }
1156
- async function bundleCore(flowConfig, buildOptions, logger2, showStats = false) {
1230
+ async function bundleCore(flowSettings, buildOptions, logger, showStats = false) {
1157
1231
  const bundleStartTime = Date.now();
1158
- const hasDeprecatedFeatures = validateFlowConfig(flowConfig, logger2);
1232
+ const hasDeprecatedFeatures = validateFlowConfig2(flowSettings, logger);
1159
1233
  if (hasDeprecatedFeatures) {
1160
- logger2.warn("Skipping deprecated code: true entries from bundle.");
1234
+ logger.warn("Skipping deprecated code: true entries from bundle.");
1161
1235
  }
1162
- const TEMP_DIR = buildOptions.tempDir || getTmpPath();
1236
+ const buildId = crypto2.randomUUID();
1237
+ const TEMP_DIR = buildOptions.tempDir || getTmpPath(void 0, `walkeros-build-${buildId}`);
1238
+ const CACHE_DIR = buildOptions.tempDir || getTmpPath();
1163
1239
  if (buildOptions.cache !== false) {
1164
- const configContent = generateCacheKeyContent(flowConfig, buildOptions);
1165
- const cached = await isBuildCached(configContent, TEMP_DIR);
1240
+ const configContent = generateCacheKeyContent(flowSettings, buildOptions);
1241
+ const cached = await isBuildCached(configContent, CACHE_DIR);
1166
1242
  if (cached) {
1167
- const cachedBuild = await getCachedBuild(configContent, TEMP_DIR);
1243
+ const cachedBuild = await getCachedBuild(configContent, CACHE_DIR);
1168
1244
  if (cachedBuild) {
1169
- logger2.debug("Using cached build");
1245
+ logger.debug("Using cached build");
1170
1246
  const outputPath = path9.resolve(buildOptions.output);
1171
1247
  await fs8.ensureDir(path9.dirname(outputPath));
1172
1248
  await fs8.writeFile(outputPath, cachedBuild);
1173
1249
  const stats = await fs8.stat(outputPath);
1174
1250
  const sizeKB = (stats.size / 1024).toFixed(1);
1175
- logger2.info(`Output: ${outputPath} (${sizeKB} KB, cached)`);
1251
+ logger.info(`Output: ${outputPath} (${sizeKB} KB, cached)`);
1176
1252
  if (showStats) {
1177
1253
  const stats2 = await fs8.stat(outputPath);
1178
1254
  const packageStats = Object.entries(buildOptions.packages).map(
@@ -1199,14 +1275,14 @@ async function bundleCore(flowConfig, buildOptions, logger2, showStats = false)
1199
1275
  try {
1200
1276
  await fs8.ensureDir(TEMP_DIR);
1201
1277
  const hasSourcesOrDests = Object.keys(
1202
- flowConfig.sources || {}
1278
+ flowSettings.sources || {}
1203
1279
  ).length > 0 || Object.keys(
1204
- flowConfig.destinations || {}
1280
+ flowSettings.destinations || {}
1205
1281
  ).length > 0;
1206
1282
  if (hasSourcesOrDests && !buildOptions.packages["@walkeros/collector"]) {
1207
1283
  buildOptions.packages["@walkeros/collector"] = {};
1208
1284
  }
1209
- logger2.debug("Downloading packages");
1285
+ logger.debug("Downloading packages");
1210
1286
  const packagesArray = Object.entries(buildOptions.packages).map(
1211
1287
  ([name, packageConfig]) => ({
1212
1288
  name,
@@ -1218,11 +1294,11 @@ async function bundleCore(flowConfig, buildOptions, logger2, showStats = false)
1218
1294
  const packagePaths = await downloadPackages(
1219
1295
  packagesArray,
1220
1296
  TEMP_DIR,
1221
- logger2,
1297
+ logger,
1222
1298
  buildOptions.cache,
1223
1299
  buildOptions.configDir,
1224
1300
  // For resolving relative local paths
1225
- TEMP_DIR
1301
+ CACHE_DIR
1226
1302
  );
1227
1303
  for (const [pkgName, pkgPath] of packagePaths.entries()) {
1228
1304
  if (pkgName.startsWith("@walkeros/")) {
@@ -1244,15 +1320,15 @@ async function bundleCore(flowConfig, buildOptions, logger2, showStats = false)
1244
1320
  packageJsonPath,
1245
1321
  JSON.stringify({ type: "module" }, null, 2)
1246
1322
  );
1247
- logger2.debug("Creating entry point");
1323
+ logger.debug("Creating entry point");
1248
1324
  const entryContent = await createEntryPoint(
1249
- flowConfig,
1325
+ flowSettings,
1250
1326
  buildOptions,
1251
1327
  packagePaths
1252
1328
  );
1253
1329
  const entryPath = path9.join(TEMP_DIR, "entry.js");
1254
1330
  await fs8.writeFile(entryPath, entryContent);
1255
- logger2.debug(
1331
+ logger.debug(
1256
1332
  `Running esbuild (target: ${buildOptions.target || "es2018"}, format: ${buildOptions.format})`
1257
1333
  );
1258
1334
  const outputPath = path9.resolve(buildOptions.output);
@@ -1263,7 +1339,7 @@ async function bundleCore(flowConfig, buildOptions, logger2, showStats = false)
1263
1339
  outputPath,
1264
1340
  TEMP_DIR,
1265
1341
  packagePaths,
1266
- logger2
1342
+ logger
1267
1343
  );
1268
1344
  try {
1269
1345
  await esbuild.build(esbuildOptions);
@@ -1278,12 +1354,12 @@ async function bundleCore(flowConfig, buildOptions, logger2, showStats = false)
1278
1354
  const outputStats = await fs8.stat(outputPath);
1279
1355
  const sizeKB = (outputStats.size / 1024).toFixed(1);
1280
1356
  const buildTime = ((Date.now() - bundleStartTime) / 1e3).toFixed(1);
1281
- logger2.info(`Output: ${outputPath} (${sizeKB} KB, ${buildTime}s)`);
1357
+ logger.info(`Output: ${outputPath} (${sizeKB} KB, ${buildTime}s)`);
1282
1358
  if (buildOptions.cache !== false) {
1283
- const configContent = generateCacheKeyContent(flowConfig, buildOptions);
1359
+ const configContent = generateCacheKeyContent(flowSettings, buildOptions);
1284
1360
  const buildOutput = await fs8.readFile(outputPath, "utf-8");
1285
- await cacheBuild(configContent, buildOutput, TEMP_DIR);
1286
- logger2.debug("Build cached for future use");
1361
+ await cacheBuild(configContent, buildOutput, CACHE_DIR);
1362
+ logger.debug("Build cached for future use");
1287
1363
  }
1288
1364
  let stats;
1289
1365
  if (showStats) {
@@ -1300,12 +1376,17 @@ async function bundleCore(flowConfig, buildOptions, logger2, showStats = false)
1300
1376
  buildOptions.include,
1301
1377
  buildOptions.configDir || process.cwd(),
1302
1378
  outputDir,
1303
- logger2
1379
+ logger
1304
1380
  );
1305
1381
  }
1306
1382
  return stats;
1307
1383
  } catch (error) {
1308
1384
  throw error;
1385
+ } finally {
1386
+ if (!buildOptions.tempDir) {
1387
+ fs8.remove(TEMP_DIR).catch(() => {
1388
+ });
1389
+ }
1309
1390
  }
1310
1391
  }
1311
1392
  async function collectBundleStats(outputPath, packages, startTime, entryContent) {
@@ -1335,7 +1416,7 @@ async function collectBundleStats(outputPath, packages, startTime, entryContent)
1335
1416
  treeshakingEffective
1336
1417
  };
1337
1418
  }
1338
- function createEsbuildOptions(buildOptions, entryPath, outputPath, tempDir, packagePaths, logger2) {
1419
+ function createEsbuildOptions(buildOptions, entryPath, outputPath, tempDir, packagePaths, logger) {
1339
1420
  const alias = {};
1340
1421
  const baseOptions = {
1341
1422
  entryPoints: [entryPath],
@@ -1403,9 +1484,9 @@ function createEsbuildOptions(buildOptions, entryPath, outputPath, tempDir, pack
1403
1484
  }
1404
1485
  return baseOptions;
1405
1486
  }
1406
- function detectDestinationPackages(flowConfig) {
1487
+ function detectDestinationPackages(flowSettings) {
1407
1488
  const destinationPackages = /* @__PURE__ */ new Set();
1408
- const destinations = flowConfig.destinations;
1489
+ const destinations = flowSettings.destinations;
1409
1490
  if (destinations) {
1410
1491
  for (const [destKey, destConfig] of Object.entries(destinations)) {
1411
1492
  if (typeof destConfig === "object" && destConfig !== null && "code" in destConfig && destConfig.code === true) {
@@ -1418,9 +1499,9 @@ function detectDestinationPackages(flowConfig) {
1418
1499
  }
1419
1500
  return destinationPackages;
1420
1501
  }
1421
- function detectSourcePackages(flowConfig) {
1502
+ function detectSourcePackages(flowSettings) {
1422
1503
  const sourcePackages = /* @__PURE__ */ new Set();
1423
- const sources = flowConfig.sources;
1504
+ const sources = flowSettings.sources;
1424
1505
  if (sources) {
1425
1506
  for (const [sourceKey, sourceConfig] of Object.entries(sources)) {
1426
1507
  if (typeof sourceConfig === "object" && sourceConfig !== null && "code" in sourceConfig && sourceConfig.code === true) {
@@ -1433,9 +1514,9 @@ function detectSourcePackages(flowConfig) {
1433
1514
  }
1434
1515
  return sourcePackages;
1435
1516
  }
1436
- function detectTransformerPackages(flowConfig) {
1517
+ function detectTransformerPackages(flowSettings) {
1437
1518
  const transformerPackages = /* @__PURE__ */ new Set();
1438
- const transformers = flowConfig.transformers;
1519
+ const transformers = flowSettings.transformers;
1439
1520
  if (transformers) {
1440
1521
  for (const [transformerKey, transformerConfig] of Object.entries(
1441
1522
  transformers
@@ -1450,9 +1531,9 @@ function detectTransformerPackages(flowConfig) {
1450
1531
  }
1451
1532
  return transformerPackages;
1452
1533
  }
1453
- function detectStorePackages(flowConfig) {
1534
+ function detectStorePackages(flowSettings) {
1454
1535
  const storePackages = /* @__PURE__ */ new Set();
1455
- const stores = flowConfig.stores;
1536
+ const stores = flowSettings.stores;
1456
1537
  if (stores) {
1457
1538
  for (const [, storeConfig] of Object.entries(stores)) {
1458
1539
  if (typeof storeConfig === "object" && storeConfig !== null && "package" in storeConfig && typeof storeConfig.package === "string") {
@@ -1462,9 +1543,9 @@ function detectStorePackages(flowConfig) {
1462
1543
  }
1463
1544
  return storePackages;
1464
1545
  }
1465
- function detectExplicitCodeImports(flowConfig) {
1546
+ function detectExplicitCodeImports(flowSettings) {
1466
1547
  const explicitCodeImports = /* @__PURE__ */ new Map();
1467
- const destinations = flowConfig.destinations;
1548
+ const destinations = flowSettings.destinations;
1468
1549
  if (destinations) {
1469
1550
  for (const [destKey, destConfig] of Object.entries(destinations)) {
1470
1551
  if (typeof destConfig === "object" && destConfig !== null && "code" in destConfig && destConfig.code === true) {
@@ -1481,7 +1562,7 @@ function detectExplicitCodeImports(flowConfig) {
1481
1562
  }
1482
1563
  }
1483
1564
  }
1484
- const sources = flowConfig.sources;
1565
+ const sources = flowSettings.sources;
1485
1566
  if (sources) {
1486
1567
  for (const [sourceKey, sourceConfig] of Object.entries(sources)) {
1487
1568
  if (typeof sourceConfig === "object" && sourceConfig !== null && "code" in sourceConfig && sourceConfig.code === true) {
@@ -1498,7 +1579,7 @@ function detectExplicitCodeImports(flowConfig) {
1498
1579
  }
1499
1580
  }
1500
1581
  }
1501
- const transformers = flowConfig.transformers;
1582
+ const transformers = flowSettings.transformers;
1502
1583
  if (transformers) {
1503
1584
  for (const [transformerKey, transformerConfig] of Object.entries(
1504
1585
  transformers
@@ -1517,7 +1598,7 @@ function detectExplicitCodeImports(flowConfig) {
1517
1598
  }
1518
1599
  }
1519
1600
  }
1520
- const stores = flowConfig.stores;
1601
+ const stores = flowSettings.stores;
1521
1602
  if (stores) {
1522
1603
  for (const [, storeConfig] of Object.entries(stores)) {
1523
1604
  if (typeof storeConfig === "object" && storeConfig !== null && "package" in storeConfig && typeof storeConfig.package === "string" && "code" in storeConfig && typeof storeConfig.code === "string") {
@@ -1596,7 +1677,6 @@ function generateImportStatements(packages, destinationPackages, sourcePackages,
1596
1677
  }
1597
1678
  return { importStatements, examplesMappings };
1598
1679
  }
1599
- var VALID_JS_IDENTIFIER = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
1600
1680
  function validateComponentNames(components, section) {
1601
1681
  for (const name of Object.keys(components)) {
1602
1682
  if (!VALID_JS_IDENTIFIER.test(name)) {
@@ -1606,7 +1686,7 @@ function validateComponentNames(components, section) {
1606
1686
  }
1607
1687
  }
1608
1688
  }
1609
- function validateStoreReferences(flowConfig, storeIds) {
1689
+ function validateStoreReferences(flowSettings, storeIds) {
1610
1690
  const refs = [];
1611
1691
  function collectRefs(obj, path15) {
1612
1692
  if (typeof obj === "string" && obj.startsWith("$store:")) {
@@ -1618,9 +1698,9 @@ function validateStoreReferences(flowConfig, storeIds) {
1618
1698
  }
1619
1699
  }
1620
1700
  for (const [section, components] of Object.entries({
1621
- sources: flowConfig.sources || {},
1622
- destinations: flowConfig.destinations || {},
1623
- transformers: flowConfig.transformers || {}
1701
+ sources: flowSettings.sources || {},
1702
+ destinations: flowSettings.destinations || {},
1703
+ transformers: flowSettings.transformers || {}
1624
1704
  })) {
1625
1705
  for (const [id, component] of Object.entries(
1626
1706
  components
@@ -1637,19 +1717,19 @@ function validateStoreReferences(flowConfig, storeIds) {
1637
1717
  }
1638
1718
  }
1639
1719
  }
1640
- async function createEntryPoint(flowConfig, buildOptions, packagePaths) {
1641
- const destinationPackages = detectDestinationPackages(flowConfig);
1642
- const sourcePackages = detectSourcePackages(flowConfig);
1643
- const transformerPackages = detectTransformerPackages(flowConfig);
1644
- const storePackages = detectStorePackages(flowConfig);
1645
- const explicitCodeImports = detectExplicitCodeImports(flowConfig);
1720
+ async function createEntryPoint(flowSettings, buildOptions, packagePaths) {
1721
+ const destinationPackages = detectDestinationPackages(flowSettings);
1722
+ const sourcePackages = detectSourcePackages(flowSettings);
1723
+ const transformerPackages = detectTransformerPackages(flowSettings);
1724
+ const storePackages = detectStorePackages(flowSettings);
1725
+ const explicitCodeImports = detectExplicitCodeImports(flowSettings);
1646
1726
  const storeIds = new Set(
1647
1727
  Object.keys(
1648
- flowConfig.stores || {}
1728
+ flowSettings.stores || {}
1649
1729
  )
1650
1730
  );
1651
- validateStoreReferences(flowConfig, storeIds);
1652
- const flowWithSections = flowConfig;
1731
+ validateStoreReferences(flowSettings, storeIds);
1732
+ const flowWithSections = flowSettings;
1653
1733
  if (flowWithSections.sources)
1654
1734
  validateComponentNames(flowWithSections.sources, "sources");
1655
1735
  if (flowWithSections.destinations)
@@ -1667,9 +1747,9 @@ async function createEntryPoint(flowConfig, buildOptions, packagePaths) {
1667
1747
  explicitCodeImports
1668
1748
  );
1669
1749
  const importsCode = importStatements.join("\n");
1670
- const hasFlow = Object.values(flowConfig.sources || {}).some(
1750
+ const hasFlow = Object.values(flowSettings.sources || {}).some(
1671
1751
  (s2) => s2.package || isInlineCode(s2.code)
1672
- ) || Object.values(flowConfig.destinations || {}).some(
1752
+ ) || Object.values(flowSettings.destinations || {}).some(
1673
1753
  (d2) => d2.package || isInlineCode(d2.code)
1674
1754
  );
1675
1755
  if (!hasFlow) {
@@ -1678,8 +1758,12 @@ async function createEntryPoint(flowConfig, buildOptions, packagePaths) {
1678
1758
 
1679
1759
  ${userCode}` : userCode;
1680
1760
  }
1681
- const configObject = buildConfigObject(flowConfig, explicitCodeImports);
1761
+ const { storesDeclaration, configObject } = buildConfigObject(
1762
+ flowSettings,
1763
+ explicitCodeImports
1764
+ );
1682
1765
  const wrappedCode = generatePlatformWrapper(
1766
+ storesDeclaration,
1683
1767
  configObject,
1684
1768
  buildOptions.code || "",
1685
1769
  buildOptions
@@ -1711,8 +1795,8 @@ ${firstError.text}`
1711
1795
  ` + (location ? ` at ${location.file}:${location.line}:${location.column}` : "")
1712
1796
  );
1713
1797
  }
1714
- function buildConfigObject(flowConfig, explicitCodeImports) {
1715
- const flowWithProps = flowConfig;
1798
+ function buildConfigObject(flowSettings, explicitCodeImports) {
1799
+ const flowWithProps = flowSettings;
1716
1800
  const sources = flowWithProps.sources || {};
1717
1801
  const destinations = flowWithProps.destinations || {};
1718
1802
  const transformers = flowWithProps.transformers || {};
@@ -1821,24 +1905,25 @@ function buildConfigObject(flowConfig, explicitCodeImports) {
1821
1905
  config: ${configStr}${envStr}
1822
1906
  }`;
1823
1907
  });
1908
+ const storesDeclaration = storesEntries.length > 0 ? `const stores = {
1909
+ ${storesEntries.join(",\n")}
1910
+ };` : "const stores = {};";
1824
1911
  const collectorStr = flowWithProps.collector ? `,
1825
1912
  ...${processConfigValue(flowWithProps.collector)}` : "";
1826
1913
  const transformersStr = transformersEntries.length > 0 ? `,
1827
1914
  transformers: {
1828
1915
  ${transformersEntries.join(",\n")}
1829
1916
  }` : "";
1830
- const storesStr = storesEntries.length > 0 ? `,
1831
- stores: {
1832
- ${storesEntries.join(",\n")}
1833
- }` : "";
1834
- return `{
1917
+ const configObject = `{
1835
1918
  sources: {
1836
1919
  ${sourcesEntries.join(",\n")}
1837
1920
  },
1838
1921
  destinations: {
1839
1922
  ${destinationsEntries.join(",\n")}
1840
- }${transformersStr}${storesStr}${collectorStr}
1923
+ }${transformersStr},
1924
+ stores${collectorStr}
1841
1925
  }`;
1926
+ return { storesDeclaration, configObject };
1842
1927
  }
1843
1928
  function processConfigValue(value) {
1844
1929
  return serializeWithCode(value, 0);
@@ -1907,7 +1992,7 @@ ${spaces}}`;
1907
1992
  }
1908
1993
  return JSON.stringify(value);
1909
1994
  }
1910
- function generatePlatformWrapper(configObject, userCode, buildOptions) {
1995
+ function generatePlatformWrapper(storesDeclaration, configObject, userCode, buildOptions) {
1911
1996
  if (buildOptions.platform === "browser") {
1912
1997
  const windowAssignments = [];
1913
1998
  if (buildOptions.windowCollector) {
@@ -1922,6 +2007,8 @@ function generatePlatformWrapper(configObject, userCode, buildOptions) {
1922
2007
  }
1923
2008
  const assignments = windowAssignments.length > 0 ? "\n" + windowAssignments.join("\n") : "";
1924
2009
  return `(async () => {
2010
+ ${storesDeclaration}
2011
+
1925
2012
  const config = ${configObject};
1926
2013
 
1927
2014
  ${userCode}
@@ -1933,6 +2020,8 @@ function generatePlatformWrapper(configObject, userCode, buildOptions) {
1933
2020
  ${userCode}
1934
2021
  ` : "";
1935
2022
  return `export default async function(context = {}) {
2023
+ ${storesDeclaration}
2024
+
1936
2025
  const config = ${configObject};${codeSection}
1937
2026
  // Apply context overrides (e.g., logger config from CLI)
1938
2027
  if (context.logger) {
@@ -1959,6 +2048,16 @@ function generatePlatformWrapper(configObject, userCode, buildOptions) {
1959
2048
  }`;
1960
2049
  }
1961
2050
  }
2051
+ var VALID_JS_IDENTIFIER;
2052
+ var init_bundler = __esm({
2053
+ "src/commands/bundle/bundler.ts"() {
2054
+ "use strict";
2055
+ init_package_manager();
2056
+ init_tmp();
2057
+ init_build_cache();
2058
+ VALID_JS_IDENTIFIER = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
2059
+ }
2060
+ });
1962
2061
 
1963
2062
  // src/commands/bundle/upload.ts
1964
2063
  import fs9 from "fs-extra";
@@ -1988,32 +2087,42 @@ async function uploadBundleToUrl(filePath, url, timeoutMs = 3e4) {
1988
2087
  };
1989
2088
  await doUpload(1);
1990
2089
  }
2090
+ var init_upload = __esm({
2091
+ "src/commands/bundle/upload.ts"() {
2092
+ "use strict";
2093
+ }
2094
+ });
1991
2095
 
1992
2096
  // src/commands/bundle/stats.ts
1993
- function displayStats(stats, logger2) {
1994
- logger2.info("\n\u{1F4CA} Bundle Statistics");
1995
- logger2.info("\u2500".repeat(50));
2097
+ function displayStats(stats, logger) {
2098
+ logger.info("\n\u{1F4CA} Bundle Statistics");
2099
+ logger.info("\u2500".repeat(50));
1996
2100
  const sizeKB = formatBytes(stats.totalSize);
1997
- logger2.info(`Total Size: ${sizeKB} KB`);
2101
+ logger.info(`Total Size: ${sizeKB} KB`);
1998
2102
  const timeSeconds = (stats.buildTime / 1e3).toFixed(2);
1999
- logger2.info(`Build Time: ${timeSeconds}s`);
2103
+ logger.info(`Build Time: ${timeSeconds}s`);
2000
2104
  const treeshakingStatus = stats.treeshakingEffective ? "\u2705 Effective" : "\u26A0\uFE0F Not optimal (consider using named imports)";
2001
- logger2.info(`Tree-shaking: ${treeshakingStatus}`);
2105
+ logger.info(`Tree-shaking: ${treeshakingStatus}`);
2002
2106
  if (stats.packages.length > 0) {
2003
- logger2.info(`
2107
+ logger.info(`
2004
2108
  Package Breakdown:`);
2005
2109
  stats.packages.forEach((pkg) => {
2006
2110
  if (pkg.size > 0) {
2007
2111
  const pkgSizeKB = formatBytes(pkg.size);
2008
- logger2.info(` \u2022 ${pkg.name}: ${pkgSizeKB} KB`);
2112
+ logger.info(` \u2022 ${pkg.name}: ${pkgSizeKB} KB`);
2009
2113
  }
2010
2114
  });
2011
2115
  }
2012
- logger2.info("\u2500".repeat(50));
2116
+ logger.info("\u2500".repeat(50));
2013
2117
  }
2118
+ var init_stats = __esm({
2119
+ "src/commands/bundle/stats.ts"() {
2120
+ "use strict";
2121
+ init_core();
2122
+ }
2123
+ });
2014
2124
 
2015
2125
  // src/core/api-client.ts
2016
- init_auth();
2017
2126
  import createClient from "openapi-fetch";
2018
2127
  function createApiClient() {
2019
2128
  const token = getToken();
@@ -2026,6 +2135,12 @@ function createApiClient() {
2026
2135
  }
2027
2136
  });
2028
2137
  }
2138
+ var init_api_client = __esm({
2139
+ "src/core/api-client.ts"() {
2140
+ "use strict";
2141
+ init_auth();
2142
+ }
2143
+ });
2029
2144
 
2030
2145
  // src/commands/bundle/dockerfile.ts
2031
2146
  import path10 from "path";
@@ -2045,19 +2160,27 @@ function buildDockerfileContent(platform, includedFolders) {
2045
2160
  lines.push("", `ENV BUNDLE=/app/flow/${bundleFile}`, "", "EXPOSE 8080", "");
2046
2161
  return lines.join("\n");
2047
2162
  }
2048
- async function generateDockerfile(outputDir, platform, logger2, customFile, includedFolders) {
2163
+ async function generateDockerfile(outputDir, platform, logger, customFile, includedFolders) {
2049
2164
  const destPath = path10.join(outputDir, "Dockerfile");
2050
2165
  if (customFile && await fs10.pathExists(customFile)) {
2051
2166
  await fs10.copy(customFile, destPath);
2052
- logger2.info(`Dockerfile: ${destPath} (copied from ${customFile})`);
2167
+ logger.info(`Dockerfile: ${destPath} (copied from ${customFile})`);
2053
2168
  return;
2054
2169
  }
2055
2170
  const dockerfile = buildDockerfileContent(platform, includedFolders || []);
2056
2171
  await fs10.writeFile(destPath, dockerfile);
2057
- logger2.info(`Dockerfile: ${destPath}`);
2172
+ logger.info(`Dockerfile: ${destPath}`);
2058
2173
  }
2174
+ var init_dockerfile = __esm({
2175
+ "src/commands/bundle/dockerfile.ts"() {
2176
+ "use strict";
2177
+ }
2178
+ });
2059
2179
 
2060
2180
  // src/commands/bundle/index.ts
2181
+ import path11 from "path";
2182
+ import fs11 from "fs-extra";
2183
+ import { getPlatform as getPlatform2 } from "@walkeros/core";
2061
2184
  function resolveOutputPath(output, buildOptions) {
2062
2185
  const resolved = path11.resolve(output);
2063
2186
  const ext = path11.extname(resolved);
@@ -2071,7 +2194,7 @@ async function bundleCommand(options) {
2071
2194
  const timer = createTimer();
2072
2195
  timer.start();
2073
2196
  const writingToStdout = !options.output;
2074
- const logger2 = createCLILogger({
2197
+ const logger = createCLILogger({
2075
2198
  ...options,
2076
2199
  stderr: writingToStdout
2077
2200
  });
@@ -2099,16 +2222,16 @@ async function bundleCommand(options) {
2099
2222
  configPath = resolveAsset(file, "config");
2100
2223
  rawConfig = await loadJsonConfig(configPath);
2101
2224
  }
2102
- const configsToBundle = options.all ? loadAllFlows(rawConfig, { configPath, logger: logger2 }) : [
2225
+ const configsToBundle = options.all ? loadAllFlows(rawConfig, { configPath, logger }) : [
2103
2226
  loadBundleConfig(rawConfig, {
2104
2227
  configPath,
2105
2228
  flowName: options.flow,
2106
- logger: logger2
2229
+ logger
2107
2230
  })
2108
2231
  ];
2109
2232
  const results = [];
2110
2233
  for (const {
2111
- flowConfig,
2234
+ flowSettings,
2112
2235
  buildOptions,
2113
2236
  flowName,
2114
2237
  isMultiFlow
@@ -2132,39 +2255,39 @@ async function bundleCommand(options) {
2132
2255
  buildOptions.output = getTmpPath(void 0, "stdout-bundle" + ext);
2133
2256
  }
2134
2257
  if (isMultiFlow || options.all) {
2135
- logger2.info(`Bundling flow: ${flowName}...`);
2258
+ logger.info(`Bundling flow: ${flowName}...`);
2136
2259
  } else {
2137
- logger2.info("Bundling...");
2260
+ logger.info("Bundling...");
2138
2261
  }
2139
2262
  const shouldCollectStats = options.stats || options.json;
2140
2263
  const stats = await bundleCore(
2141
- flowConfig,
2264
+ flowSettings,
2142
2265
  buildOptions,
2143
- logger2,
2266
+ logger,
2144
2267
  shouldCollectStats
2145
2268
  );
2146
2269
  results.push({ flowName, success: true, stats });
2147
2270
  if (uploadUrl) {
2148
2271
  await uploadBundleToUrl(buildOptions.output, uploadUrl);
2149
- logger2.info(`Uploaded to: ${sanitizeUrl(uploadUrl)}`);
2272
+ logger.info(`Uploaded to: ${sanitizeUrl(uploadUrl)}`);
2150
2273
  await fs11.remove(buildOptions.output);
2151
2274
  }
2152
2275
  if (!options.json && !options.all && options.stats && stats) {
2153
- displayStats(stats, logger2);
2276
+ displayStats(stats, logger);
2154
2277
  }
2155
2278
  if (writingToStdout && !options.json) {
2156
2279
  const bundleContent = await fs11.readFile(buildOptions.output);
2157
2280
  await writeResult(bundleContent, {});
2158
2281
  }
2159
2282
  if (options.dockerfile && options.output) {
2160
- const platform = getPlatform2(flowConfig);
2283
+ const platform = getPlatform2(flowSettings);
2161
2284
  if (platform) {
2162
2285
  const outputDir = path11.dirname(buildOptions.output);
2163
2286
  const customFile = typeof options.dockerfile === "string" ? options.dockerfile : void 0;
2164
2287
  await generateDockerfile(
2165
2288
  outputDir,
2166
2289
  platform,
2167
- logger2,
2290
+ logger,
2168
2291
  customFile,
2169
2292
  buildOptions.include
2170
2293
  );
@@ -2201,12 +2324,12 @@ async function bundleCommand(options) {
2201
2324
  });
2202
2325
  } else {
2203
2326
  if (options.all) {
2204
- logger2.info(
2327
+ logger.info(
2205
2328
  `
2206
2329
  Build Summary: ${successCount}/${results.length} succeeded`
2207
2330
  );
2208
2331
  if (failureCount > 0) {
2209
- logger2.error(`Failed: ${failureCount}`);
2332
+ logger.error(`Failed: ${failureCount}`);
2210
2333
  }
2211
2334
  }
2212
2335
  if (failureCount > 0) {
@@ -2223,7 +2346,7 @@ Build Summary: ${successCount}/${results.length} succeeded`
2223
2346
  output: options.output
2224
2347
  });
2225
2348
  } else {
2226
- logger2.error(`Error: ${errorMessage}`);
2349
+ logger.error(`Error: ${errorMessage}`);
2227
2350
  }
2228
2351
  process.exit(1);
2229
2352
  }
@@ -2237,7 +2360,7 @@ async function bundle(configOrPath, options = {}) {
2237
2360
  } else {
2238
2361
  rawConfig = configOrPath;
2239
2362
  }
2240
- const { flowConfig, buildOptions } = loadBundleConfig(rawConfig, {
2363
+ const { flowSettings, buildOptions } = loadBundleConfig(rawConfig, {
2241
2364
  configPath,
2242
2365
  flowName: options.flowName,
2243
2366
  buildOverrides: options.buildOverrides
@@ -2245,11 +2368,11 @@ async function bundle(configOrPath, options = {}) {
2245
2368
  if (options.cache !== void 0) {
2246
2369
  buildOptions.cache = options.cache;
2247
2370
  }
2248
- const logger2 = createCLILogger(options);
2371
+ const logger = createCLILogger(options);
2249
2372
  return await bundleCore(
2250
- flowConfig,
2373
+ flowSettings,
2251
2374
  buildOptions,
2252
- logger2,
2375
+ logger,
2253
2376
  options.stats ?? false
2254
2377
  );
2255
2378
  }
@@ -2271,6 +2394,110 @@ async function bundleRemote(options) {
2271
2394
  stats: statsHeader ? JSON.parse(statsHeader) : void 0
2272
2395
  };
2273
2396
  }
2397
+ var init_bundle = __esm({
2398
+ "src/commands/bundle/index.ts"() {
2399
+ "use strict";
2400
+ init_cli_logger();
2401
+ init_core();
2402
+ init_config();
2403
+ init_utils();
2404
+ init_bundler();
2405
+ init_upload();
2406
+ init_stats();
2407
+ init_api_client();
2408
+ init_dockerfile();
2409
+ }
2410
+ });
2411
+
2412
+ // src/runtime/cache.ts
2413
+ var cache_exports = {};
2414
+ __export(cache_exports, {
2415
+ readCache: () => readCache,
2416
+ readCacheConfig: () => readCacheConfig,
2417
+ writeCache: () => writeCache
2418
+ });
2419
+ import {
2420
+ existsSync as existsSync4,
2421
+ mkdirSync as mkdirSync2,
2422
+ copyFileSync,
2423
+ writeFileSync as writeFileSync3,
2424
+ readFileSync as readFileSync2
2425
+ } from "fs";
2426
+ import { join as join2 } from "path";
2427
+ function writeCache(cacheDir, bundlePath, configContent, version) {
2428
+ mkdirSync2(cacheDir, { recursive: true });
2429
+ copyFileSync(bundlePath, join2(cacheDir, "bundle.mjs"));
2430
+ writeFileSync3(join2(cacheDir, "config.json"), configContent, "utf-8");
2431
+ const meta = { version, timestamp: Date.now() };
2432
+ writeFileSync3(join2(cacheDir, "meta.json"), JSON.stringify(meta), "utf-8");
2433
+ }
2434
+ function readCache(cacheDir) {
2435
+ try {
2436
+ const metaPath = join2(cacheDir, "meta.json");
2437
+ const bundlePath = join2(cacheDir, "bundle.mjs");
2438
+ if (!existsSync4(metaPath) || !existsSync4(bundlePath)) return null;
2439
+ const meta = JSON.parse(readFileSync2(metaPath, "utf-8"));
2440
+ return { bundlePath, version: meta.version };
2441
+ } catch {
2442
+ return null;
2443
+ }
2444
+ }
2445
+ function readCacheConfig(cacheDir) {
2446
+ try {
2447
+ const configPath = join2(cacheDir, "config.json");
2448
+ if (!existsSync4(configPath)) return null;
2449
+ return readFileSync2(configPath, "utf-8");
2450
+ } catch {
2451
+ return null;
2452
+ }
2453
+ }
2454
+ var init_cache = __esm({
2455
+ "src/runtime/cache.ts"() {
2456
+ "use strict";
2457
+ }
2458
+ });
2459
+
2460
+ // src/commands/run/utils.ts
2461
+ var utils_exports = {};
2462
+ __export(utils_exports, {
2463
+ isPreBuiltConfig: () => isPreBuiltConfig,
2464
+ prepareBundleForRun: () => prepareBundleForRun
2465
+ });
2466
+ import path13 from "path";
2467
+ import fs14 from "fs-extra";
2468
+ async function prepareBundleForRun(configPath, options) {
2469
+ const tempDir = getTmpPath(
2470
+ void 0,
2471
+ `run-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
2472
+ );
2473
+ await fs14.ensureDir(tempDir);
2474
+ const tempPath = path13.join(tempDir, "bundle.mjs");
2475
+ await bundle(configPath, {
2476
+ cache: true,
2477
+ verbose: options.verbose,
2478
+ silent: options.silent,
2479
+ flowName: options.flowName,
2480
+ buildOverrides: {
2481
+ output: tempPath,
2482
+ format: "esm",
2483
+ platform: "node"
2484
+ }
2485
+ });
2486
+ return tempPath;
2487
+ }
2488
+ function isPreBuiltConfig(configPath) {
2489
+ return configPath.endsWith(".mjs") || configPath.endsWith(".js") || configPath.endsWith(".cjs");
2490
+ }
2491
+ var init_utils3 = __esm({
2492
+ "src/commands/run/utils.ts"() {
2493
+ "use strict";
2494
+ init_bundle();
2495
+ init_core();
2496
+ }
2497
+ });
2498
+
2499
+ // src/index.ts
2500
+ init_bundle();
2274
2501
 
2275
2502
  // src/commands/simulate/simulator.ts
2276
2503
  import fs12 from "fs-extra";
@@ -2282,7 +2509,7 @@ import { assign as a, clone as c, debounce as u, getId as f, getGrantedConsent a
2282
2509
  import { isArray as y } from "@walkeros/core";
2283
2510
  import { tryCatch as b, tryCatchAsync as v } from "@walkeros/core";
2284
2511
  import { getMappingValue as k, tryCatchAsync as C } from "@walkeros/core";
2285
- import { isObject as O, tryCatchAsync as q, useHooks as j } from "@walkeros/core";
2512
+ import { isObject as O, tryCatchAsync as j, useHooks as q } from "@walkeros/core";
2286
2513
  import { assign as M, getId as Q, isFunction as V, isString as _ } from "@walkeros/core";
2287
2514
  import { isObject as K } from "@walkeros/core";
2288
2515
  import { getGrantedConsent as en, processEventMapping as tn, tryCatchAsync as on, useHooks as sn } from "@walkeros/core";
@@ -2322,20 +2549,20 @@ function E(n, e2 = {}) {
2322
2549
  }
2323
2550
  return t2;
2324
2551
  }
2325
- async function P(n, e2, t2) {
2552
+ async function x(n, e2, t2) {
2326
2553
  if (e2.init && !e2.config.init) {
2327
2554
  const o2 = e2.type || "unknown", s2 = n.logger.scope(`transformer:${o2}`), r2 = { collector: n, logger: s2, id: t2, config: e2.config, env: $(e2.config.env) };
2328
2555
  s2.debug("init");
2329
- const i2 = await j(e2.init, "TransformerInit", n.hooks)(r2);
2556
+ const i2 = await q(e2.init, "TransformerInit", n.hooks)(r2);
2330
2557
  if (false === i2) return false;
2331
2558
  e2.config = { ...i2 || e2.config, init: true }, s2.debug("init done");
2332
2559
  }
2333
2560
  return true;
2334
2561
  }
2335
- async function x(n, e2, t2, o2, s2, r2) {
2562
+ async function P(n, e2, t2, o2, s2, r2) {
2336
2563
  const i2 = e2.type || "unknown", a2 = n.logger.scope(`transformer:${i2}`), c2 = { collector: n, logger: a2, id: t2, ingest: s2, config: e2.config, env: { ...$(e2.config.env), ...r2 ? { respond: r2 } : {} } };
2337
2564
  a2.debug("push", { event: o2.name });
2338
- const u2 = await j(e2.push, "TransformerPush", n.hooks)(o2, c2);
2565
+ const u2 = await q(e2.push, "TransformerPush", n.hooks)(o2, c2);
2339
2566
  return a2.debug("push done"), u2;
2340
2567
  }
2341
2568
  async function S(n, e2, t2, o2, s2, r2) {
@@ -2346,8 +2573,8 @@ async function S(n, e2, t2, o2, s2, r2) {
2346
2573
  n.logger.warn(`Transformer not found: ${o3}`);
2347
2574
  continue;
2348
2575
  }
2349
- if (!await q(P)(n, t3, o3)) return n.logger.error(`Transformer init failed: ${o3}`), null;
2350
- const r3 = await q(x, (e3) => (n.logger.scope(`transformer:${t3.type || "unknown"}`).error("Push failed", { error: e3 }), false))(n, t3, o3, i2, s2, a2);
2576
+ if (!await j(x)(n, t3, o3)) return n.logger.error(`Transformer init failed: ${o3}`), null;
2577
+ const r3 = await j(P, (e3) => (n.logger.scope(`transformer:${t3.type || "unknown"}`).error("Push failed", { error: e3 }), false))(n, t3, o3, i2, s2, a2);
2351
2578
  if (false === r3) return null;
2352
2579
  if (r3 && "object" == typeof r3) {
2353
2580
  const { event: t4, respond: o4, next: c2 } = r3;
@@ -2547,10 +2774,10 @@ async function U(n, e2, t2 = {}, o2) {
2547
2774
  })), g2 = {}, d2 = {}, m2 = {};
2548
2775
  for (const e3 of f2) {
2549
2776
  if (e3.skipped) continue;
2550
- const t3 = e3.destination, o3 = { type: t3.type || "unknown", data: e3.response };
2777
+ const t3 = { type: e3.destination.type || "unknown", data: e3.response };
2551
2778
  n.status.destinations[e3.id] || (n.status.destinations[e3.id] = { count: 0, failed: 0, duration: 0 });
2552
- const s3 = n.status.destinations[e3.id], r3 = Date.now();
2553
- e3.error ? (o3.error = e3.error, m2[e3.id] = o3, s3.failed++, s3.lastAt = r3, s3.duration += e3.totalDuration || 0, n.status.failed++) : e3.queue && e3.queue.length ? (t3.queuePush = (t3.queuePush || []).concat(e3.queue), d2[e3.id] = o3) : (g2[e3.id] = o3, s3.count++, s3.lastAt = r3, s3.duration += e3.totalDuration || 0, n.status.out++);
2779
+ const o3 = n.status.destinations[e3.id], s3 = Date.now();
2780
+ e3.error ? (t3.error = e3.error, m2[e3.id] = t3, o3.failed++, o3.lastAt = s3, o3.duration += e3.totalDuration || 0, n.status.failed++) : e3.queue && e3.queue.length ? d2[e3.id] = t3 : (g2[e3.id] = t3, o3.count++, o3.lastAt = s3, o3.duration += e3.totalDuration || 0, n.status.out++);
2554
2781
  }
2555
2782
  return N({ event: e2, ...Object.keys(g2).length && { done: g2 }, ...Object.keys(d2).length && { queued: d2 }, ...Object.keys(m2).length && { failed: m2 } });
2556
2783
  }
@@ -2817,6 +3044,9 @@ async function dn(n) {
2817
3044
 
2818
3045
  // src/commands/simulate/simulator.ts
2819
3046
  init_cli_logger();
3047
+ init_core();
3048
+ init_config();
3049
+ init_tmp();
2820
3050
 
2821
3051
  // src/commands/simulate/env-loader.ts
2822
3052
  async function loadDestinationEnvs(destinations) {
@@ -2859,13 +3089,13 @@ function callsToUsage(destName, calls) {
2859
3089
  };
2860
3090
  }
2861
3091
  async function simulateCore(inputPath, event, options = {}) {
2862
- const logger2 = createCLILogger({
3092
+ const logger = createCLILogger({
2863
3093
  verbose: options.verbose || false,
2864
3094
  silent: options.silent || false,
2865
3095
  json: options.json || false
2866
3096
  });
2867
3097
  try {
2868
- logger2.debug(`Simulating event: ${JSON.stringify(event)}`);
3098
+ logger.debug(`Simulating event: ${JSON.stringify(event)}`);
2869
3099
  const result = await executeSimulation(event, inputPath, options.platform, {
2870
3100
  flow: options.flow,
2871
3101
  step: options.step,
@@ -2934,7 +3164,7 @@ async function executeSimulation(event, inputPath, platformOverride, options = {
2934
3164
  const typedEvent = event;
2935
3165
  if (detected.type !== "config") {
2936
3166
  throw new Error(
2937
- `Input "${inputPath}" is not valid JSON config. simulate only accepts Flow.Setup config files.`
3167
+ `Input "${inputPath}" is not valid JSON config. simulate only accepts Flow.Config config files.`
2938
3168
  );
2939
3169
  }
2940
3170
  return await executeConfigSimulation(
@@ -2985,12 +3215,12 @@ function parseStepTarget(stepTarget, flowConfig) {
2985
3215
  throw new Error("No destination found in flow config");
2986
3216
  }
2987
3217
  async function executeConfigSimulation(_content, configPath, typedEvent, tempDir, startTime, flowName, stepTarget) {
2988
- const { flowConfig } = await loadFlowConfig(configPath, {
3218
+ const { flowSettings } = await loadFlowConfig(configPath, {
2989
3219
  flowName
2990
3220
  });
2991
3221
  const step = parseStepTarget(
2992
3222
  stepTarget,
2993
- flowConfig
3223
+ flowSettings
2994
3224
  );
2995
3225
  if (step.type === "destination") {
2996
3226
  const packageName = step.config.package;
@@ -2999,7 +3229,7 @@ async function executeConfigSimulation(_content, configPath, typedEvent, tempDir
2999
3229
  }
3000
3230
  const destModule = await import(packageName);
3001
3231
  const code = destModule.default || Object.values(destModule)[0];
3002
- const destinations = flowConfig.destinations;
3232
+ const destinations = flowSettings.destinations;
3003
3233
  const envs = await loadDestinationEnvs(destinations || {});
3004
3234
  const destEnv = envs[step.name];
3005
3235
  const result = await dn({
@@ -3049,6 +3279,7 @@ async function executeConfigSimulation(_content, configPath, typedEvent, tempDir
3049
3279
 
3050
3280
  // src/commands/simulate/source-simulator.ts
3051
3281
  import { JSDOM, VirtualConsole } from "jsdom";
3282
+ init_core();
3052
3283
  async function loadSourcePackage(packageName) {
3053
3284
  const mainModule = await import(packageName);
3054
3285
  const code = mainModule.default || Object.values(mainModule)[0];
@@ -3126,6 +3357,9 @@ async function simulateSourceCLI(flowConfig, setupInput, options) {
3126
3357
 
3127
3358
  // src/commands/simulate/index.ts
3128
3359
  init_cli_logger();
3360
+ init_core();
3361
+ init_config();
3362
+ init_validators();
3129
3363
 
3130
3364
  // src/commands/simulate/example-loader.ts
3131
3365
  function findExample(config, exampleName, stepTarget) {
@@ -3231,7 +3465,7 @@ ${actualStr}`
3231
3465
 
3232
3466
  // src/commands/simulate/index.ts
3233
3467
  async function simulateCommand(options) {
3234
- const logger2 = createCLILogger({ ...options, stderr: true });
3468
+ const logger = createCLILogger({ ...options, stderr: true });
3235
3469
  const startTime = Date.now();
3236
3470
  try {
3237
3471
  let config;
@@ -3279,7 +3513,7 @@ async function simulateCommand(options) {
3279
3513
  );
3280
3514
  await writeResult(errorOutput + "\n", { output: options.output });
3281
3515
  } else {
3282
- logger2.error(`Error: ${errorMessage}`);
3516
+ logger.error(`Error: ${errorMessage}`);
3283
3517
  }
3284
3518
  process.exit(1);
3285
3519
  }
@@ -3297,7 +3531,7 @@ async function simulate(configOrPath, event, options = {}) {
3297
3531
  let exampleContext;
3298
3532
  if (options.example) {
3299
3533
  const rawConfig = await loadJsonConfig(configOrPath);
3300
- const setup = validateFlowSetup(rawConfig);
3534
+ const setup = validateFlowConfig(rawConfig);
3301
3535
  const flowNames = Object.keys(setup.flows);
3302
3536
  let flowName = options.flow;
3303
3537
  if (!flowName) {
@@ -3310,13 +3544,13 @@ Available flows: ${flowNames.join(", ")}`
3310
3544
  );
3311
3545
  }
3312
3546
  }
3313
- const flowConfig = setup.flows[flowName];
3314
- if (!flowConfig) {
3547
+ const flowSettings = setup.flows[flowName];
3548
+ if (!flowSettings) {
3315
3549
  throw new Error(
3316
3550
  `Flow "${flowName}" not found. Available: ${flowNames.join(", ")}`
3317
3551
  );
3318
3552
  }
3319
- const found = findExample(flowConfig, options.example, options.step);
3553
+ const found = findExample(flowSettings, options.example, options.step);
3320
3554
  if (found.example.in === void 0) {
3321
3555
  throw new Error(
3322
3556
  `Example "${options.example}" in ${found.stepType}.${found.stepName} has no "in" value`
@@ -3333,7 +3567,7 @@ Available flows: ${flowNames.join(", ")}`
3333
3567
  let result;
3334
3568
  if (isSourceSimulation) {
3335
3569
  const rawConfig = await loadJsonConfig(configOrPath);
3336
- const setup = validateFlowSetup(rawConfig);
3570
+ const setup = validateFlowConfig(rawConfig);
3337
3571
  const flowNames = Object.keys(setup.flows);
3338
3572
  const flowName = options.flow || (flowNames.length === 1 ? flowNames[0] : void 0);
3339
3573
  if (!flowName) {
@@ -3342,15 +3576,15 @@ Available flows: ${flowNames.join(", ")}`
3342
3576
  Available: ${flowNames.join(", ")}`
3343
3577
  );
3344
3578
  }
3345
- const flowConfig = setup.flows[flowName];
3346
- if (!flowConfig) {
3579
+ const flowSettings = setup.flows[flowName];
3580
+ if (!flowSettings) {
3347
3581
  throw new Error(
3348
3582
  `Flow "${flowName}" not found. Available: ${flowNames.join(", ")}`
3349
3583
  );
3350
3584
  }
3351
3585
  const sourceStep = exampleContext?.stepName || options.step.substring("source.".length);
3352
3586
  result = await simulateSourceCLI(
3353
- flowConfig,
3587
+ flowSettings,
3354
3588
  resolvedEvent,
3355
3589
  {
3356
3590
  flow: options.flow,
@@ -3398,6 +3632,10 @@ Available: ${flowNames.join(", ")}`
3398
3632
 
3399
3633
  // src/commands/push/index.ts
3400
3634
  init_cli_logger();
3635
+ init_core();
3636
+ init_tmp();
3637
+ init_config();
3638
+ init_bundler();
3401
3639
  import path12 from "path";
3402
3640
  import { JSDOM as JSDOM2, VirtualConsole as VirtualConsole2 } from "jsdom";
3403
3641
  import fs13 from "fs-extra";
@@ -3405,7 +3643,7 @@ import { getPlatform as getPlatform3 } from "@walkeros/core";
3405
3643
  import { schemas as schemas2 } from "@walkeros/core/dev";
3406
3644
  import { Level as Level2 } from "@walkeros/core";
3407
3645
  async function pushCore(inputPath, event, options = {}) {
3408
- const logger2 = createCLILogger({
3646
+ const logger = createCLILogger({
3409
3647
  silent: options.silent,
3410
3648
  verbose: options.verbose
3411
3649
  });
@@ -3426,11 +3664,11 @@ async function pushCore(inputPath, event, options = {}) {
3426
3664
  data: parsedEvent.data || {}
3427
3665
  };
3428
3666
  if (!validatedEvent.name.includes(" ")) {
3429
- logger2.info(
3667
+ logger.info(
3430
3668
  `Warning: Event name "${validatedEvent.name}" should follow "ENTITY ACTION" format (e.g., "page view")`
3431
3669
  );
3432
3670
  }
3433
- logger2.debug("Detecting input type");
3671
+ logger.debug("Detecting input type");
3434
3672
  const detected = await detectInput(
3435
3673
  inputPath,
3436
3674
  options.platform
@@ -3444,7 +3682,7 @@ async function pushCore(inputPath, event, options = {}) {
3444
3682
  verbose: options.verbose
3445
3683
  },
3446
3684
  validatedEvent,
3447
- logger2,
3685
+ logger,
3448
3686
  (dir) => {
3449
3687
  tempDir = dir;
3450
3688
  }
@@ -3454,7 +3692,7 @@ async function pushCore(inputPath, event, options = {}) {
3454
3692
  detected.content,
3455
3693
  detected.platform,
3456
3694
  validatedEvent,
3457
- logger2,
3695
+ logger,
3458
3696
  (dir) => {
3459
3697
  tempDir = dir;
3460
3698
  },
@@ -3476,7 +3714,7 @@ async function pushCore(inputPath, event, options = {}) {
3476
3714
  }
3477
3715
  }
3478
3716
  async function pushCommand(options) {
3479
- const logger2 = createCLILogger({ ...options, stderr: true });
3717
+ const logger = createCLILogger({ ...options, stderr: true });
3480
3718
  const startTime = Date.now();
3481
3719
  try {
3482
3720
  let config;
@@ -3540,7 +3778,7 @@ async function pushCommand(options) {
3540
3778
  );
3541
3779
  await writeResult(errorOutput + "\n", { output: options.output });
3542
3780
  } else {
3543
- logger2.error(`Error: ${errorMessage}`);
3781
+ logger.error(`Error: ${errorMessage}`);
3544
3782
  }
3545
3783
  process.exit(1);
3546
3784
  }
@@ -3563,14 +3801,14 @@ async function push(configOrPath, event, options = {}) {
3563
3801
  platform: options.platform
3564
3802
  });
3565
3803
  }
3566
- async function executeConfigPush(options, validatedEvent, logger2, setTempDir) {
3567
- logger2.debug("Loading flow configuration");
3568
- const { flowConfig, buildOptions } = await loadFlowConfig(options.config, {
3804
+ async function executeConfigPush(options, validatedEvent, logger, setTempDir) {
3805
+ logger.debug("Loading flow configuration");
3806
+ const { flowSettings, buildOptions } = await loadFlowConfig(options.config, {
3569
3807
  flowName: options.flow,
3570
- logger: logger2
3808
+ logger
3571
3809
  });
3572
- const platform = getPlatform3(flowConfig);
3573
- logger2.debug("Bundling flow configuration");
3810
+ const platform = getPlatform3(flowSettings);
3811
+ logger.debug("Bundling flow configuration");
3574
3812
  const configDir = buildOptions.configDir || process.cwd();
3575
3813
  const tempDir = getTmpPath(
3576
3814
  void 0,
@@ -3592,21 +3830,21 @@ async function executeConfigPush(options, validatedEvent, logger2, setTempDir) {
3592
3830
  windowElb: "elb"
3593
3831
  }
3594
3832
  };
3595
- await bundleCore(flowConfig, pushBuildOptions, logger2, false);
3596
- logger2.debug(`Bundle created: ${tempPath}`);
3833
+ await bundleCore(flowSettings, pushBuildOptions, logger, false);
3834
+ logger.debug(`Bundle created: ${tempPath}`);
3597
3835
  if (platform === "web") {
3598
- logger2.debug("Executing in web environment (JSDOM)");
3599
- return executeWebPush(tempPath, validatedEvent, logger2);
3836
+ logger.debug("Executing in web environment (JSDOM)");
3837
+ return executeWebPush(tempPath, validatedEvent, logger);
3600
3838
  } else if (platform === "server") {
3601
- logger2.debug("Executing in server environment (Node.js)");
3602
- return executeServerPush(tempPath, validatedEvent, logger2, 6e4, {
3839
+ logger.debug("Executing in server environment (Node.js)");
3840
+ return executeServerPush(tempPath, validatedEvent, logger, 6e4, {
3603
3841
  logger: { level: options.verbose ? Level2.DEBUG : Level2.ERROR }
3604
3842
  });
3605
3843
  } else {
3606
3844
  throw new Error(`Unsupported platform: ${platform}`);
3607
3845
  }
3608
3846
  }
3609
- async function executeBundlePush(bundleContent, platform, validatedEvent, logger2, setTempDir, context = {}) {
3847
+ async function executeBundlePush(bundleContent, platform, validatedEvent, logger, setTempDir, context = {}) {
3610
3848
  const tempDir = getTmpPath(
3611
3849
  void 0,
3612
3850
  `push-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
@@ -3618,16 +3856,16 @@ async function executeBundlePush(bundleContent, platform, validatedEvent, logger
3618
3856
  `bundle.${platform === "server" ? "mjs" : "js"}`
3619
3857
  );
3620
3858
  await fs13.writeFile(tempPath, bundleContent, "utf8");
3621
- logger2.debug(`Bundle written to: ${tempPath}`);
3859
+ logger.debug(`Bundle written to: ${tempPath}`);
3622
3860
  if (platform === "web") {
3623
- logger2.debug("Executing in web environment (JSDOM)");
3624
- return executeWebPush(tempPath, validatedEvent, logger2);
3861
+ logger.debug("Executing in web environment (JSDOM)");
3862
+ return executeWebPush(tempPath, validatedEvent, logger);
3625
3863
  } else {
3626
- logger2.debug("Executing in server environment (Node.js)");
3627
- return executeServerPush(tempPath, validatedEvent, logger2, 6e4, context);
3864
+ logger.debug("Executing in server environment (Node.js)");
3865
+ return executeServerPush(tempPath, validatedEvent, logger, 6e4, context);
3628
3866
  }
3629
3867
  }
3630
- async function executeWebPush(bundlePath, event, logger2) {
3868
+ async function executeWebPush(bundlePath, event, logger) {
3631
3869
  const startTime = Date.now();
3632
3870
  try {
3633
3871
  const virtualConsole = new VirtualConsole2();
@@ -3638,10 +3876,10 @@ async function executeWebPush(bundlePath, event, logger2) {
3638
3876
  virtualConsole
3639
3877
  });
3640
3878
  const { window } = dom;
3641
- logger2.debug("Loading bundle...");
3879
+ logger.debug("Loading bundle...");
3642
3880
  const bundleCode = await fs13.readFile(bundlePath, "utf8");
3643
3881
  window.eval(bundleCode);
3644
- logger2.debug("Waiting for collector...");
3882
+ logger.debug("Waiting for collector...");
3645
3883
  await waitForWindowProperty(
3646
3884
  window,
3647
3885
  "collector",
@@ -3649,7 +3887,7 @@ async function executeWebPush(bundlePath, event, logger2) {
3649
3887
  );
3650
3888
  const windowObj = window;
3651
3889
  const collector = windowObj.collector;
3652
- logger2.info(`Pushing event: ${event.name}`);
3890
+ logger.info(`Pushing event: ${event.name}`);
3653
3891
  const elbResult = await collector.push({
3654
3892
  name: event.name,
3655
3893
  data: event.data
@@ -3667,7 +3905,7 @@ async function executeWebPush(bundlePath, event, logger2) {
3667
3905
  };
3668
3906
  }
3669
3907
  }
3670
- async function executeServerPush(bundlePath, event, logger2, timeout = 6e4, context = {}) {
3908
+ async function executeServerPush(bundlePath, event, logger, timeout = 6e4, context = {}) {
3671
3909
  const startTime = Date.now();
3672
3910
  let timer;
3673
3911
  try {
@@ -3678,12 +3916,12 @@ async function executeServerPush(bundlePath, event, logger2, timeout = 6e4, cont
3678
3916
  );
3679
3917
  });
3680
3918
  const executePromise = (async () => {
3681
- logger2.debug("Importing bundle...");
3919
+ logger.debug("Importing bundle...");
3682
3920
  const flowModule = await import(bundlePath);
3683
3921
  if (!flowModule.default || typeof flowModule.default !== "function") {
3684
3922
  throw new Error("Bundle does not export default factory function");
3685
3923
  }
3686
- logger2.debug("Calling factory function...");
3924
+ logger.debug("Calling factory function...");
3687
3925
  const result = await flowModule.default(context);
3688
3926
  if (!result || !result.collector || typeof result.collector.push !== "function") {
3689
3927
  throw new Error(
@@ -3691,7 +3929,7 @@ async function executeServerPush(bundlePath, event, logger2, timeout = 6e4, cont
3691
3929
  );
3692
3930
  }
3693
3931
  const { collector } = result;
3694
- logger2.info(`Pushing event: ${event.name}`);
3932
+ logger.info(`Pushing event: ${event.name}`);
3695
3933
  const elbResult = await collector.push({
3696
3934
  name: event.name,
3697
3935
  data: event.data
@@ -3735,106 +3973,109 @@ function waitForWindowProperty(window, prop, timeout = 5e3) {
3735
3973
 
3736
3974
  // src/commands/run/index.ts
3737
3975
  init_cli_logger();
3976
+ init_core();
3977
+ init_config_file();
3978
+ init_auth();
3738
3979
  import path14 from "path";
3739
3980
  import { createRequire } from "module";
3981
+ import { writeFileSync as writeFileSync5 } from "fs";
3982
+ import { homedir as homedir2 } from "os";
3983
+ import { join as join4 } from "path";
3984
+
3985
+ // src/runtime/resolve-bundle.ts
3986
+ init_stdin();
3987
+ import { existsSync as existsSync3, writeFileSync as writeFileSync2 } from "fs";
3988
+ var TEMP_BUNDLE_PATH = "/tmp/walkeros-bundle.mjs";
3989
+ function isUrl2(value) {
3990
+ return value.startsWith("http://") || value.startsWith("https://");
3991
+ }
3992
+ async function fetchBundle(url) {
3993
+ const response = await fetch(url, { signal: AbortSignal.timeout(3e4) });
3994
+ if (!response.ok) {
3995
+ throw new Error(
3996
+ `Failed to fetch bundle from ${url}: ${response.status} ${response.statusText}`
3997
+ );
3998
+ }
3999
+ const content = await response.text();
4000
+ if (!content.trim()) {
4001
+ throw new Error(`Bundle fetched from ${url} is empty`);
4002
+ }
4003
+ writeFileSync2(TEMP_BUNDLE_PATH, content, "utf-8");
4004
+ return TEMP_BUNDLE_PATH;
4005
+ }
4006
+ async function readBundleFromStdin() {
4007
+ const content = await readStdin();
4008
+ writeFileSync2(TEMP_BUNDLE_PATH, content, "utf-8");
4009
+ return TEMP_BUNDLE_PATH;
4010
+ }
4011
+ async function resolveBundle(bundleEnv) {
4012
+ if (!isUrl2(bundleEnv) && existsSync3(bundleEnv)) {
4013
+ return { path: bundleEnv, source: "file" };
4014
+ }
4015
+ if (isStdinPiped()) {
4016
+ const path15 = await readBundleFromStdin();
4017
+ return { path: path15, source: "stdin" };
4018
+ }
4019
+ if (isUrl2(bundleEnv)) {
4020
+ const path15 = await fetchBundle(bundleEnv);
4021
+ return { path: path15, source: "url" };
4022
+ }
4023
+ return { path: bundleEnv, source: "file" };
4024
+ }
4025
+
4026
+ // src/runtime/config-fetcher.ts
4027
+ async function fetchConfig(options) {
4028
+ const url = `${options.appUrl}/api/projects/${options.projectId}/flows/${options.flowId}`;
4029
+ const headers = {
4030
+ Authorization: `Bearer ${options.token}`
4031
+ };
4032
+ if (options.lastEtag) {
4033
+ headers["If-None-Match"] = options.lastEtag;
4034
+ }
4035
+ const response = await fetch(url, {
4036
+ headers,
4037
+ signal: AbortSignal.timeout(3e4)
4038
+ });
4039
+ if (response.status === 304) {
4040
+ return { changed: false };
4041
+ }
4042
+ if (!response.ok) {
4043
+ if (response.status === 401 || response.status === 403) {
4044
+ throw new Error(
4045
+ `Config fetch failed (${response.status}): token may have expired \u2014 redeploy to rotate`
4046
+ );
4047
+ }
4048
+ throw new Error(
4049
+ `Config fetch failed: ${response.status} ${response.statusText}`
4050
+ );
4051
+ }
4052
+ const data = await response.json();
4053
+ const etag = response.headers.get("etag") || "";
4054
+ const version = etag.replace(/"/g, "");
4055
+ return {
4056
+ content: data.config,
4057
+ version,
4058
+ etag,
4059
+ changed: true
4060
+ };
4061
+ }
4062
+
4063
+ // src/commands/run/index.ts
4064
+ init_cache();
3740
4065
 
3741
4066
  // src/commands/run/validators.ts
3742
- import { existsSync as existsSync3 } from "fs";
4067
+ init_asset_resolver();
4068
+ import { existsSync as existsSync5 } from "fs";
3743
4069
 
3744
4070
  // src/schemas/primitives.ts
3745
4071
  import { z as z2 } from "@walkeros/core/dev";
3746
4072
  var PortSchema = z2.number().int("Port must be an integer").min(1, "Port must be at least 1").max(65535, "Port must be at most 65535").describe("HTTP server port number");
3747
4073
  var FilePathSchema = z2.string().min(1, "File path cannot be empty").describe("Path to configuration file");
3748
4074
 
3749
- // src/schemas/run.ts
3750
- import { z as z3 } from "@walkeros/core/dev";
3751
- var RunOptionsSchema = z3.object({
3752
- flow: FilePathSchema,
3753
- port: PortSchema.default(8080),
3754
- flowName: z3.string().optional().describe("Specific flow name to run")
3755
- });
3756
-
3757
- // src/schemas/validate.ts
3758
- import { z as z4 } from "@walkeros/core/dev";
3759
- var ValidationTypeSchema = z4.enum(["contract", "event", "flow", "mapping"]).describe('Validation type: "event", "flow", "mapping", or "contract"');
3760
- var ValidateOptionsSchema = z4.object({
3761
- flow: z4.string().optional().describe("Flow name for multi-flow configs"),
3762
- path: z4.string().optional().describe(
3763
- 'Entry path for package schema validation (e.g., "destinations.snowplow", "sources.browser")'
3764
- )
3765
- });
3766
- var ValidateInputShape = {
3767
- type: ValidationTypeSchema,
3768
- input: z4.string().min(1).describe("JSON string, file path, or URL to validate"),
3769
- flow: z4.string().optional().describe("Flow name for multi-flow configs"),
3770
- path: z4.string().optional().describe(
3771
- 'Entry path for package schema validation (e.g., "destinations.snowplow"). When provided, validates the entry against its package JSON Schema instead of using --type.'
3772
- )
3773
- };
3774
- var ValidateInputSchema = z4.object(ValidateInputShape);
3775
-
3776
- // src/schemas/bundle.ts
3777
- import { z as z5 } from "@walkeros/core/dev";
3778
- var BundleOptionsSchema = z5.object({
3779
- silent: z5.boolean().optional().describe("Suppress all output"),
3780
- verbose: z5.boolean().optional().describe("Enable verbose logging"),
3781
- stats: z5.boolean().optional().default(true).describe("Return bundle statistics"),
3782
- cache: z5.boolean().optional().default(true).describe("Enable package caching"),
3783
- flowName: z5.string().optional().describe("Flow name for multi-flow configs")
3784
- });
3785
- var BundleInputShape = {
3786
- configPath: FilePathSchema.describe(
3787
- "Path to flow configuration file (JSON or JavaScript)"
3788
- ),
3789
- flow: z5.string().optional().describe("Flow name for multi-flow configs"),
3790
- stats: z5.boolean().optional().default(true).describe("Return bundle statistics"),
3791
- output: z5.string().optional().describe("Output file path (defaults to config-defined)")
3792
- };
3793
- var BundleInputSchema = z5.object(BundleInputShape);
3794
-
3795
- // src/schemas/simulate.ts
3796
- import { z as z6 } from "@walkeros/core/dev";
3797
- var PlatformSchema = z6.enum(["web", "server"]).describe("Platform type for event processing");
3798
- var SimulateOptionsSchema = z6.object({
3799
- silent: z6.boolean().optional().describe("Suppress all output"),
3800
- verbose: z6.boolean().optional().describe("Enable verbose logging"),
3801
- json: z6.boolean().optional().describe("Format output as JSON")
3802
- });
3803
- var SimulateInputShape = {
3804
- configPath: FilePathSchema.describe("Path to flow configuration file"),
3805
- event: z6.string().min(1).optional().describe(
3806
- "Event as JSON string, file path, or URL. Optional when example is provided."
3807
- ),
3808
- flow: z6.string().optional().describe("Flow name for multi-flow configs"),
3809
- platform: PlatformSchema.optional().describe("Override platform detection"),
3810
- example: z6.string().optional().describe(
3811
- 'Name of a step example to use as event input (uses its "in" value)'
3812
- ),
3813
- step: z6.string().optional().describe(
3814
- 'Step target in type.name format (e.g. "destination.gtag") to narrow example lookup'
3815
- )
3816
- };
3817
- var SimulateInputSchema = z6.object(SimulateInputShape);
3818
-
3819
- // src/schemas/push.ts
3820
- import { z as z7 } from "@walkeros/core/dev";
3821
- var PushOptionsSchema = z7.object({
3822
- silent: z7.boolean().optional().describe("Suppress all output"),
3823
- verbose: z7.boolean().optional().describe("Enable verbose logging"),
3824
- json: z7.boolean().optional().describe("Format output as JSON")
3825
- });
3826
- var PushInputShape = {
3827
- configPath: FilePathSchema.describe("Path to flow configuration file"),
3828
- event: z7.string().min(1).describe("Event as JSON string, file path, or URL"),
3829
- flow: z7.string().optional().describe("Flow name for multi-flow configs"),
3830
- platform: PlatformSchema.optional().describe("Override platform detection")
3831
- };
3832
- var PushInputSchema = z7.object(PushInputShape);
3833
-
3834
4075
  // src/commands/run/validators.ts
3835
4076
  function validateFlowFile(filePath) {
3836
4077
  const absolutePath = resolveAsset(filePath, "bundle");
3837
- if (!existsSync3(absolutePath)) {
4078
+ if (!existsSync5(absolutePath)) {
3838
4079
  throw new Error(
3839
4080
  `Flow file not found: ${filePath}
3840
4081
  Resolved path: ${absolutePath}
@@ -3854,40 +4095,60 @@ function validatePort(port) {
3854
4095
  }
3855
4096
  }
3856
4097
 
3857
- // src/commands/run/utils.ts
3858
- import path13 from "path";
3859
- import fs14 from "fs-extra";
3860
- async function prepareBundleForRun(configPath, options) {
3861
- const tempDir = getTmpPath(
3862
- void 0,
3863
- `run-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
3864
- );
3865
- await fs14.ensureDir(tempDir);
3866
- const tempPath = path13.join(tempDir, "bundle.mjs");
3867
- await bundle(configPath, {
3868
- cache: true,
3869
- verbose: options.verbose,
3870
- silent: options.silent,
3871
- flowName: options.flowName,
3872
- buildOverrides: {
3873
- output: tempPath,
3874
- format: "esm",
3875
- platform: "node"
3876
- }
4098
+ // src/commands/run/index.ts
4099
+ init_utils3();
4100
+
4101
+ // src/commands/run/pipeline.ts
4102
+ import { writeFileSync as writeFileSync4 } from "fs";
4103
+
4104
+ // src/runtime/health-server.ts
4105
+ import http from "http";
4106
+ function createHealthServer(port, logger) {
4107
+ return new Promise((resolve2, reject) => {
4108
+ let flowHandler = null;
4109
+ const server = http.createServer((req, res) => {
4110
+ if (req.url === "/health" && req.method === "GET") {
4111
+ res.writeHead(200, { "Content-Type": "application/json" });
4112
+ res.end(JSON.stringify({ status: "ok" }));
4113
+ return;
4114
+ }
4115
+ if (req.url === "/ready" && req.method === "GET") {
4116
+ const code = flowHandler ? 200 : 503;
4117
+ res.writeHead(code, { "Content-Type": "application/json" });
4118
+ res.end(
4119
+ JSON.stringify({ status: flowHandler ? "ready" : "not_ready" })
4120
+ );
4121
+ return;
4122
+ }
4123
+ if (flowHandler) {
4124
+ flowHandler(req, res);
4125
+ return;
4126
+ }
4127
+ res.writeHead(503, { "Content-Type": "application/json" });
4128
+ res.end(JSON.stringify({ error: "No flow loaded" }));
4129
+ });
4130
+ server.keepAliveTimeout = 5e3;
4131
+ server.headersTimeout = 1e4;
4132
+ server.listen(port, "0.0.0.0", () => {
4133
+ logger.info(`Health server listening on port ${port}`);
4134
+ resolve2({
4135
+ server,
4136
+ setFlowHandler(handler) {
4137
+ flowHandler = handler;
4138
+ },
4139
+ close: () => new Promise((res, rej) => {
4140
+ server.close((err) => err ? rej(err) : res());
4141
+ })
4142
+ });
4143
+ });
4144
+ server.on("error", reject);
3877
4145
  });
3878
- return tempPath;
3879
- }
3880
- function isPreBuiltConfig(configPath) {
3881
- return configPath.endsWith(".mjs") || configPath.endsWith(".js") || configPath.endsWith(".cjs");
3882
4146
  }
3883
4147
 
3884
- // src/commands/run/execution.ts
3885
- import { createLogger as createLogger2, Level as Level3 } from "@walkeros/core";
3886
-
3887
4148
  // src/runtime/runner.ts
3888
4149
  import { pathToFileURL } from "url";
3889
4150
  import { resolve, dirname } from "path";
3890
- async function loadFlow(file, config, logger2, loggerConfig2, healthServer) {
4151
+ async function loadFlow(file, config, logger, loggerConfig, healthServer) {
3891
4152
  const absolutePath = resolve(file);
3892
4153
  const flowDir = dirname(absolutePath);
3893
4154
  process.chdir(flowDir);
@@ -3900,7 +4161,7 @@ async function loadFlow(file, config, logger2, loggerConfig2, healthServer) {
3900
4161
  }
3901
4162
  const flowContext = {
3902
4163
  ...config,
3903
- ...loggerConfig2 ? { logger: loggerConfig2 } : {},
4164
+ ...loggerConfig ? { logger: loggerConfig } : {},
3904
4165
  ...healthServer ? { externalServer: true } : {}
3905
4166
  };
3906
4167
  const result = await module.default(flowContext);
@@ -3919,73 +4180,389 @@ async function loadFlow(file, config, logger2, loggerConfig2, healthServer) {
3919
4180
  httpHandler: result.httpHandler
3920
4181
  };
3921
4182
  }
3922
- async function runFlow(file, config, logger2, loggerConfig2) {
3923
- logger2.info(`Loading flow from ${file}`);
4183
+ async function swapFlow(currentHandle, newFile, config, logger, loggerConfig, healthServer) {
4184
+ logger.info("Shutting down current flow for hot-swap...");
4185
+ if (healthServer) {
4186
+ healthServer.setFlowHandler(null);
4187
+ }
3924
4188
  try {
3925
- const handle = await loadFlow(file, config, logger2, loggerConfig2);
3926
- logger2.info("Flow running");
3927
- if (config?.port) {
3928
- logger2.info(`Port: ${config.port}`);
3929
- }
3930
- const shutdown = async (signal) => {
3931
- logger2.info(`Received ${signal}, shutting down gracefully...`);
3932
- const forceTimer = setTimeout(() => {
3933
- logger2.error("Shutdown timed out, forcing exit");
3934
- process.exit(1);
3935
- }, 15e3);
3936
- try {
3937
- if (handle.collector.command) {
3938
- await handle.collector.command("shutdown");
3939
- }
3940
- logger2.info("Shutdown complete");
3941
- clearTimeout(forceTimer);
3942
- process.exit(0);
3943
- } catch (error) {
3944
- clearTimeout(forceTimer);
3945
- const message = error instanceof Error ? error.message : String(error);
3946
- logger2.error(`Error during shutdown: ${message}`);
3947
- process.exit(1);
3948
- }
3949
- };
3950
- process.on("SIGTERM", () => shutdown("SIGTERM"));
3951
- process.on("SIGINT", () => shutdown("SIGINT"));
3952
- await new Promise(() => {
3953
- });
4189
+ if (currentHandle.collector.command) {
4190
+ await currentHandle.collector.command("shutdown");
4191
+ }
3954
4192
  } catch (error) {
3955
- const message = error instanceof Error ? error.message : String(error);
3956
- logger2.error(`Failed to run flow: ${message}`);
3957
- if (error instanceof Error && error.stack) {
3958
- logger2.debug("Stack trace:", { stack: error.stack });
4193
+ logger.debug(`Shutdown warning: ${error}`);
4194
+ }
4195
+ const newHandle = await loadFlow(
4196
+ newFile,
4197
+ config,
4198
+ logger,
4199
+ loggerConfig,
4200
+ healthServer
4201
+ );
4202
+ logger.info("Flow swapped successfully");
4203
+ return newHandle;
4204
+ }
4205
+
4206
+ // src/runtime/heartbeat.ts
4207
+ import { randomBytes } from "crypto";
4208
+
4209
+ // src/version.ts
4210
+ import { readFileSync as readFileSync3 } from "fs";
4211
+ import { fileURLToPath as fileURLToPath2 } from "url";
4212
+ import { dirname as dirname2, join as join3 } from "path";
4213
+ var versionFilename = fileURLToPath2(import.meta.url);
4214
+ var versionDirname = dirname2(versionFilename);
4215
+ function findPackageJson() {
4216
+ const paths = [
4217
+ join3(versionDirname, "../package.json"),
4218
+ // dist/ or src/
4219
+ join3(versionDirname, "../../package.json")
4220
+ // src/core/ (not used, but safe)
4221
+ ];
4222
+ for (const p2 of paths) {
4223
+ try {
4224
+ return readFileSync3(p2, "utf-8");
4225
+ } catch {
3959
4226
  }
3960
- throw error;
3961
4227
  }
4228
+ return JSON.stringify({ version: "0.0.0" });
3962
4229
  }
4230
+ var VERSION = JSON.parse(findPackageJson()).version;
3963
4231
 
3964
4232
  // src/runtime/heartbeat.ts
3965
- init_version();
3966
- import { randomBytes } from "crypto";
4233
+ function computeCounterDelta(current, last) {
4234
+ const destinations = {};
4235
+ for (const [name, dest] of Object.entries(current.destinations)) {
4236
+ const prev = last.destinations[name] || {
4237
+ count: 0,
4238
+ failed: 0,
4239
+ duration: 0
4240
+ };
4241
+ destinations[name] = {
4242
+ count: dest.count - prev.count,
4243
+ failed: dest.failed - prev.failed,
4244
+ duration: dest.duration - prev.duration
4245
+ };
4246
+ }
4247
+ return {
4248
+ eventsIn: current.in - last.in,
4249
+ eventsOut: current.out - last.out,
4250
+ eventsFailed: current.failed - last.failed,
4251
+ destinations
4252
+ };
4253
+ }
3967
4254
  var instanceId = randomBytes(8).toString("hex");
4255
+ function getInstanceId() {
4256
+ return instanceId;
4257
+ }
4258
+ function createHeartbeat(config, logger) {
4259
+ let timer = null;
4260
+ const startTime = Date.now();
4261
+ let configVersion = config.configVersion;
4262
+ let lastReported = {
4263
+ in: 0,
4264
+ out: 0,
4265
+ failed: 0,
4266
+ destinations: {}
4267
+ };
4268
+ async function sendOnce() {
4269
+ try {
4270
+ let counters;
4271
+ const status = config.getCounters?.();
4272
+ if (status) {
4273
+ const current = {
4274
+ in: status.in,
4275
+ out: status.out,
4276
+ failed: status.failed,
4277
+ destinations: { ...status.destinations }
4278
+ };
4279
+ counters = computeCounterDelta(current, lastReported);
4280
+ }
4281
+ const response = await fetch(
4282
+ `${config.appUrl}/api/projects/${config.projectId}/runners/heartbeat`,
4283
+ {
4284
+ method: "POST",
4285
+ headers: {
4286
+ Authorization: `Bearer ${config.token}`,
4287
+ "Content-Type": "application/json"
4288
+ },
4289
+ body: JSON.stringify({
4290
+ instanceId,
4291
+ flowId: config.flowId,
4292
+ ...config.deploymentId && {
4293
+ deploymentId: config.deploymentId
4294
+ },
4295
+ configVersion,
4296
+ cliVersion: VERSION,
4297
+ uptime: Math.floor((Date.now() - startTime) / 1e3),
4298
+ ...counters && { counters }
4299
+ }),
4300
+ signal: AbortSignal.timeout(1e4)
4301
+ }
4302
+ );
4303
+ if (response.ok && status) {
4304
+ lastReported = {
4305
+ in: status.in,
4306
+ out: status.out,
4307
+ failed: status.failed,
4308
+ destinations: { ...status.destinations }
4309
+ };
4310
+ }
4311
+ if (response.status === 401 || response.status === 403) {
4312
+ logger.error(
4313
+ `Heartbeat auth failed (${response.status}). Token may have expired \u2014 redeploy to rotate.`
4314
+ );
4315
+ }
4316
+ } catch (error) {
4317
+ const message = error instanceof Error ? error.message : String(error);
4318
+ logger.warn(`Heartbeat failed: ${message}`);
4319
+ }
4320
+ }
4321
+ function start() {
4322
+ sendOnce();
4323
+ const jitter = config.intervalMs * 0.1 * (Math.random() * 2 - 1);
4324
+ timer = setInterval(() => sendOnce(), config.intervalMs + jitter);
4325
+ }
4326
+ function stop() {
4327
+ if (timer) {
4328
+ clearInterval(timer);
4329
+ timer = null;
4330
+ }
4331
+ }
4332
+ function updateConfigVersion(version) {
4333
+ configVersion = version;
4334
+ }
4335
+ return { start, stop, sendOnce, updateConfigVersion };
4336
+ }
4337
+
4338
+ // src/runtime/poller.ts
4339
+ function createPoller(config, logger) {
4340
+ let timer = null;
4341
+ let lastEtag;
4342
+ async function pollOnce() {
4343
+ try {
4344
+ const result = await fetchConfig({
4345
+ ...config.fetchOptions,
4346
+ lastEtag
4347
+ });
4348
+ if (!result.changed) {
4349
+ logger.debug("Config unchanged");
4350
+ return;
4351
+ }
4352
+ logger.info(`New config version: ${result.version}`);
4353
+ lastEtag = result.etag;
4354
+ await config.onUpdate(result.content, result.version);
4355
+ logger.info("Config updated successfully");
4356
+ } catch (error) {
4357
+ const message = error instanceof Error ? error.message : String(error);
4358
+ logger.error(`Poll error: ${message}`);
4359
+ }
4360
+ }
4361
+ function start() {
4362
+ lastEtag = void 0;
4363
+ const jitter = config.intervalMs * 0.15 * (Math.random() * 2 - 1);
4364
+ timer = setInterval(() => pollOnce(), config.intervalMs + jitter);
4365
+ logger.info(
4366
+ `Polling every ${Math.round((config.intervalMs + jitter) / 1e3)}s`
4367
+ );
4368
+ }
4369
+ function stop() {
4370
+ if (timer) {
4371
+ clearInterval(timer);
4372
+ timer = null;
4373
+ }
4374
+ }
4375
+ return { start, stop, pollOnce };
4376
+ }
3968
4377
 
3969
- // src/commands/run/execution.ts
3970
- var logLevel = process.env.VERBOSE === "true" ? Level3.DEBUG : Level3.INFO;
3971
- var loggerConfig = { level: logLevel };
3972
- var logger = createLogger2(loggerConfig);
3973
- async function executeRunLocal(flowPath, options) {
3974
- const config = {
3975
- port: options.port,
3976
- host: options.host
4378
+ // src/runtime/secrets-fetcher.ts
4379
+ var SecretsHttpError = class extends Error {
4380
+ constructor(status, statusText) {
4381
+ super(`Failed to fetch secrets: ${status} ${statusText}`);
4382
+ this.status = status;
4383
+ this.name = "SecretsHttpError";
4384
+ }
4385
+ };
4386
+ async function fetchSecrets(options) {
4387
+ const { appUrl, token, projectId, flowId } = options;
4388
+ const url = `${appUrl}/api/projects/${encodeURIComponent(projectId)}/flows/${encodeURIComponent(flowId)}/secrets/values`;
4389
+ const res = await fetch(url, {
4390
+ headers: {
4391
+ Authorization: `Bearer ${token}`,
4392
+ "Content-Type": "application/json"
4393
+ }
4394
+ });
4395
+ if (!res.ok) {
4396
+ throw new SecretsHttpError(res.status, res.statusText);
4397
+ }
4398
+ const json = await res.json();
4399
+ return json.values;
4400
+ }
4401
+
4402
+ // src/commands/run/pipeline.ts
4403
+ init_cache();
4404
+ async function runPipeline(options) {
4405
+ const { bundlePath, port, logger, loggerConfig, api } = options;
4406
+ let configVersion;
4407
+ if (api) {
4408
+ await injectSecrets(api, logger);
4409
+ }
4410
+ logger.info(`walkeros/flow v${VERSION}`);
4411
+ logger.info(`Instance: ${getInstanceId()}`);
4412
+ const healthServer = await createHealthServer(port, logger);
4413
+ const runtimeConfig = { port };
4414
+ let handle;
4415
+ try {
4416
+ handle = await loadFlow(
4417
+ bundlePath,
4418
+ runtimeConfig,
4419
+ logger,
4420
+ loggerConfig,
4421
+ healthServer
4422
+ );
4423
+ } catch (error) {
4424
+ await healthServer.close();
4425
+ throw error;
4426
+ }
4427
+ logger.info("Flow running");
4428
+ logger.info(`Port: ${port}`);
4429
+ let heartbeat = null;
4430
+ let poller = null;
4431
+ if (api) {
4432
+ heartbeat = createHeartbeat(
4433
+ {
4434
+ appUrl: api.appUrl,
4435
+ token: api.token,
4436
+ projectId: api.projectId,
4437
+ flowId: api.flowId,
4438
+ configVersion,
4439
+ intervalMs: api.heartbeatIntervalMs,
4440
+ getCounters: () => handle.collector.status
4441
+ },
4442
+ logger
4443
+ );
4444
+ heartbeat.start();
4445
+ logger.info(`Heartbeat: active (every ${api.heartbeatIntervalMs / 1e3}s)`);
4446
+ poller = createPoller(
4447
+ {
4448
+ fetchOptions: {
4449
+ appUrl: api.appUrl,
4450
+ token: api.token,
4451
+ projectId: api.projectId,
4452
+ flowId: api.flowId
4453
+ },
4454
+ intervalMs: api.pollIntervalMs,
4455
+ onUpdate: async (content, version) => {
4456
+ try {
4457
+ await injectSecrets(api, logger);
4458
+ } catch (error) {
4459
+ logger.error(
4460
+ `Failed to refresh secrets during poll, skipping hot-swap: ${error instanceof Error ? error.message : error}`
4461
+ );
4462
+ return;
4463
+ }
4464
+ const tmpConfigPath = `/tmp/walkeros-flow-${Date.now()}.json`;
4465
+ writeFileSync4(
4466
+ tmpConfigPath,
4467
+ JSON.stringify(content, null, 2),
4468
+ "utf-8"
4469
+ );
4470
+ const newBundle = await api.prepareBundleForRun(tmpConfigPath, {
4471
+ verbose: false,
4472
+ silent: true,
4473
+ flowName: api.flowName
4474
+ });
4475
+ handle = await swapFlow(
4476
+ handle,
4477
+ newBundle,
4478
+ runtimeConfig,
4479
+ logger,
4480
+ loggerConfig,
4481
+ healthServer
4482
+ );
4483
+ writeCache(api.cacheDir, newBundle, JSON.stringify(content), version);
4484
+ configVersion = version;
4485
+ if (heartbeat) heartbeat.updateConfigVersion(version);
4486
+ logger.info(`Hot-swapped to version ${version}`);
4487
+ }
4488
+ },
4489
+ logger
4490
+ );
4491
+ poller.start();
4492
+ logger.info(`Polling: active (every ${api.pollIntervalMs / 1e3}s)`);
4493
+ }
4494
+ const shutdown = async (signal) => {
4495
+ logger.info(`Received ${signal}, shutting down...`);
4496
+ const forceTimer = setTimeout(() => {
4497
+ logger.error("Shutdown timed out, forcing exit");
4498
+ process.exit(1);
4499
+ }, 15e3);
4500
+ try {
4501
+ if (poller) poller.stop();
4502
+ if (heartbeat) heartbeat.stop();
4503
+ if (handle.collector.command) {
4504
+ await handle.collector.command("shutdown");
4505
+ }
4506
+ await healthServer.close();
4507
+ logger.info("Shutdown complete");
4508
+ clearTimeout(forceTimer);
4509
+ process.exit(0);
4510
+ } catch (error) {
4511
+ clearTimeout(forceTimer);
4512
+ logger.error(
4513
+ `Error during shutdown: ${error instanceof Error ? error.message : String(error)}`
4514
+ );
4515
+ process.exit(1);
4516
+ }
3977
4517
  };
3978
- await runFlow(flowPath, config, logger.scope("runner"), loggerConfig);
4518
+ process.on("SIGTERM", () => shutdown("SIGTERM"));
4519
+ process.on("SIGINT", () => shutdown("SIGINT"));
4520
+ await new Promise(() => {
4521
+ });
4522
+ }
4523
+ async function injectSecrets(api, logger) {
4524
+ try {
4525
+ const secrets = await fetchSecrets({
4526
+ appUrl: api.appUrl,
4527
+ token: api.token,
4528
+ projectId: api.projectId,
4529
+ flowId: api.flowId
4530
+ });
4531
+ const count = Object.keys(secrets).length;
4532
+ if (count > 0) {
4533
+ for (const [name, value] of Object.entries(secrets)) {
4534
+ process.env[name] = value;
4535
+ }
4536
+ logger.info(`Injected ${count} secret(s) into environment`);
4537
+ }
4538
+ } catch (error) {
4539
+ if (error instanceof SecretsHttpError && (error.status === 401 || error.status === 403)) {
4540
+ throw error;
4541
+ }
4542
+ logger.warn(
4543
+ `Could not fetch secrets: ${error instanceof Error ? error.message : error}`
4544
+ );
4545
+ logger.info("Continuing without secrets (flow may not require them)");
4546
+ }
3979
4547
  }
3980
4548
 
3981
4549
  // src/commands/run/index.ts
3982
4550
  var esmRequire = createRequire(import.meta.url);
4551
+ function defaultCacheDir() {
4552
+ const xdgCache = process.env.XDG_CACHE_HOME;
4553
+ const base = xdgCache || join4(homedir2(), ".cache");
4554
+ return join4(base, "walkeros");
4555
+ }
4556
+ async function lazyPrepareBundleForRun(configPath, options) {
4557
+ const { prepareBundleForRun: prepareBundleForRun2 } = await Promise.resolve().then(() => (init_utils3(), utils_exports));
4558
+ return prepareBundleForRun2(configPath, options);
4559
+ }
3983
4560
  async function runCommand(options) {
3984
4561
  const timer = createTimer();
3985
4562
  timer.start();
3986
- const logger2 = createCLILogger(options);
4563
+ const logger = createCLILogger(options);
3987
4564
  try {
3988
- const configPath = validateFlowFile(options.config);
4565
+ const port = options.port ?? 8080;
3989
4566
  if (options.port !== void 0) {
3990
4567
  validatePort(options.port);
3991
4568
  }
@@ -3994,7 +4571,7 @@ async function runCommand(options) {
3994
4571
  try {
3995
4572
  esmRequire.resolve(dep);
3996
4573
  } catch {
3997
- logger2.error(
4574
+ logger.error(
3998
4575
  `Missing runtime dependency "${dep}"
3999
4576
  Server flows require express and cors when running outside Docker.
4000
4577
  Run: npm install express cors`
@@ -4002,84 +4579,167 @@ Run: npm install express cors`
4002
4579
  process.exit(1);
4003
4580
  }
4004
4581
  }
4005
- const isPreBuilt = isPreBuiltConfig(configPath);
4006
- let flowPath;
4007
- if (isPreBuilt) {
4008
- flowPath = path14.resolve(configPath);
4009
- logger2.debug(`Using pre-built flow: ${path14.basename(flowPath)}`);
4010
- } else {
4011
- logger2.debug("Building flow bundle");
4012
- flowPath = await prepareBundleForRun(configPath, {
4013
- verbose: options.verbose,
4014
- silent: options.json || options.silent
4015
- });
4016
- logger2.debug("Bundle ready");
4017
- }
4018
- if (options.deployment) {
4019
- const { startHeartbeat: startHeartbeat2 } = await Promise.resolve().then(() => (init_heartbeat(), heartbeat_exports));
4020
- await startHeartbeat2({
4021
- deployment: options.deployment,
4022
- projectId: options.project,
4023
- url: options.url || `http://localhost:${options.port || 8080}`,
4024
- healthEndpoint: options.healthEndpoint,
4025
- heartbeatInterval: options.heartbeatInterval
4026
- });
4582
+ const flowId = options.flowId;
4583
+ const projectId = options.project;
4584
+ const token = resolveRunToken();
4585
+ const appUrl = resolveAppUrl();
4586
+ const flowName = options.flow;
4587
+ let apiConfig;
4588
+ if (flowId) {
4589
+ if (!token) {
4590
+ logger.error(
4591
+ `Remote flow requires authentication.
4592
+
4593
+ No token found. Authenticate first:
4594
+ $ walkeros auth login
4595
+
4596
+ Or set WALKEROS_TOKEN:
4597
+ $ export WALKEROS_TOKEN=<your-token>`
4598
+ );
4599
+ process.exit(1);
4600
+ }
4601
+ if (!projectId) {
4602
+ logger.error(
4603
+ `--flow-id requires --project or WALKEROS_PROJECT_ID.
4604
+
4605
+ Set the project:
4606
+ $ walkeros run --flow-id ${flowId} --project <your-project-id>
4607
+ $ export WALKEROS_PROJECT_ID=<your-project-id>`
4608
+ );
4609
+ process.exit(1);
4610
+ }
4611
+ apiConfig = {
4612
+ appUrl,
4613
+ token,
4614
+ projectId,
4615
+ flowId,
4616
+ heartbeatIntervalMs: parseInt(
4617
+ process.env.WALKEROS_HEARTBEAT_INTERVAL ?? process.env.HEARTBEAT_INTERVAL ?? "60",
4618
+ 10
4619
+ ) * 1e3,
4620
+ pollIntervalMs: parseInt(
4621
+ process.env.WALKEROS_POLL_INTERVAL ?? process.env.POLL_INTERVAL ?? "30",
4622
+ 10
4623
+ ) * 1e3,
4624
+ cacheDir: process.env.WALKEROS_CACHE_DIR ?? process.env.CACHE_DIR ?? defaultCacheDir(),
4625
+ flowName,
4626
+ prepareBundleForRun: lazyPrepareBundleForRun
4627
+ };
4027
4628
  }
4028
- logger2.info("Starting flow...");
4029
- await executeRunLocal(flowPath, {
4030
- port: options.port,
4031
- host: options.host
4629
+ const bundlePath = await resolveBundlePath(
4630
+ options.config,
4631
+ apiConfig,
4632
+ logger
4633
+ );
4634
+ logger.info("Starting flow...");
4635
+ await runPipeline({
4636
+ bundlePath,
4637
+ port,
4638
+ logger: logger.scope("runner"),
4639
+ loggerConfig: options.verbose ? { level: 0 } : void 0,
4640
+ api: apiConfig
4032
4641
  });
4033
4642
  } catch (error) {
4034
4643
  const duration = timer.getElapsed() / 1e3;
4035
4644
  const errorMessage = getErrorMessage(error);
4036
4645
  if (options.json) {
4037
- logger2.json({
4646
+ logger.json({
4038
4647
  success: false,
4039
4648
  error: errorMessage,
4040
4649
  duration
4041
4650
  });
4042
4651
  } else {
4043
- logger2.error(`Error: ${errorMessage}`);
4652
+ logger.error(`Error: ${errorMessage}`);
4044
4653
  }
4045
4654
  process.exit(1);
4046
4655
  }
4047
4656
  }
4048
- async function run(options) {
4049
- const startTime = Date.now();
4050
- try {
4051
- let flowFile;
4052
- if (typeof options.config === "string") {
4053
- flowFile = validateFlowFile(options.config);
4657
+ async function resolveBundlePath(configInput, apiConfig, logger) {
4658
+ if (configInput) {
4659
+ const resolved = await resolveBundle(configInput);
4660
+ if (resolved.source === "stdin") {
4661
+ logger.info("Bundle: received via stdin");
4662
+ } else if (resolved.source === "url") {
4663
+ logger.info("Bundle: fetched from URL");
4054
4664
  } else {
4055
- throw new Error("Programmatic run() requires config file path");
4665
+ logger.info(`Bundle: ${resolved.path}`);
4056
4666
  }
4057
- if (options.port !== void 0) {
4058
- validatePort(options.port);
4667
+ if (isPreBuiltConfig(resolved.path)) {
4668
+ return path14.resolve(resolved.path);
4059
4669
  }
4060
- const runtimeDeps = ["express", "cors"];
4061
- for (const dep of runtimeDeps) {
4062
- try {
4063
- esmRequire.resolve(dep);
4064
- } catch {
4065
- throw new Error(
4066
- `Missing runtime dependency "${dep}". Server flows require express and cors when running outside Docker. Run: npm install express cors`
4670
+ const flowFile = validateFlowFile(resolved.path);
4671
+ logger.debug("Building flow bundle");
4672
+ return lazyPrepareBundleForRun(flowFile, {
4673
+ verbose: false,
4674
+ silent: true,
4675
+ flowName: apiConfig?.flowName
4676
+ });
4677
+ }
4678
+ if (apiConfig) {
4679
+ logger.info("Fetching config from API...");
4680
+ try {
4681
+ const result = await fetchConfig({
4682
+ appUrl: apiConfig.appUrl,
4683
+ token: apiConfig.token,
4684
+ projectId: apiConfig.projectId,
4685
+ flowId: apiConfig.flowId
4686
+ });
4687
+ if (result.changed) {
4688
+ const tmpConfigPath = `/tmp/walkeros-flow-${Date.now()}.json`;
4689
+ writeFileSync5(
4690
+ tmpConfigPath,
4691
+ JSON.stringify(result.content, null, 2),
4692
+ "utf-8"
4067
4693
  );
4694
+ logger.info(`Config version: ${result.version}`);
4695
+ logger.info("Building flow...");
4696
+ const bundlePath = await lazyPrepareBundleForRun(tmpConfigPath, {
4697
+ verbose: false,
4698
+ silent: true,
4699
+ flowName: apiConfig.flowName
4700
+ });
4701
+ try {
4702
+ const { writeCache: writeCache2 } = await Promise.resolve().then(() => (init_cache(), cache_exports));
4703
+ writeCache2(
4704
+ apiConfig.cacheDir,
4705
+ bundlePath,
4706
+ JSON.stringify(result.content),
4707
+ result.version
4708
+ );
4709
+ } catch {
4710
+ logger.debug("Cache write failed (non-critical)");
4711
+ }
4712
+ return bundlePath;
4068
4713
  }
4714
+ } catch (error) {
4715
+ logger.error(
4716
+ `API fetch failed: ${error instanceof Error ? error.message : error}`
4717
+ );
4718
+ const cached = readCache(apiConfig.cacheDir);
4719
+ if (cached) {
4720
+ logger.info(`Using cached bundle (version: ${cached.version})`);
4721
+ return cached.bundlePath;
4722
+ }
4723
+ throw new Error(
4724
+ "No config available. API fetch failed and no cached bundle."
4725
+ );
4069
4726
  }
4070
- const isPreBuilt = isPreBuiltConfig(flowFile);
4071
- let flowPath;
4072
- if (isPreBuilt) {
4073
- flowPath = path14.resolve(flowFile);
4074
- } else {
4075
- flowPath = await prepareBundleForRun(flowFile, {
4076
- verbose: options.verbose,
4077
- silent: true
4078
- });
4079
- }
4080
- await executeRunLocal(flowPath, {
4727
+ }
4728
+ const defaultFile = "server-collect.mjs";
4729
+ logger.debug(`No config specified, using default: ${defaultFile}`);
4730
+ return path14.resolve(defaultFile);
4731
+ }
4732
+ async function run(options) {
4733
+ const startTime = Date.now();
4734
+ try {
4735
+ await runCommand({
4736
+ config: options.config,
4081
4737
  port: options.port,
4082
- host: options.host
4738
+ flow: options.flow,
4739
+ flowId: options.flowId,
4740
+ project: options.project,
4741
+ verbose: options.verbose,
4742
+ silent: options.silent ?? true
4083
4743
  });
4084
4744
  return {
4085
4745
  success: true,
@@ -4098,6 +4758,8 @@ async function run(options) {
4098
4758
 
4099
4759
  // src/commands/validate/index.ts
4100
4760
  init_cli_logger();
4761
+ init_core();
4762
+ init_config();
4101
4763
  import chalk2 from "chalk";
4102
4764
 
4103
4765
  // src/commands/validate/validators/contract.ts
@@ -4255,7 +4917,7 @@ function validateEvent(input) {
4255
4917
 
4256
4918
  // src/commands/validate/validators/flow.ts
4257
4919
  import { schemas as schemas4 } from "@walkeros/core/dev";
4258
- var { validateFlowSetup: validateFlowSetup2 } = schemas4;
4920
+ var { validateFlowConfig: validateFlowConfig3 } = schemas4;
4259
4921
  function validateFlow(input, options = {}) {
4260
4922
  const errors = [];
4261
4923
  const warnings = [];
@@ -4271,7 +4933,7 @@ function validateFlow(input, options = {}) {
4271
4933
  });
4272
4934
  return { valid: false, type: "flow", errors, warnings, details };
4273
4935
  }
4274
- const coreResult = validateFlowSetup2(json);
4936
+ const coreResult = validateFlowConfig3(json);
4275
4937
  for (const issue of coreResult.errors) {
4276
4938
  errors.push({
4277
4939
  path: issue.path || "root",
@@ -4331,20 +4993,20 @@ function validateFlow(input, options = {}) {
4331
4993
  const flowsToCheck = options.flow ? [options.flow] : flowNames;
4332
4994
  let totalConnections = 0;
4333
4995
  for (const name of flowsToCheck) {
4334
- const flowConfig = flows[name];
4335
- if (!flowConfig) continue;
4336
- checkExampleCoverage(flowConfig, warnings);
4337
- const connections = buildConnectionGraph(flowConfig);
4996
+ const flowSettings = flows[name];
4997
+ if (!flowSettings) continue;
4998
+ checkExampleCoverage(flowSettings, warnings);
4999
+ const connections = buildConnectionGraph(flowSettings);
4338
5000
  for (const conn of connections) {
4339
5001
  checkCompatibility(conn, errors, warnings);
4340
5002
  }
4341
5003
  totalConnections += connections.length;
4342
5004
  const setupContract = config.contract;
4343
- if (setupContract || flowConfig.contract) {
5005
+ if (setupContract || flowSettings.contract) {
4344
5006
  checkContractCompliance(
4345
- flowConfig,
5007
+ flowSettings,
4346
5008
  setupContract,
4347
- flowConfig.contract,
5009
+ flowSettings.contract,
4348
5010
  warnings
4349
5011
  );
4350
5012
  }
@@ -4747,7 +5409,7 @@ function formatResult(result, options) {
4747
5409
  return lines.join("\n");
4748
5410
  }
4749
5411
  async function validateCommand(options) {
4750
- const logger2 = createCLILogger({ ...options, stderr: true });
5412
+ const logger = createCLILogger({ ...options, stderr: true });
4751
5413
  try {
4752
5414
  let input;
4753
5415
  if (isStdinPiped() && !options.input) {
@@ -4794,7 +5456,7 @@ async function validateCommand(options) {
4794
5456
  );
4795
5457
  await writeResult(errorOutput + "\n", { output: options.output });
4796
5458
  } else {
4797
- logger2.error(`Error: ${errorMessage}`);
5459
+ logger.error(`Error: ${errorMessage}`);
4798
5460
  }
4799
5461
  process.exit(3);
4800
5462
  }
@@ -4810,22 +5472,22 @@ async function openInBrowser(url) {
4810
5472
  await open(url);
4811
5473
  }
4812
5474
  async function loginCommand(options) {
4813
- const logger2 = createCLILogger(options);
5475
+ const logger = createCLILogger(options);
4814
5476
  try {
4815
5477
  const result = await login({ url: options.url });
4816
5478
  if (options.json) {
4817
- logger2.json(result);
5479
+ logger.json(result);
4818
5480
  } else if (result.success) {
4819
- logger2.info(`Logged in as ${result.email}`);
4820
- logger2.info(`Token stored in ${result.configPath}`);
5481
+ logger.info(`Logged in as ${result.email}`);
5482
+ logger.info(`Token stored in ${result.configPath}`);
4821
5483
  }
4822
5484
  process.exit(result.success ? 0 : 1);
4823
5485
  } catch (error) {
4824
5486
  const message = error instanceof Error ? error.message : String(error);
4825
5487
  if (options.json) {
4826
- logger2.json({ success: false, error: message });
5488
+ logger.json({ success: false, error: message });
4827
5489
  } else {
4828
- logger2.error(message);
5490
+ logger.error(message);
4829
5491
  }
4830
5492
  process.exit(1);
4831
5493
  }
@@ -4897,21 +5559,23 @@ async function login(options = {}) {
4897
5559
  init_cli_logger();
4898
5560
  init_config_file();
4899
5561
  async function logoutCommand(options) {
4900
- const logger2 = createCLILogger(options);
5562
+ const logger = createCLILogger(options);
4901
5563
  const deleted = deleteConfig();
4902
5564
  const configPath = getConfigPath();
4903
5565
  if (options.json) {
4904
- logger2.json({ success: true, deleted });
5566
+ logger.json({ success: true, deleted });
4905
5567
  } else if (deleted) {
4906
- logger2.info(`Logged out. Token removed from ${configPath}`);
5568
+ logger.info(`Logged out. Token removed from ${configPath}`);
4907
5569
  } else {
4908
- logger2.info("No stored credentials found.");
5570
+ logger.info("No stored credentials found.");
4909
5571
  }
4910
5572
  process.exit(0);
4911
5573
  }
4912
5574
 
4913
5575
  // src/commands/auth/index.ts
5576
+ init_api_client();
4914
5577
  init_cli_logger();
5578
+ init_output();
4915
5579
  async function whoami() {
4916
5580
  const client = createApiClient();
4917
5581
  const { data, error } = await client.GET("/api/auth/whoami");
@@ -4919,26 +5583,28 @@ async function whoami() {
4919
5583
  return data;
4920
5584
  }
4921
5585
  async function whoamiCommand(options) {
4922
- const logger2 = createCLILogger(options);
5586
+ const logger = createCLILogger(options);
4923
5587
  try {
4924
5588
  const result = await whoami();
4925
5589
  if (options.json) {
4926
5590
  await writeResult(JSON.stringify(result, null, 2), options);
4927
5591
  } else {
4928
5592
  const data = result;
4929
- if (data.email) logger2.info(`${data.email}`);
4930
- if (data.userId) logger2.info(`User: ${data.userId}`);
4931
- if (data.projectId) logger2.info(`Project: ${data.projectId}`);
5593
+ if (data.email) logger.info(`${data.email}`);
5594
+ if (data.userId) logger.info(`User: ${data.userId}`);
5595
+ if (data.projectId) logger.info(`Project: ${data.projectId}`);
4932
5596
  }
4933
5597
  } catch (error) {
4934
- logger2.error(error instanceof Error ? error.message : String(error));
5598
+ logger.error(error instanceof Error ? error.message : String(error));
4935
5599
  process.exit(1);
4936
5600
  }
4937
5601
  }
4938
5602
 
4939
5603
  // src/commands/projects/index.ts
5604
+ init_api_client();
4940
5605
  init_auth();
4941
5606
  init_cli_logger();
5607
+ init_output();
4942
5608
  async function listProjects() {
4943
5609
  const client = createApiClient();
4944
5610
  const { data, error } = await client.GET("/api/projects");
@@ -4985,12 +5651,12 @@ async function deleteProject(options = {}) {
4985
5651
  return data ?? { success: true };
4986
5652
  }
4987
5653
  async function handleResult(fn2, options) {
4988
- const logger2 = createCLILogger(options);
5654
+ const logger = createCLILogger(options);
4989
5655
  try {
4990
5656
  const result = await fn2();
4991
5657
  await writeResult(JSON.stringify(result, null, 2), options);
4992
5658
  } catch (error) {
4993
- logger2.error(error instanceof Error ? error.message : String(error));
5659
+ logger.error(error instanceof Error ? error.message : String(error));
4994
5660
  process.exit(1);
4995
5661
  }
4996
5662
  }
@@ -5027,8 +5693,11 @@ async function deleteProjectCommand(projectId, options) {
5027
5693
  }
5028
5694
 
5029
5695
  // src/commands/flows/index.ts
5696
+ init_api_client();
5030
5697
  init_auth();
5031
5698
  init_cli_logger();
5699
+ init_output();
5700
+ init_stdin();
5032
5701
  async function listFlows(options = {}) {
5033
5702
  const id = options.projectId ?? requireProjectId();
5034
5703
  const client = createApiClient();
@@ -5065,8 +5734,8 @@ async function createFlow(options) {
5065
5734
  const client = createApiClient();
5066
5735
  const { data, error } = await client.POST("/api/projects/{projectId}/flows", {
5067
5736
  params: { path: { projectId: id } },
5068
- // Content is user-provided JSON; server validates the full schema
5069
- body: { name: options.name, content: options.content }
5737
+ // Config is user-provided JSON; server validates the full schema
5738
+ body: { name: options.name, config: options.content }
5070
5739
  });
5071
5740
  if (error) throw new Error(error.error?.message || "Failed to create flow");
5072
5741
  return data;
@@ -5076,7 +5745,7 @@ async function updateFlow(options) {
5076
5745
  const client = createApiClient();
5077
5746
  const body = {};
5078
5747
  if (options.name !== void 0) body.name = options.name;
5079
- if (options.content !== void 0) body.content = options.content;
5748
+ if (options.content !== void 0) body.config = options.content;
5080
5749
  const { data, error } = await client.PATCH(
5081
5750
  "/api/projects/{projectId}/flows/{flowId}",
5082
5751
  {
@@ -5118,12 +5787,12 @@ async function duplicateFlow(options) {
5118
5787
  return data;
5119
5788
  }
5120
5789
  async function handleResult2(fn2, options) {
5121
- const logger2 = createCLILogger(options);
5790
+ const logger = createCLILogger(options);
5122
5791
  try {
5123
5792
  const result = await fn2();
5124
5793
  await writeResult(JSON.stringify(result, null, 2), options);
5125
5794
  } catch (error) {
5126
- logger2.error(error instanceof Error ? error.message : String(error));
5795
+ logger.error(error instanceof Error ? error.message : String(error));
5127
5796
  process.exit(1);
5128
5797
  }
5129
5798
  }
@@ -5183,21 +5852,24 @@ async function readFlowStdin() {
5183
5852
  }
5184
5853
 
5185
5854
  // src/commands/deploy/index.ts
5855
+ init_api_client();
5186
5856
  init_auth();
5857
+ init_sse();
5187
5858
  init_cli_logger();
5188
- async function resolveConfigId(options) {
5859
+ init_output();
5860
+ async function resolveSettingsId(options) {
5189
5861
  const flow = await getFlow({
5190
5862
  flowId: options.flowId,
5191
5863
  projectId: options.projectId
5192
5864
  });
5193
- const configs = flow.configs;
5194
- if (!configs?.length) {
5195
- throw new Error("Flow has no configs.");
5865
+ const settings = flow.settings;
5866
+ if (!settings?.length) {
5867
+ throw new Error("Flow has no settings.");
5196
5868
  }
5197
- const match = configs.find((c2) => c2.name === options.flowName);
5869
+ const match = settings.find((c2) => c2.name === options.flowName);
5198
5870
  if (!match) {
5199
5871
  throw new Error(
5200
- `Flow "${options.flowName}" not found. Available: ${configs.map((c2) => c2.name).join(", ")}`
5872
+ `Flow "${options.flowName}" not found. Available: ${settings.map((c2) => c2.name).join(", ")}`
5201
5873
  );
5202
5874
  }
5203
5875
  return match.id;
@@ -5207,8 +5879,8 @@ async function getAvailableFlowNames(options) {
5207
5879
  flowId: options.flowId,
5208
5880
  projectId: options.projectId
5209
5881
  });
5210
- const configs = flow.configs;
5211
- return configs?.map((c2) => c2.name) ?? [];
5882
+ const settings = flow.settings;
5883
+ return settings?.map((c2) => c2.name) ?? [];
5212
5884
  }
5213
5885
  async function streamDeploymentStatus(projectId, deploymentId, options) {
5214
5886
  const base = resolveBaseUrl();
@@ -5255,15 +5927,15 @@ async function deploy(options) {
5255
5927
  const projectId = options.projectId ?? requireProjectId();
5256
5928
  const client = createApiClient();
5257
5929
  if (options.flowName) {
5258
- const configId = await resolveConfigId({
5930
+ const settingsId = await resolveSettingsId({
5259
5931
  flowId: options.flowId,
5260
5932
  projectId,
5261
5933
  flowName: options.flowName
5262
5934
  });
5263
- return deployConfig({
5935
+ return deploySettings({
5264
5936
  ...options,
5265
5937
  projectId,
5266
- configId,
5938
+ settingsId,
5267
5939
  timeout: options.timeout,
5268
5940
  signal: options.signal,
5269
5941
  onStatus: options.onStatus
@@ -5282,7 +5954,7 @@ async function deploy(options) {
5282
5954
  projectId
5283
5955
  });
5284
5956
  throw new Error(
5285
- `This flow has multiple configs. Use --flow <name> to specify one.
5957
+ `This flow has multiple settings. Use --flow <name> to specify one.
5286
5958
  Available: ${names.join(", ")}`
5287
5959
  );
5288
5960
  }
@@ -5296,11 +5968,11 @@ Available: ${names.join(", ")}`
5296
5968
  });
5297
5969
  return { ...data, ...result };
5298
5970
  }
5299
- async function deployConfig(options) {
5300
- const { flowId, projectId, configId } = options;
5971
+ async function deploySettings(options) {
5972
+ const { flowId, projectId, settingsId } = options;
5301
5973
  const base = resolveBaseUrl();
5302
5974
  const response = await authenticatedFetch(
5303
- `${base}/api/projects/${projectId}/flows/${flowId}/configs/${configId}/deploy`,
5975
+ `${base}/api/projects/${projectId}/flows/${flowId}/settings/${settingsId}/deploy`,
5304
5976
  { method: "POST" }
5305
5977
  );
5306
5978
  if (!response.ok) {
@@ -5321,14 +5993,14 @@ async function deployConfig(options) {
5321
5993
  async function getDeployment(options) {
5322
5994
  const projectId = options.projectId ?? requireProjectId();
5323
5995
  if (options.flowName) {
5324
- const configId = await resolveConfigId({
5996
+ const settingsId = await resolveSettingsId({
5325
5997
  flowId: options.flowId,
5326
5998
  projectId,
5327
5999
  flowName: options.flowName
5328
6000
  });
5329
6001
  const base = resolveBaseUrl();
5330
6002
  const response = await authenticatedFetch(
5331
- `${base}/api/projects/${projectId}/flows/${options.flowId}/configs/${configId}/deploy`
6003
+ `${base}/api/projects/${projectId}/flows/${options.flowId}/settings/${settingsId}/deploy`
5332
6004
  );
5333
6005
  if (!response.ok) {
5334
6006
  const body = await response.json().catch(() => ({}));
@@ -5427,6 +6099,8 @@ async function getDeploymentCommand(flowId, options) {
5427
6099
  // src/commands/deployments/index.ts
5428
6100
  init_auth();
5429
6101
  init_cli_logger();
6102
+ init_output();
6103
+ init_loader();
5430
6104
  import { getPlatform as getPlatform4 } from "@walkeros/core";
5431
6105
  async function listDeployments(options = {}) {
5432
6106
  const id = options.projectId ?? requireProjectId();
@@ -5496,12 +6170,12 @@ async function deleteDeployment(options) {
5496
6170
  return data ?? { success: true };
5497
6171
  }
5498
6172
  async function handleResult3(fn2, options) {
5499
- const logger2 = createCLILogger(options);
6173
+ const logger = createCLILogger(options);
5500
6174
  try {
5501
6175
  const result = await fn2();
5502
6176
  await writeResult(JSON.stringify(result, null, 2), options);
5503
6177
  } catch (error) {
5504
- logger2.error(error instanceof Error ? error.message : String(error));
6178
+ logger.error(error instanceof Error ? error.message : String(error));
5505
6179
  process.exit(1);
5506
6180
  }
5507
6181
  }
@@ -5561,23 +6235,23 @@ async function createDeployCommand(config, options) {
5561
6235
  );
5562
6236
  }
5563
6237
  const flow = await resp.json();
5564
- if (!flow.content) throw new Error("Flow has no content");
5565
- const content = flow.content;
5566
- const flows = content.flows;
5567
- if (!flows) throw new Error("Invalid flow content: missing flows");
6238
+ if (!flow.config) throw new Error("Flow has no config");
6239
+ const flowConfig = flow.config;
6240
+ const flows = flowConfig.flows;
6241
+ if (!flows) throw new Error("Invalid flow config: missing flows");
5568
6242
  const flowName = options.flow ?? Object.keys(flows)[0];
5569
6243
  if (!flowName) throw new Error("No flows found in config");
5570
- const flowConfig = flows[flowName];
5571
- if (!flowConfig || typeof flowConfig !== "object")
6244
+ const flowSettings = flows[flowName];
6245
+ if (!flowSettings || typeof flowSettings !== "object")
5572
6246
  throw new Error("Invalid flow config");
5573
- if ("web" in flowConfig) type = "web";
5574
- else if ("server" in flowConfig) type = "server";
6247
+ if ("web" in flowSettings) type = "web";
6248
+ else if ("server" in flowSettings) type = "server";
5575
6249
  else throw new Error('Flow must have "web" or "server" key');
5576
6250
  } else {
5577
6251
  const result2 = await loadFlowConfig(config, {
5578
6252
  flowName: options.flow
5579
6253
  });
5580
- type = getPlatform4(result2.flowConfig);
6254
+ type = getPlatform4(result2.flowSettings);
5581
6255
  }
5582
6256
  const deployment = await createDeployment({
5583
6257
  type,
@@ -5617,7 +6291,11 @@ async function createDeployCommand(config, options) {
5617
6291
  }
5618
6292
 
5619
6293
  // src/index.ts
6294
+ init_bundle();
5620
6295
  init_auth();
6296
+ init_api_client();
6297
+ init_sse();
6298
+ init_utils();
5621
6299
  export {
5622
6300
  bundle,
5623
6301
  bundleCommand,