@kehto/paja 0.3.2 → 0.3.5
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 +2 -1
- package/dist/browser-host.js +269 -93
- package/dist/browser-host.js.map +1 -1
- package/dist/{chunk-5HWERUMK.js → chunk-6QZXEPQJ.js} +2 -2
- package/dist/{chunk-5HWERUMK.js.map → chunk-6QZXEPQJ.js.map} +1 -1
- package/dist/cli.d.ts +2 -1
- package/dist/cli.js +30 -20
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +10 -10
|
@@ -442,6 +442,7 @@ var PAJA_UPSTREAM_WEB_DOMAINS = [
|
|
|
442
442
|
"common",
|
|
443
443
|
"config",
|
|
444
444
|
"cvm",
|
|
445
|
+
"dm",
|
|
445
446
|
"identity",
|
|
446
447
|
PAJA_LEGACY_COMPATIBILITY_DOMAIN,
|
|
447
448
|
"inc",
|
|
@@ -455,7 +456,6 @@ var PAJA_UPSTREAM_WEB_DOMAINS = [
|
|
|
455
456
|
"relay",
|
|
456
457
|
"resource",
|
|
457
458
|
"serial",
|
|
458
|
-
"shell",
|
|
459
459
|
"storage",
|
|
460
460
|
"theme",
|
|
461
461
|
"upload",
|
|
@@ -656,4 +656,4 @@ export {
|
|
|
656
656
|
waitForTargetUrl,
|
|
657
657
|
startPajaServer
|
|
658
658
|
};
|
|
659
|
-
//# sourceMappingURL=chunk-
|
|
659
|
+
//# sourceMappingURL=chunk-6QZXEPQJ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config-file.ts","../src/simulation.ts","../src/options.ts","../src/host-page.ts","../src/parity.ts","../src/readiness.ts","../src/server.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport type { PajaRawOptions } from './options.js';\nimport type { PajaSimulationRawOptions } from './simulation.js';\nimport { PajaSimulationError } from './simulation.js';\n\nexport function loadPajaConfigFile(configPath: string): PajaRawOptions {\n const resolved = resolve(configPath);\n let parsed: unknown;\n try {\n parsed = JSON.parse(readFileSync(resolved, 'utf8'));\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error);\n throw new PajaSimulationError(`Unable to read --config \"${configPath}\": ${detail}`);\n }\n\n if (!isRecord(parsed)) {\n throw new PajaSimulationError(`Invalid --config \"${configPath}\": expected a JSON object.`);\n }\n\n return parsed as PajaRawOptions;\n}\n\nexport function resolvePajaRawOptions(raw: PajaRawOptions): PajaRawOptions {\n if (!raw.configPath?.trim()) return raw;\n return mergePajaRawOptions(loadPajaConfigFile(raw.configPath), raw);\n}\n\nexport function mergePajaRawOptions(\n base: PajaRawOptions,\n override: PajaRawOptions,\n): PajaRawOptions {\n return {\n targetUrl: override.targetUrl ?? base.targetUrl,\n command: override.command ?? base.command,\n host: override.host ?? base.host,\n port: override.port ?? base.port,\n readyTimeoutMs: override.readyTimeoutMs ?? base.readyTimeoutMs,\n configPath: override.configPath ?? base.configPath,\n simulation: mergeSimulationOptions(base.simulation, override.simulation),\n };\n}\n\nfunction mergeSimulationOptions(\n base: PajaSimulationRawOptions | undefined,\n override: PajaSimulationRawOptions | undefined,\n): PajaSimulationRawOptions | undefined {\n if (!base) return override;\n if (!override) return base;\n\n return {\n capabilities: {\n ...base.capabilities,\n ...override.capabilities,\n domains: {\n ...base.capabilities?.domains,\n ...override.capabilities?.domains,\n },\n },\n acl: { ...base.acl, ...override.acl },\n firewall: { ...base.firewall, ...override.firewall },\n identity: { ...base.identity, ...override.identity },\n relay: { ...base.relay, ...override.relay },\n storage: { ...base.storage, ...override.storage },\n cache: { ...base.cache, ...override.cache },\n upload: { ...base.upload, ...override.upload },\n media: { ...base.media, ...override.media },\n notifications: { ...base.notifications, ...override.notifications },\n config: {\n ...base.config,\n ...override.config,\n values: { ...base.config?.values, ...override.config?.values },\n },\n theme: {\n ...base.theme,\n ...override.theme,\n values: { ...base.theme?.values, ...override.theme?.values },\n },\n intent: { ...base.intent, ...override.intent },\n cvm: { ...base.cvm, ...override.cvm },\n };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","export type JsonPrimitive = string | number | boolean | null;\nexport type JsonValue = JsonPrimitive | JsonValue[] | { readonly [key: string]: JsonValue };\nexport type JsonRecord = Record<string, JsonValue>;\n\nexport type PajaCapabilityDomain =\n | 'relay'\n | 'outbox'\n | 'storage'\n | 'identity'\n | 'keys'\n | 'config'\n | 'resource'\n | 'theme'\n | 'notify'\n | 'media'\n | 'upload'\n | 'intent'\n | 'link'\n | 'common'\n | 'lists'\n | 'serial'\n | 'ble'\n | 'webrtc'\n | 'cvm'\n | 'inc';\n\nexport interface PajaSimulationRawOptions {\n readonly capabilities?: {\n readonly domains?: Partial<Record<PajaCapabilityDomain, boolean>>;\n };\n readonly acl?: {\n readonly mode?: 'allow' | 'deny';\n };\n readonly firewall?: {\n readonly mode?: 'allow' | 'deny' | 'observe';\n };\n readonly identity?: {\n readonly mode?: 'anonymous' | 'fixed';\n readonly pubkey?: string;\n };\n readonly relay?: {\n readonly mode?: 'memory' | 'disabled';\n readonly urls?: readonly string[];\n readonly fixtures?: readonly JsonRecord[];\n };\n readonly storage?: {\n readonly mode?: 'local' | 'memory' | 'disabled';\n };\n readonly cache?: {\n readonly mode?: 'memory' | 'disabled';\n };\n readonly upload?: {\n readonly mode?: 'memory' | 'disabled';\n readonly rail?: string;\n };\n readonly media?: {\n readonly enabled?: boolean;\n };\n readonly notifications?: {\n readonly enabled?: boolean;\n readonly grant?: boolean;\n };\n readonly config?: {\n readonly values?: JsonRecord;\n };\n readonly theme?: {\n readonly mode?: 'dark' | 'light';\n readonly values?: JsonRecord;\n };\n readonly intent?: {\n readonly enabled?: boolean;\n };\n readonly cvm?: {\n readonly enabled?: boolean;\n };\n}\n\nexport interface PajaSimulation {\n readonly capabilities: {\n readonly domains: Record<PajaCapabilityDomain, boolean>;\n readonly disabledDomains: readonly PajaCapabilityDomain[];\n };\n readonly acl: {\n readonly mode: 'allow' | 'deny';\n };\n readonly firewall: {\n readonly mode: 'allow' | 'deny' | 'observe';\n };\n readonly identity: {\n readonly mode: 'anonymous' | 'fixed';\n readonly pubkey: string;\n };\n readonly relay: {\n readonly mode: 'memory' | 'disabled';\n readonly urls: readonly string[];\n readonly fixtures: readonly JsonRecord[];\n };\n readonly storage: {\n readonly mode: 'local' | 'memory' | 'disabled';\n };\n readonly cache: {\n readonly mode: 'memory' | 'disabled';\n };\n readonly upload: {\n readonly mode: 'memory' | 'disabled';\n readonly rail: string;\n };\n readonly media: {\n readonly enabled: boolean;\n };\n readonly notifications: {\n readonly enabled: boolean;\n readonly grant: boolean;\n };\n readonly config: {\n readonly values: JsonRecord;\n };\n readonly theme: {\n readonly mode: 'dark' | 'light';\n readonly values: JsonRecord;\n };\n readonly intent: {\n readonly enabled: boolean;\n };\n readonly cvm: {\n readonly enabled: boolean;\n };\n}\n\nexport class PajaSimulationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'PajaSimulationError';\n }\n}\n\nexport const PAJA_SIMULATION_DOMAINS: readonly PajaCapabilityDomain[] = [\n 'relay',\n 'outbox',\n 'storage',\n 'identity',\n 'keys',\n 'config',\n 'resource',\n 'theme',\n 'notify',\n 'media',\n 'upload',\n 'intent',\n 'link',\n 'common',\n 'lists',\n 'serial',\n 'ble',\n 'webrtc',\n 'cvm',\n 'inc',\n];\n\nconst DEFAULT_RELAY_URLS = ['wss://relay.kehto.dev'] as const;\nconst DEFAULT_CONFIG_VALUES: JsonRecord = {\n runtime: 'kehto paja',\n mode: 'development',\n target: 'single-window',\n};\n\nconst DEFAULT_THEME_VALUES: JsonRecord = {\n title: 'Kehto Paja',\n};\n\nexport function normalizePajaSimulation(\n raw: PajaSimulationRawOptions | undefined,\n): PajaSimulation {\n const domainOverrides = raw?.capabilities?.domains ?? {};\n const domains = Object.fromEntries(\n PAJA_SIMULATION_DOMAINS.map((domain) => [domain, domainOverrides[domain] ?? true]),\n ) as Record<PajaCapabilityDomain, boolean>;\n\n const relayMode = raw?.relay?.mode ?? (domains.relay ? 'memory' : 'disabled');\n if (!domains.relay && relayMode !== 'disabled') {\n throw new PajaSimulationError('Invalid simulation: relay.mode must be \"disabled\" when capabilities.domains.relay is false.');\n }\n if (!domains.outbox && relayMode !== 'disabled') {\n throw new PajaSimulationError('Invalid simulation: relay.mode must be \"disabled\" when capabilities.domains.outbox is false.');\n }\n if (relayMode === 'disabled') {\n domains.relay = false;\n domains.outbox = false;\n }\n\n const uploadMode = raw?.upload?.mode ?? (domains.upload ? 'memory' : 'disabled');\n if (!domains.upload && uploadMode !== 'disabled') {\n throw new PajaSimulationError('Invalid simulation: upload.mode must be \"disabled\" when capabilities.domains.upload is false.');\n }\n if (uploadMode === 'disabled') domains.upload = false;\n\n const intentEnabled = raw?.intent?.enabled ?? domains.intent;\n if (!domains.intent && intentEnabled) {\n throw new PajaSimulationError('Invalid simulation: intent.enabled must be false when capabilities.domains.intent is false.');\n }\n if (!intentEnabled) domains.intent = false;\n\n const mediaEnabled = raw?.media?.enabled ?? domains.media;\n if (!domains.media && mediaEnabled) {\n throw new PajaSimulationError('Invalid simulation: media.enabled must be false when capabilities.domains.media is false.');\n }\n if (!mediaEnabled) domains.media = false;\n\n const cvmEnabled = raw?.cvm?.enabled ?? domains.cvm;\n if (!domains.cvm && cvmEnabled) {\n throw new PajaSimulationError('Invalid simulation: cvm.enabled must be false when capabilities.domains.cvm is false.');\n }\n if (!cvmEnabled) domains.cvm = false;\n\n const notificationsEnabled = raw?.notifications?.enabled ?? domains.notify;\n if (!domains.notify && notificationsEnabled) {\n throw new PajaSimulationError('Invalid simulation: notifications.enabled must be false when capabilities.domains.notify is false.');\n }\n if (!notificationsEnabled) domains.notify = false;\n\n const storageMode = raw?.storage?.mode ?? (domains.storage ? 'local' : 'disabled');\n if (!domains.storage && storageMode !== 'disabled') {\n throw new PajaSimulationError('Invalid simulation: storage.mode must be \"disabled\" when capabilities.domains.storage is false.');\n }\n if (storageMode === 'disabled') domains.storage = false;\n\n const identityMode = raw?.identity?.mode ?? 'anonymous';\n const pubkey = raw?.identity?.pubkey?.trim() ?? '';\n if (identityMode === 'fixed' && !isHexPubkey(pubkey)) {\n throw new PajaSimulationError('Invalid simulation: identity.pubkey must be a 64-character hex string when identity.mode is \"fixed\".');\n }\n\n const relayUrls = raw?.relay?.urls ?? DEFAULT_RELAY_URLS;\n if (relayMode === 'memory' && relayUrls.length === 0) {\n throw new PajaSimulationError('Invalid simulation: relay.urls must contain at least one URL when relay.mode is \"memory\".');\n }\n for (const url of relayUrls) {\n if (typeof url !== 'string' || url.trim().length === 0) {\n throw new PajaSimulationError('Invalid simulation: relay.urls entries must be non-empty strings.');\n }\n }\n\n const uploadRail = raw?.upload?.rail?.trim() || 'dev-memory';\n if (uploadMode === 'memory' && uploadRail.length === 0) {\n throw new PajaSimulationError('Invalid simulation: upload.rail must be non-empty when upload.mode is \"memory\".');\n }\n\n return {\n capabilities: {\n domains,\n disabledDomains: PAJA_SIMULATION_DOMAINS.filter((domain) => !domains[domain]),\n },\n acl: {\n mode: raw?.acl?.mode ?? 'allow',\n },\n firewall: {\n mode: raw?.firewall?.mode ?? 'observe',\n },\n identity: {\n mode: identityMode,\n pubkey: identityMode === 'fixed' ? pubkey : '',\n },\n relay: {\n mode: relayMode,\n urls: relayUrls.map((url) => url.trim()),\n fixtures: raw?.relay?.fixtures ?? [],\n },\n storage: {\n mode: storageMode,\n },\n cache: {\n mode: raw?.cache?.mode ?? 'memory',\n },\n upload: {\n mode: uploadMode,\n rail: uploadRail,\n },\n media: {\n enabled: mediaEnabled,\n },\n notifications: {\n enabled: notificationsEnabled,\n grant: raw?.notifications?.grant ?? true,\n },\n config: {\n values: { ...DEFAULT_CONFIG_VALUES, ...raw?.config?.values },\n },\n theme: {\n mode: raw?.theme?.mode ?? 'dark',\n values: { ...DEFAULT_THEME_VALUES, ...raw?.theme?.values },\n },\n intent: {\n enabled: intentEnabled,\n },\n cvm: {\n enabled: cvmEnabled,\n },\n };\n}\n\nexport function summarizePajaSimulation(simulation: PajaSimulation): string {\n const relay = simulation.relay.mode === 'memory' ? `relay:${simulation.relay.urls.length}` : 'relay:off';\n const identity = simulation.identity.mode === 'fixed' ? 'identity:fixed' : 'identity:anon';\n const storage = `storage:${simulation.storage.mode}`;\n const theme = `theme:${simulation.theme.mode}`;\n const disabled = simulation.capabilities.disabledDomains.length > 0\n ? `off:${simulation.capabilities.disabledDomains.join(',')}`\n : 'off:none';\n return `${identity} ${relay} ${storage} ${theme} ${disabled}`;\n}\n\nfunction isHexPubkey(value: string): boolean {\n return /^[0-9a-fA-F]{64}$/.test(value);\n}\n","import {\n normalizePajaSimulation,\n type PajaSimulation,\n type PajaSimulationRawOptions,\n} from './simulation.js';\n\nexport type PajaCommand =\n | { readonly mode: 'argv'; readonly argv: readonly string[] }\n | { readonly mode: 'shell'; readonly command: string };\n\nexport interface PajaRawOptions {\n readonly targetUrl?: string;\n readonly command?: PajaCommand;\n readonly host?: string;\n readonly port?: number | string;\n readonly readyTimeoutMs?: number | string;\n readonly configPath?: string;\n readonly simulation?: PajaSimulationRawOptions;\n}\n\nexport interface PajaOptions {\n readonly targetUrl: string;\n readonly command?: PajaCommand;\n readonly host: string;\n readonly port: number;\n readonly readyTimeoutMs: number;\n readonly configPath?: string;\n readonly simulation: PajaSimulation;\n readonly mode: 'external-target' | 'managed-command';\n}\n\nexport interface PajaHostConfig {\n readonly version: 1;\n readonly window: {\n readonly id: string;\n readonly dTag: string;\n readonly aggregateHash: string;\n };\n readonly target: {\n readonly url: string;\n readonly hmrStrategy: 'iframe-target-url';\n readonly command?: PajaCommand;\n };\n readonly runtime: {\n readonly host: string;\n readonly port: number;\n readonly readyTimeoutMs: number;\n readonly configPath?: string;\n readonly reloadToken: string;\n readonly createdAt: string;\n };\n readonly chrome: {\n readonly topBar: true;\n readonly bottomBar: true;\n readonly sidePanels: false;\n };\n readonly simulation: PajaSimulation;\n}\n\nexport class PajaOptionsError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'PajaOptionsError';\n }\n}\n\nexport const DEFAULT_PAJA_HOST = '127.0.0.1';\nexport const DEFAULT_PAJA_PORT = 5197;\nexport const DEFAULT_READY_TIMEOUT_MS = 30_000;\nexport const DEFAULT_PAJA_WINDOW_ID = 'kehto-paja-window';\nexport const DEFAULT_PAJA_DTAG = 'dev-target';\nexport const DEFAULT_PAJA_AGGREGATE_HASH = 'paja';\n\nexport function normalizePajaOptions(raw: PajaRawOptions): PajaOptions {\n const targetUrl = normalizeTargetUrl(raw.targetUrl);\n const host = normalizeHost(raw.host);\n const port = normalizePort(raw.port, 'port');\n const readyTimeoutMs = normalizePositiveInteger(\n raw.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS,\n 'ready-timeout',\n );\n const command = normalizeCommand(raw.command);\n const configPath = raw.configPath?.trim();\n const simulation = normalizePajaSimulation(raw.simulation);\n\n return {\n targetUrl,\n command,\n host,\n port,\n readyTimeoutMs,\n configPath: configPath && configPath.length > 0 ? configPath : undefined,\n simulation,\n mode: command ? 'managed-command' : 'external-target',\n };\n}\n\nexport function createPajaHostConfig(\n options: PajaOptions,\n now: Date = new Date(),\n): PajaHostConfig {\n return {\n version: 1,\n window: {\n id: DEFAULT_PAJA_WINDOW_ID,\n dTag: DEFAULT_PAJA_DTAG,\n aggregateHash: DEFAULT_PAJA_AGGREGATE_HASH,\n },\n target: {\n url: options.targetUrl,\n hmrStrategy: 'iframe-target-url',\n command: options.command,\n },\n runtime: {\n host: options.host,\n port: options.port,\n readyTimeoutMs: options.readyTimeoutMs,\n configPath: options.configPath,\n reloadToken: createReloadToken(now),\n createdAt: now.toISOString(),\n },\n chrome: {\n topBar: true,\n bottomBar: true,\n sidePanels: false,\n },\n simulation: options.simulation,\n };\n}\n\nexport function formatPajaUrl(options: Pick<PajaOptions, 'host' | 'port'>): string {\n return `http://${options.host}:${options.port}/`;\n}\n\nfunction normalizeTargetUrl(value: string | undefined): string {\n const raw = value?.trim();\n if (!raw) {\n throw new PajaOptionsError('Missing --target-url. Provide the napplet app URL that the iframe should load.');\n }\n\n let parsed: URL;\n try {\n parsed = new URL(raw);\n } catch {\n throw new PajaOptionsError(`Invalid --target-url \"${raw}\". Expected an absolute http(s) URL.`);\n }\n\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n throw new PajaOptionsError(`Invalid --target-url \"${raw}\". Only http: and https: URLs are supported.`);\n }\n\n return parsed.href;\n}\n\nfunction normalizeHost(value: string | undefined): string {\n const host = value?.trim() || DEFAULT_PAJA_HOST;\n if (host.length === 0 || host.includes('/')) {\n throw new PajaOptionsError(`Invalid --host \"${value ?? ''}\". Provide a hostname or IP address.`);\n }\n return host;\n}\n\nfunction normalizePort(value: number | string | undefined, label: string): number {\n return normalizeIntegerInRange(value ?? DEFAULT_PAJA_PORT, label, 0, 65_535);\n}\n\nfunction normalizePositiveInteger(value: number | string, label: string, max = Number.MAX_SAFE_INTEGER): number {\n return normalizeIntegerInRange(value, label, 1, max);\n}\n\nfunction normalizeIntegerInRange(value: number | string, label: string, min: number, max: number): number {\n const parsed = typeof value === 'number' ? value : Number(value);\n if (!Number.isInteger(parsed) || parsed < min || parsed > max) {\n throw new PajaOptionsError(`Invalid --${label} \"${String(value)}\". Expected an integer from ${min} to ${max}.`);\n }\n return parsed;\n}\n\nfunction normalizeCommand(command: PajaCommand | undefined): PajaCommand | undefined {\n if (!command) return undefined;\n\n if (command.mode === 'argv') {\n const argv = command.argv.map((part) => part.trim()).filter((part) => part.length > 0);\n if (argv.length === 0) {\n throw new PajaOptionsError('Command mode requires at least one command argument after --.');\n }\n return { mode: 'argv', argv };\n }\n\n const shellCommand = command.command.trim();\n if (shellCommand.length === 0) {\n throw new PajaOptionsError('--command requires a non-empty command string.');\n }\n return { mode: 'shell', command: shellCommand };\n}\n\nfunction createReloadToken(now: Date): string {\n const iso = now.toISOString();\n return `reload-${iso.replaceAll(/[^0-9A-Za-z]/g, '')}`;\n}\n","import type { PajaHostConfig } from './options.js';\nimport { summarizePajaSimulation } from './simulation.js';\n\nexport function renderPajaHtml(config: PajaHostConfig): string {\n const configJson = escapeJsonForHtml(JSON.stringify(config));\n const targetUrl = escapeAttribute(config.target.url);\n\n return `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>Kehto Paja</title>\n <style>\n :root {\n color-scheme: dark;\n --bg: #101211;\n --bar: #181b19;\n --line: #30352f;\n --text: #f4f0df;\n --muted: #a9ad9f;\n --accent: #d8c36a;\n }\n * { box-sizing: border-box; }\n html, body { margin: 0; min-height: 100%; background: var(--bg); color: var(--text); font: 13px/1.4 ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; }\n body { height: 100vh; display: grid; grid-template-rows: 38px minmax(0, 1fr) 30px; overflow: hidden; }\n .bar { display: flex; align-items: center; gap: 14px; min-width: 0; padding: 0 12px; background: var(--bar); border-color: var(--line); }\n .top { border-bottom: 1px solid var(--line); }\n .bottom { border-top: 1px solid var(--line); color: var(--muted); font-size: 12px; }\n .brand { font-weight: 700; letter-spacing: 0; color: var(--accent); white-space: nowrap; }\n .target { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); }\n .spacer { flex: 1; min-width: 0; }\n button { border: 1px solid var(--line); color: var(--text); background: #20241f; height: 26px; padding: 0 10px; border-radius: 4px; font: inherit; cursor: pointer; }\n button:hover { border-color: var(--accent); }\n label { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); white-space: nowrap; }\n select { border: 1px solid var(--line); color: var(--text); background: #20241f; height: 26px; border-radius: 4px; font: inherit; }\n iframe { width: 100%; height: 100%; border: 0; background: white; display: block; }\n code { color: var(--text); }\n </style>\n </head>\n <body>\n <header class=\"bar top\">\n <div class=\"brand\">Kehto</div>\n <div class=\"target\" title=\"${targetUrl}\">${targetUrl}</div>\n <div class=\"spacer\"></div>\n <label>theme\n <select id=\"simulation-theme\" aria-label=\"Simulation theme\">\n <option value=\"dark\"${config.simulation.theme.mode === 'dark' ? ' selected' : ''}>dark</option>\n <option value=\"light\"${config.simulation.theme.mode === 'light' ? ' selected' : ''}>light</option>\n </select>\n </label>\n <button type=\"button\" id=\"reload-target\">Reload</button>\n </header>\n <main>\n <iframe id=\"napplet-frame\" title=\"Napplet development target\" sandbox=\"allow-scripts\" data-target-url=\"${targetUrl}\"></iframe>\n </main>\n <footer class=\"bar bottom\">\n <span>mode: <code>${config.target.command ? 'managed-command' : 'external-target'}</code></span>\n <span>hmr: <code>${config.target.hmrStrategy}</code></span>\n <span>runtime: <code>${escapeHtml(config.runtime.host)}:${config.runtime.port}</code></span>\n <span>sim: <code id=\"simulation-status\">${escapeHtml(summarizePajaSimulation(config.simulation))}</code></span>\n <span>state: <code id=\"lifecycle-status\">booting</code></span>\n </footer>\n <script type=\"application/json\" id=\"kehto-paja-config\">${configJson}</script>\n <script type=\"module\" src=\"/__kehto/browser-host.js\"></script>\n </body>\n</html>`;\n}\n\nfunction escapeAttribute(value: string): string {\n return escapeHtml(value).replaceAll('\"', '"');\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replaceAll('&', '&')\n .replaceAll('<', '<')\n .replaceAll('>', '>');\n}\n\nfunction escapeJsonForHtml(value: string): string {\n return value.replaceAll('<', '\\\\u003c');\n}\n","import type { ShellCapabilities } from '@kehto/shell';\n\nconst PAJA_LEGACY_COMPATIBILITY_DOMAIN = `i${'fc'}`;\n\nexport const PAJA_UPSTREAM_WEB_DOMAINS = [\n 'ble',\n 'common',\n 'config',\n 'cvm',\n 'identity',\n PAJA_LEGACY_COMPATIBILITY_DOMAIN,\n 'inc',\n 'intent',\n 'keys',\n 'link',\n 'lists',\n 'media',\n 'notify',\n 'outbox',\n 'relay',\n 'resource',\n 'serial',\n 'shell',\n 'storage',\n 'theme',\n 'upload',\n 'webrtc',\n] as const;\n\nexport const PAJA_HANDSHAKE_DOMAINS = ['shell'] as const;\nexport const PAJA_DEFERRED_DOMAINS = [] as const;\n\nexport const PAJA_COMPATIBILITY_ALIASES = {\n [PAJA_LEGACY_COMPATIBILITY_DOMAIN]: 'inc',\n} as const;\n\nexport const PAJA_ADVERTISED_DOMAINS = [\n 'relay',\n 'outbox',\n 'identity',\n 'storage',\n 'inc',\n 'theme',\n 'keys',\n 'link',\n 'common',\n 'lists',\n 'serial',\n 'ble',\n 'webrtc',\n 'media',\n 'notify',\n 'config',\n 'resource',\n 'cvm',\n 'upload',\n 'intent',\n] as const;\n\nexport const PAJA_REQUIRED_SERVICES = [\n 'config',\n 'cvm',\n 'identity',\n 'intent',\n 'keys',\n 'link',\n 'common',\n 'lists',\n 'serial',\n 'ble',\n 'webrtc',\n 'media',\n 'notifications',\n 'notify',\n 'outbox',\n 'relay',\n 'resource',\n 'theme',\n 'upload',\n] as const;\n\nexport function getMissingAdvertisedDomains(capabilities: ShellCapabilities): string[] {\n const advertised = new Set(capabilities.domains);\n return PAJA_ADVERTISED_DOMAINS.filter((domain) => !advertised.has(domain));\n}\n\nexport function getMissingServices(services: readonly string[]): string[] {\n const wired = new Set(services);\n return PAJA_REQUIRED_SERVICES.filter((service) => !wired.has(service));\n}\n","export interface WaitForTargetUrlOptions {\n readonly timeoutMs: number;\n readonly intervalMs?: number;\n readonly fetch?: ReadinessFetch;\n readonly sleep?: (ms: number) => Promise<void>;\n readonly now?: () => number;\n}\n\nexport type ReadinessFetch = (url: string) => Promise<{ readonly status: number }>;\n\nexport class ReadinessError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ReadinessError';\n }\n}\n\nexport async function waitForTargetUrl(url: string, options: WaitForTargetUrlOptions): Promise<void> {\n const intervalMs = options.intervalMs ?? 250;\n const fetcher = options.fetch ?? defaultFetch;\n const sleep = options.sleep ?? defaultSleep;\n const now = options.now ?? Date.now;\n const deadline = now() + options.timeoutMs;\n let lastError = 'no response';\n\n while (now() <= deadline) {\n try {\n const response = await fetcher(url);\n if (response.status < 500) {\n return;\n }\n lastError = `status ${response.status}`;\n } catch (error) {\n lastError = error instanceof Error ? error.message : String(error);\n }\n\n await sleep(intervalMs);\n }\n\n throw new ReadinessError(`Timed out waiting ${options.timeoutMs}ms for target URL ${url}: ${lastError}`);\n}\n\nasync function defaultFetch(url: string): Promise<{ readonly status: number }> {\n return fetch(url, { method: 'GET', redirect: 'follow' });\n}\n\nfunction defaultSleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n","import { createServer } from 'node:http';\nimport { readFileSync } from 'node:fs';\nimport {\n createPajaHostConfig,\n formatPajaUrl,\n normalizePajaOptions,\n type PajaHostConfig,\n type PajaOptions,\n type PajaRawOptions,\n} from './options.js';\nimport { renderPajaHtml } from './host-page.js';\nimport { resolvePajaRawOptions } from './config-file.js';\n\nexport interface PajaServerOptions {\n readonly options: PajaRawOptions;\n readonly now?: Date;\n}\n\nexport interface PajaServer {\n readonly url: string;\n readonly hostConfig: PajaHostConfig;\n close(): Promise<void>;\n}\n\nexport async function startPajaServer(input: PajaServerOptions): Promise<PajaServer> {\n const rawOptions = resolvePajaRawOptions(input.options);\n const options = normalizePajaOptions(rawOptions);\n let hostConfig = createPajaHostConfig(options, input.now);\n let html = renderPajaHtml(hostConfig);\n let configJson = JSON.stringify(hostConfig, null, 2);\n\n const server = createServer((request, response) => {\n const requestUrl = request.url ?? '/';\n\n if (requestUrl === '/' || requestUrl.startsWith('/?')) {\n response.writeHead(200, { 'content-type': 'text/html; charset=utf-8' });\n response.end(html);\n return;\n }\n\n if (requestUrl === '/__kehto/config.json') {\n response.writeHead(200, { 'content-type': 'application/json; charset=utf-8' });\n response.end(configJson);\n return;\n }\n\n if (requestUrl === '/__kehto/browser-host.js') {\n const browserScript = readBrowserHostScript();\n response.writeHead(200, { 'content-type': 'text/javascript; charset=utf-8' });\n response.end(browserScript);\n return;\n }\n\n response.writeHead(404, { 'content-type': 'text/plain; charset=utf-8' });\n response.end('Not found');\n });\n\n await listen(server, options.host, options.port);\n const servedOptions = withBoundPort(options, getBoundPort(server, options.port));\n hostConfig = createPajaHostConfig(servedOptions, input.now);\n html = renderPajaHtml(hostConfig);\n configJson = JSON.stringify(hostConfig, null, 2);\n\n return {\n url: formatPajaUrl(servedOptions),\n hostConfig,\n close: () => close(server),\n };\n}\n\nfunction readBrowserHostScript(): string {\n return readFileSync(new URL('./browser-host.js', import.meta.url), 'utf8');\n}\n\nfunction listen(server: HttpServer, host: string, port: number): Promise<void> {\n return new Promise((resolve, reject) => {\n server.once('error', reject);\n server.listen(port, host, () => {\n server.off('error', reject);\n resolve();\n });\n });\n}\n\nfunction close(server: HttpServer): Promise<void> {\n return new Promise((resolve, reject) => {\n server.close((error?: Error) => {\n if (error) {\n reject(error);\n return;\n }\n resolve();\n });\n });\n}\n\ninterface HttpServer {\n listen(port: number, host: string, callback: () => void): void;\n once(event: 'error', callback: (error: Error) => void): void;\n off(event: 'error', callback: (error: Error) => void): void;\n close(callback: (error?: Error) => void): void;\n address(): string | { port: number } | null;\n}\n\nfunction getBoundPort(server: HttpServer, fallback: number): number {\n const address = server.address();\n return typeof address === 'object' && address !== null ? address.port : fallback;\n}\n\nfunction withBoundPort(options: PajaOptions, port: number): PajaOptions {\n return port === options.port ? options : { ...options, port };\n}\n"],"mappings":"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","names":["resolve","readFileSync","readFileSync","resolve"]}
|
|
1
|
+
{"version":3,"sources":["../src/config-file.ts","../src/simulation.ts","../src/options.ts","../src/host-page.ts","../src/parity.ts","../src/readiness.ts","../src/server.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport type { PajaRawOptions } from './options.js';\nimport type { PajaSimulationRawOptions } from './simulation.js';\nimport { PajaSimulationError } from './simulation.js';\n\nexport function loadPajaConfigFile(configPath: string): PajaRawOptions {\n const resolved = resolve(configPath);\n let parsed: unknown;\n try {\n parsed = JSON.parse(readFileSync(resolved, 'utf8'));\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error);\n throw new PajaSimulationError(`Unable to read --config \"${configPath}\": ${detail}`);\n }\n\n if (!isRecord(parsed)) {\n throw new PajaSimulationError(`Invalid --config \"${configPath}\": expected a JSON object.`);\n }\n\n return parsed as PajaRawOptions;\n}\n\nexport function resolvePajaRawOptions(raw: PajaRawOptions): PajaRawOptions {\n if (!raw.configPath?.trim()) return raw;\n return mergePajaRawOptions(loadPajaConfigFile(raw.configPath), raw);\n}\n\nexport function mergePajaRawOptions(\n base: PajaRawOptions,\n override: PajaRawOptions,\n): PajaRawOptions {\n return {\n targetUrl: override.targetUrl ?? base.targetUrl,\n command: override.command ?? base.command,\n host: override.host ?? base.host,\n port: override.port ?? base.port,\n readyTimeoutMs: override.readyTimeoutMs ?? base.readyTimeoutMs,\n configPath: override.configPath ?? base.configPath,\n simulation: mergeSimulationOptions(base.simulation, override.simulation),\n };\n}\n\nfunction mergeSimulationOptions(\n base: PajaSimulationRawOptions | undefined,\n override: PajaSimulationRawOptions | undefined,\n): PajaSimulationRawOptions | undefined {\n if (!base) return override;\n if (!override) return base;\n\n return {\n capabilities: {\n ...base.capabilities,\n ...override.capabilities,\n domains: {\n ...base.capabilities?.domains,\n ...override.capabilities?.domains,\n },\n },\n acl: { ...base.acl, ...override.acl },\n firewall: { ...base.firewall, ...override.firewall },\n identity: { ...base.identity, ...override.identity },\n relay: { ...base.relay, ...override.relay },\n storage: { ...base.storage, ...override.storage },\n cache: { ...base.cache, ...override.cache },\n upload: { ...base.upload, ...override.upload },\n media: { ...base.media, ...override.media },\n notifications: { ...base.notifications, ...override.notifications },\n config: {\n ...base.config,\n ...override.config,\n values: { ...base.config?.values, ...override.config?.values },\n },\n theme: {\n ...base.theme,\n ...override.theme,\n values: { ...base.theme?.values, ...override.theme?.values },\n },\n intent: { ...base.intent, ...override.intent },\n cvm: { ...base.cvm, ...override.cvm },\n };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","export type JsonPrimitive = string | number | boolean | null;\nexport type JsonValue = JsonPrimitive | JsonValue[] | { readonly [key: string]: JsonValue };\nexport type JsonRecord = Record<string, JsonValue>;\n\nexport type PajaCapabilityDomain =\n | 'relay'\n | 'outbox'\n | 'storage'\n | 'identity'\n | 'keys'\n | 'config'\n | 'resource'\n | 'theme'\n | 'notify'\n | 'media'\n | 'upload'\n | 'intent'\n | 'link'\n | 'common'\n | 'lists'\n | 'serial'\n | 'ble'\n | 'webrtc'\n | 'cvm'\n | 'inc';\n\nexport interface PajaSimulationRawOptions {\n readonly capabilities?: {\n readonly domains?: Partial<Record<PajaCapabilityDomain, boolean>>;\n };\n readonly acl?: {\n readonly mode?: 'allow' | 'deny';\n };\n readonly firewall?: {\n readonly mode?: 'allow' | 'deny' | 'observe';\n };\n readonly identity?: {\n readonly mode?: 'anonymous' | 'fixed';\n readonly pubkey?: string;\n };\n readonly relay?: {\n readonly mode?: 'memory' | 'disabled';\n readonly urls?: readonly string[];\n readonly fixtures?: readonly JsonRecord[];\n };\n readonly storage?: {\n readonly mode?: 'local' | 'memory' | 'disabled';\n };\n readonly cache?: {\n readonly mode?: 'memory' | 'disabled';\n };\n readonly upload?: {\n readonly mode?: 'memory' | 'disabled';\n readonly rail?: string;\n };\n readonly media?: {\n readonly enabled?: boolean;\n };\n readonly notifications?: {\n readonly enabled?: boolean;\n readonly grant?: boolean;\n };\n readonly config?: {\n readonly values?: JsonRecord;\n };\n readonly theme?: {\n readonly mode?: 'dark' | 'light';\n readonly values?: JsonRecord;\n };\n readonly intent?: {\n readonly enabled?: boolean;\n };\n readonly cvm?: {\n readonly enabled?: boolean;\n };\n}\n\nexport interface PajaSimulation {\n readonly capabilities: {\n readonly domains: Record<PajaCapabilityDomain, boolean>;\n readonly disabledDomains: readonly PajaCapabilityDomain[];\n };\n readonly acl: {\n readonly mode: 'allow' | 'deny';\n };\n readonly firewall: {\n readonly mode: 'allow' | 'deny' | 'observe';\n };\n readonly identity: {\n readonly mode: 'anonymous' | 'fixed';\n readonly pubkey: string;\n };\n readonly relay: {\n readonly mode: 'memory' | 'disabled';\n readonly urls: readonly string[];\n readonly fixtures: readonly JsonRecord[];\n };\n readonly storage: {\n readonly mode: 'local' | 'memory' | 'disabled';\n };\n readonly cache: {\n readonly mode: 'memory' | 'disabled';\n };\n readonly upload: {\n readonly mode: 'memory' | 'disabled';\n readonly rail: string;\n };\n readonly media: {\n readonly enabled: boolean;\n };\n readonly notifications: {\n readonly enabled: boolean;\n readonly grant: boolean;\n };\n readonly config: {\n readonly values: JsonRecord;\n };\n readonly theme: {\n readonly mode: 'dark' | 'light';\n readonly values: JsonRecord;\n };\n readonly intent: {\n readonly enabled: boolean;\n };\n readonly cvm: {\n readonly enabled: boolean;\n };\n}\n\nexport class PajaSimulationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'PajaSimulationError';\n }\n}\n\nexport const PAJA_SIMULATION_DOMAINS: readonly PajaCapabilityDomain[] = [\n 'relay',\n 'outbox',\n 'storage',\n 'identity',\n 'keys',\n 'config',\n 'resource',\n 'theme',\n 'notify',\n 'media',\n 'upload',\n 'intent',\n 'link',\n 'common',\n 'lists',\n 'serial',\n 'ble',\n 'webrtc',\n 'cvm',\n 'inc',\n];\n\nconst DEFAULT_RELAY_URLS = ['wss://relay.kehto.dev'] as const;\nconst DEFAULT_CONFIG_VALUES: JsonRecord = {\n runtime: 'kehto paja',\n mode: 'development',\n target: 'single-window',\n};\n\nconst DEFAULT_THEME_VALUES: JsonRecord = {\n title: 'Kehto Paja',\n};\n\nexport function normalizePajaSimulation(\n raw: PajaSimulationRawOptions | undefined,\n): PajaSimulation {\n const domainOverrides = raw?.capabilities?.domains ?? {};\n const domains = Object.fromEntries(\n PAJA_SIMULATION_DOMAINS.map((domain) => [domain, domainOverrides[domain] ?? true]),\n ) as Record<PajaCapabilityDomain, boolean>;\n\n const relayMode = raw?.relay?.mode ?? (domains.relay ? 'memory' : 'disabled');\n if (!domains.relay && relayMode !== 'disabled') {\n throw new PajaSimulationError('Invalid simulation: relay.mode must be \"disabled\" when capabilities.domains.relay is false.');\n }\n if (!domains.outbox && relayMode !== 'disabled') {\n throw new PajaSimulationError('Invalid simulation: relay.mode must be \"disabled\" when capabilities.domains.outbox is false.');\n }\n if (relayMode === 'disabled') {\n domains.relay = false;\n domains.outbox = false;\n }\n\n const uploadMode = raw?.upload?.mode ?? (domains.upload ? 'memory' : 'disabled');\n if (!domains.upload && uploadMode !== 'disabled') {\n throw new PajaSimulationError('Invalid simulation: upload.mode must be \"disabled\" when capabilities.domains.upload is false.');\n }\n if (uploadMode === 'disabled') domains.upload = false;\n\n const intentEnabled = raw?.intent?.enabled ?? domains.intent;\n if (!domains.intent && intentEnabled) {\n throw new PajaSimulationError('Invalid simulation: intent.enabled must be false when capabilities.domains.intent is false.');\n }\n if (!intentEnabled) domains.intent = false;\n\n const mediaEnabled = raw?.media?.enabled ?? domains.media;\n if (!domains.media && mediaEnabled) {\n throw new PajaSimulationError('Invalid simulation: media.enabled must be false when capabilities.domains.media is false.');\n }\n if (!mediaEnabled) domains.media = false;\n\n const cvmEnabled = raw?.cvm?.enabled ?? domains.cvm;\n if (!domains.cvm && cvmEnabled) {\n throw new PajaSimulationError('Invalid simulation: cvm.enabled must be false when capabilities.domains.cvm is false.');\n }\n if (!cvmEnabled) domains.cvm = false;\n\n const notificationsEnabled = raw?.notifications?.enabled ?? domains.notify;\n if (!domains.notify && notificationsEnabled) {\n throw new PajaSimulationError('Invalid simulation: notifications.enabled must be false when capabilities.domains.notify is false.');\n }\n if (!notificationsEnabled) domains.notify = false;\n\n const storageMode = raw?.storage?.mode ?? (domains.storage ? 'local' : 'disabled');\n if (!domains.storage && storageMode !== 'disabled') {\n throw new PajaSimulationError('Invalid simulation: storage.mode must be \"disabled\" when capabilities.domains.storage is false.');\n }\n if (storageMode === 'disabled') domains.storage = false;\n\n const identityMode = raw?.identity?.mode ?? 'anonymous';\n const pubkey = raw?.identity?.pubkey?.trim() ?? '';\n if (identityMode === 'fixed' && !isHexPubkey(pubkey)) {\n throw new PajaSimulationError('Invalid simulation: identity.pubkey must be a 64-character hex string when identity.mode is \"fixed\".');\n }\n\n const relayUrls = raw?.relay?.urls ?? DEFAULT_RELAY_URLS;\n if (relayMode === 'memory' && relayUrls.length === 0) {\n throw new PajaSimulationError('Invalid simulation: relay.urls must contain at least one URL when relay.mode is \"memory\".');\n }\n for (const url of relayUrls) {\n if (typeof url !== 'string' || url.trim().length === 0) {\n throw new PajaSimulationError('Invalid simulation: relay.urls entries must be non-empty strings.');\n }\n }\n\n const uploadRail = raw?.upload?.rail?.trim() || 'dev-memory';\n if (uploadMode === 'memory' && uploadRail.length === 0) {\n throw new PajaSimulationError('Invalid simulation: upload.rail must be non-empty when upload.mode is \"memory\".');\n }\n\n return {\n capabilities: {\n domains,\n disabledDomains: PAJA_SIMULATION_DOMAINS.filter((domain) => !domains[domain]),\n },\n acl: {\n mode: raw?.acl?.mode ?? 'allow',\n },\n firewall: {\n mode: raw?.firewall?.mode ?? 'observe',\n },\n identity: {\n mode: identityMode,\n pubkey: identityMode === 'fixed' ? pubkey : '',\n },\n relay: {\n mode: relayMode,\n urls: relayUrls.map((url) => url.trim()),\n fixtures: raw?.relay?.fixtures ?? [],\n },\n storage: {\n mode: storageMode,\n },\n cache: {\n mode: raw?.cache?.mode ?? 'memory',\n },\n upload: {\n mode: uploadMode,\n rail: uploadRail,\n },\n media: {\n enabled: mediaEnabled,\n },\n notifications: {\n enabled: notificationsEnabled,\n grant: raw?.notifications?.grant ?? true,\n },\n config: {\n values: { ...DEFAULT_CONFIG_VALUES, ...raw?.config?.values },\n },\n theme: {\n mode: raw?.theme?.mode ?? 'dark',\n values: { ...DEFAULT_THEME_VALUES, ...raw?.theme?.values },\n },\n intent: {\n enabled: intentEnabled,\n },\n cvm: {\n enabled: cvmEnabled,\n },\n };\n}\n\nexport function summarizePajaSimulation(simulation: PajaSimulation): string {\n const relay = simulation.relay.mode === 'memory' ? `relay:${simulation.relay.urls.length}` : 'relay:off';\n const identity = simulation.identity.mode === 'fixed' ? 'identity:fixed' : 'identity:anon';\n const storage = `storage:${simulation.storage.mode}`;\n const theme = `theme:${simulation.theme.mode}`;\n const disabled = simulation.capabilities.disabledDomains.length > 0\n ? `off:${simulation.capabilities.disabledDomains.join(',')}`\n : 'off:none';\n return `${identity} ${relay} ${storage} ${theme} ${disabled}`;\n}\n\nfunction isHexPubkey(value: string): boolean {\n return /^[0-9a-fA-F]{64}$/.test(value);\n}\n","import {\n normalizePajaSimulation,\n type PajaSimulation,\n type PajaSimulationRawOptions,\n} from './simulation.js';\n\nexport type PajaCommand =\n | { readonly mode: 'argv'; readonly argv: readonly string[] }\n | { readonly mode: 'shell'; readonly command: string };\n\nexport interface PajaRawOptions {\n readonly targetUrl?: string;\n readonly command?: PajaCommand;\n readonly host?: string;\n readonly port?: number | string;\n readonly readyTimeoutMs?: number | string;\n readonly configPath?: string;\n readonly simulation?: PajaSimulationRawOptions;\n}\n\nexport interface PajaOptions {\n readonly targetUrl: string;\n readonly command?: PajaCommand;\n readonly host: string;\n readonly port: number;\n readonly readyTimeoutMs: number;\n readonly configPath?: string;\n readonly simulation: PajaSimulation;\n readonly mode: 'external-target' | 'managed-command';\n}\n\nexport interface PajaHostConfig {\n readonly version: 1;\n readonly window: {\n readonly id: string;\n readonly dTag: string;\n readonly aggregateHash: string;\n };\n readonly target: {\n readonly url: string;\n readonly hmrStrategy: 'iframe-target-url';\n readonly command?: PajaCommand;\n };\n readonly runtime: {\n readonly host: string;\n readonly port: number;\n readonly readyTimeoutMs: number;\n readonly configPath?: string;\n readonly reloadToken: string;\n readonly createdAt: string;\n };\n readonly chrome: {\n readonly topBar: true;\n readonly bottomBar: true;\n readonly sidePanels: false;\n };\n readonly simulation: PajaSimulation;\n}\n\nexport class PajaOptionsError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'PajaOptionsError';\n }\n}\n\nexport const DEFAULT_PAJA_HOST = '127.0.0.1';\nexport const DEFAULT_PAJA_PORT = 5197;\nexport const DEFAULT_READY_TIMEOUT_MS = 30_000;\nexport const DEFAULT_PAJA_WINDOW_ID = 'kehto-paja-window';\nexport const DEFAULT_PAJA_DTAG = 'dev-target';\nexport const DEFAULT_PAJA_AGGREGATE_HASH = 'paja';\n\nexport function normalizePajaOptions(raw: PajaRawOptions): PajaOptions {\n const targetUrl = normalizeTargetUrl(raw.targetUrl);\n const host = normalizeHost(raw.host);\n const port = normalizePort(raw.port, 'port');\n const readyTimeoutMs = normalizePositiveInteger(\n raw.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS,\n 'ready-timeout',\n );\n const command = normalizeCommand(raw.command);\n const configPath = raw.configPath?.trim();\n const simulation = normalizePajaSimulation(raw.simulation);\n\n return {\n targetUrl,\n command,\n host,\n port,\n readyTimeoutMs,\n configPath: configPath && configPath.length > 0 ? configPath : undefined,\n simulation,\n mode: command ? 'managed-command' : 'external-target',\n };\n}\n\nexport function createPajaHostConfig(\n options: PajaOptions,\n now: Date = new Date(),\n): PajaHostConfig {\n return {\n version: 1,\n window: {\n id: DEFAULT_PAJA_WINDOW_ID,\n dTag: DEFAULT_PAJA_DTAG,\n aggregateHash: DEFAULT_PAJA_AGGREGATE_HASH,\n },\n target: {\n url: options.targetUrl,\n hmrStrategy: 'iframe-target-url',\n command: options.command,\n },\n runtime: {\n host: options.host,\n port: options.port,\n readyTimeoutMs: options.readyTimeoutMs,\n configPath: options.configPath,\n reloadToken: createReloadToken(now),\n createdAt: now.toISOString(),\n },\n chrome: {\n topBar: true,\n bottomBar: true,\n sidePanels: false,\n },\n simulation: options.simulation,\n };\n}\n\nexport function formatPajaUrl(options: Pick<PajaOptions, 'host' | 'port'>): string {\n return `http://${options.host}:${options.port}/`;\n}\n\nfunction normalizeTargetUrl(value: string | undefined): string {\n const raw = value?.trim();\n if (!raw) {\n throw new PajaOptionsError('Missing --target-url. Provide the napplet app URL that the iframe should load.');\n }\n\n let parsed: URL;\n try {\n parsed = new URL(raw);\n } catch {\n throw new PajaOptionsError(`Invalid --target-url \"${raw}\". Expected an absolute http(s) URL.`);\n }\n\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n throw new PajaOptionsError(`Invalid --target-url \"${raw}\". Only http: and https: URLs are supported.`);\n }\n\n return parsed.href;\n}\n\nfunction normalizeHost(value: string | undefined): string {\n const host = value?.trim() || DEFAULT_PAJA_HOST;\n if (host.length === 0 || host.includes('/')) {\n throw new PajaOptionsError(`Invalid --host \"${value ?? ''}\". Provide a hostname or IP address.`);\n }\n return host;\n}\n\nfunction normalizePort(value: number | string | undefined, label: string): number {\n return normalizeIntegerInRange(value ?? DEFAULT_PAJA_PORT, label, 0, 65_535);\n}\n\nfunction normalizePositiveInteger(value: number | string, label: string, max = Number.MAX_SAFE_INTEGER): number {\n return normalizeIntegerInRange(value, label, 1, max);\n}\n\nfunction normalizeIntegerInRange(value: number | string, label: string, min: number, max: number): number {\n const parsed = typeof value === 'number' ? value : Number(value);\n if (!Number.isInteger(parsed) || parsed < min || parsed > max) {\n throw new PajaOptionsError(`Invalid --${label} \"${String(value)}\". Expected an integer from ${min} to ${max}.`);\n }\n return parsed;\n}\n\nfunction normalizeCommand(command: PajaCommand | undefined): PajaCommand | undefined {\n if (!command) return undefined;\n\n if (command.mode === 'argv') {\n const argv = command.argv.map((part) => part.trim()).filter((part) => part.length > 0);\n if (argv.length === 0) {\n throw new PajaOptionsError('Command mode requires at least one command argument after --.');\n }\n return { mode: 'argv', argv };\n }\n\n const shellCommand = command.command.trim();\n if (shellCommand.length === 0) {\n throw new PajaOptionsError('--command requires a non-empty command string.');\n }\n return { mode: 'shell', command: shellCommand };\n}\n\nfunction createReloadToken(now: Date): string {\n const iso = now.toISOString();\n return `reload-${iso.replaceAll(/[^0-9A-Za-z]/g, '')}`;\n}\n","import type { PajaHostConfig } from './options.js';\nimport { summarizePajaSimulation } from './simulation.js';\n\nexport function renderPajaHtml(config: PajaHostConfig): string {\n const configJson = escapeJsonForHtml(JSON.stringify(config));\n const targetUrl = escapeAttribute(config.target.url);\n\n return `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>Kehto Paja</title>\n <style>\n :root {\n color-scheme: dark;\n --bg: #101211;\n --bar: #181b19;\n --line: #30352f;\n --text: #f4f0df;\n --muted: #a9ad9f;\n --accent: #d8c36a;\n }\n * { box-sizing: border-box; }\n html, body { margin: 0; min-height: 100%; background: var(--bg); color: var(--text); font: 13px/1.4 ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; }\n body { height: 100vh; display: grid; grid-template-rows: 38px minmax(0, 1fr) 30px; overflow: hidden; }\n .bar { display: flex; align-items: center; gap: 14px; min-width: 0; padding: 0 12px; background: var(--bar); border-color: var(--line); }\n .top { border-bottom: 1px solid var(--line); }\n .bottom { border-top: 1px solid var(--line); color: var(--muted); font-size: 12px; }\n .brand { font-weight: 700; letter-spacing: 0; color: var(--accent); white-space: nowrap; }\n .target { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); }\n .spacer { flex: 1; min-width: 0; }\n button { border: 1px solid var(--line); color: var(--text); background: #20241f; height: 26px; padding: 0 10px; border-radius: 4px; font: inherit; cursor: pointer; }\n button:hover { border-color: var(--accent); }\n label { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); white-space: nowrap; }\n select { border: 1px solid var(--line); color: var(--text); background: #20241f; height: 26px; border-radius: 4px; font: inherit; }\n iframe { width: 100%; height: 100%; border: 0; background: white; display: block; }\n code { color: var(--text); }\n </style>\n </head>\n <body>\n <header class=\"bar top\">\n <div class=\"brand\">Kehto</div>\n <div class=\"target\" title=\"${targetUrl}\">${targetUrl}</div>\n <div class=\"spacer\"></div>\n <label>theme\n <select id=\"simulation-theme\" aria-label=\"Simulation theme\">\n <option value=\"dark\"${config.simulation.theme.mode === 'dark' ? ' selected' : ''}>dark</option>\n <option value=\"light\"${config.simulation.theme.mode === 'light' ? ' selected' : ''}>light</option>\n </select>\n </label>\n <button type=\"button\" id=\"reload-target\">Reload</button>\n </header>\n <main>\n <iframe id=\"napplet-frame\" title=\"Napplet development target\" sandbox=\"allow-scripts\" data-target-url=\"${targetUrl}\"></iframe>\n </main>\n <footer class=\"bar bottom\">\n <span>mode: <code>${config.target.command ? 'managed-command' : 'external-target'}</code></span>\n <span>hmr: <code>${config.target.hmrStrategy}</code></span>\n <span>runtime: <code>${escapeHtml(config.runtime.host)}:${config.runtime.port}</code></span>\n <span>sim: <code id=\"simulation-status\">${escapeHtml(summarizePajaSimulation(config.simulation))}</code></span>\n <span>state: <code id=\"lifecycle-status\">booting</code></span>\n </footer>\n <script type=\"application/json\" id=\"kehto-paja-config\">${configJson}</script>\n <script type=\"module\" src=\"/__kehto/browser-host.js\"></script>\n </body>\n</html>`;\n}\n\nfunction escapeAttribute(value: string): string {\n return escapeHtml(value).replaceAll('\"', '"');\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replaceAll('&', '&')\n .replaceAll('<', '<')\n .replaceAll('>', '>');\n}\n\nfunction escapeJsonForHtml(value: string): string {\n return value.replaceAll('<', '\\\\u003c');\n}\n","import type { ShellCapabilities } from '@kehto/shell';\n\nconst PAJA_LEGACY_COMPATIBILITY_DOMAIN = `i${'fc'}`;\n\nexport const PAJA_UPSTREAM_WEB_DOMAINS = [\n 'ble',\n 'common',\n 'config',\n 'cvm',\n 'dm',\n 'identity',\n PAJA_LEGACY_COMPATIBILITY_DOMAIN,\n 'inc',\n 'intent',\n 'keys',\n 'link',\n 'lists',\n 'media',\n 'notify',\n 'outbox',\n 'relay',\n 'resource',\n 'serial',\n 'storage',\n 'theme',\n 'upload',\n 'webrtc',\n] as const;\n\nexport const PAJA_HANDSHAKE_DOMAINS = ['shell'] as const;\nexport const PAJA_DEFERRED_DOMAINS = ['dm'] as const;\n\nexport const PAJA_COMPATIBILITY_ALIASES = {\n [PAJA_LEGACY_COMPATIBILITY_DOMAIN]: 'inc',\n} as const;\n\nexport const PAJA_ADVERTISED_DOMAINS = [\n 'relay',\n 'outbox',\n 'identity',\n 'storage',\n 'inc',\n 'theme',\n 'keys',\n 'link',\n 'common',\n 'lists',\n 'serial',\n 'ble',\n 'webrtc',\n 'media',\n 'notify',\n 'config',\n 'resource',\n 'cvm',\n 'upload',\n 'intent',\n] as const;\n\nexport const PAJA_REQUIRED_SERVICES = [\n 'config',\n 'cvm',\n 'identity',\n 'intent',\n 'keys',\n 'link',\n 'common',\n 'lists',\n 'serial',\n 'ble',\n 'webrtc',\n 'media',\n 'notifications',\n 'notify',\n 'outbox',\n 'relay',\n 'resource',\n 'theme',\n 'upload',\n] as const;\n\nexport function getMissingAdvertisedDomains(capabilities: ShellCapabilities): string[] {\n const advertised = new Set(capabilities.domains);\n return PAJA_ADVERTISED_DOMAINS.filter((domain) => !advertised.has(domain));\n}\n\nexport function getMissingServices(services: readonly string[]): string[] {\n const wired = new Set(services);\n return PAJA_REQUIRED_SERVICES.filter((service) => !wired.has(service));\n}\n","export interface WaitForTargetUrlOptions {\n readonly timeoutMs: number;\n readonly intervalMs?: number;\n readonly fetch?: ReadinessFetch;\n readonly sleep?: (ms: number) => Promise<void>;\n readonly now?: () => number;\n}\n\nexport type ReadinessFetch = (url: string) => Promise<{ readonly status: number }>;\n\nexport class ReadinessError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ReadinessError';\n }\n}\n\nexport async function waitForTargetUrl(url: string, options: WaitForTargetUrlOptions): Promise<void> {\n const intervalMs = options.intervalMs ?? 250;\n const fetcher = options.fetch ?? defaultFetch;\n const sleep = options.sleep ?? defaultSleep;\n const now = options.now ?? Date.now;\n const deadline = now() + options.timeoutMs;\n let lastError = 'no response';\n\n while (now() <= deadline) {\n try {\n const response = await fetcher(url);\n if (response.status < 500) {\n return;\n }\n lastError = `status ${response.status}`;\n } catch (error) {\n lastError = error instanceof Error ? error.message : String(error);\n }\n\n await sleep(intervalMs);\n }\n\n throw new ReadinessError(`Timed out waiting ${options.timeoutMs}ms for target URL ${url}: ${lastError}`);\n}\n\nasync function defaultFetch(url: string): Promise<{ readonly status: number }> {\n return fetch(url, { method: 'GET', redirect: 'follow' });\n}\n\nfunction defaultSleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n","import { createServer } from 'node:http';\nimport { readFileSync } from 'node:fs';\nimport {\n createPajaHostConfig,\n formatPajaUrl,\n normalizePajaOptions,\n type PajaHostConfig,\n type PajaOptions,\n type PajaRawOptions,\n} from './options.js';\nimport { renderPajaHtml } from './host-page.js';\nimport { resolvePajaRawOptions } from './config-file.js';\n\nexport interface PajaServerOptions {\n readonly options: PajaRawOptions;\n readonly now?: Date;\n}\n\nexport interface PajaServer {\n readonly url: string;\n readonly hostConfig: PajaHostConfig;\n close(): Promise<void>;\n}\n\nexport async function startPajaServer(input: PajaServerOptions): Promise<PajaServer> {\n const rawOptions = resolvePajaRawOptions(input.options);\n const options = normalizePajaOptions(rawOptions);\n let hostConfig = createPajaHostConfig(options, input.now);\n let html = renderPajaHtml(hostConfig);\n let configJson = JSON.stringify(hostConfig, null, 2);\n\n const server = createServer((request, response) => {\n const requestUrl = request.url ?? '/';\n\n if (requestUrl === '/' || requestUrl.startsWith('/?')) {\n response.writeHead(200, { 'content-type': 'text/html; charset=utf-8' });\n response.end(html);\n return;\n }\n\n if (requestUrl === '/__kehto/config.json') {\n response.writeHead(200, { 'content-type': 'application/json; charset=utf-8' });\n response.end(configJson);\n return;\n }\n\n if (requestUrl === '/__kehto/browser-host.js') {\n const browserScript = readBrowserHostScript();\n response.writeHead(200, { 'content-type': 'text/javascript; charset=utf-8' });\n response.end(browserScript);\n return;\n }\n\n response.writeHead(404, { 'content-type': 'text/plain; charset=utf-8' });\n response.end('Not found');\n });\n\n await listen(server, options.host, options.port);\n const servedOptions = withBoundPort(options, getBoundPort(server, options.port));\n hostConfig = createPajaHostConfig(servedOptions, input.now);\n html = renderPajaHtml(hostConfig);\n configJson = JSON.stringify(hostConfig, null, 2);\n\n return {\n url: formatPajaUrl(servedOptions),\n hostConfig,\n close: () => close(server),\n };\n}\n\nfunction readBrowserHostScript(): string {\n return readFileSync(new URL('./browser-host.js', import.meta.url), 'utf8');\n}\n\nfunction listen(server: HttpServer, host: string, port: number): Promise<void> {\n return new Promise((resolve, reject) => {\n server.once('error', reject);\n server.listen(port, host, () => {\n server.off('error', reject);\n resolve();\n });\n });\n}\n\nfunction close(server: HttpServer): Promise<void> {\n return new Promise((resolve, reject) => {\n server.close((error?: Error) => {\n if (error) {\n reject(error);\n return;\n }\n resolve();\n });\n });\n}\n\ninterface HttpServer {\n listen(port: number, host: string, callback: () => void): void;\n once(event: 'error', callback: (error: Error) => void): void;\n off(event: 'error', callback: (error: Error) => void): void;\n close(callback: (error?: Error) => void): void;\n address(): string | { port: number } | null;\n}\n\nfunction getBoundPort(server: HttpServer, fallback: number): number {\n const address = server.address();\n return typeof address === 'object' && address !== null ? address.port : fallback;\n}\n\nfunction withBoundPort(options: PajaOptions, port: number): PajaOptions {\n return port === options.port ? options : { ...options, port };\n}\n"],"mappings":"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","names":["resolve","readFileSync","readFileSync","resolve"]}
|
package/dist/cli.d.ts
CHANGED
|
@@ -37,5 +37,6 @@ interface RunPajaCliOptions {
|
|
|
37
37
|
*/
|
|
38
38
|
declare function parsePajaArgs(args: readonly string[]): CliParseResult;
|
|
39
39
|
declare function runPajaCli(args?: readonly string[], io?: CliIo, runOptions?: RunPajaCliOptions): Promise<number>;
|
|
40
|
+
declare function isDirectPajaCli(entryPath?: string): boolean;
|
|
40
41
|
|
|
41
|
-
export { type CliIo, type CliParseResult, type RunPajaCliOptions, parsePajaArgs, runPajaCli };
|
|
42
|
+
export { type CliIo, type CliParseResult, type RunPajaCliOptions, isDirectPajaCli, parsePajaArgs, runPajaCli };
|
package/dist/cli.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
startPajaServer,
|
|
10
10
|
summarizePajaSimulation,
|
|
11
11
|
waitForTargetUrl
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-6QZXEPQJ.js";
|
|
13
13
|
|
|
14
14
|
// src/cli.ts
|
|
15
15
|
import { spawn } from "child_process";
|
|
@@ -45,42 +45,50 @@ async function runPajaCli(args = process.argv.slice(2), io = defaultIo, runOptio
|
|
|
45
45
|
const options = normalizePajaOptions(rawOptions);
|
|
46
46
|
const hostConfig = createPajaHostConfig(options);
|
|
47
47
|
const shouldServe = runOptions.serve ?? true;
|
|
48
|
-
|
|
48
|
+
let child;
|
|
49
49
|
let server;
|
|
50
50
|
if (shouldServe) {
|
|
51
51
|
try {
|
|
52
|
+
server = await startPajaServer({ options: rawOptions });
|
|
53
|
+
writeRuntimeSummary(io, server.url, hostConfig, options);
|
|
52
54
|
if (options.command) {
|
|
55
|
+
child = startManagedCommand(options.command);
|
|
53
56
|
await waitForTargetUrl(options.targetUrl, { timeoutMs: options.readyTimeoutMs });
|
|
54
57
|
}
|
|
55
|
-
server = await startPajaServer({ options: rawOptions });
|
|
56
58
|
} catch (error) {
|
|
57
59
|
child?.kill();
|
|
60
|
+
await server?.close().catch(() => void 0);
|
|
58
61
|
throw error;
|
|
59
62
|
}
|
|
60
63
|
}
|
|
61
64
|
const runtimeUrl = server?.url ?? formatPajaUrl(options);
|
|
62
|
-
|
|
65
|
+
if (!shouldServe) {
|
|
66
|
+
writeRuntimeSummary(io, runtimeUrl, hostConfig, options);
|
|
67
|
+
}
|
|
68
|
+
return 0;
|
|
69
|
+
} catch (error) {
|
|
70
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
71
|
+
io.stderr.write(`kehto paja: ${message}
|
|
63
72
|
`);
|
|
64
|
-
|
|
73
|
+
return 1;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function writeRuntimeSummary(io, runtimeUrl, hostConfig, options) {
|
|
77
|
+
io.stdout.write(`Kehto Paja
|
|
65
78
|
`);
|
|
66
|
-
|
|
79
|
+
io.stdout.write(`Runtime URL: ${runtimeUrl}
|
|
67
80
|
`);
|
|
68
|
-
|
|
81
|
+
io.stdout.write(`Target URL: ${hostConfig.target.url}
|
|
69
82
|
`);
|
|
70
|
-
|
|
83
|
+
io.stdout.write(`Mode: ${options.mode}
|
|
71
84
|
`);
|
|
72
|
-
|
|
85
|
+
io.stdout.write(`HMR: ${hostConfig.target.hmrStrategy}
|
|
73
86
|
`);
|
|
74
|
-
|
|
75
|
-
io.stdout.write(`Command: ${formatCommand(options.command)}
|
|
87
|
+
io.stdout.write(`Simulation: ${summarizePajaSimulation(options.simulation)}
|
|
76
88
|
`);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
} catch (error) {
|
|
80
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
81
|
-
io.stderr.write(`kehto paja: ${message}
|
|
89
|
+
if (options.command) {
|
|
90
|
+
io.stdout.write(`Command: ${formatCommand(options.command)}
|
|
82
91
|
`);
|
|
83
|
-
return 1;
|
|
84
92
|
}
|
|
85
93
|
}
|
|
86
94
|
var HELP_TEXT = `Usage:
|
|
@@ -299,15 +307,17 @@ var defaultIo = {
|
|
|
299
307
|
stdout: { write: (chunk) => process.stdout.write(chunk) },
|
|
300
308
|
stderr: { write: (chunk) => process.stderr.write(chunk) }
|
|
301
309
|
};
|
|
302
|
-
if (
|
|
310
|
+
if (isDirectPajaCli()) {
|
|
303
311
|
void runPajaCli().then((code) => {
|
|
304
312
|
process.exitCode = code;
|
|
305
313
|
});
|
|
306
314
|
}
|
|
307
|
-
function
|
|
308
|
-
|
|
315
|
+
function isDirectPajaCli(entryPath = process.argv[1]) {
|
|
316
|
+
if (!entryPath) return false;
|
|
317
|
+
return entryPath.endsWith("/cli.js") || entryPath.endsWith("/paja");
|
|
309
318
|
}
|
|
310
319
|
export {
|
|
320
|
+
isDirectPajaCli,
|
|
311
321
|
parsePajaArgs,
|
|
312
322
|
runPajaCli
|
|
313
323
|
};
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { spawn } 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}\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 child = shouldServe && options.command ? startManagedCommand(options.command) : undefined;\n let server: Awaited<ReturnType<typeof startPajaServer>> | undefined;\n if (shouldServe) {\n try {\n if (options.command) {\n await waitForTargetUrl(options.targetUrl, { timeoutMs: options.readyTimeoutMs });\n }\n server = await startPajaServer({ options: rawOptions });\n } catch (error) {\n child?.kill();\n throw error;\n }\n }\n const runtimeUrl = server?.url ?? formatPajaUrl(options);\n\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 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\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\nfunction startManagedCommand(command: PajaCommand): ManagedChildProcess {\n if (command.mode === 'shell') {\n return spawn(command.command, { shell: true, stdio: 'inherit' });\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' });\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 (isDirectCli()) {\n void runPajaCli().then((code) => {\n process.exitCode = code;\n });\n}\n\nfunction isDirectCli(): boolean {\n return typeof process !== 'undefined' && process.argv[1]?.endsWith('/cli.js') === true;\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\ninterface ManagedChildProcess {\n kill(): void;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { spawn } 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}\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 let child: ManagedChildProcess | undefined;\n let server: Awaited<ReturnType<typeof startPajaServer>> | undefined;\n if (shouldServe) {\n try {\n server = await startPajaServer({ options: rawOptions });\n writeRuntimeSummary(io, server.url, hostConfig, options);\n\n if (options.command) {\n child = startManagedCommand(options.command);\n await waitForTargetUrl(options.targetUrl, { timeoutMs: options.readyTimeoutMs });\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\nfunction startManagedCommand(command: PajaCommand): ManagedChildProcess {\n if (command.mode === 'shell') {\n return spawn(command.command, { shell: true, stdio: 'inherit' });\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' });\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\ninterface ManagedChildProcess {\n kill(): void;\n}\n"],"mappings":";;;;;;;;;;;;;;AACA,SAAS,aAAa;AAqDf,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,QAAI;AACJ,QAAI;AACJ,QAAI,aAAa;AACf,UAAI;AACF,iBAAS,MAAM,gBAAgB,EAAE,SAAS,WAAW,CAAC;AACtD,4BAAoB,IAAI,OAAO,KAAK,YAAY,OAAO;AAEvD,YAAI,QAAQ,SAAS;AACnB,kBAAQ,oBAAoB,QAAQ,OAAO;AAC3C,gBAAM,iBAAiB,QAAQ,WAAW,EAAE,WAAW,QAAQ,eAAe,CAAC;AAAA,QACjF;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,SAAS,oBAAoB,SAA2C;AACtE,MAAI,QAAQ,SAAS,SAAS;AAC5B,WAAO,MAAM,QAAQ,SAAS,EAAE,OAAO,MAAM,OAAO,UAAU,CAAC;AAAA,EACjE;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,UAAU,CAAC;AACrD;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;","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ declare function mergePajaRawOptions(base: PajaRawOptions, override: PajaRawOpti
|
|
|
8
8
|
|
|
9
9
|
declare function renderPajaHtml(config: PajaHostConfig): string;
|
|
10
10
|
|
|
11
|
-
declare const PAJA_UPSTREAM_WEB_DOMAINS: readonly ["ble", "common", "config", "cvm", "identity", "ifc", "inc", "intent", "keys", "link", "lists", "media", "notify", "outbox", "relay", "resource", "serial", "
|
|
11
|
+
declare const PAJA_UPSTREAM_WEB_DOMAINS: readonly ["ble", "common", "config", "cvm", "dm", "identity", "ifc", "inc", "intent", "keys", "link", "lists", "media", "notify", "outbox", "relay", "resource", "serial", "storage", "theme", "upload", "webrtc"];
|
|
12
12
|
declare const PAJA_HANDSHAKE_DOMAINS: readonly ["shell"];
|
|
13
13
|
declare const PAJA_COMPATIBILITY_ALIASES: {
|
|
14
14
|
readonly ifc: "inc";
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kehto/paja",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
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.
|
|
28
|
+
"@kehto/acl": "^0.14.2",
|
|
29
|
+
"@kehto/firewall": "^0.3.5",
|
|
29
30
|
"@kehto/nip": "^0.4.0",
|
|
30
|
-
"@kehto/runtime": "^0.
|
|
31
|
-
"@kehto/
|
|
32
|
-
"@kehto/
|
|
33
|
-
"@kehto/shell": "^0.14.2",
|
|
31
|
+
"@kehto/runtime": "^0.16.1",
|
|
32
|
+
"@kehto/services": "^0.13.2",
|
|
33
|
+
"@kehto/shell": "^0.15.2",
|
|
34
34
|
"@kehto/wm": "^0.0.1"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
|
-
"@napplet/core": ">=0.
|
|
38
|
-
"@napplet/nap": ">=0.
|
|
37
|
+
"@napplet/core": ">=0.23.0 <0.25.0",
|
|
38
|
+
"@napplet/nap": ">=0.23.0 <0.25.0",
|
|
39
39
|
"nostr-tools": ">=2.23.3 <3.0.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@napplet/core": ">=0.
|
|
43
|
-
"@napplet/nap": ">=0.
|
|
42
|
+
"@napplet/core": ">=0.23.0 <0.25.0",
|
|
43
|
+
"@napplet/nap": ">=0.23.0 <0.25.0",
|
|
44
44
|
"nostr-tools": "^2.23.3",
|
|
45
45
|
"tsup": "^8.5.0",
|
|
46
46
|
"typescript": "^5.9.3",
|