@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/README.md +65 -16
- package/dist/browser-host.js +13762 -10871
- package/dist/browser-host.js.map +1 -1
- package/dist/{chunk-ADMLM2LH.js → chunk-NFJCS5PG.js} +163 -26
- package/dist/chunk-NFJCS5PG.js.map +1 -0
- package/dist/cli.d.ts +18 -1
- package/dist/cli.js +10 -6
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +85 -4
- package/dist/index.js +1 -1
- package/dist/{server-qAXYczds.d.ts → server-efRTBcMR.d.ts} +132 -7
- package/package.json +12 -12
- package/dist/chunk-ADMLM2LH.js.map +0 -1
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":";;;;;;;;;;;;;;AACA,SAAS,aAAgC;AAyDlC,SAAS,cAAc,MAAyC;AACrE,QAAM,MAA6B,CAAC;AAEpC,WAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAAG;AACnD,UAAM,MAAM,KAAK,KAAK;AAEtB,QAAI,QAAQ,MAAM;AAChB,YAAM,OAAO,KAAK,MAAM,QAAQ,CAAC;AACjC,UAAI,UAAU,EAAE,MAAM,QAAQ,KAAK;AACnC;AAAA,IACF;AAEA,QAAI,QAAQ,YAAY,QAAQ,MAAM;AACpC,aAAO,EAAE,MAAM,KAAK;AAAA,IACtB;AAEA,QAAI,gBAAgB,KAAK,MAAM,OAAO,GAAG,KAAK,sBAAsB,KAAK,MAAM,OAAO,GAAG,GAAG;AAC1F,eAAS;AACT;AAAA,IACF;AAEA,UAAM,IAAI,iBAAiB,mBAAmB,GAAG,qCAAqC;AAAA,EACxF;AAEA,SAAO,EAAE,MAAM,OAAO,SAAS,IAAI;AACrC;AAEA,eAAsB,WACpB,OAA0B,QAAQ,KAAK,MAAM,CAAC,GAC9C,KAAY,WACZ,aAAgC,CAAC,GAChB;AACjB,MAAI;AACF,UAAM,SAAS,cAAc,IAAI;AACjC,QAAI,OAAO,MAAM;AACf,SAAG,OAAO,MAAM,GAAG,SAAS;AAAA,CAAI;AAChC,aAAO;AAAA,IACT;AAEA,UAAM,aAAa,sBAAsB,OAAO,WAAW,CAAC,CAAC;AAC7D,UAAM,UAAU,qBAAqB,UAAU;AAC/C,UAAM,aAAa,qBAAqB,OAAO;AAC/C,UAAM,cAAc,WAAW,SAAS;AACxC,UAAM,cAAc,WAAW,eAAe;AAC9C,UAAM,eAAe,WAAW,gBAAgB;AAChD,UAAM,gBAAgB,WAAW,oBAAoB;AACrD,QAAI;AACJ,QAAI;AACJ,QAAI,aAAa;AACf,UAAI;AACF,iBAAS,MAAM,YAAY,EAAE,SAAS,WAAW,CAAC;AAClD,4BAAoB,IAAI,OAAO,KAAK,YAAY,OAAO;AAEvD,YAAI,QAAQ,SAAS;AACnB,kBAAQ,aAAa,QAAQ,SAAS,EAAE;AACxC,gBAAM,YAAY,MAAM,wBAAwB,QAAQ,WAAW,OAAO;AAAA,YACxE,WAAW,QAAQ;AAAA,YACnB,kBAAkB,WAAW;AAAA,YAC7B,kBAAkB;AAAA,UACpB,CAAC;AACD,cAAI,cAAc,QAAQ,WAAW;AACnC,mBAAO,gBAAgB,SAAS;AAChC,eAAG,OAAO,MAAM,uBAAuB,SAAS;AAAA,CAAI;AAAA,UACtD;AAAA,QACF;AAAA,MACF,SAAS,OAAO;AACd,eAAO,KAAK;AACZ,cAAM,QAAQ,MAAM,EAAE,MAAM,MAAM,MAAS;AAC3C,cAAM;AAAA,MACR;AAAA,IACF;AACA,UAAM,aAAa,QAAQ,OAAO,cAAc,OAAO;AAEvD,QAAI,CAAC,aAAa;AAChB,0BAAoB,IAAI,YAAY,YAAY,OAAO;AAAA,IACzD;AAEA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,OAAG,OAAO,MAAM,eAAe,OAAO;AAAA,CAAI;AAC1C,WAAO;AAAA,EACT;AACF;AAEA,SAAS,oBACP,IACA,YACA,YACA,SACM;AACJ,KAAG,OAAO,MAAM;AAAA,CAAc;AAC9B,KAAG,OAAO,MAAM,gBAAgB,UAAU;AAAA,CAAI;AAC9C,KAAG,OAAO,MAAM,eAAe,WAAW,OAAO,GAAG;AAAA,CAAI;AACxD,KAAG,OAAO,MAAM,SAAS,QAAQ,IAAI;AAAA,CAAI;AACzC,KAAG,OAAO,MAAM,QAAQ,WAAW,OAAO,WAAW;AAAA,CAAI;AACzD,KAAG,OAAO,MAAM,eAAe,wBAAwB,QAAQ,UAAU,CAAC;AAAA,CAAI;AAE9E,MAAI,QAAQ,SAAS;AACnB,OAAG,OAAO,MAAM,YAAY,cAAc,QAAQ,OAAO,CAAC;AAAA,CAAI;AAAA,EAChE;AACJ;AAEA,IAAM,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8BlB,SAAS,UAAU,MAAyB,OAAe,QAAwB;AACjF,QAAM,QAAQ,KAAK,QAAQ,CAAC;AAC5B,MAAI,CAAC,SAAS,MAAM,WAAW,IAAI,GAAG;AACpC,UAAM,IAAI,iBAAiB,GAAG,MAAM,oBAAoB;AAAA,EAC1D;AACA,SAAO;AACT;AAEA,SAAS,gBACP,KACA,MACA,OACA,KACS;AACT,UAAQ,KAAK;AAAA,IACX,KAAK;AAAA,IACL,KAAK;AACH,UAAI,YAAY,UAAU,MAAM,OAAO,GAAG;AAC1C,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,UAAI,UAAU,EAAE,MAAM,SAAS,SAAS,UAAU,MAAM,OAAO,GAAG,EAAE;AACpE,aAAO;AAAA,IACT,KAAK;AACH,UAAI,OAAO,UAAU,MAAM,OAAO,GAAG;AACrC,aAAO;AAAA,IACT,KAAK;AACH,UAAI,OAAO,UAAU,MAAM,OAAO,GAAG;AACrC,aAAO;AAAA,IACT,KAAK;AACH,UAAI,iBAAiB,UAAU,MAAM,OAAO,GAAG;AAC/C,aAAO;AAAA,IACT,KAAK;AACH,UAAI,aAAa,UAAU,MAAM,OAAO,GAAG;AAC3C,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,sBACP,KACA,MACA,OACA,KACS;AACT,UAAQ,KAAK;AAAA,IACX,KAAK;AACH,kBAAY,KAAK,EAAE,MAAM,SAAS,MAAM,OAAO,KAAK,CAAC,aAAa,OAAO,CAAC,EAAE,CAAC;AAC7E,aAAO;AAAA,IACT,KAAK;AACH,kBAAY,KAAK,EAAE,QAAQ,UAAU,MAAM,OAAO,GAAG,EAAE,CAAC;AACxD,aAAO;AAAA,IACT,KAAK;AACH,eAAS,KAAK,EAAE,MAAM,SAAS,MAAM,OAAO,KAAK,CAAC,UAAU,UAAU,CAAC,EAAE,CAAC;AAC1E,aAAO;AAAA,IACT,KAAK;AACH,eAAS,KAAK,EAAE,MAAM,CAAC,GAAI,IAAI,YAAY,OAAO,QAAQ,CAAC,GAAI,UAAU,MAAM,OAAO,GAAG,CAAC,EAAE,CAAC;AAC7F,aAAO;AAAA,IACT,KAAK;AACH,uBAAiB,GAAG,EAAE,UAAU,EAAE,GAAG,IAAI,YAAY,SAAS,MAAM,SAAS,MAAM,OAAO,KAAK,CAAC,SAAS,UAAU,UAAU,CAAC,EAAE;AAChI,aAAO;AAAA,IACT,KAAK;AACH,uBAAiB,GAAG,EAAE,QAAQ,EAAE,GAAG,IAAI,YAAY,OAAO,MAAM,SAAS,MAAM,OAAO,KAAK,CAAC,UAAU,UAAU,CAAC,EAAE;AACnH,aAAO;AAAA,IACT,KAAK;AACH,gBAAU,KAAK,EAAE,MAAM,SAAS,MAAM,OAAO,KAAK,CAAC,UAAU,UAAU,CAAC,EAAE,CAAC;AAC3E,aAAO;AAAA,IACT,KAAK;AACH,gBAAU,KAAK,EAAE,MAAM,UAAU,MAAM,OAAO,GAAG,EAAE,CAAC;AACpD,aAAO;AAAA,IACT,KAAK;AACH,uBAAiB,GAAG,EAAE,QAAQ,EAAE,GAAG,IAAI,YAAY,OAAO,SAAS,YAAY,MAAM,OAAO,GAAG,EAAE;AACjG,aAAO;AAAA,IACT,KAAK;AACH,uBAAiB,KAAK,EAAE,SAAS,YAAY,MAAM,OAAO,GAAG,EAAE,CAAC;AAChE,aAAO;AAAA,IACT,KAAK;AACH,uBAAiB,KAAK,EAAE,OAAO,YAAY,MAAM,OAAO,GAAG,EAAE,CAAC;AAC9D,aAAO;AAAA,IACT,KAAK;AACH,uBAAiB,GAAG,EAAE,QAAQ,EAAE,GAAG,IAAI,YAAY,OAAO,MAAM,SAAS,MAAM,OAAO,KAAK,CAAC,QAAQ,OAAO,CAAC,EAAE;AAC9G,aAAO;AAAA,IACT,KAAK;AACH,qBAAe,KAAK,gBAAgB,MAAM,OAAO,GAAG,CAAC;AACrD,aAAO;AAAA,IACT,KAAK;AACH,oBAAc,KAAK,eAAe,MAAM,OAAO,GAAG,CAAC;AACnD,aAAO;AAAA,IACT,KAAK;AACH,uBAAiB,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,YAAY,KAAK,MAAM,SAAS,MAAM,OAAO,KAAK,CAAC,SAAS,MAAM,CAAC,EAAE;AAC1G,aAAO;AAAA,IACT,KAAK;AACH,uBAAiB,GAAG,EAAE,WAAW,EAAE,GAAG,IAAI,YAAY,UAAU,MAAM,SAAS,MAAM,OAAO,KAAK,CAAC,SAAS,QAAQ,SAAS,CAAC,EAAE;AAC/H,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,cAAc,SAA8B;AACnD,SAAO,QAAQ,SAAS,SAAS,QAAQ,KAAK,KAAK,GAAG,IAAI,QAAQ;AACpE;AAEA,SAAS,SACP,MACA,OACA,QACA,SACW;AACX,QAAM,QAAQ,UAAU,MAAM,OAAO,MAAM;AAC3C,MAAI,CAAC,QAAQ,SAAS,KAAK,GAAG;AAC5B,UAAM,IAAI,iBAAiB,GAAG,MAAM,oBAAoB,QAAQ,KAAK,IAAI,CAAC,GAAG;AAAA,EAC/E;AACA,SAAO;AACT;AAEA,SAAS,YAAY,MAAyB,OAAe,QAAyB;AACpF,QAAM,QAAQ,UAAU,MAAM,OAAO,MAAM;AAC3C,MAAI,UAAU,UAAW,QAAO;AAChC,MAAI,UAAU,WAAY,QAAO;AACjC,QAAM,IAAI,iBAAiB,GAAG,MAAM,mCAAmC;AACzE;AAEA,SAAS,YAAY,MAAyB,OAAe,QAAyB;AACpF,QAAM,QAAQ,UAAU,MAAM,OAAO,MAAM;AAC3C,MAAI,UAAU,OAAQ,QAAO;AAC7B,MAAI,UAAU,QAAS,QAAO;AAC9B,QAAM,IAAI,iBAAiB,GAAG,MAAM,6BAA6B;AACnE;AAEA,SAAS,gBACP,MACA,OACA,QACmC;AACnC,QAAM,MAAM,UAAU,MAAM,OAAO,MAAM;AACzC,QAAM,YAAY,IAAI,QAAQ,GAAG;AACjC,MAAI,aAAa,GAAG;AAClB,UAAM,IAAI,iBAAiB,GAAG,MAAM,oBAAoB;AAAA,EAC1D;AACA,QAAM,MAAM,IAAI,MAAM,GAAG,SAAS,EAAE,KAAK;AACzC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,iBAAiB,GAAG,MAAM,2BAA2B;AAAA,EACjE;AACA,MAAI;AACF,WAAO,EAAE,KAAK,OAAO,KAAK,MAAM,IAAI,MAAM,YAAY,CAAC,CAAC,EAAe;AAAA,EACzE,QAAQ;AACN,UAAM,IAAI,iBAAiB,GAAG,MAAM,eAAe,GAAG,uBAAuB;AAAA,EAC/E;AACF;AAEA,SAAS,eACP,MACA,OACA,QACoD;AACpD,QAAM,MAAM,UAAU,MAAM,OAAO,MAAM;AACzC,QAAM,CAAC,WAAW,QAAQ,IAAI,IAAI,MAAM,GAAG;AAC3C,MAAI,CAAC,aAAc,aAAa,QAAQ,aAAa,OAAQ;AAC3D,UAAM,IAAI,iBAAiB,GAAG,MAAM,mCAAmC;AAAA,EACzE;AACA,MAAI,CAAC,wBAAwB,SAAS,SAAiC,GAAG;AACxE,UAAM,IAAI,iBAAiB,GAAG,MAAM,oBAAoB,SAAS,IAAI;AAAA,EACvE;AACA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,SAAS,aAAa;AAAA,EACxB;AACF;AAEA,SAAS,YAAY,KAA4B,UAAmE;AAClH,mBAAiB,GAAG,EAAE,WAAW,EAAE,GAAG,IAAI,YAAY,UAAU,GAAG,SAAS;AAC9E;AAEA,SAAS,SAAS,KAA4B,OAA6D;AACzG,mBAAiB,GAAG,EAAE,QAAQ,EAAE,GAAG,IAAI,YAAY,OAAO,GAAG,MAAM;AACrE;AAEA,SAAS,UAAU,KAA4B,QAA+D;AAC5G,mBAAiB,GAAG,EAAE,SAAS,EAAE,GAAG,IAAI,YAAY,QAAQ,GAAG,OAAO;AACxE;AAEA,SAAS,iBACP,KACA,eACM;AACN,mBAAiB,GAAG,EAAE,gBAAgB,EAAE,GAAG,IAAI,YAAY,eAAe,GAAG,cAAc;AAC7F;AAEA,SAAS,eACP,KACA,OACM;AACN,mBAAiB,GAAG,EAAE,SAAS;AAAA,IAC7B,GAAG,IAAI,YAAY;AAAA,IACnB,QAAQ;AAAA,MACN,GAAG,IAAI,YAAY,QAAQ;AAAA,MAC3B,CAAC,MAAM,GAAG,GAAG,MAAM;AAAA,IACrB;AAAA,EACF;AACF;AAEA,SAAS,cACP,KACA,OACM;AACN,mBAAiB,GAAG,EAAE,eAAe;AAAA,IACnC,GAAG,IAAI,YAAY;AAAA,IACnB,SAAS;AAAA,MACP,GAAG,IAAI,YAAY,cAAc;AAAA,MACjC,CAAC,MAAM,MAAM,GAAG,MAAM;AAAA,IACxB;AAAA,EACF;AACF;AAEA,SAAS,iBAAiB,KAA6D;AACrF,MAAI,eAAe,CAAC;AACpB,SAAO,IAAI;AACb;AAEA,eAAe,wBACb,eACA,OACA,SAKiB;AACjB,MAAI;AACJ,QAAM,kBAAkB,QAAQ,iBAAiB,eAAe,EAAE,WAAW,QAAQ,UAAU,CAAC,EAC7F,KAAK,MAAM,aAAa,EACxB,MAAM,CAAC,UAAU;AAChB,sBAAkB;AAClB,WAAO;AAAA,EACT,CAAC;AACH,QAAM,QAAQ,MAAM,QAAQ,KAAK;AAAA,IAC/B,gBAAgB,KAAK,CAAC,QAAQ,MAAM,EAAE,MAAM,cAAuB,IAAI,IAAI,MAAS;AAAA,IACpF,MAAM,kBAAkB,KAAK,CAAC,SAAS,EAAE,MAAM,YAAqB,IAAI,EAAE;AAAA,EAC5E,CAAC;AAED,MAAI,OAAO,SAAS,YAAY;AAC9B,UAAM,QAAQ,iBAAiB,MAAM,KAAK,EAAE,WAAW,QAAQ,UAAU,CAAC;AAC1E,WAAO,MAAM;AAAA,EACf;AAEA,QAAM,UAAU,QAAQ,oBAAoB,KAAK,IAAI,KAAM,QAAQ,SAAS;AAC5E,QAAM,WAAW,MAAM,cAAc,MAAM,mBAAmB,OAAO;AACrE,MAAI,CAAC,UAAU;AACb,QAAI,OAAO,KAAK;AACd,aAAO,MAAM;AAAA,IACf;AACA,UAAM,2BAA2B,QAAQ,kBAAkB,IAAI,MAAM,OAAO,mBAAmB,2BAA2B,CAAC;AAAA,EAC7H;AAEA,QAAM,QAAQ,iBAAiB,UAAU,EAAE,WAAW,QAAQ,UAAU,CAAC;AACzE,SAAO;AACT;AAEA,SAAS,cAAiB,SAAqB,WAA2C;AACxF,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI,UAAU;AACd,UAAM,UAAU,WAAW,MAAM;AAC/B,UAAI,QAAS;AACb,gBAAU;AACV,cAAQ,MAAS;AAAA,IACnB,GAAG,KAAK,IAAI,GAAG,SAAS,CAAC;AAEzB,YAAQ,KAAK,CAAC,UAAU;AACtB,UAAI,QAAS;AACb,gBAAU;AACV,mBAAa,OAAO;AACpB,cAAQ,KAAK;AAAA,IACf,GAAG,MAAM;AACP,UAAI,QAAS;AACb,gBAAU;AACV,mBAAa,OAAO;AACpB,cAAQ,MAAS;AAAA,IACnB,CAAC;AAAA,EACH,CAAC;AACH;AAEA,SAAS,oBAAoB,SAAsB,IAAgC;AACjF,QAAM,WAAW,+BAA+B;AAChD,QAAM,QAAQ,oBAAoB,OAAO;AACzC,uBAAqB,OAAO,UAAU,EAAE;AACxC,SAAO;AAAA,IACL,MAAM,MAAM,MAAM,KAAK;AAAA,IACvB,mBAAmB,SAAS;AAAA,EAC9B;AACF;AAEA,SAAS,oBAAoB,SAAoC;AAC/D,MAAI,QAAQ,SAAS,SAAS;AAC5B,WAAO,MAAM,QAAQ,SAAS,EAAE,OAAO,MAAM,OAAO,CAAC,WAAW,QAAQ,MAAM,EAAW,CAAC;AAAA,EAC5F;AAEA,QAAM,CAAC,YAAY,GAAG,IAAI,IAAI,QAAQ;AACtC,MAAI,CAAC,YAAY;AACf,UAAM,IAAI,iBAAiB,2CAA2C;AAAA,EACxE;AACA,SAAO,MAAM,YAAY,MAAM,EAAE,OAAO,CAAC,WAAW,QAAQ,MAAM,EAAW,CAAC;AAChF;AAEA,SAAS,qBACP,OACA,UACA,IACM;AACN,QAAM,QAAQ,GAAG,QAAQ,CAAC,UAA+B;AACvD,UAAM,OAAO,OAAO,KAAK;AACzB,aAAS,QAAQ,IAAI;AACrB,OAAG,OAAO,MAAM,IAAI;AAAA,EACtB,CAAC;AACD,QAAM,QAAQ,GAAG,QAAQ,CAAC,UAA+B;AACvD,UAAM,OAAO,OAAO,KAAK;AACzB,aAAS,QAAQ,IAAI;AACrB,OAAG,OAAO,MAAM,IAAI;AAAA,EACtB,CAAC;AACH;AAEA,SAAS,iCAA2D;AAClE,MAAI,kBAAyC,MAAM;AAAA,EAEnD;AACA,MAAI;AACJ,QAAM,oBAAoB,IAAI,QAAgB,CAAC,YAAY;AACzD,sBAAkB;AAAA,EACpB,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA,QAAQ,OAAO;AACb,UAAI,SAAU;AACd,YAAM,OAAO,UAAU,KAAK;AAC5B,iBAAW,SAAS,KAAK,SAAS,sBAAsB,GAAG;AACzD,cAAM,SAAS,MAAM,CAAC;AACtB,YAAI;AACJ,YAAI;AACF,gBAAM,IAAI,IAAI,MAAM;AAAA,QACtB,QAAQ;AACN;AAAA,QACF;AACA,mBAAW,IAAI;AACf,wBAAgB,QAAQ;AACxB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,UAAU,OAAuB;AACxC,SAAO,MAAM,QAAQ,cAAc,EAAE;AACvC;AAUA,IAAM,YAAmB;AAAA,EACvB,QAAQ,EAAE,OAAO,CAAC,UAAU,QAAQ,OAAO,MAAM,KAAK,EAAE;AAAA,EACxD,QAAQ,EAAE,OAAO,CAAC,UAAU,QAAQ,OAAO,MAAM,KAAK,EAAE;AAC1D;AAEA,IAAI,gBAAgB,GAAG;AACrB,OAAK,WAAW,EAAE,KAAK,CAAC,SAAS;AAC/B,YAAQ,WAAW;AAAA,EACrB,CAAC;AACH;AAEO,SAAS,gBAAgB,YAAY,QAAQ,KAAK,CAAC,GAAY;AACpE,MAAI,CAAC,UAAW,QAAO;AACvB,SAAO,UAAU,SAAS,SAAS,KAAK,UAAU,SAAS,OAAO;AACpE;AAmBA,IAAM,yBAAyB;AAC/B,IAAM,eAAe;","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-
|
|
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-
|
|
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
|
|
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
|
|
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
|
@@ -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
|
|
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
|
-
|
|
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.
|
|
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.
|
|
29
|
-
"@kehto/firewall": "^0.3.
|
|
30
|
-
"@kehto/nip": "^0.4.
|
|
31
|
-
"@kehto/runtime": "^0.18.
|
|
32
|
-
"@kehto/services": "^0.16.
|
|
33
|
-
"@kehto/shell": "^0.
|
|
34
|
-
"@kehto/wm": "^0.0.
|
|
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.
|
|
38
|
-
"@napplet/nap": ">=0.23.0 <=0.
|
|
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.
|
|
43
|
-
"@napplet/nap": ">=0.23.0 <=0.
|
|
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",
|