@walkeros/cli 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +112 -42
  3. package/dist/__tests__/bundle/bundler.test.js +174 -164
  4. package/dist/__tests__/bundle/bundler.test.js.map +1 -1
  5. package/dist/__tests__/bundle/programmatic.test.js +76 -53
  6. package/dist/__tests__/bundle/programmatic.test.js.map +1 -1
  7. package/dist/__tests__/cli.test.js +58 -46
  8. package/dist/__tests__/cli.test.js.map +1 -1
  9. package/dist/__tests__/config-loader.test.d.ts +1 -1
  10. package/dist/__tests__/config-loader.test.js +231 -212
  11. package/dist/__tests__/config-loader.test.js.map +1 -1
  12. package/dist/__tests__/core/build-cache.test.d.ts +2 -0
  13. package/dist/__tests__/core/build-cache.test.d.ts.map +1 -0
  14. package/dist/__tests__/core/build-cache.test.js +55 -0
  15. package/dist/__tests__/core/build-cache.test.js.map +1 -0
  16. package/dist/__tests__/core/cache-utils.test.d.ts +2 -0
  17. package/dist/__tests__/core/cache-utils.test.d.ts.map +1 -0
  18. package/dist/__tests__/core/cache-utils.test.js +70 -0
  19. package/dist/__tests__/core/cache-utils.test.js.map +1 -0
  20. package/dist/__tests__/integration/bundle-run.integration.test.js +8 -4
  21. package/dist/__tests__/integration/bundle-run.integration.test.js.map +1 -1
  22. package/dist/__tests__/simulate/node-executor.test.d.ts +5 -0
  23. package/dist/__tests__/simulate/node-executor.test.d.ts.map +1 -0
  24. package/dist/__tests__/simulate/node-executor.test.js +25 -0
  25. package/dist/__tests__/simulate/node-executor.test.js.map +1 -0
  26. package/dist/__tests__/simulate/server-simulate.integration.test.d.ts +5 -0
  27. package/dist/__tests__/simulate/server-simulate.integration.test.d.ts.map +1 -0
  28. package/dist/__tests__/simulate/server-simulate.integration.test.js +59 -0
  29. package/dist/__tests__/simulate/server-simulate.integration.test.js.map +1 -0
  30. package/dist/__tests__/smoke/production.smoke.test.js +9 -2
  31. package/dist/__tests__/smoke/production.smoke.test.js.map +1 -1
  32. package/dist/commands/bundle/bundler.d.ts.map +1 -1
  33. package/dist/commands/bundle/bundler.js +93 -3
  34. package/dist/commands/bundle/bundler.js.map +1 -1
  35. package/dist/commands/bundle/index.d.ts +16 -10
  36. package/dist/commands/bundle/index.d.ts.map +1 -1
  37. package/dist/commands/bundle/index.js +44 -32
  38. package/dist/commands/bundle/index.js.map +1 -1
  39. package/dist/commands/bundle/package-manager.d.ts +2 -1
  40. package/dist/commands/bundle/package-manager.d.ts.map +1 -1
  41. package/dist/commands/bundle/package-manager.js +34 -7
  42. package/dist/commands/bundle/package-manager.js.map +1 -1
  43. package/dist/commands/cache.d.ts +3 -0
  44. package/dist/commands/cache.d.ts.map +1 -0
  45. package/dist/commands/cache.js +44 -0
  46. package/dist/commands/cache.js.map +1 -0
  47. package/dist/commands/push/index.d.ts.map +1 -1
  48. package/dist/commands/push/index.js +49 -44
  49. package/dist/commands/push/index.js.map +1 -1
  50. package/dist/commands/push/types.d.ts +1 -1
  51. package/dist/commands/push/types.d.ts.map +1 -1
  52. package/dist/commands/run/__tests__/run.integration.test.js +14 -15
  53. package/dist/commands/run/__tests__/run.integration.test.js.map +1 -1
  54. package/dist/commands/run/utils.d.ts +4 -1
  55. package/dist/commands/run/utils.d.ts.map +1 -1
  56. package/dist/commands/run/utils.js +18 -24
  57. package/dist/commands/run/utils.js.map +1 -1
  58. package/dist/commands/run/validators.d.ts +9 -5
  59. package/dist/commands/run/validators.d.ts.map +1 -1
  60. package/dist/commands/run/validators.js +14 -11
  61. package/dist/commands/run/validators.js.map +1 -1
  62. package/dist/commands/simulate/index.d.ts +1 -0
  63. package/dist/commands/simulate/index.d.ts.map +1 -1
  64. package/dist/commands/simulate/index.js +1 -0
  65. package/dist/commands/simulate/index.js.map +1 -1
  66. package/dist/commands/simulate/node-executor.d.ts +28 -0
  67. package/dist/commands/simulate/node-executor.d.ts.map +1 -0
  68. package/dist/commands/simulate/node-executor.js +94 -0
  69. package/dist/commands/simulate/node-executor.js.map +1 -0
  70. package/dist/commands/simulate/simulator.d.ts.map +1 -1
  71. package/dist/commands/simulate/simulator.js +36 -32
  72. package/dist/commands/simulate/simulator.js.map +1 -1
  73. package/dist/config/build-defaults.d.ts +49 -0
  74. package/dist/config/build-defaults.d.ts.map +1 -0
  75. package/dist/config/build-defaults.js +72 -0
  76. package/dist/config/build-defaults.js.map +1 -0
  77. package/dist/config/index.d.ts +6 -7
  78. package/dist/config/index.d.ts.map +1 -1
  79. package/dist/config/index.js +6 -7
  80. package/dist/config/index.js.map +1 -1
  81. package/dist/config/loader.d.ts +34 -27
  82. package/dist/config/loader.d.ts.map +1 -1
  83. package/dist/config/loader.js +107 -92
  84. package/dist/config/loader.js.map +1 -1
  85. package/dist/config/validators.d.ts +34 -8
  86. package/dist/config/validators.d.ts.map +1 -1
  87. package/dist/config/validators.js +59 -21
  88. package/dist/config/validators.js.map +1 -1
  89. package/dist/core/asset-resolver.d.ts +8 -15
  90. package/dist/core/asset-resolver.d.ts.map +1 -1
  91. package/dist/core/asset-resolver.js +30 -37
  92. package/dist/core/asset-resolver.js.map +1 -1
  93. package/dist/core/build-cache.d.ts +23 -0
  94. package/dist/core/build-cache.d.ts.map +1 -0
  95. package/dist/core/build-cache.js +43 -0
  96. package/dist/core/build-cache.js.map +1 -0
  97. package/dist/core/cache-utils.d.ts +27 -0
  98. package/dist/core/cache-utils.d.ts.map +1 -0
  99. package/dist/core/cache-utils.js +60 -0
  100. package/dist/core/cache-utils.js.map +1 -0
  101. package/dist/core/docker.d.ts.map +1 -1
  102. package/dist/core/docker.js +8 -25
  103. package/dist/core/docker.js.map +1 -1
  104. package/dist/core/index.d.ts +1 -0
  105. package/dist/core/index.d.ts.map +1 -1
  106. package/dist/core/index.js +1 -0
  107. package/dist/core/index.js.map +1 -1
  108. package/dist/core/local-packages.d.ts +19 -0
  109. package/dist/core/local-packages.d.ts.map +1 -0
  110. package/dist/core/local-packages.js +60 -0
  111. package/dist/core/local-packages.js.map +1 -0
  112. package/dist/examples/.npm-cache/content-v2/sha512/0d/2d/7581c288670eaf8538ddd9df145b78756ce3be0791c6e0b9cd33429b3bae894525b9bda287a3cedffbcdd2c7b3107bafc03f2b0367eea489eee1cc042abb +1 -0
  113. package/dist/examples/.npm-cache/content-v2/sha512/12/20/bc4f5acca143809f7e07da1fdafb38137d93243de4d5b403e6e10b92d0d3a6e51eab24fe9dbc9d3ed1cd72e8f7a406085e99c422bb2c7d1166cf9f1f564e +0 -0
  114. package/dist/examples/.npm-cache/content-v2/sha512/22/ee/fb2695b01871c1d36946bdcfb49f1b520a57200d0a0b221b1e7d5f047ab38a8b2ab0e5f0e25a00acde1f3f2f9d24430a18f1092d438bc1a9e9891cc45f75 +0 -0
  115. package/dist/examples/.npm-cache/content-v2/sha512/24/89/da1ce6a61bca6de7e132f241a675c01c83738bf6b78af25b5cce01d3030361332b3fe938571e2b721f1555da9ddf930fdcf8c02f0471556071590e68cc09 +0 -0
  116. package/dist/examples/.npm-cache/content-v2/sha512/47/fd/c6be997da99228c3e279b95d4a46d6913947078a178f54ac71795a159f3513b1483232f4c2d0a1f403178bf9f96bb19615de32a9e2133e949880c6bc15e2 +0 -0
  117. package/dist/examples/.npm-cache/content-v2/sha512/4b/1c/c1cb7f8b32102071a89fef97158daa32080ebaedfbbd596880d2213d84e305abc76d2a95a412ded55c1c3d487adcb1ceff87fc2c85d7e2856ebd9d3f16f3 +0 -0
  118. package/dist/examples/.npm-cache/content-v2/sha512/6e/53/ff864769671f44f39d8a3bf904cd646535b745cc4824a8bb3189193b474678049f43b5178ba15cad7f0289046105e70f1565afc84e907120b35a466690fd +1 -0
  119. package/dist/examples/.npm-cache/content-v2/sha512/70/4c/4c8837d446965c5551b4ea527e95fa011744fb727581d82cf35bb5599ea0b57d18baa490f7af93ef9a16e8e45e5c0802737da20575f4056a4a5c9a3cd288 +0 -0
  120. package/dist/examples/.npm-cache/content-v2/sha512/96/ad/05de3bbb12d7de8ea353f962bdaea7d2eb44f707f2973462a6635daf537c67b46cca7764fed7d464fe62152c3f783a07aba1ceb35e09ad446bff05a4b466 +1 -0
  121. package/dist/examples/.npm-cache/content-v2/sha512/b5/20/52dde94e6cef7170f6089c64a4843e57be18be450d956f4e455905aed047ae6a368451c93035e6ac3ee59576b600f03f815afba0836b3a16e10a9aaca4ba +1 -0
  122. package/dist/examples/.npm-cache/content-v2/sha512/c7/a9/d166a1c39f97df312c59261319ba1cf9aac178bda0a0cb697d5ddd78bd8dd38ef1bf40017bcc8633c2049896c2d70696d9bff9280851f270792ff38bb3a0 +1 -0
  123. package/dist/examples/.npm-cache/content-v2/sha512/e0/d0/8c14083b633e6adbd3c6a93da5fc0f6bbd456c5512ef276920bedd8d85d551052adff992de977aff326616a211aaa2d6ddcc801149e9b7f914f566359b6a +1 -0
  124. package/dist/examples/.npm-cache/content-v2/sha512/e7/c5/06ad3fd79ac4f1031fe0b16ea5e54e232ca397bbcd7592c679021cbfb027276099f8c848f3f7a7691f0102ad53aa64f9141e61d729b037a678bd60440d17 +1 -0
  125. package/dist/examples/.npm-cache/content-v2/sha512/f3/28/d5d32329604ed7d471a4949105daa2cc98858cf24f45b0b97c41d0eb0d5a9fe7bf1f69c792161cc6693e4fc1b52e886ac41875ebfb8fe47fafe417ca3e6e +0 -0
  126. package/dist/examples/.npm-cache/index-v5/04/5a/2b5d7a7c407d85d746baa0f5c9388a333e35a717a8a0a81943daa6cb1364 +3 -0
  127. package/dist/examples/.npm-cache/index-v5/12/9a/eba560cbace295d8ee04cf283015377bd77b379e70968fb6bc407c7fc410 +15 -0
  128. package/dist/examples/.npm-cache/index-v5/2f/a2/7b047564b0ee21ac835ec609e89153dd6549be554d098584d5bfd19fe043 +15 -0
  129. package/dist/examples/.npm-cache/index-v5/32/8e/322d58dd8d1e000be248ada51385bf96288e56039de9feec1a4c6a467653 +3 -0
  130. package/dist/examples/.npm-cache/index-v5/57/93/d1d7cd1402e3e26468db03f2870822bb2c9018a506cdfb3b405f38cd3e1c +3 -0
  131. package/dist/examples/.npm-cache/index-v5/5d/f8/0a1f4fa7149e4ff33e09eb6aea41ac8d1730c868a5d3ace91f762698acff +3 -0
  132. package/dist/examples/.npm-cache/index-v5/69/a4/a92c72d838259b051cdf8e0acfb2bc680b6d4cfc642314a7836c3f7b2c50 +15 -0
  133. package/dist/examples/.npm-cache/index-v5/71/31/6da3423bb203f3de5eb16c942431073f89be2cfcb40058ec91dcb5ce0abc +15 -0
  134. package/dist/examples/.npm-cache/index-v5/7b/94/72b6bffa050d9ef52a558dd220663695bc606f756be0dfa196ef4f3913ba +3 -0
  135. package/dist/examples/.npm-cache/index-v5/85/9e/99e97fdd562517e56285337db91d1a8f2f416b8d631cf4d7d754fa671299 +15 -0
  136. package/dist/examples/.npm-cache/index-v5/92/4c/9416ada81a9b3c679539fd1ab53f8de3d41ff268f35eba7a194389a85b06 +3 -0
  137. package/dist/examples/.npm-cache/index-v5/c1/5a/13df76b218deed8a6ef12961116af5183db98c53fad1b922fd9edc075247 +3 -0
  138. package/dist/examples/.npm-cache/index-v5/cb/11/253c55410a8ab7c4a9ea9d6e1bf8ef1450a581da64c478074dfd82c8bff6 +3 -0
  139. package/dist/examples/.npm-cache/index-v5/d5/ae/b57fad3a62b5ba2dbdf24b042a9e7b70820f3db00e5a630f02e1fea020dc +3 -0
  140. package/dist/examples/.npm-cache/index-v5/d6/32/2f620f83c7d14451de98de8298c2408e05a16cc0829bd16c891ac19d7a67 +3 -0
  141. package/dist/examples/.npm-cache/index-v5/dd/b5/01dc7a3cd8b6a03a69aee9af500d51ae19cb0aa12631a4aafd152148b8e5 +15 -0
  142. package/dist/examples/.npm-cache/index-v5/e0/cf/6b862c15d74630d3871cd813d305210ab741311deb10baf8813014e0bc30 +3 -0
  143. package/dist/examples/.npm-cache/index-v5/e2/be/e880ccd35950a814d3c1dded34d3938ac61b15a195321dc51357f801aad4 +15 -0
  144. package/dist/examples/.npm-cache/index-v5/e5/1f/f4affe0b392cd03288f23cc03abcb274ff11a2c8f8965299de681914abb2 +3 -0
  145. package/dist/examples/.npm-cache/index-v5/f3/5b/9ebe450958ff0d7cc44ab0a00080cb8a3ff1389744b5eab5f97b68a6a6af +3 -0
  146. package/dist/examples/.npm-cache/index-v5/fb/c1/0de405e902866d53e7c30cf36a97dc2578838622b261816f44dc377c9a80 +3 -0
  147. package/dist/examples/README.md +343 -0
  148. package/dist/examples/event.json +53 -0
  149. package/dist/examples/flow-order-complete.json +68 -0
  150. package/dist/examples/flow-simple.json +32 -0
  151. package/dist/examples/flow.json +82 -0
  152. package/dist/examples/server-collect.json +60 -0
  153. package/dist/examples/server-collect.mjs +13540 -0
  154. package/dist/examples/test.html +43 -0
  155. package/dist/examples/web-serve.js +25503 -0
  156. package/dist/examples/web-serve.json +74 -0
  157. package/dist/index.d.ts +84 -201
  158. package/dist/index.d.ts.map +1 -1
  159. package/dist/index.js +675 -422
  160. package/dist/index.js.map +1 -1
  161. package/dist/schemas/index.d.ts +9 -0
  162. package/dist/schemas/index.d.ts.map +1 -0
  163. package/dist/schemas/index.js +9 -0
  164. package/dist/schemas/index.js.map +1 -0
  165. package/dist/schemas/primitives.d.ts +37 -0
  166. package/dist/schemas/primitives.d.ts.map +1 -0
  167. package/dist/schemas/primitives.js +43 -0
  168. package/dist/schemas/primitives.js.map +1 -0
  169. package/dist/schemas/run.d.ts +23 -0
  170. package/dist/schemas/run.d.ts.map +1 -0
  171. package/dist/schemas/run.js +20 -0
  172. package/dist/schemas/run.js.map +1 -0
  173. package/dist/templates/server.hbs +29 -0
  174. package/dist/templates/web.hbs +45 -0
  175. package/dist/types/bundle.d.ts +68 -190
  176. package/dist/types/bundle.d.ts.map +1 -1
  177. package/dist/types/bundle.js +2 -2
  178. package/dist/walker.js +1 -0
  179. package/examples/README.md +42 -29
  180. package/examples/flow-order-complete.json +57 -57
  181. package/examples/flow-simple.json +25 -25
  182. package/examples/flow.json +69 -69
  183. package/examples/server-collect.json +51 -44
  184. package/examples/server-collect.mjs +1 -1
  185. package/examples/web-serve.json +62 -63
  186. package/package.json +2 -2
  187. package/dist/config/defaults.d.ts +0 -33
  188. package/dist/config/defaults.d.ts.map +0 -1
  189. package/dist/config/defaults.js +0 -69
  190. package/dist/config/defaults.js.map +0 -1
  191. package/dist/config/parser.d.ts +0 -128
  192. package/dist/config/parser.d.ts.map +0 -1
  193. package/dist/config/parser.js +0 -256
  194. package/dist/config/parser.js.map +0 -1
package/dist/index.js CHANGED
@@ -2,10 +2,13 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
- import { readFileSync as readFileSync2 } from "fs";
6
- import { fileURLToPath as fileURLToPath3 } from "url";
5
+ import { readFileSync } from "fs";
6
+ import { fileURLToPath as fileURLToPath2 } from "url";
7
7
  import { dirname, join } from "path";
8
8
 
9
+ // src/commands/bundle/index.ts
10
+ import path9 from "path";
11
+
9
12
  // src/core/logger.ts
10
13
  import chalk from "chalk";
11
14
  function createLogger(options = {}) {
@@ -131,8 +134,6 @@ function formatBytes(bytes) {
131
134
  // src/core/docker.ts
132
135
  import { spawn } from "child_process";
133
136
  import path2 from "path";
134
- import { readFileSync } from "fs";
135
- import { fileURLToPath } from "url";
136
137
  import { VERSION as DOCKER_VERSION } from "@walkeros/docker";
137
138
 
138
139
  // src/config/utils.ts
@@ -262,20 +263,7 @@ async function loadJsonFromSource(source, options) {
262
263
  }
263
264
 
264
265
  // src/core/docker.ts
265
- function readPackageVersion() {
266
- const moduleFilename = fileURLToPath(import.meta.url);
267
- const moduleDir = path2.dirname(moduleFilename);
268
- const prodPath = path2.join(moduleDir, "../package.json");
269
- try {
270
- const pkg = JSON.parse(readFileSync(prodPath, "utf-8"));
271
- return pkg.version;
272
- } catch {
273
- const devPath = path2.join(moduleDir, "../../package.json");
274
- const pkg = JSON.parse(readFileSync(devPath, "utf-8"));
275
- return pkg.version;
276
- }
277
- }
278
- var CLI_VERSION = readPackageVersion();
266
+ var CLI_VERSION = true ? "0.4.2" : "0.0.0";
279
267
  var CLI_DOCKER_IMAGE = process.env.WALKEROS_CLI_DOCKER_IMAGE || `walkeros/cli:${CLI_VERSION}`;
280
268
  var RUNTIME_DOCKER_IMAGE = process.env.WALKEROS_RUNTIME_DOCKER_IMAGE || `walkeros/docker:${DOCKER_VERSION}`;
281
269
  function buildCommonDockerArgs(options) {
@@ -355,8 +343,10 @@ function buildDockerRunCommand(mode, flowPath, options = {}) {
355
343
  cmd.push("-e", `MODE=${mode}`);
356
344
  if (mode === "collect" && flowPath) {
357
345
  const absoluteFlowPath = path2.resolve(cwd, flowPath);
358
- cmd.push("-v", `${absoluteFlowPath}:/app/flow.mjs:ro`);
359
- cmd.push("-e", "FLOW=/app/flow.mjs");
346
+ const flowDir = path2.dirname(absoluteFlowPath);
347
+ const flowFile = path2.basename(absoluteFlowPath);
348
+ cmd.push("-v", `${flowDir}:/app/dist:ro`);
349
+ cmd.push("-e", `FLOW=/app/dist/${flowFile}`);
360
350
  }
361
351
  if (mode === "serve" && flowPath) {
362
352
  const absoluteFilePath = path2.resolve(cwd, flowPath);
@@ -452,33 +442,36 @@ import { getHashServer } from "@walkeros/server-core";
452
442
  import fs2 from "fs-extra";
453
443
 
454
444
  // src/core/asset-resolver.ts
455
- import { fileURLToPath as fileURLToPath2 } from "url";
445
+ import { fileURLToPath } from "url";
446
+ import { existsSync } from "fs";
456
447
  import path3 from "path";
457
- function getPackageRoot() {
458
- const currentFile = fileURLToPath2(import.meta.url);
459
- if (currentFile.includes("/src/")) {
460
- const srcIndex = currentFile.indexOf("/src/");
461
- return currentFile.substring(0, srcIndex);
462
- }
463
- if (currentFile.includes("/dist/")) {
464
- const distIndex = currentFile.indexOf("/dist/");
465
- return currentFile.substring(0, distIndex);
448
+ var cachedAssetDir;
449
+ function getAssetDir() {
450
+ if (cachedAssetDir) return cachedAssetDir;
451
+ const currentFile = fileURLToPath(import.meta.url);
452
+ let dir = path3.dirname(currentFile);
453
+ while (dir !== path3.dirname(dir)) {
454
+ if (existsSync(path3.join(dir, "templates"))) {
455
+ cachedAssetDir = dir;
456
+ return dir;
457
+ }
458
+ dir = path3.dirname(dir);
466
459
  }
467
- return path3.resolve(currentFile, "../..");
460
+ cachedAssetDir = path3.dirname(currentFile);
461
+ return cachedAssetDir;
468
462
  }
469
463
  function resolveAsset(assetPath, assetType, baseDir) {
470
- const packageRoot = getPackageRoot();
471
464
  if (!assetPath.includes("/") && !assetPath.includes("\\")) {
465
+ const assetDir = getAssetDir();
472
466
  if (assetType === "template") {
473
- return path3.join(packageRoot, "templates", assetPath);
467
+ return path3.join(assetDir, "templates", assetPath);
474
468
  }
475
- return path3.join(packageRoot, "examples", assetPath);
469
+ return path3.join(assetDir, "examples", assetPath);
476
470
  }
477
471
  if (path3.isAbsolute(assetPath)) {
478
472
  return assetPath;
479
473
  }
480
- const resolveBase = baseDir || process.cwd();
481
- return path3.resolve(resolveBase, assetPath);
474
+ return path3.resolve(baseDir || process.cwd(), assetPath);
482
475
  }
483
476
 
484
477
  // src/core/utils.ts
@@ -486,273 +479,257 @@ function getErrorMessage(error) {
486
479
  return error instanceof Error ? error.message : String(error);
487
480
  }
488
481
 
489
- // src/config/validators.ts
490
- function isObject(value) {
491
- return typeof value === "object" && value !== null && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]";
492
- }
493
- function validatePlatform(platform) {
494
- return platform === "web" || platform === "server";
495
- }
496
- function isMultiEnvConfig(data) {
497
- return isObject(data) && "version" in data && data.version === 1 && "environments" in data && isObject(data.environments);
498
- }
499
- function isSingleEnvConfig(data) {
500
- return isObject(data) && "flow" in data && "build" in data && isObject(data.flow) && isObject(data.build) && "platform" in data.flow;
501
- }
502
-
503
- // src/config/parser.ts
482
+ // src/core/local-packages.ts
504
483
  import path4 from "path";
505
- function parseConfigStructure(rawConfig, options = {}) {
506
- if (isMultiEnvConfig(rawConfig)) {
507
- const setup = rawConfig;
508
- const availableEnvironments = Object.keys(setup.environments);
509
- if (!options.environment) {
510
- throw new Error(
511
- `Multi-environment configuration detected. Please specify an environment using --env flag.
512
- Available environments: ${availableEnvironments.join(", ")}`
513
- );
514
- }
515
- const selectedEnv = options.environment;
516
- if (!setup.environments[selectedEnv]) {
517
- throw new Error(
518
- `Environment "${selectedEnv}" not found in configuration.
519
- Available environments: ${availableEnvironments.join(", ")}`
520
- );
521
- }
522
- const envConfig = setup.environments[selectedEnv];
523
- return {
524
- flowConfig: envConfig.flow,
525
- buildOptions: envConfig.build,
526
- metadata: {
527
- environment: selectedEnv,
528
- isMultiEnvironment: true,
529
- availableEnvironments
530
- }
531
- };
532
- }
533
- if (isSingleEnvConfig(rawConfig)) {
534
- const config = rawConfig;
535
- return {
536
- flowConfig: config.flow,
537
- buildOptions: config.build,
538
- metadata: {
539
- environment: "default",
540
- isMultiEnvironment: false
541
- }
542
- };
543
- }
544
- const configPath = options.configPath || "configuration";
545
- const configType = isObject(rawConfig) ? "platform" in rawConfig ? `invalid platform value: "${rawConfig.platform}"` : 'missing "flow" and "build" fields' : `not an object (got ${typeof rawConfig})`;
546
- throw new Error(
547
- `Invalid configuration format at ${configPath}.
548
- Configuration ${configType}.
549
-
550
- Expected either:
551
- 1. Multi-environment: { version: 1, environments: { prod: { flow: {...}, build: {...} } } }
552
- 2. Single-environment: { flow: { platform: "web" | "server", ... }, build: { packages: {...}, ... } }`
553
- );
554
- }
555
- function normalizeAndValidate(flowConfig, buildOptions, configPath) {
556
- if (!isObject(flowConfig) || !("platform" in flowConfig)) {
484
+ import fs3 from "fs-extra";
485
+ async function resolveLocalPackage(packageName, localPath, configDir, logger) {
486
+ const absolutePath = path4.isAbsolute(localPath) ? localPath : path4.resolve(configDir, localPath);
487
+ if (!await fs3.pathExists(absolutePath)) {
557
488
  throw new Error(
558
- `Invalid flow config: missing "platform" field. Expected "web" or "server".`
489
+ `Local package path not found: ${localPath} (resolved to ${absolutePath})`
559
490
  );
560
491
  }
561
- const platform = flowConfig.platform;
562
- if (!validatePlatform(platform)) {
492
+ const pkgJsonPath = path4.join(absolutePath, "package.json");
493
+ if (!await fs3.pathExists(pkgJsonPath)) {
563
494
  throw new Error(
564
- `Invalid platform "${platform}". Must be "web" or "server".`
495
+ `No package.json found at ${absolutePath}. Is this a valid package directory?`
565
496
  );
566
497
  }
567
- if (!isObject(buildOptions)) {
568
- throw new Error(
569
- `Invalid build options: expected object, got ${typeof buildOptions}`
498
+ const distPath = path4.join(absolutePath, "dist");
499
+ const hasDistFolder = await fs3.pathExists(distPath);
500
+ if (!hasDistFolder) {
501
+ logger.warn(
502
+ `\u26A0\uFE0F ${packageName}: No dist/ folder found. Using package root.`
570
503
  );
571
504
  }
572
- const platformDefaults = platform === "web" ? {
573
- platform: "browser",
574
- format: "iife",
575
- target: "es2020",
576
- minify: false,
577
- sourcemap: false,
578
- tempDir: ".tmp",
579
- cache: true
580
- } : {
581
- platform: "node",
582
- format: "esm",
583
- target: "node20",
584
- minify: false,
585
- sourcemap: false,
586
- tempDir: ".tmp",
587
- cache: true
588
- };
589
- const merged = {
590
- ...platformDefaults,
591
- ...buildOptions
592
- };
593
- if (merged.template === void 0) {
594
- merged.template = platform === "server" ? "server.hbs" : "web.hbs";
595
- }
596
- if (merged.format === "iife" && merged.platform === "browser") {
597
- if (merged.windowCollector === void 0) {
598
- merged.windowCollector = "collector";
599
- }
600
- if (merged.windowElb === void 0) {
601
- merged.windowElb = "elb";
602
- }
603
- }
604
- if (configPath && merged.template && !path4.isAbsolute(merged.template) && (merged.template.startsWith("./") || merged.template.startsWith("../"))) {
605
- const configDir = path4.dirname(configPath);
606
- merged.template = path4.resolve(configDir, merged.template);
607
- }
608
- if (!merged.output || merged.output === "") {
609
- merged.output = platform === "web" ? "./dist/walker.js" : "./dist/bundle.js";
610
- }
611
- if (configPath && configPath !== "/unknown/path" && merged.output && !path4.isAbsolute(merged.output)) {
612
- const configDir = path4.dirname(configPath);
613
- merged.output = path4.resolve(configDir, merged.output);
614
- }
615
- if (!merged.packages) {
616
- merged.packages = {};
617
- }
618
- if (merged.code === void 0 || merged.code === "") {
619
- merged.code = "";
620
- }
621
505
  return {
622
- flowConfig,
623
- buildOptions: merged
506
+ name: packageName,
507
+ absolutePath,
508
+ distPath: hasDistFolder ? distPath : absolutePath,
509
+ hasDistFolder
624
510
  };
625
511
  }
626
- function parseBundleConfig(data) {
627
- if (!isObject(data)) {
628
- throw new Error(`Invalid config: expected object, got ${typeof data}`);
629
- }
630
- if (!("flow" in data) || !isObject(data.flow)) {
631
- throw new Error(
632
- `Invalid config: missing "flow" field. Expected format: { flow: { platform: "web" | "server", ... }, build: { ... } }`
633
- );
634
- }
635
- if (!("build" in data) || !isObject(data.build)) {
636
- throw new Error(
637
- `Invalid config: missing "build" field. Expected format: { flow: { platform: "web" | "server", ... }, build: { ... } }`
638
- );
512
+ async function copyLocalPackage(localPkg, targetDir, logger) {
513
+ const packageDir = path4.join(targetDir, "node_modules", localPkg.name);
514
+ await fs3.ensureDir(path4.dirname(packageDir));
515
+ await fs3.copy(
516
+ path4.join(localPkg.absolutePath, "package.json"),
517
+ path4.join(packageDir, "package.json")
518
+ );
519
+ if (localPkg.hasDistFolder) {
520
+ await fs3.copy(localPkg.distPath, path4.join(packageDir, "dist"));
521
+ } else {
522
+ const entries = await fs3.readdir(localPkg.absolutePath);
523
+ for (const entry of entries) {
524
+ if (!["node_modules", ".turbo", ".git"].includes(entry)) {
525
+ await fs3.copy(
526
+ path4.join(localPkg.absolutePath, entry),
527
+ path4.join(packageDir, entry)
528
+ );
529
+ }
530
+ }
639
531
  }
640
- const buildData = data.build;
641
- if ("packages" in buildData && !isObject(buildData.packages)) {
642
- throw new Error(
643
- `Invalid config: build.packages must be an object, got ${typeof buildData.packages}`
644
- );
532
+ logger.info(`\u{1F4E6} Using local: ${localPkg.name} from ${localPkg.absolutePath}`);
533
+ return packageDir;
534
+ }
535
+
536
+ // src/config/validators.ts
537
+ import { schemas } from "@walkeros/core/dev";
538
+ var { safeParseSetup } = schemas;
539
+ function isObject(value) {
540
+ return typeof value === "object" && value !== null && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]";
541
+ }
542
+ function validateFlowSetup(data) {
543
+ const result = safeParseSetup(data);
544
+ if (!result.success) {
545
+ const errors = result.error.issues.map((issue) => {
546
+ const path15 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
547
+ return ` - ${path15}: ${issue.message}`;
548
+ }).join("\n");
549
+ throw new Error(`Invalid configuration:
550
+ ${errors}`);
645
551
  }
646
- return normalizeAndValidate(data.flow, data.build, "/unknown/path");
552
+ return result.data;
553
+ }
554
+ function getAvailableFlows(setup) {
555
+ return Object.keys(setup.flows);
556
+ }
557
+
558
+ // src/config/build-defaults.ts
559
+ var WEB_BUILD_DEFAULTS = {
560
+ format: "iife",
561
+ platform: "browser",
562
+ target: "es2020",
563
+ template: "web.hbs",
564
+ minify: true,
565
+ sourcemap: false,
566
+ cache: true,
567
+ tempDir: ".tmp",
568
+ windowCollector: "collector",
569
+ windowElb: "elb"
570
+ };
571
+ var SERVER_BUILD_DEFAULTS = {
572
+ format: "esm",
573
+ platform: "node",
574
+ target: "node20",
575
+ template: "server.hbs",
576
+ minify: true,
577
+ sourcemap: false,
578
+ cache: true,
579
+ tempDir: ".tmp"
580
+ };
581
+ var DEFAULT_OUTPUT_PATHS = {
582
+ web: "./dist/walker.js",
583
+ server: "./dist/bundle.mjs"
584
+ };
585
+ function getBuildDefaults(platform) {
586
+ return platform === "web" ? WEB_BUILD_DEFAULTS : SERVER_BUILD_DEFAULTS;
647
587
  }
648
- function normalizeConfigs(config, configPath) {
649
- return normalizeAndValidate(config.flow, config.build, configPath);
588
+ function getDefaultOutput(platform) {
589
+ return DEFAULT_OUTPUT_PATHS[platform];
650
590
  }
651
591
 
652
592
  // src/config/loader.ts
593
+ import path5 from "path";
594
+ import fs4 from "fs-extra";
595
+ import { getFlowConfig, getPlatform } from "@walkeros/core";
596
+ var DEFAULT_INCLUDE_FOLDER = "./shared";
653
597
  function loadBundleConfig(rawConfig, options) {
654
- const { flowConfig, buildOptions, metadata } = parseConfigStructure(
655
- rawConfig,
656
- {
657
- configPath: options.configPath,
658
- environment: options.environment
659
- }
660
- );
661
- const normalized = normalizeAndValidate(
662
- flowConfig,
663
- buildOptions,
664
- options.configPath
665
- );
666
- if (metadata.isMultiEnvironment && options.logger) {
667
- options.logger.info(
668
- `\u{1F4E6} Using environment: ${metadata.environment} (${metadata.availableEnvironments?.length || 0} total)`
669
- );
670
- }
671
- if (!metadata.isMultiEnvironment && options.environment && options.logger) {
672
- options.logger.warn(
673
- `--env flag specified but configuration is single-environment. Ignoring flag.`
674
- );
675
- }
676
- return {
677
- ...normalized,
678
- ...metadata
679
- };
680
- }
681
- function loadMultiEnvironmentConfig(setup, options) {
682
- const availableEnvironments = Object.keys(setup.environments);
683
- if (!options.environment) {
598
+ const setup = validateFlowSetup(rawConfig);
599
+ const availableFlows = getAvailableFlows(setup);
600
+ const flowName = resolveFlow(setup, options.flowName, availableFlows);
601
+ const flowConfig = getFlowConfig(setup, flowName);
602
+ const platform = getPlatform(flowConfig);
603
+ if (!platform) {
684
604
  throw new Error(
685
- `Multi-environment configuration detected. Please specify an environment using --env flag.
686
- Available environments: ${availableEnvironments.join(", ")}`
605
+ `Invalid configuration: flow "${flowName}" must have a "web" or "server" key.`
687
606
  );
688
607
  }
689
- const selectedEnv = options.environment;
690
- if (!setup.environments[selectedEnv]) {
691
- throw new Error(
692
- `Environment "${selectedEnv}" not found in configuration.
693
- Available environments: ${availableEnvironments.join(", ")}`
694
- );
695
- }
696
- const envConfig = setup.environments[selectedEnv];
697
- const { flowConfig, buildOptions } = normalizeConfigs(
698
- envConfig,
699
- options.configPath
700
- );
701
- if (options.logger) {
608
+ const buildDefaults = getBuildDefaults(platform);
609
+ const packages = flowConfig.packages || {};
610
+ let output = getDefaultOutput(platform);
611
+ if (options.buildOverrides?.output) {
612
+ output = options.buildOverrides.output;
613
+ }
614
+ const configDir = path5.dirname(options.configPath);
615
+ if (!path5.isAbsolute(output)) {
616
+ output = path5.resolve(configDir, output);
617
+ }
618
+ let includes = setup.include;
619
+ if (!includes) {
620
+ const defaultIncludePath = path5.resolve(configDir, DEFAULT_INCLUDE_FOLDER);
621
+ if (fs4.pathExistsSync(defaultIncludePath)) {
622
+ includes = [DEFAULT_INCLUDE_FOLDER];
623
+ }
624
+ }
625
+ const buildOptions = {
626
+ ...buildDefaults,
627
+ packages,
628
+ output,
629
+ include: includes,
630
+ configDir,
631
+ ...options.buildOverrides
632
+ };
633
+ const isMultiFlow = availableFlows.length > 1;
634
+ if (isMultiFlow && options.logger) {
702
635
  options.logger.info(
703
- `\u{1F4E6} Using environment: ${selectedEnv} (${availableEnvironments.length} total)`
636
+ `\u{1F4E6} Using flow: ${flowName} (${availableFlows.length} total)`
704
637
  );
705
638
  }
706
639
  return {
707
640
  flowConfig,
708
641
  buildOptions,
709
- environment: selectedEnv,
710
- isMultiEnvironment: true,
711
- availableEnvironments
642
+ flowName,
643
+ isMultiFlow,
644
+ availableFlows
712
645
  };
713
646
  }
714
- function loadAllEnvironments(rawConfig, options) {
715
- if (!isMultiEnvConfig(rawConfig)) {
647
+ function resolveFlow(setup, requestedFlow, available) {
648
+ if (available.length === 1) {
649
+ return available[0];
650
+ }
651
+ if (!requestedFlow) {
652
+ throw new Error(
653
+ `Multiple flows found. Please specify a flow using --flow flag.
654
+ Available flows: ${available.join(", ")}`
655
+ );
656
+ }
657
+ if (!available.includes(requestedFlow)) {
716
658
  throw new Error(
717
- `--all flag requires a multi-environment configuration (Setup format).
718
- Your configuration appears to be single-environment.`
659
+ `Flow "${requestedFlow}" not found in configuration.
660
+ Available flows: ${available.join(", ")}`
719
661
  );
720
662
  }
721
- const setup = rawConfig;
722
- const environments = Object.keys(setup.environments);
663
+ return requestedFlow;
664
+ }
665
+ function loadAllFlows(rawConfig, options) {
666
+ const setup = validateFlowSetup(rawConfig);
667
+ const flows = getAvailableFlows(setup);
723
668
  if (options.logger) {
724
669
  options.logger.info(
725
- `\u{1F4E6} Loading all ${environments.length} environments: ${environments.join(", ")}`
670
+ `\u{1F4E6} Loading all ${flows.length} flows: ${flows.join(", ")}`
726
671
  );
727
672
  }
728
- return environments.map(
729
- (envName) => loadMultiEnvironmentConfig(setup, {
673
+ return flows.map(
674
+ (name) => loadBundleConfig(rawConfig, {
730
675
  ...options,
731
- environment: envName
676
+ flowName: name
732
677
  })
733
678
  );
734
679
  }
735
680
 
736
681
  // src/commands/bundle/bundler.ts
737
682
  import esbuild from "esbuild";
683
+ import path8 from "path";
684
+ import fs8 from "fs-extra";
685
+
686
+ // src/commands/bundle/package-manager.ts
687
+ import pacote from "pacote";
738
688
  import path6 from "path";
739
689
  import fs5 from "fs-extra";
740
690
 
691
+ // src/core/cache-utils.ts
692
+ import { getHashServer as getHashServer2 } from "@walkeros/server-core";
693
+ var HASH_LENGTH = 12;
694
+ function isMutableVersion(version) {
695
+ return version === "latest" || version.includes("^") || version.includes("~") || version.includes("*") || version.includes("x");
696
+ }
697
+ function getTodayDate() {
698
+ return (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
699
+ }
700
+ async function getPackageCacheKey(packageName, version, date) {
701
+ const safeName = packageName.replace(/\//g, "-").replace(/@/g, "");
702
+ if (isMutableVersion(version)) {
703
+ const dateStr = date ?? getTodayDate();
704
+ const input2 = `${safeName}@${version}:${dateStr}`;
705
+ return getHashServer2(input2, HASH_LENGTH);
706
+ }
707
+ const input = `${safeName}@${version}`;
708
+ return getHashServer2(input, HASH_LENGTH);
709
+ }
710
+ function normalizeJson(content) {
711
+ const parsed = JSON.parse(content);
712
+ return JSON.stringify(parsed);
713
+ }
714
+ async function getFlowConfigCacheKey(content, date) {
715
+ const dateStr = date ?? getTodayDate();
716
+ const normalized = normalizeJson(content);
717
+ const input = `${normalized}:${dateStr}`;
718
+ return getHashServer2(input, HASH_LENGTH);
719
+ }
720
+
741
721
  // src/commands/bundle/package-manager.ts
742
- import pacote from "pacote";
743
- import path5 from "path";
744
- import fs3 from "fs-extra";
745
722
  function getPackageDirectory(baseDir, packageName, version) {
746
- return path5.join(baseDir, "node_modules", packageName);
723
+ return path6.join(baseDir, "node_modules", packageName);
747
724
  }
748
- function getCachedPackagePath(pkg, tempDir) {
749
- const cacheDir = path5.join(".tmp", "cache", "packages");
750
- const safeName = pkg.name.replace(/\//g, "-").replace(/@/g, "");
751
- return path5.join(cacheDir, `${safeName}-${pkg.version}`);
725
+ async function getCachedPackagePath(pkg, tempDir) {
726
+ const cacheDir = path6.join(".tmp", "cache", "packages");
727
+ const cacheKey = await getPackageCacheKey(pkg.name, pkg.version);
728
+ return path6.join(cacheDir, cacheKey);
752
729
  }
753
730
  async function isPackageCached(pkg, tempDir) {
754
- const cachedPath = getCachedPackagePath(pkg, tempDir);
755
- return fs3.pathExists(cachedPath);
731
+ const cachedPath = await getCachedPackagePath(pkg, tempDir);
732
+ return fs5.pathExists(cachedPath);
756
733
  }
757
734
  function validateNoDuplicatePackages(packages) {
758
735
  const packageMap = /* @__PURE__ */ new Map();
@@ -786,9 +763,9 @@ async function resolveDependencies(pkg, packageDir, logger, visited = /* @__PURE
786
763
  }
787
764
  visited.add(pkgKey);
788
765
  try {
789
- const packageJsonPath = path5.join(packageDir, "package.json");
790
- if (await fs3.pathExists(packageJsonPath)) {
791
- const packageJson2 = await fs3.readJson(packageJsonPath);
766
+ const packageJsonPath = path6.join(packageDir, "package.json");
767
+ if (await fs5.pathExists(packageJsonPath)) {
768
+ const packageJson2 = await fs5.readJson(packageJsonPath);
792
769
  const deps = {
793
770
  ...packageJson2.dependencies,
794
771
  ...packageJson2.peerDependencies
@@ -804,12 +781,18 @@ async function resolveDependencies(pkg, packageDir, logger, visited = /* @__PURE
804
781
  }
805
782
  return dependencies;
806
783
  }
807
- async function downloadPackages(packages, targetDir, logger, useCache = true) {
784
+ async function downloadPackages(packages, targetDir, logger, useCache = true, configDir) {
808
785
  const packagePaths = /* @__PURE__ */ new Map();
809
786
  const downloadQueue = [...packages];
810
787
  const processed = /* @__PURE__ */ new Set();
788
+ const localPackageMap = /* @__PURE__ */ new Map();
789
+ for (const pkg of packages) {
790
+ if (pkg.path) {
791
+ localPackageMap.set(pkg.name, pkg.path);
792
+ }
793
+ }
811
794
  validateNoDuplicatePackages(packages);
812
- await fs3.ensureDir(targetDir);
795
+ await fs5.ensureDir(targetDir);
813
796
  while (downloadQueue.length > 0) {
814
797
  const pkg = downloadQueue.shift();
815
798
  const pkgKey = `${pkg.name}@${pkg.version}`;
@@ -817,14 +800,35 @@ async function downloadPackages(packages, targetDir, logger, useCache = true) {
817
800
  continue;
818
801
  }
819
802
  processed.add(pkgKey);
803
+ if (!pkg.path && localPackageMap.has(pkg.name)) {
804
+ pkg.path = localPackageMap.get(pkg.name);
805
+ }
806
+ if (pkg.path) {
807
+ const localPkg = await resolveLocalPackage(
808
+ pkg.name,
809
+ pkg.path,
810
+ configDir || process.cwd(),
811
+ logger
812
+ );
813
+ const installedPath = await copyLocalPackage(localPkg, targetDir, logger);
814
+ packagePaths.set(pkg.name, installedPath);
815
+ const deps = await resolveDependencies(pkg, installedPath, logger);
816
+ for (const dep of deps) {
817
+ const depKey = `${dep.name}@${dep.version}`;
818
+ if (!processed.has(depKey)) {
819
+ downloadQueue.push(dep);
820
+ }
821
+ }
822
+ continue;
823
+ }
820
824
  const packageSpec = `${pkg.name}@${pkg.version}`;
821
825
  const packageDir = getPackageDirectory(targetDir, pkg.name, pkg.version);
822
- const cachedPath = getCachedPackagePath(pkg, targetDir);
826
+ const cachedPath = await getCachedPackagePath(pkg, targetDir);
823
827
  if (useCache && await isPackageCached(pkg, targetDir)) {
824
828
  logger.debug(`Using cached ${packageSpec}...`);
825
829
  try {
826
- await fs3.ensureDir(path5.dirname(packageDir));
827
- await fs3.copy(cachedPath, packageDir);
830
+ await fs5.ensureDir(path6.dirname(packageDir));
831
+ await fs5.copy(cachedPath, packageDir);
828
832
  packagePaths.set(pkg.name, packageDir);
829
833
  const deps = await resolveDependencies(pkg, packageDir, logger);
830
834
  for (const dep of deps) {
@@ -842,8 +846,8 @@ async function downloadPackages(packages, targetDir, logger, useCache = true) {
842
846
  }
843
847
  logger.debug(`Downloading ${packageSpec}...`);
844
848
  try {
845
- await fs3.ensureDir(path5.dirname(packageDir));
846
- const cacheDir = process.env.NPM_CACHE_DIR || path5.join(process.cwd(), ".npm-cache");
849
+ await fs5.ensureDir(path6.dirname(packageDir));
850
+ const cacheDir = process.env.NPM_CACHE_DIR || path6.join(process.cwd(), ".npm-cache");
847
851
  await pacote.extract(packageSpec, packageDir, {
848
852
  // Force npm registry download, prevent workspace resolution
849
853
  registry: "https://registry.npmjs.org",
@@ -856,8 +860,8 @@ async function downloadPackages(packages, targetDir, logger, useCache = true) {
856
860
  });
857
861
  if (useCache) {
858
862
  try {
859
- await fs3.ensureDir(path5.dirname(cachedPath));
860
- await fs3.copy(packageDir, cachedPath);
863
+ await fs5.ensureDir(path6.dirname(cachedPath));
864
+ await fs5.copy(packageDir, cachedPath);
861
865
  logger.debug(`Cached ${packageSpec} for future use`);
862
866
  } catch (cacheError) {
863
867
  logger.debug(`Failed to cache ${packageSpec}: ${cacheError}`);
@@ -879,7 +883,7 @@ async function downloadPackages(packages, targetDir, logger, useCache = true) {
879
883
  }
880
884
 
881
885
  // src/commands/bundle/template-engine.ts
882
- import fs4 from "fs-extra";
886
+ import fs6 from "fs-extra";
883
887
  import Handlebars from "handlebars";
884
888
 
885
889
  // src/commands/bundle/serializer.ts
@@ -996,10 +1000,10 @@ var TemplateEngine = class {
996
1000
  */
997
1001
  async loadTemplate(templatePath) {
998
1002
  const resolvedPath = resolveAsset(templatePath, "template");
999
- if (!await fs4.pathExists(resolvedPath)) {
1003
+ if (!await fs6.pathExists(resolvedPath)) {
1000
1004
  throw new Error(`Template file not found: ${resolvedPath}`);
1001
1005
  }
1002
- return await fs4.readFile(resolvedPath, "utf-8");
1006
+ return await fs6.readFile(resolvedPath, "utf-8");
1003
1007
  }
1004
1008
  /**
1005
1009
  * Apply template with user code and variable substitution
@@ -1034,32 +1038,118 @@ var TemplateEngine = class {
1034
1038
  }
1035
1039
  };
1036
1040
 
1041
+ // src/core/build-cache.ts
1042
+ import fs7 from "fs-extra";
1043
+ import path7 from "path";
1044
+ var BUILD_CACHE_DIR = path7.join(".tmp", "cache", "builds");
1045
+ async function getBuildCachePath(configContent, cacheDir = BUILD_CACHE_DIR) {
1046
+ const cacheKey = await getFlowConfigCacheKey(configContent);
1047
+ return path7.join(cacheDir, `${cacheKey}.js`);
1048
+ }
1049
+ async function isBuildCached(configContent, cacheDir = BUILD_CACHE_DIR) {
1050
+ const cachePath = await getBuildCachePath(configContent, cacheDir);
1051
+ return fs7.pathExists(cachePath);
1052
+ }
1053
+ async function cacheBuild(configContent, buildOutput, cacheDir = BUILD_CACHE_DIR) {
1054
+ const cachePath = await getBuildCachePath(configContent, cacheDir);
1055
+ await fs7.ensureDir(path7.dirname(cachePath));
1056
+ await fs7.writeFile(cachePath, buildOutput, "utf-8");
1057
+ }
1058
+ async function getCachedBuild(configContent, cacheDir = BUILD_CACHE_DIR) {
1059
+ const cachePath = await getBuildCachePath(configContent, cacheDir);
1060
+ if (await fs7.pathExists(cachePath)) {
1061
+ return await fs7.readFile(cachePath, "utf-8");
1062
+ }
1063
+ return null;
1064
+ }
1065
+
1037
1066
  // src/commands/bundle/bundler.ts
1067
+ async function copyIncludes(includes, sourceDir, outputDir, logger) {
1068
+ for (const include of includes) {
1069
+ const sourcePath = path8.resolve(sourceDir, include);
1070
+ const folderName = path8.basename(include);
1071
+ const destPath = path8.join(outputDir, folderName);
1072
+ if (await fs8.pathExists(sourcePath)) {
1073
+ await fs8.copy(sourcePath, destPath);
1074
+ logger.debug(`Copied ${include} to output`);
1075
+ } else {
1076
+ logger.debug(`Include folder not found: ${include}`);
1077
+ }
1078
+ }
1079
+ }
1080
+ function generateCacheKeyContent(flowConfig, buildOptions) {
1081
+ const configForCache = {
1082
+ flow: flowConfig,
1083
+ build: {
1084
+ ...buildOptions,
1085
+ // Exclude non-deterministic fields from cache key
1086
+ tempDir: void 0,
1087
+ output: void 0
1088
+ }
1089
+ };
1090
+ return JSON.stringify(configForCache);
1091
+ }
1038
1092
  async function bundleCore(flowConfig, buildOptions, logger, showStats = false) {
1039
1093
  const bundleStartTime = Date.now();
1040
- const TEMP_DIR = buildOptions.tempDir ? path6.isAbsolute(buildOptions.tempDir) ? buildOptions.tempDir : path6.resolve(buildOptions.tempDir) : getTempDir();
1094
+ const TEMP_DIR = buildOptions.tempDir ? path8.isAbsolute(buildOptions.tempDir) ? buildOptions.tempDir : path8.resolve(buildOptions.tempDir) : getTempDir();
1095
+ if (buildOptions.cache !== false) {
1096
+ const configContent = generateCacheKeyContent(flowConfig, buildOptions);
1097
+ const cached = await isBuildCached(configContent);
1098
+ if (cached) {
1099
+ const cachedBuild = await getCachedBuild(configContent);
1100
+ if (cachedBuild) {
1101
+ logger.info("\u2728 Using cached build");
1102
+ const outputPath = path8.resolve(buildOptions.output);
1103
+ await fs8.ensureDir(path8.dirname(outputPath));
1104
+ await fs8.writeFile(outputPath, cachedBuild);
1105
+ logger.gray(`Output: ${outputPath}`);
1106
+ logger.success("\u2705 Build completed (from cache)");
1107
+ if (showStats) {
1108
+ const stats = await fs8.stat(outputPath);
1109
+ const packageStats = Object.entries(buildOptions.packages).map(
1110
+ ([name, pkg]) => ({
1111
+ name: `${name}@${pkg.version || "latest"}`,
1112
+ size: 0
1113
+ // Size estimation not available for cached builds
1114
+ })
1115
+ );
1116
+ return {
1117
+ totalSize: stats.size,
1118
+ packages: packageStats,
1119
+ buildTime: Date.now() - bundleStartTime,
1120
+ treeshakingEffective: true
1121
+ };
1122
+ }
1123
+ return;
1124
+ }
1125
+ }
1126
+ }
1041
1127
  try {
1042
1128
  if (!buildOptions.tempDir) {
1043
- await fs5.emptyDir(TEMP_DIR);
1129
+ await fs8.emptyDir(TEMP_DIR);
1044
1130
  }
1045
1131
  logger.debug("Cleaned temporary directory");
1046
1132
  logger.info("\u{1F4E5} Downloading packages...");
1047
1133
  const packagesArray = Object.entries(buildOptions.packages).map(
1048
1134
  ([name, packageConfig]) => ({
1049
1135
  name,
1050
- version: packageConfig.version || "latest"
1136
+ version: packageConfig.version || "latest",
1137
+ path: packageConfig.path
1138
+ // Pass local path if defined
1051
1139
  })
1052
1140
  );
1053
1141
  const packagePaths = await downloadPackages(
1054
1142
  packagesArray,
1055
1143
  TEMP_DIR,
1056
1144
  logger,
1057
- buildOptions.cache
1145
+ buildOptions.cache,
1146
+ buildOptions.configDir
1147
+ // For resolving relative local paths
1058
1148
  );
1059
1149
  for (const [pkgName, pkgPath] of packagePaths.entries()) {
1060
1150
  if (pkgName.startsWith("@walkeros/")) {
1061
- const pkgJsonPath = path6.join(pkgPath, "package.json");
1062
- const pkgJson = await fs5.readJSON(pkgJsonPath);
1151
+ const pkgJsonPath = path8.join(pkgPath, "package.json");
1152
+ const pkgJson = await fs8.readJSON(pkgJsonPath);
1063
1153
  if (!pkgJson.exports && pkgJson.module) {
1064
1154
  pkgJson.exports = {
1065
1155
  ".": {
@@ -1067,12 +1157,12 @@ async function bundleCore(flowConfig, buildOptions, logger, showStats = false) {
1067
1157
  require: pkgJson.main
1068
1158
  }
1069
1159
  };
1070
- await fs5.writeJSON(pkgJsonPath, pkgJson, { spaces: 2 });
1160
+ await fs8.writeJSON(pkgJsonPath, pkgJson, { spaces: 2 });
1071
1161
  }
1072
1162
  }
1073
1163
  }
1074
- const packageJsonPath = path6.join(TEMP_DIR, "package.json");
1075
- await fs5.writeFile(
1164
+ const packageJsonPath = path8.join(TEMP_DIR, "package.json");
1165
+ await fs8.writeFile(
1076
1166
  packageJsonPath,
1077
1167
  JSON.stringify({ type: "module" }, null, 2)
1078
1168
  );
@@ -1082,11 +1172,11 @@ async function bundleCore(flowConfig, buildOptions, logger, showStats = false) {
1082
1172
  buildOptions,
1083
1173
  packagePaths
1084
1174
  );
1085
- const entryPath = path6.join(TEMP_DIR, "entry.js");
1086
- await fs5.writeFile(entryPath, entryContent);
1175
+ const entryPath = path8.join(TEMP_DIR, "entry.js");
1176
+ await fs8.writeFile(entryPath, entryContent);
1087
1177
  logger.info("\u26A1 Bundling with esbuild...");
1088
- const outputPath = path6.resolve(buildOptions.output);
1089
- await fs5.ensureDir(path6.dirname(outputPath));
1178
+ const outputPath = path8.resolve(buildOptions.output);
1179
+ await fs8.ensureDir(path8.dirname(outputPath));
1090
1180
  const esbuildOptions = createEsbuildOptions(
1091
1181
  buildOptions,
1092
1182
  entryPath,
@@ -1104,6 +1194,12 @@ async function bundleCore(flowConfig, buildOptions, logger, showStats = false) {
1104
1194
  );
1105
1195
  }
1106
1196
  logger.gray(`Output: ${outputPath}`);
1197
+ if (buildOptions.cache !== false) {
1198
+ const configContent = generateCacheKeyContent(flowConfig, buildOptions);
1199
+ const buildOutput = await fs8.readFile(outputPath, "utf-8");
1200
+ await cacheBuild(configContent, buildOutput);
1201
+ logger.debug("Build cached for future use");
1202
+ }
1107
1203
  let stats;
1108
1204
  if (showStats) {
1109
1205
  stats = await collectBundleStats(
@@ -1113,21 +1209,30 @@ async function bundleCore(flowConfig, buildOptions, logger, showStats = false) {
1113
1209
  entryContent
1114
1210
  );
1115
1211
  }
1212
+ if (buildOptions.include && buildOptions.include.length > 0) {
1213
+ const outputDir = path8.dirname(outputPath);
1214
+ await copyIncludes(
1215
+ buildOptions.include,
1216
+ buildOptions.configDir || process.cwd(),
1217
+ outputDir,
1218
+ logger
1219
+ );
1220
+ }
1116
1221
  if (!buildOptions.tempDir) {
1117
- await fs5.remove(TEMP_DIR);
1222
+ await fs8.remove(TEMP_DIR);
1118
1223
  logger.debug("Cleaned up temporary files");
1119
1224
  }
1120
1225
  return stats;
1121
1226
  } catch (error) {
1122
1227
  if (!buildOptions.tempDir) {
1123
- await fs5.remove(TEMP_DIR).catch(() => {
1228
+ await fs8.remove(TEMP_DIR).catch(() => {
1124
1229
  });
1125
1230
  }
1126
1231
  throw error;
1127
1232
  }
1128
1233
  }
1129
1234
  async function collectBundleStats(outputPath, packages, startTime, entryContent) {
1130
- const stats = await fs5.stat(outputPath);
1235
+ const stats = await fs8.stat(outputPath);
1131
1236
  const totalSize = stats.size;
1132
1237
  const buildTime = Date.now() - startTime;
1133
1238
  const packageStats = Object.entries(packages).map(([name, pkg]) => {
@@ -1206,6 +1311,11 @@ function createEsbuildOptions(buildOptions, entryPath, outputPath, tempDir, pack
1206
1311
  ];
1207
1312
  const npmPackages = ["express", "express/*", "cors", "cors/*"];
1208
1313
  baseOptions.external = buildOptions.external ? [...nodeBuiltins, ...npmPackages, ...buildOptions.external] : [...nodeBuiltins, ...npmPackages];
1314
+ if (buildOptions.format === "esm") {
1315
+ baseOptions.banner = {
1316
+ js: `import { createRequire } from 'module';const require = createRequire(import.meta.url);`
1317
+ };
1318
+ }
1209
1319
  }
1210
1320
  if (buildOptions.target) {
1211
1321
  baseOptions.target = buildOptions.target;
@@ -1400,23 +1510,23 @@ async function bundleCommand(options) {
1400
1510
  timer.start();
1401
1511
  const logger = createCommandLogger(options);
1402
1512
  const dockerArgs = buildCommonDockerArgs(options);
1403
- if (options.env) dockerArgs.push("--env", options.env);
1513
+ if (options.flow) dockerArgs.push("--flow", options.flow);
1404
1514
  if (options.all) dockerArgs.push("--all");
1405
1515
  if (options.stats) dockerArgs.push("--stats");
1406
1516
  if (options.cache === false) dockerArgs.push("--no-cache");
1407
1517
  await executeCommand(
1408
1518
  async () => {
1409
1519
  try {
1410
- if (options.env && options.all) {
1411
- throw new Error("Cannot use both --env and --all flags together");
1520
+ if (options.flow && options.all) {
1521
+ throw new Error("Cannot use both --flow and --all flags together");
1412
1522
  }
1413
1523
  logger.info("\u{1F4E6} Reading configuration...");
1414
- const configPath = options.config;
1524
+ const configPath = resolveAsset(options.config, "config");
1415
1525
  const rawConfig = await loadJsonConfig(configPath);
1416
- const configsToBundle = options.all ? loadAllEnvironments(rawConfig, { configPath, logger }) : [
1526
+ const configsToBundle = options.all ? loadAllFlows(rawConfig, { configPath, logger }) : [
1417
1527
  loadBundleConfig(rawConfig, {
1418
1528
  configPath,
1419
- environment: options.env,
1529
+ flowName: options.flow,
1420
1530
  logger
1421
1531
  })
1422
1532
  ];
@@ -1424,16 +1534,16 @@ async function bundleCommand(options) {
1424
1534
  for (const {
1425
1535
  flowConfig,
1426
1536
  buildOptions,
1427
- environment,
1428
- isMultiEnvironment
1537
+ flowName,
1538
+ isMultiFlow
1429
1539
  } of configsToBundle) {
1430
1540
  try {
1431
1541
  if (options.cache !== void 0) {
1432
1542
  buildOptions.cache = options.cache;
1433
1543
  }
1434
- if (isMultiEnvironment || options.all) {
1544
+ if (isMultiFlow || options.all) {
1435
1545
  logger.info(`
1436
- \u{1F527} Building environment: ${environment}`);
1546
+ \u{1F527} Building flow: ${flowName}`);
1437
1547
  } else {
1438
1548
  logger.info("\u{1F527} Starting bundle process...");
1439
1549
  }
@@ -1445,7 +1555,7 @@ async function bundleCommand(options) {
1445
1555
  shouldCollectStats
1446
1556
  );
1447
1557
  results.push({
1448
- environment,
1558
+ flowName,
1449
1559
  success: true,
1450
1560
  stats
1451
1561
  });
@@ -1455,7 +1565,7 @@ async function bundleCommand(options) {
1455
1565
  } catch (error) {
1456
1566
  const errorMessage = getErrorMessage(error);
1457
1567
  results.push({
1458
- environment,
1568
+ flowName,
1459
1569
  success: false,
1460
1570
  error: errorMessage
1461
1571
  });
@@ -1471,7 +1581,7 @@ async function bundleCommand(options) {
1471
1581
  const outputLogger = createLogger({ silent: false, json: false });
1472
1582
  const output = failureCount === 0 ? createSuccessOutput(
1473
1583
  {
1474
- environments: results,
1584
+ flows: results,
1475
1585
  summary: {
1476
1586
  total: results.length,
1477
1587
  success: successCount,
@@ -1480,7 +1590,7 @@ async function bundleCommand(options) {
1480
1590
  },
1481
1591
  duration
1482
1592
  ) : createErrorOutput(
1483
- `${failureCount} environment(s) failed to build`,
1593
+ `${failureCount} flow(s) failed to build`,
1484
1594
  duration
1485
1595
  );
1486
1596
  outputLogger.log("white", JSON.stringify(output, null, 2));
@@ -1500,7 +1610,7 @@ async function bundleCommand(options) {
1500
1610
  \u2705 Bundle created successfully in ${timer.format()}`
1501
1611
  );
1502
1612
  } else {
1503
- throw new Error(`${failureCount} environment(s) failed to build`);
1613
+ throw new Error(`${failureCount} flow(s) failed to build`);
1504
1614
  }
1505
1615
  }
1506
1616
  } catch (error) {
@@ -1526,12 +1636,18 @@ async function bundleCommand(options) {
1526
1636
  }
1527
1637
  async function bundle(configOrPath, options = {}) {
1528
1638
  let rawConfig;
1639
+ let configPath = path9.resolve(process.cwd(), "walkeros.config.json");
1529
1640
  if (typeof configOrPath === "string") {
1530
- rawConfig = await loadJsonConfig(configOrPath);
1641
+ configPath = resolveAsset(configOrPath, "config");
1642
+ rawConfig = await loadJsonConfig(configPath);
1531
1643
  } else {
1532
1644
  rawConfig = configOrPath;
1533
1645
  }
1534
- const { flowConfig, buildOptions } = parseBundleConfig(rawConfig);
1646
+ const { flowConfig, buildOptions } = loadBundleConfig(rawConfig, {
1647
+ configPath,
1648
+ flowName: options.flowName,
1649
+ buildOverrides: options.buildOverrides
1650
+ });
1535
1651
  if (options.cache !== void 0) {
1536
1652
  buildOptions.cache = options.cache;
1537
1653
  }
@@ -1545,8 +1661,9 @@ async function bundle(configOrPath, options = {}) {
1545
1661
  }
1546
1662
 
1547
1663
  // src/commands/simulate/simulator.ts
1548
- import path7 from "path";
1549
- import fs7 from "fs-extra";
1664
+ import path10 from "path";
1665
+ import fs10 from "fs-extra";
1666
+ import { getPlatform as getPlatform2 } from "@walkeros/core";
1550
1667
 
1551
1668
  // src/commands/simulate/tracker.ts
1552
1669
  var CallTracker = class {
@@ -1582,9 +1699,9 @@ var CallTracker = class {
1582
1699
  }
1583
1700
  for (const fullPath of paths) {
1584
1701
  const [destKey, ...pathParts] = fullPath.split(":");
1585
- const path11 = pathParts.join(":");
1586
- if (!path11) continue;
1587
- const cleanPath = path11.replace(/^call:/, "");
1702
+ const path15 = pathParts.join(":");
1703
+ if (!path15) continue;
1704
+ const cleanPath = path15.replace(/^call:/, "");
1588
1705
  const parts = cleanPath.split(".");
1589
1706
  let current = wrapped;
1590
1707
  let source = env;
@@ -1628,7 +1745,7 @@ var CallTracker = class {
1628
1745
 
1629
1746
  // src/commands/simulate/jsdom-executor.ts
1630
1747
  import { JSDOM, VirtualConsole } from "jsdom";
1631
- import fs6 from "fs-extra";
1748
+ import fs9 from "fs-extra";
1632
1749
  function buildSandboxFromEnvs(envs, destinations, tracker) {
1633
1750
  const baseBrowserMocks = {
1634
1751
  Image: class MockImage {
@@ -1697,7 +1814,7 @@ async function executeInJSDOM(bundlePath, destinations, event, tracker, envs, ti
1697
1814
  const sandbox = buildSandboxFromEnvs(envs, destinations, tracker);
1698
1815
  Object.assign(window, sandbox.window);
1699
1816
  Object.assign(window.document, sandbox.document);
1700
- const bundleCode = await fs6.readFile(bundlePath, "utf8");
1817
+ const bundleCode = await fs9.readFile(bundlePath, "utf8");
1701
1818
  try {
1702
1819
  window.eval(bundleCode);
1703
1820
  } catch (error) {
@@ -1735,6 +1852,85 @@ async function executeInJSDOM(bundlePath, destinations, event, tracker, envs, ti
1735
1852
  };
1736
1853
  }
1737
1854
 
1855
+ // src/commands/simulate/node-executor.ts
1856
+ import { pathToFileURL } from "url";
1857
+ function buildGlobalMocksFromEnvs(envs, destinations, tracker) {
1858
+ const globalMocks = {};
1859
+ for (const [destKey] of Object.entries(destinations)) {
1860
+ const destEnv = envs[destKey];
1861
+ if (!destEnv?.push) continue;
1862
+ const mockEnv = destEnv.push;
1863
+ const trackPaths = destEnv.simulation || [];
1864
+ const trackedEnv = tracker.wrapEnv(
1865
+ mockEnv,
1866
+ trackPaths.map((p) => `${destKey}:${p}`)
1867
+ );
1868
+ Object.assign(globalMocks, trackedEnv);
1869
+ }
1870
+ return globalMocks;
1871
+ }
1872
+ function injectGlobalMocks(mocks) {
1873
+ const originalValues = {};
1874
+ for (const [key, value] of Object.entries(mocks)) {
1875
+ originalValues[key] = globalThis[key];
1876
+ globalThis[key] = value;
1877
+ }
1878
+ return () => {
1879
+ for (const [key, value] of Object.entries(originalValues)) {
1880
+ if (value === void 0) {
1881
+ delete globalThis[key];
1882
+ } else {
1883
+ globalThis[key] = value;
1884
+ }
1885
+ }
1886
+ };
1887
+ }
1888
+ async function executeInNode(bundlePath, destinations, event, tracker, envs, timeout = 3e4) {
1889
+ const start = Date.now();
1890
+ const globalMocks = buildGlobalMocksFromEnvs(envs, destinations, tracker);
1891
+ const cleanupMocks = injectGlobalMocks(globalMocks);
1892
+ try {
1893
+ const executeWithTimeout = async () => {
1894
+ const importUrl = process.env.JEST_WORKER_ID ? bundlePath : `${pathToFileURL(bundlePath).href}?t=${Date.now()}`;
1895
+ const module = await import(importUrl);
1896
+ if (!module.default || typeof module.default !== "function") {
1897
+ throw new Error("Bundle does not export default factory function");
1898
+ }
1899
+ const result = await module.default();
1900
+ if (!result || !result.elb || typeof result.elb !== "function") {
1901
+ throw new Error(
1902
+ "Factory function did not return valid result with elb"
1903
+ );
1904
+ }
1905
+ const { collector, elb } = result;
1906
+ let elbResult;
1907
+ try {
1908
+ elbResult = await elb(event.name, event.data);
1909
+ } catch (error) {
1910
+ throw new Error(`Event execution failed: ${getErrorMessage(error)}`);
1911
+ }
1912
+ return {
1913
+ collector,
1914
+ elb,
1915
+ elbResult,
1916
+ usage: tracker.getCalls(),
1917
+ duration: Date.now() - start
1918
+ };
1919
+ };
1920
+ const timeoutPromise = new Promise((_, reject) => {
1921
+ setTimeout(
1922
+ () => reject(new Error(`Server simulation timeout after ${timeout}ms`)),
1923
+ timeout
1924
+ );
1925
+ });
1926
+ return await Promise.race([executeWithTimeout(), timeoutPromise]);
1927
+ } catch (error) {
1928
+ throw new Error(`Node execution failed: ${getErrorMessage(error)}`);
1929
+ } finally {
1930
+ cleanupMocks();
1931
+ }
1932
+ }
1933
+
1738
1934
  // src/commands/simulate/env-loader.ts
1739
1935
  async function loadDestinationEnvs(destinations) {
1740
1936
  const envs = {};
@@ -1779,9 +1975,9 @@ async function simulateCore(configPath, event, options = {}) {
1779
1975
  try {
1780
1976
  logger.info("\u{1F3AF} Starting walkerOS simulation...");
1781
1977
  logger.info("\u{1F4E6} Loading bundle configuration...");
1782
- const fullConfigPath = path7.resolve(configPath);
1978
+ const fullConfigPath = path10.resolve(configPath);
1783
1979
  const rawConfig = await loadJsonConfig(fullConfigPath);
1784
- parseBundleConfig(rawConfig);
1980
+ loadBundleConfig(rawConfig, { configPath: fullConfigPath });
1785
1981
  logger.info(`\u{1F680} Executing simulation with event: ${JSON.stringify(event)}`);
1786
1982
  const result = await executeSimulation(event, fullConfigPath);
1787
1983
  if (result.success) {
@@ -1825,42 +2021,32 @@ async function executeSimulation(event, configPath) {
1825
2021
  );
1826
2022
  }
1827
2023
  const typedEvent = event;
1828
- await fs7.ensureDir(tempDir);
2024
+ await fs10.ensureDir(tempDir);
1829
2025
  const rawConfig = await loadJsonConfig(configPath);
1830
- const { flowConfig, buildOptions } = parseBundleConfig(rawConfig);
1831
- const packagesArray = Object.entries(buildOptions.packages).map(
1832
- ([name, packageConfig]) => ({
1833
- name,
1834
- version: (typeof packageConfig === "object" && packageConfig !== null && "version" in packageConfig && typeof packageConfig.version === "string" ? packageConfig.version : void 0) || "latest"
1835
- })
1836
- );
1837
- const packagePaths = await downloadPackages(
1838
- packagesArray,
1839
- tempDir,
1840
- // downloadPackages will add 'node_modules' subdirectory itself
1841
- createLogger({ silent: true }),
1842
- buildOptions.cache
1843
- );
2026
+ const { flowConfig, buildOptions } = loadBundleConfig(rawConfig, {
2027
+ configPath
2028
+ });
2029
+ const platform = getPlatform2(flowConfig);
1844
2030
  const tracker = new CallTracker();
1845
- const tempOutput = path7.join(
2031
+ const tempOutput = path10.join(
1846
2032
  tempDir,
1847
- `simulation-bundle-${generateId()}.js`
2033
+ `simulation-bundle-${generateId()}.${platform === "web" ? "js" : "mjs"}`
1848
2034
  );
1849
2035
  const destinations = flowConfig.destinations;
1850
2036
  const simulationBuildOptions = {
1851
2037
  ...buildOptions,
1852
2038
  code: buildOptions.code || "",
1853
- // No code modification - use original
1854
2039
  output: tempOutput,
1855
2040
  tempDir,
1856
- // Use same temp dir for bundle
1857
- format: "iife",
1858
- // ← Test actual production format!
1859
- platform: "browser",
1860
- // ← Browser platform for IIFE
1861
- windowCollector: "collector",
1862
- // ← Ensure window assignment
1863
- windowElb: "elb"
2041
+ ...platform === "web" ? {
2042
+ format: "iife",
2043
+ platform: "browser",
2044
+ windowCollector: "collector",
2045
+ windowElb: "elb"
2046
+ } : {
2047
+ format: "esm",
2048
+ platform: "node"
2049
+ }
1864
2050
  };
1865
2051
  await bundleCore(
1866
2052
  flowConfig,
@@ -1870,16 +2056,26 @@ async function executeSimulation(event, configPath) {
1870
2056
  );
1871
2057
  bundlePath = tempOutput;
1872
2058
  const envs = await loadDestinationEnvs(destinations || {});
1873
- const result = await executeInJSDOM(
1874
- tempOutput,
1875
- destinations || {},
1876
- typedEvent,
1877
- tracker,
1878
- envs,
1879
- // Pass dynamically loaded envs
1880
- 1e4
1881
- // 10s timeout
1882
- );
2059
+ let result;
2060
+ if (platform === "web") {
2061
+ result = await executeInJSDOM(
2062
+ tempOutput,
2063
+ destinations || {},
2064
+ typedEvent,
2065
+ tracker,
2066
+ envs,
2067
+ 1e4
2068
+ );
2069
+ } else {
2070
+ result = await executeInNode(
2071
+ tempOutput,
2072
+ destinations || {},
2073
+ typedEvent,
2074
+ tracker,
2075
+ envs,
2076
+ 3e4
2077
+ );
2078
+ }
1883
2079
  const elbResult = result.elbResult;
1884
2080
  const usage = result.usage;
1885
2081
  const duration = Date.now() - startTime;
@@ -1899,7 +2095,7 @@ async function executeSimulation(event, configPath) {
1899
2095
  };
1900
2096
  } finally {
1901
2097
  if (tempDir) {
1902
- await fs7.remove(tempDir).catch(() => {
2098
+ await fs10.remove(tempDir).catch(() => {
1903
2099
  });
1904
2100
  }
1905
2101
  }
@@ -1975,15 +2171,16 @@ async function simulate(configOrPath, event, options = {}) {
1975
2171
  }
1976
2172
 
1977
2173
  // src/commands/push/index.ts
1978
- import path8 from "path";
1979
- import os2 from "os";
2174
+ import path11 from "path";
1980
2175
  import { JSDOM as JSDOM2, VirtualConsole as VirtualConsole2 } from "jsdom";
1981
- import fs8 from "fs-extra";
2176
+ import fs11 from "fs-extra";
2177
+ import { getPlatform as getPlatform3 } from "@walkeros/core";
2178
+ import { schemas as schemas2 } from "@walkeros/core/dev";
1982
2179
  async function pushCommand(options) {
1983
2180
  const logger = createCommandLogger(options);
1984
2181
  const dockerArgs = buildCommonDockerArgs(options);
1985
2182
  dockerArgs.push("--event", options.event);
1986
- if (options.env) dockerArgs.push("--env", options.env);
2183
+ if (options.flow) dockerArgs.push("--flow", options.flow);
1987
2184
  await executeCommand(
1988
2185
  async () => {
1989
2186
  const startTime = Date.now();
@@ -1992,57 +2189,65 @@ async function pushCommand(options) {
1992
2189
  const event = await loadJsonFromSource(options.event, {
1993
2190
  name: "event"
1994
2191
  });
1995
- if (!event || typeof event !== "object" || !("name" in event) || typeof event.name !== "string") {
1996
- throw new Error(
1997
- 'Event must be an object with a "name" property (string)'
1998
- );
2192
+ const eventResult = schemas2.PartialEventSchema.safeParse(event);
2193
+ if (!eventResult.success) {
2194
+ const errors = eventResult.error.issues.map((issue) => `${String(issue.path.join("."))}: ${issue.message}`).join(", ");
2195
+ throw new Error(`Invalid event: ${errors}`);
1999
2196
  }
2000
- if (!event.name.includes(" ")) {
2197
+ const parsedEvent = eventResult.data;
2198
+ if (!parsedEvent.name) {
2199
+ throw new Error('Invalid event: Missing required "name" property');
2200
+ }
2201
+ const validatedEvent = {
2202
+ name: parsedEvent.name,
2203
+ data: parsedEvent.data || {}
2204
+ };
2205
+ if (!validatedEvent.name.includes(" ")) {
2001
2206
  logger.warn(
2002
- `Event name "${event.name}" should follow "ENTITY ACTION" format (e.g., "page view")`
2207
+ `Event name "${validatedEvent.name}" should follow "ENTITY ACTION" format (e.g., "page view")`
2003
2208
  );
2004
2209
  }
2005
2210
  logger.info("\u{1F4E6} Loading flow configuration...");
2006
- const configPath = path8.resolve(options.config);
2211
+ const configPath = path11.resolve(options.config);
2007
2212
  const rawConfig = await loadJsonConfig(configPath);
2008
- const { flowConfig, buildOptions, environment, isMultiEnvironment } = loadBundleConfig(rawConfig, {
2213
+ const { flowConfig, buildOptions, flowName, isMultiFlow } = loadBundleConfig(rawConfig, {
2009
2214
  configPath: options.config,
2010
- environment: options.env,
2215
+ flowName: options.flow,
2011
2216
  logger
2012
2217
  });
2013
- const platform = flowConfig.platform;
2218
+ const platform = getPlatform3(flowConfig);
2014
2219
  logger.info("\u{1F528} Bundling flow configuration...");
2015
- const tempPath = path8.join(
2016
- os2.tmpdir(),
2017
- `walkeros-push-${Date.now()}-${Math.random().toString(36).slice(2, 9)}.${platform === "web" ? "js" : "mjs"}`
2220
+ const configDir = path11.dirname(configPath);
2221
+ const tempDir = path11.join(
2222
+ configDir,
2223
+ ".tmp",
2224
+ `push-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
2018
2225
  );
2019
- const configWithOutput = {
2020
- flow: flowConfig,
2021
- build: {
2022
- ...buildOptions,
2023
- output: tempPath,
2024
- // Web uses IIFE for browser-like execution, server uses ESM
2025
- format: platform === "web" ? "iife" : "esm",
2026
- platform: platform === "web" ? "browser" : "node",
2027
- ...platform === "web" && {
2028
- windowCollector: "collector",
2029
- windowElb: "elb"
2030
- }
2226
+ await fs11.ensureDir(tempDir);
2227
+ const tempPath = path11.join(
2228
+ tempDir,
2229
+ `bundle.${platform === "web" ? "js" : "mjs"}`
2230
+ );
2231
+ const pushBuildOptions = {
2232
+ ...buildOptions,
2233
+ output: tempPath,
2234
+ // Web uses IIFE for browser-like execution, server uses ESM
2235
+ format: platform === "web" ? "iife" : "esm",
2236
+ platform: platform === "web" ? "browser" : "node",
2237
+ ...platform === "web" && {
2238
+ windowCollector: "collector",
2239
+ windowElb: "elb"
2031
2240
  }
2032
2241
  };
2033
- await bundle(configWithOutput, {
2034
- cache: true,
2035
- verbose: options.verbose,
2036
- silent: !options.verbose
2037
- });
2242
+ await bundleCore(flowConfig, pushBuildOptions, logger, false);
2038
2243
  logger.debug(`Bundle created: ${tempPath}`);
2039
2244
  let result;
2040
2245
  if (platform === "web") {
2041
2246
  logger.info("\u{1F310} Executing in web environment (JSDOM)...");
2042
- result = await executeWebPush(tempPath, event, logger);
2247
+ result = await executeWebPush(tempPath, validatedEvent, logger);
2043
2248
  } else if (platform === "server") {
2044
2249
  logger.info("\u{1F5A5}\uFE0F Executing in server environment (Node.js)...");
2045
- result = await executeServerPush(tempPath, event, logger);
2250
+ result = await executeServerPush(tempPath, validatedEvent, logger);
2046
2251
  } else {
2047
2252
  throw new Error(`Unsupported platform: ${platform}`);
2048
2253
  }
@@ -2083,7 +2288,7 @@ async function pushCommand(options) {
2083
2288
  }
2084
2289
  }
2085
2290
  try {
2086
- await fs8.remove(tempPath);
2291
+ await fs11.remove(tempDir);
2087
2292
  } catch {
2088
2293
  }
2089
2294
  } catch (error) {
@@ -2128,7 +2333,7 @@ async function executeWebPush(bundlePath, event, logger) {
2128
2333
  });
2129
2334
  const { window } = dom;
2130
2335
  logger.debug("Loading bundle...");
2131
- const bundleCode = await fs8.readFile(bundlePath, "utf8");
2336
+ const bundleCode = await fs11.readFile(bundlePath, "utf8");
2132
2337
  window.eval(bundleCode);
2133
2338
  logger.debug("Waiting for elb...");
2134
2339
  await waitForWindowProperty2(
@@ -2139,8 +2344,7 @@ async function executeWebPush(bundlePath, event, logger) {
2139
2344
  const windowObj = window;
2140
2345
  const elb = windowObj.elb;
2141
2346
  logger.info(`Pushing event: ${event.name}`);
2142
- const eventData = event.data || {};
2143
- const elbResult = await elb(event.name, eventData);
2347
+ const elbResult = await elb(event.name, event.data);
2144
2348
  return {
2145
2349
  success: true,
2146
2350
  elbResult,
@@ -2178,8 +2382,7 @@ async function executeServerPush(bundlePath, event, logger, timeout = 6e4) {
2178
2382
  }
2179
2383
  const { elb } = result;
2180
2384
  logger.info(`Pushing event: ${event.name}`);
2181
- const eventData = event.data || {};
2182
- const elbResult = await elb(event.name, eventData);
2385
+ const elbResult = await elb(event.name, event.data);
2183
2386
  return {
2184
2387
  success: true,
2185
2388
  elbResult,
@@ -2216,23 +2419,40 @@ function waitForWindowProperty2(window, prop, timeout = 5e3) {
2216
2419
  }
2217
2420
 
2218
2421
  // src/commands/run/index.ts
2219
- import path10 from "path";
2422
+ import path13 from "path";
2423
+
2424
+ // src/commands/run/validators.ts
2425
+ import { existsSync as existsSync2 } from "fs";
2426
+
2427
+ // src/schemas/primitives.ts
2428
+ import { z } from "@walkeros/core/dev";
2429
+ var RunModeSchema = z.enum(["collect", "serve"]).describe("CLI run mode: collect events or serve HTTP");
2430
+ var PortSchema = z.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");
2431
+ var FilePathSchema = z.string().min(1, "File path cannot be empty").describe("Path to configuration file");
2432
+
2433
+ // src/schemas/run.ts
2434
+ import { z as z2 } from "@walkeros/core/dev";
2435
+ var RunOptionsSchema = z2.object({
2436
+ mode: RunModeSchema,
2437
+ flow: FilePathSchema,
2438
+ port: PortSchema.default(8080),
2439
+ flowName: z2.string().optional().describe("Specific flow name to run")
2440
+ });
2220
2441
 
2221
2442
  // src/commands/run/validators.ts
2222
- import { existsSync } from "fs";
2223
- var VALID_MODES = ["collect", "serve"];
2224
2443
  function validateMode(mode) {
2225
- if (!VALID_MODES.includes(mode)) {
2444
+ const result = RunModeSchema.safeParse(mode);
2445
+ if (!result.success) {
2226
2446
  throw new Error(
2227
2447
  `Invalid mode: "${mode}"
2228
- Valid modes: ${VALID_MODES.join(", ")}
2448
+ Valid modes: collect, serve
2229
2449
  Example: walkeros run collect ./flow.json`
2230
2450
  );
2231
2451
  }
2232
2452
  }
2233
2453
  function validateFlowFile(filePath) {
2234
2454
  const absolutePath = resolveAsset(filePath, "bundle");
2235
- if (!existsSync(absolutePath)) {
2455
+ if (!existsSync2(absolutePath)) {
2236
2456
  throw new Error(
2237
2457
  `Flow file not found: ${filePath}
2238
2458
  Resolved path: ${absolutePath}
@@ -2242,7 +2462,8 @@ function validateFlowFile(filePath) {
2242
2462
  return absolutePath;
2243
2463
  }
2244
2464
  function validatePort(port) {
2245
- if (!Number.isInteger(port) || port < 1 || port > 65535) {
2465
+ const result = PortSchema.safeParse(port);
2466
+ if (!result.success) {
2246
2467
  throw new Error(
2247
2468
  `Invalid port: ${port}
2248
2469
  Port must be an integer between 1 and 65535
@@ -2252,26 +2473,26 @@ function validatePort(port) {
2252
2473
  }
2253
2474
 
2254
2475
  // src/commands/run/utils.ts
2255
- import path9 from "path";
2256
- import os3 from "os";
2476
+ import path12 from "path";
2477
+ import fs12 from "fs-extra";
2257
2478
  async function prepareBundleForRun(configPath, options) {
2258
- const rawConfig = await loadJsonConfig(configPath);
2259
- const tempPath = path9.join(
2260
- os3.tmpdir(),
2261
- `walkeros-${Date.now()}-${Math.random().toString(36).slice(2, 9)}.mjs`
2479
+ const configDir = path12.dirname(path12.resolve(configPath));
2480
+ const tempDir = path12.join(
2481
+ configDir,
2482
+ ".tmp",
2483
+ `run-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
2262
2484
  );
2263
- const existingBuild = typeof rawConfig === "object" && rawConfig !== null && "build" in rawConfig && typeof rawConfig.build === "object" ? rawConfig.build : {};
2264
- const configWithOutput = {
2265
- ...rawConfig,
2266
- build: {
2267
- ...existingBuild,
2268
- output: tempPath
2269
- }
2270
- };
2271
- await bundle(configWithOutput, {
2485
+ await fs12.ensureDir(tempDir);
2486
+ const tempPath = path12.join(tempDir, "bundle.mjs");
2487
+ await bundle(configPath, {
2272
2488
  cache: true,
2273
2489
  verbose: options.verbose,
2274
- silent: options.silent
2490
+ silent: options.silent,
2491
+ buildOverrides: {
2492
+ output: tempPath,
2493
+ format: "esm",
2494
+ platform: "node"
2495
+ }
2275
2496
  });
2276
2497
  return tempPath;
2277
2498
  }
@@ -2325,9 +2546,9 @@ async function runCommand(mode, options) {
2325
2546
  let flowPath = null;
2326
2547
  if (mode === "collect") {
2327
2548
  if (isPreBuilt) {
2328
- flowPath = path10.resolve(configPath);
2549
+ flowPath = path13.resolve(configPath);
2329
2550
  if (!options.json && !options.silent) {
2330
- logger.info(`\u{1F4E6} Using pre-built flow: ${path10.basename(flowPath)}`);
2551
+ logger.info(`\u{1F4E6} Using pre-built flow: ${path13.basename(flowPath)}`);
2331
2552
  }
2332
2553
  } else {
2333
2554
  if (!options.json && !options.silent) {
@@ -2416,7 +2637,7 @@ async function run(mode, options) {
2416
2637
  const isPreBuilt = isPreBuiltConfig(flowFile);
2417
2638
  let flowPath;
2418
2639
  if (isPreBuilt) {
2419
- flowPath = path10.resolve(flowFile);
2640
+ flowPath = path13.resolve(flowFile);
2420
2641
  } else {
2421
2642
  flowPath = await prepareBundleForRun(flowFile, {
2422
2643
  verbose: options.verbose,
@@ -2444,22 +2665,53 @@ async function run(mode, options) {
2444
2665
  }
2445
2666
  }
2446
2667
 
2668
+ // src/commands/cache.ts
2669
+ import fs13 from "fs-extra";
2670
+ import path14 from "path";
2671
+ var CACHE_DIR = path14.join(".tmp", "cache");
2672
+ function registerCacheCommand(program2) {
2673
+ const cache = program2.command("cache").description("Manage the CLI cache");
2674
+ cache.command("clear").description("Clear all cached packages and builds").option("--packages", "Clear only package cache").option("--builds", "Clear only build cache").action(async (options) => {
2675
+ if (options.packages) {
2676
+ await fs13.remove(path14.join(CACHE_DIR, "packages"));
2677
+ console.log("Package cache cleared");
2678
+ } else if (options.builds) {
2679
+ await fs13.remove(path14.join(CACHE_DIR, "builds"));
2680
+ console.log("Build cache cleared");
2681
+ } else {
2682
+ await fs13.remove(CACHE_DIR);
2683
+ console.log("All caches cleared");
2684
+ }
2685
+ });
2686
+ cache.command("info").description("Show cache statistics").action(async () => {
2687
+ const packagesDir = path14.join(CACHE_DIR, "packages");
2688
+ const buildsDir = path14.join(CACHE_DIR, "builds");
2689
+ const packageCount = await countEntries(packagesDir);
2690
+ const buildCount = await countEntries(buildsDir);
2691
+ console.log(`Cache directory: ${CACHE_DIR}`);
2692
+ console.log(`Cached packages: ${packageCount}`);
2693
+ console.log(`Cached builds: ${buildCount}`);
2694
+ });
2695
+ }
2696
+ async function countEntries(dir) {
2697
+ if (!await fs13.pathExists(dir)) return 0;
2698
+ const entries = await fs13.readdir(dir);
2699
+ return entries.length;
2700
+ }
2701
+
2447
2702
  // src/index.ts
2448
- var __filename = fileURLToPath3(import.meta.url);
2703
+ var __filename = fileURLToPath2(import.meta.url);
2449
2704
  var __dirname = dirname(__filename);
2450
2705
  var packageJson = JSON.parse(
2451
- readFileSync2(join(__dirname, "../package.json"), "utf-8")
2706
+ readFileSync(join(__dirname, "../package.json"), "utf-8")
2452
2707
  );
2453
2708
  var VERSION = packageJson.version;
2454
2709
  var program = new Command();
2455
2710
  program.name("walkeros").description("walkerOS CLI - Bundle and deploy walkerOS components").version(VERSION);
2456
- program.command("bundle [file]").description("Bundle NPM packages with custom code").option(
2457
- "-e, --env <name>",
2458
- "environment to build (for multi-environment configs)"
2459
- ).option("--all", "build all environments (for multi-environment configs)").option("-s, --stats", "show bundle statistics").option("--json", "output statistics in JSON format (implies --stats)").option("--no-cache", "disable package caching and download fresh packages").option("-v, --verbose", "verbose output").option("--local", "execute in local Node.js instead of Docker").option("--dry-run", "preview command without executing").option("--silent", "suppress output").action(async (file, options) => {
2711
+ program.command("bundle [file]").description("Bundle NPM packages with custom code").option("-f, --flow <name>", "flow to build (for multi-flow configs)").option("--all", "build all flows (for multi-flow configs)").option("-s, --stats", "show bundle statistics").option("--json", "output statistics in JSON format (implies --stats)").option("--no-cache", "disable package caching and download fresh packages").option("-v, --verbose", "verbose output").option("--local", "execute in local Node.js instead of Docker").option("--dry-run", "preview command without executing").option("--silent", "suppress output").action(async (file, options) => {
2460
2712
  await bundleCommand({
2461
2713
  config: file || "bundle.config.json",
2462
- env: options.env,
2714
+ flow: options.flow,
2463
2715
  all: options.all,
2464
2716
  stats: options.stats,
2465
2717
  json: options.json,
@@ -2487,11 +2739,11 @@ program.command("simulate [file]").description("Simulate event processing and ca
2487
2739
  program.command("push [file]").description("Push an event through the flow with real API execution").requiredOption(
2488
2740
  "-e, --event <source>",
2489
2741
  "Event to push (JSON string, file path, or URL)"
2490
- ).option("--env <name>", "Environment name (for multi-environment configs)").option("--json", "Output results as JSON").option("-v, --verbose", "Verbose output").option("-s, --silent", "Suppress output").option("--local", "Execute in local Node.js instead of Docker").action(async (file, options) => {
2742
+ ).option("--flow <name>", "Flow name (for multi-flow configs)").option("--json", "Output results as JSON").option("-v, --verbose", "Verbose output").option("-s, --silent", "Suppress output").option("--local", "Execute in local Node.js instead of Docker").action(async (file, options) => {
2491
2743
  await pushCommand({
2492
2744
  config: file || "bundle.config.json",
2493
2745
  event: options.event,
2494
- env: options.env,
2746
+ flow: options.flow,
2495
2747
  json: options.json,
2496
2748
  verbose: options.verbose,
2497
2749
  silent: options.silent,
@@ -2529,6 +2781,7 @@ runCmd.command("serve [file]").description(
2529
2781
  silent: options.silent
2530
2782
  });
2531
2783
  });
2784
+ registerCacheCommand(program);
2532
2785
  program.parse();
2533
2786
  export {
2534
2787
  bundle,