@walkeros/cli 1.1.3 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -148,24 +148,108 @@ async function runServeMode(config, logger) {
148
148
  }
149
149
  }
150
150
 
151
+ // src/runtime/resolve-bundle.ts
152
+ import { writeFileSync } from "fs";
153
+
154
+ // src/core/stdin.ts
155
+ function isStdinPiped() {
156
+ return !process.stdin.isTTY;
157
+ }
158
+ async function readStdin() {
159
+ const chunks = [];
160
+ for await (const chunk of process.stdin) {
161
+ chunks.push(chunk);
162
+ }
163
+ const content = Buffer.concat(chunks).toString("utf-8");
164
+ if (!content.trim()) {
165
+ throw new Error("No input received on stdin");
166
+ }
167
+ return content;
168
+ }
169
+
170
+ // src/runtime/resolve-bundle.ts
171
+ var TEMP_BUNDLE_PATH = "/tmp/walkeros-bundle.mjs";
172
+ function isUrl(value) {
173
+ return value.startsWith("http://") || value.startsWith("https://");
174
+ }
175
+ async function fetchBundle(url) {
176
+ const response = await fetch(url, { signal: AbortSignal.timeout(3e4) });
177
+ if (!response.ok) {
178
+ throw new Error(
179
+ `Failed to fetch bundle from ${url}: ${response.status} ${response.statusText}`
180
+ );
181
+ }
182
+ const content = await response.text();
183
+ if (!content.trim()) {
184
+ throw new Error(`Bundle fetched from ${url} is empty`);
185
+ }
186
+ writeFileSync(TEMP_BUNDLE_PATH, content, "utf-8");
187
+ return TEMP_BUNDLE_PATH;
188
+ }
189
+ async function readBundleFromStdin() {
190
+ const content = await readStdin();
191
+ writeFileSync(TEMP_BUNDLE_PATH, content, "utf-8");
192
+ return TEMP_BUNDLE_PATH;
193
+ }
194
+ async function resolveBundle(bundleEnv) {
195
+ if (isStdinPiped()) {
196
+ const path = await readBundleFromStdin();
197
+ return { path, source: "stdin" };
198
+ }
199
+ if (isUrl(bundleEnv)) {
200
+ const path = await fetchBundle(bundleEnv);
201
+ return { path, source: "url" };
202
+ }
203
+ return { path: bundleEnv, source: "file" };
204
+ }
205
+
206
+ // src/runtime/register.ts
207
+ async function registerRuntime(config) {
208
+ const url = `${config.appUrl}/api/projects/${config.projectId}/runtimes/register`;
209
+ const response = await fetch(url, {
210
+ method: "POST",
211
+ headers: {
212
+ Authorization: `Bearer ${config.deployToken}`,
213
+ "Content-Type": "application/json"
214
+ },
215
+ body: JSON.stringify({
216
+ flowId: config.flowId,
217
+ bundlePath: config.bundlePath
218
+ })
219
+ });
220
+ if (!response.ok) {
221
+ throw new Error(
222
+ `Registration failed: ${response.status} ${response.statusText}`
223
+ );
224
+ }
225
+ const data = await response.json();
226
+ return { bundleUrl: data.bundleUrl };
227
+ }
228
+
151
229
  // src/core/logger.ts
152
230
  import chalk from "chalk";
153
231
  var BRAND_COLOR = "#01b5e2";
154
232
  function createLogger(options = {}) {
155
- const { verbose = false, silent = false, json = false } = options;
233
+ const {
234
+ verbose = false,
235
+ silent = false,
236
+ json = false,
237
+ stderr = false
238
+ } = options;
156
239
  const shouldLog = !silent && !json;
157
240
  const shouldDebug = verbose && !silent && !json;
241
+ const out = stderr ? console.error : console.log;
158
242
  return {
159
243
  log: (...args) => {
160
244
  if (shouldLog) {
161
245
  const message = args.map((arg) => String(arg)).join(" ");
162
- console.log(message);
246
+ out(message);
163
247
  }
164
248
  },
165
249
  brand: (...args) => {
166
250
  if (shouldLog) {
167
251
  const message = args.map((arg) => String(arg)).join(" ");
168
- console.log(chalk.hex(BRAND_COLOR)(message));
252
+ out(chalk.hex(BRAND_COLOR)(message));
169
253
  }
170
254
  },
171
255
  error: (...args) => {
@@ -177,43 +261,43 @@ function createLogger(options = {}) {
177
261
  debug: (...args) => {
178
262
  if (shouldDebug) {
179
263
  const message = args.map((arg) => String(arg)).join(" ");
180
- console.log(` ${message}`);
264
+ out(` ${message}`);
181
265
  }
182
266
  },
183
267
  json: (data) => {
184
268
  if (!silent) {
185
- console.log(JSON.stringify(data, null, 2));
269
+ out(JSON.stringify(data, null, 2));
186
270
  }
187
271
  },
188
272
  // Backward-compatible methods (all use default terminal color per design)
189
273
  info: (...args) => {
190
274
  if (shouldLog) {
191
275
  const message = args.map((arg) => String(arg)).join(" ");
192
- console.log(message);
276
+ out(message);
193
277
  }
194
278
  },
195
279
  success: (...args) => {
196
280
  if (shouldLog) {
197
281
  const message = args.map((arg) => String(arg)).join(" ");
198
- console.log(message);
282
+ out(message);
199
283
  }
200
284
  },
201
285
  warning: (...args) => {
202
286
  if (shouldLog) {
203
287
  const message = args.map((arg) => String(arg)).join(" ");
204
- console.log(message);
288
+ out(message);
205
289
  }
206
290
  },
207
291
  warn: (...args) => {
208
292
  if (shouldLog) {
209
293
  const message = args.map((arg) => String(arg)).join(" ");
210
- console.log(message);
294
+ out(message);
211
295
  }
212
296
  },
213
297
  gray: (...args) => {
214
298
  if (shouldLog) {
215
299
  const message = args.map((arg) => String(arg)).join(" ");
216
- console.log(message);
300
+ out(message);
217
301
  }
218
302
  }
219
303
  };
@@ -246,12 +330,50 @@ function adaptLogger(cliLogger) {
246
330
  }
247
331
  async function main() {
248
332
  const mode = process.env.MODE || "collect";
249
- const file = process.env.BUNDLE || "/app/flow/bundle.mjs";
333
+ let bundleEnv = process.env.BUNDLE || "/app/flow/bundle.mjs";
250
334
  const port = parseInt(process.env.PORT || "8080", 10);
251
335
  const cliLogger = createLogger({ silent: false, verbose: true });
252
336
  const logger = adaptLogger(cliLogger);
253
337
  cliLogger.log(`Starting walkeros/flow in ${mode} mode`);
254
- cliLogger.log(`File: ${file}`);
338
+ const appUrl = process.env.APP_URL;
339
+ const deployToken = process.env.DEPLOY_TOKEN;
340
+ const projectId = process.env.PROJECT_ID;
341
+ const flowId = process.env.FLOW_ID;
342
+ const bundlePath = process.env.BUNDLE_PATH;
343
+ if (appUrl && deployToken && projectId && flowId && bundlePath) {
344
+ try {
345
+ cliLogger.log("Registering with app...");
346
+ const result = await registerRuntime({
347
+ appUrl,
348
+ deployToken,
349
+ projectId,
350
+ flowId,
351
+ bundlePath
352
+ });
353
+ bundleEnv = result.bundleUrl;
354
+ cliLogger.log("Registered, bundle URL received");
355
+ } catch (error) {
356
+ const message = error instanceof Error ? error.message : String(error);
357
+ cliLogger.error(`Registration failed: ${message}`);
358
+ process.exit(1);
359
+ }
360
+ }
361
+ let file;
362
+ try {
363
+ const resolved = await resolveBundle(bundleEnv);
364
+ file = resolved.path;
365
+ if (resolved.source === "stdin") {
366
+ cliLogger.log("Bundle: received via stdin pipe");
367
+ } else if (resolved.source === "url") {
368
+ cliLogger.log(`Bundle: fetched from ${bundleEnv}`);
369
+ } else {
370
+ cliLogger.log(`Bundle: ${file}`);
371
+ }
372
+ } catch (error) {
373
+ const message = error instanceof Error ? error.message : String(error);
374
+ cliLogger.error(`Failed to resolve bundle: ${message}`);
375
+ process.exit(1);
376
+ }
255
377
  cliLogger.log(`Port: ${port}`);
256
378
  try {
257
379
  if (mode === "collect") {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/runtime/runner.ts","../../src/runtime/serve.ts","../../src/version.ts","../../src/core/logger.ts","../../src/runtime/main.ts"],"sourcesContent":["/**\n * Runtime executor for pre-built walkerOS flows\n *\n * This module runs pre-built .mjs flow bundles without any build-time operations.\n * All bundling, package downloading, and code generation happens BEFORE this runs.\n */\n\nimport { pathToFileURL } from 'url';\nimport { resolve, dirname } from 'path';\nimport type { Logger } from '@walkeros/core';\n\nexport interface RuntimeConfig {\n port?: number;\n host?: string;\n}\n\n/**\n * Run a pre-built flow bundle\n *\n * @param file - Absolute path to pre-built .mjs flow file\n * @param config - Optional runtime configuration\n * @param logger - Logger instance for output\n * @param loggerConfig - Optional logger config to forward to the flow's collector\n */\nexport async function runFlow(\n file: string,\n config: RuntimeConfig | undefined,\n logger: Logger.Instance,\n loggerConfig?: Logger.Config,\n): Promise<void> {\n logger.info(`Loading flow from ${file}`);\n\n try {\n const absolutePath = resolve(file);\n const flowDir = dirname(absolutePath);\n\n // Change working directory to flow's directory\n // This ensures relative paths (e.g., ./shared/credentials.json) work\n // consistently in both local and Docker execution modes\n process.chdir(flowDir);\n\n const fileUrl = pathToFileURL(absolutePath).href;\n const module = await import(fileUrl);\n\n if (!module.default || typeof module.default !== 'function') {\n logger.throw(\n `Invalid flow bundle: ${file} must export a default function`,\n );\n }\n\n // Execute the flow's factory function with runtime config and logger\n const flowContext = loggerConfig\n ? { ...config, logger: loggerConfig }\n : config;\n const result = await module.default(flowContext);\n\n if (!result || !result.collector) {\n logger.throw(`Invalid flow bundle: ${file} must return { collector }`);\n }\n\n const { collector } = result;\n\n logger.info('Flow running');\n if (config?.port) {\n logger.info(`Port: ${config.port}`);\n }\n\n // Graceful shutdown handler\n const shutdown = async (signal: string) => {\n logger.info(`Received ${signal}, shutting down gracefully...`);\n\n try {\n // Use collector's shutdown command if available\n if (collector.command) {\n await collector.command('shutdown');\n }\n logger.info('Shutdown complete');\n process.exit(0);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`Error during shutdown: ${message}`);\n process.exit(1);\n }\n };\n\n // Register shutdown handlers\n process.on('SIGTERM', () => shutdown('SIGTERM'));\n process.on('SIGINT', () => shutdown('SIGINT'));\n\n // Keep process alive\n await new Promise(() => {});\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`Failed to run flow: ${message}`);\n if (error instanceof Error && error.stack) {\n logger.debug('Stack trace:', { stack: error.stack });\n }\n throw error;\n }\n}\n","/**\n * Serve mode - serve single file (typically generated bundle)\n */\n\nimport express from 'express';\nimport { resolve } from 'path';\nimport type { Logger } from '@walkeros/core';\nimport { VERSION } from '../version';\n\nexport interface ServeConfig {\n port?: number;\n host?: string;\n servePath?: string;\n serveName?: string;\n file?: string;\n}\n\n/**\n * Run serve mode - serve single file (typically generated bundle)\n *\n * @param config - Server configuration\n * @param logger - Logger instance for output\n */\nexport async function runServeMode(\n config: ServeConfig | undefined,\n logger: Logger.Instance,\n): Promise<void> {\n // Port priority: ENV variable > config > default\n const port = process.env.PORT\n ? parseInt(process.env.PORT, 10)\n : config?.port || 8080;\n\n // Host priority: ENV variable > config > default\n const host = process.env.HOST || config?.host || '0.0.0.0';\n\n // Bundle path: ENV variable > config > default (resolve to absolute)\n const file = resolve(\n process.env.BUNDLE || config?.file || './dist/walker.js',\n );\n\n // Serve name (filename in URL): ENV variable > config > default\n const serveName = process.env.SERVE_NAME || config?.serveName || 'walker.js';\n\n // Serve path (URL directory): ENV variable > config > default (empty = root)\n const servePath = process.env.SERVE_PATH || config?.servePath || '';\n\n // Build full URL path\n const urlPath = servePath ? `/${servePath}/${serveName}` : `/${serveName}`;\n\n logger.info('Starting single-file server...');\n logger.info(`File: ${file}`);\n logger.info(`URL: http://${host}:${port}${urlPath}`);\n\n try {\n const app = express();\n\n // Health check\n app.get('/health', (req, res) => {\n res.json({\n status: 'ok',\n version: VERSION,\n timestamp: Date.now(),\n mode: 'serve',\n file: file,\n url: urlPath,\n });\n });\n\n // Serve single file at custom URL path\n app.get(urlPath, (req, res) => {\n // Set content type before streaming\n res.type('application/javascript');\n\n // Allow dotfiles since file paths may include dotfile directories\n res.sendFile(file, { dotfiles: 'allow' }, (err) => {\n if (err && !res.headersSent) {\n const errCode = (err as NodeJS.ErrnoException).code;\n // Express 5 uses HTTP-style errors with status/statusCode\n const errStatus =\n (err as { status?: number; statusCode?: number }).status ||\n (err as { status?: number; statusCode?: number }).statusCode;\n\n // Log errors (except client disconnections)\n if (errCode !== 'ECONNABORTED') {\n logger.error(\n `sendFile error for ${file}: ${err.message} (code: ${errCode}, status: ${errStatus})`,\n );\n }\n\n // Send appropriate error response (check both Node.js codes and HTTP status)\n if (\n errStatus === 404 ||\n errCode === 'ENOENT' ||\n errCode === 'EISDIR' ||\n errCode === 'ENOTDIR'\n ) {\n res.status(404).send('File not found');\n } else if (errCode !== 'ECONNABORTED') {\n res.status(500).send('Internal server error');\n }\n }\n });\n });\n\n // Start server\n const server = app.listen(port, host, () => {\n logger.info(`Server listening on http://${host}:${port}`);\n logger.info(`GET ${urlPath} - Bundle file`);\n logger.info(`GET /health - Health check`);\n });\n\n // Graceful shutdown\n const shutdownHandler = (signal: string) => {\n logger.info(`Received ${signal}, shutting down...`);\n server.close(() => {\n logger.info('Server closed');\n process.exit(0);\n });\n };\n\n process.on('SIGTERM', () => shutdownHandler('SIGTERM'));\n process.on('SIGINT', () => shutdownHandler('SIGINT'));\n\n // Keep process alive\n await new Promise(() => {});\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`Server failed: ${message}`);\n process.exit(1);\n }\n}\n","import { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\n\nconst versionFilename = fileURLToPath(import.meta.url);\nconst versionDirname = dirname(versionFilename);\n\n/**\n * Find package.json in parent directories\n * Handles both source (src/) and bundled (dist/) contexts\n */\nfunction findPackageJson(): string {\n const paths = [\n join(versionDirname, '../package.json'), // dist/ or src/\n join(versionDirname, '../../package.json'), // src/core/ (not used, but safe)\n ];\n for (const p of paths) {\n try {\n return readFileSync(p, 'utf-8');\n } catch {\n // Continue to next path\n }\n }\n return JSON.stringify({ version: '0.0.0' });\n}\n\n/** CLI package version */\nexport const VERSION: string = JSON.parse(findPackageJson()).version;\n","/* eslint-disable no-console */\nimport chalk from 'chalk';\nimport type { GlobalOptions } from '../types/global.js';\n\nconst BRAND_COLOR = '#01b5e2';\n\nexport interface LoggerOptions {\n verbose?: boolean;\n silent?: boolean;\n json?: boolean;\n}\n\nexport interface Logger {\n log: (...args: unknown[]) => void;\n brand: (...args: unknown[]) => void;\n error: (...args: unknown[]) => void;\n debug: (...args: unknown[]) => void;\n json: (data: unknown) => void;\n // Backward-compatible methods (map to default terminal color per design)\n info: (...args: unknown[]) => void;\n success: (...args: unknown[]) => void;\n warning: (...args: unknown[]) => void;\n warn: (...args: unknown[]) => void;\n gray: (...args: unknown[]) => void;\n}\n\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const { verbose = false, silent = false, json = false } = options;\n\n const shouldLog = !silent && !json;\n const shouldDebug = verbose && !silent && !json;\n\n return {\n log: (...args: unknown[]) => {\n if (shouldLog) {\n const message = args.map((arg) => String(arg)).join(' ');\n console.log(message);\n }\n },\n\n brand: (...args: unknown[]) => {\n if (shouldLog) {\n const message = args.map((arg) => String(arg)).join(' ');\n console.log(chalk.hex(BRAND_COLOR)(message));\n }\n },\n\n error: (...args: unknown[]) => {\n if (!json) {\n const message = args.map((arg) => String(arg)).join(' ');\n console.error(chalk.red(message));\n }\n },\n\n debug: (...args: unknown[]) => {\n if (shouldDebug) {\n const message = args.map((arg) => String(arg)).join(' ');\n console.log(` ${message}`);\n }\n },\n\n json: (data: unknown) => {\n if (!silent) {\n console.log(JSON.stringify(data, null, 2));\n }\n },\n\n // Backward-compatible methods (all use default terminal color per design)\n info: (...args: unknown[]) => {\n if (shouldLog) {\n const message = args.map((arg) => String(arg)).join(' ');\n console.log(message);\n }\n },\n\n success: (...args: unknown[]) => {\n if (shouldLog) {\n const message = args.map((arg) => String(arg)).join(' ');\n console.log(message);\n }\n },\n\n warning: (...args: unknown[]) => {\n if (shouldLog) {\n const message = args.map((arg) => String(arg)).join(' ');\n console.log(message);\n }\n },\n\n warn: (...args: unknown[]) => {\n if (shouldLog) {\n const message = args.map((arg) => String(arg)).join(' ');\n console.log(message);\n }\n },\n\n gray: (...args: unknown[]) => {\n if (shouldLog) {\n const message = args.map((arg) => String(arg)).join(' ');\n console.log(message);\n }\n },\n };\n}\n\n/**\n * Create logger from command options\n * Factory function that standardizes logger creation across commands\n *\n * @param options - Command options containing verbose, silent, and json flags\n * @returns Configured logger instance\n */\nexport function createCommandLogger(\n options: GlobalOptions & { json?: boolean },\n): Logger {\n return createLogger({\n verbose: options.verbose,\n silent: options.silent ?? false,\n json: options.json,\n });\n}\n","/**\n * Entry point for walkeros/flow Docker container\n * Reads environment variables and starts the appropriate mode\n */\n\nimport { runFlow } from './runner.js';\nimport { runServeMode } from './serve.js';\nimport { createLogger } from '../core/logger.js';\nimport type { Logger } from '@walkeros/core';\n\n/**\n * Adapt CLI logger to core Logger.Instance interface\n */\nfunction adaptLogger(\n cliLogger: ReturnType<typeof createLogger>,\n): Logger.Instance {\n return {\n error: (message: string | Error) => {\n const msg = message instanceof Error ? message.message : message;\n cliLogger.error(msg);\n },\n info: (message: string | Error) => {\n const msg = message instanceof Error ? message.message : message;\n cliLogger.info(msg);\n },\n debug: (message: string | Error) => {\n const msg = message instanceof Error ? message.message : message;\n cliLogger.debug(msg);\n },\n throw: (message: string | Error): never => {\n const msg = message instanceof Error ? message.message : message;\n cliLogger.error(msg);\n throw message instanceof Error ? message : new Error(msg);\n },\n scope: (name: string) => {\n // Simple pass-through for scoped loggers - CLI logger doesn't use scopes\n return adaptLogger(cliLogger);\n },\n };\n}\n\nasync function main() {\n const mode = process.env.MODE || 'collect';\n const file = process.env.BUNDLE || '/app/flow/bundle.mjs';\n const port = parseInt(process.env.PORT || '8080', 10);\n\n const cliLogger = createLogger({ silent: false, verbose: true });\n const logger = adaptLogger(cliLogger);\n\n cliLogger.log(`Starting walkeros/flow in ${mode} mode`);\n cliLogger.log(`File: ${file}`);\n cliLogger.log(`Port: ${port}`);\n\n try {\n if (mode === 'collect') {\n await runFlow(file, { port }, logger);\n } else if (mode === 'serve') {\n await runServeMode({ file, port }, logger);\n } else {\n cliLogger.error(`Unknown mode: ${mode}. Use 'collect' or 'serve'.`);\n process.exit(1);\n }\n } catch (error) {\n cliLogger.error(`Failed to start: ${error}`);\n process.exit(1);\n }\n}\n\nmain();\n"],"mappings":"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","names":["resolve","dirname","resolve"]}
1
+ {"version":3,"sources":["../../src/runtime/runner.ts","../../src/runtime/serve.ts","../../src/version.ts","../../src/runtime/resolve-bundle.ts","../../src/core/stdin.ts","../../src/runtime/register.ts","../../src/core/logger.ts","../../src/runtime/main.ts"],"sourcesContent":["/**\n * Runtime executor for pre-built walkerOS flows\n *\n * This module runs pre-built .mjs flow bundles without any build-time operations.\n * All bundling, package downloading, and code generation happens BEFORE this runs.\n */\n\nimport { pathToFileURL } from 'url';\nimport { resolve, dirname } from 'path';\nimport type { Logger } from '@walkeros/core';\n\nexport interface RuntimeConfig {\n port?: number;\n host?: string;\n}\n\n/**\n * Run a pre-built flow bundle\n *\n * @param file - Absolute path to pre-built .mjs flow file\n * @param config - Optional runtime configuration\n * @param logger - Logger instance for output\n * @param loggerConfig - Optional logger config to forward to the flow's collector\n */\nexport async function runFlow(\n file: string,\n config: RuntimeConfig | undefined,\n logger: Logger.Instance,\n loggerConfig?: Logger.Config,\n): Promise<void> {\n logger.info(`Loading flow from ${file}`);\n\n try {\n const absolutePath = resolve(file);\n const flowDir = dirname(absolutePath);\n\n // Change working directory to flow's directory\n // This ensures relative paths (e.g., ./shared/credentials.json) work\n // consistently in both local and Docker execution modes\n process.chdir(flowDir);\n\n const fileUrl = pathToFileURL(absolutePath).href;\n const module = await import(fileUrl);\n\n if (!module.default || typeof module.default !== 'function') {\n logger.throw(\n `Invalid flow bundle: ${file} must export a default function`,\n );\n }\n\n // Execute the flow's factory function with runtime config and logger\n const flowContext = loggerConfig\n ? { ...config, logger: loggerConfig }\n : config;\n const result = await module.default(flowContext);\n\n if (!result || !result.collector) {\n logger.throw(`Invalid flow bundle: ${file} must return { collector }`);\n }\n\n const { collector } = result;\n\n logger.info('Flow running');\n if (config?.port) {\n logger.info(`Port: ${config.port}`);\n }\n\n // Graceful shutdown handler\n const shutdown = async (signal: string) => {\n logger.info(`Received ${signal}, shutting down gracefully...`);\n\n try {\n // Use collector's shutdown command if available\n if (collector.command) {\n await collector.command('shutdown');\n }\n logger.info('Shutdown complete');\n process.exit(0);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`Error during shutdown: ${message}`);\n process.exit(1);\n }\n };\n\n // Register shutdown handlers\n process.on('SIGTERM', () => shutdown('SIGTERM'));\n process.on('SIGINT', () => shutdown('SIGINT'));\n\n // Keep process alive\n await new Promise(() => {});\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`Failed to run flow: ${message}`);\n if (error instanceof Error && error.stack) {\n logger.debug('Stack trace:', { stack: error.stack });\n }\n throw error;\n }\n}\n","/**\n * Serve mode - serve single file (typically generated bundle)\n */\n\nimport express from 'express';\nimport { resolve } from 'path';\nimport type { Logger } from '@walkeros/core';\nimport { VERSION } from '../version';\n\nexport interface ServeConfig {\n port?: number;\n host?: string;\n servePath?: string;\n serveName?: string;\n file?: string;\n}\n\n/**\n * Run serve mode - serve single file (typically generated bundle)\n *\n * @param config - Server configuration\n * @param logger - Logger instance for output\n */\nexport async function runServeMode(\n config: ServeConfig | undefined,\n logger: Logger.Instance,\n): Promise<void> {\n // Port priority: ENV variable > config > default\n const port = process.env.PORT\n ? parseInt(process.env.PORT, 10)\n : config?.port || 8080;\n\n // Host priority: ENV variable > config > default\n const host = process.env.HOST || config?.host || '0.0.0.0';\n\n // Bundle path: ENV variable > config > default (resolve to absolute)\n const file = resolve(\n process.env.BUNDLE || config?.file || './dist/walker.js',\n );\n\n // Serve name (filename in URL): ENV variable > config > default\n const serveName = process.env.SERVE_NAME || config?.serveName || 'walker.js';\n\n // Serve path (URL directory): ENV variable > config > default (empty = root)\n const servePath = process.env.SERVE_PATH || config?.servePath || '';\n\n // Build full URL path\n const urlPath = servePath ? `/${servePath}/${serveName}` : `/${serveName}`;\n\n logger.info('Starting single-file server...');\n logger.info(`File: ${file}`);\n logger.info(`URL: http://${host}:${port}${urlPath}`);\n\n try {\n const app = express();\n\n // Health check\n app.get('/health', (req, res) => {\n res.json({\n status: 'ok',\n version: VERSION,\n timestamp: Date.now(),\n mode: 'serve',\n file: file,\n url: urlPath,\n });\n });\n\n // Serve single file at custom URL path\n app.get(urlPath, (req, res) => {\n // Set content type before streaming\n res.type('application/javascript');\n\n // Allow dotfiles since file paths may include dotfile directories\n res.sendFile(file, { dotfiles: 'allow' }, (err) => {\n if (err && !res.headersSent) {\n const errCode = (err as NodeJS.ErrnoException).code;\n // Express 5 uses HTTP-style errors with status/statusCode\n const errStatus =\n (err as { status?: number; statusCode?: number }).status ||\n (err as { status?: number; statusCode?: number }).statusCode;\n\n // Log errors (except client disconnections)\n if (errCode !== 'ECONNABORTED') {\n logger.error(\n `sendFile error for ${file}: ${err.message} (code: ${errCode}, status: ${errStatus})`,\n );\n }\n\n // Send appropriate error response (check both Node.js codes and HTTP status)\n if (\n errStatus === 404 ||\n errCode === 'ENOENT' ||\n errCode === 'EISDIR' ||\n errCode === 'ENOTDIR'\n ) {\n res.status(404).send('File not found');\n } else if (errCode !== 'ECONNABORTED') {\n res.status(500).send('Internal server error');\n }\n }\n });\n });\n\n // Start server\n const server = app.listen(port, host, () => {\n logger.info(`Server listening on http://${host}:${port}`);\n logger.info(`GET ${urlPath} - Bundle file`);\n logger.info(`GET /health - Health check`);\n });\n\n // Graceful shutdown\n const shutdownHandler = (signal: string) => {\n logger.info(`Received ${signal}, shutting down...`);\n server.close(() => {\n logger.info('Server closed');\n process.exit(0);\n });\n };\n\n process.on('SIGTERM', () => shutdownHandler('SIGTERM'));\n process.on('SIGINT', () => shutdownHandler('SIGINT'));\n\n // Keep process alive\n await new Promise(() => {});\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`Server failed: ${message}`);\n process.exit(1);\n }\n}\n","import { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\n\nconst versionFilename = fileURLToPath(import.meta.url);\nconst versionDirname = dirname(versionFilename);\n\n/**\n * Find package.json in parent directories\n * Handles both source (src/) and bundled (dist/) contexts\n */\nfunction findPackageJson(): string {\n const paths = [\n join(versionDirname, '../package.json'), // dist/ or src/\n join(versionDirname, '../../package.json'), // src/core/ (not used, but safe)\n ];\n for (const p of paths) {\n try {\n return readFileSync(p, 'utf-8');\n } catch {\n // Continue to next path\n }\n }\n return JSON.stringify({ version: '0.0.0' });\n}\n\n/** CLI package version */\nexport const VERSION: string = JSON.parse(findPackageJson()).version;\n","/**\n * Resolve bundle input to a local file path\n *\n * Supports three input sources (checked in priority order):\n * 1. Stdin pipe - data piped into the process\n * 2. URL - BUNDLE env var is an http(s) URL\n * 3. File path - BUNDLE env var is a local path (default)\n */\n\nimport { writeFileSync } from 'fs';\nimport { isStdinPiped, readStdin } from '../core/stdin.js';\n\nconst TEMP_BUNDLE_PATH = '/tmp/walkeros-bundle.mjs';\n\nexport type BundleSource = 'stdin' | 'url' | 'file';\n\nexport interface ResolvedBundle {\n /** Absolute file path to the bundle (ready for import()) */\n path: string;\n /** How the bundle was provided */\n source: BundleSource;\n}\n\n/**\n * Detect whether a string is an HTTP(S) URL\n */\nfunction isUrl(value: string): boolean {\n return value.startsWith('http://') || value.startsWith('https://');\n}\n\n/**\n * Fetch bundle from URL and write to temp file.\n * Uses a 30s timeout to prevent silent container hangs on unresponsive URLs.\n */\nasync function fetchBundle(url: string): Promise<string> {\n const response = await fetch(url, { signal: AbortSignal.timeout(30_000) });\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch bundle from ${url}: ${response.status} ${response.statusText}`,\n );\n }\n\n const content = await response.text();\n\n if (!content.trim()) {\n throw new Error(`Bundle fetched from ${url} is empty`);\n }\n\n writeFileSync(TEMP_BUNDLE_PATH, content, 'utf-8');\n return TEMP_BUNDLE_PATH;\n}\n\n/**\n * Read bundle from stdin and write to temp file\n */\nasync function readBundleFromStdin(): Promise<string> {\n const content = await readStdin(); // throws if empty\n writeFileSync(TEMP_BUNDLE_PATH, content, 'utf-8');\n return TEMP_BUNDLE_PATH;\n}\n\n/**\n * Resolve the bundle to a local file path\n *\n * Priority: stdin > URL > file path\n *\n * @param bundleEnv - Value of the BUNDLE env var (path or URL)\n * @returns Resolved bundle with file path and source type\n */\nexport async function resolveBundle(\n bundleEnv: string,\n): Promise<ResolvedBundle> {\n // 1. Stdin takes highest priority\n if (isStdinPiped()) {\n const path = await readBundleFromStdin();\n return { path, source: 'stdin' };\n }\n\n // 2. URL detection\n if (isUrl(bundleEnv)) {\n const path = await fetchBundle(bundleEnv);\n return { path, source: 'url' };\n }\n\n // 3. File path (default, existing behavior)\n return { path: bundleEnv, source: 'file' };\n}\n","export function isStdinPiped(): boolean {\n return !process.stdin.isTTY;\n}\n\nexport async function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk);\n }\n const content = Buffer.concat(chunks).toString('utf-8');\n if (!content.trim()) {\n throw new Error('No input received on stdin');\n }\n return content;\n}\n","/**\n * Register runtime with the app API\n *\n * Called at cold start to announce the instance and get a fresh\n * presigned bundle download URL.\n */\n\nexport interface RegisterConfig {\n appUrl: string;\n deployToken: string;\n projectId: string;\n flowId: string;\n bundlePath: string;\n}\n\nexport interface RegisterResult {\n bundleUrl: string;\n}\n\nexport async function registerRuntime(\n config: RegisterConfig,\n): Promise<RegisterResult> {\n const url = `${config.appUrl}/api/projects/${config.projectId}/runtimes/register`;\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${config.deployToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n flowId: config.flowId,\n bundlePath: config.bundlePath,\n }),\n });\n\n if (!response.ok) {\n throw new Error(\n `Registration failed: ${response.status} ${response.statusText}`,\n );\n }\n\n const data = await response.json();\n return { bundleUrl: data.bundleUrl };\n}\n","/* eslint-disable no-console */\nimport chalk from 'chalk';\nimport type { GlobalOptions } from '../types/global.js';\n\nexport const BRAND_COLOR = '#01b5e2';\n\nexport interface LoggerOptions {\n verbose?: boolean;\n silent?: boolean;\n json?: boolean;\n stderr?: boolean;\n}\n\nexport interface Logger {\n log: (...args: unknown[]) => void;\n brand: (...args: unknown[]) => void;\n error: (...args: unknown[]) => void;\n debug: (...args: unknown[]) => void;\n json: (data: unknown) => void;\n // Backward-compatible methods (map to default terminal color per design)\n info: (...args: unknown[]) => void;\n success: (...args: unknown[]) => void;\n warning: (...args: unknown[]) => void;\n warn: (...args: unknown[]) => void;\n gray: (...args: unknown[]) => void;\n}\n\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const {\n verbose = false,\n silent = false,\n json = false,\n stderr = false,\n } = options;\n\n const shouldLog = !silent && !json;\n const shouldDebug = verbose && !silent && !json;\n const out = stderr ? console.error : console.log;\n\n return {\n log: (...args: unknown[]) => {\n if (shouldLog) {\n const message = args.map((arg) => String(arg)).join(' ');\n out(message);\n }\n },\n\n brand: (...args: unknown[]) => {\n if (shouldLog) {\n const message = args.map((arg) => String(arg)).join(' ');\n out(chalk.hex(BRAND_COLOR)(message));\n }\n },\n\n error: (...args: unknown[]) => {\n if (!json) {\n const message = args.map((arg) => String(arg)).join(' ');\n console.error(chalk.red(message));\n }\n },\n\n debug: (...args: unknown[]) => {\n if (shouldDebug) {\n const message = args.map((arg) => String(arg)).join(' ');\n out(` ${message}`);\n }\n },\n\n json: (data: unknown) => {\n if (!silent) {\n out(JSON.stringify(data, null, 2));\n }\n },\n\n // Backward-compatible methods (all use default terminal color per design)\n info: (...args: unknown[]) => {\n if (shouldLog) {\n const message = args.map((arg) => String(arg)).join(' ');\n out(message);\n }\n },\n\n success: (...args: unknown[]) => {\n if (shouldLog) {\n const message = args.map((arg) => String(arg)).join(' ');\n out(message);\n }\n },\n\n warning: (...args: unknown[]) => {\n if (shouldLog) {\n const message = args.map((arg) => String(arg)).join(' ');\n out(message);\n }\n },\n\n warn: (...args: unknown[]) => {\n if (shouldLog) {\n const message = args.map((arg) => String(arg)).join(' ');\n out(message);\n }\n },\n\n gray: (...args: unknown[]) => {\n if (shouldLog) {\n const message = args.map((arg) => String(arg)).join(' ');\n out(message);\n }\n },\n };\n}\n\n/**\n * Create logger from command options\n * Factory function that standardizes logger creation across commands\n *\n * @param options - Command options containing verbose, silent, and json flags\n * @returns Configured logger instance\n */\nexport function createCommandLogger(\n options: GlobalOptions & { json?: boolean; stderr?: boolean },\n): Logger {\n return createLogger({\n verbose: options.verbose,\n silent: options.silent ?? false,\n json: options.json,\n stderr: options.stderr,\n });\n}\n","/**\n * Entry point for walkeros/flow Docker container\n * Reads environment variables and starts the appropriate mode\n */\n\nimport { runFlow } from './runner.js';\nimport { runServeMode } from './serve.js';\nimport { resolveBundle } from './resolve-bundle.js';\nimport { registerRuntime } from './register.js';\nimport { createLogger } from '../core/logger.js';\nimport type { Logger } from '@walkeros/core';\n\n/**\n * Adapt CLI logger to core Logger.Instance interface\n */\nfunction adaptLogger(\n cliLogger: ReturnType<typeof createLogger>,\n): Logger.Instance {\n return {\n error: (message: string | Error) => {\n const msg = message instanceof Error ? message.message : message;\n cliLogger.error(msg);\n },\n info: (message: string | Error) => {\n const msg = message instanceof Error ? message.message : message;\n cliLogger.info(msg);\n },\n debug: (message: string | Error) => {\n const msg = message instanceof Error ? message.message : message;\n cliLogger.debug(msg);\n },\n throw: (message: string | Error): never => {\n const msg = message instanceof Error ? message.message : message;\n cliLogger.error(msg);\n throw message instanceof Error ? message : new Error(msg);\n },\n scope: (name: string) => {\n // Simple pass-through for scoped loggers - CLI logger doesn't use scopes\n return adaptLogger(cliLogger);\n },\n };\n}\n\nasync function main() {\n const mode = process.env.MODE || 'collect';\n let bundleEnv = process.env.BUNDLE || '/app/flow/bundle.mjs';\n const port = parseInt(process.env.PORT || '8080', 10);\n\n const cliLogger = createLogger({ silent: false, verbose: true });\n const logger = adaptLogger(cliLogger);\n\n cliLogger.log(`Starting walkeros/flow in ${mode} mode`);\n\n // If registration env vars are set, register and get fresh bundle URL\n const appUrl = process.env.APP_URL;\n const deployToken = process.env.DEPLOY_TOKEN;\n const projectId = process.env.PROJECT_ID;\n const flowId = process.env.FLOW_ID;\n const bundlePath = process.env.BUNDLE_PATH;\n\n if (appUrl && deployToken && projectId && flowId && bundlePath) {\n try {\n cliLogger.log('Registering with app...');\n const result = await registerRuntime({\n appUrl,\n deployToken,\n projectId,\n flowId,\n bundlePath,\n });\n bundleEnv = result.bundleUrl;\n cliLogger.log('Registered, bundle URL received');\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n cliLogger.error(`Registration failed: ${message}`);\n process.exit(1);\n }\n }\n\n // Resolve bundle from stdin, URL, or file path\n let file: string;\n try {\n const resolved = await resolveBundle(bundleEnv);\n file = resolved.path;\n\n // Log which input method was used\n if (resolved.source === 'stdin') {\n cliLogger.log('Bundle: received via stdin pipe');\n } else if (resolved.source === 'url') {\n cliLogger.log(`Bundle: fetched from ${bundleEnv}`);\n } else {\n cliLogger.log(`Bundle: ${file}`);\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n cliLogger.error(`Failed to resolve bundle: ${message}`);\n process.exit(1);\n }\n\n cliLogger.log(`Port: ${port}`);\n\n try {\n if (mode === 'collect') {\n await runFlow(file, { port }, logger);\n } else if (mode === 'serve') {\n await runServeMode({ file, port }, logger);\n } else {\n cliLogger.error(`Unknown mode: ${mode}. Use 'collect' or 'serve'.`);\n process.exit(1);\n }\n } catch (error) {\n cliLogger.error(`Failed to start: ${error}`);\n process.exit(1);\n }\n}\n\nmain();\n"],"mappings":"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","names":["resolve","dirname","resolve"]}
package/dist/walker.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";(()=>{var o=Object.defineProperty;var i={};((e,t)=>{for(var n in t)o(e,n,{get:t[n],enumerable:!0})})(i,{Level:()=>r});var r=(e=>(e[e.ERROR=0]="ERROR",e[e.INFO=1]="INFO",e[e.DEBUG=2]="DEBUG",e))(r||{});})();
@@ -250,7 +250,10 @@
250
250
  "this",
251
251
  {
252
252
  "map": {
253
- "item_id": "data.id",
253
+ "item_id": [
254
+ { "key": "data.sku" },
255
+ { "key": "data.id" }
256
+ ],
254
257
  "item_name": "data.name",
255
258
  "item_category": "data.category",
256
259
  "price": "data.price"
@@ -322,6 +325,12 @@
322
325
  "url": "$var.apiUrl",
323
326
  "batch": 5
324
327
  },
328
+ "data": {
329
+ "map": {
330
+ "sent_at": { "fn": "$code:() => Date.now()" },
331
+ "flow_version": "$var.flowVersion"
332
+ }
333
+ },
325
334
  "mapping": {
326
335
  "order": {
327
336
  "complete": {
@@ -71,7 +71,7 @@ npx walkeros serve packages/cli/examples/flow-complete.json --flow web
71
71
 
72
72
  ## Feature Inventory
73
73
 
74
- ### Features Used (51)
74
+ ### Features Used (53)
75
75
 
76
76
  #### Mapping - Value Extraction
77
77
 
@@ -81,6 +81,7 @@ npx walkeros serve packages/cli/examples/flow-complete.json --flow web
81
81
  | Static value | Meta ViewContent | `"content_type": { "value": "product" }` |
82
82
  | Key with fallback | GA4 add_to_cart | `{ "key": "data.currency", "value": "$variables.currency" }` |
83
83
  | Nested key (deep) | dataLayer mapping | `"items.0.item_id"` |
84
+ | Fallback array | GA4 view_item | `[{ "key": "data.sku" }, { "key": "data.id" }]` |
84
85
 
85
86
  #### Mapping - Structure
86
87
 
@@ -92,6 +93,7 @@ npx walkeros serve packages/cli/examples/flow-complete.json --flow web
92
93
  | Set (single value) | Meta ViewContent | `"content_ids": { "set": ["data.id"] }` |
93
94
  | Set (multiple values) | Meta settings | `"external_id": { "set": ["user.device", "user.session"] }` |
94
95
  | Direct passthrough | Meta PageView | `"data": "data"` |
96
+ | Config-level data | API destination | `"data": { "map": { "sent_at": {...} } }` |
95
97
 
96
98
  #### Mapping - Control
97
99
 
@@ -175,36 +177,33 @@ npx walkeros serve packages/cli/examples/flow-complete.json --flow web
175
177
 
176
178
  ---
177
179
 
178
- ### Features NOT Used (15)
180
+ ### Features NOT Used (6)
179
181
 
180
- #### Requires JavaScript (7)
182
+ #### Now Available via $code: Prefix ✅
181
183
 
182
- These features cannot be used in pure JSON configurations:
184
+ These features are now fully supported in JSON via `$code:` prefix (and ARE used
185
+ in this example):
183
186
 
184
- | Feature | Reason |
185
- | --------------------------- | ----------------------------- |
186
- | `fn:` function | Requires JavaScript callback |
187
- | `condition:` | Requires JavaScript predicate |
188
- | Conditional mapping (array) | Requires condition functions |
189
- | Custom transformer code | Requires JavaScript |
190
- | Custom source code | Requires JavaScript |
191
- | Custom destination code | Requires JavaScript |
192
- | Event handler callbacks | Requires JavaScript |
187
+ | Feature | Status |
188
+ | --------------------------- | ----------------------------------- |
189
+ | `fn:` function | Used via `$code:` in GA4 value |
190
+ | `condition:` | Used via `$code:` in definitions |
191
+ | Conditional mapping (array) | Used in serverValidator |
192
+ | Custom transformer code | Used in enricher, filter |
193
+ | Custom destination code | Used in debug logger |
193
194
 
194
- #### Omitted for Clarity (8)
195
+ #### Omitted for Clarity (6)
195
196
 
196
197
  These features could be added but were omitted to keep the example focused:
197
198
 
198
- | Feature | Why Omitted |
199
- | ------------------------- | ----------------------------- |
200
- | Multiple named flows (3+) | Two flows sufficient for demo |
201
- | Queue config | Advanced batching scenario |
202
- | Retry config | Advanced error handling |
203
- | Custom fetch options | API destination advanced |
204
- | Dynamic routing | Requires condition logic |
205
- | Transform before send | Covered by policy |
206
- | Custom headers in API | Would add complexity |
207
- | Multiple validators | One per flow sufficient |
199
+ | Feature | Why Omitted |
200
+ | ------------------------- | ------------------------------ |
201
+ | Multiple named flows (3+) | Two flows sufficient for demo |
202
+ | Queue config | Advanced batching scenario |
203
+ | Retry config | Advanced error handling |
204
+ | Custom fetch options | API destination advanced |
205
+ | Custom headers in API | Would add complexity |
206
+ | `validate:` function | Could add via $code: if needed |
208
207
 
209
208
  ---
210
209
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@walkeros/cli",
3
- "version": "1.1.3",
3
+ "version": "1.3.0",
4
4
  "description": "walkerOS CLI - Bundle and deploy walkerOS components",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -10,6 +10,10 @@
10
10
  ".": {
11
11
  "types": "./dist/index.d.ts",
12
12
  "default": "./dist/index.js"
13
+ },
14
+ "./dev": {
15
+ "types": "./dist/dev.d.ts",
16
+ "default": "./dist/dev.js"
13
17
  }
14
18
  },
15
19
  "bin": {
@@ -33,8 +37,8 @@
33
37
  "docker:publish": "bash scripts/publish-docker.sh"
34
38
  },
35
39
  "dependencies": {
36
- "@walkeros/core": "1.2.2",
37
- "@walkeros/server-core": "1.0.4",
40
+ "@walkeros/core": "1.3.0",
41
+ "@walkeros/server-core": "1.0.5",
38
42
  "chalk": "^5.6.2",
39
43
  "commander": "^14.0.2",
40
44
  "cors": "^2.8.5",