@walkeros/cli 0.3.6 → 0.4.1

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 (228) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/__tests__/bundle/bundler-helpers.test.d.ts +2 -0
  3. package/dist/__tests__/bundle/bundler-helpers.test.d.ts.map +1 -0
  4. package/dist/__tests__/bundle/bundler-helpers.test.js +285 -0
  5. package/dist/__tests__/bundle/bundler-helpers.test.js.map +1 -0
  6. package/dist/__tests__/bundle/bundler.test.js +9 -3
  7. package/dist/__tests__/bundle/bundler.test.js.map +1 -1
  8. package/dist/__tests__/bundle/programmatic.test.js +5 -1
  9. package/dist/__tests__/bundle/programmatic.test.js.map +1 -1
  10. package/dist/__tests__/bundle/serializer.test.js +1 -1
  11. package/dist/__tests__/bundle/serializer.test.js.map +1 -1
  12. package/dist/__tests__/bundle/template-engine.test.js +1 -1
  13. package/dist/__tests__/bundle/template-engine.test.js.map +1 -1
  14. package/dist/__tests__/cli.test.js +6 -71
  15. package/dist/__tests__/cli.test.js.map +1 -1
  16. package/dist/__tests__/config-loader.test.js +8 -5
  17. package/dist/__tests__/config-loader.test.js.map +1 -1
  18. package/dist/__tests__/core/config.test.js +1 -1
  19. package/dist/__tests__/core/config.test.js.map +1 -1
  20. package/dist/__tests__/core/logger.test.js +1 -1
  21. package/dist/__tests__/core/logger.test.js.map +1 -1
  22. package/dist/__tests__/integration/bundle-run.integration.test.d.ts +8 -0
  23. package/dist/__tests__/integration/bundle-run.integration.test.d.ts.map +1 -0
  24. package/dist/__tests__/integration/bundle-run.integration.test.js +50 -0
  25. package/dist/__tests__/integration/bundle-run.integration.test.js.map +1 -0
  26. package/dist/__tests__/push/push.test.d.ts +7 -0
  27. package/dist/__tests__/push/push.test.d.ts.map +1 -0
  28. package/dist/__tests__/push/push.test.js +197 -0
  29. package/dist/__tests__/push/push.test.js.map +1 -0
  30. package/dist/__tests__/simulate/env-loader.test.d.ts +2 -0
  31. package/dist/__tests__/simulate/env-loader.test.d.ts.map +1 -0
  32. package/dist/__tests__/simulate/env-loader.test.js +47 -0
  33. package/dist/__tests__/simulate/env-loader.test.js.map +1 -0
  34. package/dist/__tests__/smoke/production.smoke.test.d.ts +8 -0
  35. package/dist/__tests__/smoke/production.smoke.test.d.ts.map +1 -0
  36. package/dist/__tests__/smoke/production.smoke.test.js +58 -0
  37. package/dist/__tests__/smoke/production.smoke.test.js.map +1 -0
  38. package/dist/commands/bundle/bundler.d.ts +2 -2
  39. package/dist/commands/bundle/bundler.d.ts.map +1 -1
  40. package/dist/commands/bundle/bundler.js +70 -58
  41. package/dist/commands/bundle/bundler.js.map +1 -1
  42. package/dist/commands/bundle/index.d.ts +1 -1
  43. package/dist/commands/bundle/index.d.ts.map +1 -1
  44. package/dist/commands/bundle/index.js +11 -23
  45. package/dist/commands/bundle/index.js.map +1 -1
  46. package/dist/commands/bundle/package-manager.d.ts +1 -1
  47. package/dist/commands/bundle/package-manager.d.ts.map +1 -1
  48. package/dist/commands/bundle/serializer.d.ts +1 -1
  49. package/dist/commands/bundle/serializer.d.ts.map +1 -1
  50. package/dist/commands/bundle/serializer.js +1 -1
  51. package/dist/commands/bundle/serializer.js.map +1 -1
  52. package/dist/commands/bundle/stats.d.ts +2 -2
  53. package/dist/commands/bundle/stats.d.ts.map +1 -1
  54. package/dist/commands/bundle/stats.js +1 -1
  55. package/dist/commands/bundle/stats.js.map +1 -1
  56. package/dist/commands/bundle/template-engine.d.ts +1 -1
  57. package/dist/commands/bundle/template-engine.d.ts.map +1 -1
  58. package/dist/commands/bundle/template-engine.js +4 -2
  59. package/dist/commands/bundle/template-engine.js.map +1 -1
  60. package/dist/commands/push/index.d.ts +7 -0
  61. package/dist/commands/push/index.d.ts.map +1 -0
  62. package/dist/commands/push/index.js +252 -0
  63. package/dist/commands/push/index.js.map +1 -0
  64. package/dist/commands/push/types.d.ts +21 -0
  65. package/dist/commands/push/types.d.ts.map +1 -0
  66. package/dist/commands/push/types.js +2 -0
  67. package/dist/commands/push/types.js.map +1 -0
  68. package/dist/commands/run/__tests__/run.integration.test.js +1 -1
  69. package/dist/commands/run/__tests__/run.integration.test.js.map +1 -1
  70. package/dist/commands/run/__tests__/validators.test.js +1 -1
  71. package/dist/commands/run/__tests__/validators.test.js.map +1 -1
  72. package/dist/commands/run/execution.d.ts +14 -0
  73. package/dist/commands/run/execution.d.ts.map +1 -0
  74. package/dist/commands/run/execution.js +37 -0
  75. package/dist/commands/run/execution.js.map +1 -0
  76. package/dist/commands/run/index.d.ts +1 -1
  77. package/dist/commands/run/index.d.ts.map +1 -1
  78. package/dist/commands/run/index.js +33 -107
  79. package/dist/commands/run/index.js.map +1 -1
  80. package/dist/commands/run/types.d.ts +1 -1
  81. package/dist/commands/run/types.d.ts.map +1 -1
  82. package/dist/commands/run/utils.d.ts +26 -0
  83. package/dist/commands/run/utils.d.ts.map +1 -0
  84. package/dist/commands/run/utils.js +58 -0
  85. package/dist/commands/run/utils.js.map +1 -0
  86. package/dist/commands/run/validators.d.ts +1 -1
  87. package/dist/commands/run/validators.d.ts.map +1 -1
  88. package/dist/commands/run/validators.js +1 -1
  89. package/dist/commands/run/validators.js.map +1 -1
  90. package/dist/commands/simulate/env-loader.d.ts +19 -0
  91. package/dist/commands/simulate/env-loader.d.ts.map +1 -0
  92. package/dist/commands/simulate/env-loader.js +46 -0
  93. package/dist/commands/simulate/env-loader.js.map +1 -0
  94. package/dist/commands/simulate/index.d.ts +3 -3
  95. package/dist/commands/simulate/index.d.ts.map +1 -1
  96. package/dist/commands/simulate/index.js +14 -20
  97. package/dist/commands/simulate/index.js.map +1 -1
  98. package/dist/commands/simulate/jsdom-executor.d.ts +37 -0
  99. package/dist/commands/simulate/jsdom-executor.d.ts.map +1 -0
  100. package/dist/commands/simulate/jsdom-executor.js +137 -0
  101. package/dist/commands/simulate/jsdom-executor.js.map +1 -0
  102. package/dist/commands/simulate/simulator.d.ts +1 -5
  103. package/dist/commands/simulate/simulator.d.ts.map +1 -1
  104. package/dist/commands/simulate/simulator.js +33 -111
  105. package/dist/commands/simulate/simulator.js.map +1 -1
  106. package/dist/commands/simulate/types.d.ts +2 -2
  107. package/dist/commands/simulate/types.d.ts.map +1 -1
  108. package/dist/config/defaults.d.ts +1 -1
  109. package/dist/config/defaults.d.ts.map +1 -1
  110. package/dist/config/defaults.js +0 -1
  111. package/dist/config/defaults.js.map +1 -1
  112. package/dist/config/index.d.ts +8 -8
  113. package/dist/config/index.d.ts.map +1 -1
  114. package/dist/config/index.js +5 -5
  115. package/dist/config/index.js.map +1 -1
  116. package/dist/config/loader.d.ts +1 -1
  117. package/dist/config/loader.d.ts.map +1 -1
  118. package/dist/config/loader.js +23 -19
  119. package/dist/config/loader.js.map +1 -1
  120. package/dist/config/parser.d.ts +65 -1
  121. package/dist/config/parser.d.ts.map +1 -1
  122. package/dist/config/parser.js +176 -62
  123. package/dist/config/parser.js.map +1 -1
  124. package/dist/config/utils.d.ts +46 -0
  125. package/dist/config/utils.d.ts.map +1 -1
  126. package/dist/config/utils.js +103 -0
  127. package/dist/config/utils.js.map +1 -1
  128. package/dist/config/validators.d.ts +4 -1
  129. package/dist/config/validators.d.ts.map +1 -1
  130. package/dist/config/validators.js +4 -2
  131. package/dist/config/validators.js.map +1 -1
  132. package/dist/core/asset-resolver.d.ts.map +1 -1
  133. package/dist/core/asset-resolver.js +10 -3
  134. package/dist/core/asset-resolver.js.map +1 -1
  135. package/dist/core/docker.d.ts +17 -1
  136. package/dist/core/docker.d.ts.map +1 -1
  137. package/dist/core/docker.js +22 -1
  138. package/dist/core/docker.js.map +1 -1
  139. package/dist/core/execution.d.ts +2 -2
  140. package/dist/core/execution.d.ts.map +1 -1
  141. package/dist/core/execution.js +1 -1
  142. package/dist/core/execution.js.map +1 -1
  143. package/dist/core/index.d.ts +8 -6
  144. package/dist/core/index.d.ts.map +1 -1
  145. package/dist/core/index.js +8 -6
  146. package/dist/core/index.js.map +1 -1
  147. package/dist/core/logger.d.ts +11 -0
  148. package/dist/core/logger.d.ts.map +1 -1
  149. package/dist/core/logger.js +14 -0
  150. package/dist/core/logger.js.map +1 -1
  151. package/dist/core/temp-manager.d.ts +51 -0
  152. package/dist/core/temp-manager.d.ts.map +1 -0
  153. package/dist/core/temp-manager.js +73 -0
  154. package/dist/core/temp-manager.js.map +1 -0
  155. package/dist/core/utils.d.ts +10 -0
  156. package/dist/core/utils.d.ts.map +1 -0
  157. package/dist/core/utils.js +12 -0
  158. package/dist/core/utils.js.map +1 -0
  159. package/dist/index.d.ts +42 -13
  160. package/dist/index.d.ts.map +1 -1
  161. package/dist/index.js +827 -397
  162. package/dist/index.js.map +1 -1
  163. package/dist/types/bundle.d.ts +26 -12
  164. package/dist/types/bundle.d.ts.map +1 -1
  165. package/dist/types/index.d.ts +2 -2
  166. package/dist/types/index.d.ts.map +1 -1
  167. package/dist/types/index.js +2 -2
  168. package/dist/types/index.js.map +1 -1
  169. package/examples/.npm-cache/content-v2/sha512/0d/2d/7581c288670eaf8538ddd9df145b78756ce3be0791c6e0b9cd33429b3bae894525b9bda287a3cedffbcdd2c7b3107bafc03f2b0367eea489eee1cc042abb +1 -0
  170. package/examples/.npm-cache/content-v2/sha512/12/20/bc4f5acca143809f7e07da1fdafb38137d93243de4d5b403e6e10b92d0d3a6e51eab24fe9dbc9d3ed1cd72e8f7a406085e99c422bb2c7d1166cf9f1f564e +0 -0
  171. package/examples/.npm-cache/content-v2/sha512/22/ee/fb2695b01871c1d36946bdcfb49f1b520a57200d0a0b221b1e7d5f047ab38a8b2ab0e5f0e25a00acde1f3f2f9d24430a18f1092d438bc1a9e9891cc45f75 +0 -0
  172. package/examples/.npm-cache/content-v2/sha512/24/89/da1ce6a61bca6de7e132f241a675c01c83738bf6b78af25b5cce01d3030361332b3fe938571e2b721f1555da9ddf930fdcf8c02f0471556071590e68cc09 +0 -0
  173. package/examples/.npm-cache/content-v2/sha512/47/fd/c6be997da99228c3e279b95d4a46d6913947078a178f54ac71795a159f3513b1483232f4c2d0a1f403178bf9f96bb19615de32a9e2133e949880c6bc15e2 +0 -0
  174. package/examples/.npm-cache/content-v2/sha512/4b/1c/c1cb7f8b32102071a89fef97158daa32080ebaedfbbd596880d2213d84e305abc76d2a95a412ded55c1c3d487adcb1ceff87fc2c85d7e2856ebd9d3f16f3 +0 -0
  175. package/examples/.npm-cache/content-v2/sha512/6e/53/ff864769671f44f39d8a3bf904cd646535b745cc4824a8bb3189193b474678049f43b5178ba15cad7f0289046105e70f1565afc84e907120b35a466690fd +1 -0
  176. package/examples/.npm-cache/content-v2/sha512/70/4c/4c8837d446965c5551b4ea527e95fa011744fb727581d82cf35bb5599ea0b57d18baa490f7af93ef9a16e8e45e5c0802737da20575f4056a4a5c9a3cd288 +0 -0
  177. package/examples/.npm-cache/content-v2/sha512/96/ad/05de3bbb12d7de8ea353f962bdaea7d2eb44f707f2973462a6635daf537c67b46cca7764fed7d464fe62152c3f783a07aba1ceb35e09ad446bff05a4b466 +1 -0
  178. package/examples/.npm-cache/content-v2/sha512/b5/20/52dde94e6cef7170f6089c64a4843e57be18be450d956f4e455905aed047ae6a368451c93035e6ac3ee59576b600f03f815afba0836b3a16e10a9aaca4ba +1 -0
  179. package/examples/.npm-cache/content-v2/sha512/c7/a9/d166a1c39f97df312c59261319ba1cf9aac178bda0a0cb697d5ddd78bd8dd38ef1bf40017bcc8633c2049896c2d70696d9bff9280851f270792ff38bb3a0 +1 -0
  180. package/examples/.npm-cache/content-v2/sha512/e0/d0/8c14083b633e6adbd3c6a93da5fc0f6bbd456c5512ef276920bedd8d85d551052adff992de977aff326616a211aaa2d6ddcc801149e9b7f914f566359b6a +1 -0
  181. package/examples/.npm-cache/content-v2/sha512/e7/c5/06ad3fd79ac4f1031fe0b16ea5e54e232ca397bbcd7592c679021cbfb027276099f8c848f3f7a7691f0102ad53aa64f9141e61d729b037a678bd60440d17 +1 -0
  182. package/examples/.npm-cache/content-v2/sha512/f3/28/d5d32329604ed7d471a4949105daa2cc98858cf24f45b0b97c41d0eb0d5a9fe7bf1f69c792161cc6693e4fc1b52e886ac41875ebfb8fe47fafe417ca3e6e +0 -0
  183. package/examples/.npm-cache/index-v5/04/5a/2b5d7a7c407d85d746baa0f5c9388a333e35a717a8a0a81943daa6cb1364 +3 -0
  184. package/examples/.npm-cache/index-v5/12/9a/eba560cbace295d8ee04cf283015377bd77b379e70968fb6bc407c7fc410 +15 -0
  185. package/examples/.npm-cache/index-v5/2f/a2/7b047564b0ee21ac835ec609e89153dd6549be554d098584d5bfd19fe043 +15 -0
  186. package/examples/.npm-cache/index-v5/32/8e/322d58dd8d1e000be248ada51385bf96288e56039de9feec1a4c6a467653 +3 -0
  187. package/examples/.npm-cache/index-v5/57/93/d1d7cd1402e3e26468db03f2870822bb2c9018a506cdfb3b405f38cd3e1c +3 -0
  188. package/examples/.npm-cache/index-v5/5d/f8/0a1f4fa7149e4ff33e09eb6aea41ac8d1730c868a5d3ace91f762698acff +3 -0
  189. package/examples/.npm-cache/index-v5/69/a4/a92c72d838259b051cdf8e0acfb2bc680b6d4cfc642314a7836c3f7b2c50 +15 -0
  190. package/examples/.npm-cache/index-v5/71/31/6da3423bb203f3de5eb16c942431073f89be2cfcb40058ec91dcb5ce0abc +15 -0
  191. package/examples/.npm-cache/index-v5/7b/94/72b6bffa050d9ef52a558dd220663695bc606f756be0dfa196ef4f3913ba +3 -0
  192. package/examples/.npm-cache/index-v5/85/9e/99e97fdd562517e56285337db91d1a8f2f416b8d631cf4d7d754fa671299 +15 -0
  193. package/examples/.npm-cache/index-v5/92/4c/9416ada81a9b3c679539fd1ab53f8de3d41ff268f35eba7a194389a85b06 +3 -0
  194. package/examples/.npm-cache/index-v5/c1/5a/13df76b218deed8a6ef12961116af5183db98c53fad1b922fd9edc075247 +3 -0
  195. package/examples/.npm-cache/index-v5/cb/11/253c55410a8ab7c4a9ea9d6e1bf8ef1450a581da64c478074dfd82c8bff6 +3 -0
  196. package/examples/.npm-cache/index-v5/d5/ae/b57fad3a62b5ba2dbdf24b042a9e7b70820f3db00e5a630f02e1fea020dc +3 -0
  197. package/examples/.npm-cache/index-v5/d6/32/2f620f83c7d14451de98de8298c2408e05a16cc0829bd16c891ac19d7a67 +3 -0
  198. package/examples/.npm-cache/index-v5/dd/b5/01dc7a3cd8b6a03a69aee9af500d51ae19cb0aa12631a4aafd152148b8e5 +15 -0
  199. package/examples/.npm-cache/index-v5/e0/cf/6b862c15d74630d3871cd813d305210ab741311deb10baf8813014e0bc30 +3 -0
  200. package/examples/.npm-cache/index-v5/e2/be/e880ccd35950a814d3c1dded34d3938ac61b15a195321dc51357f801aad4 +15 -0
  201. package/examples/.npm-cache/index-v5/e5/1f/f4affe0b392cd03288f23cc03abcb274ff11a2c8f8965299de681914abb2 +3 -0
  202. package/examples/.npm-cache/index-v5/f3/5b/9ebe450958ff0d7cc44ab0a00080cb8a3ff1389744b5eab5f97b68a6a6af +3 -0
  203. package/examples/.npm-cache/index-v5/fb/c1/0de405e902866d53e7c30cf36a97dc2578838622b261816f44dc377c9a80 +3 -0
  204. package/examples/README.md +4 -4
  205. package/examples/event.json +53 -0
  206. package/examples/flow-order-complete.json +68 -0
  207. package/examples/flow-simple.json +32 -0
  208. package/examples/flow.json +82 -0
  209. package/examples/server-collect.mjs +1360 -1190
  210. package/examples/test.html +43 -0
  211. package/examples/web-serve.js +25503 -0
  212. package/examples/web-serve.json +4 -3
  213. package/package.json +3 -2
  214. package/templates/server.hbs +2 -2
  215. package/templates/web.hbs +12 -11
  216. package/dist/__tests__/bundle/bundler-integration.test.d.ts +0 -2
  217. package/dist/__tests__/bundle/bundler-integration.test.d.ts.map +0 -1
  218. package/dist/__tests__/bundle/bundler-integration.test.js +0 -106
  219. package/dist/__tests__/bundle/bundler-integration.test.js.map +0 -1
  220. package/dist/__tests__/simulate/programmatic.test.d.ts +0 -2
  221. package/dist/__tests__/simulate/programmatic.test.d.ts.map +0 -1
  222. package/dist/__tests__/simulate/programmatic.test.js +0 -51
  223. package/dist/__tests__/simulate/programmatic.test.js.map +0 -1
  224. package/dist/__tests__/simulate/simulator.test.d.ts +0 -2
  225. package/dist/__tests__/simulate/simulator.test.d.ts.map +0 -1
  226. package/dist/__tests__/simulate/simulator.test.js +0 -29
  227. package/dist/__tests__/simulate/simulator.test.js.map +0 -1
  228. package/examples/web-serve.mjs +0 -19456
package/dist/index.js CHANGED
@@ -77,6 +77,13 @@ function createLogger(options = {}) {
77
77
  }
78
78
  };
79
79
  }
80
+ function createCommandLogger(options) {
81
+ return createLogger({
82
+ verbose: options.verbose,
83
+ silent: options.silent ?? false,
84
+ json: options.json
85
+ });
86
+ }
80
87
 
81
88
  // src/core/timer.ts
82
89
  function createTimer() {
@@ -200,6 +207,59 @@ function getTempDir(tempDir = ".tmp") {
200
207
  const basePath = path.isAbsolute(tempDir) ? tempDir : path.join(process.cwd(), tempDir);
201
208
  return path.join(basePath, `cli-${Date.now()}-${randomId}`);
202
209
  }
210
+ async function loadJsonFromSource(source, options) {
211
+ const paramName = options?.name || "input";
212
+ if (!source || source.trim() === "") {
213
+ if (options?.required) {
214
+ throw new Error(`${paramName} is required`);
215
+ }
216
+ if (options?.fallback !== void 0) {
217
+ return options.fallback;
218
+ }
219
+ return {};
220
+ }
221
+ const trimmedSource = source.trim();
222
+ if (isUrl(trimmedSource)) {
223
+ try {
224
+ const tempPath = await downloadFromUrl(trimmedSource);
225
+ try {
226
+ const data = await fs.readJson(tempPath);
227
+ return data;
228
+ } finally {
229
+ try {
230
+ await fs.remove(tempPath);
231
+ } catch {
232
+ }
233
+ }
234
+ } catch (error) {
235
+ throw new Error(
236
+ `Failed to load ${paramName} from URL ${trimmedSource}: ${getErrorMessage(error)}`
237
+ );
238
+ }
239
+ }
240
+ const resolvedPath = path.resolve(trimmedSource);
241
+ if (await fs.pathExists(resolvedPath)) {
242
+ try {
243
+ const data = await fs.readJson(resolvedPath);
244
+ return data;
245
+ } catch (error) {
246
+ throw new Error(
247
+ `Failed to parse ${paramName} from file ${trimmedSource}: ${getErrorMessage(error)}`
248
+ );
249
+ }
250
+ }
251
+ try {
252
+ const parsed = JSON.parse(trimmedSource);
253
+ return parsed;
254
+ } catch (jsonError) {
255
+ if (!trimmedSource.startsWith("{") && !trimmedSource.startsWith("[")) {
256
+ return { name: trimmedSource };
257
+ }
258
+ throw new Error(
259
+ `Failed to parse ${paramName}. Input appears to be JSON but contains errors: ${jsonError instanceof Error ? jsonError.message : String(jsonError)}`
260
+ );
261
+ }
262
+ }
203
263
 
204
264
  // src/core/docker.ts
205
265
  function readPackageVersion() {
@@ -218,6 +278,13 @@ function readPackageVersion() {
218
278
  var CLI_VERSION = readPackageVersion();
219
279
  var CLI_DOCKER_IMAGE = process.env.WALKEROS_CLI_DOCKER_IMAGE || `walkeros/cli:${CLI_VERSION}`;
220
280
  var RUNTIME_DOCKER_IMAGE = process.env.WALKEROS_RUNTIME_DOCKER_IMAGE || `walkeros/docker:${DOCKER_VERSION}`;
281
+ function buildCommonDockerArgs(options) {
282
+ const args = [options.config];
283
+ if (options.json) args.push("--json");
284
+ if (options.verbose) args.push("--verbose");
285
+ if (options.silent) args.push("--silent");
286
+ return args;
287
+ }
221
288
  function buildDockerCommand(command, args, options = {}, configFile) {
222
289
  const cwd = process.cwd();
223
290
  const cmd = ["docker", "run", "--rm"];
@@ -380,6 +447,10 @@ async function executeCommand(localHandler, dockerCommand, dockerArgs, options,
380
447
  }
381
448
  }
382
449
 
450
+ // src/core/temp-manager.ts
451
+ import { getHashServer } from "@walkeros/server-core";
452
+ import fs2 from "fs-extra";
453
+
383
454
  // src/core/asset-resolver.ts
384
455
  import { fileURLToPath as fileURLToPath2 } from "url";
385
456
  import path3 from "path";
@@ -389,6 +460,10 @@ function getPackageRoot() {
389
460
  const srcIndex = currentFile.indexOf("/src/");
390
461
  return currentFile.substring(0, srcIndex);
391
462
  }
463
+ if (currentFile.includes("/dist/")) {
464
+ const distIndex = currentFile.indexOf("/dist/");
465
+ return currentFile.substring(0, distIndex);
466
+ }
392
467
  return path3.resolve(currentFile, "../..");
393
468
  }
394
469
  function resolveAsset(assetPath, assetType, baseDir) {
@@ -406,6 +481,11 @@ function resolveAsset(assetPath, assetType, baseDir) {
406
481
  return path3.resolve(resolveBase, assetPath);
407
482
  }
408
483
 
484
+ // src/core/utils.ts
485
+ function getErrorMessage(error) {
486
+ return error instanceof Error ? error.message : String(error);
487
+ }
488
+
409
489
  // src/config/validators.ts
410
490
  function isObject(value) {
411
491
  return typeof value === "object" && value !== null && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]";
@@ -417,94 +497,79 @@ function isMultiEnvConfig(data) {
417
497
  return isObject(data) && "version" in data && data.version === 1 && "environments" in data && isObject(data.environments);
418
498
  }
419
499
  function isSingleEnvConfig(data) {
420
- return isObject(data) && "flow" in data && "build" in data && isObject(data.flow) && isObject(data.build) && "platform" in data.flow && validatePlatform(data.flow.platform);
500
+ return isObject(data) && "flow" in data && "build" in data && isObject(data.flow) && isObject(data.build) && "platform" in data.flow;
421
501
  }
422
502
 
423
- // src/config/defaults.ts
424
- function getDefaultBuildOptions(platform, code, output) {
425
- const common = {
426
- code,
427
- packages: {},
428
- minify: false,
429
- sourcemap: false,
430
- cache: true
431
- };
432
- if (platform === "web") {
503
+ // src/config/parser.ts
504
+ 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];
433
523
  return {
434
- ...common,
435
- platform: "browser",
436
- format: "iife",
437
- target: "es2020",
438
- output: output || "./dist/walker.js",
439
- globalName: "walkerOS"
524
+ flowConfig: envConfig.flow,
525
+ buildOptions: envConfig.build,
526
+ metadata: {
527
+ environment: selectedEnv,
528
+ isMultiEnvironment: true,
529
+ availableEnvironments
530
+ }
440
531
  };
441
532
  }
442
- return {
443
- ...common,
444
- platform: "node",
445
- format: "esm",
446
- target: "node18",
447
- output: output || "./dist/bundle.js"
448
- };
449
- }
450
- function ensureBuildOptions(buildOptions, flowPlatform) {
451
- const defaults = getDefaultBuildOptions(
452
- flowPlatform,
453
- buildOptions.code || "",
454
- buildOptions.output
455
- );
456
- if (!buildOptions.output && !defaults.output) {
457
- throw new Error("BuildOptions.output is required");
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
+ };
458
543
  }
459
- return {
460
- ...defaults,
461
- ...buildOptions,
462
- code: buildOptions.code || defaults.code || "",
463
- output: buildOptions.output || defaults.output,
464
- packages: buildOptions.packages || defaults.packages
465
- };
466
- }
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}.
467
549
 
468
- // src/config/parser.ts
469
- import path4 from "path";
470
- function parseBundleConfig(data) {
471
- if (!isObject(data)) {
472
- throw new Error(`Invalid config: expected object, got ${typeof data}`);
473
- }
474
- if (!("flow" in data) || !isObject(data.flow)) {
475
- throw new Error(
476
- `Invalid config: missing "flow" field. Expected format: { flow: { platform: "web" | "server", ... }, build: { ... } }`
477
- );
478
- }
479
- if (!("build" in data) || !isObject(data.build)) {
480
- throw new Error(
481
- `Invalid config: missing "build" field. Expected format: { flow: { platform: "web" | "server", ... }, build: { ... } }`
482
- );
483
- }
484
- const flowData = data.flow;
485
- if (!("platform" in flowData) || flowData.platform !== "web" && flowData.platform !== "server") {
486
- throw new Error(
487
- `Invalid config: flow.platform must be "web" or "server", got "${flowData.platform}"`
488
- );
489
- }
490
- const buildData = data.build;
491
- if ("packages" in buildData && !isObject(buildData.packages)) {
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)) {
492
557
  throw new Error(
493
- `Invalid config: build.packages must be an object, got ${typeof buildData.packages}`
558
+ `Invalid flow config: missing "platform" field. Expected "web" or "server".`
494
559
  );
495
560
  }
496
- const config = data;
497
- return normalizeConfigs(config, "/unknown/path");
498
- }
499
- function normalizeConfigs(config, configPath) {
500
- const flowConfig = config.flow;
501
561
  const platform = flowConfig.platform;
502
562
  if (!validatePlatform(platform)) {
503
563
  throw new Error(
504
564
  `Invalid platform "${platform}". Must be "web" or "server".`
505
565
  );
506
566
  }
507
- const buildDefaults = platform === "web" ? {
567
+ if (!isObject(buildOptions)) {
568
+ throw new Error(
569
+ `Invalid build options: expected object, got ${typeof buildOptions}`
570
+ );
571
+ }
572
+ const platformDefaults = platform === "web" ? {
508
573
  platform: "browser",
509
574
  format: "iife",
510
575
  target: "es2020",
@@ -521,43 +586,97 @@ function normalizeConfigs(config, configPath) {
521
586
  tempDir: ".tmp",
522
587
  cache: true
523
588
  };
524
- const buildConfig = {
525
- ...buildDefaults,
526
- ...config.build
589
+ const merged = {
590
+ ...platformDefaults,
591
+ ...buildOptions
527
592
  };
528
- if (buildConfig.template === void 0) {
529
- buildConfig.template = platform === "server" ? "server.hbs" : "web.hbs";
593
+ if (merged.template === void 0) {
594
+ merged.template = platform === "server" ? "server.hbs" : "web.hbs";
530
595
  }
531
- if (configPath && buildConfig.template && !path4.isAbsolute(buildConfig.template)) {
532
- if (buildConfig.template.startsWith("./") || buildConfig.template.startsWith("../")) {
533
- const configDir = path4.dirname(configPath);
534
- buildConfig.template = path4.resolve(configDir, buildConfig.template);
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";
535
602
  }
536
603
  }
537
- const buildOptions = ensureBuildOptions(buildConfig, platform);
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
+ }
538
621
  return {
539
622
  flowConfig,
540
- buildOptions
623
+ buildOptions: merged
541
624
  };
542
625
  }
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
+ );
639
+ }
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
+ );
645
+ }
646
+ return normalizeAndValidate(data.flow, data.build, "/unknown/path");
647
+ }
648
+ function normalizeConfigs(config, configPath) {
649
+ return normalizeAndValidate(config.flow, config.build, configPath);
650
+ }
543
651
 
544
652
  // src/config/loader.ts
545
653
  function loadBundleConfig(rawConfig, options) {
546
- if (isMultiEnvConfig(rawConfig)) {
547
- return loadMultiEnvironmentConfig(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
+ );
548
670
  }
549
- if (isSingleEnvConfig(rawConfig)) {
550
- return loadSingleEnvironmentConfig(rawConfig, options);
671
+ if (!metadata.isMultiEnvironment && options.environment && options.logger) {
672
+ options.logger.warn(
673
+ `--env flag specified but configuration is single-environment. Ignoring flag.`
674
+ );
551
675
  }
552
- const configType = isObject(rawConfig) ? "platform" in rawConfig ? `invalid platform value: "${rawConfig.platform}"` : 'missing "flow" and "build" fields' : `not an object (got ${typeof rawConfig})`;
553
- throw new Error(
554
- `Invalid configuration format at ${options.configPath}.
555
- Configuration ${configType}.
556
-
557
- Expected either:
558
- 1. Multi-environment: { version: 1, environments: { prod: { flow: {...}, build: {...} } } }
559
- 2. Single-environment: { flow: { platform: "web" | "server", ... }, build: { packages: {...}, ... } }`
560
- );
676
+ return {
677
+ ...normalized,
678
+ ...metadata
679
+ };
561
680
  }
562
681
  function loadMultiEnvironmentConfig(setup, options) {
563
682
  const availableEnvironments = Object.keys(setup.environments);
@@ -592,23 +711,6 @@ Available environments: ${availableEnvironments.join(", ")}`
592
711
  availableEnvironments
593
712
  };
594
713
  }
595
- function loadSingleEnvironmentConfig(config, options) {
596
- const { flowConfig, buildOptions } = normalizeConfigs(
597
- config,
598
- options.configPath
599
- );
600
- if (options.logger && options.environment) {
601
- options.logger.warn(
602
- `--env flag specified but configuration is single-environment. Ignoring flag.`
603
- );
604
- }
605
- return {
606
- flowConfig,
607
- buildOptions,
608
- environment: "default",
609
- isMultiEnvironment: false
610
- };
611
- }
612
714
  function loadAllEnvironments(rawConfig, options) {
613
715
  if (!isMultiEnvConfig(rawConfig)) {
614
716
  throw new Error(
@@ -634,12 +736,12 @@ Your configuration appears to be single-environment.`
634
736
  // src/commands/bundle/bundler.ts
635
737
  import esbuild from "esbuild";
636
738
  import path6 from "path";
637
- import fs4 from "fs-extra";
739
+ import fs5 from "fs-extra";
638
740
 
639
741
  // src/commands/bundle/package-manager.ts
640
742
  import pacote from "pacote";
641
743
  import path5 from "path";
642
- import fs2 from "fs-extra";
744
+ import fs3 from "fs-extra";
643
745
  function getPackageDirectory(baseDir, packageName, version) {
644
746
  return path5.join(baseDir, "node_modules", packageName);
645
747
  }
@@ -650,7 +752,7 @@ function getCachedPackagePath(pkg, tempDir) {
650
752
  }
651
753
  async function isPackageCached(pkg, tempDir) {
652
754
  const cachedPath = getCachedPackagePath(pkg, tempDir);
653
- return fs2.pathExists(cachedPath);
755
+ return fs3.pathExists(cachedPath);
654
756
  }
655
757
  function validateNoDuplicatePackages(packages) {
656
758
  const packageMap = /* @__PURE__ */ new Map();
@@ -685,8 +787,8 @@ async function resolveDependencies(pkg, packageDir, logger, visited = /* @__PURE
685
787
  visited.add(pkgKey);
686
788
  try {
687
789
  const packageJsonPath = path5.join(packageDir, "package.json");
688
- if (await fs2.pathExists(packageJsonPath)) {
689
- const packageJson2 = await fs2.readJson(packageJsonPath);
790
+ if (await fs3.pathExists(packageJsonPath)) {
791
+ const packageJson2 = await fs3.readJson(packageJsonPath);
690
792
  const deps = {
691
793
  ...packageJson2.dependencies,
692
794
  ...packageJson2.peerDependencies
@@ -707,7 +809,7 @@ async function downloadPackages(packages, targetDir, logger, useCache = true) {
707
809
  const downloadQueue = [...packages];
708
810
  const processed = /* @__PURE__ */ new Set();
709
811
  validateNoDuplicatePackages(packages);
710
- await fs2.ensureDir(targetDir);
812
+ await fs3.ensureDir(targetDir);
711
813
  while (downloadQueue.length > 0) {
712
814
  const pkg = downloadQueue.shift();
713
815
  const pkgKey = `${pkg.name}@${pkg.version}`;
@@ -721,8 +823,8 @@ async function downloadPackages(packages, targetDir, logger, useCache = true) {
721
823
  if (useCache && await isPackageCached(pkg, targetDir)) {
722
824
  logger.debug(`Using cached ${packageSpec}...`);
723
825
  try {
724
- await fs2.ensureDir(path5.dirname(packageDir));
725
- await fs2.copy(cachedPath, packageDir);
826
+ await fs3.ensureDir(path5.dirname(packageDir));
827
+ await fs3.copy(cachedPath, packageDir);
726
828
  packagePaths.set(pkg.name, packageDir);
727
829
  const deps = await resolveDependencies(pkg, packageDir, logger);
728
830
  for (const dep of deps) {
@@ -740,7 +842,7 @@ async function downloadPackages(packages, targetDir, logger, useCache = true) {
740
842
  }
741
843
  logger.debug(`Downloading ${packageSpec}...`);
742
844
  try {
743
- await fs2.ensureDir(path5.dirname(packageDir));
845
+ await fs3.ensureDir(path5.dirname(packageDir));
744
846
  const cacheDir = process.env.NPM_CACHE_DIR || path5.join(process.cwd(), ".npm-cache");
745
847
  await pacote.extract(packageSpec, packageDir, {
746
848
  // Force npm registry download, prevent workspace resolution
@@ -754,8 +856,8 @@ async function downloadPackages(packages, targetDir, logger, useCache = true) {
754
856
  });
755
857
  if (useCache) {
756
858
  try {
757
- await fs2.ensureDir(path5.dirname(cachedPath));
758
- await fs2.copy(packageDir, cachedPath);
859
+ await fs3.ensureDir(path5.dirname(cachedPath));
860
+ await fs3.copy(packageDir, cachedPath);
759
861
  logger.debug(`Cached ${packageSpec} for future use`);
760
862
  } catch (cacheError) {
761
863
  logger.debug(`Failed to cache ${packageSpec}: ${cacheError}`);
@@ -777,7 +879,7 @@ async function downloadPackages(packages, targetDir, logger, useCache = true) {
777
879
  }
778
880
 
779
881
  // src/commands/bundle/template-engine.ts
780
- import fs3 from "fs-extra";
882
+ import fs4 from "fs-extra";
781
883
  import Handlebars from "handlebars";
782
884
 
783
885
  // src/commands/bundle/serializer.ts
@@ -885,6 +987,7 @@ var TemplateEngine = class {
885
987
  handlebars;
886
988
  constructor() {
887
989
  this.handlebars = Handlebars.create();
990
+ this.handlebars.registerHelper("eq", (a, b) => a === b);
888
991
  }
889
992
  /**
890
993
  * Load template content from file path
@@ -893,10 +996,10 @@ var TemplateEngine = class {
893
996
  */
894
997
  async loadTemplate(templatePath) {
895
998
  const resolvedPath = resolveAsset(templatePath, "template");
896
- if (!await fs3.pathExists(resolvedPath)) {
999
+ if (!await fs4.pathExists(resolvedPath)) {
897
1000
  throw new Error(`Template file not found: ${resolvedPath}`);
898
1001
  }
899
- return await fs3.readFile(resolvedPath, "utf-8");
1002
+ return await fs4.readFile(resolvedPath, "utf-8");
900
1003
  }
901
1004
  /**
902
1005
  * Apply template with user code and variable substitution
@@ -937,7 +1040,7 @@ async function bundleCore(flowConfig, buildOptions, logger, showStats = false) {
937
1040
  const TEMP_DIR = buildOptions.tempDir ? path6.isAbsolute(buildOptions.tempDir) ? buildOptions.tempDir : path6.resolve(buildOptions.tempDir) : getTempDir();
938
1041
  try {
939
1042
  if (!buildOptions.tempDir) {
940
- await fs4.emptyDir(TEMP_DIR);
1043
+ await fs5.emptyDir(TEMP_DIR);
941
1044
  }
942
1045
  logger.debug("Cleaned temporary directory");
943
1046
  logger.info("\u{1F4E5} Downloading packages...");
@@ -956,7 +1059,7 @@ async function bundleCore(flowConfig, buildOptions, logger, showStats = false) {
956
1059
  for (const [pkgName, pkgPath] of packagePaths.entries()) {
957
1060
  if (pkgName.startsWith("@walkeros/")) {
958
1061
  const pkgJsonPath = path6.join(pkgPath, "package.json");
959
- const pkgJson = await fs4.readJSON(pkgJsonPath);
1062
+ const pkgJson = await fs5.readJSON(pkgJsonPath);
960
1063
  if (!pkgJson.exports && pkgJson.module) {
961
1064
  pkgJson.exports = {
962
1065
  ".": {
@@ -964,12 +1067,12 @@ async function bundleCore(flowConfig, buildOptions, logger, showStats = false) {
964
1067
  require: pkgJson.main
965
1068
  }
966
1069
  };
967
- await fs4.writeJSON(pkgJsonPath, pkgJson, { spaces: 2 });
1070
+ await fs5.writeJSON(pkgJsonPath, pkgJson, { spaces: 2 });
968
1071
  }
969
1072
  }
970
1073
  }
971
1074
  const packageJsonPath = path6.join(TEMP_DIR, "package.json");
972
- await fs4.writeFile(
1075
+ await fs5.writeFile(
973
1076
  packageJsonPath,
974
1077
  JSON.stringify({ type: "module" }, null, 2)
975
1078
  );
@@ -980,10 +1083,10 @@ async function bundleCore(flowConfig, buildOptions, logger, showStats = false) {
980
1083
  packagePaths
981
1084
  );
982
1085
  const entryPath = path6.join(TEMP_DIR, "entry.js");
983
- await fs4.writeFile(entryPath, entryContent);
1086
+ await fs5.writeFile(entryPath, entryContent);
984
1087
  logger.info("\u26A1 Bundling with esbuild...");
985
1088
  const outputPath = path6.resolve(buildOptions.output);
986
- await fs4.ensureDir(path6.dirname(outputPath));
1089
+ await fs5.ensureDir(path6.dirname(outputPath));
987
1090
  const esbuildOptions = createEsbuildOptions(
988
1091
  buildOptions,
989
1092
  entryPath,
@@ -1011,20 +1114,20 @@ async function bundleCore(flowConfig, buildOptions, logger, showStats = false) {
1011
1114
  );
1012
1115
  }
1013
1116
  if (!buildOptions.tempDir) {
1014
- await fs4.remove(TEMP_DIR);
1117
+ await fs5.remove(TEMP_DIR);
1015
1118
  logger.debug("Cleaned up temporary files");
1016
1119
  }
1017
1120
  return stats;
1018
1121
  } catch (error) {
1019
1122
  if (!buildOptions.tempDir) {
1020
- await fs4.remove(TEMP_DIR).catch(() => {
1123
+ await fs5.remove(TEMP_DIR).catch(() => {
1021
1124
  });
1022
1125
  }
1023
1126
  throw error;
1024
1127
  }
1025
1128
  }
1026
1129
  async function collectBundleStats(outputPath, packages, startTime, entryContent) {
1027
- const stats = await fs4.stat(outputPath);
1130
+ const stats = await fs5.stat(outputPath);
1028
1131
  const totalSize = stats.size;
1029
1132
  const buildTime = Date.now() - startTime;
1030
1133
  const packageStats = Object.entries(packages).map(([name, pkg]) => {
@@ -1111,9 +1214,6 @@ function createEsbuildOptions(buildOptions, entryPath, outputPath, tempDir, pack
1111
1214
  } else {
1112
1215
  baseOptions.target = "es2018";
1113
1216
  }
1114
- if (buildOptions.globalName && buildOptions.format === "iife") {
1115
- baseOptions.globalName = buildOptions.globalName;
1116
- }
1117
1217
  return baseOptions;
1118
1218
  }
1119
1219
  function packageNameToVariable(packageName) {
@@ -1121,9 +1221,7 @@ function packageNameToVariable(packageName) {
1121
1221
  (part, i) => i === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)
1122
1222
  ).join("");
1123
1223
  }
1124
- async function createEntryPoint(flowConfig, buildOptions, packagePaths) {
1125
- const importStatements = [];
1126
- const examplesMappings = [];
1224
+ function detectDestinationPackages(flowConfig) {
1127
1225
  const destinationPackages = /* @__PURE__ */ new Set();
1128
1226
  const destinations = flowConfig.destinations;
1129
1227
  if (destinations) {
@@ -1133,9 +1231,12 @@ async function createEntryPoint(flowConfig, buildOptions, packagePaths) {
1133
1231
  }
1134
1232
  }
1135
1233
  }
1136
- for (const [packageName, packageConfig] of Object.entries(
1137
- buildOptions.packages
1138
- )) {
1234
+ return destinationPackages;
1235
+ }
1236
+ function generateImportStatements(packages, destinationPackages) {
1237
+ const importStatements = [];
1238
+ const examplesMappings = [];
1239
+ for (const [packageName, packageConfig] of Object.entries(packages)) {
1139
1240
  if (packageConfig.imports && packageConfig.imports.length > 0) {
1140
1241
  const uniqueImports = [...new Set(packageConfig.imports)];
1141
1242
  const defaultImports = [];
@@ -1181,38 +1282,14 @@ async function createEntryPoint(flowConfig, buildOptions, packagePaths) {
1181
1282
  `import * as ${varName} from '${packageName}'; // Consider specifying explicit imports`
1182
1283
  );
1183
1284
  }
1184
- if (destinationPackages.has(packageName)) {
1185
- const destinationMatch = packageName.match(
1186
- /@walkeros\/(?:(?:web|server)-)?destination-(.+)$/
1187
- );
1188
- if (destinationMatch) {
1189
- const destinationName = destinationMatch[1];
1190
- const examplesVarName = `${destinationName.replace(/-/g, "_")}_examples`;
1191
- const isDemoPackage = packageName.includes("-demo");
1192
- if (isDemoPackage) {
1193
- importStatements.push(
1194
- `import { examples as ${examplesVarName} } from '${packageName}';`
1195
- );
1196
- } else {
1197
- importStatements.push(
1198
- `import * as ${examplesVarName} from '${packageName}/examples';`
1199
- );
1200
- }
1201
- examplesMappings.push(` ${destinationName}: ${examplesVarName}`);
1202
- }
1203
- }
1204
1285
  }
1205
- const examplesObject = examplesMappings.length > 0 ? `const examples = {
1206
- ${examplesMappings.join(",\n")}
1207
- };
1208
-
1209
- ` : "";
1210
- const importsCode = importStatements.join("\n");
1211
- let templatedCode;
1286
+ return { importStatements, examplesMappings };
1287
+ }
1288
+ async function processTemplate(flowConfig, buildOptions) {
1212
1289
  if (buildOptions.template) {
1213
1290
  const templateEngine = new TemplateEngine();
1214
1291
  const flowWithProps = flowConfig;
1215
- templatedCode = await templateEngine.process(
1292
+ return await templateEngine.process(
1216
1293
  buildOptions.template,
1217
1294
  buildOptions.code || "",
1218
1295
  // Pass user code as parameter (empty if undefined)
@@ -1223,27 +1300,53 @@ ${examplesMappings.join(",\n")}
1223
1300
  // Pass build config to template
1224
1301
  );
1225
1302
  } else {
1226
- templatedCode = buildOptions.code || "";
1303
+ return buildOptions.code || "";
1227
1304
  }
1228
- let wrappedCode = templatedCode;
1229
- const hasExport = /^\s*export\s/m.test(templatedCode);
1230
- if (!hasExport) {
1231
- if (buildOptions.format === "esm") {
1232
- wrappedCode = `export default ${templatedCode}`;
1233
- } else if (buildOptions.platform === "browser" && buildOptions.globalName) {
1234
- wrappedCode = `window['${buildOptions.globalName}'] = ${templatedCode}`;
1305
+ }
1306
+ function wrapCodeForFormat(code, format, hasTemplate) {
1307
+ if (hasTemplate) {
1308
+ return code;
1309
+ }
1310
+ if (format === "esm") {
1311
+ const hasExport = /^\s*export\s/m.test(code);
1312
+ if (!hasExport) {
1313
+ return `export default ${code}`;
1235
1314
  }
1236
1315
  }
1316
+ return code;
1317
+ }
1318
+ function assembleFinalCode(importStatements, examplesObject, wrappedCode, format) {
1319
+ const importsCode = importStatements.join("\n");
1237
1320
  let finalCode = importsCode ? `${importsCode}
1238
1321
 
1239
1322
  ${examplesObject}${wrappedCode}` : `${examplesObject}${wrappedCode}`;
1240
- if (examplesObject && buildOptions.format === "esm") {
1323
+ if (examplesObject && format === "esm") {
1241
1324
  finalCode += `
1242
1325
 
1243
1326
  export { examples };`;
1244
1327
  }
1245
1328
  return finalCode;
1246
1329
  }
1330
+ async function createEntryPoint(flowConfig, buildOptions, packagePaths) {
1331
+ const destinationPackages = detectDestinationPackages(flowConfig);
1332
+ const { importStatements } = generateImportStatements(
1333
+ buildOptions.packages,
1334
+ destinationPackages
1335
+ );
1336
+ const examplesObject = "";
1337
+ const templatedCode = await processTemplate(flowConfig, buildOptions);
1338
+ const wrappedCode = wrapCodeForFormat(
1339
+ templatedCode,
1340
+ buildOptions.format,
1341
+ !!buildOptions.template
1342
+ );
1343
+ return assembleFinalCode(
1344
+ importStatements,
1345
+ examplesObject,
1346
+ wrappedCode,
1347
+ buildOptions.format
1348
+ );
1349
+ }
1247
1350
  function createBuildError(buildError, code) {
1248
1351
  if (!buildError.errors || buildError.errors.length === 0) {
1249
1352
  return new Error(`Build failed: ${buildError.message || buildError}`);
@@ -1295,19 +1398,12 @@ Package Breakdown:`);
1295
1398
  async function bundleCommand(options) {
1296
1399
  const timer = createTimer();
1297
1400
  timer.start();
1298
- const logger = createLogger({
1299
- verbose: options.verbose,
1300
- silent: options.silent ?? false,
1301
- json: options.json
1302
- });
1303
- const dockerArgs = [options.config];
1401
+ const logger = createCommandLogger(options);
1402
+ const dockerArgs = buildCommonDockerArgs(options);
1304
1403
  if (options.env) dockerArgs.push("--env", options.env);
1305
1404
  if (options.all) dockerArgs.push("--all");
1306
1405
  if (options.stats) dockerArgs.push("--stats");
1307
- if (options.json) dockerArgs.push("--json");
1308
1406
  if (options.cache === false) dockerArgs.push("--no-cache");
1309
- if (options.verbose) dockerArgs.push("--verbose");
1310
- if (options.silent) dockerArgs.push("--silent");
1311
1407
  await executeCommand(
1312
1408
  async () => {
1313
1409
  try {
@@ -1357,7 +1453,7 @@ async function bundleCommand(options) {
1357
1453
  displayStats(stats, logger);
1358
1454
  }
1359
1455
  } catch (error) {
1360
- const errorMessage = error instanceof Error ? error.message : String(error);
1456
+ const errorMessage = getErrorMessage(error);
1361
1457
  results.push({
1362
1458
  environment,
1363
1459
  success: false,
@@ -1409,7 +1505,7 @@ async function bundleCommand(options) {
1409
1505
  }
1410
1506
  } catch (error) {
1411
1507
  const duration = timer.getElapsed() / 1e3;
1412
- const errorMessage = error instanceof Error ? error.message : String(error);
1508
+ const errorMessage = getErrorMessage(error);
1413
1509
  if (options.json) {
1414
1510
  const outputLogger = createLogger({ silent: false, json: false });
1415
1511
  const output = createErrorOutput(errorMessage, duration);
@@ -1439,10 +1535,7 @@ async function bundle(configOrPath, options = {}) {
1439
1535
  if (options.cache !== void 0) {
1440
1536
  buildOptions.cache = options.cache;
1441
1537
  }
1442
- const logger = createLogger({
1443
- silent: options.silent ?? false,
1444
- verbose: options.verbose ?? false
1445
- });
1538
+ const logger = createCommandLogger(options);
1446
1539
  return await bundleCore(
1447
1540
  flowConfig,
1448
1541
  buildOptions,
@@ -1453,7 +1546,7 @@ async function bundle(configOrPath, options = {}) {
1453
1546
 
1454
1547
  // src/commands/simulate/simulator.ts
1455
1548
  import path7 from "path";
1456
- import fs5 from "fs-extra";
1549
+ import fs7 from "fs-extra";
1457
1550
 
1458
1551
  // src/commands/simulate/tracker.ts
1459
1552
  var CallTracker = class {
@@ -1489,9 +1582,9 @@ var CallTracker = class {
1489
1582
  }
1490
1583
  for (const fullPath of paths) {
1491
1584
  const [destKey, ...pathParts] = fullPath.split(":");
1492
- const path9 = pathParts.join(":");
1493
- if (!path9) continue;
1494
- const cleanPath = path9.replace(/^call:/, "");
1585
+ const path11 = pathParts.join(":");
1586
+ if (!path11) continue;
1587
+ const cleanPath = path11.replace(/^call:/, "");
1495
1588
  const parts = cleanPath.split(".");
1496
1589
  let current = wrapped;
1497
1590
  let source = env;
@@ -1533,6 +1626,146 @@ var CallTracker = class {
1533
1626
  }
1534
1627
  };
1535
1628
 
1629
+ // src/commands/simulate/jsdom-executor.ts
1630
+ import { JSDOM, VirtualConsole } from "jsdom";
1631
+ import fs6 from "fs-extra";
1632
+ function buildSandboxFromEnvs(envs, destinations, tracker) {
1633
+ const baseBrowserMocks = {
1634
+ Image: class MockImage {
1635
+ src = "";
1636
+ onload = (() => {
1637
+ });
1638
+ onerror = (() => {
1639
+ });
1640
+ },
1641
+ fetch: async () => ({ ok: true, json: async () => ({}) }),
1642
+ location: { href: "http://localhost" },
1643
+ navigator: { userAgent: "Mozilla/5.0 (walkerOS Simulation)" }
1644
+ };
1645
+ const sandbox = {
1646
+ window: { ...baseBrowserMocks },
1647
+ document: {}
1648
+ };
1649
+ for (const [destKey, destConfig] of Object.entries(destinations)) {
1650
+ const destEnv = envs[destKey];
1651
+ if (!destEnv?.push) continue;
1652
+ const mockEnv = destEnv.push;
1653
+ const trackPaths = destEnv.simulation || [];
1654
+ const trackedEnv = tracker.wrapEnv(
1655
+ mockEnv,
1656
+ trackPaths.map((p) => `${destKey}:${p}`)
1657
+ );
1658
+ if (trackedEnv.window && typeof trackedEnv.window === "object") {
1659
+ Object.assign(sandbox.window, trackedEnv.window);
1660
+ }
1661
+ if (trackedEnv.document && typeof trackedEnv.document === "object") {
1662
+ Object.assign(sandbox.document, trackedEnv.document);
1663
+ }
1664
+ }
1665
+ return sandbox;
1666
+ }
1667
+ function waitForWindowProperty(window, prop, timeout = 5e3) {
1668
+ return new Promise((resolve, reject) => {
1669
+ const start = Date.now();
1670
+ const check = () => {
1671
+ if (window[prop] !== void 0) {
1672
+ resolve();
1673
+ } else if (Date.now() - start > timeout) {
1674
+ reject(
1675
+ new Error(
1676
+ `Timeout waiting for window.${prop}. IIFE may have failed to execute or assign to window.`
1677
+ )
1678
+ );
1679
+ } else {
1680
+ setImmediate(check);
1681
+ }
1682
+ };
1683
+ check();
1684
+ });
1685
+ }
1686
+ async function executeInJSDOM(bundlePath, destinations, event, tracker, envs, timeout = 1e4) {
1687
+ const start = Date.now();
1688
+ const virtualConsole = new VirtualConsole();
1689
+ const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>", {
1690
+ url: "http://localhost",
1691
+ runScripts: "dangerously",
1692
+ // Allow script execution
1693
+ resources: "usable",
1694
+ virtualConsole
1695
+ });
1696
+ const { window } = dom;
1697
+ const sandbox = buildSandboxFromEnvs(envs, destinations, tracker);
1698
+ Object.assign(window, sandbox.window);
1699
+ Object.assign(window.document, sandbox.document);
1700
+ const bundleCode = await fs6.readFile(bundlePath, "utf8");
1701
+ try {
1702
+ window.eval(bundleCode);
1703
+ } catch (error) {
1704
+ throw new Error(`Bundle execution failed: ${getErrorMessage(error)}`);
1705
+ }
1706
+ try {
1707
+ await waitForWindowProperty(
1708
+ window,
1709
+ "collector",
1710
+ timeout
1711
+ );
1712
+ await waitForWindowProperty(
1713
+ window,
1714
+ "elb",
1715
+ timeout
1716
+ );
1717
+ } catch (error) {
1718
+ throw new Error(
1719
+ `Window property assignment failed: ${getErrorMessage(error)}`
1720
+ );
1721
+ }
1722
+ const { collector, elb } = window;
1723
+ let elbResult;
1724
+ try {
1725
+ elbResult = await elb(event.name, event.data);
1726
+ } catch (error) {
1727
+ throw new Error(`Event execution failed: ${getErrorMessage(error)}`);
1728
+ }
1729
+ return {
1730
+ collector,
1731
+ elb,
1732
+ elbResult,
1733
+ usage: tracker.getCalls(),
1734
+ duration: Date.now() - start
1735
+ };
1736
+ }
1737
+
1738
+ // src/commands/simulate/env-loader.ts
1739
+ async function loadDestinationEnvs(destinations) {
1740
+ const envs = {};
1741
+ for (const [destKey, destConfig] of Object.entries(destinations)) {
1742
+ const typedConfig = destConfig;
1743
+ if (!typedConfig.package) {
1744
+ continue;
1745
+ }
1746
+ try {
1747
+ const packageName = typedConfig.package;
1748
+ const isDemoPackage = packageName.includes("-demo");
1749
+ const importPath = isDemoPackage ? packageName : `${packageName}/dev`;
1750
+ const module = await import(importPath);
1751
+ const examplesModule = module.examples || module.default?.examples;
1752
+ const envModule = examplesModule?.env;
1753
+ if (envModule?.push) {
1754
+ envs[destKey] = {
1755
+ init: envModule.init,
1756
+ push: envModule.push,
1757
+ simulation: envModule.simulation || []
1758
+ };
1759
+ }
1760
+ } catch (error) {
1761
+ console.warn(
1762
+ `Warning: Could not load env for destination "${destKey}": ${error instanceof Error ? error.message : String(error)}`
1763
+ );
1764
+ }
1765
+ }
1766
+ return envs;
1767
+ }
1768
+
1536
1769
  // src/commands/simulate/simulator.ts
1537
1770
  function generateId() {
1538
1771
  return `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
@@ -1558,7 +1791,7 @@ async function simulateCore(configPath, event, options = {}) {
1558
1791
  }
1559
1792
  return result;
1560
1793
  } catch (error) {
1561
- const errorMessage = error instanceof Error ? error.message : String(error);
1794
+ const errorMessage = getErrorMessage(error);
1562
1795
  logger.error(`\u{1F4A5} Simulation error: ${errorMessage}`);
1563
1796
  return {
1564
1797
  success: false,
@@ -1566,17 +1799,6 @@ async function simulateCore(configPath, event, options = {}) {
1566
1799
  };
1567
1800
  }
1568
1801
  }
1569
- function parseEventInput(eventString = "") {
1570
- if (!eventString) {
1571
- return {};
1572
- }
1573
- try {
1574
- const parsed = JSON.parse(eventString);
1575
- return isObject(parsed) ? parsed : {};
1576
- } catch {
1577
- return { name: eventString };
1578
- }
1579
- }
1580
1802
  function formatSimulationResult(result, options = {}) {
1581
1803
  if (options.json) {
1582
1804
  const output = {
@@ -1597,7 +1819,13 @@ async function executeSimulation(event, configPath) {
1597
1819
  let bundlePath;
1598
1820
  const tempDir = getTempDir();
1599
1821
  try {
1600
- await fs5.ensureDir(tempDir);
1822
+ if (!isObject(event) || !("name" in event) || typeof event.name !== "string") {
1823
+ throw new Error(
1824
+ 'Event must be an object with a "name" property of type string'
1825
+ );
1826
+ }
1827
+ const typedEvent = event;
1828
+ await fs7.ensureDir(tempDir);
1601
1829
  const rawConfig = await loadJsonConfig(configPath);
1602
1830
  const { flowConfig, buildOptions } = parseBundleConfig(rawConfig);
1603
1831
  const packagesArray = Object.entries(buildOptions.packages).map(
@@ -1614,46 +1842,25 @@ async function executeSimulation(event, configPath) {
1614
1842
  buildOptions.cache
1615
1843
  );
1616
1844
  const tracker = new CallTracker();
1617
- const envSetupCode = [];
1618
- const destinations = flowConfig.destinations;
1619
- if (destinations) {
1620
- for (const [key, dest] of Object.entries(destinations)) {
1621
- const destName = key.replace(/-/g, "_");
1622
- envSetupCode.push(`
1623
- // Inject tracked env for destination '${key}' using examples from bundle
1624
- if (examples && examples['${key}'] && examples['${key}'].env) {
1625
- const mockEnv = examples['${key}'].env.push;
1626
- const trackPaths = examples['${key}'].env.simulation || [];
1627
- if (mockEnv) {
1628
- const wrappedPaths = trackPaths.map((p) => '${key}:' + p);
1629
- const trackedEnv = __simulationTracker.wrapEnv(mockEnv, wrappedPaths);
1630
- if (config.destinations && config.destinations['${key}']) {
1631
- config.destinations['${key}'].env = trackedEnv;
1632
- }
1633
- }
1634
- }
1635
- `);
1636
- }
1637
- }
1638
- const modifiedCode = `
1639
- // Inject tracked envs into destination configs
1640
- ${envSetupCode.join("\n")}
1641
-
1642
- ${buildOptions.code || ""}
1643
- `;
1644
1845
  const tempOutput = path7.join(
1645
1846
  tempDir,
1646
- `simulation-bundle-${generateId()}.mjs`
1847
+ `simulation-bundle-${generateId()}.js`
1647
1848
  );
1849
+ const destinations = flowConfig.destinations;
1648
1850
  const simulationBuildOptions = {
1649
1851
  ...buildOptions,
1650
- code: modifiedCode,
1852
+ code: buildOptions.code || "",
1853
+ // No code modification - use original
1651
1854
  output: tempOutput,
1652
1855
  tempDir,
1653
1856
  // Use same temp dir for bundle
1654
- format: "esm",
1655
- // Force node platform for simulation since we're running in Node.js
1656
- platform: "node"
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"
1657
1864
  };
1658
1865
  await bundleCore(
1659
1866
  flowConfig,
@@ -1662,40 +1869,19 @@ ${buildOptions.code || ""}
1662
1869
  false
1663
1870
  );
1664
1871
  bundlePath = tempOutput;
1665
- const globalWithSim = globalThis;
1666
- if (!globalWithSim.window) {
1667
- globalWithSim.window = {};
1668
- }
1669
- if (!globalWithSim.document) {
1670
- globalWithSim.document = {};
1671
- }
1672
- const timestamp = Date.now();
1673
- const moduleUrl = `file://${bundlePath}?t=${timestamp}`;
1674
- const module = await import(moduleUrl);
1675
- const importedExamples = module.examples;
1676
- const destinations2 = flowConfig.destinations;
1677
- if (importedExamples && destinations2) {
1678
- for (const [key, dest] of Object.entries(destinations2)) {
1679
- const destEnv = importedExamples[key]?.env?.push;
1680
- if (destEnv) {
1681
- if (destEnv.window && typeof globalWithSim.window === "object" && globalWithSim.window !== null) {
1682
- Object.assign(globalWithSim.window, destEnv.window);
1683
- }
1684
- if (destEnv.document && typeof globalWithSim.document === "object" && globalWithSim.document !== null) {
1685
- Object.assign(globalWithSim.document, destEnv.document);
1686
- }
1687
- }
1688
- }
1689
- }
1690
- const flowResult = await module.default({ tracker });
1691
- if (!flowResult || typeof flowResult.elb !== "function") {
1692
- throw new Error(
1693
- "Bundle did not export valid flow object with elb function"
1694
- );
1695
- }
1696
- const { elb } = flowResult;
1697
- const elbResult = await elb(event);
1698
- const usage = tracker.getCalls();
1872
+ 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
+ );
1883
+ const elbResult = result.elbResult;
1884
+ const usage = result.usage;
1699
1885
  const duration = Date.now() - startTime;
1700
1886
  return {
1701
1887
  success: true,
@@ -1708,37 +1894,29 @@ ${buildOptions.code || ""}
1708
1894
  const duration = Date.now() - startTime;
1709
1895
  return {
1710
1896
  success: false,
1711
- error: error instanceof Error ? error.message : String(error),
1897
+ error: getErrorMessage(error),
1712
1898
  duration
1713
1899
  };
1714
1900
  } finally {
1715
1901
  if (tempDir) {
1716
- await fs5.remove(tempDir).catch(() => {
1902
+ await fs7.remove(tempDir).catch(() => {
1717
1903
  });
1718
1904
  }
1719
- const globalWithSim = globalThis;
1720
- delete globalWithSim.window;
1721
- delete globalWithSim.document;
1722
1905
  }
1723
1906
  }
1724
1907
 
1725
1908
  // src/commands/simulate/index.ts
1726
1909
  async function simulateCommand(options) {
1727
- const logger = createLogger({
1728
- verbose: options.verbose,
1729
- silent: options.silent ?? false,
1730
- json: options.json
1731
- });
1732
- const dockerArgs = [options.config];
1910
+ const logger = createCommandLogger(options);
1911
+ const dockerArgs = buildCommonDockerArgs(options);
1733
1912
  if (options.event) dockerArgs.push("--event", options.event);
1734
- if (options.json) dockerArgs.push("--json");
1735
- if (options.verbose) dockerArgs.push("--verbose");
1736
- if (options.silent) dockerArgs.push("--silent");
1737
1913
  await executeCommand(
1738
1914
  async () => {
1739
1915
  const startTime = Date.now();
1740
1916
  try {
1741
- const event = parseEventInput(options.event);
1917
+ const event = await loadJsonFromSource(options.event, {
1918
+ name: "event"
1919
+ });
1742
1920
  const result = await simulateCore(options.config, event, {
1743
1921
  json: options.json,
1744
1922
  verbose: options.verbose,
@@ -1757,7 +1935,7 @@ async function simulateCommand(options) {
1757
1935
  process.exit(1);
1758
1936
  }
1759
1937
  } catch (error) {
1760
- const errorMessage = error instanceof Error ? error.message : String(error);
1938
+ const errorMessage = getErrorMessage(error);
1761
1939
  if (options.json) {
1762
1940
  const outputLogger = createLogger({ silent: false, json: false });
1763
1941
  const errorOutput = JSON.stringify(
@@ -1796,13 +1974,249 @@ async function simulate(configOrPath, event, options = {}) {
1796
1974
  });
1797
1975
  }
1798
1976
 
1799
- // src/commands/run/index.ts
1977
+ // src/commands/push/index.ts
1800
1978
  import path8 from "path";
1801
1979
  import os2 from "os";
1802
- import {
1803
- runFlow,
1804
- runServeMode
1805
- } from "@walkeros/docker";
1980
+ import { JSDOM as JSDOM2, VirtualConsole as VirtualConsole2 } from "jsdom";
1981
+ import fs8 from "fs-extra";
1982
+ async function pushCommand(options) {
1983
+ const logger = createCommandLogger(options);
1984
+ const dockerArgs = buildCommonDockerArgs(options);
1985
+ dockerArgs.push("--event", options.event);
1986
+ if (options.env) dockerArgs.push("--env", options.env);
1987
+ await executeCommand(
1988
+ async () => {
1989
+ const startTime = Date.now();
1990
+ try {
1991
+ logger.info("\u{1F4E5} Loading event...");
1992
+ const event = await loadJsonFromSource(options.event, {
1993
+ name: "event"
1994
+ });
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
+ );
1999
+ }
2000
+ if (!event.name.includes(" ")) {
2001
+ logger.warn(
2002
+ `Event name "${event.name}" should follow "ENTITY ACTION" format (e.g., "page view")`
2003
+ );
2004
+ }
2005
+ logger.info("\u{1F4E6} Loading flow configuration...");
2006
+ const configPath = path8.resolve(options.config);
2007
+ const rawConfig = await loadJsonConfig(configPath);
2008
+ const { flowConfig, buildOptions, environment, isMultiEnvironment } = loadBundleConfig(rawConfig, {
2009
+ configPath: options.config,
2010
+ environment: options.env,
2011
+ logger
2012
+ });
2013
+ const platform = flowConfig.platform;
2014
+ 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"}`
2018
+ );
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
+ }
2031
+ }
2032
+ };
2033
+ await bundle(configWithOutput, {
2034
+ cache: true,
2035
+ verbose: options.verbose,
2036
+ silent: !options.verbose
2037
+ });
2038
+ logger.debug(`Bundle created: ${tempPath}`);
2039
+ let result;
2040
+ if (platform === "web") {
2041
+ logger.info("\u{1F310} Executing in web environment (JSDOM)...");
2042
+ result = await executeWebPush(tempPath, event, logger);
2043
+ } else if (platform === "server") {
2044
+ logger.info("\u{1F5A5}\uFE0F Executing in server environment (Node.js)...");
2045
+ result = await executeServerPush(tempPath, event, logger);
2046
+ } else {
2047
+ throw new Error(`Unsupported platform: ${platform}`);
2048
+ }
2049
+ const duration = Date.now() - startTime;
2050
+ if (options.json) {
2051
+ const outputLogger = createLogger({ silent: false, json: false });
2052
+ outputLogger.log(
2053
+ "white",
2054
+ JSON.stringify(
2055
+ {
2056
+ success: result.success,
2057
+ event: result.elbResult,
2058
+ duration
2059
+ },
2060
+ null,
2061
+ 2
2062
+ )
2063
+ );
2064
+ } else {
2065
+ if (result.success) {
2066
+ logger.success("\u2705 Event pushed successfully");
2067
+ if (result.elbResult && typeof result.elbResult === "object") {
2068
+ const pushResult = result.elbResult;
2069
+ if ("id" in pushResult && pushResult.id) {
2070
+ logger.info(` Event ID: ${pushResult.id}`);
2071
+ }
2072
+ if ("entity" in pushResult && pushResult.entity) {
2073
+ logger.info(` Entity: ${pushResult.entity}`);
2074
+ }
2075
+ if ("action" in pushResult && pushResult.action) {
2076
+ logger.info(` Action: ${pushResult.action}`);
2077
+ }
2078
+ }
2079
+ logger.info(` Duration: ${duration}ms`);
2080
+ } else {
2081
+ logger.error(`\u274C Push failed: ${result.error}`);
2082
+ process.exit(1);
2083
+ }
2084
+ }
2085
+ try {
2086
+ await fs8.remove(tempPath);
2087
+ } catch {
2088
+ }
2089
+ } catch (error) {
2090
+ const duration = Date.now() - startTime;
2091
+ const errorMessage = getErrorMessage(error);
2092
+ if (options.json) {
2093
+ const outputLogger = createLogger({ silent: false, json: false });
2094
+ outputLogger.log(
2095
+ "white",
2096
+ JSON.stringify(
2097
+ {
2098
+ success: false,
2099
+ error: errorMessage,
2100
+ duration
2101
+ },
2102
+ null,
2103
+ 2
2104
+ )
2105
+ );
2106
+ } else {
2107
+ logger.error(`\u274C Push command failed: ${errorMessage}`);
2108
+ }
2109
+ process.exit(1);
2110
+ }
2111
+ },
2112
+ "push",
2113
+ dockerArgs,
2114
+ options,
2115
+ logger,
2116
+ options.config
2117
+ );
2118
+ }
2119
+ async function executeWebPush(bundlePath, event, logger) {
2120
+ const startTime = Date.now();
2121
+ try {
2122
+ const virtualConsole = new VirtualConsole2();
2123
+ const dom = new JSDOM2("<!DOCTYPE html><html><body></body></html>", {
2124
+ url: "http://localhost",
2125
+ runScripts: "dangerously",
2126
+ resources: "usable",
2127
+ virtualConsole
2128
+ });
2129
+ const { window } = dom;
2130
+ logger.debug("Loading bundle...");
2131
+ const bundleCode = await fs8.readFile(bundlePath, "utf8");
2132
+ window.eval(bundleCode);
2133
+ logger.debug("Waiting for elb...");
2134
+ await waitForWindowProperty2(
2135
+ window,
2136
+ "elb",
2137
+ 5e3
2138
+ );
2139
+ const windowObj = window;
2140
+ const elb = windowObj.elb;
2141
+ logger.info(`Pushing event: ${event.name}`);
2142
+ const eventData = event.data || {};
2143
+ const elbResult = await elb(event.name, eventData);
2144
+ return {
2145
+ success: true,
2146
+ elbResult,
2147
+ duration: Date.now() - startTime
2148
+ };
2149
+ } catch (error) {
2150
+ return {
2151
+ success: false,
2152
+ duration: Date.now() - startTime,
2153
+ error: getErrorMessage(error)
2154
+ };
2155
+ }
2156
+ }
2157
+ async function executeServerPush(bundlePath, event, logger, timeout = 6e4) {
2158
+ const startTime = Date.now();
2159
+ try {
2160
+ const timeoutPromise = new Promise((_, reject) => {
2161
+ setTimeout(
2162
+ () => reject(new Error(`Server push timeout after ${timeout}ms`)),
2163
+ timeout
2164
+ );
2165
+ });
2166
+ const executePromise = (async () => {
2167
+ logger.debug("Importing bundle...");
2168
+ const flowModule = await import(bundlePath);
2169
+ if (!flowModule.default || typeof flowModule.default !== "function") {
2170
+ throw new Error("Bundle does not export default factory function");
2171
+ }
2172
+ logger.debug("Calling factory function...");
2173
+ const result = await flowModule.default();
2174
+ if (!result || !result.elb || typeof result.elb !== "function") {
2175
+ throw new Error(
2176
+ "Factory function did not return valid result with elb"
2177
+ );
2178
+ }
2179
+ const { elb } = result;
2180
+ logger.info(`Pushing event: ${event.name}`);
2181
+ const eventData = event.data || {};
2182
+ const elbResult = await elb(event.name, eventData);
2183
+ return {
2184
+ success: true,
2185
+ elbResult,
2186
+ duration: Date.now() - startTime
2187
+ };
2188
+ })();
2189
+ return await Promise.race([executePromise, timeoutPromise]);
2190
+ } catch (error) {
2191
+ return {
2192
+ success: false,
2193
+ duration: Date.now() - startTime,
2194
+ error: getErrorMessage(error)
2195
+ };
2196
+ }
2197
+ }
2198
+ function waitForWindowProperty2(window, prop, timeout = 5e3) {
2199
+ return new Promise((resolve, reject) => {
2200
+ const start = Date.now();
2201
+ const check = () => {
2202
+ if (window[prop] !== void 0) {
2203
+ resolve();
2204
+ } else if (Date.now() - start > timeout) {
2205
+ reject(
2206
+ new Error(
2207
+ `Timeout waiting for window.${prop}. IIFE may have failed to execute.`
2208
+ )
2209
+ );
2210
+ } else {
2211
+ setImmediate(check);
2212
+ }
2213
+ };
2214
+ check();
2215
+ });
2216
+ }
2217
+
2218
+ // src/commands/run/index.ts
2219
+ import path10 from "path";
1806
2220
 
1807
2221
  // src/commands/run/validators.ts
1808
2222
  import { existsSync } from "fs";
@@ -1837,58 +2251,108 @@ function validatePort(port) {
1837
2251
  }
1838
2252
  }
1839
2253
 
2254
+ // src/commands/run/utils.ts
2255
+ import path9 from "path";
2256
+ import os3 from "os";
2257
+ 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`
2262
+ );
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, {
2272
+ cache: true,
2273
+ verbose: options.verbose,
2274
+ silent: options.silent
2275
+ });
2276
+ return tempPath;
2277
+ }
2278
+ function isPreBuiltConfig(configPath) {
2279
+ return configPath.endsWith(".mjs") || configPath.endsWith(".js") || configPath.endsWith(".cjs");
2280
+ }
2281
+
2282
+ // src/commands/run/execution.ts
2283
+ import { runFlow, runServeMode } from "@walkeros/docker";
2284
+ async function executeRunLocal(mode, flowPath, options) {
2285
+ switch (mode) {
2286
+ case "collect": {
2287
+ if (!flowPath) {
2288
+ throw new Error("Flow path is required for collect mode");
2289
+ }
2290
+ const config = {
2291
+ port: options.port,
2292
+ host: options.host
2293
+ };
2294
+ await runFlow(flowPath, config);
2295
+ break;
2296
+ }
2297
+ case "serve": {
2298
+ const config = {
2299
+ port: options.port,
2300
+ host: options.host,
2301
+ serveName: options.serveName,
2302
+ servePath: options.servePath,
2303
+ filePath: flowPath || void 0
2304
+ };
2305
+ await runServeMode(config);
2306
+ break;
2307
+ }
2308
+ default:
2309
+ throw new Error(`Unknown mode: ${mode}`);
2310
+ }
2311
+ }
2312
+
1840
2313
  // src/commands/run/index.ts
1841
2314
  async function runCommand(mode, options) {
1842
2315
  const timer = createTimer();
1843
2316
  timer.start();
1844
- const logger = createLogger({
1845
- verbose: options.verbose,
1846
- silent: options.silent ?? false,
1847
- json: options.json
1848
- });
2317
+ const logger = createCommandLogger(options);
1849
2318
  try {
1850
2319
  validateMode(mode);
1851
2320
  const configPath = validateFlowFile(options.config);
1852
2321
  if (options.port !== void 0) {
1853
2322
  validatePort(options.port);
1854
2323
  }
1855
- const isPreBuilt = configPath.endsWith(".mjs") || configPath.endsWith(".js") || configPath.endsWith(".cjs");
2324
+ const isPreBuilt = isPreBuiltConfig(configPath);
1856
2325
  let flowPath = null;
1857
2326
  if (mode === "collect") {
1858
2327
  if (isPreBuilt) {
1859
- flowPath = path8.resolve(configPath);
2328
+ flowPath = path10.resolve(configPath);
1860
2329
  if (!options.json && !options.silent) {
1861
- logger.info(`\u{1F4E6} Using pre-built flow: ${path8.basename(flowPath)}`);
2330
+ logger.info(`\u{1F4E6} Using pre-built flow: ${path10.basename(flowPath)}`);
1862
2331
  }
1863
2332
  } else {
1864
2333
  if (!options.json && !options.silent) {
1865
2334
  logger.info("\u{1F528} Building flow bundle...");
1866
2335
  }
1867
- const rawConfig = await loadJsonConfig(configPath);
1868
- const tempPath = path8.join(
1869
- os2.tmpdir(),
1870
- `walkeros-${Date.now()}-${Math.random().toString(36).slice(2, 9)}.mjs`
1871
- );
1872
- const existingBuild = typeof rawConfig === "object" && rawConfig !== null && "build" in rawConfig && typeof rawConfig.build === "object" ? rawConfig.build : {};
1873
- const configWithOutput = {
1874
- ...rawConfig,
1875
- build: {
1876
- ...existingBuild,
1877
- output: tempPath
1878
- }
1879
- };
1880
- await bundle(configWithOutput, {
1881
- cache: true,
2336
+ flowPath = await prepareBundleForRun(configPath, {
1882
2337
  verbose: options.verbose,
1883
2338
  silent: options.json || options.silent
1884
2339
  });
1885
- flowPath = tempPath;
1886
2340
  if (!options.json && !options.silent) {
1887
2341
  logger.success("\u2705 Bundle ready");
1888
2342
  }
1889
2343
  }
1890
2344
  }
1891
2345
  const executionMode = getExecutionMode(options);
2346
+ if (options.dryRun) {
2347
+ if (executionMode === "docker") {
2348
+ logger.info(
2349
+ `[DRY-RUN] Would execute in Docker: run ${mode} with runtime image`
2350
+ );
2351
+ } else {
2352
+ logger.info(`[DRY-RUN] Would execute locally: run ${mode}`);
2353
+ }
2354
+ return;
2355
+ }
1892
2356
  if (executionMode === "docker") {
1893
2357
  const dockerAvailable = await isDockerAvailable();
1894
2358
  if (!dockerAvailable) {
@@ -1911,36 +2375,16 @@ async function runCommand(mode, options) {
1911
2375
  const modeLabel = mode === "collect" ? "Collector" : "Server";
1912
2376
  logger.info(`\u{1F5A5}\uFE0F Starting ${modeLabel} locally...`);
1913
2377
  }
1914
- switch (mode) {
1915
- case "collect": {
1916
- if (!flowPath) {
1917
- throw new Error("Flow path is required for collect mode");
1918
- }
1919
- const config = {
1920
- port: options.port,
1921
- host: options.host
1922
- };
1923
- await runFlow(flowPath, config);
1924
- break;
1925
- }
1926
- case "serve": {
1927
- const config = {
1928
- port: options.port,
1929
- host: options.host,
1930
- serveName: options.serveName,
1931
- servePath: options.servePath,
1932
- filePath: flowPath || void 0
1933
- };
1934
- await runServeMode(config);
1935
- break;
1936
- }
1937
- default:
1938
- throw new Error(`Unknown mode: ${mode}`);
1939
- }
2378
+ await executeRunLocal(mode, flowPath, {
2379
+ port: options.port,
2380
+ host: options.host,
2381
+ serveName: options.serveName,
2382
+ servePath: options.servePath
2383
+ });
1940
2384
  }
1941
2385
  } catch (error) {
1942
2386
  const duration = timer.getElapsed() / 1e3;
1943
- const errorMessage = error instanceof Error ? error.message : String(error);
2387
+ const errorMessage = getErrorMessage(error);
1944
2388
  if (options.json) {
1945
2389
  const output = {
1946
2390
  success: false,
@@ -1969,54 +2413,22 @@ async function run(mode, options) {
1969
2413
  if (options.port !== void 0) {
1970
2414
  validatePort(options.port);
1971
2415
  }
1972
- const isPreBuilt = flowFile.endsWith(".mjs") || flowFile.endsWith(".js") || flowFile.endsWith(".cjs");
2416
+ const isPreBuilt = isPreBuiltConfig(flowFile);
1973
2417
  let flowPath;
1974
2418
  if (isPreBuilt) {
1975
- flowPath = path8.resolve(flowFile);
2419
+ flowPath = path10.resolve(flowFile);
1976
2420
  } else {
1977
- const rawConfig = await loadJsonConfig(flowFile);
1978
- const tempPath = path8.join(
1979
- os2.tmpdir(),
1980
- `walkeros-${Date.now()}-${Math.random().toString(36).slice(2, 9)}.mjs`
1981
- );
1982
- const existingBuild = typeof rawConfig === "object" && rawConfig !== null && "build" in rawConfig && typeof rawConfig.build === "object" ? rawConfig.build : {};
1983
- const configWithOutput = {
1984
- ...rawConfig,
1985
- build: {
1986
- ...existingBuild,
1987
- output: tempPath
1988
- }
1989
- };
1990
- await bundle(configWithOutput, {
1991
- cache: true,
2421
+ flowPath = await prepareBundleForRun(flowFile, {
1992
2422
  verbose: options.verbose,
1993
2423
  silent: true
1994
2424
  });
1995
- flowPath = tempPath;
1996
- }
1997
- switch (mode) {
1998
- case "collect": {
1999
- const config = {
2000
- port: options.port,
2001
- host: options.host
2002
- };
2003
- await runFlow(flowPath, config);
2004
- break;
2005
- }
2006
- case "serve": {
2007
- const config = {
2008
- port: options.port,
2009
- host: options.host,
2010
- serveName: options.serveName,
2011
- servePath: options.servePath,
2012
- filePath: flowPath
2013
- };
2014
- await runServeMode(config);
2015
- break;
2016
- }
2017
- default:
2018
- throw new Error(`Unknown mode: ${mode}`);
2019
2425
  }
2426
+ await executeRunLocal(mode, flowPath, {
2427
+ port: options.port,
2428
+ host: options.host,
2429
+ serveName: options.serveName,
2430
+ servePath: options.servePath
2431
+ });
2020
2432
  return {
2021
2433
  success: true,
2022
2434
  exitCode: 0,
@@ -2027,7 +2439,7 @@ async function run(mode, options) {
2027
2439
  success: false,
2028
2440
  exitCode: 1,
2029
2441
  duration: Date.now() - startTime,
2030
- error: error instanceof Error ? error.message : String(error)
2442
+ error: getErrorMessage(error)
2031
2443
  };
2032
2444
  }
2033
2445
  }
@@ -2058,7 +2470,10 @@ program.command("bundle [file]").description("Bundle NPM packages with custom co
2058
2470
  silent: options.silent
2059
2471
  });
2060
2472
  });
2061
- program.command("simulate [file]").description("Simulate event processing and capture API calls").option("-e, --event <json>", "Event to simulate (JSON string)").option("--json", "Output results as JSON").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) => {
2473
+ program.command("simulate [file]").description("Simulate event processing and capture API calls").option(
2474
+ "-e, --event <source>",
2475
+ "Event to simulate (JSON string, file path, or URL)"
2476
+ ).option("--json", "Output results as JSON").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) => {
2062
2477
  await simulateCommand({
2063
2478
  config: file || "bundle.config.json",
2064
2479
  event: options.event,
@@ -2069,6 +2484,20 @@ program.command("simulate [file]").description("Simulate event processing and ca
2069
2484
  silent: options.silent
2070
2485
  });
2071
2486
  });
2487
+ program.command("push [file]").description("Push an event through the flow with real API execution").requiredOption(
2488
+ "-e, --event <source>",
2489
+ "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) => {
2491
+ await pushCommand({
2492
+ config: file || "bundle.config.json",
2493
+ event: options.event,
2494
+ env: options.env,
2495
+ json: options.json,
2496
+ verbose: options.verbose,
2497
+ silent: options.silent,
2498
+ local: options.local
2499
+ });
2500
+ });
2072
2501
  var runCmd = program.command("run").description("Run walkerOS flows in collect or serve mode");
2073
2502
  runCmd.command("collect [file]").description(
2074
2503
  "Run collector mode (event collection endpoint). Defaults to server-collect.mjs if no file specified."
@@ -2085,10 +2514,10 @@ runCmd.command("collect [file]").description(
2085
2514
  });
2086
2515
  });
2087
2516
  runCmd.command("serve [file]").description(
2088
- "Run serve mode (single-file server for browser bundles). Defaults to baked-in web-serve.mjs if no file specified."
2517
+ "Run serve mode (single-file server for browser bundles). Defaults to baked-in web-serve.js if no file specified."
2089
2518
  ).option("-p, --port <number>", "Port to listen on (default: 8080)", parseInt).option("-h, --host <address>", "Host address (default: 0.0.0.0)").option("--name <filename>", "Filename in URL (default: walker.js)").option("--path <directory>", "URL directory path (e.g., libs/v1)").option("--json", "Output results as JSON").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) => {
2090
2519
  await runCommand("serve", {
2091
- config: file || "web-serve.mjs",
2520
+ config: file || "web-serve.js",
2092
2521
  port: options.port,
2093
2522
  host: options.host,
2094
2523
  serveName: options.name,
@@ -2104,6 +2533,7 @@ program.parse();
2104
2533
  export {
2105
2534
  bundle,
2106
2535
  bundleCommand,
2536
+ pushCommand,
2107
2537
  run,
2108
2538
  runCommand,
2109
2539
  simulate,