@walkeros/cli 4.8.1-next-1791586788897 → 4.8.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.
- package/CHANGELOG.md +19 -6
- package/dist/cli.js +4840 -6962
- package/dist/dev.d.ts +62 -1
- package/dist/dev.js +56 -1
- package/dist/dev.js.map +1 -1
- package/dist/examples/flow-complete.json +22 -22
- package/dist/examples/flow-complete.md +7 -7
- package/dist/examples/index.d.ts +0 -1
- package/dist/examples/index.js +30 -31
- package/dist/examples/index.js.map +1 -1
- package/dist/index.d.ts +122 -5747
- package/dist/index.js +1652 -3718
- package/dist/index.js.map +1 -1
- package/dist/validate.d.ts +93 -0
- package/dist/validate.js +2077 -0
- package/dist/validate.js.map +1 -0
- package/examples/flow-complete.json +22 -22
- package/examples/flow-complete.md +7 -7
- package/package.json +34 -38
- package/openapi/client-operations.json +0 -250
- package/openapi/spec.json +0 -7904
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/validate/index.ts","../src/core/cli-logger.ts","../src/core/timer.ts","../src/core/output.ts","../src/core/tmp.ts","../src/config/utils.ts","../src/core/fetch-failure.ts","../src/core/utils.ts","../src/core/local-packages.ts","../src/core/input-detector.ts","../src/core/stdin.ts","../src/core/oauth-client.ts","../src/core/app-fetch.ts","../src/core/event-validation.ts","../src/config/validators.ts","../src/config/loader.ts","../src/core/content-digest.ts","../src/config/window-collector.ts","../src/commands/validate/validators/contract.ts","../src/commands/validate/validators/event.ts","../src/commands/validate/validators/flow.ts","../src/commands/validate/scope.ts","../src/commands/validate/validators/resolve.ts","../src/commands/validate/validators/settings.ts","../src/core/resolve-export-name.ts","../src/core/step-packages.ts","../src/commands/validate/validators/mapping.ts","../src/commands/validate/validators/entry.ts","../src/commands/validate/types.ts"],"sourcesContent":["// walkerOS/packages/cli/src/commands/validate/index.ts\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport chalk from 'chalk';\nimport { isObject } from '@walkeros/core';\nimport { createCLILogger } from '../../core/cli-logger.js';\nimport {\n getErrorMessage,\n isStdinPiped,\n readStdin,\n writeResult,\n} from '../../core/index.js';\nimport { loadJsonConfig } from '../../config/index.js';\nimport {\n validateContract,\n validateEvent,\n validateMapping,\n} from './validators/index.js';\nimport { validateEntry } from './validators/entry.js';\nimport { isFlowJson } from './scope.js';\nimport { validateFlowWithPackages } from './validators/flow.js';\nimport type { ValidateOptions } from '../../schemas/validate.js';\nimport {\n USAGE_CODES,\n type ValidateCheck,\n type ValidateCommandOptions,\n type ValidateResult,\n type ValidationError,\n type ValidationType,\n} from './types.js';\n\n/**\n * Options that do not apply to the validation type: `--path` and `--flow`\n * address flow files only, `--offline` removes the package settings check\n * of a whole-file flow run. Never ignored silently (OPTION_NOT_APPLICABLE).\n */\nfunction inapplicableOptions(\n type: ValidationType,\n options: ValidateOptions,\n): ValidationError[] {\n const errors: ValidationError[] = [];\n if (options.offline === true && (type !== 'flow' || options.path)) {\n errors.push({\n path: 'options.offline',\n message:\n type === 'flow'\n ? '--offline removes the package settings check, which is all --path checks; drop one of them'\n : `--offline applies to a whole flow file and does not apply to -t ${type}`,\n code: 'OPTION_NOT_APPLICABLE',\n });\n }\n if (type === 'flow') return errors;\n if (options.path !== undefined) {\n errors.push({\n path: 'options.path',\n message: `--path addresses an entry in a flow file and does not apply to -t ${type}`,\n code: 'OPTION_NOT_APPLICABLE',\n });\n }\n if (options.flow !== undefined) {\n errors.push({\n path: 'options.flow',\n message: `--flow names a flow in a flow file and does not apply to -t ${type}`,\n code: 'OPTION_NOT_APPLICABLE',\n });\n }\n return errors;\n}\n\n/**\n * `-t contract` on a flow file validates its `contract` section, exactly as\n * on the section alone (M-dispatch).\n */\nfunction validateContractInput(input: unknown): ValidateResult {\n if (!isFlowJson(input)) return validateContract(input);\n const contract = isObject(input) ? input.contract : undefined;\n if (contract === undefined) {\n return {\n valid: false,\n type: 'contract',\n errors: [\n {\n path: 'contract',\n message: 'The flow file has no contract section to validate',\n code: 'NO_CONTRACT_SECTION',\n },\n ],\n warnings: [],\n details: {},\n };\n }\n return validateContract(contract);\n}\n\n/**\n * The directory a local `path` package resolves against: the input file's,\n * when the input is a file on disk. Otherwise none, and no disk reads.\n */\nfunction configDirOf(input: unknown): string | undefined {\n if (typeof input !== 'string') return undefined;\n const candidate = path.resolve(input);\n return fs.existsSync(candidate) && fs.statSync(candidate).isFile()\n ? path.dirname(candidate)\n : undefined;\n}\n\n/** Whole-document validations state their one check as their scope. */\nfunction withDocumentScope(\n result: ValidateResult,\n check: ValidateCheck,\n): ValidateResult {\n return {\n ...result,\n details: {\n ...result.details,\n scope: result.details.scope ?? { flows: [], checks: [check] },\n skipped: result.details.skipped ?? [],\n },\n };\n}\n\n/**\n * Programmatic API for validation.\n * Can be called directly from code or MCP server.\n *\n * Accepts parsed objects, JSON strings, file paths, or URLs as input.\n */\nexport async function validate(\n type: ValidationType,\n input: unknown,\n options: ValidateOptions = {},\n): Promise<ValidateResult> {\n // Resolve string inputs (file paths, URLs, JSON strings) to parsed objects.\n // A path that cannot be read or parsed is an input error, never a document.\n let resolved = input;\n if (typeof input === 'string') {\n if (input.trim() === '') throw new Error(`${type} is required`);\n resolved = await loadJsonConfig(input);\n }\n\n const misuse = inapplicableOptions(type, options);\n if (misuse.length > 0) {\n return {\n valid: false,\n type,\n errors: misuse,\n warnings: [],\n details: { scope: { flows: [], checks: [] }, skipped: [] },\n };\n }\n\n const result = await validateByType(type, input, resolved, options);\n return options.strict === true ? escalateStrict(result) : result;\n}\n\n/**\n * `strict` turns warnings and skipped checks into failures (C4), in every\n * entry point (C9): the result is invalid, with the findings unchanged.\n */\nfunction escalateStrict(result: ValidateResult): ValidateResult {\n const skipped = result.details.skipped ?? [];\n if (result.warnings.length === 0 && skipped.length === 0) return result;\n return { ...result, valid: false };\n}\n\nasync function validateByType(\n type: ValidationType,\n input: unknown,\n resolved: unknown,\n options: ValidateOptions,\n): Promise<ValidateResult> {\n switch (type) {\n case 'contract':\n return withDocumentScope(validateContractInput(resolved), 'contract');\n case 'event':\n return withDocumentScope(validateEvent(resolved), 'event');\n case 'flow':\n if (options.path !== undefined) {\n return validateEntry(options.path, resolved, {\n flow: options.flow,\n configDir: options.configDir ?? configDirOf(input),\n });\n }\n return validateFlowWithPackages(resolved, {\n flow: options.flow,\n strict: options.strict,\n offline: options.offline,\n configDir: options.configDir ?? configDirOf(input),\n });\n case 'mapping':\n return withDocumentScope(validateMapping(resolved), 'mapping');\n default:\n throw new Error(`Unknown validation type: ${type}`);\n }\n}\n\n/** One line naming what the run covered (C6). */\nfunction formatScope(result: ValidateResult): string | undefined {\n const scope = result.details.scope;\n if (!scope) return undefined;\n const parts: string[] = [];\n if (scope.flows.length > 0) parts.push(`flows ${scope.flows.join(', ')}`);\n if (scope.entry) {\n const { section, key, flows, searchedFlows } = scope.entry;\n const name = section ? `${section}.${key}` : key;\n parts.push(\n `entry ${name} in ${flows.join(', ') || 'no flow'} (searched ${searchedFlows.join(', ') || 'none'})`,\n );\n }\n parts.push(`${scope.checks.length} check(s): ${scope.checks.join(', ')}`);\n if (scope.offline) parts.push('offline: package settings not checked');\n return `Scope: ${parts.join('; ')}`;\n}\n\n/**\n * Format validation result for CLI output.\n */\nfunction formatResult(\n result: ValidateResult,\n options: { json?: boolean; verbose?: boolean; exitCode: number },\n): string {\n if (options.json) {\n return JSON.stringify(result, null, 2);\n }\n\n const lines: string[] = [];\n lines.push('');\n lines.push(`Validating ${result.type}...`);\n lines.push('');\n\n const scopeLine = formatScope(result);\n if (scopeLine) {\n lines.push(scopeLine);\n lines.push('');\n }\n\n // Show details if verbose\n if (options.verbose && Object.keys(result.details).length > 0) {\n lines.push('Details:');\n for (const [key, value] of Object.entries(result.details)) {\n lines.push(` ${key}: ${JSON.stringify(value)}`);\n }\n lines.push('');\n }\n\n lines.push('Validation Results:');\n\n // Errors\n for (const error of result.errors) {\n lines.push(chalk.red(` ✗ ${error.path}: ${error.message}`));\n }\n\n // Warnings\n for (const warning of result.warnings) {\n lines.push(chalk.yellow(` ⚠ ${warning.path}: ${warning.message}`));\n if (warning.suggestion) {\n lines.push(chalk.gray(` → ${warning.suggestion}`));\n }\n }\n\n // Skips are listed whatever the verbosity (C5)\n const skipped = result.details.skipped ?? [];\n for (const skip of skipped) {\n lines.push(\n chalk.gray(` - skipped ${skip.check} at ${skip.path}: ${skip.reason}`),\n );\n }\n\n // The verdict line follows the exit code: a run that fails under\n // --strict (exit 2) never reads as passed.\n if (options.exitCode === 2) {\n lines.push(\n chalk.red(\n ` ✗ Failed under --strict: ${result.warnings.length} warning(s) and ${skipped.length} skipped check(s) count as failures`,\n ),\n );\n } else if (result.valid && skipped.length === 0) {\n lines.push(chalk.green(` ✓ All checks passed`));\n } else if (result.valid) {\n lines.push(\n chalk.green(\n ` ✓ No errors in checked scope; ${skipped.length} check(s) skipped`,\n ),\n );\n }\n\n lines.push('');\n lines.push(\n `Summary: ${result.errors.length} error(s), ${result.warnings.length} warning(s), ${skipped.length} skipped`,\n );\n\n return lines.join('\\n');\n}\n\n/**\n * CLI command handler for validate command.\n */\nexport async function validateCommand(\n options: ValidateCommandOptions,\n): Promise<void> {\n // Result always goes to stdout; logs to stderr\n const logger = createCLILogger({ ...options, stderr: true });\n\n let exitCode: number;\n try {\n // Load input: stdin > argument > error\n let input: unknown;\n if (isStdinPiped() && !options.input) {\n const stdinContent = await readStdin();\n try {\n input = JSON.parse(stdinContent);\n } catch {\n throw new Error('Invalid JSON received on stdin');\n }\n } else {\n input = options.input;\n }\n\n // Run validation\n const result = await validate(options.type, input, {\n flow: options.flow,\n path: options.path,\n strict: options.strict,\n offline: options.offline,\n });\n\n exitCode = exitCodeOf(result, options.strict === true);\n\n // Format and write result; --silent suppresses stdout, never a file\n if (!options.silent || options.output) {\n const formatted = formatResult(result, {\n json: options.json,\n verbose: options.verbose,\n exitCode,\n });\n await writeResult(formatted + '\\n', { output: options.output });\n }\n } catch (error) {\n const errorMessage = getErrorMessage(error);\n\n if (options.json) {\n const errorOutput = JSON.stringify(\n {\n valid: false,\n type: options.type,\n errors: [\n { path: 'input', message: errorMessage, code: 'INPUT_ERROR' },\n ],\n warnings: [],\n details: { scope: { flows: [], checks: [] }, skipped: [] },\n },\n null,\n 2,\n );\n await writeResult(errorOutput + '\\n', { output: options.output });\n } else {\n logger.error(`Error: ${errorMessage}`);\n }\n\n exitCode = 3;\n }\n process.exit(exitCode);\n}\n\n/**\n * Exit code (C7): 3 could not run, 1 errors, 2 warnings or skips under\n * --strict, 0 valid.\n */\nfunction exitCodeOf(result: ValidateResult, strict: boolean): number {\n if (\n result.errors.some((e) =>\n USAGE_CODES.some((usageCode) => usageCode === e.code),\n )\n )\n return 3;\n if (result.errors.length > 0) return 1;\n const skipped = result.details.skipped ?? [];\n if (strict && (result.warnings.length > 0 || skipped.length > 0)) return 2;\n return result.valid ? 0 : 1;\n}\n\n// Re-export types\nexport * from './types.js';\nexport {\n validateContract,\n validateEvent,\n validateFlow,\n validateMapping,\n} from './validators/index.js';\nexport { validateEntry } from './validators/entry.js';\n","import chalk from 'chalk';\nimport {\n createCLILogger as createCoreCLILogger,\n createCLILoggerConfig as createCoreCLILoggerConfig,\n type CLILoggerColors,\n type CLILoggerOptions,\n} from '@walkeros/core/node';\nimport type { Logger } from '@walkeros/core';\n\nexport type { CLILoggerOptions };\n\n/**\n * The CLI's terminal colours. Binding them here matters: the shared factory in\n * `@walkeros/core/node` defaults every level to identity, so a plain re-export\n * would silently drop red ERROR output at every CLI call site.\n */\nconst CLI_COLORS: CLILoggerColors = { error: chalk.red };\n\n/**\n * Build the `Logger.Config` backing the CLI logger, with the CLI's colours.\n * See `createCLILoggerConfig` in `@walkeros/core/node` for the handler contract.\n */\nexport function createCLILoggerConfig(\n options: CLILoggerOptions = {},\n): Logger.Config {\n return createCoreCLILoggerConfig(options, CLI_COLORS);\n}\n\n/**\n * Create a core Logger.Instance with CLI-appropriate behavior.\n *\n * Behavior:\n * - ERROR: always shown (chalk red, via console.error) unless --json\n * - WARN: shown unless --silent or --json\n * - INFO: shown unless --silent or --json\n * - DEBUG: shown only with --verbose (and not --silent/--json)\n * - json(): shown unless --silent\n */\nexport function createCLILogger(\n options: CLILoggerOptions = {},\n): Logger.Instance {\n return createCoreCLILogger(options, CLI_COLORS);\n}\n","export { createTimer, type Timer } from '@walkeros/core';\n","/**\n * Output formatting utilities for CLI commands\n */\n\nimport fs from 'fs-extra';\nimport path from 'path';\n\n/**\n * Write command result to stdout or file.\n * Used by all commands to implement -o/--output flag.\n */\nexport async function writeResult(\n content: string | Buffer,\n options: { output?: string },\n): Promise<void> {\n if (options.output) {\n const outputPath = path.resolve(options.output);\n await fs.ensureDir(path.dirname(outputPath));\n await fs.writeFile(outputPath, content);\n } else {\n process.stdout.write(content);\n process.stdout.write('\\n');\n }\n}\n\nexport interface JsonOutput<T = Record<string, unknown>> {\n success: boolean;\n data?: T;\n error?: string;\n duration?: number;\n}\n\n/**\n * Create standardized JSON output for CLI commands\n */\nexport function createJsonOutput<T = Record<string, unknown>>(\n success: boolean,\n data?: T,\n error?: string,\n duration?: number,\n): JsonOutput<T> {\n return {\n success,\n ...(data && { data }),\n ...(error && { error }),\n ...(duration && { duration }),\n };\n}\n\n/**\n * Create success JSON output\n */\nexport function createSuccessOutput<T = Record<string, unknown>>(\n data?: T,\n duration?: number,\n): JsonOutput<T> {\n return createJsonOutput(true, data, undefined, duration);\n}\n\n/**\n * Create error JSON output\n */\nexport function createErrorOutput(\n error: string,\n duration?: number,\n): JsonOutput<never> {\n return createJsonOutput<never>(false, undefined, error, duration);\n}\n\n/**\n * Format bytes to KB with 2 decimal places\n */\nexport function formatBytes(bytes: number): string {\n return (bytes / 1024).toFixed(2);\n}\n\n/**\n * Format file size with appropriate unit\n */\nexport function formatFileSize(bytes: number): string {\n const units = ['B', 'KB', 'MB', 'GB'];\n let size = bytes;\n let unitIndex = 0;\n\n while (size >= 1024 && unitIndex < units.length - 1) {\n size /= 1024;\n unitIndex++;\n }\n\n return `${size.toFixed(2)} ${units[unitIndex]}`;\n}\n","/**\n * Temp path helpers live in `@walkeros/core/node`, shared with the runtime.\n * All temp files go to os.tmpdir() by default.\n */\nexport {\n getTmpPath,\n createTmpResolver,\n getDefaultTmpRoot,\n type TmpResolver,\n} from '@walkeros/core/node';\n","/**\n * Configuration Utility Functions\n */\n\nimport fs from 'fs-extra';\nimport path from 'path';\nimport { fetchFailureReason } from '../core/fetch-failure.js';\n\n/**\n * Check if a string is a valid URL\n *\n * @param str - String to check\n * @returns True if string is a valid HTTP/HTTPS URL\n */\nexport function isUrl(str: string): boolean {\n try {\n const url = new URL(str);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n return false;\n }\n}\n\n/** A config input named an http(s) URL that could not be read. */\nexport class ConfigFetchError extends Error {\n readonly url: string;\n /** The HTTP status, when the host answered. */\n readonly status?: number;\n\n constructor(message: string, url: string, status?: number) {\n super(message);\n this.name = 'ConfigFetchError';\n this.url = url;\n this.status = status;\n }\n}\n\n/**\n * Fetch content from a URL as a string.\n * Shared helper for all URL-loading paths.\n *\n * A plain GET with no credential for every host: a config input is any URL\n * the person names, and a link to a saved flow carries its own signature.\n *\n * @param url - HTTP/HTTPS URL to fetch\n * @returns Response body as a string\n * @throws ConfigFetchError if the host cannot be reached or answers non-OK\n */\nexport async function fetchContentString(url: string): Promise<string> {\n let response: Response;\n try {\n response = await fetch(url);\n } catch (error) {\n throw new ConfigFetchError(\n `Could not reach ${url}: ${fetchFailureReason(error)}`,\n url,\n );\n }\n if (!response.ok) {\n throw new ConfigFetchError(\n `Failed to fetch ${url}: ${response.status} ${response.statusText}`.trimEnd(),\n url,\n response.status,\n );\n }\n return response.text();\n}\n\n/**\n * Substitute environment variables in a string.\n *\n * @param value - String with ${VAR} placeholders\n * @returns String with environment variables substituted\n * @throws Error if environment variable is not found\n *\n * @example\n * ```typescript\n * substituteEnvVariables('${HOME}/config') // \"/Users/name/config\"\n * ```\n */\nexport function substituteEnvVariables(value: string): string {\n return value.replace(/\\${([^}]+)}/g, (_, envVar) => {\n const envValue = process.env[envVar];\n if (!envValue) {\n throw new Error(`Environment variable ${envVar} not found`);\n }\n return envValue;\n });\n}\n\n/**\n * Resolve raw string content from a URL, file path, or inline string.\n *\n * Detection priority:\n * 1. URL (http://, https://) — download content\n * 2. Existing file path — read file content\n * 3. Inline string — return as-is\n *\n * @param input - URL, file path, or inline string\n * @returns Raw string content and the resolved absolute path (if file-based)\n * @throws Error if file not found or download fails\n */\nasync function resolveContent(input: string): Promise<string> {\n const trimmed = input.trim();\n\n // 1. Check if input is a URL\n if (isUrl(trimmed)) {\n return fetchContentString(trimmed);\n }\n\n // 2. Check if file path exists\n const absolutePath = path.resolve(trimmed);\n if (await fs.pathExists(absolutePath)) {\n return fs.readFile(absolutePath, 'utf-8');\n }\n\n // 3. Inline content — return as-is\n if (trimmed.startsWith('{') || trimmed.startsWith('[')) {\n return trimmed;\n }\n\n // 4. Nothing matched — file not found\n throw new Error(`Configuration file not found: ${absolutePath}`);\n}\n\n/**\n * Load configuration from a file path, URL, or inline string.\n *\n * Supports two modes:\n * - `json: true` (default) — resolves content and parses as JSON\n * - `json: false` — resolves content and returns raw string\n *\n * Detection priority:\n * 1. URL (http://, https://) — download content\n * 2. Existing file path — read file content\n * 3. Inline string (starting with { or [) — use directly\n *\n * @param input - Path to file, HTTP/HTTPS URL, or inline string\n * @param options - Optional settings\n * @param options.json - Parse as JSON (default: true)\n * @returns Parsed object (json: true) or raw string (json: false)\n * @throws Error if file not found, download fails, or invalid JSON\n *\n * @example\n * ```typescript\n * // JSON mode (default) — same as loadJsonConfig\n * const config = await loadConfig('./config.json')\n * const config = await loadConfig('https://example.com/config.json')\n * const config = await loadConfig('{\"version\":3,\"flows\":{}}')\n *\n * // Raw string mode — returns file/URL content as string\n * const code = await loadConfig('./bundle.js', { json: false })\n * ```\n */\nexport async function loadConfig<T = unknown>(\n input: string,\n options?: { json?: boolean },\n): Promise<T | string> {\n const json = options?.json !== false; // default true\n\n if (!json) {\n return resolveContent(input);\n }\n\n // JSON mode — resolve content then parse\n const trimmed = input.trim();\n\n try {\n const content = await resolveContent(trimmed);\n\n // Parse the resolved content as JSON\n return JSON.parse(content) as T;\n } catch (error) {\n // Distinguish between JSON parse errors and resolution errors\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n // Re-throw resolution errors (a URL that could not be read, a file not\n // found) as-is\n if (error instanceof ConfigFetchError || errorMessage.includes('not found'))\n throw error;\n\n // JSON-looking inline content with parse errors\n if (trimmed.startsWith('{') || trimmed.startsWith('[')) {\n throw new Error(\n `Input appears to be JSON but contains errors: ${errorMessage}`,\n );\n }\n\n // File or URL with invalid JSON content\n throw new Error(`Invalid JSON in config file: ${input}. ${errorMessage}`);\n }\n}\n\n/**\n * Load and parse JSON configuration from a file path, URL, or inline JSON string.\n *\n * Thin wrapper around `loadConfig` with `json: true` (default).\n *\n * Detection priority:\n * 1. URL (http://, https://) — download and parse\n * 2. Existing file path — read and parse\n * 3. Inline JSON string (starting with { or [) — parse directly\n *\n * @param configPath - Path to JSON file, HTTP/HTTPS URL, or inline JSON string\n * @returns Parsed configuration object\n * @throws Error if file not found, download fails, or invalid JSON\n *\n * @example\n * ```typescript\n * // Local file\n * const config = await loadJsonConfig('./config.json')\n *\n * // Remote URL\n * const config = await loadJsonConfig('https://example.com/config.json')\n *\n * // Inline JSON\n * const config = await loadJsonConfig('{\"version\":3,\"flows\":{}}')\n * ```\n */\nexport async function loadJsonConfig<T>(configPath: string): Promise<T> {\n return loadConfig<T>(configPath, { json: true }) as Promise<T>;\n}\n\n/**\n * Load JSON from inline string, file path, or URL.\n *\n * Supports three input formats:\n * 1. Inline JSON string - parsed directly\n * 2. Local file path - read and parsed\n * 3. HTTP/HTTPS URL - downloaded and parsed\n *\n * Detection priority:\n * 1. URL (http://, https://) → download and parse\n * 2. Existing file path → read and parse\n * 3. Valid JSON string → parse directly\n * 4. Simple string → treat as {name: string} for backward compatibility\n *\n * @param source - JSON string, file path, or URL\n * @param options - Optional configuration\n * @param options.name - Parameter name for error messages (e.g., \"event\", \"config\")\n * @param options.required - Throw error if source is empty (default: false)\n * @param options.fallback - Default value if source is empty\n * @returns Parsed JSON object\n * @throws Error if source is required but empty, or if loading/parsing fails\n *\n * @example\n * ```typescript\n * // Inline JSON\n * await loadJsonFromSource('{\"name\":\"order complete\",\"data\":{}}')\n *\n * // File path\n * await loadJsonFromSource('./examples/event.json')\n *\n * // URL\n * await loadJsonFromSource('https://example.com/event.json')\n *\n * // With options\n * await loadJsonFromSource(input, {\n * name: 'event',\n * required: true,\n * fallback: { name: 'default' }\n * })\n * ```\n */\nexport async function loadJsonFromSource<T = unknown>(\n source: string | undefined,\n options?: {\n name?: string;\n required?: boolean;\n fallback?: T;\n },\n): Promise<T> {\n const paramName = options?.name || 'input';\n\n // 1. Handle empty/undefined input (pre-check)\n if (!source || source.trim() === '') {\n if (options?.required) throw new Error(`${paramName} is required`);\n if (options?.fallback !== undefined) return options.fallback;\n return {} as T;\n }\n\n // 2. Try the strict loader (handles URL, file, inline JSON)\n try {\n return await loadJsonConfig<T>(source);\n } catch (error) {\n const trimmed = source.trim();\n\n // 3. Not JSON-looking? Treat as event name (backward compat)\n if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {\n return { name: trimmed } as T;\n }\n\n // 4. JSON-looking but invalid -- re-throw with context\n throw new Error(\n `Failed to parse ${paramName}. ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n}\n","function isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\n/**\n * Why a request did not reach its host: `timeout after <ms> ms`, or the\n * network error with its code, such as `fetch failed (ECONNREFUSED)`. Read by\n * shape, not instanceof: an abort's DOMException can come from another realm.\n */\nexport function fetchFailureReason(error: unknown, timeoutMs?: number): string {\n if (!isRecord(error)) return String(error);\n if (error.name === 'TimeoutError')\n return timeoutMs === undefined\n ? 'timeout'\n : `timeout after ${timeoutMs} ms`;\n const message =\n typeof error.message === 'string' ? error.message : String(error);\n const cause = error.cause;\n const code =\n isRecord(cause) && typeof cause.code === 'string' ? cause.code : undefined;\n return code ? `${message} (${code})` : message;\n}\n","export { getErrorMessage } from '@walkeros/core';\n","import path from 'path';\nimport fs from 'fs-extra';\nimport type { Logger } from '@walkeros/core';\n\nexport type LocalPackageInfo =\n | { name: string; absolutePath: string; type: 'file' }\n | { name: string; absolutePath: string; type: 'directory' }\n | {\n name: string;\n absolutePath: string;\n type: 'package';\n distPath: string;\n hasDistFolder: boolean;\n };\n\n/**\n * Resolve and validate a local package path.\n *\n * Handles three cases:\n * 1. Single file (with or without extension) → type: 'file'\n * 2. Directory without package.json → type: 'directory'\n * 3. Directory with package.json → type: 'package' (existing behavior)\n */\nexport async function resolveLocalPackage(\n packageName: string,\n localPath: string,\n configDir: string,\n logger: Logger.Instance,\n): Promise<LocalPackageInfo> {\n // Resolve relative to config file directory\n const absolutePath = path.isAbsolute(localPath)\n ? localPath\n : path.resolve(configDir, localPath);\n\n const stat = await fs.stat(absolutePath).catch(() => null);\n\n // Case 1a: Direct file reference (e.g., ./src/decoder.ts)\n if (stat?.isFile()) {\n return { name: packageName, absolutePath, type: 'file' };\n }\n\n // Case 1b: Try with extensions (e.g., ./src/decoder → ./src/decoder.ts)\n if (!stat) {\n for (const ext of ['.ts', '.mjs', '.js', '.json']) {\n const withExt = absolutePath + ext;\n if (await fs.pathExists(withExt)) {\n return { name: packageName, absolutePath: withExt, type: 'file' };\n }\n }\n throw new Error(\n `Local package path not found: ${localPath} (resolved to ${absolutePath})`,\n );\n }\n\n // Path is a directory\n if (stat.isDirectory()) {\n const hasPkgJson = await fs.pathExists(\n path.join(absolutePath, 'package.json'),\n );\n\n if (hasPkgJson) {\n // Case 3: Full package (existing behavior)\n const distPath = path.join(absolutePath, 'dist');\n const hasDistFolder = await fs.pathExists(distPath);\n\n if (!hasDistFolder) {\n logger.warn(\n `⚠️ ${packageName}: No dist/ folder found. Using package root.`,\n );\n }\n\n return {\n name: packageName,\n absolutePath,\n type: 'package',\n distPath: hasDistFolder ? distPath : absolutePath,\n hasDistFolder,\n };\n }\n\n // Case 2: Directory without package.json\n return { name: packageName, absolutePath, type: 'directory' };\n }\n\n throw new Error(\n `Local package path not found: ${localPath} (resolved to ${absolutePath})`,\n );\n}\n\n/**\n * Copy local package to target node_modules directory.\n *\n * Handles three cases:\n * - file: Copy as index.{ext} with generated package.json\n * - directory: Copy contents with generated package.json\n * - package: Existing behavior (copy package.json + dist/)\n */\nexport async function copyLocalPackage(\n localPkg: LocalPackageInfo,\n targetDir: string,\n logger: Logger.Instance,\n): Promise<string> {\n const packageDir = path.join(targetDir, 'node_modules', localPkg.name);\n\n if (localPkg.type === 'file') {\n await fs.ensureDir(packageDir);\n\n // Copy the single file as index (esbuild will resolve it)\n const ext = path.extname(localPkg.absolutePath);\n await fs.copy(localPkg.absolutePath, path.join(packageDir, `index${ext}`));\n\n // Create minimal package.json for module resolution\n await fs.writeJson(path.join(packageDir, 'package.json'), {\n name: localPkg.name,\n main: `./index${ext}`,\n });\n\n logger.info(\n `📦 Using local file: ${localPkg.name} from ${localPkg.absolutePath}`,\n );\n return packageDir;\n }\n\n if (localPkg.type === 'directory') {\n await fs.ensureDir(path.dirname(packageDir));\n\n // Copy directory contents (excluding node_modules etc.)\n const entries = await fs.readdir(localPkg.absolutePath);\n for (const entry of entries) {\n if (!['node_modules', '.turbo', '.git'].includes(entry)) {\n await fs.copy(\n path.join(localPkg.absolutePath, entry),\n path.join(packageDir, entry),\n );\n }\n }\n\n // Generate minimal package.json for module resolution\n await fs.writeJson(path.join(packageDir, 'package.json'), {\n name: localPkg.name,\n main: './index.ts',\n });\n\n logger.info(\n `📦 Using local dir: ${localPkg.name} from ${localPkg.absolutePath}`,\n );\n return packageDir;\n }\n\n // type === 'package': Existing behavior\n await fs.ensureDir(path.dirname(packageDir));\n\n // Always copy package.json for module resolution\n await fs.copy(\n path.join(localPkg.absolutePath, 'package.json'),\n path.join(packageDir, 'package.json'),\n );\n\n // Copy dist folder AS dist folder (preserving structure for exports like ./dist/index.mjs)\n if (localPkg.hasDistFolder) {\n await fs.copy(localPkg.distPath, path.join(packageDir, 'dist'));\n } else {\n // No dist folder - copy package root contents (excluding node_modules, etc.)\n const entries = await fs.readdir(localPkg.absolutePath);\n for (const entry of entries) {\n if (!['node_modules', '.turbo', '.git'].includes(entry)) {\n await fs.copy(\n path.join(localPkg.absolutePath, entry),\n path.join(packageDir, entry),\n );\n }\n }\n }\n\n logger.info(`📦 Using local: ${localPkg.name} from ${localPkg.absolutePath}`);\n\n return packageDir;\n}\n","/**\n * Input Detector\n *\n * Detects whether CLI input is a config JSON or pre-built bundle.\n * Supports both local files and URLs.\n */\n\nimport fs from 'fs-extra';\nimport { fetchContentString, isUrl } from '../config/utils.js';\n\nexport type Platform = 'web' | 'server';\n\nexport type DetectedInput =\n | { type: 'config'; content: string }\n | { type: 'bundle'; content: string; platform: Platform };\n\n/**\n * Detect if input is config JSON or pre-built bundle.\n *\n * Detection: Try JSON.parse, if fails = bundle\n * Platform: .mjs = server, .js = web\n *\n * @param inputPath - Path to file or URL\n * @param platformOverride - Optional platform override\n * @returns Detected input type with content\n */\nexport async function detectInput(\n inputPath: string,\n platformOverride?: Platform,\n): Promise<DetectedInput> {\n // Load content (URL or local file)\n const content = await loadContent(inputPath);\n\n // Try parsing as JSON\n try {\n JSON.parse(content);\n return { type: 'config', content };\n } catch {\n // Not JSON, treat as bundle\n const platform = platformOverride ?? detectPlatformFromPath(inputPath);\n return { type: 'bundle', content, platform };\n }\n}\n\n/**\n * Detect platform from file extension.\n *\n * @param inputPath - Path to file or URL\n * @returns Platform based on extension (.mjs = server, .js = web)\n */\nexport function detectPlatformFromPath(inputPath: string): Platform {\n // Remove query params for URLs\n const cleanPath = inputPath.split('?')[0];\n return cleanPath.endsWith('.mjs') ? 'server' : 'web';\n}\n\n/**\n * Load content from URL or local file.\n *\n * @param inputPath - Path to file or URL\n * @returns File content as string\n */\nasync function loadContent(inputPath: string): Promise<string> {\n if (isUrl(inputPath)) {\n return fetchContentString(inputPath);\n }\n // Inline JSON passthrough: JS bundles never start with { or [\n const trimmed = inputPath.trim();\n if (trimmed.startsWith('{') || trimmed.startsWith('[')) {\n return trimmed;\n }\n\n return fs.readFile(inputPath, 'utf8');\n}\n","import fs from 'fs-extra';\nimport path from 'path';\nimport { getTmpPath } from './tmp.js';\n\nexport function isStdinPiped(): boolean {\n return !process.stdin.isTTY;\n}\n\nexport async function readStdin(\n stream: NodeJS.ReadableStream = process.stdin,\n): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n // A stream may yield strings as well as buffers.\n chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : 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/**\n * Read stdin content and write to a labeled temp file.\n * Returns the temp file path for downstream functions that expect file paths.\n */\nexport async function readStdinToTempFile(label: string): Promise<string> {\n const content = await readStdin();\n const tmpPath = getTmpPath(undefined, `stdin-${label}.json`);\n await fs.ensureDir(path.dirname(tmpPath));\n await fs.writeFile(tmpPath, content, 'utf-8');\n return tmpPath;\n}\n","import { z } from 'zod';\nimport { requireSecureUrl } from '../lib/secure-url.js';\nimport { appErrorMessage, appFetch } from './app-fetch.js';\nimport { APP_PATHS } from './app-paths.js';\n\n/**\n * OAuth 2.1 client for the walkerOS authorization server.\n *\n * Pure HTTP with `fetch` injected: nothing here reads the config file or the\n * environment, so the flows can be exercised without a machine state.\n */\n\n/** Public client id seeded for the CLI. It has no secret. */\nexport const CLI_CLIENT_ID = 'walkeros-cli';\n\n/**\n * `offline_access` is what buys the refresh token; without it every command\n * would send the person back to the browser once the access token expired.\n */\nexport const CLI_SCOPE = 'read write offline_access';\n\nconst DEVICE_CODE_GRANT = 'urn:ietf:params:oauth:grant-type:device_code';\n\n/**\n * Ceiling on a refresh request. It is deliberately below the 15 s after which\n * `withConfigLock` treats a lock as abandoned: a refresh runs while holding\n * that lock, so a request allowed to hang longer would have its own lock\n * broken out from under it and race the process that took it next.\n */\nconst REFRESH_TIMEOUT_MS = 10_000;\n\n/**\n * Ceiling on a revocation. Nothing waits on its answer, so this only bounds\n * how long a logout stands still before clearing the machine.\n */\nconst REVOKE_TIMEOUT_MS = 5_000;\n\n/**\n * Ceiling on the request that opens a device authorization. Nothing has been\n * issued yet, so this only bounds how long `walkeros auth login` stands still\n * before it can show a code, but a server that accepts the connection and then\n * says nothing would otherwise hold it for the HTTP client's own default.\n */\nconst DEVICE_AUTHORIZATION_TIMEOUT_MS = 10_000;\n\nconst DeviceAuthorizationSchema = z.object({\n device_code: z.string().min(1),\n user_code: z.string().min(1),\n verification_uri: z.string().min(1),\n verification_uri_complete: z.string().min(1).optional(),\n expires_in: z.number().int().nonnegative(),\n interval: z.number().int().nonnegative(),\n});\n\nconst TokenSchema = z.object({\n access_token: z.string().min(1),\n expires_in: z.number().int().nonnegative(),\n refresh_token: z.string().min(1).optional(),\n});\n\nconst ErrorSchema = z.object({\n error: z.string().min(1),\n error_description: z.string().optional(),\n});\n\nexport interface DeviceAuthorization {\n deviceCode: string;\n userCode: string;\n verificationUri: string;\n verificationUriComplete: string;\n expiresIn: number;\n interval: number;\n}\n\nexport interface TokenSet {\n accessToken: string;\n accessTokenExpiresAt: string;\n refreshToken: string | null;\n}\n\nexport type DevicePoll =\n | { status: 'ok'; tokens: TokenSet }\n | { status: 'pending' }\n | { status: 'slow_down' }\n | { status: 'denied' }\n | { status: 'expired' }\n | { status: 'error'; error: string };\n\n/** Parse a response body as JSON, or null when it is not JSON at all. */\nasync function readJson(response: Response): Promise<unknown> {\n try {\n return await response.json();\n } catch {\n return null;\n }\n}\n\n/**\n * The RFC 6749 section 5.2 error code carried by a failed response, or null\n * when the body is not an OAuth error (a proxy's HTML, say).\n */\nfunction errorCode(body: unknown): string | null {\n const parsed = ErrorSchema.safeParse(body);\n return parsed.success ? parsed.data.error : null;\n}\n\n/**\n * The OAuth error first, then the app's own error envelope (a version floor\n * answers with one), then the bare status.\n */\nfunction describe(response: Response, body: unknown): string {\n const parsed = ErrorSchema.safeParse(body);\n if (parsed.success) {\n return parsed.data.error_description\n ? `${parsed.data.error}: ${parsed.data.error_description}`\n : parsed.data.error;\n }\n return appErrorMessage(body) ?? `HTTP ${response.status}`;\n}\n\n/**\n * Every request in this module either carries a credential or mints one, so\n * the two rules that protect one are applied here rather than per call:\n * plain http is refused off the local machine, and a redirect is an error\n * rather than a hop, because following one would hand the token (or the code\n * that buys it) to whichever host the answer named.\n */\nfunction postForm(\n appUrl: string,\n path: string,\n form: Record<string, string>,\n fetchFn: typeof fetch,\n signal?: AbortSignal,\n): Promise<Response> {\n return appFetch(path, {\n method: 'POST',\n baseUrl: requireSecureUrl(appUrl),\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams(form).toString(),\n redirect: 'error',\n fetch: fetchFn,\n signal,\n });\n}\n\nfunction toTokenSet(body: unknown): TokenSet {\n const parsed = TokenSchema.safeParse(body);\n if (!parsed.success) throw new Error('Malformed token response');\n\n return {\n accessToken: parsed.data.access_token,\n accessTokenExpiresAt: new Date(\n Date.now() + parsed.data.expires_in * 1000,\n ).toISOString(),\n refreshToken: parsed.data.refresh_token ?? null,\n };\n}\n\n/**\n * RFC 8628 section 3.1. Ask for a device code and the URL to send the person\n * to. Unauthenticated: the code is worth nothing until somebody approves it.\n */\nexport async function startDeviceAuthorization(\n appUrl: string,\n fetchFn: typeof fetch = globalThis.fetch,\n): Promise<DeviceAuthorization> {\n const response = await postForm(\n appUrl,\n APP_PATHS.deviceAuthorization,\n {\n client_id: CLI_CLIENT_ID,\n scope: CLI_SCOPE,\n // RFC 8707. The token comes back bound to the API, so a leaked CLI token\n // cannot be replayed against the MCP resource.\n resource: `${appUrl}/api`,\n },\n fetchFn,\n AbortSignal.timeout(DEVICE_AUTHORIZATION_TIMEOUT_MS),\n );\n\n const body = await readJson(response);\n if (!response.ok) throw new Error(describe(response, body));\n\n const parsed = DeviceAuthorizationSchema.safeParse(body);\n if (!parsed.success)\n throw new Error('Malformed device authorization response');\n\n return {\n deviceCode: parsed.data.device_code,\n userCode: parsed.data.user_code,\n verificationUri: parsed.data.verification_uri,\n verificationUriComplete:\n parsed.data.verification_uri_complete ?? parsed.data.verification_uri,\n expiresIn: parsed.data.expires_in,\n interval: parsed.data.interval,\n };\n}\n\n/**\n * One poll of RFC 8628 section 3.4. Every outcome is a returned status rather\n * than a throw, because four of them are ordinary steps of a flow that is\n * still running.\n *\n * `signal` is how a caller keeps its own deadline: without one, a server that\n * accepts the connection and then says nothing holds this call for the HTTP\n * client's default, which is minutes.\n */\nexport async function pollDeviceToken(\n appUrl: string,\n deviceCode: string,\n fetchFn: typeof fetch = globalThis.fetch,\n signal?: AbortSignal,\n): Promise<DevicePoll> {\n let response: Response;\n try {\n response = await postForm(\n appUrl,\n APP_PATHS.token,\n {\n grant_type: DEVICE_CODE_GRANT,\n device_code: deviceCode,\n client_id: CLI_CLIENT_ID,\n },\n fetchFn,\n signal,\n );\n } catch (error) {\n // Only an abort of the caller's own signal is an outcome rather than a\n // fault: the authorization is untouched, so it is still pending and the\n // caller's loop decides whether there is room for another attempt. Any\n // other transport failure is a real error and stays one.\n if (signal?.aborted) return { status: 'pending' };\n throw error;\n }\n\n const body = await readJson(response);\n\n if (response.ok) {\n try {\n return { status: 'ok', tokens: toTokenSet(body) };\n } catch (error) {\n return {\n status: 'error',\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n switch (errorCode(body)) {\n case 'authorization_pending':\n return { status: 'pending' };\n case 'slow_down':\n return { status: 'slow_down' };\n case 'access_denied':\n return { status: 'denied' };\n case 'expired_token':\n return { status: 'expired' };\n default:\n return { status: 'error', error: describe(response, body) };\n }\n}\n\n/**\n * Spend a refresh token for a new pair.\n *\n * `null` means the server rejected the token itself and only a fresh login\n * can recover. Every other failure throws, so a transient fault stays\n * distinguishable from a dead session and never costs the person their login.\n */\nexport async function refreshTokens(\n appUrl: string,\n refreshToken: string,\n fetchFn: typeof fetch = globalThis.fetch,\n): Promise<TokenSet | null> {\n const response = await postForm(\n appUrl,\n APP_PATHS.token,\n {\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: CLI_CLIENT_ID,\n },\n fetchFn,\n AbortSignal.timeout(REFRESH_TIMEOUT_MS),\n );\n\n const body = await readJson(response);\n\n if (!response.ok) {\n if (errorCode(body) === 'invalid_grant') return null;\n throw new Error(describe(response, body));\n }\n\n return toTokenSet(body);\n}\n\n/**\n * RFC 7009. Best effort by design: logout must clear the local config whether\n * or not the server could be reached, and the server answers a revocation it\n * cannot act on with 200 anyway.\n */\nexport async function revokeRefreshToken(\n appUrl: string,\n refreshToken: string,\n fetchFn: typeof fetch = globalThis.fetch,\n): Promise<void> {\n try {\n await postForm(\n appUrl,\n APP_PATHS.revoke,\n {\n token: refreshToken,\n token_type_hint: 'refresh_token',\n client_id: CLI_CLIENT_ID,\n },\n fetchFn,\n AbortSignal.timeout(REVOKE_TIMEOUT_MS),\n );\n } catch {\n // Offline, or the server is down. The local credential is still cleared.\n }\n}\n","import { z } from 'zod';\nimport { resolveAppUrl } from '../lib/config-file.js';\nimport { requireSecureUrl } from '../lib/secure-url.js';\nimport { clientContextHeaders } from './client-context.js';\n\nexport interface AppFetchInit {\n method?: string;\n /** The app, default `resolveAppUrl()`; trailing slashes are trimmed. */\n baseUrl?: string;\n /** Sent as `Authorization: Bearer <token>` unless the caller set Authorization. */\n token?: string | null;\n headers?: Readonly<Record<string, string>>;\n body?: string;\n signal?: AbortSignal;\n redirect?: RequestRedirect;\n fetch?: typeof fetch;\n}\n\nconst AppErrorSchema = z.object({\n error: z.object({ message: z.string().min(1) }),\n});\n\n/** The message of the app's error envelope `{ error: { message } }`, or undefined. */\nexport function appErrorMessage(body: unknown): string | undefined {\n const parsed = AppErrorSchema.safeParse(body);\n return parsed.success ? parsed.data.error.message : undefined;\n}\n\n/**\n * Call the walkerOS app. Every request carries the client-context headers\n * (`User-Agent`, `X-WalkerOS-Client`, `X-WalkerOS-Client-Version`); caller\n * headers win over them; a request carrying Authorization goes only to a\n * secure URL (`requireSecureUrl`). `path` starts with `/` and may carry a query.\n */\nexport async function appFetch(\n path: string,\n init: AppFetchInit = {},\n): Promise<Response> {\n const url = `${(init.baseUrl ?? resolveAppUrl()).replace(/\\/+$/, '')}${path}`;\n const headers = new Headers(clientContextHeaders());\n for (const [name, value] of Object.entries(init.headers ?? {}))\n headers.set(name, value);\n if (init.token && !headers.has('Authorization'))\n headers.set('Authorization', `Bearer ${init.token}`);\n if (headers.has('Authorization')) requireSecureUrl(url);\n const request: RequestInit = { headers };\n if (init.method && init.method !== 'GET') request.method = init.method;\n if (init.body !== undefined) request.body = init.body;\n if (init.signal) request.signal = init.signal;\n if (init.redirect) request.redirect = init.redirect;\n return (init.fetch ?? fetch)(url, request);\n}\n","import { schemas } from '@walkeros/core/dev';\n\nconst { PartialEventSchema } = schemas;\n\nexport type ValidationLevel = 'strict' | 'standard' | 'minimal';\n\nexport type EventValidationCode =\n | 'NOT_AN_OBJECT'\n | 'MISSING_EVENT_NAME'\n | 'EMPTY_EVENT_NAME'\n | 'INVALID_EVENT_NAME'\n | 'SCHEMA_VALIDATION';\n\nexport interface EventValidationError {\n path: string;\n message: string;\n value?: unknown;\n code: EventValidationCode;\n}\n\nexport interface EventValidationWarning {\n path: string;\n message: string;\n suggestion?: string;\n}\n\nexport interface EventValidationDetails {\n entity?: string | null;\n action?: string | null;\n hasConsent?: boolean;\n hasData?: boolean;\n hasContext?: boolean;\n}\n\nexport interface EventValidationResult {\n valid: boolean;\n errors: EventValidationError[];\n warnings: EventValidationWarning[];\n details: EventValidationDetails;\n}\n\nexport function validateEvent(\n input: unknown,\n level: ValidationLevel = 'strict',\n): EventValidationResult {\n const errors: EventValidationError[] = [];\n const warnings: EventValidationWarning[] = [];\n const details: EventValidationDetails = {};\n\n // All levels: must be an object\n if (typeof input !== 'object' || input === null || Array.isArray(input)) {\n errors.push({\n path: 'root',\n message: 'Event must be an object',\n code: 'NOT_AN_OBJECT',\n });\n return { valid: false, errors, warnings, details };\n }\n\n const event = input as Record<string, unknown>;\n\n // All levels: name field checks\n if (!('name' in event) || event.name === undefined) {\n errors.push({\n path: 'name',\n message: 'Event must have a name field',\n code: 'MISSING_EVENT_NAME',\n });\n } else if (typeof event.name !== 'string' || event.name.trim() === '') {\n errors.push({\n path: 'name',\n message: 'Event name cannot be empty',\n value: event.name,\n code: 'EMPTY_EVENT_NAME',\n });\n } else {\n // Entity-action format check (strict + standard only)\n const name = event.name;\n if (!name.includes(' ')) {\n if (level === 'strict') {\n errors.push({\n path: 'name',\n message:\n 'Event name must be \"entity action\" format with space (e.g., \"page view\")',\n value: name,\n code: 'INVALID_EVENT_NAME',\n });\n details.entity = null;\n details.action = null;\n } else if (level === 'standard') {\n warnings.push({\n path: 'name',\n message: `Event name \"${name}\" should follow \"ENTITY ACTION\" format (e.g., \"page view\")`,\n });\n details.entity = null;\n details.action = null;\n }\n // minimal: skip entirely\n } else {\n const parts = name.trim().split(/\\s+/);\n const action = parts.pop()!;\n const entity = parts.join(' ');\n details.entity = entity;\n details.action = action;\n }\n }\n\n // Minimal stops here\n if (level === 'minimal') {\n return { valid: errors.length === 0, errors, warnings, details };\n }\n\n // Standard + Strict: Zod schema validation\n const zodResult = PartialEventSchema.safeParse(input);\n if (!zodResult.success) {\n for (const issue of zodResult.error.issues) {\n const issuePath = issue.path.join('.');\n if (issuePath === 'name') continue; // handled above with better messages\n errors.push({\n path: issuePath || 'root',\n message: issue.message,\n code: 'SCHEMA_VALIDATION',\n });\n }\n }\n\n // Strict only: consent warning + details\n if (level === 'strict') {\n if (!event.consent) {\n warnings.push({\n path: 'consent',\n message: 'No consent object provided',\n suggestion:\n 'Consider adding a consent object for GDPR/privacy compliance',\n });\n }\n details.hasConsent = !!event.consent;\n details.hasData = !!event.data;\n details.hasContext = !!event.context;\n }\n\n return { valid: errors.length === 0, errors, warnings, details };\n}\n","/**\n * Configuration Type Guards and Validators\n *\n * Type checking utilities for configuration validation.\n * Uses Zod schemas from @walkeros/core for Flow.Json validation.\n */\n\nimport type { Flow } from '@walkeros/core';\nimport { isObject } from '@walkeros/core';\nimport { schemas } from '@walkeros/core/dev';\n\nconst { safeParseConfig } = schemas;\n\n/**\n * Detect platform from a single flow.\n *\n * Platform is determined by `flow.config.platform`.\n */\nexport function detectPlatform(\n flow: Record<string, unknown>,\n): 'web' | 'server' | undefined {\n const config = flow.config;\n if (!isObject(config)) return undefined;\n const platform = config.platform;\n if (platform === 'web' || platform === 'server') return platform;\n return undefined;\n}\n\n/**\n * Type guard: Check if config is a valid Flow.Json structure.\n *\n * @remarks\n * Uses Zod validation from @walkeros/core.\n * Returns false instead of throwing on invalid input.\n *\n * @example\n * ```typescript\n * if (isFlowConfig(config)) {\n * const flowSettings = getFlowSettings(config, 'production');\n * }\n * ```\n */\nexport function isFlowConfig(data: unknown): data is Flow.Json {\n const result = safeParseConfig(data);\n return result.success;\n}\n\n/**\n * Validate Flow.Json and throw descriptive error if invalid.\n *\n * @remarks\n * Uses Zod validation from @walkeros/core.\n * Provides detailed error messages from Zod.\n *\n * @param data - Raw configuration data\n * @returns Validated Flow.Json\n * @throws Error with descriptive message if validation fails\n */\nexport function validateFlowConfig(data: unknown): Flow.Json {\n // After successful Zod parse, the data conforms structurally to Flow.Json.\n // The existing `isFlowConfig` guard re-narrows `unknown` to `Flow.Json` via\n // the same schema — TS can't see through `safeParseConfig` because it\n // returns a Zod-inferred type that differs nominally (not structurally)\n // from the Flow.Json interface.\n if (isFlowConfig(data)) return data;\n\n // Not parseable — format Zod errors for CLI display.\n const result = safeParseConfig(data);\n if (result.success) {\n // Defensive: isFlowConfig and safeParseConfig disagreed (cannot happen).\n throw new Error('Invalid configuration: failed Flow.Json type guard.');\n }\n const errors = result.error.issues\n .map((issue) => {\n const path =\n issue.path.length > 0 ? issue.path.map(String).join('.') : 'root';\n return ` - ${path}: ${issue.message}`;\n })\n .join('\\n');\n throw new Error(`Invalid configuration:\\n${errors}`);\n}\n\n/**\n * Get available flow names from a Flow.Json.\n *\n * @param config - Flow.Json configuration\n * @returns Array of flow names\n */\nexport function getAvailableFlows(config: Flow.Json): string[] {\n return Object.keys(config.flows);\n}\n","/**\n * Configuration Loader\n *\n * Loads and parses Flow.Json configurations using core getFlowSettings().\n * Build options are determined by static platform defaults.\n */\n\nimport path from 'path';\nimport fs from 'fs-extra';\nimport { getFlowSettings, getPlatform, type Flow } from '@walkeros/core';\nimport type { BuildOptions } from '../types/bundle.js';\nimport {\n validateFlowConfig,\n isFlowConfig,\n getAvailableFlows as getFlowNames,\n} from './validators.js';\nimport { getBuildDefaults, getDefaultOutput } from './build-defaults.js';\nimport { isUrl, loadJsonConfig } from './utils.js';\nimport { configDigest } from '../core/content-digest.js';\nimport {\n assertWindowCollector,\n type WindowCollectorSource,\n} from './window-collector.js';\n\n/** Default folder for includes if it exists */\nconst DEFAULT_INCLUDE_FOLDER = './shared';\n\n/**\n * Result of configuration loading.\n */\nexport interface LoadConfigResult {\n /** Runtime event processing configuration (resolved single Flow) */\n flowSettings: Flow;\n /** Build-time configuration */\n buildOptions: BuildOptions;\n /** Name of the selected flow */\n flowName: string;\n /** Whether multiple flows are available */\n isMultiFlow: boolean;\n /** All available flow names */\n availableFlows: string[];\n /**\n * Digest of the deferred flow settings, the config input of the default\n * release. Never carries an env or secret value.\n */\n configDigest: string;\n}\n\n/**\n * Options for loading configuration.\n */\nexport interface LoadConfigOptions {\n /** Path to config file */\n configPath: string;\n /** Flow name to load (required for multi-flow, optional for single-flow) */\n flowName?: string;\n /** CLI build overrides (future: --output, --minify, etc.) */\n buildOverrides?: Partial<BuildOptions>;\n /**\n * Base environment for web `$env` resolution, layered BENEATH the flow's\n * declared `config.bundle.env`. Omitted, it is the shell's `process.env`\n * (local builds). Pass `{}` for a hermetic build that resolves against the\n * declared values alone. Server flows are unaffected: their `$env` is read\n * at runtime.\n */\n buildEnv?: Record<string, string | undefined>;\n /** Logger for warnings */\n logger?: {\n warn: (message: string) => void;\n info: (message: string) => void;\n };\n}\n\n/**\n * Load and parse bundle configuration.\n *\n * @remarks\n * Uses Flow.Json from @walkeros/core as the only config format.\n * - Validates config structure\n * - Uses core getFlowSettings() for variable/definition resolution\n * - Determines platform from resolved config\n * - Applies static build defaults based on platform\n *\n * @param rawConfig - Raw configuration object from JSON file\n * @param options - Loading options\n * @returns Parsed configuration with flow and build separated\n *\n * @example\n * ```typescript\n * const config = loadBundleConfig(rawConfig, {\n * configPath: './walkeros.config.json',\n * flowName: 'production',\n * });\n * ```\n */\nexport function loadBundleConfig(\n rawConfig: unknown,\n options: LoadConfigOptions,\n): LoadConfigResult {\n // Pre-validation scan: detect the legacy `flow.config.bundle.external`\n // field and strip it before schema validation. The strict Bundle schema\n // rejects unknown keys, so without this step the config would fail to\n // load with a confusing error. Emit a deprecation warning instead.\n const sanitized = stripLegacyBundleExternal(rawConfig, options.logger);\n\n // Validate as Flow.Json\n const config = validateFlowConfig(sanitized);\n const availableFlows = getFlowNames(config);\n\n // Determine which flow to use\n const flowName = resolveFlow(config, options.flowName, availableFlows);\n\n assertLiteralBuildEnv(config, flowName);\n\n // Resolve with deferred mode first (markers don't affect platform detection)\n let flowSettings = getFlowSettings(config, flowName, { deferred: true });\n const platform = getPlatform(flowSettings);\n const flowConfigDigest = configDigest(flowSettings, flowName);\n if (!platform) {\n throw new Error(\n `Invalid configuration: flow \"${flowName}\" must have config.platform set to \"web\" or \"server\".`,\n );\n }\n\n // For web: re-resolve without deferred to bake values at build time. The\n // values come from an explicit map, never from an ambient read, so a build\n // inside a process holding its own secrets cannot inline them.\n if (platform === 'web') {\n flowSettings = getFlowSettings(config, flowName, {\n env: resolveBuildEnv(flowSettings.config?.bundle?.env, options.buildEnv),\n });\n }\n\n // Auto-inject validator transformers for any step-level `validate?:`\n // Get static build defaults based on platform\n const buildDefaults = getBuildDefaults(platform);\n\n // Extract packages + overrides + traceInclude from the canonical\n // `flow.<name>.config.bundle.{packages, overrides, traceInclude}` location.\n //\n // The `config.bundle.external` sub-field is no longer supported (replaced\n // by nft tracing); it is warned about and stripped pre-validation in\n // `stripLegacyBundleExternal` so it does not surface here.\n const bundle = flowSettings.config?.bundle;\n const packages: Record<string, Flow.BundlePackage> = bundle?.packages ?? {};\n const overrides: Record<string, string> = bundle?.overrides ?? {};\n const traceInclude = bundle?.traceInclude;\n\n // Output path: use --output if provided, otherwise default\n // Always relative to cwd, no dynamic resolution\n const output = options.buildOverrides?.output || getDefaultOutput(platform);\n\n // Get config directory for resolving includes and local packages\n // For URLs, use cwd since there's no local config directory\n const configDir = isUrl(options.configPath)\n ? process.cwd()\n : path.dirname(options.configPath);\n\n // Get includes from config or use default if ./shared exists\n let includes = config.include;\n if (!includes) {\n const defaultIncludePath = path.resolve(configDir, DEFAULT_INCLUDE_FOLDER);\n if (fs.pathExistsSync(defaultIncludePath)) {\n includes = [DEFAULT_INCLUDE_FOLDER];\n }\n }\n\n // Merge build options: defaults + flow settings + CLI overrides\n const buildOptions: BuildOptions = {\n ...buildDefaults,\n ...settingsToBuildOptions(platform, flowSettings.config?.settings, {\n path: `flows.${flowName}.config.settings.windowCollector`,\n written: config.flows[flowName]?.config?.settings?.windowCollector,\n }),\n packages,\n overrides,\n traceInclude,\n output,\n include: includes,\n configDir,\n ...options.buildOverrides,\n };\n\n // Log flow selection\n const isMultiFlow = availableFlows.length > 1;\n if (isMultiFlow && options.logger) {\n options.logger.info(\n `📦 Using flow: ${flowName} (${availableFlows.length} total)`,\n );\n }\n\n return {\n flowSettings,\n buildOptions,\n flowName,\n isMultiFlow,\n availableFlows,\n configDigest: flowConfigDigest,\n };\n}\n\n/**\n * The build options a flow's `config.settings` controls. Each key is mapped\n * explicitly, so an unknown settings key never reaches generated code.\n *\n * - `windowCollector` (web): the global the collector instance is assigned\n * to. It is interpolated into the generated entry, so the resolved value\n * must be a JavaScript identifier.\n */\nexport function settingsToBuildOptions(\n platform: 'web' | 'server',\n settings: Flow.Settings | undefined,\n source: WindowCollectorSource = {},\n): Pick<BuildOptions, 'windowCollector'> {\n if (platform !== 'web' || settings?.windowCollector === undefined) return {};\n return {\n windowCollector: assertWindowCollector(settings.windowCollector, source),\n };\n}\n\n/** Any reference or marker the resolver would act on inside a string. */\nconst REFERENCE_PATTERN =\n /\\$(?:env|var|secret|flow|contract)\\.|\\$code:|__WALKEROS_(?:ENV|SECRET):/;\n\n/**\n * `config.bundle.env` values are the declared build values themselves, so\n * each must be a literal string. A reference there would be resolved (or\n * turned into a runtime marker) instead of declared, so it is refused. The\n * message names keys only, never values.\n */\nfunction assertLiteralBuildEnv(config: Flow.Json, flowName: string): void {\n const declared = config.flows[flowName]?.config?.bundle?.env;\n if (!declared) return;\n const refs = Object.entries(declared)\n .filter(([, value]) => REFERENCE_PATTERN.test(value))\n .map(([key]) => key);\n if (refs.length > 0) {\n throw new Error(\n `config.bundle.env values must be literal strings; references are not allowed in: ${refs.join(', ')}`,\n );\n }\n}\n\n/**\n * The map web `$env` references resolve against: the base environment\n * (`process.env` unless the caller passes one) with the flow's declared\n * `config.bundle.env` on top.\n */\nexport function resolveBuildEnv(\n declared: Record<string, string> | undefined,\n base: Record<string, string | undefined> = process.env,\n): Record<string, string | undefined> {\n return { ...base, ...(declared ?? {}) };\n}\n\n/**\n * Resolve which flow to use.\n *\n * @param config - Flow.Json configuration\n * @param requestedFlow - Flow name from CLI (optional)\n * @param available - Available flow names\n * @returns Flow name to use\n * @throws Error if flow selection is invalid\n */\nfunction resolveFlow(\n config: Flow.Json,\n requestedFlow: string | undefined,\n available: string[],\n): string {\n // If only one flow, use it automatically\n if (available.length === 1) {\n return available[0];\n }\n\n // Multiple flows require explicit selection\n if (!requestedFlow) {\n throw new Error(\n `Multiple flows found. Please specify a flow using --flow flag.\\n` +\n `Available flows: ${available.join(', ')}`,\n );\n }\n\n // Validate the requested flow exists\n if (!available.includes(requestedFlow)) {\n throw new Error(\n `Flow \"${requestedFlow}\" not found in configuration.\\n` +\n `Available flows: ${available.join(', ')}`,\n );\n }\n\n return requestedFlow;\n}\n\n/**\n * Load all flows from a configuration.\n *\n * @remarks\n * Used by the --all flag to build all flows.\n *\n * @param rawConfig - Raw configuration object\n * @param options - Loading options (without flowName)\n * @returns Array of loaded configurations for all flows\n */\nexport function loadAllFlows(\n rawConfig: unknown,\n options: Omit<LoadConfigOptions, 'flowName'>,\n): LoadConfigResult[] {\n // Validate as Flow.Json\n const config = validateFlowConfig(rawConfig);\n const flows = getFlowNames(config);\n\n if (options.logger) {\n options.logger.info(\n `📦 Loading all ${flows.length} flows: ${flows.join(', ')}`,\n );\n }\n\n // Load each flow\n return flows.map((name) =>\n loadBundleConfig(rawConfig, {\n ...options,\n flowName: name,\n }),\n );\n}\n\n/**\n * Get list of available flows from configuration.\n *\n * @param rawConfig - Raw configuration object\n * @returns Array of flow names\n */\nexport function getAvailableFlows(rawConfig: unknown): string[] {\n if (isFlowConfig(rawConfig)) {\n return getFlowNames(rawConfig);\n }\n return [];\n}\n\n/**\n * Load flow configuration from file or URL.\n *\n * Single entry point for all commands (bundle, simulate, push).\n * Handles URL vs local path detection automatically.\n *\n * @param configPath - Path to config file or URL\n * @param options - Loading options (flowName, logger, buildOverrides)\n * @returns Parsed configuration with flow and build options\n *\n * @example\n * ```typescript\n * const { flowSettings, buildOptions } = await loadFlowConfig('./flow.json');\n * const { flowSettings } = await loadFlowConfig('https://example.com/flow.json');\n * ```\n */\nexport async function loadFlowConfig(\n configPath: string,\n options?: Omit<LoadConfigOptions, 'configPath'> & {\n /**\n * The config at `configPath`, already read by the caller: it is used\n * instead of reading the path again (`configPath` still anchors\n * relative paths).\n */\n raw?: unknown;\n },\n): Promise<LoadConfigResult> {\n const { raw, ...rest } = options ?? {};\n const rawConfig = raw !== undefined ? raw : await loadJsonConfig(configPath);\n return loadBundleConfig(rawConfig, { configPath, ...rest });\n}\n\n/**\n * Pre-validation pass: detect and strip the legacy\n * `flow.config.bundle.external` field. The strict Bundle schema rejects\n * unknown keys, so without this step a config containing the legacy\n * field would fail validation with a confusing error. Emit a one-time\n * deprecation warning per offending flow and return a sanitized clone.\n *\n * The clone is shallow at the levels we mutate (root, `flows`, each flow,\n * `config`, `bundle`); deeper structures are aliased into the clone, which\n * is fine because we only delete a top-level key on the bundle object.\n */\nfunction stripLegacyBundleExternal(\n rawConfig: unknown,\n logger: LoadConfigOptions['logger'],\n): unknown {\n if (!isPlainObject(rawConfig)) return rawConfig;\n const flows = rawConfig.flows;\n if (!isPlainObject(flows)) return rawConfig;\n\n let mutated: Record<string, unknown> | null = null;\n\n for (const [flowName, flowValue] of Object.entries(flows)) {\n if (!isPlainObject(flowValue)) continue;\n const flowConfig = flowValue.config;\n if (!isPlainObject(flowConfig)) continue;\n const bundle = flowConfig.bundle;\n if (!isPlainObject(bundle)) continue;\n if (!('external' in bundle)) continue;\n\n logger?.warn(\n `flow.config.bundle.external is no longer supported; @walkeros/cli@4.x traces server bundles automatically. Remove it from flows.${flowName}.config.bundle.`,\n );\n\n if (!mutated) {\n mutated = {\n ...rawConfig,\n flows: { ...flows },\n };\n }\n const mutatedFlows = mutated.flows as Record<string, unknown>;\n const newBundle = { ...bundle };\n delete newBundle.external;\n const newConfig = { ...flowConfig, bundle: newBundle };\n mutatedFlows[flowName] = { ...flowValue, config: newConfig };\n }\n\n return mutated ?? rawConfig;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","/**\n * Content digests for build cache keys and the default release id.\n *\n * Every input is content the bundler consumes: the deferred flow settings,\n * the resolved package set (local packages by the bytes of their installed\n * copy) and the CLI version. Environment and secret values are never inputs,\n * only their markers, so a digest leaks none of them.\n */\n\nimport { createHash } from 'node:crypto';\nimport path from 'path';\nimport fs from 'fs-extra';\nimport type { Flow } from '@walkeros/core';\n\nconst DIGEST_LENGTH = 12;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\n/** JSON with object keys sorted at every depth. Arrays keep their order. */\nexport function canonicalJson(value: unknown): string {\n return JSON.stringify(value, (_key, inner: unknown) => {\n if (!isRecord(inner)) return inner;\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(inner).sort()) sorted[key] = inner[key];\n return sorted;\n });\n}\n\n/**\n * Hash a flow's deferred settings (its `$env` and `$secret` references are\n * still markers). `collector.release` is left out and `collector.name`\n * defaults to the flow name, so the digest names the config the release is\n * derived from. Declared `config.bundle.env` values are reduced to their keys:\n * they are the values web `$env` references resolve to.\n */\nexport function configDigest(flowSettings: Flow, flowName: string): string {\n const collector: Record<string, unknown> = {\n ...(flowSettings.collector ?? {}),\n };\n delete collector.release;\n collector.name ??= flowName;\n\n const config = flowSettings.config;\n const declaredEnv = config?.bundle?.env;\n const hashedConfig =\n config && declaredEnv\n ? {\n ...config,\n bundle: { ...config.bundle, env: Object.keys(declaredEnv).sort() },\n }\n : config;\n\n return createHash('sha256')\n .update(canonicalJson({ ...flowSettings, config: hashedConfig, collector }))\n .digest('hex');\n}\n\n/**\n * Hash an installed package directory: every file by relative path and bytes,\n * a symlink by its target. Paths are sorted, so file system order and mtimes\n * never change the result.\n */\nexport async function hashInstalledDir(dir: string): Promise<string> {\n const hash = createHash('sha256');\n for (const rel of await listFiles(dir, '')) {\n const abs = path.join(dir, rel);\n const stat = await fs.lstat(abs);\n hash.update(`${rel}\\0`);\n hash.update(\n stat.isSymbolicLink() ? await fs.readlink(abs) : await fs.readFile(abs),\n );\n hash.update('\\0');\n }\n return hash.digest('hex').slice(0, DIGEST_LENGTH);\n}\n\nasync function listFiles(root: string, rel: string): Promise<string[]> {\n const entries = await fs.readdir(path.join(root, rel), {\n withFileTypes: true,\n });\n const files: string[] = [];\n for (const entry of entries) {\n const entryRel = rel ? `${rel}/${entry.name}` : entry.name;\n if (entry.isDirectory()) files.push(...(await listFiles(root, entryRel)));\n else files.push(entryRel);\n }\n return files.sort();\n}\n\nexport interface ReleaseDigestInput {\n /** {@link configDigest} of the flow. */\n configDigest: string;\n /** Sorted `name@version` lines, a local package as `name@local:<hash>`. */\n versions: string[];\n /** CLI version, since generated code changes with it. */\n toolchain: string;\n}\n\n/** Default release id: 12 lowercase hex over config, packages and CLI. */\nexport function releaseDigest(input: ReleaseDigestInput): string {\n return createHash('sha256')\n .update(\n canonicalJson({\n config: input.configDigest,\n versions: input.versions,\n toolchain: input.toolchain,\n }),\n )\n .digest('hex')\n .slice(0, DIGEST_LENGTH);\n}\n","import { checkWindowCollector } from '@walkeros/core';\n\n/** Where a collector global name came from, for the error message. */\nexport interface WindowCollectorSource {\n /** Setting path, e.g. `flows.web.config.settings.windowCollector`. */\n path?: string;\n /** The value as written, when it was a `$var` / `$env` reference. */\n written?: unknown;\n}\n\n/**\n * Return `value` as the collector global name, or throw when it is not a\n * JavaScript identifier or names a reserved global. The name is interpolated\n * into generated code, so every build path checks it before use.\n */\nexport function assertWindowCollector(\n value: unknown,\n source: WindowCollectorSource = {},\n): string {\n const check = checkWindowCollector(value);\n if (check.ok) return check.name;\n const path = source.path ?? 'config.settings.windowCollector';\n const subject =\n source.written !== undefined && source.written !== value\n ? `${JSON.stringify(source.written)} resolved to ${JSON.stringify(value)}, which`\n : JSON.stringify(value);\n throw new Error(`${path}: ${subject} ${check.reason}.`);\n}\n","import { isObject } from '@walkeros/core';\nimport type {\n ValidateResult,\n ValidationError,\n ValidationWarning,\n} from '../types.js';\n\nconst SECTION_KEYS = ['globals', 'context', 'custom', 'user', 'consent'];\nconst KNOWN_KEYS = new Set([\n 'extend',\n 'tagging',\n 'description',\n 'events',\n 'schema',\n ...SECTION_KEYS,\n]);\n\nexport function validateContract(input: unknown): ValidateResult {\n const errors: ValidationError[] = [];\n const warnings: ValidationWarning[] = [];\n const details: Record<string, unknown> = {};\n\n if (typeof input !== 'object' || input === null || Array.isArray(input)) {\n errors.push({\n path: 'root',\n message: 'Contract must be an object of named contract entries',\n code: 'INVALID_CONTRACT',\n });\n return { valid: false, type: 'contract', errors, warnings, details };\n }\n\n const contracts = input as Record<string, unknown>;\n const contractNames = Object.keys(contracts);\n details.contractCount = contractNames.length;\n\n // Check for $-prefixed root keys (flat app shape)\n for (const name of contractNames) {\n if (name.startsWith('$')) {\n errors.push({\n path: name,\n message:\n `\"${name}\" is not a named contract entry. This looks like the flat ` +\n 'shape; use named ContractRule entries, lift $tagging to the rule ' +\n 'field \"tagging\", and nest entity-action schemas under \"events\".',\n code: 'FLAT_CONTRACT_SHAPE',\n });\n }\n }\n\n // Check each named contract entry\n for (const [name, entry] of Object.entries(contracts)) {\n // Skip $-prefixed names (already reported above)\n if (name.startsWith('$')) {\n continue;\n }\n\n if (typeof entry !== 'object' || entry === null) {\n errors.push({\n path: name,\n message: `Contract \"${name}\" must be an object`,\n code: 'INVALID_CONTRACT_ENTRY',\n });\n continue;\n }\n\n const obj = entry as Record<string, unknown>;\n const keys = Object.keys(obj);\n const unknownKeys = keys.filter((k) => !KNOWN_KEYS.has(k));\n const hasKnownKey = keys.some((k) => KNOWN_KEYS.has(k));\n const objectValuedUnknown = unknownKeys.filter((k) => isObject(obj[k]));\n\n // Check for flat entity-action maps (object-valued keys without known keys)\n if (!hasKnownKey && objectValuedUnknown.length > 0) {\n errors.push({\n path: name,\n message:\n `Contract \"${name}\" looks like a flat entity-action map. Nest ` +\n 'entity-action schemas under an \"events\" key of a named ContractRule.',\n code: 'FLAT_CONTRACT_SHAPE',\n });\n continue;\n }\n\n // Warn on unknown keys\n for (const key of unknownKeys) {\n warnings.push({\n path: `${name}.${key}`,\n message: `Unknown contract key \"${key}\" is ignored`,\n code: 'UNKNOWN_CONTRACT_KEY',\n });\n }\n\n // Validate tagging\n if (obj.tagging !== undefined && typeof obj.tagging !== 'number') {\n errors.push({\n path: `${name}.tagging`,\n message: 'tagging must be a number',\n code: 'INVALID_TAGGING',\n });\n }\n\n // Validate schema\n if (obj.schema !== undefined && !isObject(obj.schema)) {\n errors.push({\n path: `${name}.schema`,\n message: 'schema must be a JSON Schema object',\n code: 'INVALID_SCHEMA',\n });\n }\n\n // Validate extend\n if (obj.extend !== undefined) {\n if (typeof obj.extend !== 'string') {\n errors.push({\n path: `${name}.extend`,\n message: 'extend must be a string',\n code: 'INVALID_EXTENDS',\n });\n } else if (!contractNames.includes(obj.extend)) {\n errors.push({\n path: `${name}.extend`,\n message: `extend references non-existent contract \"${obj.extend}\"`,\n value: obj.extend,\n code: 'INVALID_EXTENDS',\n });\n }\n }\n\n // Validate sections\n for (const key of SECTION_KEYS) {\n if (key in obj) {\n if (typeof obj[key] !== 'object' || obj[key] === null) {\n errors.push({\n path: `${name}.${key}`,\n message: `Section \"${key}\" must be a JSON Schema object`,\n value: obj[key],\n code: 'INVALID_SECTION',\n });\n }\n }\n }\n\n // Validate events\n if (obj.events !== undefined) {\n if (typeof obj.events !== 'object' || obj.events === null) {\n errors.push({\n path: `${name}.events`,\n message: 'events must be an object',\n code: 'INVALID_EVENTS',\n });\n } else {\n validateEntityActions(\n obj.events as Record<string, unknown>,\n `${name}.events`,\n errors,\n );\n }\n }\n }\n\n // Check for circular extend: one error per cycle, at its first member.\n const reportedCycles = new Set<string>();\n for (const name of contractNames) {\n const chain: string[] = [];\n let current = name;\n while (current) {\n const start = chain.indexOf(current);\n if (start !== -1) {\n const cycle = chain.slice(start);\n const key = [...cycle].sort().join('\\u0000');\n if (!reportedCycles.has(key)) {\n reportedCycles.add(key);\n errors.push({\n path: `${cycle[0]}.extend`,\n message: `Circular extend chain: ${[...cycle, current].join(' → ')}`,\n code: 'CIRCULAR_EXTENDS',\n });\n }\n break;\n }\n chain.push(current);\n const entry = contracts[current];\n current =\n isObject(entry) && typeof entry.extend === 'string' ? entry.extend : '';\n }\n }\n\n return {\n valid: errors.length === 0,\n type: 'contract',\n errors,\n warnings,\n details,\n };\n}\n\nfunction validateEntityActions(\n obj: Record<string, unknown>,\n prefix: string,\n errors: ValidationError[],\n): void {\n for (const [entityKey, entityValue] of Object.entries(obj)) {\n if (entityKey.trim() === '') {\n errors.push({\n path: `${prefix}.${entityKey}`,\n message: 'Entity key cannot be empty',\n code: 'INVALID_ENTITY_KEY',\n });\n continue;\n }\n\n if (typeof entityValue !== 'object' || entityValue === null) {\n errors.push({\n path: `${prefix}.${entityKey}`,\n message: `Entity \"${entityKey}\" must be an object`,\n value: entityValue,\n code: 'INVALID_ENTITY',\n });\n continue;\n }\n\n for (const [actionKey, actionValue] of Object.entries(\n entityValue as Record<string, unknown>,\n )) {\n if (actionKey.trim() === '') {\n errors.push({\n path: `${prefix}.${entityKey}.${actionKey}`,\n message: 'Action key cannot be empty',\n code: 'INVALID_ACTION_KEY',\n });\n continue;\n }\n\n if (\n typeof actionValue !== 'object' ||\n actionValue === null ||\n Array.isArray(actionValue)\n ) {\n errors.push({\n path: `${prefix}.${entityKey}.${actionKey}`,\n message: 'Contract entry must be a JSON Schema object',\n value: typeof actionValue,\n code: 'INVALID_SCHEMA_ENTRY',\n });\n }\n }\n }\n}\n","// walkerOS/packages/cli/src/commands/validate/validators/event.ts\n\nimport { validateEvent as coreValidateEvent } from '../../../core/event-validation.js';\nimport type { ValidateResult } from '../types.js';\n\nexport function validateEvent(input: unknown): ValidateResult {\n const result = coreValidateEvent(input, 'strict');\n\n return {\n valid: result.valid,\n type: 'event',\n errors: result.errors,\n warnings: result.warnings,\n details: result.details as Record<string, unknown>,\n };\n}\n","// walkerOS/packages/cli/src/commands/validate/validators/flow.ts\n\nimport type { Flow, Transformer, WalkerOS } from '@walkeros/core';\nimport {\n checkWindowCollector,\n ENV_MARKER_PREFIX,\n getByPath,\n getRouteGraph,\n isObject,\n REF_CONTRACT,\n resolveContracts,\n validateStepEntry,\n} from '@walkeros/core';\nimport { schemas, validateFlowStructure } from '@walkeros/core/dev';\nimport {\n validateEventAgainstContract,\n type ContractSource,\n} from '@walkeros/transformer-validate';\nimport {\n describeScope,\n ENTRY_SECTIONS,\n flowOfPath,\n isFlowJson,\n resolveScope,\n type ResolvedScope,\n} from '../scope.js';\nimport type {\n ValidateCheck,\n ValidateDeferred,\n ValidateDetails,\n ValidateResult,\n ValidateSkip,\n ValidationError,\n ValidationWarning,\n} from '../types.js';\nimport { validateContract } from './contract.js';\nimport { resolveFlow, type FlowResolution } from './resolve.js';\nimport {\n checkStepSettings,\n createSettingsContext,\n type CheckedPackage,\n type SettingsOutcome,\n} from './settings.js';\n\nconst { validateFlowConfig } = schemas;\n\ninterface FlowValidateOptions {\n flow?: string;\n /** When true, contract violations are reported as errors instead of warnings. */\n strict?: boolean;\n}\n\ninterface FlowPackageOptions extends FlowValidateOptions {\n /** Skip the package settings check (no network); named in the scope. */\n offline?: boolean;\n /** Directory local `path` packages resolve against (the input file's). */\n configDir?: string;\n}\n\n/** Removed packages: reported as a warning for one minor (D3), then errors. */\nconst DEPRECATED_PACKAGES: Record<string, string> = {\n '@walkeros/store-memory':\n 'has been removed. Use the built-in cache by omitting cache.store, or remove the store declaration if it was only used as a cache target.',\n};\n\n/** Step sections without their own closed-schema check (transformers have one). */\nconst OPEN_STEP_KINDS = [\n ['destinations', 'Destination'],\n ['stores', 'Store'],\n] as const;\n\n/** Everything the synchronous checks produced, for the package pass. */\ninterface FlowRun {\n result: ValidateResult;\n scope: ResolvedScope;\n typed?: Flow.Json;\n resolved: Map<string, Flow>;\n checks: ValidateCheck[];\n skipped: ValidateSkip[];\n gate: (name: string) => string | undefined;\n}\n\n/**\n * Validate a flow file without the network: schema and references, the\n * root contract, the bundler's structural preflight, routes, examples and\n * resolution of every flow in scope. `validate()` adds the package settings\n * check on top (see {@link validateFlowWithPackages}).\n */\nexport function validateFlow(\n input: unknown,\n options: FlowValidateOptions = {},\n): ValidateResult {\n return runFlowChecks(input, options).result;\n}\n\n/**\n * The whole-file run of `validate()`: {@link validateFlow} plus every step\n * with a `package` in scope checked against its package settings schema at\n * the pinned version. Findings are warnings for one minor (D3); a schema\n * that cannot be loaded is a skip; `offline` removes the check and says so.\n */\nexport async function validateFlowWithPackages(\n input: unknown,\n options: FlowPackageOptions = {},\n): Promise<ValidateResult> {\n const run = runFlowChecks(input, options);\n const { result, scope } = run;\n if (options.offline) {\n const described = describeScope(scope, run.checks);\n described.offline = true;\n result.details.scope = described;\n return result;\n }\n\n run.checks.push('flow:package-settings');\n const context = createSettingsContext(options.configDir);\n const deferred: ValidateDeferred[] = [];\n const packages: CheckedPackage[] = [];\n // Checks run in parallel; outcomes are applied in step order afterwards,\n // so the result does not depend on which schema arrives first.\n const pending: Array<Promise<SettingsOutcome>> = [];\n for (const name of scope.flows) {\n const flow = run.resolved.get(name);\n const rawFlow = run.typed?.flows[name];\n const reason = run.gate(name);\n if (!flow || !rawFlow || reason) {\n run.skipped.push({\n path: `flows.${name}`,\n check: 'flow:package-settings',\n reason: reason ?? `flows.${name} did not resolve`,\n code: 'GATED_BY_ERRORS',\n });\n continue;\n }\n for (const section of ENTRY_SECTIONS) {\n const steps = isObject(rawFlow[section]) ? rawFlow[section] : {};\n for (const [key, entry] of Object.entries(steps)) {\n if (!isObject(entry) || entry.package === undefined) continue;\n const target = { flow: name, section, key, entry };\n pending.push(\n checkStepSettings(\n target,\n flow,\n rawFlow,\n 'flow:package-settings',\n context,\n ),\n );\n }\n }\n }\n for (const outcome of await Promise.all(pending)) {\n result.warnings.push(...outcome.findings);\n run.skipped.push(...outcome.skipped);\n deferred.push(...outcome.deferred);\n if (outcome.checked) packages.push(outcome.checked);\n }\n\n result.details.scope = describeScope(scope, run.checks);\n result.details.deferred = [...(result.details.deferred ?? []), ...deferred];\n if (packages.length > 0) result.details.packages = packages;\n return result;\n}\n\nfunction runFlowChecks(input: unknown, options: FlowValidateOptions): FlowRun {\n const errors: ValidationError[] = [];\n const warnings: ValidationWarning[] = [];\n const skipped: ValidateSkip[] = [];\n const checks: ValidateCheck[] = ['file:schema', 'flow:schema'];\n const details: ValidateDetails = {};\n const resolved = new Map<string, Flow>();\n // `valid` is set once every error-producing check has run; the package\n // pass only adds warnings and skips.\n const result: ValidateResult = {\n valid: false,\n type: 'flow',\n errors,\n warnings,\n details,\n };\n\n // 1. Serialize to JSON for core validator\n // Core's validateFlowConfig takes a JSON string, but CLI receives parsed objects.\n // Re-serializing is the bridge between the two interfaces.\n let json: string;\n const scope = resolveScope(input, { flow: options.flow });\n try {\n json = JSON.stringify(input, null, 2);\n } catch {\n errors.push({\n path: 'root',\n message: 'Input cannot be serialized to JSON',\n code: 'SERIALIZATION_ERROR',\n });\n return {\n result,\n scope,\n resolved,\n checks,\n skipped,\n gate: () => 'the input cannot be serialized',\n };\n }\n\n // 2. Scope: every per-flow check below runs on scope.flows only.\n errors.push(...scope.errors);\n const config: Record<string, unknown> = isObject(input) ? input : {};\n const flowsValue = config.flows;\n const flows: Record<string, unknown> | undefined = isObject(flowsValue)\n ? flowsValue\n : undefined;\n const allFlows = scope.allFlows;\n const inScope = (path: string): boolean => {\n const flow = flowOfPath(path, allFlows);\n return flow === undefined || scope.flows.includes(flow);\n };\n\n // 3. The root contract, validated as `-t contract` validates it, with\n // paths under `contract.`. A file-level check: it runs whatever --flow.\n let contractErrors = 0;\n if ('contract' in config) {\n checks.push('file:contract');\n const contract = validateContract(config.contract);\n contractErrors = contract.errors.length;\n for (const error of contract.errors)\n errors.push({ ...error, path: `contract.${error.path}` });\n for (const warning of contract.warnings)\n warnings.push({ ...warning, path: `contract.${warning.path}` });\n }\n\n // 4. Run core validation (Zod schema + reference checking). File-level\n // findings always count; per-flow findings only for flows in scope.\n // Core's own contract-resolution error at `contract` is the same\n // finding the contract check above already reported in detail.\n const coreResult = validateFlowConfig(json);\n for (const issue of coreResult.errors) {\n const path = issue.path || 'root';\n if (!inScope(path)) continue;\n if (path === 'contract' && contractErrors > 0) continue;\n errors.push({ path, message: issue.message, code: 'SCHEMA_VALIDATION' });\n }\n for (const issue of coreResult.warnings) {\n const path = issue.path || 'root';\n if (!inScope(path)) continue;\n warnings.push({ path, message: issue.message, code: 'CONFIG_WARNING' });\n }\n\n // 5. CLI-specific: check for empty flows\n if (flows && allFlows.length === 0) {\n errors.push({\n path: 'flows',\n message: 'At least one flow is required',\n code: 'EMPTY_FLOWS',\n });\n }\n\n // 6. Step entries. Transformers are closed (errors, single source of\n // truth in @walkeros/core); an unknown key on a destination or store is\n // dropped by the resolver, so it warns (UNKNOWN_KEY) for one minor.\n // Removed packages warn (DEPRECATED_PACKAGE) for one minor (D3).\n checks.push('flow:steps');\n for (const flowName of scope.flows) {\n const flowValue = flows?.[flowName];\n if (!isObject(flowValue)) continue;\n const transformersValue = flowValue.transformers;\n if (isObject(transformersValue)) {\n for (const [name, transformerValue] of Object.entries(\n transformersValue,\n )) {\n if (!isObject(transformerValue)) continue;\n const result = validateStepEntry(transformerValue, 'Transformer');\n if (!result.ok) {\n errors.push({\n path: `flows.${flowName}.transformers.${name}`,\n message: result.reason || 'Invalid transformer entry.',\n code: result.code,\n });\n }\n }\n }\n for (const [section, kind] of OPEN_STEP_KINDS) {\n const steps = flowValue[section];\n if (!isObject(steps)) continue;\n for (const [name, step] of Object.entries(steps)) {\n if (!isObject(step)) continue;\n const at = `flows.${flowName}.${section}.${name}`;\n for (const key of unknownStepKeys(step, kind)) {\n warnings.push({\n path: `${at}.${key}`,\n message: `Unknown key \"${key}\" on ${kind} is ignored by the runtime`,\n suggestion: 'Remove the key, or move it to where it belongs.',\n code: 'UNKNOWN_KEY',\n });\n }\n const pkg = step.package;\n if (typeof pkg === 'string' && pkg in DEPRECATED_PACKAGES) {\n warnings.push({\n path: at,\n message: `${kind} \"${name}\" uses ${pkg}, which ${DEPRECATED_PACKAGES[pkg]}`,\n code: 'DEPRECATED_PACKAGE',\n });\n }\n }\n }\n }\n\n // 7. Extract flow details\n if (flows) {\n details.flowNames = allFlows;\n details.flowCount = allFlows.length;\n }\n\n // 8. CLI-specific: warn about packages without version (per-flow config.bundle.packages)\n checks.push('flow:package-versions');\n let totalPackageCount = 0;\n for (const flowName of scope.flows) {\n const flowValue = flows?.[flowName];\n if (!isObject(flowValue)) continue;\n const flowConfig = flowValue.config;\n if (!isObject(flowConfig)) continue;\n const bundle = flowConfig.bundle;\n if (!isObject(bundle)) continue;\n const packages = bundle.packages;\n if (!isObject(packages)) continue;\n\n for (const [pkgName, pkgConfigValue] of Object.entries(packages)) {\n if (!isObject(pkgConfigValue)) continue;\n if (!pkgConfigValue.version && !pkgConfigValue.path) {\n warnings.push({\n path: `flows.${flowName}.config.bundle.packages.${pkgName}`,\n message: `Package \"${pkgName}\" has no version specified`,\n suggestion: 'Consider specifying a version for reproducible builds',\n code: 'PACKAGE_VERSION_MISSING',\n });\n }\n }\n totalPackageCount += Object.keys(packages).length;\n }\n if (totalPackageCount > 0) {\n details.packageCount = totalPackageCount;\n }\n\n // 9. Expose core's IntelliSense context in details (bonus for MCP consumers)\n if (coreResult.context) {\n details.context = coreResult.context;\n }\n\n // 10. Deep checks run per flow on shapes core has already validated: a\n // flow with its own errors, or a file with file-level errors (its\n // shape, its contract), skips them, and every skip is listed.\n const typed = isFlowJson(input) ? input : undefined;\n const gate = (name: string): string | undefined => {\n if (\n !typed ||\n errors.some((e) => flowOfPath(e.path, allFlows) === undefined)\n )\n return 'file-level errors: the file shape or its contract is not valid';\n if (errors.some((e) => flowOfPath(e.path, allFlows) === name))\n return `earlier errors in flows.${name}`;\n return undefined;\n };\n const perFlow = (\n stageChecks: ValidateCheck[],\n run: (name: string, flow: Flow, file: Flow.Json) => void,\n ): void => {\n checks.push(...stageChecks);\n for (const name of scope.flows) {\n const reason = gate(name);\n const flow = typed?.flows[name];\n if (reason || !typed || !flow) {\n for (const check of stageChecks) {\n skipped.push({\n path: `flows.${name}`,\n check,\n reason: reason ?? `flows.${name} is not a flow object`,\n code: 'GATED_BY_ERRORS',\n });\n }\n continue;\n }\n run(name, flow, typed);\n }\n };\n\n // 10a. The bundler's own structural preflight (identifier names, package\n // xor code, per-flow $store targets), so a valid result implies the\n // bundle preflight passes. Its warnings (a transformer mapping that\n // does nothing) stay warnings: the runtime keeps the step.\n perFlow(['flow:structure'], (name, flow, file) => {\n const structure = validateFlowStructure({\n ...file,\n flows: { [name]: flow },\n });\n errors.push(...structure.errors);\n warnings.push(...structure.warnings);\n });\n\n // 10b. Route checks on every chain field, read through core's\n // getRouteGraph. Unknown targets are errors; shapes the schema\n // accepts but the author probably did not intend are warnings.\n perFlow(['flow:routes'], (name, flow) => {\n lintFlowRoutes(name, flow, errors, warnings);\n });\n\n // Each flow is resolved once, as the bundler resolves it: the validate\n // step check below reads its settings from there, 10d reports failures.\n const resolutions = new Map<string, FlowResolution>();\n const resolutionOf = (name: string, file: Flow.Json): FlowResolution => {\n let resolution = resolutions.get(name);\n if (!resolution) {\n resolution = resolveFlow(file, name);\n resolutions.set(name, resolution);\n }\n return resolution;\n };\n\n // 10c. Cross-step example compatibility, validate step examples against\n // their contract, and flat dot-separated mapping keys.\n let totalConnections: number | undefined;\n perFlow(\n ['flow:examples', 'flow:contract-examples', 'flow:mapping-keys'],\n (name, flow, file) => {\n const connections = buildConnectionGraph(flow);\n for (const conn of connections) {\n checkCompatibility(name, conn, errors, warnings);\n }\n totalConnections = (totalConnections ?? 0) + connections.length;\n\n // Contracts bind only where a transformer-validate step links them,\n // with exactly that step's settings, as at runtime. The config-level\n // contract block binds nothing by itself.\n const resolution = resolutionOf(name, file);\n for (const [stepName, transformer] of Object.entries(\n flow.transformers || {},\n )) {\n if (!isValidateStep(transformer)) continue;\n const resolvedConfig = resolution.ok\n ? resolution.flow.transformers?.[stepName]?.config\n : undefined;\n checkValidateStepExamples(\n `flows.${name}.transformers.${stepName}`,\n transformer,\n file.contract,\n errors,\n warnings,\n options.strict === true,\n skipped,\n isObject(resolvedConfig) && isObject(resolvedConfig.settings)\n ? resolvedConfig.settings\n : undefined,\n );\n }\n\n for (const [destName, dest] of Object.entries(flow.destinations || {})) {\n if (!isObject(dest.config)) continue;\n const mapping = dest.config.mapping;\n if (!isObject(mapping)) continue;\n\n for (const key of Object.keys(mapping)) {\n if (key.includes('.') && !key.includes(' ')) {\n const parts = key.split('.');\n warnings.push({\n path: `flows.${name}.destinations.${destName}.config.mapping`,\n message: `Mapping key \"${key}\" looks like dot-notation. Mapping uses nested entity → action structure.`,\n suggestion: `Use nested format: { \"${parts[0]}\": { \"${parts.slice(1).join('.')}\": { ... } } }`,\n code: 'MAPPING_DOT_KEY',\n });\n }\n }\n }\n },\n );\n if (totalConnections !== undefined) {\n details.connectionsChecked = totalConnections;\n }\n\n // 10d. Resolve every flow as the bundler does. Every resolver failure\n // (unknown $var, unresolvable $flow, unknown contract, cycles) is an\n // error, since the bundle of that flow fails the same way. Values\n // known only at runtime ($env without default, $secret) stay deferred.\n // The collector global is checked on its resolved value; an `$env`\n // value is known only at build time and stays deferred.\n const deferred: ValidateDeferred[] = [];\n perFlow(['flow:resolve'], (name, flow, file) => {\n const resolution = resolutionOf(name, file);\n if (!resolution.ok) {\n errors.push(resolution.error);\n return;\n }\n resolved.set(name, resolution.flow);\n checkResolvedWindowCollector(name, flow, resolution.flow, errors, deferred);\n });\n\n details.scope = describeScope(scope, checks);\n details.skipped = skipped;\n details.deferred = deferred;\n result.valid = errors.length === 0;\n\n return {\n result,\n scope,\n typed,\n resolved,\n checks,\n skipped,\n gate,\n };\n}\n\n/**\n * A `$var` / `$env` collector global, checked on its resolved value as the\n * build checks it. A literal is already checked by the schema; a value that\n * needs the build env is deferred to the build.\n */\nfunction checkResolvedWindowCollector(\n name: string,\n raw: Flow,\n flow: Flow,\n errors: ValidationError[],\n deferred: ValidateDeferred[],\n): void {\n const written = raw.config?.settings?.windowCollector;\n const value = flow.config?.settings?.windowCollector;\n if (\n flow.config?.platform !== 'web' ||\n typeof written !== 'string' ||\n !/\\$(?:var|env)\\./.test(written)\n )\n return;\n const path = `flows.${name}.config.settings.windowCollector`;\n if (typeof value === 'string' && value.includes(ENV_MARKER_PREFIX)) {\n deferred.push({ path, reference: written });\n return;\n }\n const check = checkWindowCollector(value);\n if (check.ok) return;\n errors.push({\n path,\n message: `${JSON.stringify(written)} resolved to ${JSON.stringify(value)}, which ${check.reason}`,\n code: 'SCHEMA_VALIDATION',\n });\n}\n\n/**\n * Top-level keys of a destination or store that the runtime does not know,\n * read through core's closed step-entry check (one source of truth).\n */\nfunction unknownStepKeys(\n step: Record<string, unknown>,\n kind: 'Destination' | 'Store',\n): string[] {\n const unknown: string[] = [];\n const rest: Record<string, unknown> = { ...step };\n for (;;) {\n const verdict = validateStepEntry(rest, kind);\n if (verdict.code !== 'UNKNOWN_KEY' || verdict.key === undefined) break;\n unknown.push(verdict.key);\n Reflect.deleteProperty(rest, verdict.key);\n }\n return unknown;\n}\n\n// --- Deep validation helpers ---\n\ninterface StepInfo {\n type: 'source' | 'transformer' | 'destination';\n name: string;\n examples: Flow.StepExamples;\n}\n\ninterface StepConnection {\n from: StepInfo;\n to: StepInfo;\n}\n\n/**\n * Every transformer id a route can reach, read through core's\n * `getRouteGraph` (the one enumerator over the compiled route form). An\n * over-approximation by design: static validation has no event, so every\n * branch counts.\n */\nfunction routeTargets(spec: Transformer.Route | undefined): string[] {\n if (spec === undefined) return [];\n const targets = new Set<string>();\n for (const node of getRouteGraph(spec)) {\n for (const target of node.targets) targets.add(target);\n }\n return [...targets];\n}\n\nfunction buildConnectionGraph(config: Flow): StepConnection[] {\n const connections: StepConnection[] = [];\n\n // Source → next transformer\n for (const [name, source] of Object.entries(config.sources || {})) {\n if (!source.next || !source.examples) continue;\n const nextNames = routeTargets(source.next);\n for (const nextName of nextNames) {\n const transformer = config.transformers?.[nextName];\n if (transformer?.examples) {\n connections.push({\n from: { type: 'source', name, examples: source.examples },\n to: {\n type: 'transformer',\n name: nextName,\n examples: transformer.examples,\n },\n });\n }\n }\n }\n\n // Transformer → next transformer\n for (const [name, transformer] of Object.entries(config.transformers || {})) {\n if (!transformer.next || !transformer.examples) continue;\n const nextNames = routeTargets(transformer.next);\n for (const nextName of nextNames) {\n const nextTransformer = config.transformers?.[nextName];\n if (nextTransformer?.examples) {\n connections.push({\n from: {\n type: 'transformer',\n name,\n examples: transformer.examples,\n },\n to: {\n type: 'transformer',\n name: nextName,\n examples: nextTransformer.examples,\n },\n });\n }\n }\n }\n\n // Destination.before → transformer chain → destination\n for (const [name, dest] of Object.entries(config.destinations || {})) {\n if (!dest.before || !dest.examples) continue;\n const beforeNames = routeTargets(dest.before);\n for (const beforeName of beforeNames) {\n const transformer = config.transformers?.[beforeName];\n if (transformer?.examples) {\n connections.push({\n from: {\n type: 'transformer',\n name: beforeName,\n examples: transformer.examples,\n },\n to: { type: 'destination', name, examples: dest.examples },\n });\n }\n }\n }\n\n return connections;\n}\n\nfunction checkCompatibility(\n flowName: string,\n conn: StepConnection,\n errors: ValidationError[],\n warnings: ValidationWarning[],\n): void {\n const fromOuts = Object.entries(conn.from.examples)\n .filter(([, ex]) => hasComparableOut(ex.out))\n .map(([name, ex]) => ({ name, value: ex.out }));\n\n // A command example's `in` is a walker command payload, never a pushed event\n const toIns = Object.entries(conn.to.examples)\n .filter(([, ex]) => ex.in !== undefined && !ex.command)\n .map(([name, ex]) => ({ name, value: ex.in }));\n\n const path = `flows.${flowName}.${conn.from.type}s.${conn.from.name} → ${conn.to.type}s.${conn.to.name}`;\n\n if (fromOuts.length === 0 || toIns.length === 0) {\n warnings.push({\n path,\n message: 'Cannot check compatibility: missing out or in examples',\n suggestion:\n 'Add out examples to the source step or in examples to the target step',\n code: 'EXAMPLES_INCOMPLETE',\n });\n return;\n }\n\n const hasMatch = fromOuts.some((out) =>\n outEvents(out.value).some((event) =>\n toIns.some((inp) => isStructurallyCompatible(event, inp.value)),\n ),\n );\n\n if (!hasMatch) {\n errors.push({\n path,\n message: 'No compatible out/in pair found between connected steps',\n code: 'INCOMPATIBLE_EXAMPLES',\n });\n }\n}\n\n/** An effect tuple of a StepOut: a string head, then the call arguments. */\ntype StepOutEffect = [string, ...unknown[]];\n\n/**\n * A StepOut is an array whose every entry is an array with a string head\n * (`[]` included): `[['elb', event]]`, `[['return', { event }]]`, ...\n */\nfunction isStepOut(value: unknown): value is StepOutEffect[] {\n return (\n Array.isArray(value) &&\n value.every((entry) => Array.isArray(entry) && typeof entry[0] === 'string')\n );\n}\n\n/**\n * Events a `return` effect passes on: `{ event }` yields the event, a bare\n * object is the event itself, an array is a fan-out read item by item by the\n * same rule. `false` and other values pass nothing on.\n */\nfunction returnedEvents(value: unknown): unknown[] {\n if (isObject(value)) return [isObject(value.event) ? value.event : value];\n if (Array.isArray(value)) return value.flatMap(returnedEvents);\n return [];\n}\n\n/**\n * The events an example `out` hands to the next step. A StepOut yields the\n * object argument of each `elb` effect and the events of each `return`\n * effect; every other head (`message.ack`, `response`, vendor calls) yields\n * nothing. A non-StepOut value is the output itself (back compat), when it\n * is a non-empty array, string or object.\n */\nfunction outEvents(out: unknown): unknown[] {\n if (isStepOut(out)) {\n return out.flatMap(([head, first]) => {\n if (head === 'elb') return isObject(first) ? [first] : [];\n if (head === 'return') return returnedEvents(first);\n return [];\n });\n }\n if (Array.isArray(out) || typeof out === 'string')\n return out.length > 0 ? [out] : [];\n return isObject(out) && Object.keys(out).length > 0 ? [out] : [];\n}\n\nfunction hasComparableOut(out: unknown): boolean {\n return outEvents(out).length > 0;\n}\n\nfunction isStructurallyCompatible(a: unknown, b: unknown): boolean {\n if (typeof a !== typeof b) return false;\n if (a === null || b === null) return a === b;\n if (Array.isArray(a) && Array.isArray(b)) return true;\n if (typeof a === 'object' && typeof b === 'object') {\n const keysA = Object.keys(a as object);\n const keysB = Object.keys(b as object);\n const shared = keysA.filter((k) => keysB.includes(k));\n return shared.length >= Math.min(keysA.length, keysB.length) * 0.5;\n }\n return true;\n}\n\n/**\n * Checks every chain field of a flow (source `before`/`next`, transformer\n * `before`/`next`, destination `before`/`next`, `collector.next`):\n *\n * - error: a route target that is not a transformer of the flow. At runtime\n * an unknown id is skipped with a warning, so a misspelled step (for\n * example a redaction branch) would otherwise fail open.\n * - warning: entries after an unconditional `stop` never run.\n * - warning: `many: []` selects nothing; `many: [\"x\"]` is just `next`.\n * - warning: an array made only of route configs is first-match.\n */\nfunction lintFlowRoutes(\n flowName: string,\n flow: Flow,\n errors: ValidationError[],\n warnings: ValidationWarning[],\n): void {\n const known = new Set(Object.keys(flow.transformers || {}));\n const check = (\n spec: Transformer.Route | undefined,\n position: string,\n ): void => {\n if (spec !== undefined) lintRoute(spec, position, known, errors, warnings);\n };\n const at = `flows.${flowName}`;\n\n for (const [name, source] of Object.entries(flow.sources || {})) {\n check(source.before, `${at}.sources.${name}.before`);\n check(source.next, `${at}.sources.${name}.next`);\n }\n for (const [name, transformer] of Object.entries(flow.transformers || {})) {\n check(transformer.before, `${at}.transformers.${name}.before`);\n check(transformer.next, `${at}.transformers.${name}.next`);\n }\n check(flow.collector?.next, `${at}.collector.next`);\n for (const [name, dest] of Object.entries(flow.destinations || {})) {\n check(dest.before, `${at}.destinations.${name}.before`);\n check(dest.next, `${at}.destinations.${name}.next`);\n }\n}\n\ntype RoutePath = (string | number)[];\n\n/** The raw value at `path` inside a route (a plain lookup, no grammar). */\nfunction routeAt(spec: Transformer.Route, path: RoutePath): unknown {\n let current: unknown = spec;\n for (const key of path) {\n if (typeof key === 'number')\n current = Array.isArray(current) ? current[key] : undefined;\n else current = isObject(current) ? current[key] : undefined;\n }\n return current;\n}\n\n/**\n * Lints one route through `getRouteGraph`. Every branch node, and every\n * enclosing decision it lists in `via`, is looked at once by its path.\n */\nfunction lintRoute(\n spec: Transformer.Route,\n position: string,\n known: Set<string>,\n errors: ValidationError[],\n warnings: ValidationWarning[],\n): void {\n const where = (path: RoutePath) =>\n path.length > 0 ? `${position}.${path.join('.')}` : position;\n const reported = new Set<string>();\n const once = (key: string): boolean => {\n if (reported.has(key)) return false;\n reported.add(key);\n return true;\n };\n\n for (const node of getRouteGraph(spec)) {\n for (const target of node.targets) {\n if (known.has(target) || !once(`unknown:${target}`)) continue;\n errors.push({\n path: position,\n message: `Unknown transformer \"${target}\" in route at ${position}`,\n code: 'UNKNOWN_ROUTE_TARGET',\n });\n }\n\n // Entries after an unconditional stop never run (a `many` entry's stop\n // ends only its own copy, so it does not shadow its siblings).\n const last = node.path[node.path.length - 1];\n if (node.stop && !node.match && node.kind !== 'many') {\n const self = routeAt(spec, node.path);\n const list = routeAt(spec, node.path.slice(0, -1));\n if (\n isObject(self) &&\n self.stop === true &&\n typeof last === 'number' &&\n Array.isArray(list) &&\n last < list.length - 1 &&\n once(`stop:${where(node.path)}`)\n ) {\n const at = where(node.path);\n warnings.push({\n path: at,\n message: `dead code after stop at ${at}: entries after an unconditional stop never run`,\n code: 'ROUTE_DEAD_CODE',\n suggestion:\n 'Remove the entries after the stop, or give the stop a match.',\n });\n }\n }\n\n if (\n node.kind === 'many' &&\n last === 'many' &&\n node.targets.length === 0 &&\n once(`empty:${where(node.path)}`)\n ) {\n const at = where(node.path.slice(0, -1));\n warnings.push({\n path: at,\n message: `empty many at ${at}: selects no branch, so it has no effect`,\n code: 'ROUTE_EMPTY_MANY',\n suggestion: 'Add two or more branch targets to many, or remove it.',\n });\n }\n\n for (const decision of [...(node.via ?? []), node]) {\n const index = decision.path[decision.path.length - 1];\n if (typeof index !== 'number') continue;\n const listPath = decision.path.slice(0, -1);\n const list = routeAt(spec, listPath);\n if (!Array.isArray(list)) continue;\n const at = where(listPath);\n\n if (\n decision.kind === 'many' &&\n list.length === 1 &&\n once(`single:${at}`)\n ) {\n const only = list[0];\n const hint =\n typeof only === 'string'\n ? `use 'next: \"${only}\"' for clarity`\n : `use 'next' for clarity`;\n warnings.push({\n path: at,\n message: `single-entry many at ${at}: ${hint}`,\n code: 'ROUTE_SINGLE_MANY',\n suggestion: 'Replace many with next when only one branch exists.',\n });\n }\n\n // A pure route-config array is compiled as an implicit `one`.\n const explicitOne = listPath[listPath.length - 1] === 'one';\n if (\n decision.kind === 'one' &&\n !explicitOne &&\n list.length > 1 &&\n once(`first-match:${at}`)\n ) {\n warnings.push({\n path: at,\n message: `first-match array at ${at}: an array made only of route configs is an implicit one, the first matching entry wins`,\n code: 'ROUTE_FIRST_MATCH',\n suggestion:\n 'Write { \"one\": [...] } explicitly, or add the step ids as a sequence to run every entry in order.',\n });\n }\n }\n }\n}\n\nconst VALIDATE_PACKAGE = '@walkeros/transformer-validate';\n\n/** A transformer step that runs `@walkeros/transformer-validate`. */\nexport function isValidateStep(step: Flow.Transformer): boolean {\n return step.package === VALIDATE_PACKAGE;\n}\n\ntype StepContracts =\n | { ok: true; sources: ContractSource[] }\n | { ok: false; index?: number; message: string };\n\n/**\n * The contract sources a validate step runs with, as at runtime: a whole\n * `$contract.<name>(.<path>)` string resolves against the config-level\n * contract definitions, an inline schema is used as given. An entry that\n * does not resolve says which one and why; the step is then not judged.\n */\nfunction resolveStepContracts(\n entries: unknown[],\n contract: Flow.Contract | undefined,\n): StepContracts {\n let resolved: Record<string, Flow.ContractRule> = {};\n if (contract) {\n try {\n resolved = resolveContracts(contract);\n } catch (error) {\n return {\n ok: false,\n message: `the root contract does not resolve (${error instanceof Error ? error.message : String(error)})`,\n };\n }\n }\n\n const sources: ContractSource[] = [];\n for (const [index, entry] of entries.entries()) {\n if (isObject(entry)) {\n sources.push(entry);\n continue;\n }\n const match = typeof entry === 'string' ? entry.match(REF_CONTRACT) : null;\n if (!match)\n return {\n ok: false,\n index,\n message: 'an entry must be a $contract reference or a JSON Schema',\n };\n if (!(match[1] in resolved))\n return {\n ok: false,\n index,\n message: `contract \"${match[1]}\" is not defined in the root contract (defined: ${Object.keys(resolved).join(', ') || 'none'})`,\n };\n const rule: unknown = match[2]\n ? getByPath(resolved[match[1]], match[2])\n : resolved[match[1]];\n if (!isObject(rule))\n return {\n ok: false,\n index,\n message: `${match[0]} does not point at a contract rule object`,\n };\n sources.push(rule);\n }\n return { ok: true, sources };\n}\n\n/**\n * Check a validate step's own examples against its own contract and\n * settings: the verdict the step reaches on `in` must agree with what `out`\n * shows. A valid event goes on (its `output.isValid` flag, when shown, is\n * true); an invalid one is dropped in `strict` mode and otherwise goes on\n * with the flag false. A disagreement is CONTRACT_VIOLATION (error when\n * {@link strict}, else warning). Deterministic: the verdict comes from the\n * shared {@link validateEventAgainstContract} runtime authority.\n * `stepPath` is the step's result path, `flows.<flow>.transformers.<name>`.\n * A contract entry that does not resolve is an error (UNRESOLVED_CONTRACT),\n * examples or not; a contract setting that is not a list is a skip.\n * `resolvedSettings` are the step's settings as the resolver produced them\n * (`$var` and `$contract` resolved, as the runtime sees them); without them\n * the settings as written are read.\n */\nexport function checkValidateStepExamples(\n stepPath: string,\n step: Flow.Transformer,\n contract: Flow.Contract | undefined,\n errors: ValidationError[],\n warnings: ValidationWarning[],\n strict: boolean,\n skipped?: ValidateSkip[],\n resolvedSettings?: Record<string, unknown>,\n): void {\n const settings =\n resolvedSettings ??\n (isObject(step.config) && isObject(step.config.settings)\n ? step.config.settings\n : {});\n const contractPath = `${stepPath}.config.settings.contract`;\n // A contract that is set but not a list cannot be judged statically.\n if (settings.contract !== undefined && !Array.isArray(settings.contract)) {\n if (step.examples)\n skipped?.push({\n path: stepPath,\n check: 'flow:contract-examples',\n reason:\n 'config.settings.contract is not a list, so the step cannot be judged statically',\n code: 'CONTRACT_NOT_STATIC',\n });\n return;\n }\n const resolution: StepContracts = Array.isArray(settings.contract)\n ? resolveStepContracts(settings.contract, contract)\n : { ok: true, sources: [] };\n if (!resolution.ok) {\n errors.push({\n path:\n resolution.index === undefined\n ? contractPath\n : `${contractPath}.${resolution.index}`,\n message: `The validate step's contract does not resolve: ${resolution.message}`,\n code: 'UNRESOLVED_CONTRACT',\n });\n return;\n }\n if (!step.examples) return;\n const contracts = resolution.sources;\n\n const mode = settings.mode === 'strict' ? 'strict' : 'pass';\n const format = settings.format === true;\n const output = isObject(settings.output) ? settings.output : {};\n const isValidPath =\n typeof output.isValid === 'string' ? output.isValid : 'source.valid';\n\n for (const [exName, example] of Object.entries(step.examples)) {\n if (example.command || !isObject(example.in)) continue;\n if (example.out === undefined) continue;\n\n const event: WalkerOS.DeepPartialEvent = example.in;\n const verdict = validateEventAgainstContract(event, undefined, {\n contracts,\n format,\n });\n const passed = outEvents(example.out);\n const dropped =\n isStepOut(example.out) &&\n example.out.some(([head, first]) => head === 'return' && first === false);\n\n let agrees: boolean;\n if (mode === 'strict' && !verdict.isValid) {\n agrees = dropped && passed.length === 0;\n } else {\n agrees =\n passed.length > 0 &&\n passed.every((out) => {\n if (!isValidPath) return true;\n const flag = getByPath(out, isValidPath);\n return verdict.isValid ? flag !== false : flag === false;\n });\n }\n if (agrees) continue;\n\n const reason = verdict.isValid\n ? 'the event satisfies the contract'\n : `the event breaks the contract (${verdict.errors\n .map((e) => `${e.path || '/'}: ${e.message}`)\n .join('; ')})`;\n const expected =\n mode === 'strict' && !verdict.isValid\n ? 'drops it ([\"return\", false])'\n : `passes it on${isValidPath ? ` with ${isValidPath} ${verdict.isValid}` : ''}`;\n const path = `${stepPath}.examples.${exName}.out`;\n const message = `Example out disagrees with the validate step: ${reason}, so with mode \"${mode}\" the step ${expected}.`;\n\n if (strict) {\n errors.push({ path, message, code: 'CONTRACT_VIOLATION' });\n } else {\n warnings.push({\n path,\n message,\n suggestion:\n 'Make the example out show what the validate step does with its settings.',\n code: 'CONTRACT_VIOLATION',\n });\n }\n }\n}\n","// walkerOS/packages/cli/src/commands/validate/scope.ts\n\nimport type { Flow } from '@walkeros/core';\nimport { isObject } from '@walkeros/core';\nimport type { ValidateCheck, ValidateScope, ValidationError } from './types.js';\n\n/**\n * A parsed Flow.Json shape (a `version` and a `flows` object), so the\n * validators can hand it to core's resolver and preflight without casts.\n */\nexport function isFlowJson(value: unknown): value is Flow.Json {\n return isObject(value) && 'version' in value && isObject(value.flows);\n}\n\n/** Step sections a `--path` can address. */\nexport const ENTRY_SECTIONS = [\n 'sources',\n 'destinations',\n 'transformers',\n 'stores',\n] as const;\n\nexport type EntrySection = (typeof ENTRY_SECTIONS)[number];\n\nfunction isEntrySection(value: string): value is EntrySection {\n return ENTRY_SECTIONS.some((section) => section === value);\n}\n\nexport interface ScopeOptions {\n flow?: string;\n path?: string;\n}\n\nexport interface ScopeEntry {\n flow: string;\n section: EntrySection;\n key: string;\n entry: Record<string, unknown>;\n}\n\nexport interface ResolvedScope {\n /** Every flow in the file, in file order. */\n allFlows: string[];\n /** Flows every per-flow check runs on. */\n flows: string[];\n /** Entries a `--path` addressed, one per flow that has it. */\n entries: ScopeEntry[];\n /** Flows searched for the `--path` entry (empty without a path). */\n searchedFlows: string[];\n /** The entry a `--path` names, when one was given and parsed. */\n target?: { section?: EntrySection; key: string };\n /** FLOW_NOT_FOUND, ENTRY_NOT_FOUND, AMBIGUOUS_ENTRY, UNSUPPORTED_SECTION, INVALID_PATH. */\n errors: ValidationError[];\n}\n\n/**\n * The one place validate picks flows and entries. `flow` narrows to that\n * flow; without it every flow is in scope. `path` (`section.key` or `key`)\n * addresses the entry in every flow in scope that has it.\n */\nexport function resolveScope(\n config: unknown,\n options: ScopeOptions = {},\n): ResolvedScope {\n const flowsValue = isObject(config) ? config.flows : undefined;\n const flowMap = isObject(flowsValue) ? flowsValue : {};\n const allFlows = Object.keys(flowMap);\n\n let flows = allFlows;\n if (options.flow !== undefined) {\n if (!allFlows.includes(options.flow)) {\n return {\n allFlows,\n flows: [],\n entries: [],\n searchedFlows: [],\n errors: [\n {\n path: 'flows',\n message: `Flow \"${options.flow}\" not found. Available: ${allFlows.join(', ') || 'none'}`,\n code: 'FLOW_NOT_FOUND',\n },\n ],\n };\n }\n flows = [options.flow];\n }\n\n const path = options.path;\n if (path === undefined) {\n return { allFlows, flows, entries: [], searchedFlows: [], errors: [] };\n }\n\n const parts = path.split('.');\n let sections: readonly EntrySection[] = ENTRY_SECTIONS;\n let section: EntrySection | undefined;\n let key: string;\n if (parts.length === 2 && parts[0] !== '' && parts[1] !== '') {\n if (!isEntrySection(parts[0])) {\n return {\n allFlows,\n flows,\n entries: [],\n searchedFlows: [],\n errors: [\n {\n path,\n message: `Section \"${parts[0]}\" cannot be addressed by --path. Use one of: ${ENTRY_SECTIONS.join(', ')}`,\n code: 'UNSUPPORTED_SECTION',\n },\n ],\n };\n }\n section = parts[0];\n sections = [section];\n key = parts[1];\n } else if (parts.length === 1 && parts[0] !== '') {\n key = parts[0];\n } else {\n return {\n allFlows,\n flows,\n entries: [],\n searchedFlows: [],\n errors: [\n {\n path,\n message: `Invalid path \"${path}\". Use \"section.key\" or just \"key\"`,\n code: 'INVALID_PATH',\n },\n ],\n };\n }\n\n const entries: ScopeEntry[] = [];\n for (const flow of flows) {\n const flowValue = flowMap[flow];\n if (!isObject(flowValue)) continue;\n for (const candidate of sections) {\n const sectionValue = flowValue[candidate];\n if (!isObject(sectionValue)) continue;\n const entry = sectionValue[key];\n if (isObject(entry))\n entries.push({ flow, section: candidate, key, entry });\n }\n }\n\n const matched = [...new Set(entries.map((entry) => entry.section))];\n if (matched.length > 1) {\n return {\n allFlows,\n flows,\n entries: [],\n searchedFlows: flows,\n target: { key },\n errors: [\n {\n path,\n message: `Ambiguous key \"${key}\" found in multiple sections: ${matched.join(', ')}. Use dot-notation (e.g., ${matched[0]}.${key})`,\n code: 'AMBIGUOUS_ENTRY',\n },\n ],\n };\n }\n\n const target = { section: section ?? matched[0], key };\n if (entries.length === 0) {\n return {\n allFlows,\n flows,\n entries,\n searchedFlows: flows,\n target,\n errors: [\n {\n path,\n message: `Entry \"${key}\" not found in ${section ?? 'any section'} of flow(s): ${flows.join(', ') || 'none'}`,\n code: 'ENTRY_NOT_FOUND',\n },\n ],\n };\n }\n\n return {\n allFlows,\n flows,\n entries,\n searchedFlows: flows,\n target,\n errors: [],\n };\n}\n\n/** The flow a result path belongs to, or undefined for a file-level path. */\nexport function flowOfPath(\n path: string,\n flowNames: readonly string[],\n): string | undefined {\n return flowNames.find(\n (name) => path === `flows.${name}` || path.startsWith(`flows.${name}.`),\n );\n}\n\n/** `details.scope` for a resolved scope and the checks the run included. */\nexport function describeScope(\n resolved: ResolvedScope,\n checks: ValidateCheck[],\n): ValidateScope {\n const scope: ValidateScope = { flows: resolved.flows, checks };\n if (resolved.target) {\n const { section, key } = resolved.target;\n scope.entry = {\n ...(section ? { section } : {}),\n key,\n flows: [...new Set(resolved.entries.map((entry) => entry.flow))],\n searchedFlows: resolved.searchedFlows,\n };\n }\n return scope;\n}\n","// walkerOS/packages/cli/src/commands/validate/validators/resolve.ts\n\nimport type { Flow } from '@walkeros/core';\nimport {\n FlowCycleError,\n FlowReferenceError,\n getFlowSettings,\n getErrorMessage,\n} from '@walkeros/core';\nimport type { ValidateCode, ValidationError } from '../types.js';\n\nexport type FlowResolution =\n | { ok: true; flow: Flow }\n | { ok: false; error: ValidationError };\n\n/**\n * Resolve one flow exactly as the bundler does (`getFlowSettings` with\n * deferred `$env`/`$secret`, and `$flow` refs as strict as the bundle). A\n * resolver failure is an error at `flows.<name>`: the bundle of this flow\n * fails the same way.\n */\nexport function resolveFlow(file: Flow.Json, name: string): FlowResolution {\n try {\n const flow = getFlowSettings(file, name, { deferred: true });\n return { ok: true, flow };\n } catch (error) {\n return {\n ok: false,\n error: {\n path: `flows.${name}`,\n message: getErrorMessage(error),\n code: resolutionCode(error),\n },\n };\n }\n}\n\n/** The code of a resolver failure, read from its type. */\nfunction resolutionCode(error: unknown): ValidateCode {\n if (error instanceof FlowReferenceError) return error.code;\n if (error instanceof FlowCycleError) return error.code;\n return 'UNRESOLVED_REFERENCE';\n}\n","// walkerOS/packages/cli/src/commands/validate/validators/settings.ts\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport Ajv, { type ErrorObject, type ValidateFunction } from 'ajv';\nimport type { Flow } from '@walkeros/core';\nimport {\n ENV_MARKER_PREFIX,\n fetchPackage,\n getErrorMessage,\n isObject,\n REF_CODE_PREFIX,\n REF_STORE,\n SECRET_MARKER_PREFIX,\n} from '@walkeros/core';\nimport {\n resolveExportName,\n type ComponentKind,\n} from '../../../core/resolve-export-name.js';\nimport { parsePackageSpec } from '../../../core/step-packages.js';\nimport type { EntrySection } from '../scope.js';\nimport type {\n ValidateCheck,\n ValidateDeferred,\n ValidateSkip,\n ValidationError,\n} from '../types.js';\n\n// __VERSION__ is replaced at build time by tsup's `define` (see tsup.config.ts).\n// In tests, it's set as a global by the shared jest config (@walkeros/config/jest).\ndeclare const __VERSION__: string;\n\nconst CLIENT_HEADER = 'walkeros-cli/' + __VERSION__;\n\n/** One step whose settings are checked against its package schema. */\nexport interface SettingsTarget {\n flow: string;\n section: EntrySection;\n key: string;\n /** The step as written in the file (package, bundle pins). */\n entry: Record<string, unknown>;\n}\n\nexport interface SettingsContext {\n /** Directory a local `path` package resolves against; unset: no disk reads. */\n configDir?: string;\n /** Schemas fetched in this run, by package source. */\n cache: Map<string, Promise<PackageSchema>>;\n /** Settings validators compiled in this run, by package source and export. */\n compiled: Map<string, CompiledSettings | undefined>;\n}\n\nexport interface CheckedPackage {\n path: string;\n package: string;\n version?: string;\n}\n\nexport interface SettingsOutcome {\n findings: ValidationError[];\n skipped: ValidateSkip[];\n deferred: ValidateDeferred[];\n checked?: CheckedPackage;\n}\n\nexport interface PackageSchema {\n version?: string;\n /** The default export's settings schema. */\n settings: unknown;\n /** Schemas per export, keyed by export name (multi-export packages). */\n exportSchemas?: Record<string, unknown>;\n /** Export names the package declares. */\n exports?: string[];\n}\n\nexport type SettingsSelection =\n | { ok: true; settings: unknown }\n | { ok: false; reason: string };\n\n/** A settings schema compiled once per package source, export and run. */\ntype CompiledSettings =\n | { ok: true; validate: ValidateFunction }\n | { ok: false; message: string };\n\ninterface PackageSource {\n name: string;\n version?: string;\n localPath?: string;\n}\n\nexport function createSettingsContext(configDir?: string): SettingsContext {\n return { configDir, cache: new Map(), compiled: new Map() };\n}\n\n/**\n * The settings schema for the export a step imports, by the same rule\n * simulate uses for dev examples: no export named takes `settings`; a\n * per-export map takes that export's entry and never another export's; a\n * package declaring at most one export takes `settings` for its only step\n * export; a multi-export package without a map, or a package that does not\n * publish its exports, cannot be checked.\n */\nexport function selectSettingsSchema(\n pkg: PackageSchema,\n packageLabel: string,\n exportName: string | undefined,\n): SettingsSelection {\n if (exportName === undefined) return { ok: true, settings: pkg.settings };\n if (pkg.exportSchemas) {\n const entry = Object.prototype.hasOwnProperty.call(\n pkg.exportSchemas,\n exportName,\n )\n ? pkg.exportSchemas[exportName]\n : undefined;\n if (!isObject(entry))\n return {\n ok: false,\n reason: `${packageLabel} has no export \"${exportName}\"`,\n };\n return { ok: true, settings: entry.settings };\n }\n if (pkg.exports && pkg.exports.length < 2)\n return { ok: true, settings: pkg.settings };\n return {\n ok: false,\n reason: `${packageLabel} predates per-export settings schemas; the step imports \"${exportName}\"`,\n };\n}\n\nconst SECTION_KIND: Record<EntrySection, ComponentKind> = {\n sources: 'source',\n transformers: 'transformer',\n destinations: 'destination',\n stores: 'store',\n};\n\n/** Segments of an Ajv instance path (a JSON pointer). */\nfunction pointerSegments(pointer: string): string[] {\n if (pointer === '') return [];\n return pointer\n .split('/')\n .slice(1)\n .map((segment) => segment.replace(/~1/g, '/').replace(/~0/g, '~'));\n}\n\nfunction valueAt(root: unknown, segments: string[]): unknown {\n let current = root;\n for (const segment of segments) {\n if (Array.isArray(current)) current = current[Number(segment)];\n else if (isObject(current)) current = current[segment];\n else return undefined;\n }\n return current;\n}\n\n// The bundler's deferred-$env marker grammar (see bundle/bundler.ts): a\n// default runs until whitespace, a quote or the next marker.\nconst MARKER = ENV_MARKER_PREFIX.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\nconst ENV_MARKER = new RegExp(\n `${MARKER}([a-zA-Z_][a-zA-Z0-9_]*)(?::((?:(?!${MARKER})[^\\\\s\"'])*))?`,\n 'g',\n);\n\ninterface PreparedSettings {\n value: unknown;\n /** Instance paths known only at runtime, with the reference as written. */\n deferred: Array<{ segments: string[]; reference: string }>;\n}\n\n/**\n * The placeholder rule, applied to settings already resolved by\n * `getFlowSettings(..., { deferred: true })`: `$var` and `$flow` values are\n * already resolved (an unresolvable one fails the flow first); `$env.NAME:default`\n * is checked as its default; `$env.NAME` without default, `$secret`, `$store`\n * and `$code` are known only at runtime and deferred.\n */\nfunction prepareSettings(settings: unknown): PreparedSettings {\n const deferred: PreparedSettings['deferred'] = [];\n const walk = (value: unknown, segments: string[]): unknown => {\n if (Array.isArray(value))\n return value.map((item, index) => walk(item, [...segments, `${index}`]));\n if (isObject(value))\n return Object.fromEntries(\n Object.entries(value).map(([key, item]) => [\n key,\n walk(item, [...segments, key]),\n ]),\n );\n if (typeof value !== 'string') return value;\n\n if (value.startsWith(SECRET_MARKER_PREFIX)) {\n deferred.push({\n segments,\n reference: `$secret.${value.slice(SECRET_MARKER_PREFIX.length)}`,\n });\n return value;\n }\n if (value.includes(ENV_MARKER_PREFIX)) {\n let runtimeOnly = false;\n const withDefaults = value.replace(\n ENV_MARKER,\n (_match, _name: string, fallback: string | undefined) => {\n if (fallback === undefined) runtimeOnly = true;\n return fallback ?? '';\n },\n );\n if (!runtimeOnly) return withDefaults;\n deferred.push({\n segments,\n reference: value.replace(\n ENV_MARKER,\n (_match, name: string, fallback: string | undefined) =>\n fallback === undefined\n ? `$env.${name}`\n : `$env.${name}:${fallback}`,\n ),\n });\n return value;\n }\n if (REF_STORE.test(value) || value.startsWith(REF_CODE_PREFIX)) {\n deferred.push({ segments, reference: value });\n }\n return value;\n };\n return { value: walk(settings, []), deferred };\n}\n\nfunction isUnder(segments: string[], prefix: string[]): boolean {\n return prefix.every((segment, index) => segments[index] === segment);\n}\n\nfunction bundlePin(\n rawFlow: unknown,\n name: string,\n): { version?: string; path?: string } {\n const config = isObject(rawFlow) ? rawFlow.config : undefined;\n const bundle = isObject(config) ? config.bundle : undefined;\n const packages = isObject(bundle) ? bundle.packages : undefined;\n const pin = isObject(packages) ? packages[name] : undefined;\n if (!isObject(pin)) return {};\n return {\n ...(typeof pin.version === 'string' ? { version: pin.version } : {}),\n ...(typeof pin.path === 'string' ? { path: pin.path } : {}),\n };\n}\n\n/**\n * Where a step's package comes from, as the bundler picks it: a local\n * `path` (inline `./` or `/` spec, or a bundle pin), else the bundle pin's\n * version, else the inline `@version`, else latest.\n */\nfunction packageSource(spec: string, rawFlow: unknown): PackageSource {\n if (spec.startsWith('.') || spec.startsWith('/'))\n return { name: spec, localPath: spec };\n const { name, version } = parsePackageSpec(spec);\n const pin = bundlePin(rawFlow, name);\n if (pin.path) return { name, localPath: pin.path };\n const pinned = pin.version ?? version;\n return pinned ? { name, version: pinned } : { name };\n}\n\nfunction readJson(file: string): unknown {\n return JSON.parse(fs.readFileSync(file, 'utf-8'));\n}\n\n/** Schemas of a local package, read from its `walkerOS.json` on disk. */\nfunction readLocalSchema(\n source: PackageSource,\n configDir: string,\n): PackageSchema {\n const localPath = source.localPath ?? '';\n const root = path.isAbsolute(localPath)\n ? localPath\n : path.resolve(configDir, localPath);\n const file = [\n path.join(root, 'dist', 'walkerOS.json'),\n path.join(root, 'walkerOS.json'),\n ].find((candidate) => fs.existsSync(candidate));\n if (!file) throw new Error(`no walkerOS.json under ${root}`);\n const meta = readJson(file);\n const pkgFile = path.join(root, 'package.json');\n const pkg = fs.existsSync(pkgFile) ? readJson(pkgFile) : undefined;\n const schemas = isObject(meta) ? meta.schemas : undefined;\n const exportSchemas = isObject(meta) ? meta.exportSchemas : undefined;\n const declared =\n isObject(meta) && isObject(meta.$meta) ? meta.$meta.exports : undefined;\n const version =\n isObject(pkg) && typeof pkg.version === 'string' ? pkg.version : undefined;\n return {\n ...(version ? { version } : {}),\n settings: isObject(schemas) ? schemas.settings : undefined,\n ...(isObject(exportSchemas) ? { exportSchemas } : {}),\n ...(isObject(declared) ? { exports: Object.keys(declared) } : {}),\n };\n}\n\nasync function loadSchema(\n source: PackageSource,\n context: SettingsContext,\n): Promise<PackageSchema> {\n if (source.localPath !== undefined) {\n const configDir = context.configDir;\n if (configDir === undefined)\n throw new Error(\n 'it is a local path package and the input is not a file, so there is no directory to read it from',\n );\n return readLocalSchema(source, configDir);\n }\n const info = await fetchPackage(source.name, {\n ...(source.version ? { version: source.version } : {}),\n client: CLIENT_HEADER,\n });\n return {\n version: info.version,\n settings: info.schemas.settings,\n ...(info.exportSchemas ? { exportSchemas: info.exportSchemas } : {}),\n ...(info.exports ? { exports: Object.keys(info.exports) } : {}),\n };\n}\n\n/**\n * Compile a package's settings schema. A schema Ajv cannot compile (an\n * unknown keyword, a bad `$ref`) cannot be checked against, so it is a\n * failed compile the caller reports as a skip, never a crash of the run.\n */\nfunction compileSettings(settings: unknown): CompiledSettings | undefined {\n if (!isObject(settings)) return undefined;\n // Formats such as `uri` and `email` are not bundled with Ajv; ignore them\n // instead of failing to compile. Every structural keyword is still checked.\n const ajv = new Ajv({ allErrors: true, validateFormats: false });\n try {\n return { ok: true, validate: ajv.compile(settings) };\n } catch (error) {\n return { ok: false, message: getErrorMessage(error) };\n }\n}\n\nfunction sourceKey(source: PackageSource): string {\n return source.localPath\n ? `path:${source.localPath}`\n : `${source.name}@${source.version ?? 'latest'}`;\n}\n\nfunction cachedSchema(\n source: PackageSource,\n context: SettingsContext,\n): Promise<PackageSchema> {\n const key = sourceKey(source);\n let pending = context.cache.get(key);\n if (!pending) {\n pending = loadSchema(source, context);\n context.cache.set(key, pending);\n }\n return pending;\n}\n\nfunction cachedCompile(\n source: PackageSource,\n exportName: string | undefined,\n settings: unknown,\n context: SettingsContext,\n): CompiledSettings | undefined {\n const key = `${sourceKey(source)}#${exportName ?? ''}`;\n if (context.compiled.has(key)) return context.compiled.get(key);\n const compiled = compileSettings(settings);\n context.compiled.set(key, compiled);\n return compiled;\n}\n\n/**\n * Check one step's resolved `config.settings` against its package's\n * settings schema, at the version the bundle would install. Findings are\n * returned for the caller to report as errors or warnings; a check that\n * cannot run is a skip; values known only at runtime are deferred.\n */\nexport async function checkStepSettings(\n target: SettingsTarget,\n resolvedFlow: Flow,\n rawFlow: unknown,\n check: ValidateCheck,\n context: SettingsContext,\n): Promise<SettingsOutcome> {\n const at = `flows.${target.flow}.${target.section}.${target.key}`;\n const outcome: SettingsOutcome = { findings: [], skipped: [], deferred: [] };\n const spec =\n typeof target.entry.package === 'string' ? target.entry.package : '';\n if (!spec) {\n outcome.skipped.push({\n path: at,\n check,\n reason: 'No package field, so there is no settings schema to fetch',\n code: 'NO_PACKAGE',\n });\n return outcome;\n }\n\n const source = packageSource(spec, rawFlow);\n let schema: PackageSchema;\n try {\n schema = await cachedSchema(source, context);\n } catch (error) {\n outcome.skipped.push({\n path: at,\n check,\n reason: `Schema for ${source.name}${source.version ? `@${source.version}` : ''} could not be loaded: ${getErrorMessage(error)}`,\n code: 'SCHEMA_UNAVAILABLE',\n });\n return outcome;\n }\n outcome.checked = {\n path: at,\n package: source.name,\n ...(schema.version ? { version: schema.version } : {}),\n };\n\n // The export the step imports, resolved as the bundler resolves it.\n const { exportName } = resolveExportName(\n resolvedFlow,\n SECTION_KIND[target.section],\n target.key,\n );\n const version = schema.version ?? source.version;\n const selection = selectSettingsSchema(\n schema,\n version ? `${source.name}@${version}` : source.name,\n exportName,\n );\n if (!selection.ok) {\n outcome.skipped.push({\n path: at,\n check,\n reason: selection.reason,\n code: 'NO_SETTINGS_SCHEMA',\n });\n return outcome;\n }\n\n const compiled = cachedCompile(\n source,\n exportName,\n selection.settings,\n context,\n );\n if (!compiled) {\n outcome.skipped.push({\n path: at,\n check,\n reason: `Package ${source.name} has no settings schema`,\n code: 'NO_SETTINGS_SCHEMA',\n });\n return outcome;\n }\n if (!compiled.ok) {\n outcome.skipped.push({\n path: at,\n check,\n reason: `The settings schema of ${source.name} cannot be compiled: ${compiled.message}`,\n code: 'SCHEMA_UNAVAILABLE',\n });\n return outcome;\n }\n const validate = compiled.validate;\n\n const step = stepOf(resolvedFlow, target.section, target.key);\n const config = isObject(step?.config) ? step.config : {};\n const prepared = prepareSettings(config.settings ?? {});\n const base = `${at}.config.settings`;\n for (const { segments, reference } of prepared.deferred) {\n outcome.deferred.push({\n path: [base, ...segments].join('.'),\n reference,\n });\n }\n\n if (validate(prepared.value)) return outcome;\n\n for (const e of validate.errors || []) {\n const segments = pointerSegments(e.instancePath);\n if (prepared.deferred.some((d) => isUnder(segments, d.segments))) continue;\n const finding: ValidationError = {\n path: [base, ...segments].join('.'),\n message: describeAjvError(e),\n code: 'ENTRY_SCHEMA',\n keyword: e.keyword,\n };\n if (segments.length > 0) finding.value = valueAt(prepared.value, segments);\n outcome.findings.push(finding);\n }\n return outcome;\n}\n\n/** Ajv's message, naming the offending key where Ajv only reports it in params. */\nfunction describeAjvError(error: ErrorObject): string {\n const message = error.message || 'Unknown error';\n const extra: unknown = error.params.additionalProperty;\n return error.keyword === 'additionalProperties' && typeof extra === 'string'\n ? `${message}: \"${extra}\"`\n : message;\n}\n\nfunction stepOf(\n flow: Flow,\n section: EntrySection,\n key: string,\n): Flow.Step | undefined {\n switch (section) {\n case 'sources':\n return flow.sources?.[key];\n case 'destinations':\n return flow.destinations?.[key];\n case 'transformers':\n return flow.transformers?.[key];\n case 'stores':\n return flow.stores?.[key];\n }\n}\n","/**\n * Shared resolver for the export name to import from a flow component's\n * package.\n *\n * Both `walkeros bundle` and `walkeros setup` need to know which named export\n * (or default) to pull off a package referenced by a flow component. The\n * precedence chain is:\n *\n * 1. `flow.<kind>.<id>.import` if set (named export selector at the step).\n * 2. `flow.config.bundle.packages[<package>].imports[0]` if set.\n * 3. Otherwise undefined; the caller falls back to the package's `default`\n * export.\n *\n * This lives in `cli/src/core/` so both `commands/bundle/*` and\n * `commands/setup/*` import the same function. Duplicating the chain is how\n * setup ended up out of sync with bundle (Bug F: `setup destination.pubsub`\n * routed through BigQuery's setup because it ignored the `code` field and\n * always grabbed `mod.default`).\n */\n\nimport type { Flow } from '@walkeros/core';\n\nexport type ComponentKind = 'source' | 'transformer' | 'destination' | 'store';\n\nexport type ResolveSource = 'import' | 'imports' | 'default';\n\nexport interface ResolvedExportName {\n /**\n * The named export to pull off the imported module, or `undefined` to\n * indicate the caller should use the package's `default` export.\n */\n exportName: string | undefined;\n /** Which precedence step produced the result (useful for diagnostics). */\n source: ResolveSource;\n}\n\ninterface FlowStepView {\n package?: string;\n import?: string;\n}\n\nfunction getStep(\n flow: Flow,\n kind: ComponentKind,\n id: string,\n): FlowStepView | undefined {\n switch (kind) {\n case 'source':\n return flow.sources?.[id];\n case 'transformer':\n return flow.transformers?.[id];\n case 'destination':\n return flow.destinations?.[id];\n case 'store':\n return flow.stores?.[id];\n }\n}\n\nfunction getBundlePackages(\n flow: Flow,\n): Record<string, Flow.BundlePackage> | undefined {\n return flow.config?.bundle?.packages;\n}\n\n/**\n * Read the first entry of `bundle.packages[<package>].imports` if it is a\n * non-empty string. Returns `undefined` otherwise.\n */\nfunction readFirstImport(\n packages: Record<string, Flow.BundlePackage> | undefined,\n packageName: string | undefined,\n): string | undefined {\n if (!packages || !packageName) return undefined;\n const pkg = packages[packageName];\n if (!pkg || !pkg.imports || pkg.imports.length === 0) return undefined;\n const first = pkg.imports[0];\n return typeof first === 'string' && first.length > 0 ? first : undefined;\n}\n\n/**\n * Resolve the export name to import for a flow component's package.\n *\n * See module docs for the precedence chain. Inline code (`code` is an object)\n * doesn't enter this resolver at all — setup rejects inline code at a higher\n * layer.\n */\nexport function resolveExportName(\n flow: Flow,\n kind: ComponentKind,\n id: string,\n): ResolvedExportName {\n const step = getStep(flow, kind, id);\n if (!step) return { exportName: undefined, source: 'default' };\n\n const packageName = step.package;\n const importName = step.import;\n\n // 1. Explicit `import` field on the step wins.\n if (typeof importName === 'string' && importName.length > 0) {\n return { exportName: importName, source: 'import' };\n }\n\n // 2. Fallback to bundle.packages[pkg].imports[0].\n const firstImport = readFirstImport(getBundlePackages(flow), packageName);\n if (firstImport) {\n return { exportName: firstImport, source: 'imports' };\n }\n\n // 3. Default export.\n return { exportName: undefined, source: 'default' };\n}\n","/**\n * Step-package normalization shared by bundle and setup.\n *\n * Pure flow-config logic: which packages do the flow's steps declare, and\n * what is the effective {name, version | path} for each after merging inline\n * step specs with config.bundle.packages pins. Lives in core/ so both\n * commands/bundle/* and commands/setup/* run the exact same precedence\n * (a bundle pin always wins; an unversioned bundle entry is filled from the\n * first inline version; conflicting inline versions with no pin throw;\n * local paths become synthetic packageNameToVariable keys).\n */\nimport type { Flow, Logger } from '@walkeros/core';\nimport { packageNameToVariable } from '@walkeros/core';\n\n/**\n * Type-narrowed accessor for a Flow section. Returns the typed step record\n * (or undefined) — exhaustive switch over the literal-union parameter avoids\n * a generic indexed-access cast.\n *\n * Returns the union of all section types when the caller passes a runtime\n * variable. Call sites that need a specific section type access the field\n * directly (e.g. `flow.sources`).\n */\nexport type FlowStepRecord =\n | Record<string, Flow.Source>\n | Record<string, Flow.Destination>\n | Record<string, Flow.Transformer>\n | Record<string, Flow.Store>;\nexport function getFlowSection(\n flow: Flow,\n section: 'sources' | 'destinations' | 'transformers' | 'stores',\n): FlowStepRecord | undefined {\n switch (section) {\n case 'sources':\n return flow.sources;\n case 'destinations':\n return flow.destinations;\n case 'transformers':\n return flow.transformers;\n case 'stores':\n return flow.stores;\n }\n}\n\n/**\n * Split a step package spec into bare name and optional version suffix.\n * `@walkeros/x@1.2.3` → { name: '@walkeros/x', version: '1.2.3' }.\n * The scope `@` at index 0 is never a separator. A trailing `@` is ignored.\n * Alias/git/file suffixes are not interpreted — the resolver handles or\n * rejects them downstream.\n */\nexport function parsePackageSpec(spec: string): {\n name: string;\n version?: string;\n} {\n const at = spec.lastIndexOf('@');\n if (at <= 0) return { name: spec };\n const version = spec.slice(at + 1);\n return version\n ? { name: spec.slice(0, at), version }\n : { name: spec.slice(0, at) };\n}\n\n/**\n * Detects destination packages from flow configuration.\n * Extracts package names from destinations that have explicit 'package' field.\n */\n/**\n * Detects packages from a flow config section (sources, destinations, transformers, stores).\n * Extracts package names from steps that have an explicit 'package' field.\n */\nexport function detectStepPackages(\n flowSettings: Flow,\n section: 'sources' | 'destinations' | 'transformers' | 'stores',\n): Set<string> {\n const packages = new Set<string>();\n const steps = getFlowSection(flowSettings, section);\n\n if (steps) {\n for (const [, stepConfig] of Object.entries(steps)) {\n if (typeof stepConfig !== 'object' || stepConfig === null) continue;\n // Require explicit package field\n if (typeof stepConfig.package === 'string') {\n packages.add(stepConfig.package);\n }\n }\n }\n\n return packages;\n}\n\n/**\n * Collects all package names declared in flow steps.\n * Returns both npm packages and local paths — caller handles routing.\n */\nexport function collectAllStepPackages(flowSettings: Flow): Set<string> {\n const allPackages = new Set<string>();\n const sections = [\n 'sources',\n 'destinations',\n 'transformers',\n 'stores',\n ] as const;\n\n for (const section of sections) {\n for (const pkg of detectStepPackages(flowSettings, section)) {\n allPackages.add(pkg);\n }\n }\n\n return allPackages;\n}\n\n/**\n * Auto-adds every step-declared package (sources, destinations, transformers,\n * stores) to `packages`, mutating `flowSettings` in place so each step's\n * `package` field points at the key that ends up in `packages`.\n *\n * Local paths (`.` or `/` prefixed) are normalized to a synthetic\n * `packageNameToVariable` key so the regular default-import codegen wires\n * them up automatically.\n *\n * npm specs go through `parsePackageSpec` to split an inline version\n * (`@walkeros/x@1.2.3`) from the bare name. Precedence policy:\n * - An explicit `config.bundle.packages` version always wins; a disagreeing\n * inline version only warns (bundle pin is authoritative).\n * - An unversioned bundle entry is filled from the first inline version seen\n * for that bare name, preserving any other fields already on the entry.\n * - Two different inline versions for the same bare name, with no bundle\n * pin to arbitrate, are ambiguous — throw naming both steps' versions\n * rather than silently picking one.\n * - Identical inline versions across steps are fine (no-op).\n * Alias/git/file suffixes are not special-cased: `parsePackageSpec` splits on\n * the last `@` and the resolver handles or rejects the rest downstream.\n */\nexport function applyStepPackages(\n flowSettings: Flow,\n packages: Record<string, Flow.BundlePackage>,\n logger: Logger.Instance,\n): void {\n const stepPackages = collectAllStepPackages(flowSettings);\n // Bundle-pinned version per bare name, captured the first time each name is\n // encountered — i.e. before this function's own fill-ins can be mistaken\n // for a real `config.bundle.packages` pin on a later iteration.\n const originalPins = new Map<string, boolean>();\n // Inline version already seen per bare name (with no real bundle pin),\n // used to detect a second, different inline version for the same name.\n const inlineSeen = new Map<string, string>();\n\n const rewriteSteps = (from: string, to: string): void => {\n for (const section of [\n 'sources',\n 'destinations',\n 'transformers',\n 'stores',\n ] as const) {\n const steps = getFlowSection(flowSettings, section);\n if (!steps) continue;\n for (const step of Object.values(steps)) {\n if (step.package === from) {\n step.package = to;\n }\n }\n }\n };\n\n for (const pkg of stepPackages) {\n const isLocalPath = pkg.startsWith('.') || pkg.startsWith('/');\n\n if (isLocalPath) {\n // Normalize: convert path-based package: to packages section entry.\n // The synthetic key acts as the package name for downstream codegen,\n // so the regular default-import flow wires it up automatically.\n const varName = packageNameToVariable(pkg);\n if (!packages[varName]) {\n packages[varName] = {\n path: pkg,\n };\n }\n\n // Rewrite all components that reference the raw path to point at the\n // synthetic packages-section key instead.\n rewriteSteps(pkg, varName);\n continue;\n }\n\n const { name, version } = parsePackageSpec(pkg);\n\n if (!originalPins.has(name)) {\n const entry = packages[name];\n // A `path` entry is a pin too: local paths win at resolution, so the\n // inline versions the steps declare can never be used.\n originalPins.set(\n name,\n entry?.version !== undefined || entry?.path !== undefined,\n );\n }\n const hasBundlePin = originalPins.get(name) === true;\n\n if (name !== pkg) {\n // Rewrite every step that declared the versioned spec to the bare\n // name, mirroring the local-path rewrite above.\n rewriteSteps(pkg, name);\n }\n\n if (version && !hasBundlePin) {\n const seen = inlineSeen.get(name);\n if (seen !== undefined && seen !== version) {\n throw new Error(\n `Conflicting inline versions for ${name}: \"${seen}\" and \"${version}\" are ` +\n `declared by different steps. Pin one version in config.bundle.packages.`,\n );\n }\n inlineSeen.set(name, version);\n }\n\n const existing = packages[name];\n if (!existing) {\n packages[name] = version ? { version } : {};\n } else if (version && !existing.path) {\n // A path entry decides on its own; stamping a version onto it would\n // record a version that resolution never consults.\n if (!existing.version) {\n existing.version = version; // fill an unversioned bundle entry\n } else if (existing.version !== version) {\n logger.warn(\n `Package ${name}: config.bundle.packages pins ${existing.version}; ` +\n `a step declares ${version} inline. Using the bundle pin.`,\n );\n }\n }\n }\n}\n","// walkerOS/packages/cli/src/commands/validate/validators/mapping.ts\n\nimport { isObject } from '@walkeros/core';\nimport { schemas } from '@walkeros/core/dev';\nimport type {\n ValidateDetails,\n ValidateResult,\n ValidationError,\n ValidationWarning,\n} from '../types.js';\n\nconst { RuleSchema } = schemas.MappingSchemas;\n\nfunction isRule(value: unknown): boolean {\n return isObject(value) && RuleSchema.safeParse(value).success;\n}\n\n/**\n * The nested runtime shape: an entity key whose value maps actions to a rule\n * or a list of rules (`{ page: { view: { name: 'page_view' } } }`).\n */\nfunction isNestedActions(\n key: string,\n value: unknown,\n): value is Record<string, unknown> {\n if (key.includes(' ') || !isObject(value)) return false;\n const rules = Object.values(value);\n return (\n rules.length > 0 &&\n rules.every((rule) =>\n Array.isArray(rule)\n ? rule.length > 0 && rule.every(isRule)\n : isRule(rule),\n )\n );\n}\n\nexport function validateMapping(input: unknown): ValidateResult {\n const errors: ValidationError[] = [];\n const warnings: ValidationWarning[] = [];\n const details: ValidateDetails = {};\n\n // Must be an object\n if (!isObject(input)) {\n errors.push({\n path: 'root',\n message: 'Mapping must be an object with event patterns as keys',\n code: 'INVALID_MAPPING_TYPE',\n });\n return { valid: false, type: 'mapping', errors, warnings, details };\n }\n\n const mapping = input;\n const nestedPatterns: string[] = [];\n const flatPatterns: string[] = [];\n for (const [key, value] of Object.entries(mapping)) {\n if (isNestedActions(key, value)) {\n for (const action of Object.keys(value))\n nestedPatterns.push(`${key} ${action}`);\n } else {\n flatPatterns.push(key);\n }\n }\n const patterns = [...nestedPatterns, ...flatPatterns];\n details.eventPatterns = patterns;\n details.patternCount = patterns.length;\n\n // Validate each flat \"entity action\" pattern (legacy flat shape)\n flatPatterns.forEach((pattern, index) => {\n // Check pattern format: must be \"entity action\", contain wildcard, or be \"*\"\n const isWildcard = pattern.includes('*');\n const hasSpace = pattern.includes(' ');\n\n if (!isWildcard && !hasSpace) {\n errors.push({\n path: pattern,\n message: `Invalid event pattern \"${pattern}\". Must be \"entity action\" format or contain wildcard (*)`,\n code: 'INVALID_EVENT_PATTERN',\n });\n }\n\n // Warn if catch-all is not last\n if (pattern === '*' && index !== flatPatterns.length - 1) {\n warnings.push({\n path: '*',\n code: 'CATCH_ALL_NOT_LAST',\n message: 'Catch-all pattern (*) should be last',\n suggestion:\n 'Move the catch-all pattern (*) to last position for predictable matching',\n });\n }\n\n // Validate rule structure (accepts single rule object or array of rules)\n const rule = mapping[pattern];\n const isValidRule = Array.isArray(rule)\n ? rule.every((r) => typeof r === 'object' && r !== null)\n : typeof rule === 'object' && rule !== null;\n\n if (!isValidRule) {\n errors.push({\n path: pattern,\n message: 'Mapping rule must be an object or array of objects',\n code: 'INVALID_RULE_TYPE',\n });\n }\n });\n\n return {\n valid: errors.length === 0,\n type: 'mapping',\n errors,\n warnings,\n details,\n };\n}\n","// walkerOS/packages/cli/src/commands/validate/validators/entry.ts\n\nimport { describeScope, isFlowJson, resolveScope } from '../scope.js';\nimport type {\n ValidateDeferred,\n ValidateResult,\n ValidateSkip,\n ValidationError,\n} from '../types.js';\nimport { resolveFlow, type FlowResolution } from './resolve.js';\nimport {\n checkStepSettings,\n createSettingsContext,\n type CheckedPackage,\n} from './settings.js';\n\n/**\n * Validate an entry (source, destination, transformer or store) addressed by\n * `path` (`section.key` or `key`) against its package's published JSON\n * Schema, in every flow that has it, or only in `options.flow`. Settings are\n * checked as the flow resolves them (the placeholder rule); a flow that does\n * not resolve is an error and its entry check a skip.\n */\nexport async function validateEntry(\n path: string,\n flowConfig: unknown,\n options: { flow?: string; configDir?: string } = {},\n): Promise<ValidateResult> {\n const resolved = resolveScope(flowConfig, { flow: options.flow, path });\n const errors: ValidationError[] = [...resolved.errors];\n const skipped: ValidateSkip[] = [];\n const deferred: ValidateDeferred[] = [];\n const packages: CheckedPackage[] = [];\n const context = createSettingsContext(options.configDir);\n const file = isFlowJson(flowConfig) ? flowConfig : undefined;\n const resolutions = new Map<string, FlowResolution>();\n\n for (const target of resolved.entries) {\n const at = `flows.${target.flow}.${target.section}.${target.key}`;\n let resolution = resolutions.get(target.flow);\n if (!resolution && file) {\n resolution = resolveFlow(file, target.flow);\n resolutions.set(target.flow, resolution);\n if (!resolution.ok) errors.push(resolution.error);\n }\n if (!resolution?.ok) {\n skipped.push({\n path: at,\n check: 'entry:settings',\n reason: `flows.${target.flow} does not resolve, so its settings cannot be checked`,\n code: 'GATED_BY_ERRORS',\n });\n continue;\n }\n const outcome = await checkStepSettings(\n target,\n resolution.flow,\n file?.flows[target.flow],\n 'entry:settings',\n context,\n );\n errors.push(...outcome.findings);\n skipped.push(...outcome.skipped);\n deferred.push(...outcome.deferred);\n if (outcome.checked) packages.push(outcome.checked);\n }\n\n return {\n valid: errors.length === 0,\n type: 'entry',\n errors,\n warnings: [],\n details: {\n scope: describeScope(resolved, ['entry:settings']),\n skipped,\n deferred,\n ...(packages.length > 0 ? { packages } : {}),\n },\n };\n}\n","// walkerOS/packages/cli/src/commands/validate/types.ts\n\nimport type {\n ValidateResult as CoreValidateResult,\n ValidationError as CoreValidationError,\n ValidationType,\n ValidationWarning as CoreValidationWarning,\n} from '@walkeros/core/dev';\n\n// Base result types are declared in @walkeros/core/dev beside\n// validateFlowStructure, so consumers can type its return without the CLI.\n// The CLI narrows them: every code comes from VALIDATE_CODES, and the\n// details carry the scope, skips and deferred values of the run.\nexport type { ValidateResultType, ValidationType } from '@walkeros/core/dev';\n\n/**\n * Every code an error, warning or skip of `validate` can carry. Agents and\n * tests branch on these, never on message text.\n */\nexport const VALIDATE_CODES = [\n // Input and options\n 'INPUT_ERROR',\n 'SERIALIZATION_ERROR',\n 'OPTION_NOT_APPLICABLE',\n // Scope (--flow, --path)\n 'FLOW_NOT_FOUND',\n 'ENTRY_NOT_FOUND',\n 'AMBIGUOUS_ENTRY',\n 'UNSUPPORTED_SECTION',\n 'INVALID_PATH',\n // Flow file\n 'SCHEMA_VALIDATION',\n 'CONFIG_WARNING',\n 'EMPTY_FLOWS',\n 'UNKNOWN_KEY',\n 'CONFLICT',\n 'MISSING_PACKAGE',\n 'OBSOLETE_CODE_STRING',\n 'INVALID_IMPORT',\n 'INVALID_CODE_SHAPE',\n 'PACKAGE_VERSION_MISSING',\n 'DEPRECATED_PACKAGE',\n 'UNKNOWN_ROUTE_TARGET',\n 'ROUTE_DEAD_CODE',\n 'ROUTE_EMPTY_MANY',\n 'ROUTE_SINGLE_MANY',\n 'ROUTE_FIRST_MATCH',\n 'INCOMPATIBLE_EXAMPLES',\n 'EXAMPLES_INCOMPLETE',\n 'CONTRACT_VIOLATION',\n 'MAPPING_DOT_KEY',\n 'FLOW_REF_WARNING',\n 'FLOW_CYCLE',\n 'VAR_CYCLE',\n // Structure (the bundler's own preflight, validateFlowStructure)\n 'INVALID_COMPONENT_NAME',\n 'INVALID_REFERENCE',\n 'STORE_REFERENCE_NOT_FOUND',\n 'STATE_STORE_UNKNOWN',\n 'STATE_STORE_FILE',\n 'TRANSFORMER_MAPPING_NO_OP',\n // Resolution (getFlowSettings, as the bundler resolves the flow)\n 'UNRESOLVED_REFERENCE',\n 'MISSING_ENV',\n 'WEB_SECRET_REF',\n 'UNRESOLVED_CONTRACT',\n // Entry settings against the package schema\n 'ENTRY_SCHEMA',\n // Contract\n 'NO_CONTRACT_SECTION',\n 'INVALID_CONTRACT',\n 'FLAT_CONTRACT_SHAPE',\n 'INVALID_CONTRACT_ENTRY',\n 'UNKNOWN_CONTRACT_KEY',\n 'INVALID_TAGGING',\n 'INVALID_SCHEMA',\n 'INVALID_EXTENDS',\n 'INVALID_SECTION',\n 'INVALID_EVENTS',\n 'CIRCULAR_EXTENDS',\n 'INVALID_ENTITY_KEY',\n 'INVALID_ENTITY',\n 'INVALID_ACTION_KEY',\n 'INVALID_SCHEMA_ENTRY',\n // Event\n 'NOT_AN_OBJECT',\n 'MISSING_EVENT_NAME',\n 'EMPTY_EVENT_NAME',\n 'INVALID_EVENT_NAME',\n // Mapping\n 'INVALID_MAPPING_TYPE',\n 'INVALID_EVENT_PATTERN',\n 'INVALID_RULE_TYPE',\n 'CATCH_ALL_NOT_LAST',\n // Skips (details.skipped[].code)\n 'GATED_BY_ERRORS',\n 'CONTRACT_NOT_STATIC',\n 'NO_PACKAGE',\n 'NO_SETTINGS_SCHEMA',\n 'SCHEMA_UNAVAILABLE',\n] as const;\n\nexport type ValidateCode = (typeof VALIDATE_CODES)[number];\n\n/** Codes that mean validate could not run as asked (CLI exit 3). */\nexport const USAGE_CODES: readonly ValidateCode[] = ['OPTION_NOT_APPLICABLE'];\n\n/**\n * Named checks a run includes (`details.scope.checks`). `file:` checks run\n * on the whole file whatever `--flow` says; `flow:` checks run per flow in\n * scope; `entry:` checks run per entry `--path` addressed.\n */\nexport type ValidateCheck =\n | 'file:schema'\n | 'file:contract'\n | 'flow:schema'\n | 'flow:steps'\n | 'flow:structure'\n | 'flow:package-versions'\n | 'flow:routes'\n | 'flow:examples'\n | 'flow:contract-examples'\n | 'flow:mapping-keys'\n | 'flow:resolve'\n | 'flow:package-settings'\n | 'entry:settings'\n | 'contract'\n | 'event'\n | 'mapping';\n\nexport interface ValidateScopeEntry {\n /** Section of the addressed entry, when the path or the match names one. */\n section?: string;\n key: string;\n /** Flows that have the entry and were checked. */\n flows: string[];\n /** Flows searched for the entry. */\n searchedFlows: string[];\n}\n\n/** What a run covered (C6). */\nexport interface ValidateScope {\n flows: string[];\n entry?: ValidateScopeEntry;\n checks: ValidateCheck[];\n /** Set when `offline` removed the package settings check from `checks`. */\n offline?: true;\n}\n\n/** A check the scope includes that did not run (C5). */\nexport interface ValidateSkip {\n path: string;\n check: ValidateCheck;\n reason: string;\n code: ValidateCode;\n}\n\n/** A value known only at runtime, not schema-checked (info, not a skip). */\nexport interface ValidateDeferred {\n path: string;\n reference: string;\n}\n\nexport interface ValidateDetails {\n scope?: ValidateScope;\n skipped?: ValidateSkip[];\n deferred?: ValidateDeferred[];\n [key: string]: unknown;\n}\n\n// `code` stays core's `string` for consumers; validate emits only\n// ValidateCode values.\nexport interface ValidationError extends CoreValidationError {\n /** The JSON Schema keyword of an ENTRY_SCHEMA error. */\n keyword?: string;\n}\n\nexport interface ValidationWarning extends CoreValidationWarning {\n keyword?: string;\n}\n\nexport interface ValidateResult extends CoreValidateResult {\n errors: ValidationError[];\n warnings: ValidationWarning[];\n details: ValidateDetails;\n}\n\nexport interface ValidateCommandOptions {\n type: ValidationType;\n input?: string;\n output?: string;\n flow?: string; // Flow name for multi-flow configs\n path?: string; // Entry path for dot-notation validation (e.g., \"destinations.snowplow\")\n json?: boolean;\n verbose?: boolean;\n strict?: boolean;\n /** Skip every package settings check (no network); named in the scope. */\n offline?: boolean;\n silent?: boolean;\n}\n"],"mappings":"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","names":["fs","path","chalk","isObject","fs","fs","fs","fs","fs","z","z","schemas","fs","fs","isObject","validateEvent","checkWindowCollector","ENV_MARKER_PREFIX","isObject","schemas","isObject","path","getFlowSettings","getErrorMessage","fs","path","getErrorMessage","isObject","isObject","schemas","getErrorMessage","validate","validateFlowConfig","schemas","isObject","path","validateFlowConfig","result","ENV_MARKER_PREFIX","checkWindowCollector","isObject","schemas","path","isObject","validateEvent"]}
|