@kehto/paja 0.6.3 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { spawn, type ChildProcess } from 'node:child_process';\nimport {\n createPajaHostConfig,\n formatPajaUrl,\n normalizePajaOptions,\n waitForTargetUrl,\n type PajaCommand,\n type PajaRawOptions,\n PajaOptionsError,\n} from './index.js';\nimport { resolvePajaRawOptions } from './config-file.js';\nimport { startPajaServer } from './server.js';\nimport {\n PAJA_SIMULATION_DOMAINS,\n summarizePajaSimulation,\n type PajaCapabilityDomain,\n type PajaSimulationRawOptions,\n type JsonValue,\n} from './simulation.js';\n\n/**\n * Minimal output streams used by the CLI runner.\n *\n * @remarks\n * Tests and embedders can pass custom streams to capture output without\n * patching global `process.stdout` or `process.stderr`.\n */\nexport interface CliIo {\n readonly stdout: { write(chunk: string): void };\n readonly stderr: { write(chunk: string): void };\n}\n\n/**\n * Parsed CLI arguments before full option normalization.\n */\nexport interface CliParseResult {\n readonly options?: PajaRawOptions;\n readonly help: boolean;\n}\n\n/**\n * Execution controls for embedding the CLI runner in tests or wrappers.\n */\nexport interface RunPajaCliOptions {\n readonly serve?: boolean;\n readonly startServer?: typeof startPajaServer;\n readonly startCommand?: (command: PajaCommand, io: CliIo) => ManagedChildProcess;\n readonly waitForTargetUrl?: typeof waitForTargetUrl;\n readonly targetDiscoveryGraceMs?: number;\n}\n\n/**\n * Parse raw `kehto paja` arguments into raw runtime options.\n *\n * @param args - Argument vector without the node executable or script path.\n * @returns Parsed raw options, or a help flag when `--help` is present.\n */\nexport function parsePajaArgs(args: readonly string[]): CliParseResult {\n const raw: MutablePajaRawOptions = {};\n\n for (let index = 0; index < args.length; index += 1) {\n const arg = args[index];\n\n if (arg === '--') {\n const argv = args.slice(index + 1);\n raw.command = { mode: 'argv', argv };\n break;\n }\n\n if (arg === '--help' || arg === '-h') {\n return { help: true };\n }\n\n if (applyCoreOption(arg, args, index, raw) || applySimulationOption(arg, args, index, raw)) {\n index += 1;\n continue;\n }\n\n throw new PajaOptionsError(`Unknown option \"${arg}\". Run kehto paja --help for usage.`);\n }\n\n return { help: false, options: raw };\n}\n\nexport async function runPajaCli(\n args: readonly string[] = process.argv.slice(2),\n io: CliIo = defaultIo,\n runOptions: RunPajaCliOptions = {},\n): Promise<number> {\n try {\n const parsed = parsePajaArgs(args);\n if (parsed.help) {\n io.stdout.write(`${HELP_TEXT}\\n`);\n return 0;\n }\n\n const rawOptions = resolvePajaRawOptions(parsed.options ?? {});\n const options = normalizePajaOptions(rawOptions);\n const hostConfig = createPajaHostConfig(options);\n const shouldServe = runOptions.serve ?? true;\n const startServer = runOptions.startServer ?? startPajaServer;\n const startCommand = runOptions.startCommand ?? startManagedCommand;\n const waitForTarget = runOptions.waitForTargetUrl ?? waitForTargetUrl;\n let child: ManagedChildProcess | undefined;\n let server: Awaited<ReturnType<typeof startPajaServer>> | undefined;\n if (shouldServe) {\n try {\n server = await startServer({ options: rawOptions });\n writeRuntimeSummary(io, server.url, hostConfig, options);\n\n if (options.command) {\n child = startCommand(options.command, io);\n const targetUrl = await resolveManagedTargetUrl(options.targetUrl, child, {\n timeoutMs: options.readyTimeoutMs,\n discoveryGraceMs: runOptions.targetDiscoveryGraceMs,\n waitForTargetUrl: waitForTarget,\n });\n if (targetUrl !== options.targetUrl) {\n server.updateTargetUrl(targetUrl);\n io.stdout.write(`Target URL updated: ${targetUrl}\\n`);\n }\n }\n } catch (error) {\n child?.kill();\n await server?.close().catch(() => undefined);\n throw error;\n }\n }\n const runtimeUrl = server?.url ?? formatPajaUrl(options);\n\n if (!shouldServe) {\n writeRuntimeSummary(io, runtimeUrl, hostConfig, options);\n }\n\n return 0;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n io.stderr.write(`kehto paja: ${message}\\n`);\n return 1;\n }\n}\n\nfunction writeRuntimeSummary(\n io: CliIo,\n runtimeUrl: string,\n hostConfig: ReturnType<typeof createPajaHostConfig>,\n options: ReturnType<typeof normalizePajaOptions>,\n): void {\n io.stdout.write(`Kehto Paja\\n`);\n io.stdout.write(`Runtime URL: ${runtimeUrl}\\n`);\n io.stdout.write(`Target URL: ${hostConfig.target.url}\\n`);\n io.stdout.write(`Mode: ${options.mode}\\n`);\n io.stdout.write(`HMR: ${hostConfig.target.hmrStrategy}\\n`);\n io.stdout.write(`Simulation: ${summarizePajaSimulation(options.simulation)}\\n`);\n\n if (options.command) {\n io.stdout.write(`Command: ${formatCommand(options.command)}\\n`);\n }\n}\n\nconst HELP_TEXT = `Usage:\n kehto paja --target-url <url> [options]\n kehto paja --target-url <url> [options] -- <command...>\n\nOptions:\n --target-url, -u <url> App dev-server URL to load in the runtime iframe.\n --command, -c <command> Shell command to start before waiting for target URL.\n -- <command...> Argv command form; preserves arbitrary framework commands.\n --host <host> Runtime host. Default: 127.0.0.1.\n --port <port> Runtime port. Default: 5197.\n --ready-timeout <ms> Target readiness timeout. Default: 30000.\n --config <path> JSON config file using the same option schema.\n --identity-mode <mode> anonymous or fixed.\n --identity-pubkey <hex> Required when identity mode is fixed.\n --relay-mode <mode> memory or disabled.\n --relay-url <url> Add a relay URL for memory relay simulation.\n --storage-mode <mode> local, memory, or disabled.\n --cache-mode <mode> memory or disabled.\n --upload-mode <mode> memory or disabled.\n --upload-rail <name> Upload rail name for memory uploads.\n --media <state> enabled or disabled.\n --notifications <state> enabled or disabled.\n --notify-grant <bool> true or false default notification grant.\n --theme <mode> dark or light.\n --config-value <key=json> Add a JSON config value.\n --capability <domain:on|off> Toggle an advertised capability domain.\n --acl-mode <mode> allow or deny.\n --firewall-mode <mode> allow, deny, or observe.\n --help, -h Show this help.`;\n\nfunction readValue(args: readonly string[], index: number, option: string): string {\n const value = args[index + 1];\n if (!value || value.startsWith('--')) {\n throw new PajaOptionsError(`${option} requires a value.`);\n }\n return value;\n}\n\nfunction applyCoreOption(\n arg: string,\n args: readonly string[],\n index: number,\n raw: MutablePajaRawOptions,\n): boolean {\n switch (arg) {\n case '--target-url':\n case '-u':\n raw.targetUrl = readValue(args, index, arg);\n return true;\n case '--command':\n case '-c':\n raw.command = { mode: 'shell', command: readValue(args, index, arg) };\n return true;\n case '--host':\n raw.host = readValue(args, index, arg);\n return true;\n case '--port':\n raw.port = readValue(args, index, arg);\n return true;\n case '--ready-timeout':\n raw.readyTimeoutMs = readValue(args, index, arg);\n return true;\n case '--config':\n raw.configPath = readValue(args, index, arg);\n return true;\n default:\n return false;\n }\n}\n\nfunction applySimulationOption(\n arg: string,\n args: readonly string[],\n index: number,\n raw: MutablePajaRawOptions,\n): boolean {\n switch (arg) {\n case '--identity-mode':\n setIdentity(raw, { mode: readEnum(args, index, arg, ['anonymous', 'fixed']) });\n return true;\n case '--identity-pubkey':\n setIdentity(raw, { pubkey: readValue(args, index, arg) });\n return true;\n case '--relay-mode':\n setRelay(raw, { mode: readEnum(args, index, arg, ['memory', 'disabled']) });\n return true;\n case '--relay-url':\n setRelay(raw, { urls: [...(raw.simulation?.relay?.urls ?? []), readValue(args, index, arg)] });\n return true;\n case '--storage-mode':\n ensureSimulation(raw).storage = { ...raw.simulation?.storage, mode: readEnum(args, index, arg, ['local', 'memory', 'disabled']) };\n return true;\n case '--cache-mode':\n ensureSimulation(raw).cache = { ...raw.simulation?.cache, mode: readEnum(args, index, arg, ['memory', 'disabled']) };\n return true;\n case '--upload-mode':\n setUpload(raw, { mode: readEnum(args, index, arg, ['memory', 'disabled']) });\n return true;\n case '--upload-rail':\n setUpload(raw, { rail: readValue(args, index, arg) });\n return true;\n case '--media':\n ensureSimulation(raw).media = { ...raw.simulation?.media, enabled: readEnabled(args, index, arg) };\n return true;\n case '--notifications':\n setNotifications(raw, { enabled: readEnabled(args, index, arg) });\n return true;\n case '--notify-grant':\n setNotifications(raw, { grant: readBoolean(args, index, arg) });\n return true;\n case '--theme':\n ensureSimulation(raw).theme = { ...raw.simulation?.theme, mode: readEnum(args, index, arg, ['dark', 'light']) };\n return true;\n case '--config-value':\n setConfigValue(raw, readConfigValue(args, index, arg));\n return true;\n case '--capability':\n setCapability(raw, readCapability(args, index, arg));\n return true;\n case '--acl-mode':\n ensureSimulation(raw).acl = { ...raw.simulation?.acl, mode: readEnum(args, index, arg, ['allow', 'deny']) };\n return true;\n case '--firewall-mode':\n ensureSimulation(raw).firewall = { ...raw.simulation?.firewall, mode: readEnum(args, index, arg, ['allow', 'deny', 'observe']) };\n return true;\n default:\n return false;\n }\n}\n\nfunction formatCommand(command: PajaCommand): string {\n return command.mode === 'argv' ? command.argv.join(' ') : command.command;\n}\n\nfunction readEnum<const T extends readonly string[]>(\n args: readonly string[],\n index: number,\n option: string,\n allowed: T,\n): T[number] {\n const value = readValue(args, index, option);\n if (!allowed.includes(value)) {\n throw new PajaOptionsError(`${option} must be one of: ${allowed.join(', ')}.`);\n }\n return value;\n}\n\nfunction readEnabled(args: readonly string[], index: number, option: string): boolean {\n const value = readValue(args, index, option);\n if (value === 'enabled') return true;\n if (value === 'disabled') return false;\n throw new PajaOptionsError(`${option} must be \"enabled\" or \"disabled\".`);\n}\n\nfunction readBoolean(args: readonly string[], index: number, option: string): boolean {\n const value = readValue(args, index, option);\n if (value === 'true') return true;\n if (value === 'false') return false;\n throw new PajaOptionsError(`${option} must be \"true\" or \"false\".`);\n}\n\nfunction readConfigValue(\n args: readonly string[],\n index: number,\n option: string,\n): { key: string; value: JsonValue } {\n const raw = readValue(args, index, option);\n const separator = raw.indexOf('=');\n if (separator <= 0) {\n throw new PajaOptionsError(`${option} expects key=json.`);\n }\n const key = raw.slice(0, separator).trim();\n if (!key) {\n throw new PajaOptionsError(`${option} expects a non-empty key.`);\n }\n try {\n return { key, value: JSON.parse(raw.slice(separator + 1)) as JsonValue };\n } catch {\n throw new PajaOptionsError(`${option} value for \"${key}\" must be valid JSON.`);\n }\n}\n\nfunction readCapability(\n args: readonly string[],\n index: number,\n option: string,\n): { domain: PajaCapabilityDomain; enabled: boolean } {\n const raw = readValue(args, index, option);\n const [domainRaw, stateRaw] = raw.split(':') as [string | undefined, string | undefined];\n if (!domainRaw || (stateRaw !== 'on' && stateRaw !== 'off')) {\n throw new PajaOptionsError(`${option} expects domain:on or domain:off.`);\n }\n if (!PAJA_SIMULATION_DOMAINS.includes(domainRaw as PajaCapabilityDomain)) {\n throw new PajaOptionsError(`${option} unknown domain \"${domainRaw}\".`);\n }\n return {\n domain: domainRaw as PajaCapabilityDomain,\n enabled: stateRaw === 'on',\n };\n}\n\nfunction setIdentity(raw: MutablePajaRawOptions, identity: NonNullable<PajaSimulationRawOptions['identity']>): void {\n ensureSimulation(raw).identity = { ...raw.simulation?.identity, ...identity };\n}\n\nfunction setRelay(raw: MutablePajaRawOptions, relay: NonNullable<PajaSimulationRawOptions['relay']>): void {\n ensureSimulation(raw).relay = { ...raw.simulation?.relay, ...relay };\n}\n\nfunction setUpload(raw: MutablePajaRawOptions, upload: NonNullable<PajaSimulationRawOptions['upload']>): void {\n ensureSimulation(raw).upload = { ...raw.simulation?.upload, ...upload };\n}\n\nfunction setNotifications(\n raw: MutablePajaRawOptions,\n notifications: NonNullable<PajaSimulationRawOptions['notifications']>,\n): void {\n ensureSimulation(raw).notifications = { ...raw.simulation?.notifications, ...notifications };\n}\n\nfunction setConfigValue(\n raw: MutablePajaRawOptions,\n entry: { key: string; value: JsonValue },\n): void {\n ensureSimulation(raw).config = {\n ...raw.simulation?.config,\n values: {\n ...raw.simulation?.config?.values,\n [entry.key]: entry.value,\n },\n };\n}\n\nfunction setCapability(\n raw: MutablePajaRawOptions,\n entry: { domain: PajaCapabilityDomain; enabled: boolean },\n): void {\n ensureSimulation(raw).capabilities = {\n ...raw.simulation?.capabilities,\n domains: {\n ...raw.simulation?.capabilities?.domains,\n [entry.domain]: entry.enabled,\n },\n };\n}\n\nfunction ensureSimulation(raw: MutablePajaRawOptions): MutablePajaSimulationRawOptions {\n raw.simulation ??= {};\n return raw.simulation as MutablePajaSimulationRawOptions;\n}\n\nasync function resolveManagedTargetUrl(\n configuredUrl: string,\n child: ManagedChildProcess,\n options: {\n readonly timeoutMs: number;\n readonly discoveryGraceMs?: number;\n readonly waitForTargetUrl: typeof waitForTargetUrl;\n },\n): Promise<string> {\n let configuredError: unknown;\n const configuredReady = options.waitForTargetUrl(configuredUrl, { timeoutMs: options.timeoutMs })\n .then(() => configuredUrl)\n .catch((error) => {\n configuredError = error;\n return undefined;\n });\n const first = await Promise.race([\n configuredReady.then((url) => url ? { kind: 'configured' as const, url } : undefined),\n child.detectedTargetUrl.then((url) => ({ kind: 'detected' as const, url })),\n ]);\n\n if (first?.kind === 'detected') {\n await options.waitForTargetUrl(first.url, { timeoutMs: options.timeoutMs });\n return first.url;\n }\n\n const graceMs = options.discoveryGraceMs ?? Math.min(1000, options.timeoutMs);\n const detected = await resolveWithin(child.detectedTargetUrl, graceMs);\n if (!detected) {\n if (first?.url) {\n return first.url;\n }\n throw configuredError instanceof Error ? configuredError : new Error(String(configuredError ?? 'Target URL was not ready.'));\n }\n\n await options.waitForTargetUrl(detected, { timeoutMs: options.timeoutMs });\n return detected;\n}\n\nfunction resolveWithin<T>(promise: Promise<T>, timeoutMs: number): Promise<T | undefined> {\n return new Promise((resolve) => {\n let settled = false;\n const timeout = setTimeout(() => {\n if (settled) return;\n settled = true;\n resolve(undefined);\n }, Math.max(0, timeoutMs));\n\n promise.then((value) => {\n if (settled) return;\n settled = true;\n clearTimeout(timeout);\n resolve(value);\n }, () => {\n if (settled) return;\n settled = true;\n clearTimeout(timeout);\n resolve(undefined);\n });\n });\n}\n\nfunction startManagedCommand(command: PajaCommand, io: CliIo): ManagedChildProcess {\n const detector = createManagedTargetUrlDetector();\n const child = spawnManagedCommand(command);\n forwardManagedOutput(child, detector, io);\n return {\n kill: () => child.kill(),\n detectedTargetUrl: detector.detectedTargetUrl,\n };\n}\n\nfunction spawnManagedCommand(command: PajaCommand): ChildProcess {\n if (command.mode === 'shell') {\n return spawn(command.command, { shell: true, stdio: ['inherit', 'pipe', 'pipe'] as const });\n }\n\n const [executable, ...args] = command.argv;\n if (!executable) {\n throw new PajaOptionsError('Argv command mode requires an executable.');\n }\n return spawn(executable, args, { stdio: ['inherit', 'pipe', 'pipe'] as const });\n}\n\nfunction forwardManagedOutput(\n child: ChildProcess,\n detector: ManagedTargetUrlDetector,\n io: CliIo,\n): void {\n child.stdout?.on('data', (chunk: string | Uint8Array) => {\n const text = String(chunk);\n detector.observe(text);\n io.stdout.write(text);\n });\n child.stderr?.on('data', (chunk: string | Uint8Array) => {\n const text = String(chunk);\n detector.observe(text);\n io.stderr.write(text);\n });\n}\n\nfunction createManagedTargetUrlDetector(): ManagedTargetUrlDetector {\n let resolveDetected: (url: string) => void = () => {\n // Promise executor replaces this before any child-process output can arrive.\n };\n let detected: string | undefined;\n const detectedTargetUrl = new Promise<string>((resolve) => {\n resolveDetected = resolve;\n });\n\n return {\n detectedTargetUrl,\n observe(chunk) {\n if (detected) return;\n const text = stripAnsi(chunk);\n for (const match of text.matchAll(LOCAL_HTTP_URL_PATTERN)) {\n const rawUrl = match[0];\n let url: URL;\n try {\n url = new URL(rawUrl);\n } catch {\n continue;\n }\n detected = url.href;\n resolveDetected(detected);\n return;\n }\n },\n };\n}\n\nfunction stripAnsi(value: string): string {\n return value.replace(ANSI_PATTERN, '');\n}\n\ntype MutablePajaRawOptions = {\n -readonly [K in keyof PajaRawOptions]: PajaRawOptions[K];\n};\n\ntype MutablePajaSimulationRawOptions = {\n -readonly [K in keyof PajaSimulationRawOptions]: PajaSimulationRawOptions[K];\n};\n\nconst defaultIo: CliIo = {\n stdout: { write: (chunk) => process.stdout.write(chunk) },\n stderr: { write: (chunk) => process.stderr.write(chunk) },\n};\n\nif (isDirectPajaCli()) {\n void runPajaCli().then((code) => {\n process.exitCode = code;\n });\n}\n\nexport function isDirectPajaCli(entryPath = process.argv[1]): boolean {\n if (!entryPath) return false;\n return entryPath.endsWith('/cli.js') || entryPath.endsWith('/paja');\n}\n\ndeclare const process: {\n argv: string[];\n exitCode?: number;\n stdout: { write(chunk: string): void };\n stderr: { write(chunk: string): void };\n};\n\nexport interface ManagedChildProcess {\n kill(): void;\n readonly detectedTargetUrl: Promise<string>;\n}\n\ninterface ManagedTargetUrlDetector {\n readonly detectedTargetUrl: Promise<string>;\n observe(chunk: string): void;\n}\n\nconst LOCAL_HTTP_URL_PATTERN = /https?:\\/\\/(?:localhost|127(?:\\.\\d{1,3}){3}|\\[::1\\])(?::\\d+)?(?:\\/[^\\s'\"<>)\\]]*)?/g;\nconst ANSI_PATTERN = /\\u001b\\[[0-?]*[ -/]*[@-~]/g;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * CLI entrypoint for running the Paja local authoring runtime.\n *\n * @module\n */\nimport { spawn, type ChildProcess } from 'node:child_process';\nimport {\n createPajaHostConfig,\n formatPajaUrl,\n normalizePajaOptions,\n waitForTargetUrl,\n type PajaCommand,\n type PajaRawOptions,\n PajaOptionsError,\n} from './index.js';\nimport { resolvePajaRawOptions } from './config-file.js';\nimport { startPajaServer } from './server.js';\nimport {\n PAJA_SIMULATION_DOMAINS,\n summarizePajaSimulation,\n type PajaCapabilityDomain,\n type PajaSimulationRawOptions,\n type JsonValue,\n} from './simulation.js';\n\n/**\n * Minimal output streams used by the CLI runner.\n *\n * @remarks\n * Tests and embedders can pass custom streams to capture output without\n * patching global `process.stdout` or `process.stderr`.\n */\nexport interface CliIo {\n readonly stdout: { write(chunk: string): void };\n readonly stderr: { write(chunk: string): void };\n}\n\n/**\n * Parsed CLI arguments before full option normalization.\n */\nexport interface CliParseResult {\n readonly options?: PajaRawOptions;\n readonly help: boolean;\n}\n\n/**\n * Execution controls for embedding the CLI runner in tests or wrappers.\n */\nexport interface RunPajaCliOptions {\n readonly serve?: boolean;\n readonly startServer?: typeof startPajaServer;\n readonly startCommand?: (command: PajaCommand, io: CliIo) => ManagedChildProcess;\n readonly waitForTargetUrl?: typeof waitForTargetUrl;\n readonly targetDiscoveryGraceMs?: number;\n}\n\n/**\n * Parse raw `kehto paja` arguments into raw runtime options.\n *\n * @param args - Argument vector without the node executable or script path.\n * @returns Parsed raw options, or a help flag when `--help` is present.\n */\nexport function parsePajaArgs(args: readonly string[]): CliParseResult {\n const raw: MutablePajaRawOptions = {};\n\n for (let index = 0; index < args.length; index += 1) {\n const arg = args[index];\n\n if (arg === '--') {\n const argv = args.slice(index + 1);\n raw.command = { mode: 'argv', argv };\n break;\n }\n\n if (arg === '--help' || arg === '-h') {\n return { help: true };\n }\n\n if (applyCoreOption(arg, args, index, raw) || applySimulationOption(arg, args, index, raw)) {\n index += 1;\n continue;\n }\n\n throw new PajaOptionsError(`Unknown option \"${arg}\". Run kehto paja --help for usage.`);\n }\n\n return { help: false, options: raw };\n}\n\n/**\n * Run the Paja CLI command.\n *\n * @param args - Argument vector without the node executable or script path.\n * @param io - Output streams used by the command.\n * @param runOptions - Test/embedding controls for server and process spawning.\n * @returns Process exit code.\n */\nexport async function runPajaCli(\n args: readonly string[] = process.argv.slice(2),\n io: CliIo = defaultIo,\n runOptions: RunPajaCliOptions = {},\n): Promise<number> {\n try {\n const parsed = parsePajaArgs(args);\n if (parsed.help) {\n io.stdout.write(`${HELP_TEXT}\\n`);\n return 0;\n }\n\n const rawOptions = resolvePajaRawOptions(parsed.options ?? {});\n const options = normalizePajaOptions(rawOptions);\n const hostConfig = createPajaHostConfig(options);\n const shouldServe = runOptions.serve ?? true;\n const startServer = runOptions.startServer ?? startPajaServer;\n const startCommand = runOptions.startCommand ?? startManagedCommand;\n const waitForTarget = runOptions.waitForTargetUrl ?? waitForTargetUrl;\n let child: ManagedChildProcess | undefined;\n let server: Awaited<ReturnType<typeof startPajaServer>> | undefined;\n if (shouldServe) {\n try {\n server = await startServer({ options: rawOptions });\n writeRuntimeSummary(io, server.url, hostConfig, options);\n\n if (options.command) {\n child = startCommand(options.command, io);\n const targetUrl = await resolveManagedTargetUrl(options.targetUrl, child, {\n timeoutMs: options.readyTimeoutMs,\n discoveryGraceMs: runOptions.targetDiscoveryGraceMs,\n waitForTargetUrl: waitForTarget,\n });\n if (targetUrl !== options.targetUrl) {\n server.updateTargetUrl(targetUrl);\n io.stdout.write(`Target URL updated: ${targetUrl}\\n`);\n }\n }\n } catch (error) {\n child?.kill();\n await server?.close().catch(() => undefined);\n throw error;\n }\n }\n const runtimeUrl = server?.url ?? formatPajaUrl(options);\n\n if (!shouldServe) {\n writeRuntimeSummary(io, runtimeUrl, hostConfig, options);\n }\n\n return 0;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n io.stderr.write(`kehto paja: ${message}\\n`);\n return 1;\n }\n}\n\nfunction writeRuntimeSummary(\n io: CliIo,\n runtimeUrl: string,\n hostConfig: ReturnType<typeof createPajaHostConfig>,\n options: ReturnType<typeof normalizePajaOptions>,\n): void {\n io.stdout.write(`Kehto Paja\\n`);\n io.stdout.write(`Runtime URL: ${runtimeUrl}\\n`);\n io.stdout.write(`Target URL: ${hostConfig.target.url}\\n`);\n io.stdout.write(`Mode: ${options.mode}\\n`);\n io.stdout.write(`HMR: ${hostConfig.target.hmrStrategy}\\n`);\n io.stdout.write(`Simulation: ${summarizePajaSimulation(options.simulation)}\\n`);\n\n if (options.command) {\n io.stdout.write(`Command: ${formatCommand(options.command)}\\n`);\n }\n}\n\nconst HELP_TEXT = `Usage:\n kehto paja --target-url <url> [options]\n kehto paja --target-url <url> [options] -- <command...>\n\nOptions:\n --target-url, -u <url> App dev-server URL to load in the runtime iframe.\n --command, -c <command> Shell command to start before waiting for target URL.\n -- <command...> Argv command form; preserves arbitrary framework commands.\n --host <host> Runtime host. Default: 127.0.0.1.\n --port <port> Runtime port. Default: 5197.\n --ready-timeout <ms> Target readiness timeout. Default: 30000.\n --config <path> JSON config file using the same option schema.\n --identity-mode <mode> anonymous or fixed.\n --identity-pubkey <hex> Required when identity mode is fixed.\n --relay-mode <mode> live, memory, or disabled.\n --relay-url <url> Add a relay URL for live or memory relay backends.\n --storage-mode <mode> local, memory, or disabled.\n --cache-mode <mode> memory or disabled.\n --upload-mode <mode> memory, blossom, or disabled.\n --upload-rail <name> Upload rail name for memory uploads.\n --upload-server <url> Add a shell-owned Blossom server (repeatable).\n --media <state> enabled or disabled.\n --notifications <state> enabled or disabled.\n --notify-grant <bool> true or false default notification grant.\n --theme <mode> dark or light.\n --config-value <key=json> Add a JSON config value.\n --capability <domain:on|off> Toggle an advertised capability domain.\n --acl-mode <mode> allow or deny.\n --firewall-mode <mode> allow, deny, or observe.\n --help, -h Show this help.`;\n\nfunction readValue(args: readonly string[], index: number, option: string): string {\n const value = args[index + 1];\n if (!value || value.startsWith('--')) {\n throw new PajaOptionsError(`${option} requires a value.`);\n }\n return value;\n}\n\nfunction applyCoreOption(\n arg: string,\n args: readonly string[],\n index: number,\n raw: MutablePajaRawOptions,\n): boolean {\n switch (arg) {\n case '--target-url':\n case '-u':\n raw.targetUrl = readValue(args, index, arg);\n return true;\n case '--command':\n case '-c':\n raw.command = { mode: 'shell', command: readValue(args, index, arg) };\n return true;\n case '--host':\n raw.host = readValue(args, index, arg);\n return true;\n case '--port':\n raw.port = readValue(args, index, arg);\n return true;\n case '--ready-timeout':\n raw.readyTimeoutMs = readValue(args, index, arg);\n return true;\n case '--config':\n raw.configPath = readValue(args, index, arg);\n return true;\n default:\n return false;\n }\n}\n\nfunction applySimulationOption(\n arg: string,\n args: readonly string[],\n index: number,\n raw: MutablePajaRawOptions,\n): boolean {\n switch (arg) {\n case '--identity-mode':\n setIdentity(raw, { mode: readEnum(args, index, arg, ['anonymous', 'fixed']) });\n return true;\n case '--identity-pubkey':\n setIdentity(raw, { pubkey: readValue(args, index, arg) });\n return true;\n case '--relay-mode':\n setRelay(raw, { mode: readEnum(args, index, arg, ['live', 'memory', 'disabled']) });\n return true;\n case '--relay-url':\n setRelay(raw, { urls: [...(raw.simulation?.relay?.urls ?? []), readValue(args, index, arg)] });\n return true;\n case '--storage-mode':\n ensureSimulation(raw).storage = { ...raw.simulation?.storage, mode: readEnum(args, index, arg, ['local', 'memory', 'disabled']) };\n return true;\n case '--cache-mode':\n ensureSimulation(raw).cache = { ...raw.simulation?.cache, mode: readEnum(args, index, arg, ['memory', 'disabled']) };\n return true;\n case '--upload-mode':\n setUpload(raw, { mode: readEnum(args, index, arg, ['memory', 'blossom', 'disabled']) });\n return true;\n case '--upload-rail':\n setUpload(raw, { rail: readValue(args, index, arg) });\n return true;\n case '--upload-server':\n setUpload(raw, { servers: [...(raw.simulation?.upload?.servers ?? []), readValue(args, index, arg)] });\n return true;\n case '--media':\n ensureSimulation(raw).media = { ...raw.simulation?.media, enabled: readEnabled(args, index, arg) };\n return true;\n case '--notifications':\n setNotifications(raw, { enabled: readEnabled(args, index, arg) });\n return true;\n case '--notify-grant':\n setNotifications(raw, { grant: readBoolean(args, index, arg) });\n return true;\n case '--theme':\n ensureSimulation(raw).theme = { ...raw.simulation?.theme, mode: readEnum(args, index, arg, ['dark', 'light']) };\n return true;\n case '--config-value':\n setConfigValue(raw, readConfigValue(args, index, arg));\n return true;\n case '--capability':\n setCapability(raw, readCapability(args, index, arg));\n return true;\n case '--acl-mode':\n ensureSimulation(raw).acl = { ...raw.simulation?.acl, mode: readEnum(args, index, arg, ['allow', 'deny']) };\n return true;\n case '--firewall-mode':\n ensureSimulation(raw).firewall = { ...raw.simulation?.firewall, mode: readEnum(args, index, arg, ['allow', 'deny', 'observe']) };\n return true;\n default:\n return false;\n }\n}\n\nfunction formatCommand(command: PajaCommand): string {\n return command.mode === 'argv' ? command.argv.join(' ') : command.command;\n}\n\nfunction readEnum<const T extends readonly string[]>(\n args: readonly string[],\n index: number,\n option: string,\n allowed: T,\n): T[number] {\n const value = readValue(args, index, option);\n if (!allowed.includes(value)) {\n throw new PajaOptionsError(`${option} must be one of: ${allowed.join(', ')}.`);\n }\n return value;\n}\n\nfunction readEnabled(args: readonly string[], index: number, option: string): boolean {\n const value = readValue(args, index, option);\n if (value === 'enabled') return true;\n if (value === 'disabled') return false;\n throw new PajaOptionsError(`${option} must be \"enabled\" or \"disabled\".`);\n}\n\nfunction readBoolean(args: readonly string[], index: number, option: string): boolean {\n const value = readValue(args, index, option);\n if (value === 'true') return true;\n if (value === 'false') return false;\n throw new PajaOptionsError(`${option} must be \"true\" or \"false\".`);\n}\n\nfunction readConfigValue(\n args: readonly string[],\n index: number,\n option: string,\n): { key: string; value: JsonValue } {\n const raw = readValue(args, index, option);\n const separator = raw.indexOf('=');\n if (separator <= 0) {\n throw new PajaOptionsError(`${option} expects key=json.`);\n }\n const key = raw.slice(0, separator).trim();\n if (!key) {\n throw new PajaOptionsError(`${option} expects a non-empty key.`);\n }\n try {\n return { key, value: JSON.parse(raw.slice(separator + 1)) as JsonValue };\n } catch {\n throw new PajaOptionsError(`${option} value for \"${key}\" must be valid JSON.`);\n }\n}\n\nfunction readCapability(\n args: readonly string[],\n index: number,\n option: string,\n): { domain: PajaCapabilityDomain; enabled: boolean } {\n const raw = readValue(args, index, option);\n const [domainRaw, stateRaw] = raw.split(':') as [string | undefined, string | undefined];\n if (!domainRaw || (stateRaw !== 'on' && stateRaw !== 'off')) {\n throw new PajaOptionsError(`${option} expects domain:on or domain:off.`);\n }\n if (!PAJA_SIMULATION_DOMAINS.includes(domainRaw as PajaCapabilityDomain)) {\n throw new PajaOptionsError(`${option} unknown domain \"${domainRaw}\".`);\n }\n return {\n domain: domainRaw as PajaCapabilityDomain,\n enabled: stateRaw === 'on',\n };\n}\n\nfunction setIdentity(raw: MutablePajaRawOptions, identity: NonNullable<PajaSimulationRawOptions['identity']>): void {\n ensureSimulation(raw).identity = { ...raw.simulation?.identity, ...identity };\n}\n\nfunction setRelay(raw: MutablePajaRawOptions, relay: NonNullable<PajaSimulationRawOptions['relay']>): void {\n ensureSimulation(raw).relay = { ...raw.simulation?.relay, ...relay };\n}\n\nfunction setUpload(raw: MutablePajaRawOptions, upload: NonNullable<PajaSimulationRawOptions['upload']>): void {\n ensureSimulation(raw).upload = { ...raw.simulation?.upload, ...upload };\n}\n\nfunction setNotifications(\n raw: MutablePajaRawOptions,\n notifications: NonNullable<PajaSimulationRawOptions['notifications']>,\n): void {\n ensureSimulation(raw).notifications = { ...raw.simulation?.notifications, ...notifications };\n}\n\nfunction setConfigValue(\n raw: MutablePajaRawOptions,\n entry: { key: string; value: JsonValue },\n): void {\n ensureSimulation(raw).config = {\n ...raw.simulation?.config,\n values: {\n ...raw.simulation?.config?.values,\n [entry.key]: entry.value,\n },\n };\n}\n\nfunction setCapability(\n raw: MutablePajaRawOptions,\n entry: { domain: PajaCapabilityDomain; enabled: boolean },\n): void {\n ensureSimulation(raw).capabilities = {\n ...raw.simulation?.capabilities,\n domains: {\n ...raw.simulation?.capabilities?.domains,\n [entry.domain]: entry.enabled,\n },\n };\n}\n\nfunction ensureSimulation(raw: MutablePajaRawOptions): MutablePajaSimulationRawOptions {\n raw.simulation ??= {};\n return raw.simulation as MutablePajaSimulationRawOptions;\n}\n\nasync function resolveManagedTargetUrl(\n configuredUrl: string,\n child: ManagedChildProcess,\n options: {\n readonly timeoutMs: number;\n readonly discoveryGraceMs?: number;\n readonly waitForTargetUrl: typeof waitForTargetUrl;\n },\n): Promise<string> {\n let configuredError: unknown;\n const configuredReady = options.waitForTargetUrl(configuredUrl, { timeoutMs: options.timeoutMs })\n .then(() => configuredUrl)\n .catch((error) => {\n configuredError = error;\n return undefined;\n });\n const first = await Promise.race([\n configuredReady.then((url) => url ? { kind: 'configured' as const, url } : undefined),\n child.detectedTargetUrl.then((url) => ({ kind: 'detected' as const, url })),\n ]);\n\n if (first?.kind === 'detected') {\n await options.waitForTargetUrl(first.url, { timeoutMs: options.timeoutMs });\n return first.url;\n }\n\n const graceMs = options.discoveryGraceMs ?? Math.min(1000, options.timeoutMs);\n const detected = await resolveWithin(child.detectedTargetUrl, graceMs);\n if (!detected) {\n if (first?.url) {\n return first.url;\n }\n throw configuredError instanceof Error ? configuredError : new Error(String(configuredError ?? 'Target URL was not ready.'));\n }\n\n await options.waitForTargetUrl(detected, { timeoutMs: options.timeoutMs });\n return detected;\n}\n\nfunction resolveWithin<T>(promise: Promise<T>, timeoutMs: number): Promise<T | undefined> {\n return new Promise((resolve) => {\n let settled = false;\n const timeout = setTimeout(() => {\n if (settled) return;\n settled = true;\n resolve(undefined);\n }, Math.max(0, timeoutMs));\n\n promise.then((value) => {\n if (settled) return;\n settled = true;\n clearTimeout(timeout);\n resolve(value);\n }, () => {\n if (settled) return;\n settled = true;\n clearTimeout(timeout);\n resolve(undefined);\n });\n });\n}\n\nfunction startManagedCommand(command: PajaCommand, io: CliIo): ManagedChildProcess {\n const detector = createManagedTargetUrlDetector();\n const child = spawnManagedCommand(command);\n forwardManagedOutput(child, detector, io);\n return {\n kill: () => child.kill(),\n detectedTargetUrl: detector.detectedTargetUrl,\n };\n}\n\nfunction spawnManagedCommand(command: PajaCommand): ChildProcess {\n if (command.mode === 'shell') {\n return spawn(command.command, { shell: true, stdio: ['inherit', 'pipe', 'pipe'] as const });\n }\n\n const [executable, ...args] = command.argv;\n if (!executable) {\n throw new PajaOptionsError('Argv command mode requires an executable.');\n }\n return spawn(executable, args, { stdio: ['inherit', 'pipe', 'pipe'] as const });\n}\n\nfunction forwardManagedOutput(\n child: ChildProcess,\n detector: ManagedTargetUrlDetector,\n io: CliIo,\n): void {\n child.stdout?.on('data', (chunk: string | Uint8Array) => {\n const text = String(chunk);\n detector.observe(text);\n io.stdout.write(text);\n });\n child.stderr?.on('data', (chunk: string | Uint8Array) => {\n const text = String(chunk);\n detector.observe(text);\n io.stderr.write(text);\n });\n}\n\nfunction createManagedTargetUrlDetector(): ManagedTargetUrlDetector {\n let resolveDetected: (url: string) => void = () => {\n // Promise executor replaces this before any child-process output can arrive.\n };\n let detected: string | undefined;\n const detectedTargetUrl = new Promise<string>((resolve) => {\n resolveDetected = resolve;\n });\n\n return {\n detectedTargetUrl,\n observe(chunk) {\n if (detected) return;\n const text = stripAnsi(chunk);\n for (const match of text.matchAll(LOCAL_HTTP_URL_PATTERN)) {\n const rawUrl = match[0];\n let url: URL;\n try {\n url = new URL(rawUrl);\n } catch {\n continue;\n }\n detected = url.href;\n resolveDetected(detected);\n return;\n }\n },\n };\n}\n\nfunction stripAnsi(value: string): string {\n return value.replace(ANSI_PATTERN, '');\n}\n\ntype MutablePajaRawOptions = {\n -readonly [K in keyof PajaRawOptions]: PajaRawOptions[K];\n};\n\ntype MutablePajaSimulationRawOptions = {\n -readonly [K in keyof PajaSimulationRawOptions]: PajaSimulationRawOptions[K];\n};\n\nconst defaultIo: CliIo = {\n stdout: { write: (chunk) => process.stdout.write(chunk) },\n stderr: { write: (chunk) => process.stderr.write(chunk) },\n};\n\nif (isDirectPajaCli()) {\n void runPajaCli().then((code) => {\n process.exitCode = code;\n });\n}\n\n/**\n * Detect whether this module is running as the direct Paja CLI entrypoint.\n *\n * @param entryPath - Process entry path to inspect.\n * @returns `true` when the entry path looks like Paja's built CLI.\n */\nexport function isDirectPajaCli(entryPath = process.argv[1]): boolean {\n if (!entryPath) return false;\n return entryPath.endsWith('/cli.js') || entryPath.endsWith('/paja');\n}\n\ndeclare const process: {\n argv: string[];\n exitCode?: number;\n stdout: { write(chunk: string): void };\n stderr: { write(chunk: string): void };\n};\n\n/** Managed child process handle. */\nexport interface ManagedChildProcess {\n /** Stop the managed target process. */\n kill(): void;\n /** First local target URL detected from process output. */\n readonly detectedTargetUrl: Promise<string>;\n}\n\ninterface ManagedTargetUrlDetector {\n readonly detectedTargetUrl: Promise<string>;\n observe(chunk: string): void;\n}\n\nconst LOCAL_HTTP_URL_PATTERN = /https?:\\/\\/(?:localhost|127(?:\\.\\d{1,3}){3}|\\[::1\\])(?::\\d+)?(?:\\/[^\\s'\"<>)\\]]*)?/g;\nconst ANSI_PATTERN = /\\u001b\\[[0-?]*[ -/]*[@-~]/g;\n"],"mappings":"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","names":[]}
package/dist/index.d.ts CHANGED
@@ -1,20 +1,46 @@
1
- import { P as PajaRawOptions, b as PajaHostConfig } from './server-qAXYczds.js';
2
- export { D as DEFAULT_PAJA_AGGREGATE_HASH, c as DEFAULT_PAJA_DTAG, d as DEFAULT_PAJA_HOST, e as DEFAULT_PAJA_PORT, f as DEFAULT_PAJA_RUNTIME_WAIT_MS, g as DEFAULT_PAJA_WINDOW_ID, h as DEFAULT_READY_TIMEOUT_MS, J as JsonPrimitive, i as JsonRecord, j as JsonValue, k as PAJA_SIMULATION_DOMAINS, l as PajaCapabilityDomain, a as PajaCommand, m as PajaHmrStrategy, n as PajaOptions, o as PajaOptionsError, p as PajaPointerRuntimeConfig, q as PajaServer, r as PajaServerOptions, t as PajaSimulation, u as PajaSimulationError, v as PajaSimulationRawOptions, x as PajaTargetMode, R as ReadinessError, y as ReadinessFetch, W as WaitForTargetUrlOptions, z as createPajaHostConfig, A as createPajaRuntimeHostConfig, B as formatPajaUrl, C as normalizePajaOptions, E as normalizePajaSimulation, s as startPajaServer, F as summarizePajaSimulation, w as waitForTargetUrl } from './server-qAXYczds.js';
1
+ import { P as PajaRawOptions, b as PajaHostConfig } from './server-efRTBcMR.js';
2
+ export { D as DEFAULT_PAJA_AGGREGATE_HASH, c as DEFAULT_PAJA_DTAG, d as DEFAULT_PAJA_HOST, e as DEFAULT_PAJA_PORT, f as DEFAULT_PAJA_RUNTIME_WAIT_MS, g as DEFAULT_PAJA_WINDOW_ID, h as DEFAULT_READY_TIMEOUT_MS, J as JsonPrimitive, i as JsonRecord, j as JsonValue, k as PAJA_SIMULATION_DOMAINS, l as PajaCapabilityDomain, a as PajaCommand, m as PajaHmrStrategy, n as PajaOptions, o as PajaOptionsError, p as PajaPointerRuntimeConfig, q as PajaServer, r as PajaServerOptions, t as PajaSimulation, u as PajaSimulationError, v as PajaSimulationRawOptions, x as PajaTargetMode, R as ReadinessError, y as ReadinessFetch, W as WaitForTargetUrlOptions, z as createPajaHostConfig, A as createPajaRuntimeHostConfig, B as formatPajaUrl, C as normalizePajaOptions, E as normalizePajaSimulation, s as startPajaServer, F as summarizePajaSimulation, w as waitForTargetUrl } from './server-efRTBcMR.js';
3
3
  import { NostrEvent } from 'nostr-tools';
4
4
  import { Filter } from 'nostr-tools/filter';
5
5
  import { ResolvedNapplet } from '@kehto/nip/5d';
6
6
  import { ShellCapabilities } from '@kehto/shell';
7
7
 
8
+ /**
9
+ * Load a JSON Paja config file from disk.
10
+ *
11
+ * @param configPath - Path to a JSON config file.
12
+ * @returns Raw options parsed from the config file.
13
+ */
8
14
  declare function loadPajaConfigFile(configPath: string): PajaRawOptions;
15
+ /**
16
+ * Resolve raw options by merging an optional config file with explicit values.
17
+ *
18
+ * @param raw - CLI/config options, optionally including `configPath`.
19
+ * @returns Raw options with config-file defaults applied.
20
+ */
9
21
  declare function resolvePajaRawOptions(raw: PajaRawOptions): PajaRawOptions;
22
+ /**
23
+ * Merge two raw Paja option objects, with override values taking precedence.
24
+ *
25
+ * @param base - Base options, usually from a config file.
26
+ * @param override - Explicit options, usually from CLI args.
27
+ * @returns Merged raw options.
28
+ */
10
29
  declare function mergePajaRawOptions(base: PajaRawOptions, override: PajaRawOptions): PajaRawOptions;
11
30
 
31
+ /**
32
+ * Render the browser host page for a Paja runtime config.
33
+ *
34
+ * @param config - Serializable host-page config.
35
+ * @returns Complete HTML document served by Paja.
36
+ */
12
37
  declare function renderPajaHtml(config: PajaHostConfig): string;
13
38
 
14
39
  /** Named/addressable NIP-5D napplet manifest kind (`35129`). */
15
40
  declare const PAJA_NAPPLET_MANIFEST_KIND = 35129;
16
41
  /** All NIP-5D napplet manifest kinds accepted by Paja pointers (`5129`, `15129`, `35129`). */
17
42
  declare const PAJA_NAPPLET_MANIFEST_KINDS: readonly number[];
43
+ /** Decoded naddr/nevent pointer accepted by Paja runtime-pointer mode. */
18
44
  type PajaDecodedPointer = {
19
45
  readonly type: 'naddr';
20
46
  readonly value: string;
@@ -30,17 +56,28 @@ type PajaDecodedPointer = {
30
56
  readonly kind?: number;
31
57
  readonly relays: readonly string[];
32
58
  };
59
+ /** Fully resolved pointer plus verified napplet artifact bytes. */
33
60
  interface PajaResolvedPointer {
61
+ /** Decoded pointer input. */
34
62
  readonly pointer: PajaDecodedPointer;
63
+ /** Manifest event resolved from relays. */
35
64
  readonly event: NostrEvent;
65
+ /** Relay URLs queried for the pointer. */
36
66
  readonly relays: readonly string[];
67
+ /** Blossom server hints used for blob fetches. */
37
68
  readonly blossomServers: readonly string[];
69
+ /** Resolved manifest `d` tag. */
38
70
  readonly dTag: string;
71
+ /** Verified NIP-5A aggregate hash. */
39
72
  readonly aggregateHash: string;
73
+ /** Verified target `/index.html` content. */
40
74
  readonly indexHtml: string;
75
+ /** Parsed NIP-5D manifest. */
41
76
  readonly manifest: ResolvedNapplet['manifest'];
42
77
  }
78
+ /** Relay-pool contract for runtime-pointer resolution. */
43
79
  interface PajaPointerRelayPool {
80
+ /** Query relays synchronously for matching manifest events. */
44
81
  querySync(relays: string[], filter: Filter, params?: {
45
82
  readonly maxWait?: number;
46
83
  readonly label?: string;
@@ -49,25 +86,69 @@ interface PajaPointerRelayPool {
49
86
  close?(relays: string[]): void;
50
87
  destroy?(): void;
51
88
  }
89
+ /** Options for resolving a Paja runtime pointer. */
52
90
  interface ResolvePajaPointerOptions {
91
+ /** Relay pool override; defaults to a `nostr-tools` `SimplePool`. */
53
92
  readonly pool?: PajaPointerRelayPool;
93
+ /** Fetch override used for Blossom blob URLs. */
54
94
  readonly fetcher?: (url: string) => Promise<Response>;
95
+ /** Extra relay hints appended to pointer relays. */
55
96
  readonly relays?: readonly string[];
97
+ /** Extra Blossom server hints appended during artifact fetch. */
56
98
  readonly blossomServers?: readonly string[];
99
+ /** Maximum relay query wait in milliseconds. */
57
100
  readonly maxWaitMs?: number;
58
101
  }
102
+ /**
103
+ * Decode a NIP-19 naddr/nevent pointer for Paja runtime-pointer mode.
104
+ *
105
+ * @param value - NIP-19 pointer string.
106
+ * @returns Structured pointer metadata.
107
+ */
59
108
  declare function decodePajaPointer(value: string): PajaDecodedPointer;
109
+ /**
110
+ * Resolve a Paja runtime pointer into verified napplet HTML and manifest data.
111
+ *
112
+ * @param value - NIP-19 naddr or nevent pointer.
113
+ * @param options - Relay, fetch, and Blossom overrides.
114
+ * @returns Verified napplet artifact ready for srcdoc injection.
115
+ */
60
116
  declare function resolvePajaPointer(value: string, options?: ResolvePajaPointerOptions): Promise<PajaResolvedPointer>;
117
+ /**
118
+ * Inject a restrictive connect-src CSP for runtime-pointer srcdoc output.
119
+ *
120
+ * @param html - Verified target HTML.
121
+ * @param origins - Origins the resolved target may connect to.
122
+ * @returns HTML with a CSP meta tag inserted.
123
+ */
61
124
  declare function injectPajaRuntimeCsp(html: string, origins: readonly string[]): string;
62
125
 
63
- declare const PAJA_UPSTREAM_WEB_DOMAINS: readonly ["ble", "common", "config", "count", "cvm", "dm", "identity", "ifc", "inc", "intent", "keys", "link", "lists", "media", "notify", "outbox", "relay", "resource", "serial", "storage", "theme", "upload", "webrtc"];
126
+ declare const PAJA_LEGACY_COMPATIBILITY_DOMAIN: string;
127
+ /** Domain list mirrored from the upstream web runtime for parity checks. */
128
+ declare const PAJA_UPSTREAM_WEB_DOMAINS: readonly ["ble", "common", "config", "count", "cvm", "dm", "identity", string, "inc", "intent", "keys", "link", "lists", "media", "notify", "outbox", "relay", "resource", "serial", "storage", "theme", "upload", "webrtc"];
129
+ /** Domains required during the initial Paja handshake. */
64
130
  declare const PAJA_HANDSHAKE_DOMAINS: readonly ["shell"];
131
+ /** Compatibility aliases for renamed upstream capability domains. */
65
132
  declare const PAJA_COMPATIBILITY_ALIASES: {
66
- readonly ifc: "inc";
133
+ readonly [PAJA_LEGACY_COMPATIBILITY_DOMAIN]: "inc";
67
134
  };
135
+ /** Domains Paja advertises through its simulated shell capability surface. */
68
136
  declare const PAJA_ADVERTISED_DOMAINS: readonly ["relay", "outbox", "identity", "storage", "inc", "theme", "keys", "link", "common", "lists", "serial", "ble", "webrtc", "media", "notify", "config", "resource", "cvm", "upload", "intent", "count"];
137
+ /** Service names Paja expects the host runtime to provide. */
69
138
  declare const PAJA_REQUIRED_SERVICES: readonly ["config", "cvm", "identity", "intent", "keys", "link", "common", "lists", "serial", "ble", "webrtc", "media", "notifications", "notify", "outbox", "relay", "resource", "theme", "upload", "count"];
139
+ /**
140
+ * Find advertised Paja domains missing from a shell capability snapshot.
141
+ *
142
+ * @param capabilities - Shell capability snapshot to inspect.
143
+ * @returns Advertised domains not present in the snapshot.
144
+ */
70
145
  declare function getMissingAdvertisedDomains(capabilities: ShellCapabilities): string[];
146
+ /**
147
+ * Find required service names missing from a runtime service list.
148
+ *
149
+ * @param services - Runtime service names to inspect.
150
+ * @returns Required service names that are absent.
151
+ */
71
152
  declare function getMissingServices(services: readonly string[]): string[];
72
153
 
73
154
  export { PAJA_ADVERTISED_DOMAINS, PAJA_COMPATIBILITY_ALIASES, PAJA_HANDSHAKE_DOMAINS, PAJA_NAPPLET_MANIFEST_KIND, PAJA_NAPPLET_MANIFEST_KINDS, PAJA_REQUIRED_SERVICES, PAJA_UPSTREAM_WEB_DOMAINS, type PajaDecodedPointer, PajaHostConfig, type PajaPointerRelayPool, PajaRawOptions, type PajaResolvedPointer, type ResolvePajaPointerOptions, decodePajaPointer, getMissingAdvertisedDomains, getMissingServices, injectPajaRuntimeCsp, loadPajaConfigFile, mergePajaRawOptions, renderPajaHtml, resolvePajaPointer, resolvePajaRawOptions };
package/dist/index.js CHANGED
@@ -34,7 +34,7 @@ import {
34
34
  startPajaServer,
35
35
  summarizePajaSimulation,
36
36
  waitForTargetUrl
37
- } from "./chunk-ADMLM2LH.js";
37
+ } from "./chunk-NFJCS5PG.js";
38
38
  export {
39
39
  DEFAULT_PAJA_AGGREGATE_HASH,
40
40
  DEFAULT_PAJA_DTAG,
@@ -1,13 +1,20 @@
1
+ /** JSON primitive accepted in Paja simulation config values. */
1
2
  type JsonPrimitive = string | number | boolean | null;
3
+ /** JSON value accepted in Paja simulation config values. */
2
4
  type JsonValue = JsonPrimitive | JsonValue[] | {
3
5
  readonly [key: string]: JsonValue;
4
6
  };
7
+ /** JSON object used for Paja simulation fixtures and config/theme values. */
5
8
  type JsonRecord = Record<string, JsonValue>;
9
+ /** Capability domain names Paja can advertise or disable. */
6
10
  type PajaCapabilityDomain = 'relay' | 'outbox' | 'storage' | 'identity' | 'keys' | 'config' | 'resource' | 'theme' | 'notify' | 'media' | 'upload' | 'intent' | 'count' | 'link' | 'common' | 'lists' | 'serial' | 'ble' | 'webrtc' | 'cvm' | 'inc';
11
+ /** Raw simulation controls accepted from CLI args or JSON config. */
7
12
  interface PajaSimulationRawOptions {
13
+ /** Per-domain capability overrides. */
8
14
  readonly capabilities?: {
9
15
  readonly domains?: Partial<Record<PajaCapabilityDomain, boolean>>;
10
16
  };
17
+ /** ACL behavior mode for simulated services. */
11
18
  readonly acl?: {
12
19
  readonly mode?: 'allow' | 'deny';
13
20
  };
@@ -19,7 +26,7 @@ interface PajaSimulationRawOptions {
19
26
  readonly pubkey?: string;
20
27
  };
21
28
  readonly relay?: {
22
- readonly mode?: 'memory' | 'disabled';
29
+ readonly mode?: 'live' | 'memory' | 'disabled';
23
30
  readonly urls?: readonly string[];
24
31
  readonly fixtures?: readonly JsonRecord[];
25
32
  };
@@ -30,8 +37,12 @@ interface PajaSimulationRawOptions {
30
37
  readonly mode?: 'memory' | 'disabled';
31
38
  };
32
39
  readonly upload?: {
33
- readonly mode?: 'memory' | 'disabled';
40
+ readonly mode?: 'memory' | 'blossom' | 'disabled';
34
41
  readonly rail?: string;
42
+ readonly servers?: readonly string[];
43
+ readonly discoverServers?: boolean;
44
+ readonly maxBytes?: number;
45
+ readonly mimeTypes?: readonly string[];
35
46
  };
36
47
  readonly media?: {
37
48
  readonly enabled?: boolean;
@@ -54,7 +65,9 @@ interface PajaSimulationRawOptions {
54
65
  readonly enabled?: boolean;
55
66
  };
56
67
  }
68
+ /** Fully normalized Paja simulation model served to the browser host. */
57
69
  interface PajaSimulation {
70
+ /** Capability domains and disabled-domain summary. */
58
71
  readonly capabilities: {
59
72
  readonly domains: Record<PajaCapabilityDomain, boolean>;
60
73
  readonly disabledDomains: readonly PajaCapabilityDomain[];
@@ -70,7 +83,7 @@ interface PajaSimulation {
70
83
  readonly pubkey: string;
71
84
  };
72
85
  readonly relay: {
73
- readonly mode: 'memory' | 'disabled';
86
+ readonly mode: 'live' | 'memory' | 'disabled';
74
87
  readonly urls: readonly string[];
75
88
  readonly fixtures: readonly JsonRecord[];
76
89
  };
@@ -81,8 +94,12 @@ interface PajaSimulation {
81
94
  readonly mode: 'memory' | 'disabled';
82
95
  };
83
96
  readonly upload: {
84
- readonly mode: 'memory' | 'disabled';
85
- readonly rail: string;
97
+ readonly mode: 'memory' | 'blossom' | 'disabled';
98
+ readonly rail?: string;
99
+ readonly servers: readonly string[];
100
+ readonly discoverServers: boolean;
101
+ readonly maxBytes?: number;
102
+ readonly mimeTypes?: readonly string[];
86
103
  };
87
104
  readonly media: {
88
105
  readonly enabled: boolean;
@@ -105,49 +122,95 @@ interface PajaSimulation {
105
122
  readonly enabled: boolean;
106
123
  };
107
124
  }
125
+ /** Thrown when Paja simulation options are internally inconsistent. */
108
126
  declare class PajaSimulationError extends Error {
109
127
  constructor(message: string);
110
128
  }
129
+ /** Capability domains exposed by Paja simulation controls. */
111
130
  declare const PAJA_SIMULATION_DOMAINS: readonly PajaCapabilityDomain[];
131
+ /**
132
+ * Normalize raw simulation options into a complete deterministic model.
133
+ *
134
+ * @param raw - Partial simulation options from CLI args or config.
135
+ * @returns Complete simulation model.
136
+ */
112
137
  declare function normalizePajaSimulation(raw: PajaSimulationRawOptions | undefined): PajaSimulation;
138
+ /**
139
+ * Format a compact, human-readable simulation summary.
140
+ *
141
+ * @param simulation - Normalized simulation model.
142
+ * @returns One-line summary used by CLI and host-page chrome.
143
+ */
113
144
  declare function summarizePajaSimulation(simulation: PajaSimulation): string;
114
145
 
115
- type PajaCommand = {
146
+ /** Command configuration for a managed Paja target process. */
147
+ type PajaCommand =
148
+ /** Spawn an executable with argv preserved exactly after `--`. */
149
+ {
116
150
  readonly mode: 'argv';
117
151
  readonly argv: readonly string[];
118
- } | {
152
+ }
153
+ /** Run a shell command string. */
154
+ | {
119
155
  readonly mode: 'shell';
120
156
  readonly command: string;
121
157
  };
158
+ /** Raw, unnormalized options accepted from CLI arguments or config files. */
122
159
  interface PajaRawOptions {
160
+ /** App dev-server URL that Paja should load. */
123
161
  readonly targetUrl?: string;
162
+ /** Optional managed command to start before serving Paja. */
124
163
  readonly command?: PajaCommand;
164
+ /** Hostname or IP address for the Paja HTTP server. */
125
165
  readonly host?: string;
166
+ /** Runtime HTTP port. */
126
167
  readonly port?: number | string;
168
+ /** Target readiness timeout in milliseconds. */
127
169
  readonly readyTimeoutMs?: number | string;
170
+ /** Optional JSON config file path. */
128
171
  readonly configPath?: string;
172
+ /** Simulation controls for injected shell domains. */
129
173
  readonly simulation?: PajaSimulationRawOptions;
130
174
  }
175
+ /** Paja target loading mode. */
131
176
  type PajaTargetMode = 'iframe-url' | 'runtime-pointer';
177
+ /** Hot-module-reload strategy for the hosted target. */
132
178
  type PajaHmrStrategy = 'iframe-target-url' | 'none';
179
+ /** Runtime-pointer resolution config embedded into the Paja host page. */
133
180
  interface PajaPointerRuntimeConfig {
181
+ /** Optional naddr/nevent pointer to resolve at boot. */
134
182
  readonly value?: string;
183
+ /** Relay hints used to resolve the pointer. */
135
184
  readonly relays: readonly string[];
185
+ /** Blossom server hints used for artifact blob fetches. */
136
186
  readonly blossomServers: readonly string[];
187
+ /** Maximum pointer-resolution wait in milliseconds. */
137
188
  readonly maxWaitMs: number;
138
189
  }
190
+ /** Normalized Paja runtime options. */
139
191
  interface PajaOptions {
192
+ /** Absolute target URL for iframe-url mode. */
140
193
  readonly targetUrl: string;
194
+ /** Optional managed target command. */
141
195
  readonly command?: PajaCommand;
196
+ /** Paja server host. */
142
197
  readonly host: string;
198
+ /** Paja server port. */
143
199
  readonly port: number;
200
+ /** Target readiness timeout in milliseconds. */
144
201
  readonly readyTimeoutMs: number;
202
+ /** Optional config path retained for host diagnostics. */
145
203
  readonly configPath?: string;
204
+ /** Normalized simulation model. */
146
205
  readonly simulation: PajaSimulation;
206
+ /** Whether Paja owns a managed command or attaches to an external target. */
147
207
  readonly mode: 'external-target' | 'managed-command';
148
208
  }
209
+ /** Serialized host-page config served to the browser runtime. */
149
210
  interface PajaHostConfig {
211
+ /** Config schema version. */
150
212
  readonly version: 1;
213
+ /** Window identity used for the development target. */
151
214
  readonly window: {
152
215
  readonly id: string;
153
216
  readonly dTag: string;
@@ -175,51 +238,113 @@ interface PajaHostConfig {
175
238
  };
176
239
  readonly simulation: PajaSimulation;
177
240
  }
241
+ /** Thrown when raw Paja options cannot be normalized. */
178
242
  declare class PajaOptionsError extends Error {
179
243
  constructor(message: string);
180
244
  }
245
+ /** Default loopback host for the Paja HTTP server. */
181
246
  declare const DEFAULT_PAJA_HOST = "127.0.0.1";
247
+ /** Default Paja HTTP port. */
182
248
  declare const DEFAULT_PAJA_PORT = 5197;
249
+ /** Default readiness timeout for the target URL. */
183
250
  declare const DEFAULT_READY_TIMEOUT_MS = 30000;
251
+ /** Default development window id used in host config. */
184
252
  declare const DEFAULT_PAJA_WINDOW_ID = "kehto-paja-window";
253
+ /** Default development `d` tag used for target identity. */
185
254
  declare const DEFAULT_PAJA_DTAG = "dev-target";
255
+ /** Default development aggregate hash used for target identity. */
186
256
  declare const DEFAULT_PAJA_AGGREGATE_HASH = "paja";
257
+ /** Default pointer resolution wait in runtime-pointer mode. */
187
258
  declare const DEFAULT_PAJA_RUNTIME_WAIT_MS = 5000;
259
+ /**
260
+ * Normalize raw CLI/config options into a validated Paja runtime config.
261
+ *
262
+ * @param raw - Raw options from CLI parsing or a config file.
263
+ * @returns Fully normalized runtime options.
264
+ */
188
265
  declare function normalizePajaOptions(raw: PajaRawOptions): PajaOptions;
266
+ /**
267
+ * Create browser host-page config for iframe-url mode.
268
+ *
269
+ * @param options - Normalized Paja options.
270
+ * @param now - Clock value used for reload token and timestamps.
271
+ * @returns Serializable host-page config.
272
+ */
189
273
  declare function createPajaHostConfig(options: PajaOptions, now?: Date): PajaHostConfig;
274
+ /**
275
+ * Create browser host-page config for runtime-pointer mode.
276
+ *
277
+ * @param options - Pointer, relay, and Blossom hints.
278
+ * @param now - Clock value used for reload token and timestamps.
279
+ * @returns Serializable host-page config.
280
+ */
190
281
  declare function createPajaRuntimeHostConfig(options?: {
191
282
  readonly pointer?: string;
192
283
  readonly relays?: readonly string[];
193
284
  readonly blossomServers?: readonly string[];
194
285
  readonly maxWaitMs?: number;
195
286
  }, now?: Date): PajaHostConfig;
287
+ /**
288
+ * Format the local Paja runtime URL for display and CLI output.
289
+ *
290
+ * @param options - Host and port pair.
291
+ * @returns HTTP URL for the Paja runtime.
292
+ */
196
293
  declare function formatPajaUrl(options: Pick<PajaOptions, 'host' | 'port'>): string;
197
294
 
295
+ /** Options for polling a target URL until it is ready. */
198
296
  interface WaitForTargetUrlOptions {
297
+ /** Total wait budget in milliseconds. */
199
298
  readonly timeoutMs: number;
299
+ /** Poll interval in milliseconds. Defaults to 250. */
200
300
  readonly intervalMs?: number;
301
+ /** Fetch implementation override for tests. */
201
302
  readonly fetch?: ReadinessFetch;
303
+ /** Sleep implementation override for tests. */
202
304
  readonly sleep?: (ms: number) => Promise<void>;
305
+ /** Clock override for tests. */
203
306
  readonly now?: () => number;
204
307
  }
308
+ /** Fetch-like target readiness probe. */
205
309
  type ReadinessFetch = (url: string) => Promise<{
206
310
  readonly status: number;
207
311
  }>;
312
+ /** Thrown when a target URL does not become ready before the timeout. */
208
313
  declare class ReadinessError extends Error {
209
314
  constructor(message: string);
210
315
  }
316
+ /**
317
+ * Poll a target URL until it returns a non-5xx response or times out.
318
+ *
319
+ * @param url - Target URL to poll.
320
+ * @param options - Timeout and polling controls.
321
+ */
211
322
  declare function waitForTargetUrl(url: string, options: WaitForTargetUrlOptions): Promise<void>;
212
323
 
324
+ /** Options for starting the Paja local HTTP server. */
213
325
  interface PajaServerOptions {
326
+ /** Raw options accepted by Paja; config-file references are resolved before serving. */
214
327
  readonly options: PajaRawOptions;
328
+ /** Clock override used for deterministic host config in tests. */
215
329
  readonly now?: Date;
216
330
  }
331
+ /** Running Paja server handle. */
217
332
  interface PajaServer {
333
+ /** Runtime URL where the Paja host page is served. */
218
334
  readonly url: string;
335
+ /** Current host-page config. */
219
336
  readonly hostConfig: PajaHostConfig;
337
+ /** Update the target iframe URL without restarting the server. */
220
338
  updateTargetUrl(targetUrl: string): PajaHostConfig;
339
+ /** Stop the HTTP server. */
221
340
  close(): Promise<void>;
222
341
  }
342
+ /**
343
+ * Start the local Paja development HTTP server.
344
+ *
345
+ * @param input - Raw options and optional clock override.
346
+ * @returns Running server handle.
347
+ */
223
348
  declare function startPajaServer(input: PajaServerOptions): Promise<PajaServer>;
224
349
 
225
350
  export { createPajaRuntimeHostConfig as A, formatPajaUrl as B, normalizePajaOptions as C, DEFAULT_PAJA_AGGREGATE_HASH as D, normalizePajaSimulation as E, summarizePajaSimulation as F, type JsonPrimitive as J, type PajaRawOptions as P, ReadinessError as R, type WaitForTargetUrlOptions as W, type PajaCommand as a, type PajaHostConfig as b, DEFAULT_PAJA_DTAG as c, DEFAULT_PAJA_HOST as d, DEFAULT_PAJA_PORT as e, DEFAULT_PAJA_RUNTIME_WAIT_MS as f, DEFAULT_PAJA_WINDOW_ID as g, DEFAULT_READY_TIMEOUT_MS as h, type JsonRecord as i, type JsonValue as j, PAJA_SIMULATION_DOMAINS as k, type PajaCapabilityDomain as l, type PajaHmrStrategy as m, type PajaOptions as n, PajaOptionsError as o, type PajaPointerRuntimeConfig as p, type PajaServer as q, type PajaServerOptions as r, startPajaServer as s, type PajaSimulation as t, PajaSimulationError as u, type PajaSimulationRawOptions as v, waitForTargetUrl as w, type PajaTargetMode as x, type ReadinessFetch as y, createPajaHostConfig as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kehto/paja",
3
- "version": "0.6.3",
3
+ "version": "0.8.0",
4
4
  "description": "Paja local authoring workshop for hosting napplets in a real Kehto iframe during development",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -25,22 +25,22 @@
25
25
  "access": "public"
26
26
  },
27
27
  "dependencies": {
28
- "@kehto/acl": "^0.15.4",
29
- "@kehto/firewall": "^0.3.8",
30
- "@kehto/nip": "^0.4.1",
31
- "@kehto/runtime": "^0.18.2",
32
- "@kehto/services": "^0.16.1",
33
- "@kehto/shell": "^0.16.4",
34
- "@kehto/wm": "^0.0.1"
28
+ "@kehto/acl": "^0.15.6",
29
+ "@kehto/firewall": "^0.3.9",
30
+ "@kehto/nip": "^0.4.2",
31
+ "@kehto/runtime": "^0.18.5",
32
+ "@kehto/services": "^0.16.5",
33
+ "@kehto/shell": "^0.17.2",
34
+ "@kehto/wm": "^0.0.2"
35
35
  },
36
36
  "peerDependencies": {
37
- "@napplet/core": ">=0.23.0 <=0.27.x",
38
- "@napplet/nap": ">=0.23.0 <=0.27.x",
37
+ "@napplet/core": ">=0.23.0 <=0.28.x",
38
+ "@napplet/nap": ">=0.23.0 <=0.28.x",
39
39
  "nostr-tools": ">=2.23.3 <=2.x"
40
40
  },
41
41
  "devDependencies": {
42
- "@napplet/core": ">=0.23.0 <=0.27.x",
43
- "@napplet/nap": ">=0.23.0 <=0.27.x",
42
+ "@napplet/core": ">=0.23.0 <=0.28.x",
43
+ "@napplet/nap": ">=0.23.0 <=0.28.x",
44
44
  "nostr-tools": "^2.23.3",
45
45
  "tsup": "^8.5.0",
46
46
  "typescript": "^5.9.3",