@walkeros/cli 2.1.1 → 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
@@ -1,11 +1,5 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __getOwnPropNames = Object.getOwnPropertyNames;
3
- var __require = /* @__PURE__ */ ((x2) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x2, {
4
- get: (a2, b2) => (typeof require !== "undefined" ? require : a2)[b2]
5
- }) : x2)(function(x2) {
6
- if (typeof require !== "undefined") return require.apply(this, arguments);
7
- throw Error('Dynamic require of "' + x2 + '" is not supported');
8
- });
9
3
  var __esm = (fn2, res) => function __init() {
10
4
  return fn2 && (res = (0, fn2[__getOwnPropNames(fn2)[0]])(fn2 = 0)), res;
11
5
  };
@@ -54,6 +48,87 @@ var init_cli_logger = __esm({
54
48
  }
55
49
  });
56
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
+
57
132
  // src/lib/config-file.ts
58
133
  import {
59
134
  readFileSync,
@@ -149,6 +224,9 @@ async function deployAuthenticatedFetch(url, init) {
149
224
  headers: { ...existingHeaders, Authorization: `Bearer ${token}` }
150
225
  });
151
226
  }
227
+ function resolveRunToken() {
228
+ return resolveDeployToken() ?? resolveToken()?.token ?? null;
229
+ }
152
230
  function resolveBaseUrl() {
153
231
  return resolveAppUrl();
154
232
  }
@@ -164,220 +242,10 @@ var init_auth = __esm({
164
242
  }
165
243
  });
166
244
 
167
- // src/version.ts
168
- import { readFileSync as readFileSync2 } from "fs";
169
- import { fileURLToPath as fileURLToPath2 } from "url";
170
- import { dirname as dirname2, join as join2 } from "path";
171
- function findPackageJson() {
172
- const paths = [
173
- join2(versionDirname, "../package.json"),
174
- // dist/ or src/
175
- join2(versionDirname, "../../package.json")
176
- // src/core/ (not used, but safe)
177
- ];
178
- for (const p2 of paths) {
179
- try {
180
- return readFileSync2(p2, "utf-8");
181
- } catch {
182
- }
183
- }
184
- return JSON.stringify({ version: "0.0.0" });
185
- }
186
- var versionFilename, versionDirname, VERSION;
187
- var init_version = __esm({
188
- "src/version.ts"() {
189
- "use strict";
190
- versionFilename = fileURLToPath2(import.meta.url);
191
- versionDirname = dirname2(versionFilename);
192
- VERSION = JSON.parse(findPackageJson()).version;
193
- }
194
- });
195
-
196
- // src/commands/run/heartbeat.ts
197
- var heartbeat_exports = {};
198
- __export(heartbeat_exports, {
199
- startHeartbeat: () => startHeartbeat
200
- });
201
- import { randomUUID } from "crypto";
202
- async function startHeartbeat(options) {
203
- const projectId = options.projectId ?? requireProjectId();
204
- const base = resolveBaseUrl();
205
- const instanceId2 = randomUUID();
206
- const healthEndpoint = options.healthEndpoint ?? "/health";
207
- const intervalSec = options.heartbeatInterval ?? 60;
208
- const log = createCLILogger();
209
- const startTime = Date.now();
210
- const heartbeatUrl = `${base}/api/projects/${projectId}/deployments/${options.deployment}/heartbeat`;
211
- const initResponse = await deployAuthenticatedFetch(heartbeatUrl, {
212
- method: "POST",
213
- headers: { "Content-Type": "application/json" },
214
- body: JSON.stringify({
215
- url: options.url,
216
- healthEndpoint,
217
- instanceId: instanceId2,
218
- cliVersion: VERSION
219
- })
220
- });
221
- if (!initResponse.ok) {
222
- const err = await initResponse.json().catch(() => ({}));
223
- throw new Error(
224
- err.error?.message || `Initial heartbeat failed (${initResponse.status})`
225
- );
226
- }
227
- const initData = await initResponse.json();
228
- log.info(
229
- `Registered as ${instanceId2} on deployment ${options.deployment} (${initData.deploymentId})`
230
- );
231
- const heartbeatTimer = setInterval(async () => {
232
- try {
233
- const resp = await deployAuthenticatedFetch(heartbeatUrl, {
234
- method: "POST",
235
- headers: { "Content-Type": "application/json" },
236
- body: JSON.stringify({
237
- instanceId: instanceId2,
238
- uptime: Math.floor((Date.now() - startTime) / 1e3),
239
- cliVersion: VERSION,
240
- metadata: {
241
- nodeVersion: process.version,
242
- platform: process.platform
243
- }
244
- })
245
- });
246
- if (resp.ok) {
247
- const data = await resp.json();
248
- if (data.action === "update" && data.bundleUrl) {
249
- log.info(
250
- `Update available: version ${data.versionNumber}, downloading from ${data.bundleUrl}`
251
- );
252
- } else if (data.action === "stop") {
253
- log.info("Received stop signal from server, shutting down...");
254
- await cleanup();
255
- process.exit(0);
256
- }
257
- }
258
- } catch (err) {
259
- log.error(
260
- `Heartbeat failed: ${err instanceof Error ? err.message : "Unknown error"}`
261
- );
262
- }
263
- }, intervalSec * 1e3);
264
- const cleanup = async () => {
265
- clearInterval(heartbeatTimer);
266
- try {
267
- await deployAuthenticatedFetch(heartbeatUrl, {
268
- method: "POST",
269
- headers: { "Content-Type": "application/json" },
270
- body: JSON.stringify({
271
- instanceId: instanceId2,
272
- uptime: Math.floor((Date.now() - startTime) / 1e3),
273
- shutting_down: true
274
- })
275
- });
276
- } catch {
277
- }
278
- };
279
- process.on("SIGTERM", async () => {
280
- await cleanup();
281
- process.exit(0);
282
- });
283
- process.on("SIGINT", async () => {
284
- await cleanup();
285
- process.exit(0);
286
- });
287
- return { instanceId: instanceId2, deploymentId: initData.deploymentId, cleanup };
288
- }
289
- var init_heartbeat = __esm({
290
- "src/commands/run/heartbeat.ts"() {
291
- "use strict";
292
- init_auth();
293
- init_cli_logger();
294
- init_version();
295
- }
296
- });
297
-
298
- // src/commands/bundle/index.ts
299
- init_cli_logger();
300
- import path10 from "path";
301
- import fs10 from "fs-extra";
302
- import { getPlatform as getPlatform2 } from "@walkeros/core";
303
-
304
- // src/core/index.ts
305
- init_cli_logger();
306
-
307
- // src/core/timer.ts
308
- function createTimer() {
309
- let startTime = 0;
310
- let endTime = 0;
311
- return {
312
- start() {
313
- startTime = Date.now();
314
- endTime = 0;
315
- },
316
- end() {
317
- endTime = Date.now();
318
- return endTime - startTime;
319
- },
320
- getElapsed() {
321
- const currentTime = endTime || Date.now();
322
- return currentTime - startTime;
323
- },
324
- format() {
325
- const elapsed = this.getElapsed();
326
- return (elapsed / 1e3).toFixed(2) + "s";
327
- }
328
- };
329
- }
330
-
331
- // src/core/output.ts
332
- import fs from "fs-extra";
333
- import path from "path";
334
- async function writeResult(content, options) {
335
- if (options.output) {
336
- const outputPath = path.resolve(options.output);
337
- await fs.ensureDir(path.dirname(outputPath));
338
- await fs.writeFile(outputPath, content);
339
- } else {
340
- process.stdout.write(content);
341
- process.stdout.write("\n");
342
- }
343
- }
344
- function createJsonOutput(success, data, error, duration) {
345
- return {
346
- success,
347
- ...data && { data },
348
- ...error && { error },
349
- ...duration && { duration }
350
- };
351
- }
352
- function createSuccessOutput(data, duration) {
353
- return createJsonOutput(true, data, void 0, duration);
354
- }
355
- function createErrorOutput(error, duration) {
356
- return createJsonOutput(false, void 0, error, duration);
357
- }
358
- function formatBytes(bytes) {
359
- return (bytes / 1024).toFixed(2);
360
- }
361
-
362
- // src/core/tmp.ts
363
- import os from "os";
364
- import path2 from "path";
365
- var DEFAULT_TMP_ROOT = os.tmpdir();
366
- function getTmpPath(tmpDir, ...segments) {
367
- const root = tmpDir || DEFAULT_TMP_ROOT;
368
- const absoluteRoot = path2.isAbsolute(root) ? root : path2.resolve(root);
369
- return path2.join(absoluteRoot, ...segments);
370
- }
371
-
372
- // src/core/asset-resolver.ts
373
- import { fileURLToPath } from "url";
374
- import { existsSync as existsSync2 } from "fs";
375
- import path4 from "path";
376
-
377
245
  // src/config/utils.ts
246
+ import crypto from "crypto";
378
247
  import fs2 from "fs-extra";
379
248
  import path3 from "path";
380
- init_auth();
381
249
  function isUrl(str) {
382
250
  try {
383
251
  const url = new URL(str);
@@ -400,7 +268,8 @@ async function downloadFromUrl(url) {
400
268
  const content = await response.text();
401
269
  const downloadsDir = getTmpPath(void 0, "downloads");
402
270
  await fs2.ensureDir(downloadsDir);
403
- const tempPath = path3.join(downloadsDir, "flow.json");
271
+ const downloadId = crypto.randomUUID().slice(0, 8);
272
+ const tempPath = path3.join(downloadsDir, `flow-${downloadId}.json`);
404
273
  await fs2.writeFile(tempPath, content, "utf-8");
405
274
  return tempPath;
406
275
  } catch (error) {
@@ -491,9 +360,19 @@ async function loadJsonFromSource(source, options) {
491
360
  );
492
361
  }
493
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
+ });
494
371
 
495
372
  // src/core/asset-resolver.ts
496
- var cachedAssetDir;
373
+ import { fileURLToPath } from "url";
374
+ import { existsSync as existsSync2 } from "fs";
375
+ import path4 from "path";
497
376
  function getAssetDir() {
498
377
  if (cachedAssetDir) return cachedAssetDir;
499
378
  const currentFile = fileURLToPath(import.meta.url);
@@ -521,16 +400,28 @@ function resolveAsset(assetPath, assetType, baseDir) {
521
400
  }
522
401
  return path4.resolve(baseDir || process.cwd(), assetPath);
523
402
  }
403
+ var cachedAssetDir;
404
+ var init_asset_resolver = __esm({
405
+ "src/core/asset-resolver.ts"() {
406
+ "use strict";
407
+ init_utils();
408
+ }
409
+ });
524
410
 
525
411
  // src/core/utils.ts
526
412
  function getErrorMessage(error) {
527
413
  return error instanceof Error ? error.message : String(error);
528
414
  }
415
+ var init_utils2 = __esm({
416
+ "src/core/utils.ts"() {
417
+ "use strict";
418
+ }
419
+ });
529
420
 
530
421
  // src/core/local-packages.ts
531
422
  import path5 from "path";
532
423
  import fs3 from "fs-extra";
533
- async function resolveLocalPackage(packageName, localPath, configDir, logger2) {
424
+ async function resolveLocalPackage(packageName, localPath, configDir, logger) {
534
425
  const absolutePath = path5.isAbsolute(localPath) ? localPath : path5.resolve(configDir, localPath);
535
426
  if (!await fs3.pathExists(absolutePath)) {
536
427
  throw new Error(
@@ -546,7 +437,7 @@ async function resolveLocalPackage(packageName, localPath, configDir, logger2) {
546
437
  const distPath = path5.join(absolutePath, "dist");
547
438
  const hasDistFolder = await fs3.pathExists(distPath);
548
439
  if (!hasDistFolder) {
549
- logger2.warn(
440
+ logger.warn(
550
441
  `\u26A0\uFE0F ${packageName}: No dist/ folder found. Using package root.`
551
442
  );
552
443
  }
@@ -557,7 +448,7 @@ async function resolveLocalPackage(packageName, localPath, configDir, logger2) {
557
448
  hasDistFolder
558
449
  };
559
450
  }
560
- async function copyLocalPackage(localPkg, targetDir, logger2) {
451
+ async function copyLocalPackage(localPkg, targetDir, logger) {
561
452
  const packageDir = path5.join(targetDir, "node_modules", localPkg.name);
562
453
  await fs3.ensureDir(path5.dirname(packageDir));
563
454
  await fs3.copy(
@@ -577,13 +468,17 @@ async function copyLocalPackage(localPkg, targetDir, logger2) {
577
468
  }
578
469
  }
579
470
  }
580
- logger2.info(`\u{1F4E6} Using local: ${localPkg.name} from ${localPkg.absolutePath}`);
471
+ logger.info(`\u{1F4E6} Using local: ${localPkg.name} from ${localPkg.absolutePath}`);
581
472
  return packageDir;
582
473
  }
474
+ var init_local_packages = __esm({
475
+ "src/core/local-packages.ts"() {
476
+ "use strict";
477
+ }
478
+ });
583
479
 
584
480
  // src/core/input-detector.ts
585
481
  import fs4 from "fs-extra";
586
- init_auth();
587
482
  async function detectInput(inputPath, platformOverride) {
588
483
  const content = await loadContent(inputPath);
589
484
  try {
@@ -608,6 +503,13 @@ async function loadContent(inputPath) {
608
503
  }
609
504
  return fs4.readFile(inputPath, "utf8");
610
505
  }
506
+ var init_input_detector = __esm({
507
+ "src/core/input-detector.ts"() {
508
+ "use strict";
509
+ init_utils();
510
+ init_auth();
511
+ }
512
+ });
611
513
 
612
514
  // src/core/stdin.ts
613
515
  function isStdinPiped() {
@@ -624,9 +526,11 @@ async function readStdin() {
624
526
  }
625
527
  return content;
626
528
  }
627
-
628
- // src/core/index.ts
629
- init_auth();
529
+ var init_stdin = __esm({
530
+ "src/core/stdin.ts"() {
531
+ "use strict";
532
+ }
533
+ });
630
534
 
631
535
  // src/core/sse.ts
632
536
  function parseSSEEvents(buffer) {
@@ -650,83 +554,115 @@ function parseSSEEvents(buffer) {
650
554
  }
651
555
  return { parsed: events, remainder };
652
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
+ });
653
578
 
654
579
  // src/config/validators.ts
655
580
  import { schemas } from "@walkeros/core/dev";
656
- var { safeParseSetup } = schemas;
657
581
  function isObject(value) {
658
582
  return typeof value === "object" && value !== null && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]";
659
583
  }
660
- function validateFlowSetup(data) {
661
- const result = safeParseSetup(data);
584
+ function validateFlowConfig(data) {
585
+ const result = safeParseConfig(data);
662
586
  if (!result.success) {
663
587
  const errors = result.error.issues.map((issue) => {
664
- const path14 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
665
- return ` - ${path14}: ${issue.message}`;
588
+ const path15 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
589
+ return ` - ${path15}: ${issue.message}`;
666
590
  }).join("\n");
667
591
  throw new Error(`Invalid configuration:
668
592
  ${errors}`);
669
593
  }
670
594
  return result.data;
671
595
  }
672
- function getAvailableFlows(setup) {
673
- return Object.keys(setup.flows);
596
+ function getAvailableFlows(config) {
597
+ return Object.keys(config.flows);
674
598
  }
599
+ var safeParseConfig;
600
+ var init_validators = __esm({
601
+ "src/config/validators.ts"() {
602
+ "use strict";
603
+ ({ safeParseConfig } = schemas);
604
+ }
605
+ });
675
606
 
676
607
  // src/config/build-defaults.ts
677
- var WEB_BUILD_DEFAULTS = {
678
- format: "iife",
679
- platform: "browser",
680
- target: "es2020",
681
- minify: true,
682
- sourcemap: false,
683
- cache: true,
684
- windowCollector: "collector",
685
- windowElb: "elb"
686
- };
687
- var SERVER_BUILD_DEFAULTS = {
688
- format: "esm",
689
- platform: "node",
690
- target: "node20",
691
- minify: true,
692
- sourcemap: false,
693
- cache: true
694
- };
695
- var DEFAULT_OUTPUT_PATHS = {
696
- web: "./dist/walker.js",
697
- server: "./dist/bundle.mjs"
698
- };
699
608
  function getBuildDefaults(platform) {
700
609
  return platform === "web" ? WEB_BUILD_DEFAULTS : SERVER_BUILD_DEFAULTS;
701
610
  }
702
611
  function getDefaultOutput(platform) {
703
612
  return DEFAULT_OUTPUT_PATHS[platform];
704
613
  }
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
+ });
705
642
 
706
643
  // src/config/loader.ts
707
644
  import path6 from "path";
708
645
  import fs5 from "fs-extra";
709
- import { getFlowConfig, getPlatform } from "@walkeros/core";
710
- var DEFAULT_INCLUDE_FOLDER = "./shared";
646
+ import { getFlowSettings, getPlatform } from "@walkeros/core";
711
647
  function loadBundleConfig(rawConfig, options) {
712
- const setup = validateFlowSetup(rawConfig);
713
- const availableFlows = getAvailableFlows(setup);
714
- const flowName = resolveFlow(setup, options.flowName, availableFlows);
715
- let flowConfig = getFlowConfig(setup, flowName, { deferred: true });
716
- 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);
717
653
  if (!platform) {
718
654
  throw new Error(
719
655
  `Invalid configuration: flow "${flowName}" must have a "web" or "server" key.`
720
656
  );
721
657
  }
722
658
  if (platform === "web") {
723
- flowConfig = getFlowConfig(setup, flowName);
659
+ flowSettings = getFlowSettings(config, flowName);
724
660
  }
725
661
  const buildDefaults = getBuildDefaults(platform);
726
- const packages = flowConfig.packages || {};
662
+ const packages = flowSettings.packages || {};
727
663
  const output = options.buildOverrides?.output || getDefaultOutput(platform);
728
664
  const configDir = isUrl(options.configPath) ? process.cwd() : path6.dirname(options.configPath);
729
- let includes = setup.include;
665
+ let includes = config.include;
730
666
  if (!includes) {
731
667
  const defaultIncludePath = path6.resolve(configDir, DEFAULT_INCLUDE_FOLDER);
732
668
  if (fs5.pathExistsSync(defaultIncludePath)) {
@@ -748,14 +684,14 @@ function loadBundleConfig(rawConfig, options) {
748
684
  );
749
685
  }
750
686
  return {
751
- flowConfig,
687
+ flowSettings,
752
688
  buildOptions,
753
689
  flowName,
754
690
  isMultiFlow,
755
691
  availableFlows
756
692
  };
757
693
  }
758
- function resolveFlow(setup, requestedFlow, available) {
694
+ function resolveFlow(config, requestedFlow, available) {
759
695
  if (available.length === 1) {
760
696
  return available[0];
761
697
  }
@@ -774,8 +710,8 @@ Available flows: ${available.join(", ")}`
774
710
  return requestedFlow;
775
711
  }
776
712
  function loadAllFlows(rawConfig, options) {
777
- const setup = validateFlowSetup(rawConfig);
778
- const flows = getAvailableFlows(setup);
713
+ const config = validateFlowConfig(rawConfig);
714
+ const flows = getAvailableFlows(config);
779
715
  if (options.logger) {
780
716
  options.logger.info(
781
717
  `\u{1F4E6} Loading all ${flows.length} flows: ${flows.join(", ")}`
@@ -792,21 +728,29 @@ async function loadFlowConfig(configPath, options) {
792
728
  const rawConfig = await loadJsonConfig(configPath);
793
729
  return loadBundleConfig(rawConfig, { configPath, ...options });
794
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
+ });
795
741
 
796
- // src/commands/bundle/bundler.ts
797
- import esbuild from "esbuild";
798
- import path9 from "path";
799
- import fs8 from "fs-extra";
800
- import { packageNameToVariable, ENV_MARKER_PREFIX } from "@walkeros/core";
801
-
802
- // src/commands/bundle/package-manager.ts
803
- import pacote from "pacote";
804
- import path7 from "path";
805
- 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
+ });
806
751
 
807
752
  // src/core/cache-utils.ts
808
753
  import { getHashServer } from "@walkeros/server-core";
809
- var HASH_LENGTH = 12;
810
754
  function isMutableVersion(version) {
811
755
  return version === "latest" || version.includes("^") || version.includes("~") || version.includes("*") || version.includes("x");
812
756
  }
@@ -827,15 +771,25 @@ function normalizeJson(content) {
827
771
  const parsed = JSON.parse(content);
828
772
  return JSON.stringify(parsed);
829
773
  }
830
- async function getFlowConfigCacheKey(content, date) {
774
+ async function getFlowSettingsCacheKey(content, date) {
831
775
  const dateStr = date ?? getTodayDate();
832
776
  const normalized = normalizeJson(content);
833
777
  const input = `${normalized}:${dateStr}`;
834
778
  return getHashServer(input, HASH_LENGTH);
835
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
+ });
836
787
 
837
788
  // src/commands/bundle/package-manager.ts
838
- 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";
839
793
  async function withTimeout(promise, ms, errorMessage) {
840
794
  let timer;
841
795
  const timeout = new Promise((_2, reject) => {
@@ -847,132 +801,199 @@ async function withTimeout(promise, ms, errorMessage) {
847
801
  clearTimeout(timer);
848
802
  }
849
803
  }
850
- function getPackageDirectory(baseDir, packageName, version) {
804
+ function getPackageDirectory(baseDir, packageName) {
851
805
  return path7.join(baseDir, "node_modules", packageName);
852
806
  }
853
- async function getCachedPackagePath(pkg, tmpDir) {
854
- const cacheDir = getTmpPath(tmpDir, "cache", "packages");
855
- const cacheKey = await getPackageCacheKey(pkg.name, pkg.version);
856
- return path7.join(cacheDir, cacheKey);
857
- }
858
- async function isPackageCached(pkg, tmpDir) {
859
- const cachedPath = await getCachedPackagePath(pkg, tmpDir);
860
- return fs6.pathExists(cachedPath);
861
- }
862
- function validateNoDuplicatePackages(packages) {
863
- const packageMap = /* @__PURE__ */ new Map();
864
- for (const pkg of packages) {
865
- if (!packageMap.has(pkg.name)) {
866
- 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;
867
844
  }
868
- packageMap.get(pkg.name).push(pkg.version);
869
- }
870
- const conflicts = [];
871
- for (const [name, versions] of packageMap.entries()) {
872
- const uniqueVersions = [...new Set(versions)];
873
- if (uniqueVersions.length > 1) {
874
- 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
+ }
875
871
  }
876
872
  }
877
- if (conflicts.length > 0) {
878
- throw new Error(
879
- `Version conflicts detected:
880
- ${conflicts.map((c2) => ` - ${c2}`).join("\n")}
881
-
882
- Each package must use the same version across all declarations. Please update your configuration to use consistent versions.`
883
- );
884
- }
873
+ return allSpecs;
885
874
  }
886
- async function resolveDependencies(pkg, packageDir, logger2, visited = /* @__PURE__ */ new Set()) {
887
- const dependencies = [];
888
- const pkgKey = `${pkg.name}@${pkg.version}`;
889
- if (visited.has(pkgKey)) {
890
- return dependencies;
891
- }
892
- visited.add(pkgKey);
893
- try {
894
- const packageJsonPath = path7.join(packageDir, "package.json");
895
- if (await fs6.pathExists(packageJsonPath)) {
896
- const packageJson = await fs6.readJson(packageJsonPath);
897
- const deps = {
898
- ...packageJson.dependencies,
899
- ...packageJson.peerDependencies
900
- };
901
- for (const [name, versionSpec] of Object.entries(deps)) {
902
- if (typeof versionSpec === "string") {
903
- 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
+ }
904
948
  }
905
949
  }
906
950
  }
907
- } catch (error) {
908
- logger2.debug(`Failed to read dependencies for ${pkgKey}: ${error}`);
951
+ resolved.set(name, { name, version: chosenVersion });
909
952
  }
910
- return dependencies;
953
+ return resolved;
911
954
  }
912
- async function downloadPackages(packages, targetDir, logger2, useCache = true, configDir, tmpDir) {
955
+ async function downloadPackages(packages, targetDir, logger, useCache = true, configDir, tmpDir) {
913
956
  const packagePaths = /* @__PURE__ */ new Map();
914
- const downloadQueue = [...packages];
915
- const processed = /* @__PURE__ */ new Set();
916
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);
917
963
  const localPackageMap = /* @__PURE__ */ new Map();
918
964
  for (const pkg of packages) {
919
- if (pkg.path) {
920
- localPackageMap.set(pkg.name, pkg.path);
921
- }
965
+ if (pkg.path) localPackageMap.set(pkg.name, pkg.path);
922
966
  }
923
- validateNoDuplicatePackages(packages);
924
- await fs6.ensureDir(targetDir);
925
- while (downloadQueue.length > 0) {
926
- const pkg = downloadQueue.shift();
927
- const pkgKey = `${pkg.name}@${pkg.version}`;
928
- if (processed.has(pkgKey)) {
929
- continue;
930
- }
931
- processed.add(pkgKey);
932
- if (!pkg.path && localPackageMap.has(pkg.name)) {
933
- pkg.path = localPackageMap.get(pkg.name);
934
- }
935
- 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);
936
970
  const localPkg = await resolveLocalPackage(
937
- pkg.name,
938
- pkg.path,
971
+ name,
972
+ localPath,
939
973
  configDir || process.cwd(),
940
- logger2
974
+ logger
941
975
  );
942
- const installedPath = await copyLocalPackage(localPkg, targetDir, logger2);
943
- packagePaths.set(pkg.name, installedPath);
944
- const deps = await resolveDependencies(pkg, installedPath, logger2);
945
- for (const dep of deps) {
946
- const depKey = `${dep.name}@${dep.version}`;
947
- if (!processed.has(depKey)) {
948
- downloadQueue.push(dep);
949
- }
950
- }
976
+ const installedPath = await copyLocalPackage(localPkg, targetDir, logger);
977
+ packagePaths.set(name, installedPath);
951
978
  continue;
952
979
  }
953
- const packageSpec = `${pkg.name}@${pkg.version}`;
954
- const packageDir = getPackageDirectory(targetDir, pkg.name, pkg.version);
955
- const cachedPath = await getCachedPackagePath(pkg, tmpDir);
956
- if (useCache && await isPackageCached(pkg, tmpDir)) {
957
- if (userSpecifiedPackages.has(pkg.name)) {
958
- 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)`);
959
989
  }
960
990
  try {
961
991
  await fs6.ensureDir(path7.dirname(packageDir));
962
992
  await fs6.copy(cachedPath, packageDir);
963
- packagePaths.set(pkg.name, packageDir);
964
- const deps = await resolveDependencies(pkg, packageDir, logger2);
965
- for (const dep of deps) {
966
- const depKey = `${dep.name}@${dep.version}`;
967
- if (!processed.has(depKey)) {
968
- downloadQueue.push(dep);
969
- }
970
- }
993
+ packagePaths.set(name, packageDir);
971
994
  continue;
972
- } catch (error) {
973
- logger2.debug(
974
- `Failed to use cache for ${packageSpec}, downloading fresh: ${error}`
975
- );
995
+ } catch {
996
+ logger.debug(`Cache miss for ${packageSpec}, downloading fresh`);
976
997
  }
977
998
  }
978
999
  try {
@@ -980,52 +1001,87 @@ async function downloadPackages(packages, targetDir, logger2, useCache = true, c
980
1001
  const cacheDir = process.env.NPM_CACHE_DIR || getTmpPath(tmpDir, "cache", "npm");
981
1002
  await withTimeout(
982
1003
  pacote.extract(packageSpec, packageDir, {
983
- // Force npm registry download, prevent workspace resolution
984
- registry: "https://registry.npmjs.org",
985
- // Force online fetching from registry (don't use cached workspace packages)
986
- preferOnline: true,
987
- // Cache for performance
988
- cache: cacheDir,
989
- // Don't resolve relative to workspace context
990
- where: void 0
1004
+ ...PACOTE_OPTS,
1005
+ cache: cacheDir
991
1006
  }),
992
1007
  PACKAGE_DOWNLOAD_TIMEOUT_MS,
993
1008
  `Package download timed out after ${PACKAGE_DOWNLOAD_TIMEOUT_MS / 1e3}s: ${packageSpec}`
994
1009
  );
995
- if (userSpecifiedPackages.has(pkg.name)) {
996
- const pkgStats = await fs6.stat(path7.join(packageDir, "package.json"));
997
- const pkgJsonSize = pkgStats.size;
998
- const sizeKB = (pkgJsonSize / 1024).toFixed(1);
999
- logger2.debug(`Downloading ${packageSpec} (${sizeKB} KB)`);
1010
+ if (userSpecifiedPackages.has(name)) {
1011
+ logger.debug(`Downloading ${packageSpec}`);
1000
1012
  }
1001
1013
  if (useCache) {
1002
1014
  try {
1003
1015
  await fs6.ensureDir(path7.dirname(cachedPath));
1004
1016
  await fs6.copy(packageDir, cachedPath);
1005
- } catch (cacheError) {
1006
- }
1007
- }
1008
- packagePaths.set(pkg.name, packageDir);
1009
- const deps = await resolveDependencies(pkg, packageDir, logger2);
1010
- for (const dep of deps) {
1011
- const depKey = `${dep.name}@${dep.version}`;
1012
- if (!processed.has(depKey)) {
1013
- downloadQueue.push(dep);
1017
+ } catch {
1014
1018
  }
1015
1019
  }
1020
+ packagePaths.set(name, packageDir);
1016
1021
  } catch (error) {
1017
1022
  throw new Error(`Failed to download ${packageSpec}: ${error}`);
1018
1023
  }
1019
1024
  }
1020
1025
  return packagePaths;
1021
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
+ });
1022
1078
 
1023
1079
  // src/core/build-cache.ts
1024
1080
  import fs7 from "fs-extra";
1025
1081
  import path8 from "path";
1026
1082
  async function getBuildCachePath(configContent, tmpDir) {
1027
1083
  const cacheDir = getTmpPath(tmpDir, "cache", "builds");
1028
- const cacheKey = await getFlowConfigCacheKey(configContent);
1084
+ const cacheKey = await getFlowSettingsCacheKey(configContent);
1029
1085
  return path8.join(cacheDir, `${cacheKey}.js`);
1030
1086
  }
1031
1087
  async function isBuildCached(configContent, tmpDir) {
@@ -1044,8 +1100,20 @@ async function getCachedBuild(configContent, tmpDir) {
1044
1100
  }
1045
1101
  return null;
1046
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
+ });
1047
1110
 
1048
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";
1049
1117
  function isInlineCode(code) {
1050
1118
  return code !== null && typeof code === "object" && !Array.isArray(code) && "push" in code;
1051
1119
  }
@@ -1091,22 +1159,29 @@ function generateInlineCode(inline, config, env, chain, chainPropertyName, isDes
1091
1159
  ${chainLine.slice(0, -1)}` : ""}
1092
1160
  }`;
1093
1161
  }
1094
- async function copyIncludes(includes, sourceDir, outputDir, logger2) {
1162
+ async function copyIncludes(includes, sourceDir, outputDir, logger) {
1095
1163
  for (const include of includes) {
1096
1164
  const sourcePath = path9.resolve(sourceDir, include);
1097
1165
  const folderName = path9.basename(include);
1098
1166
  const destPath = path9.join(outputDir, folderName);
1167
+ const resolvedOutput = path9.resolve(outputDir);
1168
+ const resolvedSource = path9.resolve(sourcePath);
1169
+ if (resolvedSource === resolvedOutput || resolvedOutput.startsWith(resolvedSource + path9.sep) || resolvedSource.startsWith(resolvedOutput + path9.sep)) {
1170
+ throw new Error(
1171
+ `Circular include detected: "${include}" resolves to "${resolvedSource}" which overlaps with output directory "${resolvedOutput}"`
1172
+ );
1173
+ }
1099
1174
  if (await fs8.pathExists(sourcePath)) {
1100
1175
  await fs8.copy(sourcePath, destPath);
1101
- logger2.debug(`Copied ${include} to output`);
1176
+ logger.debug(`Copied ${include} to output`);
1102
1177
  } else {
1103
- logger2.debug(`Include folder not found: ${include}`);
1178
+ logger.warn(`Include folder not found: ${include}`);
1104
1179
  }
1105
1180
  }
1106
1181
  }
1107
- function generateCacheKeyContent(flowConfig, buildOptions) {
1182
+ function generateCacheKeyContent(flowSettings, buildOptions) {
1108
1183
  const configForCache = {
1109
- flow: flowConfig,
1184
+ flow: flowSettings,
1110
1185
  build: {
1111
1186
  ...buildOptions,
1112
1187
  // Exclude non-deterministic fields from cache key
@@ -1116,62 +1191,64 @@ function generateCacheKeyContent(flowConfig, buildOptions) {
1116
1191
  };
1117
1192
  return JSON.stringify(configForCache);
1118
1193
  }
1119
- function validateFlowConfig(flowConfig, logger2) {
1194
+ function validateFlowConfig2(flowSettings, logger) {
1120
1195
  let hasDeprecatedCodeTrue = false;
1121
- const sources = flowConfig.sources || {};
1196
+ const sources = flowSettings.sources || {};
1122
1197
  for (const [sourceId, source] of Object.entries(sources)) {
1123
1198
  if (source && typeof source === "object" && source.code === true) {
1124
- logger2.warn(
1199
+ logger.warn(
1125
1200
  `DEPRECATED: Source "${sourceId}" uses code: true which is no longer supported. Use $code: prefix in config values or create a source package instead.`
1126
1201
  );
1127
1202
  hasDeprecatedCodeTrue = true;
1128
1203
  }
1129
1204
  }
1130
- const destinations = flowConfig.destinations || {};
1205
+ const destinations = flowSettings.destinations || {};
1131
1206
  for (const [destId, dest] of Object.entries(destinations)) {
1132
1207
  if (dest && typeof dest === "object" && dest.code === true) {
1133
- logger2.warn(
1208
+ logger.warn(
1134
1209
  `DEPRECATED: Destination "${destId}" uses code: true which is no longer supported. Use $code: prefix in config values or create a destination package instead.`
1135
1210
  );
1136
1211
  hasDeprecatedCodeTrue = true;
1137
1212
  }
1138
1213
  }
1139
- const transformers = flowConfig.transformers || {};
1214
+ const transformers = flowSettings.transformers || {};
1140
1215
  for (const [transformerId, transformer] of Object.entries(transformers)) {
1141
1216
  if (transformer && typeof transformer === "object" && transformer.code === true) {
1142
- logger2.warn(
1217
+ logger.warn(
1143
1218
  `DEPRECATED: Transformer "${transformerId}" uses code: true which is no longer supported. Use $code: prefix in config values or create a transformer package instead.`
1144
1219
  );
1145
1220
  hasDeprecatedCodeTrue = true;
1146
1221
  }
1147
1222
  }
1148
1223
  if (hasDeprecatedCodeTrue) {
1149
- logger2.warn(
1224
+ logger.warn(
1150
1225
  `See https://www.elbwalker.com/docs/walkeros/getting-started/flow for migration guide.`
1151
1226
  );
1152
1227
  }
1153
1228
  return hasDeprecatedCodeTrue;
1154
1229
  }
1155
- async function bundleCore(flowConfig, buildOptions, logger2, showStats = false) {
1230
+ async function bundleCore(flowSettings, buildOptions, logger, showStats = false) {
1156
1231
  const bundleStartTime = Date.now();
1157
- const hasDeprecatedFeatures = validateFlowConfig(flowConfig, logger2);
1232
+ const hasDeprecatedFeatures = validateFlowConfig2(flowSettings, logger);
1158
1233
  if (hasDeprecatedFeatures) {
1159
- logger2.warn("Skipping deprecated code: true entries from bundle.");
1234
+ logger.warn("Skipping deprecated code: true entries from bundle.");
1160
1235
  }
1161
- 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();
1162
1239
  if (buildOptions.cache !== false) {
1163
- const configContent = generateCacheKeyContent(flowConfig, buildOptions);
1164
- const cached = await isBuildCached(configContent, TEMP_DIR);
1240
+ const configContent = generateCacheKeyContent(flowSettings, buildOptions);
1241
+ const cached = await isBuildCached(configContent, CACHE_DIR);
1165
1242
  if (cached) {
1166
- const cachedBuild = await getCachedBuild(configContent, TEMP_DIR);
1243
+ const cachedBuild = await getCachedBuild(configContent, CACHE_DIR);
1167
1244
  if (cachedBuild) {
1168
- logger2.debug("Using cached build");
1245
+ logger.debug("Using cached build");
1169
1246
  const outputPath = path9.resolve(buildOptions.output);
1170
1247
  await fs8.ensureDir(path9.dirname(outputPath));
1171
1248
  await fs8.writeFile(outputPath, cachedBuild);
1172
1249
  const stats = await fs8.stat(outputPath);
1173
1250
  const sizeKB = (stats.size / 1024).toFixed(1);
1174
- logger2.info(`Output: ${outputPath} (${sizeKB} KB, cached)`);
1251
+ logger.info(`Output: ${outputPath} (${sizeKB} KB, cached)`);
1175
1252
  if (showStats) {
1176
1253
  const stats2 = await fs8.stat(outputPath);
1177
1254
  const packageStats = Object.entries(buildOptions.packages).map(
@@ -1198,14 +1275,14 @@ async function bundleCore(flowConfig, buildOptions, logger2, showStats = false)
1198
1275
  try {
1199
1276
  await fs8.ensureDir(TEMP_DIR);
1200
1277
  const hasSourcesOrDests = Object.keys(
1201
- flowConfig.sources || {}
1278
+ flowSettings.sources || {}
1202
1279
  ).length > 0 || Object.keys(
1203
- flowConfig.destinations || {}
1280
+ flowSettings.destinations || {}
1204
1281
  ).length > 0;
1205
1282
  if (hasSourcesOrDests && !buildOptions.packages["@walkeros/collector"]) {
1206
1283
  buildOptions.packages["@walkeros/collector"] = {};
1207
1284
  }
1208
- logger2.debug("Downloading packages");
1285
+ logger.debug("Downloading packages");
1209
1286
  const packagesArray = Object.entries(buildOptions.packages).map(
1210
1287
  ([name, packageConfig]) => ({
1211
1288
  name,
@@ -1217,11 +1294,11 @@ async function bundleCore(flowConfig, buildOptions, logger2, showStats = false)
1217
1294
  const packagePaths = await downloadPackages(
1218
1295
  packagesArray,
1219
1296
  TEMP_DIR,
1220
- logger2,
1297
+ logger,
1221
1298
  buildOptions.cache,
1222
1299
  buildOptions.configDir,
1223
1300
  // For resolving relative local paths
1224
- TEMP_DIR
1301
+ CACHE_DIR
1225
1302
  );
1226
1303
  for (const [pkgName, pkgPath] of packagePaths.entries()) {
1227
1304
  if (pkgName.startsWith("@walkeros/")) {
@@ -1243,15 +1320,15 @@ async function bundleCore(flowConfig, buildOptions, logger2, showStats = false)
1243
1320
  packageJsonPath,
1244
1321
  JSON.stringify({ type: "module" }, null, 2)
1245
1322
  );
1246
- logger2.debug("Creating entry point");
1323
+ logger.debug("Creating entry point");
1247
1324
  const entryContent = await createEntryPoint(
1248
- flowConfig,
1325
+ flowSettings,
1249
1326
  buildOptions,
1250
1327
  packagePaths
1251
1328
  );
1252
1329
  const entryPath = path9.join(TEMP_DIR, "entry.js");
1253
1330
  await fs8.writeFile(entryPath, entryContent);
1254
- logger2.debug(
1331
+ logger.debug(
1255
1332
  `Running esbuild (target: ${buildOptions.target || "es2018"}, format: ${buildOptions.format})`
1256
1333
  );
1257
1334
  const outputPath = path9.resolve(buildOptions.output);
@@ -1262,7 +1339,7 @@ async function bundleCore(flowConfig, buildOptions, logger2, showStats = false)
1262
1339
  outputPath,
1263
1340
  TEMP_DIR,
1264
1341
  packagePaths,
1265
- logger2
1342
+ logger
1266
1343
  );
1267
1344
  try {
1268
1345
  await esbuild.build(esbuildOptions);
@@ -1277,12 +1354,12 @@ async function bundleCore(flowConfig, buildOptions, logger2, showStats = false)
1277
1354
  const outputStats = await fs8.stat(outputPath);
1278
1355
  const sizeKB = (outputStats.size / 1024).toFixed(1);
1279
1356
  const buildTime = ((Date.now() - bundleStartTime) / 1e3).toFixed(1);
1280
- logger2.info(`Output: ${outputPath} (${sizeKB} KB, ${buildTime}s)`);
1357
+ logger.info(`Output: ${outputPath} (${sizeKB} KB, ${buildTime}s)`);
1281
1358
  if (buildOptions.cache !== false) {
1282
- const configContent = generateCacheKeyContent(flowConfig, buildOptions);
1359
+ const configContent = generateCacheKeyContent(flowSettings, buildOptions);
1283
1360
  const buildOutput = await fs8.readFile(outputPath, "utf-8");
1284
- await cacheBuild(configContent, buildOutput, TEMP_DIR);
1285
- logger2.debug("Build cached for future use");
1361
+ await cacheBuild(configContent, buildOutput, CACHE_DIR);
1362
+ logger.debug("Build cached for future use");
1286
1363
  }
1287
1364
  let stats;
1288
1365
  if (showStats) {
@@ -1299,12 +1376,17 @@ async function bundleCore(flowConfig, buildOptions, logger2, showStats = false)
1299
1376
  buildOptions.include,
1300
1377
  buildOptions.configDir || process.cwd(),
1301
1378
  outputDir,
1302
- logger2
1379
+ logger
1303
1380
  );
1304
1381
  }
1305
1382
  return stats;
1306
1383
  } catch (error) {
1307
1384
  throw error;
1385
+ } finally {
1386
+ if (!buildOptions.tempDir) {
1387
+ fs8.remove(TEMP_DIR).catch(() => {
1388
+ });
1389
+ }
1308
1390
  }
1309
1391
  }
1310
1392
  async function collectBundleStats(outputPath, packages, startTime, entryContent) {
@@ -1334,7 +1416,7 @@ async function collectBundleStats(outputPath, packages, startTime, entryContent)
1334
1416
  treeshakingEffective
1335
1417
  };
1336
1418
  }
1337
- function createEsbuildOptions(buildOptions, entryPath, outputPath, tempDir, packagePaths, logger2) {
1419
+ function createEsbuildOptions(buildOptions, entryPath, outputPath, tempDir, packagePaths, logger) {
1338
1420
  const alias = {};
1339
1421
  const baseOptions = {
1340
1422
  entryPoints: [entryPath],
@@ -1402,9 +1484,9 @@ function createEsbuildOptions(buildOptions, entryPath, outputPath, tempDir, pack
1402
1484
  }
1403
1485
  return baseOptions;
1404
1486
  }
1405
- function detectDestinationPackages(flowConfig) {
1487
+ function detectDestinationPackages(flowSettings) {
1406
1488
  const destinationPackages = /* @__PURE__ */ new Set();
1407
- const destinations = flowConfig.destinations;
1489
+ const destinations = flowSettings.destinations;
1408
1490
  if (destinations) {
1409
1491
  for (const [destKey, destConfig] of Object.entries(destinations)) {
1410
1492
  if (typeof destConfig === "object" && destConfig !== null && "code" in destConfig && destConfig.code === true) {
@@ -1417,9 +1499,9 @@ function detectDestinationPackages(flowConfig) {
1417
1499
  }
1418
1500
  return destinationPackages;
1419
1501
  }
1420
- function detectSourcePackages(flowConfig) {
1502
+ function detectSourcePackages(flowSettings) {
1421
1503
  const sourcePackages = /* @__PURE__ */ new Set();
1422
- const sources = flowConfig.sources;
1504
+ const sources = flowSettings.sources;
1423
1505
  if (sources) {
1424
1506
  for (const [sourceKey, sourceConfig] of Object.entries(sources)) {
1425
1507
  if (typeof sourceConfig === "object" && sourceConfig !== null && "code" in sourceConfig && sourceConfig.code === true) {
@@ -1432,9 +1514,9 @@ function detectSourcePackages(flowConfig) {
1432
1514
  }
1433
1515
  return sourcePackages;
1434
1516
  }
1435
- function detectTransformerPackages(flowConfig) {
1517
+ function detectTransformerPackages(flowSettings) {
1436
1518
  const transformerPackages = /* @__PURE__ */ new Set();
1437
- const transformers = flowConfig.transformers;
1519
+ const transformers = flowSettings.transformers;
1438
1520
  if (transformers) {
1439
1521
  for (const [transformerKey, transformerConfig] of Object.entries(
1440
1522
  transformers
@@ -1449,9 +1531,21 @@ function detectTransformerPackages(flowConfig) {
1449
1531
  }
1450
1532
  return transformerPackages;
1451
1533
  }
1452
- function detectExplicitCodeImports(flowConfig) {
1534
+ function detectStorePackages(flowSettings) {
1535
+ const storePackages = /* @__PURE__ */ new Set();
1536
+ const stores = flowSettings.stores;
1537
+ if (stores) {
1538
+ for (const [, storeConfig] of Object.entries(stores)) {
1539
+ if (typeof storeConfig === "object" && storeConfig !== null && "package" in storeConfig && typeof storeConfig.package === "string") {
1540
+ storePackages.add(storeConfig.package);
1541
+ }
1542
+ }
1543
+ }
1544
+ return storePackages;
1545
+ }
1546
+ function detectExplicitCodeImports(flowSettings) {
1453
1547
  const explicitCodeImports = /* @__PURE__ */ new Map();
1454
- const destinations = flowConfig.destinations;
1548
+ const destinations = flowSettings.destinations;
1455
1549
  if (destinations) {
1456
1550
  for (const [destKey, destConfig] of Object.entries(destinations)) {
1457
1551
  if (typeof destConfig === "object" && destConfig !== null && "code" in destConfig && destConfig.code === true) {
@@ -1468,7 +1562,7 @@ function detectExplicitCodeImports(flowConfig) {
1468
1562
  }
1469
1563
  }
1470
1564
  }
1471
- const sources = flowConfig.sources;
1565
+ const sources = flowSettings.sources;
1472
1566
  if (sources) {
1473
1567
  for (const [sourceKey, sourceConfig] of Object.entries(sources)) {
1474
1568
  if (typeof sourceConfig === "object" && sourceConfig !== null && "code" in sourceConfig && sourceConfig.code === true) {
@@ -1485,7 +1579,7 @@ function detectExplicitCodeImports(flowConfig) {
1485
1579
  }
1486
1580
  }
1487
1581
  }
1488
- const transformers = flowConfig.transformers;
1582
+ const transformers = flowSettings.transformers;
1489
1583
  if (transformers) {
1490
1584
  for (const [transformerKey, transformerConfig] of Object.entries(
1491
1585
  transformers
@@ -1504,15 +1598,30 @@ function detectExplicitCodeImports(flowConfig) {
1504
1598
  }
1505
1599
  }
1506
1600
  }
1601
+ const stores = flowSettings.stores;
1602
+ if (stores) {
1603
+ for (const [, storeConfig] of Object.entries(stores)) {
1604
+ if (typeof storeConfig === "object" && storeConfig !== null && "package" in storeConfig && typeof storeConfig.package === "string" && "code" in storeConfig && typeof storeConfig.code === "string") {
1605
+ const isAutoGenerated = storeConfig.code.startsWith("_");
1606
+ if (!isAutoGenerated) {
1607
+ if (!explicitCodeImports.has(storeConfig.package)) {
1608
+ explicitCodeImports.set(storeConfig.package, /* @__PURE__ */ new Set());
1609
+ }
1610
+ explicitCodeImports.get(storeConfig.package).add(storeConfig.code);
1611
+ }
1612
+ }
1613
+ }
1614
+ }
1507
1615
  return explicitCodeImports;
1508
1616
  }
1509
- function generateImportStatements(packages, destinationPackages, sourcePackages, transformerPackages, explicitCodeImports) {
1617
+ function generateImportStatements(packages, destinationPackages, sourcePackages, transformerPackages, storePackages, explicitCodeImports) {
1510
1618
  const importStatements = [];
1511
1619
  const examplesMappings = [];
1512
1620
  const usedPackages = /* @__PURE__ */ new Set([
1513
1621
  ...destinationPackages,
1514
1622
  ...sourcePackages,
1515
- ...transformerPackages
1623
+ ...transformerPackages,
1624
+ ...storePackages
1516
1625
  ]);
1517
1626
  for (const [packageName, packageConfig] of Object.entries(packages)) {
1518
1627
  const isUsedByDestOrSource = usedPackages.has(packageName);
@@ -1568,22 +1677,79 @@ function generateImportStatements(packages, destinationPackages, sourcePackages,
1568
1677
  }
1569
1678
  return { importStatements, examplesMappings };
1570
1679
  }
1571
- async function createEntryPoint(flowConfig, buildOptions, packagePaths) {
1572
- const destinationPackages = detectDestinationPackages(flowConfig);
1573
- const sourcePackages = detectSourcePackages(flowConfig);
1574
- const transformerPackages = detectTransformerPackages(flowConfig);
1575
- const explicitCodeImports = detectExplicitCodeImports(flowConfig);
1680
+ function validateComponentNames(components, section) {
1681
+ for (const name of Object.keys(components)) {
1682
+ if (!VALID_JS_IDENTIFIER.test(name)) {
1683
+ throw new Error(
1684
+ `Invalid ${section} name "${name}": must be a valid JavaScript identifier (use camelCase, e.g., "${name.replace(/-([a-z])/g, (_2, c2) => c2.toUpperCase())}")`
1685
+ );
1686
+ }
1687
+ }
1688
+ }
1689
+ function validateStoreReferences(flowSettings, storeIds) {
1690
+ const refs = [];
1691
+ function collectRefs(obj, path15) {
1692
+ if (typeof obj === "string" && obj.startsWith("$store:")) {
1693
+ refs.push({ ref: obj.slice(7), location: path15 });
1694
+ } else if (obj && typeof obj === "object") {
1695
+ for (const [key, val] of Object.entries(obj)) {
1696
+ collectRefs(val, `${path15}.${key}`);
1697
+ }
1698
+ }
1699
+ }
1700
+ for (const [section, components] of Object.entries({
1701
+ sources: flowSettings.sources || {},
1702
+ destinations: flowSettings.destinations || {},
1703
+ transformers: flowSettings.transformers || {}
1704
+ })) {
1705
+ for (const [id, component] of Object.entries(
1706
+ components
1707
+ )) {
1708
+ collectRefs(component, `${section}.${id}`);
1709
+ }
1710
+ }
1711
+ for (const { ref, location } of refs) {
1712
+ if (!storeIds.has(ref)) {
1713
+ const available = storeIds.size > 0 ? `Available stores: ${Array.from(storeIds).join(", ")}` : "No stores defined";
1714
+ throw new Error(
1715
+ `Store reference "$store:${ref}" in ${location} \u2014 store "${ref}" not found. ${available}`
1716
+ );
1717
+ }
1718
+ }
1719
+ }
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);
1726
+ const storeIds = new Set(
1727
+ Object.keys(
1728
+ flowSettings.stores || {}
1729
+ )
1730
+ );
1731
+ validateStoreReferences(flowSettings, storeIds);
1732
+ const flowWithSections = flowSettings;
1733
+ if (flowWithSections.sources)
1734
+ validateComponentNames(flowWithSections.sources, "sources");
1735
+ if (flowWithSections.destinations)
1736
+ validateComponentNames(flowWithSections.destinations, "destinations");
1737
+ if (flowWithSections.transformers)
1738
+ validateComponentNames(flowWithSections.transformers, "transformers");
1739
+ if (flowWithSections.stores)
1740
+ validateComponentNames(flowWithSections.stores, "stores");
1576
1741
  const { importStatements } = generateImportStatements(
1577
1742
  buildOptions.packages,
1578
1743
  destinationPackages,
1579
1744
  sourcePackages,
1580
1745
  transformerPackages,
1746
+ storePackages,
1581
1747
  explicitCodeImports
1582
1748
  );
1583
1749
  const importsCode = importStatements.join("\n");
1584
- const hasFlow = Object.values(flowConfig.sources || {}).some(
1750
+ const hasFlow = Object.values(flowSettings.sources || {}).some(
1585
1751
  (s2) => s2.package || isInlineCode(s2.code)
1586
- ) || Object.values(flowConfig.destinations || {}).some(
1752
+ ) || Object.values(flowSettings.destinations || {}).some(
1587
1753
  (d2) => d2.package || isInlineCode(d2.code)
1588
1754
  );
1589
1755
  if (!hasFlow) {
@@ -1592,8 +1758,12 @@ async function createEntryPoint(flowConfig, buildOptions, packagePaths) {
1592
1758
 
1593
1759
  ${userCode}` : userCode;
1594
1760
  }
1595
- const configObject = buildConfigObject(flowConfig, explicitCodeImports);
1761
+ const { storesDeclaration, configObject } = buildConfigObject(
1762
+ flowSettings,
1763
+ explicitCodeImports
1764
+ );
1596
1765
  const wrappedCode = generatePlatformWrapper(
1766
+ storesDeclaration,
1597
1767
  configObject,
1598
1768
  buildOptions.code || "",
1599
1769
  buildOptions
@@ -1625,11 +1795,12 @@ ${firstError.text}`
1625
1795
  ` + (location ? ` at ${location.file}:${location.line}:${location.column}` : "")
1626
1796
  );
1627
1797
  }
1628
- function buildConfigObject(flowConfig, explicitCodeImports) {
1629
- const flowWithProps = flowConfig;
1798
+ function buildConfigObject(flowSettings, explicitCodeImports) {
1799
+ const flowWithProps = flowSettings;
1630
1800
  const sources = flowWithProps.sources || {};
1631
1801
  const destinations = flowWithProps.destinations || {};
1632
1802
  const transformers = flowWithProps.transformers || {};
1803
+ const stores = flowWithProps.stores || {};
1633
1804
  Object.entries(sources).forEach(([name, source]) => {
1634
1805
  if (source.code !== true) {
1635
1806
  validateReference("Source", name, source);
@@ -1711,20 +1882,48 @@ function buildConfigObject(flowConfig, explicitCodeImports) {
1711
1882
  config: ${configStr}${envStr}${nextStr}
1712
1883
  }`;
1713
1884
  });
1885
+ Object.entries(stores).forEach(([name, store]) => {
1886
+ if (store.package || isInlineCode(store.code)) {
1887
+ validateReference("Store", name, store);
1888
+ }
1889
+ });
1890
+ const storesEntries = Object.entries(stores).filter(([, store]) => store.package || isInlineCode(store.code)).map(([key, store]) => {
1891
+ if (isInlineCode(store.code)) {
1892
+ return ` ${key}: ${generateInlineCode(store.code, store.config || {}, store.env)}`;
1893
+ }
1894
+ let codeVar;
1895
+ if (store.code && typeof store.code === "string" && explicitCodeImports.has(store.package)) {
1896
+ codeVar = store.code;
1897
+ } else {
1898
+ codeVar = packageNameToVariable(store.package);
1899
+ }
1900
+ const configStr = store.config ? processConfigValue(store.config) : "{}";
1901
+ const envStr = store.env ? `,
1902
+ env: ${processConfigValue(store.env)}` : "";
1903
+ return ` ${key}: {
1904
+ code: ${codeVar},
1905
+ config: ${configStr}${envStr}
1906
+ }`;
1907
+ });
1908
+ const storesDeclaration = storesEntries.length > 0 ? `const stores = {
1909
+ ${storesEntries.join(",\n")}
1910
+ };` : "const stores = {};";
1714
1911
  const collectorStr = flowWithProps.collector ? `,
1715
1912
  ...${processConfigValue(flowWithProps.collector)}` : "";
1716
1913
  const transformersStr = transformersEntries.length > 0 ? `,
1717
1914
  transformers: {
1718
1915
  ${transformersEntries.join(",\n")}
1719
1916
  }` : "";
1720
- return `{
1917
+ const configObject = `{
1721
1918
  sources: {
1722
1919
  ${sourcesEntries.join(",\n")}
1723
1920
  },
1724
1921
  destinations: {
1725
1922
  ${destinationsEntries.join(",\n")}
1726
- }${transformersStr}${collectorStr}
1923
+ }${transformersStr},
1924
+ stores${collectorStr}
1727
1925
  }`;
1926
+ return { storesDeclaration, configObject };
1728
1927
  }
1729
1928
  function processConfigValue(value) {
1730
1929
  return serializeWithCode(value, 0);
@@ -1733,6 +1932,10 @@ function serializeWithCode(value, indent) {
1733
1932
  const spaces = " ".repeat(indent);
1734
1933
  const nextSpaces = " ".repeat(indent + 1);
1735
1934
  if (typeof value === "string") {
1935
+ if (value.startsWith("$store:")) {
1936
+ const storeId = value.slice(7);
1937
+ return `stores.${storeId}`;
1938
+ }
1736
1939
  if (value.startsWith("$code:")) {
1737
1940
  return value.slice(6);
1738
1941
  }
@@ -1789,7 +1992,7 @@ ${spaces}}`;
1789
1992
  }
1790
1993
  return JSON.stringify(value);
1791
1994
  }
1792
- function generatePlatformWrapper(configObject, userCode, buildOptions) {
1995
+ function generatePlatformWrapper(storesDeclaration, configObject, userCode, buildOptions) {
1793
1996
  if (buildOptions.platform === "browser") {
1794
1997
  const windowAssignments = [];
1795
1998
  if (buildOptions.windowCollector) {
@@ -1804,6 +2007,8 @@ function generatePlatformWrapper(configObject, userCode, buildOptions) {
1804
2007
  }
1805
2008
  const assignments = windowAssignments.length > 0 ? "\n" + windowAssignments.join("\n") : "";
1806
2009
  return `(async () => {
2010
+ ${storesDeclaration}
2011
+
1807
2012
  const config = ${configObject};
1808
2013
 
1809
2014
  ${userCode}
@@ -1815,6 +2020,8 @@ function generatePlatformWrapper(configObject, userCode, buildOptions) {
1815
2020
  ${userCode}
1816
2021
  ` : "";
1817
2022
  return `export default async function(context = {}) {
2023
+ ${storesDeclaration}
2024
+
1818
2025
  const config = ${configObject};${codeSection}
1819
2026
  // Apply context overrides (e.g., logger config from CLI)
1820
2027
  if (context.logger) {
@@ -1841,6 +2048,16 @@ function generatePlatformWrapper(configObject, userCode, buildOptions) {
1841
2048
  }`;
1842
2049
  }
1843
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
+ });
1844
2061
 
1845
2062
  // src/commands/bundle/upload.ts
1846
2063
  import fs9 from "fs-extra";
@@ -1870,32 +2087,42 @@ async function uploadBundleToUrl(filePath, url, timeoutMs = 3e4) {
1870
2087
  };
1871
2088
  await doUpload(1);
1872
2089
  }
2090
+ var init_upload = __esm({
2091
+ "src/commands/bundle/upload.ts"() {
2092
+ "use strict";
2093
+ }
2094
+ });
1873
2095
 
1874
2096
  // src/commands/bundle/stats.ts
1875
- function displayStats(stats, logger2) {
1876
- logger2.info("\n\u{1F4CA} Bundle Statistics");
1877
- logger2.info("\u2500".repeat(50));
2097
+ function displayStats(stats, logger) {
2098
+ logger.info("\n\u{1F4CA} Bundle Statistics");
2099
+ logger.info("\u2500".repeat(50));
1878
2100
  const sizeKB = formatBytes(stats.totalSize);
1879
- logger2.info(`Total Size: ${sizeKB} KB`);
2101
+ logger.info(`Total Size: ${sizeKB} KB`);
1880
2102
  const timeSeconds = (stats.buildTime / 1e3).toFixed(2);
1881
- logger2.info(`Build Time: ${timeSeconds}s`);
2103
+ logger.info(`Build Time: ${timeSeconds}s`);
1882
2104
  const treeshakingStatus = stats.treeshakingEffective ? "\u2705 Effective" : "\u26A0\uFE0F Not optimal (consider using named imports)";
1883
- logger2.info(`Tree-shaking: ${treeshakingStatus}`);
2105
+ logger.info(`Tree-shaking: ${treeshakingStatus}`);
1884
2106
  if (stats.packages.length > 0) {
1885
- logger2.info(`
2107
+ logger.info(`
1886
2108
  Package Breakdown:`);
1887
2109
  stats.packages.forEach((pkg) => {
1888
2110
  if (pkg.size > 0) {
1889
2111
  const pkgSizeKB = formatBytes(pkg.size);
1890
- logger2.info(` \u2022 ${pkg.name}: ${pkgSizeKB} KB`);
2112
+ logger.info(` \u2022 ${pkg.name}: ${pkgSizeKB} KB`);
1891
2113
  }
1892
2114
  });
1893
2115
  }
1894
- logger2.info("\u2500".repeat(50));
2116
+ logger.info("\u2500".repeat(50));
1895
2117
  }
2118
+ var init_stats = __esm({
2119
+ "src/commands/bundle/stats.ts"() {
2120
+ "use strict";
2121
+ init_core();
2122
+ }
2123
+ });
1896
2124
 
1897
2125
  // src/core/api-client.ts
1898
- init_auth();
1899
2126
  import createClient from "openapi-fetch";
1900
2127
  function createApiClient() {
1901
2128
  const token = getToken();
@@ -1908,14 +2135,58 @@ function createApiClient() {
1908
2135
  }
1909
2136
  });
1910
2137
  }
2138
+ var init_api_client = __esm({
2139
+ "src/core/api-client.ts"() {
2140
+ "use strict";
2141
+ init_auth();
2142
+ }
2143
+ });
2144
+
2145
+ // src/commands/bundle/dockerfile.ts
2146
+ import path10 from "path";
2147
+ import fs10 from "fs-extra";
2148
+ function buildDockerfileContent(platform, includedFolders) {
2149
+ const bundleFile = platform === "web" ? "walker.js" : "bundle.mjs";
2150
+ const lines = [
2151
+ "# Generated by walkeros CLI",
2152
+ "FROM walkeros/flow:latest",
2153
+ "",
2154
+ `COPY ${bundleFile} /app/flow/${bundleFile}`
2155
+ ];
2156
+ for (const folder of includedFolders) {
2157
+ const name = path10.basename(folder);
2158
+ lines.push(`COPY ${name}/ /app/flow/${name}/`);
2159
+ }
2160
+ lines.push("", `ENV BUNDLE=/app/flow/${bundleFile}`, "", "EXPOSE 8080", "");
2161
+ return lines.join("\n");
2162
+ }
2163
+ async function generateDockerfile(outputDir, platform, logger, customFile, includedFolders) {
2164
+ const destPath = path10.join(outputDir, "Dockerfile");
2165
+ if (customFile && await fs10.pathExists(customFile)) {
2166
+ await fs10.copy(customFile, destPath);
2167
+ logger.info(`Dockerfile: ${destPath} (copied from ${customFile})`);
2168
+ return;
2169
+ }
2170
+ const dockerfile = buildDockerfileContent(platform, includedFolders || []);
2171
+ await fs10.writeFile(destPath, dockerfile);
2172
+ logger.info(`Dockerfile: ${destPath}`);
2173
+ }
2174
+ var init_dockerfile = __esm({
2175
+ "src/commands/bundle/dockerfile.ts"() {
2176
+ "use strict";
2177
+ }
2178
+ });
1911
2179
 
1912
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";
1913
2184
  function resolveOutputPath(output, buildOptions) {
1914
- const resolved = path10.resolve(output);
1915
- const ext = path10.extname(resolved);
1916
- if (output.endsWith("/") || output.endsWith(path10.sep) || !ext) {
2185
+ const resolved = path11.resolve(output);
2186
+ const ext = path11.extname(resolved);
2187
+ if (output.endsWith("/") || output.endsWith(path11.sep) || !ext) {
1917
2188
  const filename = buildOptions.platform === "browser" ? "walker.js" : "bundle.mjs";
1918
- return path10.join(resolved, filename);
2189
+ return path11.join(resolved, filename);
1919
2190
  }
1920
2191
  return resolved;
1921
2192
  }
@@ -1923,7 +2194,7 @@ async function bundleCommand(options) {
1923
2194
  const timer = createTimer();
1924
2195
  timer.start();
1925
2196
  const writingToStdout = !options.output;
1926
- const logger2 = createCLILogger({
2197
+ const logger = createCLILogger({
1927
2198
  ...options,
1928
2199
  stderr: writingToStdout
1929
2200
  });
@@ -1945,22 +2216,22 @@ async function bundleCommand(options) {
1945
2216
  } catch {
1946
2217
  throw new Error("Invalid JSON received on stdin");
1947
2218
  }
1948
- configPath = path10.resolve(process.cwd(), "stdin.config.json");
2219
+ configPath = path11.resolve(process.cwd(), "stdin.config.json");
1949
2220
  } else {
1950
2221
  const file = options.config || "bundle.config.json";
1951
2222
  configPath = resolveAsset(file, "config");
1952
2223
  rawConfig = await loadJsonConfig(configPath);
1953
2224
  }
1954
- const configsToBundle = options.all ? loadAllFlows(rawConfig, { configPath, logger: logger2 }) : [
2225
+ const configsToBundle = options.all ? loadAllFlows(rawConfig, { configPath, logger }) : [
1955
2226
  loadBundleConfig(rawConfig, {
1956
2227
  configPath,
1957
2228
  flowName: options.flow,
1958
- logger: logger2
2229
+ logger
1959
2230
  })
1960
2231
  ];
1961
2232
  const results = [];
1962
2233
  for (const {
1963
- flowConfig,
2234
+ flowSettings,
1964
2235
  buildOptions,
1965
2236
  flowName,
1966
2237
  isMultiFlow
@@ -1984,36 +2255,42 @@ async function bundleCommand(options) {
1984
2255
  buildOptions.output = getTmpPath(void 0, "stdout-bundle" + ext);
1985
2256
  }
1986
2257
  if (isMultiFlow || options.all) {
1987
- logger2.info(`Bundling flow: ${flowName}...`);
2258
+ logger.info(`Bundling flow: ${flowName}...`);
1988
2259
  } else {
1989
- logger2.info("Bundling...");
2260
+ logger.info("Bundling...");
1990
2261
  }
1991
2262
  const shouldCollectStats = options.stats || options.json;
1992
2263
  const stats = await bundleCore(
1993
- flowConfig,
2264
+ flowSettings,
1994
2265
  buildOptions,
1995
- logger2,
2266
+ logger,
1996
2267
  shouldCollectStats
1997
2268
  );
1998
2269
  results.push({ flowName, success: true, stats });
1999
2270
  if (uploadUrl) {
2000
2271
  await uploadBundleToUrl(buildOptions.output, uploadUrl);
2001
- logger2.info(`Uploaded to: ${sanitizeUrl(uploadUrl)}`);
2002
- await fs10.remove(buildOptions.output);
2272
+ logger.info(`Uploaded to: ${sanitizeUrl(uploadUrl)}`);
2273
+ await fs11.remove(buildOptions.output);
2003
2274
  }
2004
2275
  if (!options.json && !options.all && options.stats && stats) {
2005
- displayStats(stats, logger2);
2276
+ displayStats(stats, logger);
2006
2277
  }
2007
2278
  if (writingToStdout && !options.json) {
2008
- const bundleContent = await fs10.readFile(buildOptions.output);
2279
+ const bundleContent = await fs11.readFile(buildOptions.output);
2009
2280
  await writeResult(bundleContent, {});
2010
2281
  }
2011
2282
  if (options.dockerfile && options.output) {
2012
- const platform = getPlatform2(flowConfig);
2283
+ const platform = getPlatform2(flowSettings);
2013
2284
  if (platform) {
2014
- const outputDir = path10.dirname(buildOptions.output);
2285
+ const outputDir = path11.dirname(buildOptions.output);
2015
2286
  const customFile = typeof options.dockerfile === "string" ? options.dockerfile : void 0;
2016
- await generateDockerfile(outputDir, platform, logger2, customFile);
2287
+ await generateDockerfile(
2288
+ outputDir,
2289
+ platform,
2290
+ logger,
2291
+ customFile,
2292
+ buildOptions.include
2293
+ );
2017
2294
  }
2018
2295
  }
2019
2296
  } catch (error) {
@@ -2047,12 +2324,12 @@ async function bundleCommand(options) {
2047
2324
  });
2048
2325
  } else {
2049
2326
  if (options.all) {
2050
- logger2.info(
2327
+ logger.info(
2051
2328
  `
2052
2329
  Build Summary: ${successCount}/${results.length} succeeded`
2053
2330
  );
2054
2331
  if (failureCount > 0) {
2055
- logger2.error(`Failed: ${failureCount}`);
2332
+ logger.error(`Failed: ${failureCount}`);
2056
2333
  }
2057
2334
  }
2058
2335
  if (failureCount > 0) {
@@ -2069,21 +2346,21 @@ Build Summary: ${successCount}/${results.length} succeeded`
2069
2346
  output: options.output
2070
2347
  });
2071
2348
  } else {
2072
- logger2.error(`Error: ${errorMessage}`);
2349
+ logger.error(`Error: ${errorMessage}`);
2073
2350
  }
2074
2351
  process.exit(1);
2075
2352
  }
2076
2353
  }
2077
2354
  async function bundle(configOrPath, options = {}) {
2078
2355
  let rawConfig;
2079
- let configPath = path10.resolve(process.cwd(), "walkeros.config.json");
2356
+ let configPath = path11.resolve(process.cwd(), "walkeros.config.json");
2080
2357
  if (typeof configOrPath === "string") {
2081
2358
  configPath = resolveAsset(configOrPath, "config");
2082
2359
  rawConfig = await loadJsonConfig(configPath);
2083
2360
  } else {
2084
2361
  rawConfig = configOrPath;
2085
2362
  }
2086
- const { flowConfig, buildOptions } = loadBundleConfig(rawConfig, {
2363
+ const { flowSettings, buildOptions } = loadBundleConfig(rawConfig, {
2087
2364
  configPath,
2088
2365
  flowName: options.flowName,
2089
2366
  buildOverrides: options.buildOverrides
@@ -2091,35 +2368,14 @@ async function bundle(configOrPath, options = {}) {
2091
2368
  if (options.cache !== void 0) {
2092
2369
  buildOptions.cache = options.cache;
2093
2370
  }
2094
- const logger2 = createCLILogger(options);
2371
+ const logger = createCLILogger(options);
2095
2372
  return await bundleCore(
2096
- flowConfig,
2373
+ flowSettings,
2097
2374
  buildOptions,
2098
- logger2,
2375
+ logger,
2099
2376
  options.stats ?? false
2100
2377
  );
2101
2378
  }
2102
- async function generateDockerfile(outputDir, platform, logger2, customFile) {
2103
- const destPath = path10.join(outputDir, "Dockerfile");
2104
- if (customFile && await fs10.pathExists(customFile)) {
2105
- await fs10.copy(customFile, destPath);
2106
- logger2.info(`Dockerfile: ${destPath} (copied from ${customFile})`);
2107
- return;
2108
- }
2109
- const isWeb = platform === "web";
2110
- const bundleFile = isWeb ? "walker.js" : "bundle.mjs";
2111
- const dockerfile = `# Generated by walkeros CLI
2112
- FROM walkeros/flow:latest
2113
-
2114
- COPY ${bundleFile} /app/flow/${bundleFile}
2115
-
2116
- ENV BUNDLE=/app/flow/${bundleFile}
2117
-
2118
- EXPOSE 8080
2119
- `;
2120
- await fs10.writeFile(destPath, dockerfile);
2121
- logger2.info(`Dockerfile: ${destPath}`);
2122
- }
2123
2379
  async function bundleRemote(options) {
2124
2380
  const client = createApiClient();
2125
2381
  const body = { flow: options.content };
@@ -2138,19 +2394,122 @@ async function bundleRemote(options) {
2138
2394
  stats: statsHeader ? JSON.parse(statsHeader) : void 0
2139
2395
  };
2140
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();
2141
2501
 
2142
2502
  // src/commands/simulate/simulator.ts
2143
- import fs11 from "fs-extra";
2144
- import { Level as Level2 } from "@walkeros/core";
2503
+ import fs12 from "fs-extra";
2145
2504
 
2146
2505
  // ../collector/dist/index.mjs
2147
2506
  import { assign as o } from "@walkeros/core";
2148
- import { assign as i, createLogger as r } from "@walkeros/core";
2149
- import { assign as a, clone as c, debounce as u, getId as f, getGrantedConsent as l, isDefined as d, isFunction as g, isObject as m, processEventMapping as p, tryCatchAsync as h, useHooks as w } from "@walkeros/core";
2507
+ import { assign as r, createLogger as i } from "@walkeros/core";
2508
+ import { assign as a, clone as c, debounce as u, getId as f, getGrantedConsent as l, isDefined as g, isFunction as d, isObject as m, processEventMapping as p, tryCatchAsync as h, useHooks as w } from "@walkeros/core";
2150
2509
  import { isArray as y } from "@walkeros/core";
2151
2510
  import { tryCatch as b, tryCatchAsync as v } from "@walkeros/core";
2152
2511
  import { getMappingValue as k, tryCatchAsync as C } from "@walkeros/core";
2153
- 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";
2154
2513
  import { assign as M, getId as Q, isFunction as V, isString as _ } from "@walkeros/core";
2155
2514
  import { isObject as K } from "@walkeros/core";
2156
2515
  import { getGrantedConsent as en, processEventMapping as tn, tryCatchAsync as on, useHooks as sn } from "@walkeros/core";
@@ -2190,58 +2549,58 @@ function E(n, e2 = {}) {
2190
2549
  }
2191
2550
  return t2;
2192
2551
  }
2193
- async function P(n, e2, t2) {
2552
+ async function x(n, e2, t2) {
2194
2553
  if (e2.init && !e2.config.init) {
2195
- const o2 = e2.type || "unknown", s2 = n.logger.scope(`transformer:${o2}`), i2 = { collector: n, logger: s2, id: t2, config: e2.config, env: $(e2.config.env) };
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) };
2196
2555
  s2.debug("init");
2197
- const r2 = await j(e2.init, "TransformerInit", n.hooks)(i2);
2198
- if (false === r2) return false;
2199
- e2.config = { ...r2 || e2.config, init: true }, s2.debug("init done");
2556
+ const i2 = await q(e2.init, "TransformerInit", n.hooks)(r2);
2557
+ if (false === i2) return false;
2558
+ e2.config = { ...i2 || e2.config, init: true }, s2.debug("init done");
2200
2559
  }
2201
2560
  return true;
2202
2561
  }
2203
- async function x(n, e2, t2, o2, s2, i2) {
2204
- const r2 = e2.type || "unknown", a2 = n.logger.scope(`transformer:${r2}`), c2 = { collector: n, logger: a2, id: t2, ingest: s2, config: e2.config, env: { ...$(e2.config.env), ...i2 ? { respond: i2 } : {} } };
2562
+ async function P(n, e2, t2, o2, s2, r2) {
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 } : {} } };
2205
2564
  a2.debug("push", { event: o2.name });
2206
- const u2 = await j(e2.push, "TransformerPush", n.hooks)(o2, c2);
2565
+ const u2 = await q(e2.push, "TransformerPush", n.hooks)(o2, c2);
2207
2566
  return a2.debug("push done"), u2;
2208
2567
  }
2209
- async function S(n, e2, t2, o2, s2, i2) {
2210
- let r2 = o2, a2 = i2;
2568
+ async function S(n, e2, t2, o2, s2, r2) {
2569
+ let i2 = o2, a2 = r2;
2211
2570
  for (const o3 of t2) {
2212
2571
  const t3 = e2[o3];
2213
2572
  if (!t3) {
2214
2573
  n.logger.warn(`Transformer not found: ${o3}`);
2215
2574
  continue;
2216
2575
  }
2217
- if (!await q(P)(n, t3, o3)) return n.logger.error(`Transformer init failed: ${o3}`), null;
2218
- const i3 = await q(x, (e3) => (n.logger.scope(`transformer:${t3.type || "unknown"}`).error("Push failed", { error: e3 }), false))(n, t3, o3, r2, s2, a2);
2219
- if (false === i3) return null;
2220
- if (i3 && "object" == typeof i3) {
2221
- const { event: t4, respond: o4, next: c2 } = i3;
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);
2578
+ if (false === r3) return null;
2579
+ if (r3 && "object" == typeof r3) {
2580
+ const { event: t4, respond: o4, next: c2 } = r3;
2222
2581
  if (o4 && (a2 = o4), c2) {
2223
2582
  const o5 = E(c2, D(e2));
2224
- return o5.length > 0 ? S(n, e2, o5, t4 || r2, s2, a2) : (n.logger.warn(`Branch target not found: ${JSON.stringify(c2)}`), null);
2583
+ return o5.length > 0 ? S(n, e2, o5, t4 || i2, s2, a2) : (n.logger.warn(`Branch target not found: ${JSON.stringify(c2)}`), null);
2225
2584
  }
2226
- t4 && (r2 = t4);
2585
+ t4 && (i2 = t4);
2227
2586
  }
2228
2587
  }
2229
- return r2;
2588
+ return i2;
2230
2589
  }
2231
2590
  function $(n) {
2232
2591
  return n && O(n) ? n : {};
2233
2592
  }
2234
2593
  async function R(n, e2, t2) {
2235
- const { code: o2, config: s2 = {}, env: i2 = {}, primary: r2, next: a2 } = t2;
2594
+ const { code: o2, config: s2 = {}, env: r2 = {}, primary: i2, next: a2 } = t2;
2236
2595
  let c2, u2;
2237
- const f2 = E(a2, D(n.transformers)), l2 = n.logger.scope("source").scope(e2), d2 = { push: (t3, o3 = {}) => n.push(t3, { ...o3, id: e2, ingest: c2, respond: u2, mapping: s2, preChain: f2 }), command: n.command, sources: n.sources, elb: n.sources.elb.push, logger: l2, ...i2 }, g2 = { collector: n, logger: l2, id: e2, config: s2, env: d2, setIngest: async (e3) => {
2596
+ const f2 = E(a2, D(n.transformers)), l2 = n.logger.scope("source").scope(e2), g2 = { push: (t3, o3 = {}) => n.push(t3, { ...o3, id: e2, ingest: c2, respond: u2, mapping: s2, preChain: f2 }), command: n.command, sources: n.sources, elb: n.sources.elb.push, logger: l2, ...r2 }, d2 = { collector: n, logger: l2, id: e2, config: s2, env: g2, setIngest: async (e3) => {
2238
2597
  c2 = s2.ingest ? await k(e3, s2.ingest, { collector: n }) : void 0;
2239
2598
  }, setRespond: (n2) => {
2240
2599
  u2 = n2;
2241
- } }, m2 = await C(o2)(g2);
2600
+ } }, m2 = await C(o2)(d2);
2242
2601
  if (!m2) return;
2243
2602
  const p2 = m2.type || "unknown", h2 = n.logger.scope(p2).scope(e2);
2244
- return d2.logger = h2, r2 && (m2.config = { ...m2.config, primary: r2 }), m2;
2603
+ return g2.logger = h2, i2 && (m2.config = { ...m2.config, primary: i2 }), m2;
2245
2604
  }
2246
2605
  async function T(n, e2 = {}) {
2247
2606
  const t2 = {};
@@ -2251,81 +2610,81 @@ async function T(n, e2 = {}) {
2251
2610
  n.pending.sources[o2] = s2;
2252
2611
  continue;
2253
2612
  }
2254
- const i2 = await R(n, o2, s2);
2255
- i2 && (t2[o2] = i2);
2613
+ const r2 = await R(n, o2, s2);
2614
+ r2 && (t2[o2] = r2);
2256
2615
  }
2257
2616
  return t2;
2258
2617
  }
2259
2618
  async function I(n, e2, t2) {
2260
- const o2 = n.on, s2 = o2[e2] || [], i2 = y(t2) ? t2 : [t2];
2261
- i2.forEach((n2) => {
2619
+ const o2 = n.on, s2 = o2[e2] || [], r2 = y(t2) ? t2 : [t2];
2620
+ r2.forEach((n2) => {
2262
2621
  s2.push(n2);
2263
- }), o2[e2] = s2, await G(n, e2, i2);
2622
+ }), o2[e2] = s2, await G(n, e2, r2);
2264
2623
  }
2265
2624
  function B(n, e2, t2, o2, s2) {
2266
2625
  if (!e2.on) return;
2267
- const i2 = e2.type || "unknown", r2 = n.logger.scope(i2).scope("on").scope(o2), a2 = { collector: n, logger: r2, id: t2, config: e2.config, data: s2, env: L(e2.env, e2.config.env) };
2626
+ const r2 = e2.type || "unknown", i2 = n.logger.scope(r2).scope("on").scope(o2), a2 = { collector: n, logger: i2, id: t2, config: e2.config, data: s2, env: L(e2.env, e2.config.env) };
2268
2627
  b(e2.on)(o2, a2);
2269
2628
  }
2270
2629
  async function G(n, e2, o2, s2) {
2271
- let i2, r2 = o2 || [];
2272
- switch (o2 || (r2 = n.on[e2] || []), e2) {
2630
+ let r2, i2 = o2 || [];
2631
+ switch (o2 || (i2 = n.on[e2] || []), e2) {
2273
2632
  case t.Commands.Consent:
2274
- i2 = s2 || n.consent;
2633
+ r2 = s2 || n.consent;
2275
2634
  break;
2276
2635
  case t.Commands.Session:
2277
- i2 = n.session;
2636
+ r2 = n.session;
2278
2637
  break;
2279
2638
  case t.Commands.User:
2280
- i2 = s2 || n.user;
2639
+ r2 = s2 || n.user;
2281
2640
  break;
2282
2641
  case t.Commands.Custom:
2283
- i2 = s2 || n.custom;
2642
+ r2 = s2 || n.custom;
2284
2643
  break;
2285
2644
  case t.Commands.Globals:
2286
- i2 = s2 || n.globals;
2645
+ r2 = s2 || n.globals;
2287
2646
  break;
2288
2647
  case t.Commands.Config:
2289
- i2 = s2 || n.config;
2648
+ r2 = s2 || n.config;
2290
2649
  break;
2291
2650
  case t.Commands.Ready:
2292
2651
  case t.Commands.Run:
2293
2652
  default:
2294
- i2 = void 0;
2653
+ r2 = void 0;
2295
2654
  }
2296
2655
  let a2 = false;
2297
2656
  for (const t2 of Object.values(n.sources)) if (t2.on) {
2298
- false === await v(t2.on)(e2, i2) && (a2 = true);
2657
+ false === await v(t2.on)(e2, r2) && (a2 = true);
2299
2658
  }
2300
2659
  if (Object.entries(n.destinations).forEach(([t2, o3]) => {
2301
2660
  if (o3.on) {
2302
- if (!o3.config.init) return o3.queueOn = o3.queueOn || [], void o3.queueOn.push({ type: e2, data: i2 });
2303
- B(n, o3, t2, e2, i2);
2661
+ if (!o3.config.init) return o3.queueOn = o3.queueOn || [], void o3.queueOn.push({ type: e2, data: r2 });
2662
+ B(n, o3, t2, e2, r2);
2304
2663
  }
2305
2664
  }), (Object.keys(n.pending.sources).length > 0 || Object.keys(n.pending.destinations).length > 0) && await (async function(n2, e3) {
2306
2665
  for (const [t2, o3] of Object.entries(n2.pending.sources)) {
2307
2666
  if (!n2.pending.sources[t2] || n2.sources[t2]) continue;
2308
2667
  const s3 = o3.config?.require;
2309
2668
  if (!s3) continue;
2310
- const i3 = s3.indexOf(e3);
2311
- if (-1 === i3) continue;
2312
- if (s3.splice(i3, 1), s3.length > 0) continue;
2669
+ const r3 = s3.indexOf(e3);
2670
+ if (-1 === r3) continue;
2671
+ if (s3.splice(r3, 1), s3.length > 0) continue;
2313
2672
  delete n2.pending.sources[t2];
2314
- const r3 = await R(n2, t2, o3);
2315
- r3 && (n2.sources[t2] = r3);
2673
+ const i3 = await R(n2, t2, o3);
2674
+ i3 && (n2.sources[t2] = i3);
2316
2675
  }
2317
2676
  for (const [t2, o3] of Object.entries(n2.pending.destinations)) {
2318
2677
  if (!n2.pending.destinations[t2] || n2.destinations[t2]) continue;
2319
2678
  const s3 = o3.config?.require;
2320
2679
  if (!s3) continue;
2321
- const i3 = s3.indexOf(e3);
2322
- if (-1 === i3) continue;
2323
- if (s3.splice(i3, 1), s3.length > 0) continue;
2680
+ const r3 = s3.indexOf(e3);
2681
+ if (-1 === r3) continue;
2682
+ if (s3.splice(r3, 1), s3.length > 0) continue;
2324
2683
  delete n2.pending.destinations[t2];
2325
- const r3 = W(o3);
2326
- false !== r3.config.queue && (r3.queuePush = [...n2.queue]), n2.destinations[t2] = r3;
2684
+ const i3 = W(o3);
2685
+ false !== i3.config.queue && (i3.queuePush = [...n2.queue]), n2.destinations[t2] = i3;
2327
2686
  }
2328
- })(n, e2), !r2.length) return !a2;
2687
+ })(n, e2), !i2.length) return !a2;
2329
2688
  switch (e2) {
2330
2689
  case t.Commands.Consent:
2331
2690
  !(function(n2, e3, t2) {
@@ -2335,7 +2694,7 @@ async function G(n, e2, o2, s2) {
2335
2694
  b(e4[t3])(n2, o3);
2336
2695
  });
2337
2696
  });
2338
- })(n, r2, s2);
2697
+ })(n, i2, s2);
2339
2698
  break;
2340
2699
  case t.Commands.Ready:
2341
2700
  case t.Commands.Run:
@@ -2343,7 +2702,7 @@ async function G(n, e2, o2, s2) {
2343
2702
  n2.allowed && e3.forEach((e4) => {
2344
2703
  b(e4)(n2);
2345
2704
  });
2346
- })(n, r2);
2705
+ })(n, i2);
2347
2706
  break;
2348
2707
  case t.Commands.Session:
2349
2708
  !(function(n2, e3) {
@@ -2351,19 +2710,19 @@ async function G(n, e2, o2, s2) {
2351
2710
  e3.forEach((e4) => {
2352
2711
  b(e4)(n2, n2.session);
2353
2712
  });
2354
- })(n, r2);
2713
+ })(n, i2);
2355
2714
  break;
2356
2715
  default:
2357
- r2.forEach((e3) => {
2358
- "function" == typeof e3 && b(e3)(n, i2);
2716
+ i2.forEach((e3) => {
2717
+ "function" == typeof e3 && b(e3)(n, r2);
2359
2718
  });
2360
2719
  }
2361
2720
  return !a2;
2362
2721
  }
2363
2722
  async function H(n, e2, t2) {
2364
- const { code: o2, config: s2 = {}, env: i2 = {}, before: r2 } = e2;
2365
- if (!g(o2.push)) return N({ ok: false, failed: { invalid: { type: "invalid", error: "Destination code must have a push method" } } });
2366
- const a2 = t2 || s2 || { init: false }, c2 = r2 ? { ...a2, before: r2 } : a2, u2 = { ...o2, config: c2, env: L(o2.env, i2) };
2723
+ const { code: o2, config: s2 = {}, env: r2 = {}, before: i2 } = e2;
2724
+ if (!d(o2.push)) return N({ ok: false, failed: { invalid: { type: "invalid", error: "Destination code must have a push method" } } });
2725
+ const a2 = t2 || s2 || { init: false }, c2 = i2 ? { ...a2, before: i2 } : a2, u2 = { ...o2, config: c2, env: L(o2.env, r2) };
2367
2726
  let l2 = u2.config.id;
2368
2727
  if (!l2) do {
2369
2728
  l2 = f(4);
@@ -2371,11 +2730,11 @@ async function H(n, e2, t2) {
2371
2730
  return n.destinations[l2] = u2, false !== u2.config.queue && (u2.queuePush = [...n.queue]), U(n, void 0, {}, { [l2]: u2 });
2372
2731
  }
2373
2732
  async function U(n, e2, t2 = {}, o2) {
2374
- const { allowed: s2, consent: i2, globals: r2, user: u2 } = n;
2733
+ const { allowed: s2, consent: r2, globals: i2, user: u2 } = n;
2375
2734
  if (!s2) return N({ ok: false });
2376
2735
  e2 && (n.queue.push(e2), n.status.in++), o2 || (o2 = n.destinations);
2377
2736
  const f2 = await Promise.all(Object.entries(o2 || {}).map(async ([o3, s3]) => {
2378
- let f3 = (s3.queuePush || []).map((n2) => ({ ...n2, consent: i2 }));
2737
+ let f3 = (s3.queuePush || []).map((n2) => ({ ...n2, consent: r2 }));
2379
2738
  if (s3.queuePush = [], e2) {
2380
2739
  const n2 = c(e2);
2381
2740
  f3.push(n2);
@@ -2385,11 +2744,11 @@ async function U(n, e2, t2 = {}, o2) {
2385
2744
  const e3 = await h(F)(n, s3, o3);
2386
2745
  return { id: o3, destination: s3, skipped: !e3 };
2387
2746
  }
2388
- const d3 = [], g3 = f3.filter((n2) => {
2389
- const e3 = l(s3.config.consent, i2, n2.consent);
2390
- return !e3 || (n2.consent = e3, d3.push(n2), false);
2747
+ const g3 = [], d3 = f3.filter((n2) => {
2748
+ const e3 = l(s3.config.consent, r2, n2.consent);
2749
+ return !e3 || (n2.consent = e3, g3.push(n2), false);
2391
2750
  });
2392
- if (s3.queuePush.push(...g3), !d3.length) return { id: o3, destination: s3, queue: f3 };
2751
+ if (s3.queuePush.push(...d3), !g3.length) return { id: o3, destination: s3, queue: f3 };
2393
2752
  if (!await h(F)(n, s3, o3)) return { id: o3, destination: s3, queue: f3 };
2394
2753
  let m3, p2;
2395
2754
  s3.dlq || (s3.dlq = []);
@@ -2398,50 +2757,50 @@ async function U(n, e2, t2 = {}, o2) {
2398
2757
  return t3 ? E(t3, D(e3)) : [];
2399
2758
  })(s3, n.transformers);
2400
2759
  let y2 = 0;
2401
- return await Promise.all(d3.map(async (e3) => {
2402
- e3.globals = a(r2, e3.globals), e3.user = a(u2, e3.user);
2403
- let i3 = e3;
2760
+ return await Promise.all(g3.map(async (e3) => {
2761
+ e3.globals = a(i2, e3.globals), e3.user = a(u2, e3.user);
2762
+ let r3 = e3;
2404
2763
  if (w2.length > 0 && n.transformers && Object.keys(n.transformers).length > 0) {
2405
2764
  const o4 = await S(n, n.transformers, w2, e3, t2.ingest, t2.respond);
2406
2765
  if (null === o4) return e3;
2407
- i3 = o4;
2766
+ r3 = o4;
2408
2767
  }
2409
2768
  const c2 = Date.now(), f4 = await h(J, (e4) => {
2410
2769
  const t3 = s3.type || "unknown";
2411
- n.logger.scope(t3).error("Push failed", { error: e4, event: i3.name }), m3 = e4, s3.dlq.push([i3, e4]);
2412
- })(n, s3, o3, i3, t2.ingest, t2.respond);
2770
+ n.logger.scope(t3).error("Push failed", { error: e4, event: r3.name }), m3 = e4, s3.dlq.push([r3, e4]);
2771
+ })(n, s3, o3, r3, t2.ingest, t2.respond);
2413
2772
  return y2 += Date.now() - c2, void 0 !== f4 && (p2 = f4), e3;
2414
2773
  })), { id: o3, destination: s3, error: m3, response: p2, totalDuration: y2 };
2415
- })), d2 = {}, g2 = {}, m2 = {};
2774
+ })), g2 = {}, d2 = {}, m2 = {};
2416
2775
  for (const e3 of f2) {
2417
2776
  if (e3.skipped) continue;
2418
- const t3 = e3.destination, o3 = { type: t3.type || "unknown", data: e3.response };
2777
+ const t3 = { type: e3.destination.type || "unknown", data: e3.response };
2419
2778
  n.status.destinations[e3.id] || (n.status.destinations[e3.id] = { count: 0, failed: 0, duration: 0 });
2420
- const s3 = n.status.destinations[e3.id], i3 = Date.now();
2421
- e3.error ? (o3.error = e3.error, m2[e3.id] = o3, s3.failed++, s3.lastAt = i3, s3.duration += e3.totalDuration || 0, n.status.failed++) : e3.queue && e3.queue.length ? (t3.queuePush = (t3.queuePush || []).concat(e3.queue), g2[e3.id] = o3) : (d2[e3.id] = o3, s3.count++, s3.lastAt = i3, 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++);
2422
2781
  }
2423
- return N({ event: e2, ...Object.keys(d2).length && { done: d2 }, ...Object.keys(g2).length && { queued: g2 }, ...Object.keys(m2).length && { failed: m2 } });
2782
+ return N({ event: e2, ...Object.keys(g2).length && { done: g2 }, ...Object.keys(d2).length && { queued: d2 }, ...Object.keys(m2).length && { failed: m2 } });
2424
2783
  }
2425
2784
  async function F(n, e2, t2) {
2426
2785
  if (e2.init && !e2.config.init) {
2427
- const o2 = e2.type || "unknown", s2 = n.logger.scope(o2), i2 = { collector: n, logger: s2, id: t2, config: e2.config, env: L(e2.env, e2.config.env) };
2786
+ const o2 = e2.type || "unknown", s2 = n.logger.scope(o2), r2 = { collector: n, logger: s2, id: t2, config: e2.config, env: L(e2.env, e2.config.env) };
2428
2787
  s2.debug("init");
2429
- const r2 = await w(e2.init, "DestinationInit", n.hooks)(i2);
2430
- if (false === r2) return r2;
2431
- if (e2.config = { ...r2 || e2.config, init: true }, e2.queueOn?.length) {
2788
+ const i2 = await w(e2.init, "DestinationInit", n.hooks)(r2);
2789
+ if (false === i2) return i2;
2790
+ if (e2.config = { ...i2 || e2.config, init: true }, e2.queueOn?.length) {
2432
2791
  const o3 = e2.queueOn;
2433
2792
  e2.queueOn = [];
2434
- for (const { type: s3, data: i3 } of o3) B(n, e2, t2, s3, i3);
2793
+ for (const { type: s3, data: r3 } of o3) B(n, e2, t2, s3, r3);
2435
2794
  }
2436
2795
  s2.debug("init done");
2437
2796
  }
2438
2797
  return true;
2439
2798
  }
2440
- async function J(n, e2, t2, o2, s2, i2) {
2441
- const { config: r2 } = e2, a2 = await p(o2, r2, n);
2799
+ async function J(n, e2, t2, o2, s2, r2) {
2800
+ const { config: i2 } = e2, a2 = await p(o2, i2, n);
2442
2801
  if (a2.ignore) return false;
2443
- const c2 = e2.type || "unknown", f2 = n.logger.scope(c2), l2 = { collector: n, logger: f2, id: t2, config: r2, data: a2.data, rule: a2.mapping, ingest: s2, env: { ...L(e2.env, r2.env), ...i2 ? { respond: i2 } : {} } }, g2 = a2.mapping, m2 = a2.mappingKey || "* *";
2444
- if (!g2?.batch || !e2.pushBatch) {
2802
+ const c2 = e2.type || "unknown", f2 = n.logger.scope(c2), l2 = { collector: n, logger: f2, id: t2, config: i2, data: a2.data, rule: a2.mapping, ingest: s2, env: { ...L(e2.env, i2.env), ...r2 ? { respond: r2 } : {} } }, d2 = a2.mapping, m2 = a2.mappingKey || "* *";
2803
+ if (!d2?.batch || !e2.pushBatch) {
2445
2804
  f2.debug("push", { event: a2.event.name });
2446
2805
  const t3 = await w(e2.push, "DestinationPush", n.hooks)(a2.event, l2);
2447
2806
  return f2.debug("push done"), t3;
@@ -2450,12 +2809,12 @@ async function J(n, e2, t2, o2, s2, i2) {
2450
2809
  if (e2.batches = e2.batches || {}, !e2.batches[m2]) {
2451
2810
  const o4 = { key: m2, events: [], data: [] };
2452
2811
  e2.batches[m2] = { batched: o4, batchFn: u(() => {
2453
- const o5 = e2.batches[m2].batched, a3 = { collector: n, logger: f2, id: t2, config: r2, data: void 0, rule: g2, ingest: s2, env: { ...L(e2.env, r2.env), ...i2 ? { respond: i2 } : {} } };
2812
+ const o5 = e2.batches[m2].batched, a3 = { collector: n, logger: f2, id: t2, config: i2, data: void 0, rule: d2, ingest: s2, env: { ...L(e2.env, i2.env), ...r2 ? { respond: r2 } : {} } };
2454
2813
  f2.debug("push batch", { events: o5.events.length }), w(e2.pushBatch, "DestinationPushBatch", n.hooks)(o5, a3), f2.debug("push batch done"), o5.events = [], o5.data = [];
2455
- }, g2.batch) };
2814
+ }, d2.batch) };
2456
2815
  }
2457
2816
  const o3 = e2.batches[m2];
2458
- o3.batched.events.push(a2.event), d(a2.data) && o3.batched.data.push(a2.data), o3.batchFn();
2817
+ o3.batched.events.push(a2.event), g(a2.data) && o3.batched.data.push(a2.data), o3.batchFn();
2459
2818
  }
2460
2819
  return true;
2461
2820
  }
@@ -2463,8 +2822,8 @@ function N(n) {
2463
2822
  return { ok: !n?.failed, ...n };
2464
2823
  }
2465
2824
  function W(n) {
2466
- const { code: e2, config: t2 = {}, env: o2 = {} } = n, { config: s2 } = A(n, "before"), i2 = { ...e2.config, ...t2, ...s2 }, r2 = L(e2.env, o2);
2467
- return { ...e2, config: i2, env: r2 };
2825
+ const { code: e2, config: t2 = {}, env: o2 = {} } = n, { config: s2 } = A(n, "before"), r2 = { ...e2.config, ...t2, ...s2 }, i2 = L(e2.env, o2);
2826
+ return { ...e2, config: r2, env: i2 };
2468
2827
  }
2469
2828
  async function z(n, e2 = {}) {
2470
2829
  const t2 = {};
@@ -2478,17 +2837,17 @@ async function X(n, e2, t2) {
2478
2837
  const o2 = Object.entries(n).map(async ([n2, o3]) => {
2479
2838
  const s2 = o3.destroy;
2480
2839
  if (!s2) return;
2481
- const i2 = o3.type || "unknown", r2 = t2.scope(i2), a2 = { id: n2, config: o3.config, env: o3.env ?? {}, logger: r2 };
2840
+ const r2 = o3.type || "unknown", i2 = t2.scope(r2), a2 = { id: n2, config: o3.config, env: o3.env ?? {}, logger: i2 };
2482
2841
  try {
2483
2842
  await Promise.race([s2(a2), new Promise((t3, o4) => setTimeout(() => o4(new Error(`${e2} '${n2}' destroy timed out`)), 5e3))]);
2484
2843
  } catch (t3) {
2485
- r2.error(`${e2} '${n2}' destroy failed: ${t3}`);
2844
+ i2.error(`${e2} '${n2}' destroy failed: ${t3}`);
2486
2845
  }
2487
2846
  });
2488
2847
  await Promise.allSettled(o2);
2489
2848
  }
2490
- async function Y(n, e2, o2, i2) {
2491
- let r2, a2, c2 = false, u2 = false;
2849
+ async function Y(n, e2, o2, r2) {
2850
+ let i2, a2, c2 = false, u2 = false;
2492
2851
  switch (e2) {
2493
2852
  case t.Commands.Config:
2494
2853
  K(o2) && (M(n.config, o2, { shallow: false }), a2 = o2, c2 = true);
@@ -2503,19 +2862,19 @@ async function Y(n, e2, o2, i2) {
2503
2862
  K(o2) && (n.custom = M(n.custom, o2), a2 = o2, c2 = true);
2504
2863
  break;
2505
2864
  case t.Commands.Destination:
2506
- K(o2) && ("code" in o2 && K(o2.code) ? r2 = await H(n, o2, i2) : V(o2.push) && (r2 = await H(n, { code: o2 }, i2)));
2865
+ K(o2) && ("code" in o2 && K(o2.code) ? i2 = await H(n, o2, r2) : V(o2.push) && (i2 = await H(n, { code: o2 }, r2)));
2507
2866
  break;
2508
2867
  case t.Commands.Globals:
2509
2868
  K(o2) && (n.globals = M(n.globals, o2), a2 = o2, c2 = true);
2510
2869
  break;
2511
2870
  case t.Commands.On:
2512
- _(o2) && await I(n, o2, i2);
2871
+ _(o2) && await I(n, o2, r2);
2513
2872
  break;
2514
2873
  case t.Commands.Ready:
2515
2874
  c2 = true;
2516
2875
  break;
2517
2876
  case t.Commands.Run:
2518
- r2 = await nn(n, o2), c2 = true;
2877
+ i2 = await nn(n, o2), c2 = true;
2519
2878
  break;
2520
2879
  case t.Commands.Session:
2521
2880
  c2 = true;
@@ -2523,21 +2882,21 @@ async function Y(n, e2, o2, i2) {
2523
2882
  case t.Commands.Shutdown:
2524
2883
  await (async function(n2) {
2525
2884
  const e3 = n2.logger;
2526
- await X(n2.sources, "source", e3), await X(n2.destinations, "destination", e3), await X(n2.transformers, "transformer", e3);
2885
+ await X(n2.sources, "source", e3), await X(n2.destinations, "destination", e3), await X(n2.transformers, "transformer", e3), await X(n2.stores, "store", e3);
2527
2886
  })(n);
2528
2887
  break;
2529
2888
  case t.Commands.User:
2530
2889
  K(o2) && (M(n.user, o2, { shallow: false }), a2 = o2, c2 = true);
2531
2890
  }
2532
- return c2 && await G(n, e2, void 0, a2), u2 && (r2 = await U(n)), r2 || N({ ok: true });
2891
+ return c2 && await G(n, e2, void 0, a2), u2 && (i2 = await U(n)), i2 || N({ ok: true });
2533
2892
  }
2534
2893
  function Z(n, e2) {
2535
2894
  if (!e2.name) throw new Error("Event name is required");
2536
2895
  const [t2, o2] = e2.name.split(" ");
2537
2896
  if (!t2 || !o2) throw new Error("Event name is invalid");
2538
2897
  ++n.count;
2539
- const { timestamp: s2 = Date.now(), group: i2 = n.group, count: r2 = n.count } = e2, { name: a2 = `${t2} ${o2}`, data: c2 = {}, context: u2 = {}, globals: f2 = n.globals, custom: l2 = {}, user: d2 = n.user, nested: g2 = [], consent: m2 = n.consent, id: p2 = `${s2}-${i2}-${r2}`, trigger: h2 = "", entity: w2 = t2, action: y2 = o2, timing: b2 = 0, version: v2 = { source: n.version, tagging: n.config.tagging || 0 }, source: k2 = { type: "collector", id: "", previous_id: "" } } = e2;
2540
- return { name: a2, data: c2, context: u2, globals: f2, custom: l2, user: d2, nested: g2, consent: m2, id: p2, trigger: h2, entity: w2, action: y2, timestamp: s2, timing: b2, group: i2, count: r2, version: v2, source: k2 };
2898
+ const { timestamp: s2 = Date.now(), group: r2 = n.group, count: i2 = n.count } = e2, { name: a2 = `${t2} ${o2}`, data: c2 = {}, context: u2 = {}, globals: f2 = n.globals, custom: l2 = {}, user: g2 = n.user, nested: d2 = [], consent: m2 = n.consent, id: p2 = `${s2}-${r2}-${i2}`, trigger: h2 = "", entity: w2 = t2, action: y2 = o2, timing: b2 = 0, version: v2 = { source: n.version, tagging: n.config.tagging || 0 }, source: k2 = { type: "collector", id: "", previous_id: "" } } = e2;
2899
+ return { name: a2, data: c2, context: u2, globals: f2, custom: l2, user: g2, nested: d2, consent: m2, id: p2, trigger: h2, entity: w2, action: y2, timestamp: s2, timing: b2, group: r2, count: i2, version: v2, source: k2 };
2541
2900
  }
2542
2901
  async function nn(n, e2) {
2543
2902
  n.allowed = true, n.count = 0, n.group = Q(), n.timing = Date.now(), e2 && (e2.consent && (n.consent = M(n.consent, e2.consent)), e2.user && (n.user = M(n.user, e2.user)), e2.globals && (n.globals = M(n.config.globalsStatic || {}, e2.globals)), e2.custom && (n.custom = M(n.custom, e2.custom))), Object.values(n.destinations).forEach((n2) => {
@@ -2547,9 +2906,9 @@ async function nn(n, e2) {
2547
2906
  }
2548
2907
  function rn(n, e2) {
2549
2908
  return sn(async (t2, o2 = {}) => await on(async () => {
2550
- const s2 = Date.now(), { id: i2, ingest: r2, respond: a2, mapping: c2, preChain: u2 } = o2;
2909
+ const s2 = Date.now(), { id: r2, ingest: i2, respond: a2, mapping: c2, preChain: u2 } = o2;
2551
2910
  let f2 = t2;
2552
- const l2 = r2 ? Object.freeze(r2) : void 0;
2911
+ const l2 = i2 ? Object.freeze(i2) : void 0;
2553
2912
  if (c2) {
2554
2913
  const e3 = await tn(f2, c2, n);
2555
2914
  if (e3.ignore) return N({ ok: true });
@@ -2563,23 +2922,30 @@ function rn(n, e2) {
2563
2922
  if (null === e3) return N({ ok: true });
2564
2923
  f2 = e3;
2565
2924
  }
2566
- const d2 = e2(f2), g2 = Z(n, d2), m2 = await U(n, g2, { id: i2, ingest: l2, respond: a2 });
2567
- if (i2) {
2568
- n.status.sources[i2] || (n.status.sources[i2] = { count: 0, duration: 0 });
2569
- const e3 = n.status.sources[i2];
2925
+ const g2 = e2(f2), d2 = Z(n, g2), m2 = await U(n, d2, { id: r2, ingest: l2, respond: a2 });
2926
+ if (r2) {
2927
+ n.status.sources[r2] || (n.status.sources[r2] = { count: 0, duration: 0 });
2928
+ const e3 = n.status.sources[r2];
2570
2929
  e3.count++, e3.lastAt = Date.now(), e3.duration += Date.now() - s2;
2571
2930
  }
2572
2931
  return m2;
2573
2932
  }, () => N({ ok: false }))(), "Push", n.hooks);
2574
2933
  }
2575
2934
  async function un(n) {
2576
- const e2 = i({ globalsStatic: {}, sessionStatic: {}, tagging: 0, run: true }, n, { merge: false, extend: false }), t2 = { level: n.logger?.level, handler: n.logger?.handler }, o2 = r(t2), s2 = { ...e2.globalsStatic, ...n.globals }, a2 = { allowed: false, config: e2, consent: n.consent || {}, count: 0, custom: n.custom || {}, destinations: {}, transformers: {}, globals: s2, group: "", hooks: {}, logger: o2, on: {}, queue: [], round: 0, session: void 0, status: { startedAt: Date.now(), in: 0, out: 0, failed: 0, sources: {}, destinations: {} }, timing: Date.now(), user: n.user || {}, version: "2.1.0", sources: {}, pending: { sources: {}, destinations: {} }, push: void 0, command: void 0 };
2935
+ const e2 = r({ globalsStatic: {}, sessionStatic: {}, tagging: 0, run: true }, n, { merge: false, extend: false }), t2 = { level: n.logger?.level, handler: n.logger?.handler }, o2 = i(t2), s2 = { ...e2.globalsStatic, ...n.globals }, a2 = { allowed: false, config: e2, consent: n.consent || {}, count: 0, custom: n.custom || {}, destinations: {}, transformers: {}, stores: {}, globals: s2, group: "", hooks: {}, logger: o2, on: {}, queue: [], round: 0, session: void 0, status: { startedAt: Date.now(), in: 0, out: 0, failed: 0, sources: {}, destinations: {} }, timing: Date.now(), user: n.user || {}, version: "2.1.1", sources: {}, pending: { sources: {}, destinations: {} }, push: void 0, command: void 0 };
2577
2936
  return a2.push = rn(a2, (n2) => ({ timing: Math.round((Date.now() - a2.timing) / 10) / 100, source: { type: "collector", id: "", previous_id: "" }, ...n2 })), a2.command = (function(n2, e3) {
2578
2937
  return an(async (t3, o3, s3) => await cn(async () => await e3(n2, t3, o3, s3), () => N({ ok: false }))(), "Command", n2.hooks);
2579
- })(a2, Y), a2.destinations = await z(a2, n.destinations || {}), a2.transformers = await (async function(n2, e3 = {}) {
2938
+ })(a2, Y), a2.stores = await (async function(n2, e3 = {}) {
2939
+ const t3 = {};
2940
+ for (const [o3, s3] of Object.entries(e3)) {
2941
+ const { code: e4, config: r2 = {}, env: i2 = {} } = s3, a3 = n2.logger.scope("store").scope(o3), c2 = { collector: n2, logger: a3, id: o3, config: r2, env: i2 }, u2 = await e4(c2);
2942
+ t3[o3] = u2;
2943
+ }
2944
+ return t3;
2945
+ })(a2, n.stores || {}), a2.destinations = await z(a2, n.destinations || {}), a2.transformers = await (async function(n2, e3 = {}) {
2580
2946
  const t3 = {};
2581
2947
  for (const [o3, s3] of Object.entries(e3)) {
2582
- const { code: e4, env: i2 = {} } = s3, { config: r2 } = A(s3, "next"), a3 = n2.logger.scope("transformer").scope(o3), c2 = { collector: n2, logger: a3, id: o3, config: r2, env: i2 }, u2 = await e4(c2);
2948
+ const { code: e4, env: r2 = {} } = s3, { config: i2 } = A(s3, "next"), a3 = n2.logger.scope("transformer").scope(o3), c2 = { collector: n2, logger: a3, id: o3, config: i2, env: r2 }, u2 = await e4(c2);
2583
2949
  t3[o3] = u2;
2584
2950
  }
2585
2951
  return t3;
@@ -2587,7 +2953,7 @@ async function un(n) {
2587
2953
  }
2588
2954
  async function fn(n) {
2589
2955
  n = n || {};
2590
- const e2 = await un(n), t2 = (o2 = e2, { type: "elb", config: {}, push: async (n2, e3, t3, s3, i3, r3) => {
2956
+ const e2 = await un(n), t2 = (o2 = e2, { type: "elb", config: {}, push: async (n2, e3, t3, s3, r3, i3) => {
2591
2957
  if ("string" == typeof n2 && n2.startsWith("walker ")) {
2592
2958
  const s4 = n2.replace("walker ", "");
2593
2959
  return o2.command(s4, e3, t3);
@@ -2598,14 +2964,14 @@ async function fn(n) {
2598
2964
  if (!n2 || "object" != typeof n2) return N({ ok: false });
2599
2965
  a3 = n2, e3 && "object" == typeof e3 && !Array.isArray(e3) && (a3.data = { ...a3.data || {}, ...e3 });
2600
2966
  }
2601
- return s3 && "object" == typeof s3 && (a3.context = s3), i3 && Array.isArray(i3) && (a3.nested = i3), r3 && "object" == typeof r3 && (a3.custom = r3), o2.push(a3);
2967
+ return s3 && "object" == typeof s3 && (a3.context = s3), r3 && Array.isArray(r3) && (a3.nested = r3), i3 && "object" == typeof i3 && (a3.custom = i3), o2.push(a3);
2602
2968
  } });
2603
2969
  var o2;
2604
2970
  e2.sources.elb = t2;
2605
2971
  const s2 = await T(e2, n.sources || {});
2606
2972
  Object.assign(e2.sources, s2);
2607
- const { consent: i2, user: r2, globals: a2, custom: c2 } = n;
2608
- i2 && await e2.command("consent", i2), r2 && await e2.command("user", r2), a2 && Object.assign(e2.globals, a2), c2 && Object.assign(e2.custom, c2), e2.config.run && await e2.command("run");
2973
+ const { consent: r2, user: i2, globals: a2, custom: c2 } = n;
2974
+ r2 && await e2.command("consent", r2), i2 && await e2.command("user", i2), a2 && Object.assign(e2.globals, a2), c2 && Object.assign(e2.custom, c2), e2.config.run && await e2.command("run");
2609
2975
  let u2 = t2.push;
2610
2976
  const f2 = Object.values(e2.sources).filter((n2) => "elb" !== n2.type), l2 = f2.find((n2) => n2.config.primary);
2611
2977
  return l2 ? u2 = l2.push : f2.length > 0 && (u2 = f2[0].push), { collector: e2, elb: u2 };
@@ -2617,58 +2983,58 @@ function ln(n) {
2617
2983
  for (const [t2, o2] of Object.entries(n)) e2[t2] = "function" == typeof o2 ? o2 : ln(o2);
2618
2984
  return e2;
2619
2985
  }
2620
- function dn(n) {
2986
+ function gn(n) {
2621
2987
  const e2 = [], { simulation: t2, ...o2 } = n, s2 = ln(o2);
2622
2988
  for (const n2 of t2) {
2623
2989
  const t3 = n2.startsWith("call:") ? n2.slice(5) : n2, o3 = t3.split(".");
2624
- let i2 = s2;
2625
- for (let n3 = 0; n3 < o3.length - 1 && null != i2[o3[n3]]; n3++) i2 = i2[o3[n3]];
2626
- const r2 = o3[o3.length - 1];
2627
- if (null == i2 || !(r2 in i2)) continue;
2628
- const a2 = i2[r2];
2629
- "function" == typeof a2 && (i2[r2] = function(...n3) {
2990
+ let r2 = s2;
2991
+ for (let n3 = 0; n3 < o3.length - 1 && null != r2[o3[n3]]; n3++) r2 = r2[o3[n3]];
2992
+ const i2 = o3[o3.length - 1];
2993
+ if (null == r2 || !(i2 in r2)) continue;
2994
+ const a2 = r2[i2];
2995
+ "function" == typeof a2 && (r2[i2] = function(...n3) {
2630
2996
  return e2.push({ fn: t3, args: n3, ts: Date.now() }), a2.apply(this, n3);
2631
2997
  });
2632
2998
  }
2633
2999
  return { wrappedEnv: s2, calls: e2 };
2634
3000
  }
2635
- async function gn(n) {
3001
+ async function dn(n) {
2636
3002
  const e2 = Date.now();
2637
3003
  try {
2638
3004
  switch (n.step) {
2639
3005
  case "transformer":
2640
3006
  return await (async function(n2, e3) {
2641
- const { code: t2, config: o2 = {}, event: s2 } = n2, { collector: i2 } = await fn({ transformers: { sim: { code: t2, config: o2 } } }), r2 = i2.transformers?.sim;
2642
- if (!r2) throw new Error("Transformer failed to initialize");
2643
- const a2 = await r2.push(s2, { collector: i2, logger: i2.logger.scope("transformer").scope("sim"), id: "sim", config: r2.config, env: r2.config?.env || {} });
3007
+ const { code: t2, config: o2 = {}, event: s2 } = n2, { collector: r2 } = await fn({ transformers: { sim: { code: t2, config: o2 } } }), i2 = r2.transformers?.sim;
3008
+ if (!i2) throw new Error("Transformer failed to initialize");
3009
+ const a2 = await i2.push(s2, { collector: r2, logger: r2.logger.scope("transformer").scope("sim"), id: "sim", config: i2.config, env: i2.config?.env || {} });
2644
3010
  let c2;
2645
3011
  c2 = false === a2 ? [] : null == a2 ? [s2] : [a2.event || s2];
2646
3012
  return { step: "transformer", name: n2.name, events: c2, calls: [], duration: Date.now() - e3 };
2647
3013
  })(n, e2);
2648
3014
  case "source":
2649
3015
  return await (async function(n2, e3) {
2650
- const { code: t2, config: o2 = {}, setup: s2, input: i2, env: r2, consent: a2 } = n2, c2 = { functional: true, marketing: true, analytics: true };
3016
+ const { code: t2, config: o2 = {}, setup: s2, input: r2, env: i2, consent: a2 } = n2, c2 = { functional: true, marketing: true, analytics: true };
2651
3017
  let u2;
2652
3018
  if (s2) {
2653
- const n3 = s2(i2, r2);
3019
+ const n3 = s2(r2, i2);
2654
3020
  "function" == typeof n3 && (u2 = n3);
2655
3021
  }
2656
- const f2 = [], { collector: l2 } = await fn({ consent: a2 || c2, sources: { sim: { code: t2, config: o2, env: r2, next: "spy" } }, transformers: { spy: { code: () => ({ type: "spy", config: {}, push: (n3) => (f2.push(JSON.parse(JSON.stringify(n3))), { event: n3 }) }) } } });
3022
+ const f2 = [], { collector: l2 } = await fn({ consent: a2 || c2, sources: { sim: { code: t2, config: o2, env: i2, next: "spy" } }, transformers: { spy: { code: () => ({ type: "spy", config: {}, push: (n3) => (f2.push(JSON.parse(JSON.stringify(n3))), { event: n3 }) }) } } });
2657
3023
  u2 && u2();
2658
3024
  return { step: "source", name: n2.name, events: f2, calls: [], duration: Date.now() - e3 };
2659
3025
  })(n, e2);
2660
3026
  case "destination":
2661
3027
  return await (async function(n2, e3) {
2662
- const { code: t2, config: o2 = {}, event: s2, consent: i2, env: r2, track: a2 } = n2, c2 = { functional: true, marketing: true, analytics: true };
2663
- let u2 = [], f2 = r2;
2664
- if (r2 && a2 && a2.length > 0) {
2665
- const n3 = dn({ ...r2, simulation: a2 });
3028
+ const { code: t2, config: o2 = {}, event: s2, consent: r2, env: i2, track: a2 } = n2, c2 = { functional: true, marketing: true, analytics: true };
3029
+ let u2 = [], f2 = i2;
3030
+ if (i2 && a2 && a2.length > 0) {
3031
+ const n3 = gn({ ...i2, simulation: a2 });
2666
3032
  f2 = n3.wrappedEnv, u2 = n3.calls;
2667
3033
  }
2668
3034
  const l2 = { ...o2 };
2669
3035
  f2 && (l2.env = f2);
2670
- const { collector: d2 } = await fn({ consent: i2 || c2, destinations: { sim: { code: t2, config: l2 } } });
2671
- return await d2.push(s2), { step: "destination", name: n2.name, events: [], calls: u2, duration: Date.now() - e3 };
3036
+ const { collector: g2 } = await fn({ consent: r2 || c2, destinations: { sim: { code: t2, config: l2 } } });
3037
+ return await g2.push(s2), { step: "destination", name: n2.name, events: [], calls: u2, duration: Date.now() - e3 };
2672
3038
  })(n, e2);
2673
3039
  }
2674
3040
  } catch (t2) {
@@ -2678,6 +3044,9 @@ async function gn(n) {
2678
3044
 
2679
3045
  // src/commands/simulate/simulator.ts
2680
3046
  init_cli_logger();
3047
+ init_core();
3048
+ init_config();
3049
+ init_tmp();
2681
3050
 
2682
3051
  // src/commands/simulate/env-loader.ts
2683
3052
  async function loadDestinationEnvs(destinations) {
@@ -2708,21 +3077,6 @@ async function loadDestinationEnvs(destinations) {
2708
3077
  }
2709
3078
 
2710
3079
  // src/commands/simulate/simulator.ts
2711
- function createCollectorLoggerConfigInline(logger2, verbose) {
2712
- return {
2713
- level: verbose ? Level2.DEBUG : Level2.ERROR,
2714
- handler: (level, message, context, scope) => {
2715
- const scopePath = scope.length > 0 ? `[${scope.join(":")}] ` : "";
2716
- const hasContext = Object.keys(context).length > 0;
2717
- const contextStr = hasContext ? ` ${JSON.stringify(context)}` : "";
2718
- if (level === Level2.ERROR) {
2719
- logger2.error(`${scopePath}${message}${contextStr}`);
2720
- } else {
2721
- logger2.debug(`${scopePath}${message}${contextStr}`);
2722
- }
2723
- }
2724
- };
2725
- }
2726
3080
  function callsToUsage(destName, calls) {
2727
3081
  if (!calls.length) return {};
2728
3082
  return {
@@ -2735,17 +3089,16 @@ function callsToUsage(destName, calls) {
2735
3089
  };
2736
3090
  }
2737
3091
  async function simulateCore(inputPath, event, options = {}) {
2738
- const logger2 = createCLILogger({
3092
+ const logger = createCLILogger({
2739
3093
  verbose: options.verbose || false,
2740
3094
  silent: options.silent || false,
2741
3095
  json: options.json || false
2742
3096
  });
2743
3097
  try {
2744
- logger2.debug(`Simulating event: ${JSON.stringify(event)}`);
3098
+ logger.debug(`Simulating event: ${JSON.stringify(event)}`);
2745
3099
  const result = await executeSimulation(event, inputPath, options.platform, {
2746
3100
  flow: options.flow,
2747
3101
  step: options.step,
2748
- logger: logger2,
2749
3102
  verbose: options.verbose
2750
3103
  });
2751
3104
  return result;
@@ -2800,9 +3153,8 @@ function formatSimulationResult(result, options = {}) {
2800
3153
  async function executeSimulation(event, inputPath, platformOverride, options = {}) {
2801
3154
  const startTime = Date.now();
2802
3155
  const tempDir = getTmpPath();
2803
- const collectorLoggerConfig = options.logger ? createCollectorLoggerConfigInline(options.logger, options.verbose) : void 0;
2804
3156
  try {
2805
- await fs11.ensureDir(tempDir);
3157
+ await fs12.ensureDir(tempDir);
2806
3158
  const detected = await detectInput(inputPath, platformOverride);
2807
3159
  if (!isObject(event) || !("name" in event) || typeof event.name !== "string") {
2808
3160
  throw new Error(
@@ -2812,7 +3164,7 @@ async function executeSimulation(event, inputPath, platformOverride, options = {
2812
3164
  const typedEvent = event;
2813
3165
  if (detected.type !== "config") {
2814
3166
  throw new Error(
2815
- `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.`
2816
3168
  );
2817
3169
  }
2818
3170
  return await executeConfigSimulation(
@@ -2821,7 +3173,6 @@ async function executeSimulation(event, inputPath, platformOverride, options = {
2821
3173
  typedEvent,
2822
3174
  tempDir,
2823
3175
  startTime,
2824
- collectorLoggerConfig,
2825
3176
  options.flow,
2826
3177
  options.step
2827
3178
  );
@@ -2834,7 +3185,7 @@ async function executeSimulation(event, inputPath, platformOverride, options = {
2834
3185
  };
2835
3186
  } finally {
2836
3187
  if (tempDir) {
2837
- await fs11.remove(tempDir).catch(() => {
3188
+ await fs12.remove(tempDir).catch(() => {
2838
3189
  });
2839
3190
  }
2840
3191
  }
@@ -2863,13 +3214,13 @@ function parseStepTarget(stepTarget, flowConfig) {
2863
3214
  }
2864
3215
  throw new Error("No destination found in flow config");
2865
3216
  }
2866
- async function executeConfigSimulation(_content, configPath, typedEvent, tempDir, startTime, loggerConfig2, flowName, stepTarget) {
2867
- const { flowConfig } = await loadFlowConfig(configPath, {
3217
+ async function executeConfigSimulation(_content, configPath, typedEvent, tempDir, startTime, flowName, stepTarget) {
3218
+ const { flowSettings } = await loadFlowConfig(configPath, {
2868
3219
  flowName
2869
3220
  });
2870
3221
  const step = parseStepTarget(
2871
3222
  stepTarget,
2872
- flowConfig
3223
+ flowSettings
2873
3224
  );
2874
3225
  if (step.type === "destination") {
2875
3226
  const packageName = step.config.package;
@@ -2878,10 +3229,10 @@ async function executeConfigSimulation(_content, configPath, typedEvent, tempDir
2878
3229
  }
2879
3230
  const destModule = await import(packageName);
2880
3231
  const code = destModule.default || Object.values(destModule)[0];
2881
- const destinations = flowConfig.destinations;
3232
+ const destinations = flowSettings.destinations;
2882
3233
  const envs = await loadDestinationEnvs(destinations || {});
2883
3234
  const destEnv = envs[step.name];
2884
- const result = await gn({
3235
+ const result = await dn({
2885
3236
  step: "destination",
2886
3237
  name: step.name,
2887
3238
  code,
@@ -2906,7 +3257,7 @@ async function executeConfigSimulation(_content, configPath, typedEvent, tempDir
2906
3257
  }
2907
3258
  const mod = await import(packageName);
2908
3259
  const code = mod.default || Object.values(mod)[0];
2909
- const result = await gn({
3260
+ const result = await dn({
2910
3261
  step: "transformer",
2911
3262
  name: step.name,
2912
3263
  code,
@@ -2928,6 +3279,7 @@ async function executeConfigSimulation(_content, configPath, typedEvent, tempDir
2928
3279
 
2929
3280
  // src/commands/simulate/source-simulator.ts
2930
3281
  import { JSDOM, VirtualConsole } from "jsdom";
3282
+ init_core();
2931
3283
  async function loadSourcePackage(packageName) {
2932
3284
  const mainModule = await import(packageName);
2933
3285
  const code = mainModule.default || Object.values(mainModule)[0];
@@ -2978,7 +3330,7 @@ async function simulateSourceCLI(flowConfig, setupInput, options) {
2978
3330
  document: dom.window.document,
2979
3331
  localStorage: dom.window.localStorage
2980
3332
  };
2981
- const result = await gn({
3333
+ const result = await dn({
2982
3334
  step: "source",
2983
3335
  name: options.sourceStep,
2984
3336
  code,
@@ -3005,6 +3357,9 @@ async function simulateSourceCLI(flowConfig, setupInput, options) {
3005
3357
 
3006
3358
  // src/commands/simulate/index.ts
3007
3359
  init_cli_logger();
3360
+ init_core();
3361
+ init_config();
3362
+ init_validators();
3008
3363
 
3009
3364
  // src/commands/simulate/example-loader.ts
3010
3365
  function findExample(config, exampleName, stepTarget) {
@@ -3110,135 +3465,39 @@ ${actualStr}`
3110
3465
 
3111
3466
  // src/commands/simulate/index.ts
3112
3467
  async function simulateCommand(options) {
3113
- const logger2 = createCLILogger({ ...options, stderr: true });
3468
+ const logger = createCLILogger({ ...options, stderr: true });
3114
3469
  const startTime = Date.now();
3115
3470
  try {
3116
3471
  let config;
3117
3472
  if (isStdinPiped() && !options.config) {
3118
3473
  const stdinContent = await readStdin();
3119
- const fs14 = await import("fs-extra");
3120
- const path14 = await import("path");
3474
+ const fs15 = await import("fs-extra");
3475
+ const path15 = await import("path");
3121
3476
  const tmpPath = getTmpPath(void 0, "stdin-simulate.json");
3122
- await fs14.default.ensureDir(path14.default.dirname(tmpPath));
3123
- await fs14.default.writeFile(tmpPath, stdinContent, "utf-8");
3477
+ await fs15.default.ensureDir(path15.default.dirname(tmpPath));
3478
+ await fs15.default.writeFile(tmpPath, stdinContent, "utf-8");
3124
3479
  config = tmpPath;
3125
3480
  } else {
3126
3481
  config = options.config || "bundle.config.json";
3127
3482
  }
3128
- let event;
3129
- let exampleContext;
3130
- if (options.example) {
3131
- const rawConfig = await loadJsonConfig(config);
3132
- const setup = validateFlowSetup(rawConfig);
3133
- const flowNames = Object.keys(setup.flows);
3134
- let flowName = options.flow;
3135
- if (!flowName) {
3136
- if (flowNames.length === 1) {
3137
- flowName = flowNames[0];
3138
- } else {
3139
- throw new Error(
3140
- `Multiple flows found. Use --flow to specify which flow contains the example.
3141
- Available flows: ${flowNames.join(", ")}`
3142
- );
3143
- }
3144
- }
3145
- const flowConfig = setup.flows[flowName];
3146
- if (!flowConfig) {
3147
- throw new Error(
3148
- `Flow "${flowName}" not found. Available: ${flowNames.join(", ")}`
3149
- );
3150
- }
3151
- const found = findExample(flowConfig, options.example, options.step);
3152
- if (found.example.in === void 0) {
3153
- throw new Error(
3154
- `Example "${options.example}" in ${found.stepType}.${found.stepName} has no "in" value`
3155
- );
3156
- }
3157
- event = found.example.in;
3158
- exampleContext = {
3159
- stepType: found.stepType,
3160
- stepName: found.stepName,
3161
- expected: found.example.out
3162
- };
3163
- } else {
3164
- event = await loadJsonFromSource(options.event, {
3165
- name: "event"
3166
- });
3167
- }
3168
- const isSourceSimulation = exampleContext?.stepType === "source" || options.step?.startsWith("source.");
3169
- let result;
3170
- if (isSourceSimulation) {
3171
- const rawConfig = await loadJsonConfig(config);
3172
- const setup = validateFlowSetup(rawConfig);
3173
- const flowNames = Object.keys(setup.flows);
3174
- const flowName = options.flow || (flowNames.length === 1 ? flowNames[0] : void 0);
3175
- if (!flowName) {
3176
- throw new Error(
3177
- `Multiple flows found. Use --flow to specify which flow.
3178
- Available: ${flowNames.join(", ")}`
3179
- );
3180
- }
3181
- const flowConfig = setup.flows[flowName];
3182
- if (!flowConfig) {
3183
- throw new Error(
3184
- `Flow "${flowName}" not found. Available: ${flowNames.join(", ")}`
3185
- );
3186
- }
3187
- const sourceStep = exampleContext?.stepName || options.step.substring("source.".length);
3188
- result = await simulateSourceCLI(
3189
- flowConfig,
3190
- event,
3191
- {
3192
- flow: options.flow,
3193
- sourceStep,
3194
- json: options.json,
3195
- verbose: options.verbose,
3196
- silent: options.silent
3197
- }
3198
- );
3199
- } else {
3200
- const stepTarget = exampleContext ? `${exampleContext.stepType}.${exampleContext.stepName}` : options.step;
3201
- result = await simulateCore(config, event, {
3202
- flow: options.flow,
3203
- json: options.json,
3204
- verbose: options.verbose,
3205
- silent: options.silent,
3206
- step: stepTarget
3207
- });
3208
- }
3209
- let exampleMatch;
3210
- if (exampleContext && result.success) {
3211
- const stepKey = `${exampleContext.stepType}.${exampleContext.stepName}`;
3212
- if (exampleContext.expected === false) {
3213
- const calls = result.usage?.[exampleContext.stepName];
3214
- const wasFiltered = !calls || calls.length === 0;
3215
- exampleMatch = {
3216
- name: options.example,
3217
- step: stepKey,
3218
- expected: false,
3219
- actual: wasFiltered ? false : calls,
3220
- match: wasFiltered,
3221
- diff: wasFiltered ? void 0 : `Expected event to be filtered, but ${calls.length} API call(s) were made`
3222
- };
3223
- } else if (exampleContext.expected !== void 0) {
3224
- const actual = result.usage?.[exampleContext.stepName] ?? [];
3225
- exampleMatch = {
3226
- name: options.example,
3227
- step: stepKey,
3228
- ...compareOutput(exampleContext.expected, actual)
3229
- };
3230
- }
3231
- }
3483
+ const result = await simulate(config, options.event, {
3484
+ flow: options.flow,
3485
+ json: options.json,
3486
+ verbose: options.verbose,
3487
+ silent: options.silent,
3488
+ platform: options.platform,
3489
+ example: options.example,
3490
+ step: options.step
3491
+ });
3232
3492
  const resultWithDuration = {
3233
3493
  ...result,
3234
- duration: (Date.now() - startTime) / 1e3,
3235
- ...exampleMatch ? { exampleMatch } : {}
3494
+ duration: (Date.now() - startTime) / 1e3
3236
3495
  };
3237
3496
  const formatted = formatSimulationResult(resultWithDuration, {
3238
3497
  json: options.json
3239
3498
  });
3240
3499
  await writeResult(formatted + "\n", { output: options.output });
3241
- const exitCode = !result.success || exampleMatch && !exampleMatch.match ? 1 : 0;
3500
+ const exitCode = !result.success || result.exampleMatch && !result.exampleMatch.match ? 1 : 0;
3242
3501
  process.exit(exitCode);
3243
3502
  } catch (error) {
3244
3503
  const errorMessage = getErrorMessage(error);
@@ -3254,7 +3513,7 @@ Available: ${flowNames.join(", ")}`
3254
3513
  );
3255
3514
  await writeResult(errorOutput + "\n", { output: options.output });
3256
3515
  } else {
3257
- logger2.error(`Error: ${errorMessage}`);
3516
+ logger.error(`Error: ${errorMessage}`);
3258
3517
  }
3259
3518
  process.exit(1);
3260
3519
  }
@@ -3266,10 +3525,13 @@ async function simulate(configOrPath, event, options = {}) {
3266
3525
  );
3267
3526
  }
3268
3527
  let resolvedEvent = event;
3528
+ if (typeof event === "string") {
3529
+ resolvedEvent = await loadJsonFromSource(event, { name: "event" });
3530
+ }
3269
3531
  let exampleContext;
3270
3532
  if (options.example) {
3271
3533
  const rawConfig = await loadJsonConfig(configOrPath);
3272
- const setup = validateFlowSetup(rawConfig);
3534
+ const setup = validateFlowConfig(rawConfig);
3273
3535
  const flowNames = Object.keys(setup.flows);
3274
3536
  let flowName = options.flow;
3275
3537
  if (!flowName) {
@@ -3282,13 +3544,13 @@ Available flows: ${flowNames.join(", ")}`
3282
3544
  );
3283
3545
  }
3284
3546
  }
3285
- const flowConfig = setup.flows[flowName];
3286
- if (!flowConfig) {
3547
+ const flowSettings = setup.flows[flowName];
3548
+ if (!flowSettings) {
3287
3549
  throw new Error(
3288
3550
  `Flow "${flowName}" not found. Available: ${flowNames.join(", ")}`
3289
3551
  );
3290
3552
  }
3291
- const found = findExample(flowConfig, options.example, options.step);
3553
+ const found = findExample(flowSettings, options.example, options.step);
3292
3554
  if (found.example.in === void 0) {
3293
3555
  throw new Error(
3294
3556
  `Example "${options.example}" in ${found.stepType}.${found.stepName} has no "in" value`
@@ -3301,12 +3563,48 @@ Available flows: ${flowNames.join(", ")}`
3301
3563
  expected: found.example.out
3302
3564
  };
3303
3565
  }
3304
- const result = await simulateCore(configOrPath, resolvedEvent, {
3305
- json: options.json ?? false,
3306
- verbose: options.verbose ?? false,
3307
- flow: options.flow,
3308
- platform: options.platform
3309
- });
3566
+ const isSourceSimulation = exampleContext?.stepType === "source" || options.step?.startsWith("source.");
3567
+ let result;
3568
+ if (isSourceSimulation) {
3569
+ const rawConfig = await loadJsonConfig(configOrPath);
3570
+ const setup = validateFlowConfig(rawConfig);
3571
+ const flowNames = Object.keys(setup.flows);
3572
+ const flowName = options.flow || (flowNames.length === 1 ? flowNames[0] : void 0);
3573
+ if (!flowName) {
3574
+ throw new Error(
3575
+ `Multiple flows found. Use --flow to specify which flow.
3576
+ Available: ${flowNames.join(", ")}`
3577
+ );
3578
+ }
3579
+ const flowSettings = setup.flows[flowName];
3580
+ if (!flowSettings) {
3581
+ throw new Error(
3582
+ `Flow "${flowName}" not found. Available: ${flowNames.join(", ")}`
3583
+ );
3584
+ }
3585
+ const sourceStep = exampleContext?.stepName || options.step.substring("source.".length);
3586
+ result = await simulateSourceCLI(
3587
+ flowSettings,
3588
+ resolvedEvent,
3589
+ {
3590
+ flow: options.flow,
3591
+ sourceStep,
3592
+ json: options.json,
3593
+ verbose: options.verbose,
3594
+ silent: options.silent
3595
+ }
3596
+ );
3597
+ } else {
3598
+ const stepTarget = exampleContext ? `${exampleContext.stepType}.${exampleContext.stepName}` : options.step;
3599
+ result = await simulateCore(configOrPath, resolvedEvent, {
3600
+ json: options.json ?? false,
3601
+ verbose: options.verbose ?? false,
3602
+ silent: options.silent ?? false,
3603
+ flow: options.flow,
3604
+ platform: options.platform,
3605
+ step: stepTarget
3606
+ });
3607
+ }
3310
3608
  if (exampleContext && result.success) {
3311
3609
  const stepKey = `${exampleContext.stepType}.${exampleContext.stepName}`;
3312
3610
  if (exampleContext.expected === false) {
@@ -3334,40 +3632,25 @@ Available flows: ${flowNames.join(", ")}`
3334
3632
 
3335
3633
  // src/commands/push/index.ts
3336
3634
  init_cli_logger();
3337
- import path11 from "path";
3635
+ init_core();
3636
+ init_tmp();
3637
+ init_config();
3638
+ init_bundler();
3639
+ import path12 from "path";
3338
3640
  import { JSDOM as JSDOM2, VirtualConsole as VirtualConsole2 } from "jsdom";
3339
- import fs12 from "fs-extra";
3641
+ import fs13 from "fs-extra";
3340
3642
  import { getPlatform as getPlatform3 } from "@walkeros/core";
3341
3643
  import { schemas as schemas2 } from "@walkeros/core/dev";
3342
- import { Level as Level3 } from "@walkeros/core";
3343
- function createCollectorLoggerConfig(logger2, verbose) {
3344
- return {
3345
- level: verbose ? Level3.DEBUG : Level3.ERROR,
3346
- handler: (level, message, context, scope) => {
3347
- const scopePath = scope.length > 0 ? `[${scope.join(":")}] ` : "";
3348
- const hasContext = Object.keys(context).length > 0;
3349
- const contextStr = hasContext ? ` ${JSON.stringify(context)}` : "";
3350
- if (level === Level3.ERROR) {
3351
- logger2.error(`${scopePath}${message}${contextStr}`);
3352
- } else {
3353
- logger2.debug(`${scopePath}${message}${contextStr}`);
3354
- }
3355
- }
3356
- };
3357
- }
3644
+ import { Level as Level2 } from "@walkeros/core";
3358
3645
  async function pushCore(inputPath, event, options = {}) {
3359
- const logger2 = createCLILogger({
3646
+ const logger = createCLILogger({
3360
3647
  silent: options.silent,
3361
3648
  verbose: options.verbose
3362
3649
  });
3363
3650
  const startTime = Date.now();
3364
3651
  let tempDir;
3365
3652
  try {
3366
- let loadedEvent = event;
3367
- if (typeof event === "string") {
3368
- loadedEvent = await loadJsonFromSource(event, { name: "event" });
3369
- }
3370
- const eventResult = schemas2.PartialEventSchema.safeParse(loadedEvent);
3653
+ const eventResult = schemas2.PartialEventSchema.safeParse(event);
3371
3654
  if (!eventResult.success) {
3372
3655
  const errors = eventResult.error.issues.map((issue) => `${String(issue.path.join("."))}: ${issue.message}`).join(", ");
3373
3656
  throw new Error(`Invalid event: ${errors}`);
@@ -3381,11 +3664,11 @@ async function pushCore(inputPath, event, options = {}) {
3381
3664
  data: parsedEvent.data || {}
3382
3665
  };
3383
3666
  if (!validatedEvent.name.includes(" ")) {
3384
- logger2.info(
3667
+ logger.info(
3385
3668
  `Warning: Event name "${validatedEvent.name}" should follow "ENTITY ACTION" format (e.g., "page view")`
3386
3669
  );
3387
3670
  }
3388
- logger2.debug("Detecting input type");
3671
+ logger.debug("Detecting input type");
3389
3672
  const detected = await detectInput(
3390
3673
  inputPath,
3391
3674
  options.platform
@@ -3399,7 +3682,7 @@ async function pushCore(inputPath, event, options = {}) {
3399
3682
  verbose: options.verbose
3400
3683
  },
3401
3684
  validatedEvent,
3402
- logger2,
3685
+ logger,
3403
3686
  (dir) => {
3404
3687
  tempDir = dir;
3405
3688
  }
@@ -3409,11 +3692,11 @@ async function pushCore(inputPath, event, options = {}) {
3409
3692
  detected.content,
3410
3693
  detected.platform,
3411
3694
  validatedEvent,
3412
- logger2,
3695
+ logger,
3413
3696
  (dir) => {
3414
3697
  tempDir = dir;
3415
3698
  },
3416
- { logger: createCollectorLoggerConfig(logger2, options.verbose) }
3699
+ { logger: { level: options.verbose ? Level2.DEBUG : Level2.ERROR } }
3417
3700
  );
3418
3701
  }
3419
3702
  return result;
@@ -3425,27 +3708,26 @@ async function pushCore(inputPath, event, options = {}) {
3425
3708
  };
3426
3709
  } finally {
3427
3710
  if (tempDir) {
3428
- await fs12.remove(tempDir).catch(() => {
3711
+ await fs13.remove(tempDir).catch(() => {
3429
3712
  });
3430
3713
  }
3431
3714
  }
3432
3715
  }
3433
3716
  async function pushCommand(options) {
3434
- const logger2 = createCLILogger({ ...options, stderr: true });
3717
+ const logger = createCLILogger({ ...options, stderr: true });
3435
3718
  const startTime = Date.now();
3436
3719
  try {
3437
3720
  let config;
3438
3721
  if (isStdinPiped() && !options.config) {
3439
3722
  const stdinContent = await readStdin();
3440
3723
  const tmpPath = getTmpPath(void 0, "stdin-push.json");
3441
- await fs12.ensureDir(path11.dirname(tmpPath));
3442
- await fs12.writeFile(tmpPath, stdinContent, "utf-8");
3724
+ await fs13.ensureDir(path12.dirname(tmpPath));
3725
+ await fs13.writeFile(tmpPath, stdinContent, "utf-8");
3443
3726
  config = tmpPath;
3444
3727
  } else {
3445
3728
  config = options.config || "bundle.config.json";
3446
3729
  }
3447
- const event = await loadJsonFromSource(options.event, { name: "event" });
3448
- const result = await pushCore(config, event, {
3730
+ const result = await push(config, options.event, {
3449
3731
  flow: options.flow,
3450
3732
  json: options.json,
3451
3733
  verbose: options.verbose,
@@ -3496,7 +3778,7 @@ async function pushCommand(options) {
3496
3778
  );
3497
3779
  await writeResult(errorOutput + "\n", { output: options.output });
3498
3780
  } else {
3499
- logger2.error(`Error: ${errorMessage}`);
3781
+ logger.error(`Error: ${errorMessage}`);
3500
3782
  }
3501
3783
  process.exit(1);
3502
3784
  }
@@ -3507,29 +3789,34 @@ async function push(configOrPath, event, options = {}) {
3507
3789
  "push() currently only supports config file paths. Config object support will be added in a future version. Please provide a path to a configuration file."
3508
3790
  );
3509
3791
  }
3510
- return await pushCore(configOrPath, event, {
3792
+ let resolvedEvent = event;
3793
+ if (typeof event === "string") {
3794
+ resolvedEvent = await loadJsonFromSource(event, { name: "event" });
3795
+ }
3796
+ return await pushCore(configOrPath, resolvedEvent, {
3511
3797
  json: options.json ?? false,
3512
3798
  verbose: options.verbose ?? false,
3799
+ silent: options.silent ?? false,
3513
3800
  flow: options.flow,
3514
3801
  platform: options.platform
3515
3802
  });
3516
3803
  }
3517
- async function executeConfigPush(options, validatedEvent, logger2, setTempDir) {
3518
- logger2.debug("Loading flow configuration");
3519
- 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, {
3520
3807
  flowName: options.flow,
3521
- logger: logger2
3808
+ logger
3522
3809
  });
3523
- const platform = getPlatform3(flowConfig);
3524
- logger2.debug("Bundling flow configuration");
3810
+ const platform = getPlatform3(flowSettings);
3811
+ logger.debug("Bundling flow configuration");
3525
3812
  const configDir = buildOptions.configDir || process.cwd();
3526
3813
  const tempDir = getTmpPath(
3527
3814
  void 0,
3528
3815
  `push-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
3529
3816
  );
3530
3817
  setTempDir(tempDir);
3531
- await fs12.ensureDir(tempDir);
3532
- const tempPath = path11.join(
3818
+ await fs13.ensureDir(tempDir);
3819
+ const tempPath = path12.join(
3533
3820
  tempDir,
3534
3821
  `bundle.${platform === "web" ? "js" : "mjs"}`
3535
3822
  );
@@ -3543,42 +3830,42 @@ async function executeConfigPush(options, validatedEvent, logger2, setTempDir) {
3543
3830
  windowElb: "elb"
3544
3831
  }
3545
3832
  };
3546
- await bundleCore(flowConfig, pushBuildOptions, logger2, false);
3547
- logger2.debug(`Bundle created: ${tempPath}`);
3833
+ await bundleCore(flowSettings, pushBuildOptions, logger, false);
3834
+ logger.debug(`Bundle created: ${tempPath}`);
3548
3835
  if (platform === "web") {
3549
- logger2.debug("Executing in web environment (JSDOM)");
3550
- return executeWebPush(tempPath, validatedEvent, logger2);
3836
+ logger.debug("Executing in web environment (JSDOM)");
3837
+ return executeWebPush(tempPath, validatedEvent, logger);
3551
3838
  } else if (platform === "server") {
3552
- logger2.debug("Executing in server environment (Node.js)");
3553
- return executeServerPush(tempPath, validatedEvent, logger2, 6e4, {
3554
- logger: createCollectorLoggerConfig(logger2, options.verbose)
3839
+ logger.debug("Executing in server environment (Node.js)");
3840
+ return executeServerPush(tempPath, validatedEvent, logger, 6e4, {
3841
+ logger: { level: options.verbose ? Level2.DEBUG : Level2.ERROR }
3555
3842
  });
3556
3843
  } else {
3557
3844
  throw new Error(`Unsupported platform: ${platform}`);
3558
3845
  }
3559
3846
  }
3560
- async function executeBundlePush(bundleContent, platform, validatedEvent, logger2, setTempDir, context = {}) {
3847
+ async function executeBundlePush(bundleContent, platform, validatedEvent, logger, setTempDir, context = {}) {
3561
3848
  const tempDir = getTmpPath(
3562
3849
  void 0,
3563
3850
  `push-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
3564
3851
  );
3565
3852
  setTempDir(tempDir);
3566
- await fs12.ensureDir(tempDir);
3567
- const tempPath = path11.join(
3853
+ await fs13.ensureDir(tempDir);
3854
+ const tempPath = path12.join(
3568
3855
  tempDir,
3569
3856
  `bundle.${platform === "server" ? "mjs" : "js"}`
3570
3857
  );
3571
- await fs12.writeFile(tempPath, bundleContent, "utf8");
3572
- logger2.debug(`Bundle written to: ${tempPath}`);
3858
+ await fs13.writeFile(tempPath, bundleContent, "utf8");
3859
+ logger.debug(`Bundle written to: ${tempPath}`);
3573
3860
  if (platform === "web") {
3574
- logger2.debug("Executing in web environment (JSDOM)");
3575
- return executeWebPush(tempPath, validatedEvent, logger2);
3861
+ logger.debug("Executing in web environment (JSDOM)");
3862
+ return executeWebPush(tempPath, validatedEvent, logger);
3576
3863
  } else {
3577
- logger2.debug("Executing in server environment (Node.js)");
3578
- return executeServerPush(tempPath, validatedEvent, logger2, 6e4, context);
3864
+ logger.debug("Executing in server environment (Node.js)");
3865
+ return executeServerPush(tempPath, validatedEvent, logger, 6e4, context);
3579
3866
  }
3580
3867
  }
3581
- async function executeWebPush(bundlePath, event, logger2) {
3868
+ async function executeWebPush(bundlePath, event, logger) {
3582
3869
  const startTime = Date.now();
3583
3870
  try {
3584
3871
  const virtualConsole = new VirtualConsole2();
@@ -3589,10 +3876,10 @@ async function executeWebPush(bundlePath, event, logger2) {
3589
3876
  virtualConsole
3590
3877
  });
3591
3878
  const { window } = dom;
3592
- logger2.debug("Loading bundle...");
3593
- const bundleCode = await fs12.readFile(bundlePath, "utf8");
3879
+ logger.debug("Loading bundle...");
3880
+ const bundleCode = await fs13.readFile(bundlePath, "utf8");
3594
3881
  window.eval(bundleCode);
3595
- logger2.debug("Waiting for collector...");
3882
+ logger.debug("Waiting for collector...");
3596
3883
  await waitForWindowProperty(
3597
3884
  window,
3598
3885
  "collector",
@@ -3600,7 +3887,7 @@ async function executeWebPush(bundlePath, event, logger2) {
3600
3887
  );
3601
3888
  const windowObj = window;
3602
3889
  const collector = windowObj.collector;
3603
- logger2.info(`Pushing event: ${event.name}`);
3890
+ logger.info(`Pushing event: ${event.name}`);
3604
3891
  const elbResult = await collector.push({
3605
3892
  name: event.name,
3606
3893
  data: event.data
@@ -3618,7 +3905,7 @@ async function executeWebPush(bundlePath, event, logger2) {
3618
3905
  };
3619
3906
  }
3620
3907
  }
3621
- async function executeServerPush(bundlePath, event, logger2, timeout = 6e4, context = {}) {
3908
+ async function executeServerPush(bundlePath, event, logger, timeout = 6e4, context = {}) {
3622
3909
  const startTime = Date.now();
3623
3910
  let timer;
3624
3911
  try {
@@ -3629,12 +3916,12 @@ async function executeServerPush(bundlePath, event, logger2, timeout = 6e4, cont
3629
3916
  );
3630
3917
  });
3631
3918
  const executePromise = (async () => {
3632
- logger2.debug("Importing bundle...");
3919
+ logger.debug("Importing bundle...");
3633
3920
  const flowModule = await import(bundlePath);
3634
3921
  if (!flowModule.default || typeof flowModule.default !== "function") {
3635
3922
  throw new Error("Bundle does not export default factory function");
3636
3923
  }
3637
- logger2.debug("Calling factory function...");
3924
+ logger.debug("Calling factory function...");
3638
3925
  const result = await flowModule.default(context);
3639
3926
  if (!result || !result.collector || typeof result.collector.push !== "function") {
3640
3927
  throw new Error(
@@ -3642,7 +3929,7 @@ async function executeServerPush(bundlePath, event, logger2, timeout = 6e4, cont
3642
3929
  );
3643
3930
  }
3644
3931
  const { collector } = result;
3645
- logger2.info(`Pushing event: ${event.name}`);
3932
+ logger.info(`Pushing event: ${event.name}`);
3646
3933
  const elbResult = await collector.push({
3647
3934
  name: event.name,
3648
3935
  data: event.data
@@ -3685,106 +3972,110 @@ function waitForWindowProperty(window, prop, timeout = 5e3) {
3685
3972
  }
3686
3973
 
3687
3974
  // src/commands/run/index.ts
3688
- init_cli_logger();
3689
- import path13 from "path";
3975
+ init_cli_logger();
3976
+ init_core();
3977
+ init_config_file();
3978
+ init_auth();
3979
+ import path14 from "path";
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();
3690
4065
 
3691
4066
  // src/commands/run/validators.ts
3692
- import { existsSync as existsSync3 } from "fs";
4067
+ init_asset_resolver();
4068
+ import { existsSync as existsSync5 } from "fs";
3693
4069
 
3694
4070
  // src/schemas/primitives.ts
3695
4071
  import { z as z2 } from "@walkeros/core/dev";
3696
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");
3697
4073
  var FilePathSchema = z2.string().min(1, "File path cannot be empty").describe("Path to configuration file");
3698
4074
 
3699
- // src/schemas/run.ts
3700
- import { z as z3 } from "@walkeros/core/dev";
3701
- var RunOptionsSchema = z3.object({
3702
- flow: FilePathSchema,
3703
- port: PortSchema.default(8080),
3704
- flowName: z3.string().optional().describe("Specific flow name to run")
3705
- });
3706
-
3707
- // src/schemas/validate.ts
3708
- import { z as z4 } from "@walkeros/core/dev";
3709
- var ValidationTypeSchema = z4.enum(["contract", "event", "flow", "mapping"]).describe('Validation type: "event", "flow", "mapping", or "contract"');
3710
- var ValidateOptionsSchema = z4.object({
3711
- flow: z4.string().optional().describe("Flow name for multi-flow configs"),
3712
- path: z4.string().optional().describe(
3713
- 'Entry path for package schema validation (e.g., "destinations.snowplow", "sources.browser")'
3714
- )
3715
- });
3716
- var ValidateInputShape = {
3717
- type: ValidationTypeSchema,
3718
- input: z4.string().min(1).describe("JSON string, file path, or URL to validate"),
3719
- flow: z4.string().optional().describe("Flow name for multi-flow configs"),
3720
- path: z4.string().optional().describe(
3721
- 'Entry path for package schema validation (e.g., "destinations.snowplow"). When provided, validates the entry against its package JSON Schema instead of using --type.'
3722
- )
3723
- };
3724
- var ValidateInputSchema = z4.object(ValidateInputShape);
3725
-
3726
- // src/schemas/bundle.ts
3727
- import { z as z5 } from "@walkeros/core/dev";
3728
- var BundleOptionsSchema = z5.object({
3729
- silent: z5.boolean().optional().describe("Suppress all output"),
3730
- verbose: z5.boolean().optional().describe("Enable verbose logging"),
3731
- stats: z5.boolean().optional().default(true).describe("Return bundle statistics"),
3732
- cache: z5.boolean().optional().default(true).describe("Enable package caching"),
3733
- flowName: z5.string().optional().describe("Flow name for multi-flow configs")
3734
- });
3735
- var BundleInputShape = {
3736
- configPath: FilePathSchema.describe(
3737
- "Path to flow configuration file (JSON or JavaScript)"
3738
- ),
3739
- flow: z5.string().optional().describe("Flow name for multi-flow configs"),
3740
- stats: z5.boolean().optional().default(true).describe("Return bundle statistics"),
3741
- output: z5.string().optional().describe("Output file path (defaults to config-defined)")
3742
- };
3743
- var BundleInputSchema = z5.object(BundleInputShape);
3744
-
3745
- // src/schemas/simulate.ts
3746
- import { z as z6 } from "@walkeros/core/dev";
3747
- var PlatformSchema = z6.enum(["web", "server"]).describe("Platform type for event processing");
3748
- var SimulateOptionsSchema = z6.object({
3749
- silent: z6.boolean().optional().describe("Suppress all output"),
3750
- verbose: z6.boolean().optional().describe("Enable verbose logging"),
3751
- json: z6.boolean().optional().describe("Format output as JSON")
3752
- });
3753
- var SimulateInputShape = {
3754
- configPath: FilePathSchema.describe("Path to flow configuration file"),
3755
- event: z6.string().min(1).optional().describe(
3756
- "Event as JSON string, file path, or URL. Optional when example is provided."
3757
- ),
3758
- flow: z6.string().optional().describe("Flow name for multi-flow configs"),
3759
- platform: PlatformSchema.optional().describe("Override platform detection"),
3760
- example: z6.string().optional().describe(
3761
- 'Name of a step example to use as event input (uses its "in" value)'
3762
- ),
3763
- step: z6.string().optional().describe(
3764
- 'Step target in type.name format (e.g. "destination.gtag") to narrow example lookup'
3765
- )
3766
- };
3767
- var SimulateInputSchema = z6.object(SimulateInputShape);
3768
-
3769
- // src/schemas/push.ts
3770
- import { z as z7 } from "@walkeros/core/dev";
3771
- var PushOptionsSchema = z7.object({
3772
- silent: z7.boolean().optional().describe("Suppress all output"),
3773
- verbose: z7.boolean().optional().describe("Enable verbose logging"),
3774
- json: z7.boolean().optional().describe("Format output as JSON")
3775
- });
3776
- var PushInputShape = {
3777
- configPath: FilePathSchema.describe("Path to flow configuration file"),
3778
- event: z7.string().min(1).describe("Event as JSON string, file path, or URL"),
3779
- flow: z7.string().optional().describe("Flow name for multi-flow configs"),
3780
- platform: PlatformSchema.optional().describe("Override platform detection")
3781
- };
3782
- var PushInputSchema = z7.object(PushInputShape);
3783
-
3784
4075
  // src/commands/run/validators.ts
3785
4076
  function validateFlowFile(filePath) {
3786
4077
  const absolutePath = resolveAsset(filePath, "bundle");
3787
- if (!existsSync3(absolutePath)) {
4078
+ if (!existsSync5(absolutePath)) {
3788
4079
  throw new Error(
3789
4080
  `Flow file not found: ${filePath}
3790
4081
  Resolved path: ${absolutePath}
@@ -3804,40 +4095,60 @@ function validatePort(port) {
3804
4095
  }
3805
4096
  }
3806
4097
 
3807
- // src/commands/run/utils.ts
3808
- import path12 from "path";
3809
- import fs13 from "fs-extra";
3810
- async function prepareBundleForRun(configPath, options) {
3811
- const tempDir = getTmpPath(
3812
- void 0,
3813
- `run-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
3814
- );
3815
- await fs13.ensureDir(tempDir);
3816
- const tempPath = path12.join(tempDir, "bundle.mjs");
3817
- await bundle(configPath, {
3818
- cache: true,
3819
- verbose: options.verbose,
3820
- silent: options.silent,
3821
- flowName: options.flowName,
3822
- buildOverrides: {
3823
- output: tempPath,
3824
- format: "esm",
3825
- platform: "node"
3826
- }
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);
3827
4145
  });
3828
- return tempPath;
3829
- }
3830
- function isPreBuiltConfig(configPath) {
3831
- return configPath.endsWith(".mjs") || configPath.endsWith(".js") || configPath.endsWith(".cjs");
3832
4146
  }
3833
4147
 
3834
- // src/commands/run/execution.ts
3835
- import { createLogger as createLogger2, Level as Level4 } from "@walkeros/core";
3836
-
3837
4148
  // src/runtime/runner.ts
3838
4149
  import { pathToFileURL } from "url";
3839
4150
  import { resolve, dirname } from "path";
3840
- async function loadFlow(file, config, logger2, loggerConfig2, healthServer) {
4151
+ async function loadFlow(file, config, logger, loggerConfig, healthServer) {
3841
4152
  const absolutePath = resolve(file);
3842
4153
  const flowDir = dirname(absolutePath);
3843
4154
  process.chdir(flowDir);
@@ -3850,7 +4161,7 @@ async function loadFlow(file, config, logger2, loggerConfig2, healthServer) {
3850
4161
  }
3851
4162
  const flowContext = {
3852
4163
  ...config,
3853
- ...loggerConfig2 ? { logger: loggerConfig2 } : {},
4164
+ ...loggerConfig ? { logger: loggerConfig } : {},
3854
4165
  ...healthServer ? { externalServer: true } : {}
3855
4166
  };
3856
4167
  const result = await module.default(flowContext);
@@ -3869,81 +4180,398 @@ async function loadFlow(file, config, logger2, loggerConfig2, healthServer) {
3869
4180
  httpHandler: result.httpHandler
3870
4181
  };
3871
4182
  }
3872
- async function runFlow(file, config, logger2, loggerConfig2) {
3873
- 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
+ }
3874
4188
  try {
3875
- const handle = await loadFlow(file, config, logger2, loggerConfig2);
3876
- logger2.info("Flow running");
3877
- if (config?.port) {
3878
- logger2.info(`Port: ${config.port}`);
3879
- }
3880
- const shutdown = async (signal) => {
3881
- logger2.info(`Received ${signal}, shutting down gracefully...`);
3882
- const forceTimer = setTimeout(() => {
3883
- logger2.error("Shutdown timed out, forcing exit");
3884
- process.exit(1);
3885
- }, 15e3);
3886
- try {
3887
- if (handle.collector.command) {
3888
- await handle.collector.command("shutdown");
3889
- }
3890
- logger2.info("Shutdown complete");
3891
- clearTimeout(forceTimer);
3892
- process.exit(0);
3893
- } catch (error) {
3894
- clearTimeout(forceTimer);
3895
- const message = error instanceof Error ? error.message : String(error);
3896
- logger2.error(`Error during shutdown: ${message}`);
3897
- process.exit(1);
3898
- }
3899
- };
3900
- process.on("SIGTERM", () => shutdown("SIGTERM"));
3901
- process.on("SIGINT", () => shutdown("SIGINT"));
3902
- await new Promise(() => {
3903
- });
4189
+ if (currentHandle.collector.command) {
4190
+ await currentHandle.collector.command("shutdown");
4191
+ }
3904
4192
  } catch (error) {
3905
- const message = error instanceof Error ? error.message : String(error);
3906
- logger2.error(`Failed to run flow: ${message}`);
3907
- if (error instanceof Error && error.stack) {
3908
- 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 {
3909
4226
  }
3910
- throw error;
3911
4227
  }
4228
+ return JSON.stringify({ version: "0.0.0" });
3912
4229
  }
4230
+ var VERSION = JSON.parse(findPackageJson()).version;
3913
4231
 
3914
4232
  // src/runtime/heartbeat.ts
3915
- init_version();
3916
- 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
+ }
3917
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
+ }
4377
+
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
+ }
3918
4401
 
3919
- // src/commands/run/execution.ts
3920
- var logLevel = process.env.VERBOSE === "true" ? Level4.DEBUG : Level4.INFO;
3921
- var loggerConfig = { level: logLevel };
3922
- var logger = createLogger2(loggerConfig);
3923
- async function executeRunLocal(flowPath, options) {
3924
- const config = {
3925
- port: options.port,
3926
- host: options.host
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
+ }
3927
4517
  };
3928
- 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
+ }
3929
4547
  }
3930
4548
 
3931
4549
  // src/commands/run/index.ts
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
+ }
3932
4560
  async function runCommand(options) {
3933
4561
  const timer = createTimer();
3934
4562
  timer.start();
3935
- const logger2 = createCLILogger(options);
4563
+ const logger = createCLILogger(options);
3936
4564
  try {
3937
- const configPath = validateFlowFile(options.config);
4565
+ const port = options.port ?? 8080;
3938
4566
  if (options.port !== void 0) {
3939
4567
  validatePort(options.port);
3940
4568
  }
3941
4569
  const runtimeDeps = ["express", "cors"];
3942
4570
  for (const dep of runtimeDeps) {
3943
4571
  try {
3944
- __require.resolve(dep);
4572
+ esmRequire.resolve(dep);
3945
4573
  } catch {
3946
- logger2.error(
4574
+ logger.error(
3947
4575
  `Missing runtime dependency "${dep}"
3948
4576
  Server flows require express and cors when running outside Docker.
3949
4577
  Run: npm install express cors`
@@ -3951,84 +4579,167 @@ Run: npm install express cors`
3951
4579
  process.exit(1);
3952
4580
  }
3953
4581
  }
3954
- const isPreBuilt = isPreBuiltConfig(configPath);
3955
- let flowPath;
3956
- if (isPreBuilt) {
3957
- flowPath = path13.resolve(configPath);
3958
- logger2.debug(`Using pre-built flow: ${path13.basename(flowPath)}`);
3959
- } else {
3960
- logger2.debug("Building flow bundle");
3961
- flowPath = await prepareBundleForRun(configPath, {
3962
- verbose: options.verbose,
3963
- silent: options.json || options.silent
3964
- });
3965
- logger2.debug("Bundle ready");
3966
- }
3967
- if (options.deployment) {
3968
- const { startHeartbeat: startHeartbeat2 } = await Promise.resolve().then(() => (init_heartbeat(), heartbeat_exports));
3969
- await startHeartbeat2({
3970
- deployment: options.deployment,
3971
- projectId: options.project,
3972
- url: options.url || `http://localhost:${options.port || 8080}`,
3973
- healthEndpoint: options.healthEndpoint,
3974
- heartbeatInterval: options.heartbeatInterval
3975
- });
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
+ };
3976
4628
  }
3977
- logger2.info("Starting flow...");
3978
- await executeRunLocal(flowPath, {
3979
- port: options.port,
3980
- 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
3981
4641
  });
3982
4642
  } catch (error) {
3983
4643
  const duration = timer.getElapsed() / 1e3;
3984
4644
  const errorMessage = getErrorMessage(error);
3985
4645
  if (options.json) {
3986
- logger2.json({
4646
+ logger.json({
3987
4647
  success: false,
3988
4648
  error: errorMessage,
3989
4649
  duration
3990
4650
  });
3991
4651
  } else {
3992
- logger2.error(`Error: ${errorMessage}`);
4652
+ logger.error(`Error: ${errorMessage}`);
3993
4653
  }
3994
4654
  process.exit(1);
3995
4655
  }
3996
4656
  }
3997
- async function run(options) {
3998
- const startTime = Date.now();
3999
- try {
4000
- let flowFile;
4001
- if (typeof options.config === "string") {
4002
- 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");
4003
4664
  } else {
4004
- throw new Error("Programmatic run() requires config file path");
4665
+ logger.info(`Bundle: ${resolved.path}`);
4005
4666
  }
4006
- if (options.port !== void 0) {
4007
- validatePort(options.port);
4667
+ if (isPreBuiltConfig(resolved.path)) {
4668
+ return path14.resolve(resolved.path);
4008
4669
  }
4009
- const runtimeDeps = ["express", "cors"];
4010
- for (const dep of runtimeDeps) {
4011
- try {
4012
- __require.resolve(dep);
4013
- } catch {
4014
- throw new Error(
4015
- `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"
4016
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;
4017
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
+ );
4018
4726
  }
4019
- const isPreBuilt = isPreBuiltConfig(flowFile);
4020
- let flowPath;
4021
- if (isPreBuilt) {
4022
- flowPath = path13.resolve(flowFile);
4023
- } else {
4024
- flowPath = await prepareBundleForRun(flowFile, {
4025
- verbose: options.verbose,
4026
- silent: true
4027
- });
4028
- }
4029
- 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,
4030
4737
  port: options.port,
4031
- host: options.host
4738
+ flow: options.flow,
4739
+ flowId: options.flowId,
4740
+ project: options.project,
4741
+ verbose: options.verbose,
4742
+ silent: options.silent ?? true
4032
4743
  });
4033
4744
  return {
4034
4745
  success: true,
@@ -4047,6 +4758,8 @@ async function run(options) {
4047
4758
 
4048
4759
  // src/commands/validate/index.ts
4049
4760
  init_cli_logger();
4761
+ init_core();
4762
+ init_config();
4050
4763
  import chalk2 from "chalk";
4051
4764
 
4052
4765
  // src/commands/validate/validators/contract.ts
@@ -4174,10 +4887,10 @@ function validateEvent(input) {
4174
4887
  const zodResult = PartialEventSchema.safeParse(input);
4175
4888
  if (!zodResult.success) {
4176
4889
  for (const issue of zodResult.error.issues) {
4177
- const path14 = issue.path.join(".");
4178
- if (path14 === "name") continue;
4890
+ const path15 = issue.path.join(".");
4891
+ if (path15 === "name") continue;
4179
4892
  errors.push({
4180
- path: path14 || "root",
4893
+ path: path15 || "root",
4181
4894
  message: issue.message,
4182
4895
  code: "SCHEMA_VALIDATION"
4183
4896
  });
@@ -4204,7 +4917,7 @@ function validateEvent(input) {
4204
4917
 
4205
4918
  // src/commands/validate/validators/flow.ts
4206
4919
  import { schemas as schemas4 } from "@walkeros/core/dev";
4207
- var { validateFlowSetup: validateFlowSetup2 } = schemas4;
4920
+ var { validateFlowConfig: validateFlowConfig3 } = schemas4;
4208
4921
  function validateFlow(input, options = {}) {
4209
4922
  const errors = [];
4210
4923
  const warnings = [];
@@ -4220,7 +4933,7 @@ function validateFlow(input, options = {}) {
4220
4933
  });
4221
4934
  return { valid: false, type: "flow", errors, warnings, details };
4222
4935
  }
4223
- const coreResult = validateFlowSetup2(json);
4936
+ const coreResult = validateFlowConfig3(json);
4224
4937
  for (const issue of coreResult.errors) {
4225
4938
  errors.push({
4226
4939
  path: issue.path || "root",
@@ -4280,20 +4993,20 @@ function validateFlow(input, options = {}) {
4280
4993
  const flowsToCheck = options.flow ? [options.flow] : flowNames;
4281
4994
  let totalConnections = 0;
4282
4995
  for (const name of flowsToCheck) {
4283
- const flowConfig = flows[name];
4284
- if (!flowConfig) continue;
4285
- checkExampleCoverage(flowConfig, warnings);
4286
- const connections = buildConnectionGraph(flowConfig);
4996
+ const flowSettings = flows[name];
4997
+ if (!flowSettings) continue;
4998
+ checkExampleCoverage(flowSettings, warnings);
4999
+ const connections = buildConnectionGraph(flowSettings);
4287
5000
  for (const conn of connections) {
4288
5001
  checkCompatibility(conn, errors, warnings);
4289
5002
  }
4290
5003
  totalConnections += connections.length;
4291
5004
  const setupContract = config.contract;
4292
- if (setupContract || flowConfig.contract) {
5005
+ if (setupContract || flowSettings.contract) {
4293
5006
  checkContractCompliance(
4294
- flowConfig,
5007
+ flowSettings,
4295
5008
  setupContract,
4296
- flowConfig.contract,
5009
+ flowSettings.contract,
4297
5010
  warnings
4298
5011
  );
4299
5012
  }
@@ -4390,10 +5103,10 @@ function buildConnectionGraph(config) {
4390
5103
  function checkCompatibility(conn, errors, warnings) {
4391
5104
  const fromOuts = Object.entries(conn.from.examples).filter(([, ex]) => ex.out !== void 0 && ex.out !== false).map(([name, ex]) => ({ name, value: ex.out }));
4392
5105
  const toIns = Object.entries(conn.to.examples).filter(([, ex]) => ex.in !== void 0).map(([name, ex]) => ({ name, value: ex.in }));
4393
- const path14 = `${conn.from.type}.${conn.from.name} \u2192 ${conn.to.type}.${conn.to.name}`;
5106
+ const path15 = `${conn.from.type}.${conn.from.name} \u2192 ${conn.to.type}.${conn.to.name}`;
4394
5107
  if (fromOuts.length === 0 || toIns.length === 0) {
4395
5108
  warnings.push({
4396
- path: path14,
5109
+ path: path15,
4397
5110
  message: "Cannot check compatibility: missing out or in examples",
4398
5111
  suggestion: "Add out examples to the source step or in examples to the target step"
4399
5112
  });
@@ -4411,7 +5124,7 @@ function checkCompatibility(conn, errors, warnings) {
4411
5124
  }
4412
5125
  if (!hasMatch) {
4413
5126
  errors.push({
4414
- path: path14,
5127
+ path: path15,
4415
5128
  message: "No compatible out/in pair found between connected steps",
4416
5129
  code: "INCOMPATIBLE_EXAMPLES"
4417
5130
  });
@@ -4507,13 +5220,13 @@ function validateMapping(input) {
4507
5220
  import Ajv from "ajv";
4508
5221
  import { fetchPackageSchema } from "@walkeros/core";
4509
5222
  var SECTIONS = ["destinations", "sources", "transformers"];
4510
- function resolveEntry(path14, flowConfig) {
5223
+ function resolveEntry(path15, flowConfig) {
4511
5224
  const flows = flowConfig.flows;
4512
5225
  if (!flows || typeof flows !== "object") return "No flows found in config";
4513
5226
  const flowName = Object.keys(flows)[0];
4514
5227
  const flow = flows[flowName];
4515
5228
  if (!flow) return `Flow "${flowName}" is empty`;
4516
- const parts = path14.split(".");
5229
+ const parts = path15.split(".");
4517
5230
  if (parts.length === 2) {
4518
5231
  const [section, key] = parts;
4519
5232
  if (!SECTIONS.includes(section)) {
@@ -4550,15 +5263,15 @@ function resolveEntry(path14, flowConfig) {
4550
5263
  }
4551
5264
  return { section: matches[0].section, key, entry: matches[0].entry };
4552
5265
  }
4553
- return `Invalid path "${path14}". Use "section.key" or just "key"`;
5266
+ return `Invalid path "${path15}". Use "section.key" or just "key"`;
4554
5267
  }
4555
- async function validateEntry(path14, flowConfig) {
4556
- const resolved = resolveEntry(path14, flowConfig);
5268
+ async function validateEntry(path15, flowConfig) {
5269
+ const resolved = resolveEntry(path15, flowConfig);
4557
5270
  if (typeof resolved === "string") {
4558
5271
  return {
4559
5272
  valid: false,
4560
5273
  type: "entry",
4561
- errors: [{ path: path14, message: resolved, code: "ENTRY_VALIDATION" }],
5274
+ errors: [{ path: path15, message: resolved, code: "ENTRY_VALIDATION" }],
4562
5275
  warnings: [],
4563
5276
  details: {}
4564
5277
  };
@@ -4589,7 +5302,7 @@ async function validateEntry(path14, flowConfig) {
4589
5302
  type: "entry",
4590
5303
  errors: [
4591
5304
  {
4592
- path: path14,
5305
+ path: path15,
4593
5306
  message: error instanceof Error ? error.message : "Unknown error",
4594
5307
  code: "ENTRY_VALIDATION"
4595
5308
  }
@@ -4638,18 +5351,25 @@ async function validateEntry(path14, flowConfig) {
4638
5351
 
4639
5352
  // src/commands/validate/index.ts
4640
5353
  async function validate(type, input, options = {}) {
5354
+ let resolved = input;
5355
+ if (typeof input === "string") {
5356
+ resolved = await loadJsonFromSource(input, {
5357
+ name: type,
5358
+ required: true
5359
+ });
5360
+ }
4641
5361
  if (options.path) {
4642
- return validateEntry(options.path, input);
5362
+ return validateEntry(options.path, resolved);
4643
5363
  }
4644
5364
  switch (type) {
4645
5365
  case "contract":
4646
- return validateContract(input);
5366
+ return validateContract(resolved);
4647
5367
  case "event":
4648
- return validateEvent(input);
5368
+ return validateEvent(resolved);
4649
5369
  case "flow":
4650
- return validateFlow(input, { flow: options.flow });
5370
+ return validateFlow(resolved, { flow: options.flow });
4651
5371
  case "mapping":
4652
- return validateMapping(input);
5372
+ return validateMapping(resolved);
4653
5373
  default:
4654
5374
  throw new Error(`Unknown validation type: ${type}`);
4655
5375
  }
@@ -4689,7 +5409,7 @@ function formatResult(result, options) {
4689
5409
  return lines.join("\n");
4690
5410
  }
4691
5411
  async function validateCommand(options) {
4692
- const logger2 = createCLILogger({ ...options, stderr: true });
5412
+ const logger = createCLILogger({ ...options, stderr: true });
4693
5413
  try {
4694
5414
  let input;
4695
5415
  if (isStdinPiped() && !options.input) {
@@ -4700,10 +5420,7 @@ async function validateCommand(options) {
4700
5420
  throw new Error("Invalid JSON received on stdin");
4701
5421
  }
4702
5422
  } else {
4703
- input = await loadJsonFromSource(options.input, {
4704
- name: options.type,
4705
- required: true
4706
- });
5423
+ input = options.input;
4707
5424
  }
4708
5425
  const result = await validate(options.type, input, {
4709
5426
  flow: options.flow,
@@ -4739,7 +5456,7 @@ async function validateCommand(options) {
4739
5456
  );
4740
5457
  await writeResult(errorOutput + "\n", { output: options.output });
4741
5458
  } else {
4742
- logger2.error(`Error: ${errorMessage}`);
5459
+ logger.error(`Error: ${errorMessage}`);
4743
5460
  }
4744
5461
  process.exit(3);
4745
5462
  }
@@ -4755,22 +5472,22 @@ async function openInBrowser(url) {
4755
5472
  await open(url);
4756
5473
  }
4757
5474
  async function loginCommand(options) {
4758
- const logger2 = createCLILogger(options);
5475
+ const logger = createCLILogger(options);
4759
5476
  try {
4760
5477
  const result = await login({ url: options.url });
4761
5478
  if (options.json) {
4762
- logger2.json(result);
5479
+ logger.json(result);
4763
5480
  } else if (result.success) {
4764
- logger2.info(`Logged in as ${result.email}`);
4765
- logger2.info(`Token stored in ${result.configPath}`);
5481
+ logger.info(`Logged in as ${result.email}`);
5482
+ logger.info(`Token stored in ${result.configPath}`);
4766
5483
  }
4767
5484
  process.exit(result.success ? 0 : 1);
4768
5485
  } catch (error) {
4769
5486
  const message = error instanceof Error ? error.message : String(error);
4770
5487
  if (options.json) {
4771
- logger2.json({ success: false, error: message });
5488
+ logger.json({ success: false, error: message });
4772
5489
  } else {
4773
- logger2.error(message);
5490
+ logger.error(message);
4774
5491
  }
4775
5492
  process.exit(1);
4776
5493
  }
@@ -4842,21 +5559,23 @@ async function login(options = {}) {
4842
5559
  init_cli_logger();
4843
5560
  init_config_file();
4844
5561
  async function logoutCommand(options) {
4845
- const logger2 = createCLILogger(options);
5562
+ const logger = createCLILogger(options);
4846
5563
  const deleted = deleteConfig();
4847
5564
  const configPath = getConfigPath();
4848
5565
  if (options.json) {
4849
- logger2.json({ success: true, deleted });
5566
+ logger.json({ success: true, deleted });
4850
5567
  } else if (deleted) {
4851
- logger2.info(`Logged out. Token removed from ${configPath}`);
5568
+ logger.info(`Logged out. Token removed from ${configPath}`);
4852
5569
  } else {
4853
- logger2.info("No stored credentials found.");
5570
+ logger.info("No stored credentials found.");
4854
5571
  }
4855
5572
  process.exit(0);
4856
5573
  }
4857
5574
 
4858
5575
  // src/commands/auth/index.ts
5576
+ init_api_client();
4859
5577
  init_cli_logger();
5578
+ init_output();
4860
5579
  async function whoami() {
4861
5580
  const client = createApiClient();
4862
5581
  const { data, error } = await client.GET("/api/auth/whoami");
@@ -4864,26 +5583,28 @@ async function whoami() {
4864
5583
  return data;
4865
5584
  }
4866
5585
  async function whoamiCommand(options) {
4867
- const logger2 = createCLILogger(options);
5586
+ const logger = createCLILogger(options);
4868
5587
  try {
4869
5588
  const result = await whoami();
4870
5589
  if (options.json) {
4871
5590
  await writeResult(JSON.stringify(result, null, 2), options);
4872
5591
  } else {
4873
5592
  const data = result;
4874
- if (data.email) logger2.info(`${data.email}`);
4875
- if (data.userId) logger2.info(`User: ${data.userId}`);
4876
- 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}`);
4877
5596
  }
4878
5597
  } catch (error) {
4879
- logger2.error(error instanceof Error ? error.message : String(error));
5598
+ logger.error(error instanceof Error ? error.message : String(error));
4880
5599
  process.exit(1);
4881
5600
  }
4882
5601
  }
4883
5602
 
4884
5603
  // src/commands/projects/index.ts
5604
+ init_api_client();
4885
5605
  init_auth();
4886
5606
  init_cli_logger();
5607
+ init_output();
4887
5608
  async function listProjects() {
4888
5609
  const client = createApiClient();
4889
5610
  const { data, error } = await client.GET("/api/projects");
@@ -4930,12 +5651,12 @@ async function deleteProject(options = {}) {
4930
5651
  return data ?? { success: true };
4931
5652
  }
4932
5653
  async function handleResult(fn2, options) {
4933
- const logger2 = createCLILogger(options);
5654
+ const logger = createCLILogger(options);
4934
5655
  try {
4935
5656
  const result = await fn2();
4936
5657
  await writeResult(JSON.stringify(result, null, 2), options);
4937
5658
  } catch (error) {
4938
- logger2.error(error instanceof Error ? error.message : String(error));
5659
+ logger.error(error instanceof Error ? error.message : String(error));
4939
5660
  process.exit(1);
4940
5661
  }
4941
5662
  }
@@ -4972,8 +5693,11 @@ async function deleteProjectCommand(projectId, options) {
4972
5693
  }
4973
5694
 
4974
5695
  // src/commands/flows/index.ts
5696
+ init_api_client();
4975
5697
  init_auth();
4976
5698
  init_cli_logger();
5699
+ init_output();
5700
+ init_stdin();
4977
5701
  async function listFlows(options = {}) {
4978
5702
  const id = options.projectId ?? requireProjectId();
4979
5703
  const client = createApiClient();
@@ -4996,7 +5720,10 @@ async function getFlow(options) {
4996
5720
  const { data, error } = await client.GET(
4997
5721
  "/api/projects/{projectId}/flows/{flowId}",
4998
5722
  {
4999
- params: { path: { projectId: id, flowId: options.flowId } }
5723
+ params: {
5724
+ path: { projectId: id, flowId: options.flowId },
5725
+ query: options.fields ? { fields: options.fields.join(",") } : {}
5726
+ }
5000
5727
  }
5001
5728
  );
5002
5729
  if (error) throw new Error(error.error?.message || "Failed to get flow");
@@ -5007,8 +5734,8 @@ async function createFlow(options) {
5007
5734
  const client = createApiClient();
5008
5735
  const { data, error } = await client.POST("/api/projects/{projectId}/flows", {
5009
5736
  params: { path: { projectId: id } },
5010
- // Content is user-provided JSON; server validates the full schema
5011
- 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 }
5012
5739
  });
5013
5740
  if (error) throw new Error(error.error?.message || "Failed to create flow");
5014
5741
  return data;
@@ -5018,13 +5745,16 @@ async function updateFlow(options) {
5018
5745
  const client = createApiClient();
5019
5746
  const body = {};
5020
5747
  if (options.name !== void 0) body.name = options.name;
5021
- if (options.content !== void 0) body.content = options.content;
5748
+ if (options.content !== void 0) body.config = options.content;
5022
5749
  const { data, error } = await client.PATCH(
5023
5750
  "/api/projects/{projectId}/flows/{flowId}",
5024
5751
  {
5025
5752
  params: { path: { projectId: id, flowId: options.flowId } },
5026
5753
  // Dynamically constructed body; server validates the full schema
5027
- body
5754
+ body,
5755
+ ...options.mergePatch && {
5756
+ headers: { "Content-Type": "application/merge-patch+json" }
5757
+ }
5028
5758
  }
5029
5759
  );
5030
5760
  if (error) throw new Error(error.error?.message || "Failed to update flow");
@@ -5057,12 +5787,12 @@ async function duplicateFlow(options) {
5057
5787
  return data;
5058
5788
  }
5059
5789
  async function handleResult2(fn2, options) {
5060
- const logger2 = createCLILogger(options);
5790
+ const logger = createCLILogger(options);
5061
5791
  try {
5062
5792
  const result = await fn2();
5063
5793
  await writeResult(JSON.stringify(result, null, 2), options);
5064
5794
  } catch (error) {
5065
- logger2.error(error instanceof Error ? error.message : String(error));
5795
+ logger.error(error instanceof Error ? error.message : String(error));
5066
5796
  process.exit(1);
5067
5797
  }
5068
5798
  }
@@ -5122,21 +5852,24 @@ async function readFlowStdin() {
5122
5852
  }
5123
5853
 
5124
5854
  // src/commands/deploy/index.ts
5855
+ init_api_client();
5125
5856
  init_auth();
5857
+ init_sse();
5126
5858
  init_cli_logger();
5127
- async function resolveConfigId(options) {
5859
+ init_output();
5860
+ async function resolveSettingsId(options) {
5128
5861
  const flow = await getFlow({
5129
5862
  flowId: options.flowId,
5130
5863
  projectId: options.projectId
5131
5864
  });
5132
- const configs = flow.configs;
5133
- if (!configs?.length) {
5134
- throw new Error("Flow has no configs.");
5865
+ const settings = flow.settings;
5866
+ if (!settings?.length) {
5867
+ throw new Error("Flow has no settings.");
5135
5868
  }
5136
- const match = configs.find((c2) => c2.name === options.flowName);
5869
+ const match = settings.find((c2) => c2.name === options.flowName);
5137
5870
  if (!match) {
5138
5871
  throw new Error(
5139
- `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(", ")}`
5140
5873
  );
5141
5874
  }
5142
5875
  return match.id;
@@ -5146,8 +5879,8 @@ async function getAvailableFlowNames(options) {
5146
5879
  flowId: options.flowId,
5147
5880
  projectId: options.projectId
5148
5881
  });
5149
- const configs = flow.configs;
5150
- return configs?.map((c2) => c2.name) ?? [];
5882
+ const settings = flow.settings;
5883
+ return settings?.map((c2) => c2.name) ?? [];
5151
5884
  }
5152
5885
  async function streamDeploymentStatus(projectId, deploymentId, options) {
5153
5886
  const base = resolveBaseUrl();
@@ -5194,15 +5927,15 @@ async function deploy(options) {
5194
5927
  const projectId = options.projectId ?? requireProjectId();
5195
5928
  const client = createApiClient();
5196
5929
  if (options.flowName) {
5197
- const configId = await resolveConfigId({
5930
+ const settingsId = await resolveSettingsId({
5198
5931
  flowId: options.flowId,
5199
5932
  projectId,
5200
5933
  flowName: options.flowName
5201
5934
  });
5202
- return deployConfig({
5935
+ return deploySettings({
5203
5936
  ...options,
5204
5937
  projectId,
5205
- configId,
5938
+ settingsId,
5206
5939
  timeout: options.timeout,
5207
5940
  signal: options.signal,
5208
5941
  onStatus: options.onStatus
@@ -5221,7 +5954,7 @@ async function deploy(options) {
5221
5954
  projectId
5222
5955
  });
5223
5956
  throw new Error(
5224
- `This flow has multiple configs. Use --flow <name> to specify one.
5957
+ `This flow has multiple settings. Use --flow <name> to specify one.
5225
5958
  Available: ${names.join(", ")}`
5226
5959
  );
5227
5960
  }
@@ -5235,11 +5968,11 @@ Available: ${names.join(", ")}`
5235
5968
  });
5236
5969
  return { ...data, ...result };
5237
5970
  }
5238
- async function deployConfig(options) {
5239
- const { flowId, projectId, configId } = options;
5971
+ async function deploySettings(options) {
5972
+ const { flowId, projectId, settingsId } = options;
5240
5973
  const base = resolveBaseUrl();
5241
5974
  const response = await authenticatedFetch(
5242
- `${base}/api/projects/${projectId}/flows/${flowId}/configs/${configId}/deploy`,
5975
+ `${base}/api/projects/${projectId}/flows/${flowId}/settings/${settingsId}/deploy`,
5243
5976
  { method: "POST" }
5244
5977
  );
5245
5978
  if (!response.ok) {
@@ -5260,14 +5993,14 @@ async function deployConfig(options) {
5260
5993
  async function getDeployment(options) {
5261
5994
  const projectId = options.projectId ?? requireProjectId();
5262
5995
  if (options.flowName) {
5263
- const configId = await resolveConfigId({
5996
+ const settingsId = await resolveSettingsId({
5264
5997
  flowId: options.flowId,
5265
5998
  projectId,
5266
5999
  flowName: options.flowName
5267
6000
  });
5268
6001
  const base = resolveBaseUrl();
5269
6002
  const response = await authenticatedFetch(
5270
- `${base}/api/projects/${projectId}/flows/${options.flowId}/configs/${configId}/deploy`
6003
+ `${base}/api/projects/${projectId}/flows/${options.flowId}/settings/${settingsId}/deploy`
5271
6004
  );
5272
6005
  if (!response.ok) {
5273
6006
  const body = await response.json().catch(() => ({}));
@@ -5366,6 +6099,8 @@ async function getDeploymentCommand(flowId, options) {
5366
6099
  // src/commands/deployments/index.ts
5367
6100
  init_auth();
5368
6101
  init_cli_logger();
6102
+ init_output();
6103
+ init_loader();
5369
6104
  import { getPlatform as getPlatform4 } from "@walkeros/core";
5370
6105
  async function listDeployments(options = {}) {
5371
6106
  const id = options.projectId ?? requireProjectId();
@@ -5435,12 +6170,12 @@ async function deleteDeployment(options) {
5435
6170
  return data ?? { success: true };
5436
6171
  }
5437
6172
  async function handleResult3(fn2, options) {
5438
- const logger2 = createCLILogger(options);
6173
+ const logger = createCLILogger(options);
5439
6174
  try {
5440
6175
  const result = await fn2();
5441
6176
  await writeResult(JSON.stringify(result, null, 2), options);
5442
6177
  } catch (error) {
5443
- logger2.error(error instanceof Error ? error.message : String(error));
6178
+ logger.error(error instanceof Error ? error.message : String(error));
5444
6179
  process.exit(1);
5445
6180
  }
5446
6181
  }
@@ -5500,23 +6235,23 @@ async function createDeployCommand(config, options) {
5500
6235
  );
5501
6236
  }
5502
6237
  const flow = await resp.json();
5503
- if (!flow.content) throw new Error("Flow has no content");
5504
- const content = flow.content;
5505
- const flows = content.flows;
5506
- 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");
5507
6242
  const flowName = options.flow ?? Object.keys(flows)[0];
5508
6243
  if (!flowName) throw new Error("No flows found in config");
5509
- const flowConfig = flows[flowName];
5510
- if (!flowConfig || typeof flowConfig !== "object")
6244
+ const flowSettings = flows[flowName];
6245
+ if (!flowSettings || typeof flowSettings !== "object")
5511
6246
  throw new Error("Invalid flow config");
5512
- if ("web" in flowConfig) type = "web";
5513
- else if ("server" in flowConfig) type = "server";
6247
+ if ("web" in flowSettings) type = "web";
6248
+ else if ("server" in flowSettings) type = "server";
5514
6249
  else throw new Error('Flow must have "web" or "server" key');
5515
6250
  } else {
5516
6251
  const result2 = await loadFlowConfig(config, {
5517
6252
  flowName: options.flow
5518
6253
  });
5519
- type = getPlatform4(result2.flowConfig);
6254
+ type = getPlatform4(result2.flowSettings);
5520
6255
  }
5521
6256
  const deployment = await createDeployment({
5522
6257
  type,
@@ -5556,7 +6291,11 @@ async function createDeployCommand(config, options) {
5556
6291
  }
5557
6292
 
5558
6293
  // src/index.ts
6294
+ init_bundle();
5559
6295
  init_auth();
6296
+ init_api_client();
6297
+ init_sse();
6298
+ init_utils();
5560
6299
  export {
5561
6300
  bundle,
5562
6301
  bundleCommand,