@kehto/paja 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config-file.ts","../src/simulation.ts","../src/options.ts","../src/host-page.ts","../src/runtime-resolver.ts","../src/parity.ts","../src/readiness.ts","../src/installed-napplet-catalog.ts","../src/browser-intent-controller.ts","../src/server.ts","../src/target-cors.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\n/**\n * Load a JSON Paja config file from disk.\n *\n * @param configPath - Path to a JSON config file.\n * @returns Raw options parsed from the config file.\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\n/**\n * Resolve raw options by merging an optional config file with explicit values.\n *\n * @param raw - CLI/config options, optionally including `configPath`.\n * @returns Raw options with config-file defaults applied.\n */\nexport function resolvePajaRawOptions(raw: PajaRawOptions): PajaRawOptions {\n if (!raw.configPath?.trim()) return raw;\n return mergePajaRawOptions(loadPajaConfigFile(raw.configPath), raw);\n}\n\n/**\n * Merge two raw Paja option objects, with override values taking precedence.\n *\n * @param base - Base options, usually from a config file.\n * @param override - Explicit options, usually from CLI args.\n * @returns Merged raw options.\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","/** JSON primitive accepted in Paja simulation config values. */\nexport type JsonPrimitive = string | number | boolean | null;\n/** JSON value accepted in Paja simulation config values. */\nexport type JsonValue = JsonPrimitive | JsonValue[] | { readonly [key: string]: JsonValue };\n/** JSON object used for Paja simulation fixtures and config/theme values. */\nexport type JsonRecord = Record<string, JsonValue>;\n\n/** Capability domain names Paja can advertise or disable. */\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 | 'count'\n | 'link'\n | 'common'\n | 'lists'\n | 'serial'\n | 'ble'\n | 'webrtc'\n | 'cvm'\n | 'inc';\n\n/** Raw simulation controls accepted from CLI args or JSON config. */\nexport interface PajaSimulationRawOptions {\n /** Per-domain capability overrides. */\n readonly capabilities?: {\n readonly domains?: Partial<Record<PajaCapabilityDomain, boolean>>;\n };\n /** ACL behavior mode for simulated services. */\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?: 'live' | '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' | 'blossom' | 'disabled';\n readonly rail?: string;\n readonly servers?: readonly string[];\n readonly discoverServers?: boolean;\n readonly maxBytes?: number;\n readonly mimeTypes?: readonly 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\n/** Fully normalized Paja simulation model served to the browser host. */\nexport interface PajaSimulation {\n /** Capability domains and disabled-domain summary. */\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: 'live' | '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' | 'blossom' | 'disabled';\n readonly rail?: string;\n readonly servers: readonly string[];\n readonly discoverServers: boolean;\n readonly maxBytes?: number;\n readonly mimeTypes?: readonly 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\n/** Thrown when Paja simulation options are internally inconsistent. */\nexport class PajaSimulationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'PajaSimulationError';\n }\n}\n\n/** Capability domains exposed by Paja simulation controls. */\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 'count',\n 'link',\n 'common',\n 'lists',\n 'serial',\n 'ble',\n 'webrtc',\n 'cvm',\n 'inc',\n];\n\nconst DEFAULT_RELAY_URLS = [\n 'wss://relay.damus.io',\n 'wss://nos.lol',\n 'wss://relay.primal.net',\n 'wss://relay.snort.social',\n] 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\n/**\n * Normalize raw simulation options into a complete deterministic model.\n *\n * @param raw - Partial simulation options from CLI args or config.\n * @returns Complete simulation model.\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 ? 'live' : '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 if (!domains.relay) domains.count = 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 !== 'disabled' && relayUrls.length === 0) {\n throw new PajaSimulationError('Invalid simulation: relay.urls must contain at least one URL when relay.mode is enabled.');\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 const uploadServers = normalizeUploadServers(raw?.upload?.servers ?? []);\n const discoverServers = raw?.upload?.discoverServers ?? uploadMode === 'blossom';\n const maxBytes = raw?.upload?.maxBytes;\n if (maxBytes !== undefined && (!Number.isSafeInteger(maxBytes) || maxBytes <= 0)) {\n throw new PajaSimulationError('Invalid simulation: upload.maxBytes must be a positive safe integer.');\n }\n const mimeTypes = normalizeMimeTypes(raw?.upload?.mimeTypes);\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 ...(uploadMode === 'memory' ? { rail: uploadRail } : {}),\n servers: uploadServers,\n discoverServers,\n ...(maxBytes !== undefined ? { maxBytes } : {}),\n ...(mimeTypes ? { mimeTypes } : {}),\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\n/**\n * Format a compact, human-readable simulation summary.\n *\n * @param simulation - Normalized simulation model.\n * @returns One-line summary used by CLI and host-page chrome.\n */\nexport function summarizePajaSimulation(simulation: PajaSimulation): string {\n const relay = simulation.relay.mode === 'disabled' ? 'relay:off' : `relay:${simulation.relay.mode}:${simulation.relay.urls.length}`;\n const identity = simulation.identity.mode === 'fixed' ? 'identity:fixed' : 'identity:anon';\n const storage = `storage:${simulation.storage.mode}`;\n const upload = simulation.upload.mode === 'memory'\n ? 'upload:memory:simulator'\n : simulation.upload.mode === 'blossom'\n ? `upload:blossom:${simulation.upload.servers.length}`\n : 'upload:off';\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} ${upload} ${theme} ${disabled}`;\n}\n\n/** Normalize an ordered list of shell-owned Blossom server base URLs. */\nexport function normalizeUploadServers(servers: readonly string[]): string[] {\n const normalized: string[] = [];\n for (const value of servers) {\n if (typeof value !== 'string' || value.trim().length === 0) {\n throw new PajaSimulationError('Invalid simulation: upload.servers entries must be non-empty URLs.');\n }\n let url: URL;\n try {\n url = new URL(value.trim());\n } catch {\n throw new PajaSimulationError(`Invalid simulation: upload server \"${value}\" is not a valid URL.`);\n }\n if (url.username || url.password) {\n throw new PajaSimulationError('Invalid simulation: upload server URLs must not contain credentials.');\n }\n if (url.protocol !== 'https:' && !(url.protocol === 'http:' && isLoopbackHost(url.hostname))) {\n throw new PajaSimulationError('Invalid simulation: upload servers require HTTPS, except loopback HTTP for development.');\n }\n if (url.search || url.hash) {\n throw new PajaSimulationError('Invalid simulation: upload server URLs must not contain a query or fragment.');\n }\n const result = url.href.replace(/\\/+$/, '');\n if (!normalized.includes(result)) normalized.push(result);\n }\n return normalized;\n}\n\nfunction isLoopbackHost(hostname: string): boolean {\n return hostname === 'localhost'\n || hostname === '[::1]'\n || /^127(?:\\.\\d{1,3}){3}$/.test(hostname);\n}\n\nfunction normalizeMimeTypes(mimeTypes: readonly string[] | undefined): string[] | undefined {\n if (mimeTypes === undefined) return undefined;\n const normalized: string[] = [];\n for (const value of mimeTypes) {\n if (typeof value !== 'string' || value.trim().length === 0) {\n throw new PajaSimulationError('Invalid simulation: upload.mimeTypes entries must be non-empty strings.');\n }\n const mimeType = value.trim();\n if (!normalized.includes(mimeType)) normalized.push(mimeType);\n }\n return normalized;\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\n/** Command configuration for a managed Paja target process. */\nexport type PajaCommand =\n /** Spawn an executable with argv preserved exactly after `--`. */\n | { readonly mode: 'argv'; readonly argv: readonly string[] }\n /** Run a shell command string. */\n | { readonly mode: 'shell'; readonly command: string };\n\n/** Raw, unnormalized options accepted from CLI arguments or config files. */\nexport interface PajaRawOptions {\n /** App dev-server URL that Paja should load. */\n readonly targetUrl?: string;\n /** Optional managed command to start before serving Paja. */\n readonly command?: PajaCommand;\n /** Hostname or IP address for the Paja HTTP server. */\n readonly host?: string;\n /** Runtime HTTP port. */\n readonly port?: number | string;\n /** Target readiness timeout in milliseconds. */\n readonly readyTimeoutMs?: number | string;\n /** Optional JSON config file path. */\n readonly configPath?: string;\n /** Simulation controls for injected shell domains. */\n readonly simulation?: PajaSimulationRawOptions;\n}\n\n/** Paja target loading mode. */\nexport type PajaTargetMode = 'iframe-url' | 'runtime-pointer';\n/** Hot-module-reload strategy for the hosted target. */\nexport type PajaHmrStrategy = 'iframe-target-url' | 'none';\n\n/** Runtime-pointer resolution config embedded into the Paja host page. */\nexport interface PajaPointerRuntimeConfig {\n /** Optional naddr/nevent pointer to resolve at boot. */\n readonly value?: string;\n /** Relay hints used to resolve the pointer. */\n readonly relays: readonly string[];\n /** Blossom server hints used for artifact blob fetches. */\n readonly blossomServers: readonly string[];\n /** Maximum pointer-resolution wait in milliseconds. */\n readonly maxWaitMs: number;\n}\n\n/** Normalized Paja runtime options. */\nexport interface PajaOptions {\n /** Absolute target URL for iframe-url mode. */\n readonly targetUrl: string;\n /** Optional managed target command. */\n readonly command?: PajaCommand;\n /** Paja server host. */\n readonly host: string;\n /** Paja server port. */\n readonly port: number;\n /** Target readiness timeout in milliseconds. */\n readonly readyTimeoutMs: number;\n /** Optional config path retained for host diagnostics. */\n readonly configPath?: string;\n /** Normalized simulation model. */\n readonly simulation: PajaSimulation;\n /** Whether Paja owns a managed command or attaches to an external target. */\n readonly mode: 'external-target' | 'managed-command';\n}\n\n/** Serialized host-page config served to the browser runtime. */\nexport interface PajaHostConfig {\n /** Config schema version. */\n readonly version: 1;\n /** Window identity used for the development target. */\n readonly window: {\n readonly id: string;\n readonly dTag: string;\n readonly aggregateHash: string;\n };\n readonly target: {\n readonly mode: PajaTargetMode;\n readonly url: string;\n readonly hmrStrategy: PajaHmrStrategy;\n readonly command?: PajaCommand;\n readonly pointer?: PajaPointerRuntimeConfig;\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\n/** Thrown when raw Paja options cannot be normalized. */\nexport class PajaOptionsError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'PajaOptionsError';\n }\n}\n\n/** Default loopback host for the Paja HTTP server. */\nexport const DEFAULT_PAJA_HOST = '127.0.0.1';\n/** Default Paja HTTP port. */\nexport const DEFAULT_PAJA_PORT = 5197;\n/** Default readiness timeout for the target URL. */\nexport const DEFAULT_READY_TIMEOUT_MS = 30_000;\n/** Default development window id used in host config. */\nexport const DEFAULT_PAJA_WINDOW_ID = 'kehto-paja-window';\n/** Default development `d` tag used for target identity. */\nexport const DEFAULT_PAJA_DTAG = 'dev-target';\n/** Default development aggregate hash used for target identity. */\nexport const DEFAULT_PAJA_AGGREGATE_HASH = 'paja';\n/** Default pointer resolution wait in runtime-pointer mode. */\nexport const DEFAULT_PAJA_RUNTIME_WAIT_MS = 5_000;\n\n/**\n * Normalize raw CLI/config options into a validated Paja runtime config.\n *\n * @param raw - Raw options from CLI parsing or a config file.\n * @returns Fully normalized runtime options.\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\n/**\n * Create browser host-page config for iframe-url mode.\n *\n * @param options - Normalized Paja options.\n * @param now - Clock value used for reload token and timestamps.\n * @returns Serializable host-page config.\n */\nexport function createPajaHostConfig(\n options: PajaOptions,\n now: Date = new Date(),\n): PajaHostConfig {\n const base = createPajaHostConfigBase(options.simulation);\n return {\n ...base,\n target: {\n mode: 'iframe-url',\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 };\n}\n\n/**\n * Create browser host-page config for runtime-pointer mode.\n *\n * @param options - Pointer, relay, and Blossom hints.\n * @param now - Clock value used for reload token and timestamps.\n * @returns Serializable host-page config.\n */\nexport function createPajaRuntimeHostConfig(\n options: {\n readonly pointer?: string;\n readonly relays?: readonly string[];\n readonly blossomServers?: readonly string[];\n readonly maxWaitMs?: number;\n } = {},\n now: Date = new Date(),\n): PajaHostConfig {\n const base = createPajaHostConfigBase(normalizePajaSimulation({}));\n return {\n ...base,\n target: {\n mode: 'runtime-pointer',\n url: 'about:blank',\n hmrStrategy: 'none',\n pointer: {\n ...(options.pointer ? { value: options.pointer } : {}),\n relays: [...(options.relays ?? [])],\n blossomServers: [...(options.blossomServers ?? [])],\n maxWaitMs: normalizePositiveInteger(\n options.maxWaitMs ?? DEFAULT_PAJA_RUNTIME_WAIT_MS,\n 'runtime-wait',\n ),\n },\n },\n runtime: {\n host: 'static',\n port: 0,\n readyTimeoutMs: 1,\n reloadToken: createReloadToken(now),\n createdAt: now.toISOString(),\n },\n };\n}\n\n/**\n * Format the local Paja runtime URL for display and CLI output.\n *\n * @param options - Host and port pair.\n * @returns HTTP URL for the Paja runtime.\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 createPajaHostConfigBase(simulation: PajaSimulation): Pick<PajaHostConfig, 'version' | 'window' | 'chrome' | 'simulation'> {\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 chrome: {\n topBar: true,\n bottomBar: true,\n sidePanels: false,\n },\n simulation,\n };\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\n/**\n * Render the browser host page for a Paja runtime config.\n *\n * @param config - Serializable host-page config.\n * @returns Complete HTML document served by Paja.\n */\nexport function renderPajaHtml(config: PajaHostConfig): string {\n const configJson = escapeJsonForHtml(JSON.stringify(config));\n const targetLabel = escapeAttribute(getTargetLabel(config));\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 --paja-console-column: minmax(320px, 380px);\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 { display: grid; grid-template-columns: var(--paja-console-column) minmax(0, 1fr); align-items: stretch; gap: 0; padding: 0; border-bottom: 1px solid var(--line); }\n .top-console { min-width: 0; display: flex; align-items: center; gap: 14px; padding: 0 12px; border-right: 1px solid var(--line); }\n .top-stage { min-width: 0; display: flex; align-items: stretch; gap: 14px; padding: 0 12px 0 0; overflow: hidden; }\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 .brand-product { color: var(--text); }\n .target { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); }\n .spacer { flex: 1; min-width: 0; }\n .tabs { display: flex; align-items: stretch; align-self: flex-end; gap: 4px; min-width: 120px; max-width: min(100%, 760px); overflow-x: auto; scrollbar-width: thin; }\n .tabs:empty { display: none; }\n .tab { min-width: 116px; max-width: 240px; height: 30px; display: grid; grid-template-columns: minmax(0, 1fr) 24px 24px; align-items: center; gap: 2px; border: 1px solid var(--line); border-bottom-color: transparent; background: #151815; color: var(--muted); border-radius: 5px 5px 0 0; padding: 0 2px 0 9px; }\n .tab[data-active=\"true\"] { color: var(--text); border-color: var(--accent); border-bottom-color: #151815; background: #20241f; }\n .tab-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; text-align: left; }\n .tab-share, .tab-close { width: 20px; height: 20px; padding: 0; border: 0; background: transparent; color: var(--muted); display: inline-grid; place-items: center; }\n .tab-share:hover, .tab-close:hover { color: var(--text); background: #2d302b; border-color: transparent; }\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, input { border: 1px solid var(--line); color: var(--text); background: #20241f; height: 26px; border-radius: 4px; font: inherit; }\n main { min-height: 0; display: grid; grid-template-columns: var(--paja-console-column) minmax(0, 1fr); }\n .console { min-height: 0; overflow: auto; border-right: 1px solid var(--line); background: #121512; padding: 10px; display: flex; flex-direction: column; gap: 12px; }\n .section { display: grid; gap: 8px; }\n .section-title { color: var(--accent); font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0; }\n .switch-grid, .acl-grid { display: flex; flex-wrap: wrap; gap: 6px; }\n .toggle { height: 24px; padding: 0 8px; color: var(--muted); }\n .toggle[data-enabled=\"true\"] { color: var(--text); border-color: #5f724f; background: #24301f; }\n .toggle[data-enabled=\"false\"] { color: #8d9187; border-color: #453536; background: #241d1d; }\n .signer { color: var(--muted); word-break: break-all; font-size: 12px; }\n .signer-controls { display: grid; grid-template-columns: auto auto minmax(0, 1fr) auto; gap: 6px; }\n .signer-controls button[data-active=\"true\"] { border-color: var(--accent); color: var(--text); background: #2a2a1d; }\n .signer-controls input { min-width: 0; padding: 0 8px; }\n .pointer-controls { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 6px; }\n .pointer-status { min-width: 0; color: var(--muted); font-size: 12px; overflow-wrap: anywhere; }\n .log-tools { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 6px; }\n .log-list { min-height: 160px; max-height: 38vh; overflow: auto; border: 1px solid var(--line); border-radius: 4px; background: #0b0d0b; }\n .log-row { display: grid; grid-template-columns: 88px minmax(0, 1fr); gap: 6px; padding: 5px 7px; border-bottom: 1px solid #1b1f1a; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11px; }\n .log-row[data-error=\"true\"] { background: #1d1414; }\n .log-row:last-child { border-bottom: 0; }\n .log-dir { color: var(--muted); }\n .log-body { min-width: 0; display: grid; gap: 2px; }\n .log-type { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .log-detail { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #e6a5a5; }\n .stage { min-width: 0; min-height: 0; position: relative; background: #050705; }\n .empty-stage { position: absolute; inset: 0; display: grid; place-items: center; color: var(--muted); font-size: 12px; }\n .empty-stage[hidden] { display: none; }\n .tab-panel { position: absolute; inset: 0; min-width: 0; min-height: 0; }\n .tab-panel[hidden] { display: none; }\n iframe { width: 100%; height: 100%; border: 0; background: white; display: block; }\n code { color: var(--text); }\n .dialog-backdrop { position: fixed; inset: 0; z-index: 20; display: grid; place-items: center; padding: 24px; background: rgb(0 0 0 / 0.58); }\n .dialog-backdrop[hidden] { display: none; }\n .dialog { width: min(420px, 100%); border: 1px solid var(--line); border-radius: 6px; background: #181b19; box-shadow: 0 18px 60px rgb(0 0 0 / 0.45); padding: 16px; display: grid; gap: 14px; }\n .dialog-title { font-weight: 700; color: var(--text); }\n .dialog-actions { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: 8px; }\n @media (max-width: 900px) {\n .top { grid-template-columns: minmax(0, 1fr); }\n .top-console { display: none; }\n .top-stage { padding-left: 0; }\n main { grid-template-columns: 1fr; grid-template-rows: minmax(240px, 40vh) minmax(0, 1fr); }\n .console { border-right: 0; border-bottom: 1px solid var(--line); }\n }\n </style>\n </head>\n <body>\n <header class=\"bar top\">\n <div class=\"top-console\">\n <div class=\"brand\">@kehto/<span class=\"brand-product\">paja</span></div>\n <div class=\"target\" title=\"${targetLabel}\">${targetLabel}</div>\n </div>\n <div class=\"top-stage\">\n <div class=\"tabs\" id=\"napplet-tabs\" role=\"tablist\" aria-label=\"Loaded napplets\"></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 </div>\n </header>\n <main>\n <aside class=\"console\" aria-label=\"Paja development controls\">\n ${renderPointerControls(config)}\n <section class=\"section\">\n <div class=\"section-title\">Interfaces</div>\n <div class=\"switch-grid\" id=\"interface-toggles\"></div>\n </section>\n <section class=\"section\">\n <div class=\"section-title\">ACL</div>\n <div class=\"acl-grid\" id=\"acl-controls\"></div>\n </section>\n <section class=\"section\">\n <div class=\"section-title\">Signer</div>\n <div class=\"signer\" id=\"signer-status\">loading</div>\n <div class=\"signer-controls\" id=\"signer-controls\"></div>\n </section>\n <section class=\"section\">\n <div class=\"section-title\">Messages</div>\n <div class=\"log-tools\">\n <input id=\"message-filter\" type=\"search\" autocomplete=\"off\" placeholder=\"filter messages\" aria-label=\"Filter message log\">\n <button type=\"button\" id=\"clear-log\">Clear</button>\n </div>\n <div class=\"log-list\" id=\"message-log\" aria-live=\"polite\"></div>\n </section>\n </aside>\n ${renderStage(config, targetLabel)}\n </main>\n ${renderDuplicateDialog()}\n <footer class=\"bar bottom\">\n <span>mode: <code>${escapeHtml(getModeLabel(config))}</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 renderStage(config: PajaHostConfig, targetLabel: string): string {\n if (config.target.mode === 'runtime-pointer') {\n return `<section class=\"stage\" id=\"napplet-stage\" aria-label=\"Loaded napplet runtimes\">\n <div class=\"empty-stage\" id=\"empty-runtime-stage\">Load a napplet pointer to start a runtime tab.</div>\n </section>`;\n }\n return `<section class=\"stage\" id=\"napplet-stage\">\n <iframe id=\"napplet-frame\" title=\"Napplet development target\" sandbox=\"allow-scripts\" data-target-url=\"${targetLabel}\"></iframe>\n </section>`;\n}\n\nfunction renderDuplicateDialog(): string {\n return `<div class=\"dialog-backdrop\" id=\"duplicate-pointer-dialog\" hidden>\n <div class=\"dialog\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"duplicate-pointer-title\">\n <div class=\"dialog-title\" id=\"duplicate-pointer-title\">this napplet is already running.</div>\n <div class=\"dialog-actions\">\n <button type=\"button\" id=\"duplicate-load-again\">load it again</button>\n <button type=\"button\" id=\"duplicate-open-tab\">open it in tab</button>\n <button type=\"button\" id=\"duplicate-cancel\">cancel</button>\n </div>\n </div>\n </div>`;\n}\n\nfunction renderPointerControls(config: PajaHostConfig): string {\n if (config.target.mode !== 'runtime-pointer') return '';\n const value = escapeAttribute(config.target.pointer?.value ?? '');\n return `<section class=\"section\" id=\"runtime-pointer-section\">\n <div class=\"section-title\">Pointer</div>\n <form class=\"pointer-controls\" id=\"runtime-pointer-form\">\n <input id=\"runtime-pointer-input\" type=\"text\" inputmode=\"url\" autocomplete=\"off\" spellcheck=\"false\" placeholder=\"naddr or nevent\" aria-label=\"Runtime napplet pointer\" value=\"${value}\">\n <button type=\"submit\" id=\"runtime-pointer-load\">Load</button>\n </form>\n <div class=\"pointer-status\" id=\"runtime-pointer-status\" aria-live=\"polite\">idle</div>\n </section>`;\n}\n\nfunction getModeLabel(config: PajaHostConfig): string {\n if (config.target.mode === 'runtime-pointer') return 'runtime-pointer';\n return config.target.command ? 'managed-command' : 'external-target';\n}\n\nfunction getTargetLabel(config: PajaHostConfig): string {\n if (config.target.mode === 'runtime-pointer') {\n return config.target.pointer?.value ?? 'runtime pointer';\n }\n return config.target.url;\n}\n\nfunction escapeAttribute(value: string): string {\n return escapeHtml(value).replaceAll('\"', '&quot;');\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;');\n}\n\nfunction escapeJsonForHtml(value: string): string {\n return value.replaceAll('<', '\\\\u003c');\n}\n","import type { NostrEvent } from 'nostr-tools';\nimport type { Filter } from 'nostr-tools/filter';\nimport { SimplePool } from 'nostr-tools/pool';\nimport { decode } from 'nostr-tools/nip19';\nimport {\n fetchBlob,\n isNappletManifestKind,\n NAPPLET_KIND_NAMED,\n NAPPLET_KINDS,\n openNappletArtifactCache,\n resolveNapplet,\n type ResolvedNapplet,\n} from '@kehto/nip/5d';\n\n/** Named/addressable NIP-5D napplet manifest kind (`35129`). */\nexport const PAJA_NAPPLET_MANIFEST_KIND = NAPPLET_KIND_NAMED;\n/** All NIP-5D napplet manifest kinds accepted by Paja pointers (`5129`, `15129`, `35129`). */\nexport const PAJA_NAPPLET_MANIFEST_KINDS = NAPPLET_KINDS;\n\n/** Decoded naddr/nevent pointer accepted by Paja runtime-pointer mode. */\nexport type PajaDecodedPointer =\n | {\n readonly type: 'naddr';\n readonly value: string;\n readonly identifier: string;\n readonly pubkey: string;\n readonly kind: number;\n readonly relays: readonly string[];\n }\n | {\n readonly type: 'nevent';\n readonly value: string;\n readonly id: string;\n readonly author?: string;\n readonly kind?: number;\n readonly relays: readonly string[];\n };\n\n/** Fully resolved pointer plus verified napplet artifact bytes. */\nexport interface PajaResolvedPointer {\n /** Decoded pointer input. */\n readonly pointer: PajaDecodedPointer;\n /** Manifest event resolved from relays. */\n readonly event: NostrEvent;\n /** Ordered relay URLs queried for the pointer, with embedded hints first. */\n readonly relays: readonly string[];\n /** Blossom server hints used for blob fetches. */\n readonly blossomServers: readonly string[];\n /** Resolved manifest `d` tag. */\n readonly dTag: string;\n /** Verified NIP-5A aggregate hash. */\n readonly aggregateHash: string;\n /** Verified target `/index.html` content. */\n readonly indexHtml: string;\n /** Parsed NIP-5D manifest. */\n readonly manifest: ResolvedNapplet['manifest'];\n}\n\n/** Relay-pool contract for runtime-pointer resolution. */\nexport interface PajaPointerRelayPool {\n /** Query relays synchronously for matching manifest events. */\n querySync(\n relays: string[],\n filter: Filter,\n params?: { readonly maxWait?: number; readonly label?: string; readonly id?: string },\n ): Promise<NostrEvent[]>;\n /** Subscribe until all relays reach EOSE, fail, or the shared deadline expires. */\n subscribeManyEose?(\n relays: string[],\n filter: Filter,\n params: {\n readonly maxWait?: number;\n readonly label?: string;\n readonly id?: string;\n readonly onevent: (event: NostrEvent) => void;\n readonly onclose: (reasons: string[]) => void;\n },\n ): { close(reason?: string): void | Promise<void> };\n close?(relays: string[]): void;\n destroy?(): void;\n}\n\n/** Options for resolving a Paja runtime pointer. */\nexport interface ResolvePajaPointerOptions {\n /** Relay pool override; defaults to a `nostr-tools` `SimplePool`. */\n readonly pool?: PajaPointerRelayPool;\n /** Fetch override used for Blossom blob URLs. */\n readonly fetcher?: (url: string) => Promise<Response>;\n /** Extra relay candidates appended after embedded pointer hints. */\n readonly relays?: readonly string[];\n /** Extra Blossom server hints appended during artifact fetch. */\n readonly blossomServers?: readonly string[];\n /** One overall deadline for relay connection, fanout, and EOSE in milliseconds. */\n readonly maxWaitMs?: number;\n}\n\n/**\n * Decode a NIP-19 naddr/nevent pointer for Paja runtime-pointer mode.\n *\n * @param value - NIP-19 pointer string.\n * @returns Structured pointer metadata.\n */\nexport function decodePajaPointer(value: string): PajaDecodedPointer {\n const trimmed = value.trim();\n const decoded = decode(trimmed);\n if (decoded.type === 'naddr') {\n return {\n type: 'naddr',\n value: trimmed,\n identifier: decoded.data.identifier,\n pubkey: decoded.data.pubkey,\n kind: decoded.data.kind,\n relays: [...(decoded.data.relays ?? [])],\n };\n }\n if (decoded.type === 'nevent') {\n return {\n type: 'nevent',\n value: trimmed,\n id: decoded.data.id,\n ...(decoded.data.author ? { author: decoded.data.author } : {}),\n ...(decoded.data.kind ? { kind: decoded.data.kind } : {}),\n relays: [...(decoded.data.relays ?? [])],\n };\n }\n throw new Error(`Expected naddr or nevent pointer, got ${decoded.type}.`);\n}\n\n/**\n * Resolve a Paja runtime pointer into verified napplet HTML and manifest data.\n *\n * @param value - NIP-19 naddr or nevent pointer.\n * @param options - Relay, fetch, and Blossom overrides.\n * @returns Verified napplet artifact ready for srcdoc injection.\n */\nexport async function resolvePajaPointer(\n value: string,\n options: ResolvePajaPointerOptions = {},\n): Promise<PajaResolvedPointer> {\n const pointer = decodePajaPointer(value);\n const relays = uniqueRelayUrls([...pointer.relays, ...(options.relays ?? [])]);\n if (relays.length === 0) {\n throw new Error('Pointer has no relay hints or enabled configured live relays.');\n }\n\n const pool = options.pool ?? new SimplePool();\n const ownsPool = options.pool === undefined;\n try {\n const event = await resolvePointerEvent(pointer, pool, relays, normalizeMaxWaitMs(options.maxWaitMs));\n const blossomServers = [...(options.blossomServers ?? [])];\n const resolved = await resolveNapplet({\n event,\n cache: await openNappletArtifactCache({ requireStorageEstimate: false }),\n fetchBlob: (sha256Hex, servers) =>\n fetchBlob([...servers, ...blossomServers], sha256Hex, async (url) => {\n const response = await (options.fetcher ?? fetch)(url);\n if (!response.ok) throw new Error(`[paja-runtime] blob ${url}: ${response.status}`);\n return new Uint8Array(await response.arrayBuffer());\n }),\n });\n return {\n pointer,\n event,\n relays,\n blossomServers,\n dTag: resolved.dTag,\n aggregateHash: resolved.aggregateHash,\n indexHtml: resolved.indexHtml,\n manifest: resolved.manifest,\n };\n } finally {\n if (ownsPool) {\n pool.close?.(relays);\n pool.destroy?.();\n }\n }\n}\n\n/**\n * Inject Kehto's Class-1 CSP for verified runtime-pointer srcdoc output.\n * NIP-5D mandates the verified srcdoc and opaque sandbox, but this baseline CSP\n * is Kehto policy rather than a protocol requirement.\n *\n * @param html - Verified target HTML.\n * @param origins - Origins the resolved target may connect to.\n * @returns HTML with a CSP meta tag inserted.\n */\nexport function injectPajaRuntimeCsp(html: string, origins: readonly string[]): string {\n const grantedOrigins = [...new Set(origins)].sort();\n const connectSrc = grantedOrigins.length > 0\n ? `connect-src ${grantedOrigins.join(' ')}`\n : \"connect-src 'none'\";\n const value = [\n \"default-src 'none'\",\n \"script-src 'unsafe-inline'\",\n \"style-src 'unsafe-inline'\",\n 'img-src data: blob:',\n 'font-src data:',\n connectSrc,\n \"worker-src 'none'\",\n \"child-src 'none'\",\n \"frame-src 'none'\",\n \"media-src 'none'\",\n \"object-src 'none'\",\n \"manifest-src 'none'\",\n \"prefetch-src 'none'\",\n \"base-uri 'none'\",\n \"form-action 'none'\",\n \"frame-ancestors 'self'\",\n ].join('; ');\n const meta = `<meta http-equiv=\"Content-Security-Policy\" content=\"${escapeAttribute(value)}\">`;\n if (/<head[^>]*>/i.test(html)) {\n return html.replace(/<head[^>]*>/i, (open) => `${open}${meta}`);\n }\n if (/<html[^>]*>/i.test(html)) {\n return html.replace(/<html[^>]*>/i, (open) => `${open}<head>${meta}</head>`);\n }\n return `${meta}${html}`;\n}\n\nasync function resolvePointerEvent(\n pointer: PajaDecodedPointer,\n pool: PajaPointerRelayPool,\n relays: readonly string[],\n maxWaitMs: number,\n): Promise<NostrEvent> {\n const filter = pointer.type === 'naddr'\n ? addressableFilter(pointer)\n : eventFilter(pointer);\n const result = await queryPointerRelays(pool, relays, filter, maxWaitMs);\n const event = result.events\n .filter((candidate) => matchesPointer(pointer, candidate))\n .sort((a, b) => b.created_at - a.created_at)[0];\n if (!event) {\n if (result.timedOut) {\n throw new Error(\n `Relay resolution timed out after ${maxWaitMs}ms for ${pointer.type} pointer across ${relays.length} relays before complete EOSE.`,\n );\n }\n const failures = relayFailureReasons(result.reasons);\n if (result.error || failures.length > 0) {\n const detail = result.error instanceof Error\n ? result.error.message\n : result.error === undefined\n ? failures.join('; ')\n : String(result.error);\n throw new Error(`Relay query failed for ${pointer.type} pointer before complete EOSE: ${detail}`);\n }\n throw new Error(\n `All ${relays.length} relays reached EOSE without a matching ${pointer.type} napplet manifest event.`,\n );\n }\n if (!isNappletManifestKind(event.kind)) {\n throw new Error(`Pointer resolved kind ${event.kind}; expected ${formatNappletManifestKinds()}.`);\n }\n return event;\n}\n\ninterface PointerRelayQueryResult {\n readonly events: readonly NostrEvent[];\n readonly reasons: readonly string[];\n readonly timedOut: boolean;\n readonly error?: unknown;\n}\n\nfunction queryPointerRelays(\n pool: PajaPointerRelayPool,\n relays: readonly string[],\n filter: Filter,\n maxWaitMs: number,\n): Promise<PointerRelayQueryResult> {\n if (pool.subscribeManyEose) {\n return queryPointerRelaySubscription(pool, relays, filter, maxWaitMs);\n }\n return queryPointerRelaySync(pool, relays, filter, maxWaitMs);\n}\n\nfunction queryPointerRelaySubscription(\n pool: PajaPointerRelayPool,\n relays: readonly string[],\n filter: Filter,\n maxWaitMs: number,\n): Promise<PointerRelayQueryResult> {\n return new Promise((resolve) => {\n const events: NostrEvent[] = [];\n let settled = false;\n let subscription: ReturnType<NonNullable<PajaPointerRelayPool['subscribeManyEose']>> | undefined;\n const finish = (result: Omit<PointerRelayQueryResult, 'events'>) => {\n if (settled) return;\n settled = true;\n clearTimeout(deadline);\n resolve({ events, ...result });\n };\n const deadline = setTimeout(() => {\n finish({ reasons: [], timedOut: true });\n void subscription?.close('Paja pointer relay deadline exceeded');\n }, maxWaitMs);\n\n try {\n subscription = pool.subscribeManyEose!([...relays], filter, {\n maxWait: maxWaitMs,\n label: 'kehto-paja-runtime',\n onevent(event) {\n events.push(event);\n },\n onclose(reasons) {\n finish({ reasons, timedOut: false });\n },\n });\n } catch (error) {\n finish({ reasons: [], timedOut: false, error });\n }\n });\n}\n\nfunction queryPointerRelaySync(\n pool: PajaPointerRelayPool,\n relays: readonly string[],\n filter: Filter,\n maxWaitMs: number,\n): Promise<PointerRelayQueryResult> {\n return new Promise((resolve) => {\n let settled = false;\n const finish = (result: PointerRelayQueryResult) => {\n if (settled) return;\n settled = true;\n clearTimeout(deadline);\n resolve(result);\n };\n const deadline = setTimeout(() => {\n finish({ events: [], reasons: [], timedOut: true });\n }, maxWaitMs);\n\n void pool.querySync([...relays], filter, {\n maxWait: maxWaitMs,\n label: 'kehto-paja-runtime',\n }).then(\n (events) => finish({ events, reasons: [], timedOut: false }),\n (error: unknown) => finish({ events: [], reasons: [], timedOut: false, error }),\n );\n });\n}\n\nfunction relayFailureReasons(reasons: readonly string[]): string[] {\n return [...new Set(reasons\n .map((reason) => reason.trim())\n .filter((reason) => reason.length > 0 && reason !== 'closed automatically on eose')\n .map((reason) => reason.slice(0, 160)))]\n .slice(0, 3);\n}\n\nfunction normalizeMaxWaitMs(value: number | undefined): number {\n if (value === undefined) return 5_000;\n if (!Number.isFinite(value) || value <= 0) {\n throw new Error('Pointer relay deadline must be a positive number of milliseconds.');\n }\n return Math.floor(value);\n}\n\nfunction addressableFilter(pointer: Extract<PajaDecodedPointer, { type: 'naddr' }>): Filter {\n if (pointer.kind !== NAPPLET_KIND_NAMED) {\n throw new Error(`naddr kind ${pointer.kind} is not a named NIP-5D napplet manifest kind.`);\n }\n return {\n kinds: [NAPPLET_KIND_NAMED],\n authors: [pointer.pubkey],\n '#d': [pointer.identifier],\n limit: 1,\n };\n}\n\nfunction eventFilter(pointer: Extract<PajaDecodedPointer, { type: 'nevent' }>): Filter {\n return {\n ids: [pointer.id],\n ...(pointer.kind ? { kinds: [pointer.kind] } : {}),\n ...(pointer.author ? { authors: [pointer.author] } : {}),\n limit: 1,\n };\n}\n\nfunction matchesPointer(pointer: PajaDecodedPointer, event: NostrEvent): boolean {\n if (pointer.type === 'nevent') {\n if (event.id !== pointer.id) return false;\n if (pointer.author && event.pubkey !== pointer.author) return false;\n if (pointer.kind && event.kind !== pointer.kind) return false;\n return true;\n }\n return event.kind === pointer.kind\n && event.pubkey === pointer.pubkey\n && event.tags.some((tag) => tag[0] === 'd' && tag[1] === pointer.identifier);\n}\n\nfunction uniqueRelayUrls(values: readonly string[]): string[] {\n const out: string[] = [];\n const seen = new Set<string>();\n for (const value of values) {\n const url = normalizeRelayUrl(value);\n if (!url || seen.has(url)) continue;\n seen.add(url);\n out.push(url);\n }\n return out;\n}\n\nfunction normalizeRelayUrl(value: string): string | undefined {\n const raw = value.trim();\n if (!raw) return undefined;\n try {\n const url = new URL(raw);\n if (url.protocol !== 'wss:' && url.protocol !== 'ws:') return undefined;\n url.hash = '';\n url.search = '';\n return url.href.replace(/\\/$/, '');\n } catch {\n return undefined;\n }\n}\n\nfunction escapeAttribute(value: string): string {\n return value\n .replaceAll('&', '&amp;')\n .replaceAll('\"', '&quot;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;');\n}\n\nfunction formatNappletManifestKinds(): string {\n return PAJA_NAPPLET_MANIFEST_KINDS.join(' / ');\n}\n","import type { ShellCapabilities } from '@kehto/shell';\n\n/** The exact host-visible shell environment shape shared by bootstrap and init. */\nexport type PajaShellEnvironment = Readonly<{\n capabilities: ShellCapabilities;\n services: readonly string[];\n}>;\n\nconst PAJA_LEGACY_COMPATIBILITY_DOMAIN: string = `i${'fc'}`;\n\n/** Domain list mirrored from the upstream web runtime for parity checks. */\nexport const PAJA_UPSTREAM_WEB_DOMAINS = [\n 'ble',\n 'common',\n 'config',\n 'count',\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\n/** Domains required during the initial Paja handshake. */\nexport const PAJA_HANDSHAKE_DOMAINS = ['shell'] as const;\n/** Domains intentionally deferred until their runtime service exists. */\nexport const PAJA_DEFERRED_DOMAINS = ['dm'] as const;\n\n/** Compatibility aliases for renamed upstream capability domains. */\nexport const PAJA_COMPATIBILITY_ALIASES = {\n [PAJA_LEGACY_COMPATIBILITY_DOMAIN]: 'inc',\n} as const;\n\n/** Domains Paja advertises through its simulated shell capability surface. */\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 'count',\n] as const;\n\n/** Service names Paja expects the host runtime to provide. */\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 'count',\n] as const;\n\n/**\n * Find advertised Paja domains missing from a shell capability snapshot.\n *\n * @param capabilities - Shell capability snapshot to inspect.\n * @returns Advertised domains not present in the snapshot.\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\n/**\n * Find required service names missing from a runtime service list.\n *\n * @param services - Runtime service names to inspect.\n * @returns Required service names that are absent.\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\n/**\n * Compare the observable membership of two independently resolved Paja shell\n * environments. Resolver calls intentionally return different frozen objects.\n */\nexport function hasEqualPajaEnvironmentMembership(\n left: PajaShellEnvironment,\n right: PajaShellEnvironment,\n): boolean {\n return left.capabilities.domains.length === right.capabilities.domains.length\n && left.capabilities.domains.every((domain, index) => domain === right.capabilities.domains[index])\n && left.services.length === right.services.length\n && left.services.every((service, index) => service === right.services[index]);\n}\n","/** Options for polling a target URL until it is ready. */\nexport interface WaitForTargetUrlOptions {\n /** Total wait budget in milliseconds. */\n readonly timeoutMs: number;\n /** Poll interval in milliseconds. Defaults to 250. */\n readonly intervalMs?: number;\n /** Fetch implementation override for tests. */\n readonly fetch?: ReadinessFetch;\n /** Sleep implementation override for tests. */\n readonly sleep?: (ms: number) => Promise<void>;\n /** Clock override for tests. */\n readonly now?: () => number;\n}\n\n/** Fetch-like target readiness probe. */\nexport type ReadinessFetch = (url: string) => Promise<{ readonly status: number }>;\n\n/** Thrown when a target URL does not become ready before the timeout. */\nexport class ReadinessError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ReadinessError';\n }\n}\n\n/**\n * Poll a target URL until it returns a non-5xx response or times out.\n *\n * @param url - Target URL to poll.\n * @param options - Timeout and polling controls.\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","/**\n * Persistent Paja catalog of resolver-verified napplet installations.\n *\n * The catalog deliberately contains only serializable facts copied from a\n * verified pointer result. Runtime frames, sessions, and controller state are\n * owned elsewhere, so closing a tab cannot alter handler eligibility.\n *\n * @packageDocumentation\n */\n\nimport { manifestToIntentCatalogEntry } from '@kehto/services';\nimport type { IntentCatalogEntry } from '@kehto/services';\nimport type { PajaDecodedPointer, PajaResolvedPointer } from './runtime-resolver.js';\n\n/** Serializable verified pointer and manifest facts for one installed napplet. */\nexport interface InstalledNappletRecord {\n /** Verified manifest d-tag used as the handler identity. */\n readonly dTag: string;\n /** Verified NIP-5A aggregate hash for the installed artifact. */\n readonly aggregateHash: string;\n /** Pointer identity that can later be re-resolved and verified. */\n readonly pointer: PajaDecodedPointer;\n /** Optional manifest title for handler selection UI. */\n readonly title?: string;\n /** Exact manifest convention contracts used for intent eligibility. */\n readonly archetypes: readonly {\n readonly slug: string;\n readonly convention: string;\n readonly eventKinds?: readonly number[];\n }[];\n}\n\n/** Return whether a live runtime target is exactly the installed verified artifact. */\nexport function matchesInstalledNappletRecord(\n record: Pick<InstalledNappletRecord, 'dTag' | 'aggregateHash'>,\n target: Pick<InstalledNappletRecord, 'dTag' | 'aggregateHash'>,\n): boolean {\n return target.dTag === record.dTag && target.aggregateHash === record.aggregateHash;\n}\n\n/** Listener notified when an installed artifact is inserted or removed. */\nexport type InstalledNappletCatalogListener = (dTag: string) => void;\n\n/**\n * Stores verified Paja installations separately from the browser runtime.\n *\n * @example\n * ```ts\n * const catalog = new InstalledNappletCatalog();\n * catalog.install(resolvedPointer);\n * const candidates = catalog.intentCatalog();\n * ```\n */\nexport class InstalledNappletCatalog {\n private readonly records = new Map<string, InstalledNappletRecord>();\n private readonly listeners = new Set<InstalledNappletCatalogListener>();\n\n /** Insert or replace a record from an already resolver-verified pointer. */\n install(resolved: PajaResolvedPointer): InstalledNappletRecord {\n const record = freezeRecord({\n dTag: resolved.dTag,\n aggregateHash: resolved.aggregateHash,\n pointer: copyPointer(resolved.pointer),\n ...(resolved.manifest.title === undefined ? {} : { title: resolved.manifest.title }),\n archetypes: resolved.manifest.archetypes.map((archetype) => ({\n slug: archetype.slug,\n convention: archetype.convention,\n ...(archetype.eventKinds === undefined ? {} : { eventKinds: [...archetype.eventKinds] }),\n })),\n });\n this.records.set(record.dTag, record);\n this.notify(record.dTag);\n return record;\n }\n\n /** Remove an artifact explicitly; frame teardown never calls this method. */\n remove(dTag: string): boolean {\n const removed = this.records.delete(dTag);\n if (removed) this.notify(dTag);\n return removed;\n }\n\n /** Return whether a verified installation exists for a d-tag. */\n has(dTag: string): boolean {\n return this.records.has(dTag);\n }\n\n /** Return immutable serializable installed-artifact facts. */\n installed(): readonly InstalledNappletRecord[] {\n return [...this.records.values()];\n }\n\n /** Return a verified record by d-tag. */\n get(dTag: string): InstalledNappletRecord | undefined {\n return this.records.get(dTag);\n }\n\n /**\n * Atomically confirm that a resolved target still belongs to the exact record\n * selected before an async operation. The record object is the catalog version\n * token, so even a same-identity replacement cannot pass this check.\n */\n validateCurrent(\n selected: InstalledNappletRecord,\n target: Pick<InstalledNappletRecord, 'dTag' | 'aggregateHash'>,\n ): InstalledNappletRecord | null {\n if (this.records.get(selected.dTag) !== selected) return null;\n return matchesInstalledNappletRecord(selected, target) ? selected : null;\n }\n\n /** Return exact handler candidates derived only from installed manifests. */\n intentCatalog(): IntentCatalogEntry[] {\n return this.installed().map((record) => manifestToIntentCatalogEntry({\n dTag: record.dTag,\n ...(record.title === undefined ? {} : { title: record.title }),\n archetypes: record.archetypes.map((archetype) => ({\n slug: archetype.slug,\n convention: archetype.convention,\n ...(archetype.eventKinds === undefined ? {} : { eventKinds: [...archetype.eventKinds] }),\n })),\n }));\n }\n\n /** Subscribe to explicit install and artifact-removal changes. */\n onChanged(listener: InstalledNappletCatalogListener): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n private notify(dTag: string): void {\n for (const listener of this.listeners) listener(dTag);\n }\n}\n\nfunction copyPointer(pointer: PajaDecodedPointer): PajaDecodedPointer {\n if (pointer.type === 'naddr') {\n return Object.freeze({\n type: 'naddr' as const,\n value: pointer.value,\n identifier: pointer.identifier,\n pubkey: pointer.pubkey,\n kind: pointer.kind,\n relays: Object.freeze([...pointer.relays]),\n });\n }\n return Object.freeze({\n type: 'nevent' as const,\n value: pointer.value,\n id: pointer.id,\n ...(pointer.author === undefined ? {} : { author: pointer.author }),\n ...(pointer.kind === undefined ? {} : { kind: pointer.kind }),\n relays: Object.freeze([...pointer.relays]),\n });\n}\n\nfunction freezeRecord(record: Omit<InstalledNappletRecord, 'archetypes'> & {\n readonly archetypes: readonly {\n readonly slug: string;\n readonly convention: string;\n readonly eventKinds?: readonly number[];\n }[];\n}): InstalledNappletRecord {\n return Object.freeze({\n ...record,\n archetypes: Object.freeze(record.archetypes.map((archetype) => Object.freeze({\n ...archetype,\n ...(archetype.eventKinds === undefined ? {} : { eventKinds: Object.freeze([...archetype.eventKinds]) }),\n }))),\n });\n}\n","/**\n * Browser-owned retained NAP-INTENT target lifecycle policy.\n *\n * Retention is intentionally independent from browser frames. The host supplies\n * generation creation/reuse, source-bound readiness, current-generation checks,\n * and delivery. This controller freezes responsibility before an accepted\n * result, then starts that policy only afterward.\n *\n * @packageDocumentation\n */\n\nimport type {\n IntentRetentionParams,\n IntentRetainedDelivery,\n IntentTargetController,\n} from '@kehto/services';\n\n/** Opaque current target generation controlled by the browser host. */\nexport interface BrowserIntentGeneration {\n /** Host-owned stable identifier for one target generation. */\n readonly id: string;\n}\n\n/** Terminal reasons exposed only to host observability and cleanup policy. */\nexport type BrowserIntentTerminalReason =\n | 'open-failed'\n | 'ready-failed'\n | 'no-current-target'\n | 'send-failed';\n\n/** Browser lifecycle callbacks injected by the Paja host. */\nexport interface BrowserIntentControllerOptions {\n /** Open a compatible target or reuse its current generation. */\n openOrReuse(\n params: IntentRetentionParams,\n attempt: number,\n ): BrowserIntentGeneration | null | Promise<BrowserIntentGeneration | null>;\n /** Await source-bound NAP-SHELL readiness for a selected generation. */\n waitForReady(generation: BrowserIntentGeneration): void | Promise<void>;\n /** Return true only while the generation remains the selected current target. */\n isCurrent(generation: BrowserIntentGeneration): boolean | Promise<boolean>;\n /** Send the retained delivery to the current ready generation exactly once. */\n send(\n generation: BrowserIntentGeneration,\n delivery: IntentRetentionParams['delivery'],\n ): void | Promise<void>;\n /** Maximum open/replacement attempts after acceptance. Finite values clamp to 1–10; defaults to two. */\n maxAttempts?: number;\n /** Observe terminal post-acceptance policy without producing another result. */\n onTerminal?(params: IntentRetentionParams, reason: BrowserIntentTerminalReason): void;\n}\n\nconst MAX_INTENT_DELIVERY_ATTEMPTS = 10;\n\n/**\n * Retains immutable delivery responsibility before the intent service accepts.\n *\n * It has no public lifecycle state: host callbacks own generation identity,\n * readiness, reuse, and replacement. A returned task is inert until its\n * `start()` method is invoked by the intent service after sending acceptance.\n */\nexport class BrowserIntentController implements IntentTargetController {\n private readonly maxAttempts: number;\n\n constructor(private readonly options: BrowserIntentControllerOptions) {\n this.maxAttempts = normalizeAttempts(options.maxAttempts);\n }\n\n retain(params: IntentRetentionParams): IntentRetainedDelivery {\n const retained = freezeRetention(params);\n let started: Promise<void> | undefined;\n let delivered = false;\n\n return {\n start: () => {\n started ??= this.start(retained, () => delivered, () => { delivered = true; });\n return started;\n },\n };\n }\n\n private async start(\n params: IntentRetentionParams,\n isDelivered: () => boolean,\n markDelivered: () => void,\n ): Promise<void> {\n let reason: BrowserIntentTerminalReason = 'no-current-target';\n for (let attempt = 1; attempt <= this.maxAttempts; attempt += 1) {\n let generation: BrowserIntentGeneration | null;\n try {\n generation = await this.options.openOrReuse(params, attempt);\n } catch {\n reason = 'open-failed';\n continue;\n }\n if (!generation) {\n reason = 'open-failed';\n continue;\n }\n try {\n await this.options.waitForReady(generation);\n } catch {\n reason = 'ready-failed';\n continue;\n }\n if (!await this.options.isCurrent(generation)) {\n reason = 'no-current-target';\n continue;\n }\n if (isDelivered()) return;\n markDelivered();\n try {\n await this.options.send(generation, params.delivery);\n return;\n } catch {\n this.options.onTerminal?.(params, 'send-failed');\n return;\n }\n }\n this.options.onTerminal?.(params, reason);\n }\n}\n\nfunction normalizeAttempts(value: number | undefined): number {\n if (value === undefined) return 2;\n if (!Number.isFinite(value)) throw new TypeError('maxAttempts must be finite');\n return Math.min(MAX_INTENT_DELIVERY_ATTEMPTS, Math.max(1, Math.floor(value)));\n}\n\nfunction freezeRetention(params: IntentRetentionParams): IntentRetentionParams {\n if (!params || typeof params.handler !== 'string' || params.handler.length === 0) {\n throw new TypeError('Intent retention requires a handler');\n }\n const delivery = freezeValue({ ...params.delivery }) as IntentRetentionParams['delivery'];\n const behavior = params.behavior === undefined\n ? undefined\n : freezeValue({ ...params.behavior }) as NonNullable<IntentRetentionParams['behavior']>;\n return Object.freeze({\n handler: params.handler,\n delivery,\n ...(behavior === undefined ? {} : { behavior }),\n });\n}\n\nfunction freezeValue<T>(value: T, seen = new WeakMap<object, unknown>()): T {\n if (typeof value !== 'object' || value === null) return value;\n const existing = seen.get(value);\n if (existing !== undefined) return existing as T;\n if (Array.isArray(value)) {\n const copy: unknown[] = [];\n seen.set(value, copy);\n for (const item of value) copy.push(freezeValue(item, seen));\n return Object.freeze(copy) as T;\n }\n const copy: Record<string, unknown> = {};\n seen.set(value, copy);\n for (const [key, item] of Object.entries(value)) copy[key] = freezeValue(item, seen);\n return Object.freeze(copy) as T;\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';\nimport { probeTargetCors } from './target-cors.js';\n\n/** Options for starting the Paja local HTTP server. */\nexport interface PajaServerOptions {\n /** Raw options accepted by Paja; config-file references are resolved before serving. */\n readonly options: PajaRawOptions;\n /** Clock override used for deterministic host config in tests. */\n readonly now?: Date;\n}\n\n/** Running Paja server handle. */\nexport interface PajaServer {\n /** Runtime URL where the Paja host page is served. */\n readonly url: string;\n /** Current host-page config. */\n readonly hostConfig: PajaHostConfig;\n /** Update the target iframe URL without restarting the server. */\n updateTargetUrl(targetUrl: string): PajaHostConfig;\n /** Stop the HTTP server. */\n close(): Promise<void>;\n}\n\n/**\n * Start the local Paja development HTTP server.\n *\n * @param input - Raw options and optional clock override.\n * @returns Running server handle.\n */\nexport async function startPajaServer(input: PajaServerOptions): Promise<PajaServer> {\n const rawOptions = resolvePajaRawOptions(input.options);\n const options = normalizePajaOptions(rawOptions);\n const createdAt = input.now ?? new Date();\n let hostConfig = createPajaHostConfig(options, createdAt);\n let html = renderPajaHtml(hostConfig);\n let configJson = JSON.stringify(hostConfig, null, 2);\n let currentOptions = options;\n\n const setHostConfig = (nextOptions: PajaOptions): PajaHostConfig => {\n currentOptions = nextOptions;\n hostConfig = createPajaHostConfig(currentOptions, createdAt);\n html = renderPajaHtml(hostConfig);\n configJson = JSON.stringify(hostConfig, null, 2);\n return hostConfig;\n };\n\n const handleRequest = async (requestUrl: string, response: HttpResponse): Promise<void> => {\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/target.html') {\n const targetHtml = await fetchTargetHtml(hostConfig.target.url);\n response.writeHead(200, {\n 'cache-control': 'no-store',\n 'content-type': 'text/html; charset=utf-8',\n });\n response.end(targetHtml);\n return;\n }\n\n if (requestUrl === '/__kehto/target-cors.json') {\n const diagnostic = await probeTargetCors(hostConfig.target.url);\n response.writeHead(200, {\n 'cache-control': 'no-store',\n 'content-type': 'application/json; charset=utf-8',\n });\n response.end(JSON.stringify(diagnostic));\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 const server = createServer((request, response) => {\n void handleRequest(request.url ?? '/', response).catch((error) => {\n const message = error instanceof Error ? error.message : String(error);\n response.writeHead(502, { 'content-type': 'text/plain; charset=utf-8' });\n response.end(message);\n });\n });\n\n await listen(server, options.host, options.port);\n const servedOptions = withBoundPort(options, getBoundPort(server, options.port));\n setHostConfig(servedOptions);\n\n return {\n url: formatPajaUrl(servedOptions),\n get hostConfig() {\n return hostConfig;\n },\n updateTargetUrl(targetUrl) {\n return setHostConfig(withTargetUrl(currentOptions, targetUrl));\n },\n close: () => close(server),\n };\n}\n\nfunction readBrowserHostScript(): string {\n return readFileSync(new URL('./browser-host.js', import.meta.url), 'utf8');\n}\n\nasync function fetchTargetHtml(targetUrl: string): Promise<string> {\n const response = await fetch(targetUrl, {\n headers: {\n accept: 'text/html, application/xhtml+xml;q=0.9, */*;q=0.8',\n },\n });\n if (!response.ok) {\n throw new Error(`Target ${targetUrl} returned ${response.status} ${response.statusText}`);\n }\n return response.text();\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 const forceClose = setTimeout(() => {\n server.closeAllConnections?.();\n }, 500);\n server.close((error?: Error) => {\n clearTimeout(forceClose);\n if (error) {\n reject(error);\n return;\n }\n resolve();\n });\n server.closeIdleConnections?.();\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 closeAllConnections?(): void;\n closeIdleConnections?(): void;\n address(): string | { port: number } | null;\n}\n\ninterface HttpResponse {\n writeHead(statusCode: number, headers: Record<string, string>): void;\n end(chunk: string): void;\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\nfunction withTargetUrl(options: PajaOptions, targetUrl: string): PajaOptions {\n const url = normalizeServerTargetUrl(targetUrl);\n return url === options.targetUrl ? options : { ...options, targetUrl: url };\n}\n\nfunction normalizeServerTargetUrl(value: string): string {\n const raw = value.trim();\n let parsed: URL;\n try {\n parsed = new URL(raw);\n } catch {\n throw new Error(`Invalid managed target URL \"${raw}\". Expected an absolute http(s) URL.`);\n }\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n throw new Error(`Invalid managed target URL \"${raw}\". Only http: and https: URLs are supported.`);\n }\n return parsed.href;\n}\n","/**\n * Target dev-server CORS diagnostics.\n *\n * Paja loads the napplet target into a `srcdoc` iframe sandboxed without\n * `allow-same-origin`, so the napplet document has an opaque origin and sends\n * `Origin: null` on every subresource fetch. `<script type=\"module\">` is always\n * fetched in CORS mode, so a dev server that does not allow the `null` origin\n * blocks the napplet's entry module and the iframe renders blank.\n *\n * These helpers probe the target with an explicit `Origin: null` request so\n * Paja can report the cause instead of leaving an empty frame behind.\n */\n\n/** Whether the target dev server will serve the sandboxed frame's subresources. */\nexport type PajaTargetCorsStatus = 'allowed' | 'blocked' | 'unreachable';\n\n/** Result of probing a target dev server for opaque-origin CORS support. */\nexport interface PajaTargetCorsDiagnostic {\n /** Classification of the probe result. */\n readonly status: PajaTargetCorsStatus;\n /** Target URL that was probed. */\n readonly targetUrl: string;\n /** `access-control-allow-origin` value the target returned, when any. */\n readonly allowOrigin: string | null;\n /** Human-readable explanation of the classification. */\n readonly detail: string;\n /** Actionable remedy, present only when `status` is not `allowed`. */\n readonly hint: string | null;\n}\n\n/** Remedy shown whenever the target rejects the sandboxed frame's `null` origin. */\nexport const PAJA_TARGET_CORS_HINT =\n \"Paja sandboxes the napplet frame without allow-same-origin, so its assets are requested with `Origin: null`. \"\n + \"Allow that origin in the napplet dev server, e.g. Vite `server: { cors: { origin: '*' } }`.\";\n\n/**\n * Classify an `access-control-allow-origin` response value for an opaque origin.\n *\n * @param targetUrl - Target URL the header came from.\n * @param allowOrigin - Raw `access-control-allow-origin` header value, or `null` when absent.\n * @returns Diagnostic describing whether the sandboxed frame can load assets.\n * @example\n * ```ts\n * classifyTargetCors('http://127.0.0.1:5173/', '*').status; // 'allowed'\n * classifyTargetCors('http://127.0.0.1:5173/', null).status; // 'blocked'\n * ```\n */\nexport function classifyTargetCors(\n targetUrl: string,\n allowOrigin: string | null,\n): PajaTargetCorsDiagnostic {\n const value = allowOrigin?.trim() ?? null;\n if (value === '*' || value === 'null') {\n return {\n status: 'allowed',\n targetUrl,\n allowOrigin: value,\n detail: `Target allows the sandboxed frame's null origin (access-control-allow-origin: ${value}).`,\n hint: null,\n };\n }\n if (value === null || value === '') {\n return {\n status: 'blocked',\n targetUrl,\n allowOrigin: null,\n detail: 'Target sent no access-control-allow-origin for an Origin: null request.',\n hint: PAJA_TARGET_CORS_HINT,\n };\n }\n return {\n status: 'blocked',\n targetUrl,\n allowOrigin: value,\n detail: `Target only allows origin \"${value}\", not the sandboxed frame's null origin.`,\n hint: PAJA_TARGET_CORS_HINT,\n };\n}\n\n/** Minimal fetch surface the probe depends on. */\nexport type PajaTargetCorsFetch = (\n input: string,\n init: { method: string; headers: Record<string, string> },\n) => Promise<{ headers: { get(name: string): string | null } }>;\n\nconst defaultTargetCorsFetch: PajaTargetCorsFetch = (input, init) => fetch(input, init);\n\n/**\n * Probe a target dev server for opaque-origin CORS support.\n *\n * Sends `Origin: null` explicitly — a browser cannot forge that header, but the\n * Paja server can, which is why the probe runs server-side.\n *\n * @param targetUrl - Absolute target URL served by the napplet dev server.\n * @param fetchImpl - Fetch implementation; defaults to the global `fetch`.\n * @returns Diagnostic describing whether the sandboxed frame can load assets.\n * @example\n * ```ts\n * const diagnostic = await probeTargetCors('http://127.0.0.1:5173/');\n * if (diagnostic.status === 'blocked') console.warn(diagnostic.hint);\n * ```\n */\nexport async function probeTargetCors(\n targetUrl: string,\n fetchImpl: PajaTargetCorsFetch = defaultTargetCorsFetch,\n): Promise<PajaTargetCorsDiagnostic> {\n try {\n const response = await fetchImpl(targetUrl, {\n method: 'GET',\n headers: {\n origin: 'null',\n accept: 'text/html, application/xhtml+xml;q=0.9, */*;q=0.8',\n },\n });\n return classifyTargetCors(targetUrl, response.headers.get('access-control-allow-origin'));\n } catch (error) {\n return {\n status: 'unreachable',\n targetUrl,\n allowOrigin: null,\n detail: `Target CORS probe failed: ${error instanceof Error ? error.message : String(error)}`,\n hint: 'Confirm the napplet dev server is running and --target-url points at it.',\n };\n }\n}\n"],"mappings":"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","names":["escapeAttribute","resolve","resolve","copy","readFileSync","readFileSync","resolve"]}
1
+ {"version":3,"sources":["../src/config-file.ts","../src/simulation.ts","../src/options.ts","../src/host-page.ts","../src/runtime-resolver.ts","../src/parity.ts","../src/readiness.ts","../src/installed-napplet-catalog.ts","../src/browser-intent-controller.ts","../src/server.ts","../src/target-cors.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\n/**\n * Load a JSON Paja config file from disk.\n *\n * @param configPath - Path to a JSON config file.\n * @returns Raw options parsed from the config file.\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\n/**\n * Resolve raw options by merging an optional config file with explicit values.\n *\n * @param raw - CLI/config options, optionally including `configPath`.\n * @returns Raw options with config-file defaults applied.\n */\nexport function resolvePajaRawOptions(raw: PajaRawOptions): PajaRawOptions {\n if (!raw.configPath?.trim()) return raw;\n return mergePajaRawOptions(loadPajaConfigFile(raw.configPath), raw);\n}\n\n/**\n * Merge two raw Paja option objects, with override values taking precedence.\n *\n * @param base - Base options, usually from a config file.\n * @param override - Explicit options, usually from CLI args.\n * @returns Merged raw options.\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","/** JSON primitive accepted in Paja simulation config values. */\nexport type JsonPrimitive = string | number | boolean | null;\n/** JSON value accepted in Paja simulation config values. */\nexport type JsonValue = JsonPrimitive | JsonValue[] | { readonly [key: string]: JsonValue };\n/** JSON object used for Paja simulation fixtures and config/theme values. */\nexport type JsonRecord = Record<string, JsonValue>;\n\n/** Capability domain names Paja can advertise or disable. */\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 | 'count'\n | 'link'\n | 'common'\n | 'lists'\n | 'serial'\n | 'ble'\n | 'webrtc'\n | 'cvm'\n | 'inc';\n\n/** Raw simulation controls accepted from CLI args or JSON config. */\nexport interface PajaSimulationRawOptions {\n /** Per-domain capability overrides. */\n readonly capabilities?: {\n readonly domains?: Partial<Record<PajaCapabilityDomain, boolean>>;\n };\n /** ACL behavior mode for simulated services. */\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?: 'live' | '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' | 'blossom' | 'disabled';\n readonly rail?: string;\n readonly servers?: readonly string[];\n readonly discoverServers?: boolean;\n readonly maxBytes?: number;\n readonly mimeTypes?: readonly 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\n/** Fully normalized Paja simulation model served to the browser host. */\nexport interface PajaSimulation {\n /** Capability domains and disabled-domain summary. */\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: 'live' | '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' | 'blossom' | 'disabled';\n readonly rail?: string;\n readonly servers: readonly string[];\n readonly discoverServers: boolean;\n readonly maxBytes?: number;\n readonly mimeTypes?: readonly 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\n/** Thrown when Paja simulation options are internally inconsistent. */\nexport class PajaSimulationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'PajaSimulationError';\n }\n}\n\n/** Capability domains exposed by Paja simulation controls. */\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 'count',\n 'link',\n 'common',\n 'lists',\n 'serial',\n 'ble',\n 'webrtc',\n 'cvm',\n 'inc',\n];\n\nconst DEFAULT_RELAY_URLS = [\n 'wss://relay.damus.io',\n 'wss://nos.lol',\n 'wss://relay.primal.net',\n 'wss://relay.snort.social',\n] 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\n/**\n * Normalize raw simulation options into a complete deterministic model.\n *\n * @param raw - Partial simulation options from CLI args or config.\n * @returns Complete simulation model.\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 ? 'live' : '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 if (!domains.relay) domains.count = 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 !== 'disabled' && relayUrls.length === 0) {\n throw new PajaSimulationError('Invalid simulation: relay.urls must contain at least one URL when relay.mode is enabled.');\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 const uploadServers = normalizeUploadServers(raw?.upload?.servers ?? []);\n const discoverServers = raw?.upload?.discoverServers ?? uploadMode === 'blossom';\n const maxBytes = raw?.upload?.maxBytes;\n if (maxBytes !== undefined && (!Number.isSafeInteger(maxBytes) || maxBytes <= 0)) {\n throw new PajaSimulationError('Invalid simulation: upload.maxBytes must be a positive safe integer.');\n }\n const mimeTypes = normalizeMimeTypes(raw?.upload?.mimeTypes);\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 ...(uploadMode === 'memory' ? { rail: uploadRail } : {}),\n servers: uploadServers,\n discoverServers,\n ...(maxBytes !== undefined ? { maxBytes } : {}),\n ...(mimeTypes ? { mimeTypes } : {}),\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\n/**\n * Format a compact, human-readable simulation summary.\n *\n * @param simulation - Normalized simulation model.\n * @returns One-line summary used by CLI and host-page chrome.\n */\nexport function summarizePajaSimulation(simulation: PajaSimulation): string {\n const relay = simulation.relay.mode === 'disabled' ? 'relay:off' : `relay:${simulation.relay.mode}:${simulation.relay.urls.length}`;\n const identity = simulation.identity.mode === 'fixed' ? 'identity:fixed' : 'identity:anon';\n const storage = `storage:${simulation.storage.mode}`;\n const upload = simulation.upload.mode === 'memory'\n ? 'upload:memory:simulator'\n : simulation.upload.mode === 'blossom'\n ? `upload:blossom:${simulation.upload.servers.length}`\n : 'upload:off';\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} ${upload} ${theme} ${disabled}`;\n}\n\n/** Normalize an ordered list of shell-owned Blossom server base URLs. */\nexport function normalizeUploadServers(servers: readonly string[]): string[] {\n const normalized: string[] = [];\n for (const value of servers) {\n if (typeof value !== 'string' || value.trim().length === 0) {\n throw new PajaSimulationError('Invalid simulation: upload.servers entries must be non-empty URLs.');\n }\n let url: URL;\n try {\n url = new URL(value.trim());\n } catch {\n throw new PajaSimulationError(`Invalid simulation: upload server \"${value}\" is not a valid URL.`);\n }\n if (url.username || url.password) {\n throw new PajaSimulationError('Invalid simulation: upload server URLs must not contain credentials.');\n }\n if (url.protocol !== 'https:' && !(url.protocol === 'http:' && isLoopbackHost(url.hostname))) {\n throw new PajaSimulationError('Invalid simulation: upload servers require HTTPS, except loopback HTTP for development.');\n }\n if (url.search || url.hash) {\n throw new PajaSimulationError('Invalid simulation: upload server URLs must not contain a query or fragment.');\n }\n const result = url.href.replace(/\\/+$/, '');\n if (!normalized.includes(result)) normalized.push(result);\n }\n return normalized;\n}\n\nfunction isLoopbackHost(hostname: string): boolean {\n return hostname === 'localhost'\n || hostname === '[::1]'\n || /^127(?:\\.\\d{1,3}){3}$/.test(hostname);\n}\n\nfunction normalizeMimeTypes(mimeTypes: readonly string[] | undefined): string[] | undefined {\n if (mimeTypes === undefined) return undefined;\n const normalized: string[] = [];\n for (const value of mimeTypes) {\n if (typeof value !== 'string' || value.trim().length === 0) {\n throw new PajaSimulationError('Invalid simulation: upload.mimeTypes entries must be non-empty strings.');\n }\n const mimeType = value.trim();\n if (!normalized.includes(mimeType)) normalized.push(mimeType);\n }\n return normalized;\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\n/** Command configuration for a managed Paja target process. */\nexport type PajaCommand =\n /** Spawn an executable with argv preserved exactly after `--`. */\n | { readonly mode: 'argv'; readonly argv: readonly string[] }\n /** Run a shell command string. */\n | { readonly mode: 'shell'; readonly command: string };\n\n/** Raw, unnormalized options accepted from CLI arguments or config files. */\nexport interface PajaRawOptions {\n /** App dev-server URL that Paja should load. */\n readonly targetUrl?: string;\n /** Optional managed command to start before serving Paja. */\n readonly command?: PajaCommand;\n /** Hostname or IP address for the Paja HTTP server. */\n readonly host?: string;\n /** Runtime HTTP port. */\n readonly port?: number | string;\n /** Target readiness timeout in milliseconds. */\n readonly readyTimeoutMs?: number | string;\n /** Optional JSON config file path. */\n readonly configPath?: string;\n /** Simulation controls for injected shell domains. */\n readonly simulation?: PajaSimulationRawOptions;\n}\n\n/** Paja target loading mode. */\nexport type PajaTargetMode = 'iframe-url' | 'runtime-pointer';\n/** Hot-module-reload strategy for the hosted target. */\nexport type PajaHmrStrategy = 'iframe-target-url' | 'none';\n\n/** Runtime-pointer resolution config embedded into the Paja host page. */\nexport interface PajaPointerRuntimeConfig {\n /** Optional naddr/nevent pointer to resolve at boot. */\n readonly value?: string;\n /** Relay hints used to resolve the pointer. */\n readonly relays: readonly string[];\n /** Blossom server hints used for artifact blob fetches. */\n readonly blossomServers: readonly string[];\n /** Maximum pointer-resolution wait in milliseconds. */\n readonly maxWaitMs: number;\n}\n\n/** Normalized Paja runtime options. */\nexport interface PajaOptions {\n /** Absolute target URL for iframe-url mode. */\n readonly targetUrl: string;\n /** Optional managed target command. */\n readonly command?: PajaCommand;\n /** Paja server host. */\n readonly host: string;\n /** Paja server port. */\n readonly port: number;\n /** Target readiness timeout in milliseconds. */\n readonly readyTimeoutMs: number;\n /** Optional config path retained for host diagnostics. */\n readonly configPath?: string;\n /** Normalized simulation model. */\n readonly simulation: PajaSimulation;\n /** Whether Paja owns a managed command or attaches to an external target. */\n readonly mode: 'external-target' | 'managed-command';\n}\n\n/** Serialized host-page config served to the browser runtime. */\nexport interface PajaHostConfig {\n /** Config schema version. */\n readonly version: 1;\n /** Window identity used for the development target. */\n readonly window: {\n readonly id: string;\n readonly dTag: string;\n readonly aggregateHash: string;\n };\n readonly target: {\n readonly mode: PajaTargetMode;\n readonly url: string;\n readonly hmrStrategy: PajaHmrStrategy;\n readonly command?: PajaCommand;\n readonly pointer?: PajaPointerRuntimeConfig;\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\n/** Thrown when raw Paja options cannot be normalized. */\nexport class PajaOptionsError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'PajaOptionsError';\n }\n}\n\n/** Default loopback host for the Paja HTTP server. */\nexport const DEFAULT_PAJA_HOST = '127.0.0.1';\n/** Default Paja HTTP port. */\nexport const DEFAULT_PAJA_PORT = 5197;\n/** Default readiness timeout for the target URL. */\nexport const DEFAULT_READY_TIMEOUT_MS = 30_000;\n/** Default development window id used in host config. */\nexport const DEFAULT_PAJA_WINDOW_ID = 'kehto-paja-window';\n/** Default development `d` tag used for target identity. */\nexport const DEFAULT_PAJA_DTAG = 'dev-target';\n/** Default development aggregate hash used for target identity. */\nexport const DEFAULT_PAJA_AGGREGATE_HASH = 'paja';\n/** Default pointer resolution wait in runtime-pointer mode. */\nexport const DEFAULT_PAJA_RUNTIME_WAIT_MS = 5_000;\n\n/**\n * Normalize raw CLI/config options into a validated Paja runtime config.\n *\n * @param raw - Raw options from CLI parsing or a config file.\n * @returns Fully normalized runtime options.\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\n/**\n * Create browser host-page config for iframe-url mode.\n *\n * @param options - Normalized Paja options.\n * @param now - Clock value used for reload token and timestamps.\n * @returns Serializable host-page config.\n */\nexport function createPajaHostConfig(\n options: PajaOptions,\n now: Date = new Date(),\n): PajaHostConfig {\n const base = createPajaHostConfigBase(options.simulation);\n return {\n ...base,\n target: {\n mode: 'iframe-url',\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 };\n}\n\n/**\n * Create browser host-page config for runtime-pointer mode.\n *\n * @param options - Pointer, relay, and Blossom hints.\n * @param now - Clock value used for reload token and timestamps.\n * @returns Serializable host-page config.\n */\nexport function createPajaRuntimeHostConfig(\n options: {\n readonly pointer?: string;\n readonly relays?: readonly string[];\n readonly blossomServers?: readonly string[];\n readonly maxWaitMs?: number;\n } = {},\n now: Date = new Date(),\n): PajaHostConfig {\n const base = createPajaHostConfigBase(normalizePajaSimulation({}));\n return {\n ...base,\n target: {\n mode: 'runtime-pointer',\n url: 'about:blank',\n hmrStrategy: 'none',\n pointer: {\n ...(options.pointer ? { value: options.pointer } : {}),\n relays: [...(options.relays ?? [])],\n blossomServers: [...(options.blossomServers ?? [])],\n maxWaitMs: normalizePositiveInteger(\n options.maxWaitMs ?? DEFAULT_PAJA_RUNTIME_WAIT_MS,\n 'runtime-wait',\n ),\n },\n },\n runtime: {\n host: 'static',\n port: 0,\n readyTimeoutMs: 1,\n reloadToken: createReloadToken(now),\n createdAt: now.toISOString(),\n },\n };\n}\n\n/**\n * Format the local Paja runtime URL for display and CLI output.\n *\n * @param options - Host and port pair.\n * @returns HTTP URL for the Paja runtime.\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 createPajaHostConfigBase(simulation: PajaSimulation): Pick<PajaHostConfig, 'version' | 'window' | 'chrome' | 'simulation'> {\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 chrome: {\n topBar: true,\n bottomBar: true,\n sidePanels: false,\n },\n simulation,\n };\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\n/**\n * Render the browser host page for a Paja runtime config.\n *\n * @param config - Serializable host-page config.\n * @returns Complete HTML document served by Paja.\n */\nexport function renderPajaHtml(config: PajaHostConfig): string {\n const configJson = escapeJsonForHtml(JSON.stringify(config));\n const targetLabel = escapeAttribute(getTargetLabel(config));\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 --paja-console-column: minmax(320px, 380px);\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 { display: grid; grid-template-columns: var(--paja-console-column) minmax(0, 1fr); align-items: stretch; gap: 0; padding: 0; border-bottom: 1px solid var(--line); }\n .top-console { min-width: 0; display: flex; align-items: center; gap: 14px; padding: 0 12px; border-right: 1px solid var(--line); }\n .top-stage { min-width: 0; display: flex; align-items: stretch; gap: 14px; padding: 0 12px 0 0; overflow: hidden; }\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 .brand-product { color: var(--text); }\n .target { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); }\n .spacer { flex: 1; min-width: 0; }\n .tabs { display: flex; align-items: stretch; align-self: flex-end; gap: 4px; min-width: 120px; max-width: min(100%, 760px); overflow-x: auto; scrollbar-width: thin; }\n .tabs:empty { display: none; }\n .tab { min-width: 116px; max-width: 240px; height: 30px; display: grid; grid-template-columns: minmax(0, 1fr) 24px 24px; align-items: center; gap: 2px; border: 1px solid var(--line); border-bottom-color: transparent; background: #151815; color: var(--muted); border-radius: 5px 5px 0 0; padding: 0 2px 0 9px; }\n .tab[data-active=\"true\"] { color: var(--text); border-color: var(--accent); border-bottom-color: #151815; background: #20241f; }\n .tab-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; text-align: left; }\n .tab-share, .tab-close { width: 20px; height: 20px; padding: 0; border: 0; background: transparent; color: var(--muted); display: inline-grid; place-items: center; }\n .tab-share:hover, .tab-close:hover { color: var(--text); background: #2d302b; border-color: transparent; }\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, input { border: 1px solid var(--line); color: var(--text); background: #20241f; height: 26px; border-radius: 4px; font: inherit; }\n main { min-height: 0; display: grid; grid-template-columns: var(--paja-console-column) minmax(0, 1fr); }\n .console { min-height: 0; overflow: auto; border-right: 1px solid var(--line); background: #121512; padding: 10px; display: flex; flex-direction: column; gap: 12px; }\n .section { display: grid; gap: 8px; }\n .section-title { color: var(--accent); font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0; }\n .switch-grid, .acl-grid { display: flex; flex-wrap: wrap; gap: 6px; }\n .toggle { height: 24px; padding: 0 8px; color: var(--muted); }\n .toggle[data-enabled=\"true\"] { color: var(--text); border-color: #5f724f; background: #24301f; }\n .toggle[data-enabled=\"false\"] { color: #8d9187; border-color: #453536; background: #241d1d; }\n .signer { color: var(--muted); word-break: break-all; font-size: 12px; }\n .signer-controls { display: grid; grid-template-columns: auto auto minmax(0, 1fr) auto; gap: 6px; }\n .signer-controls button[data-active=\"true\"] { border-color: var(--accent); color: var(--text); background: #2a2a1d; }\n .signer-controls input { min-width: 0; padding: 0 8px; }\n .pointer-controls { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 6px; }\n .pointer-status { min-width: 0; color: var(--muted); font-size: 12px; overflow-wrap: anywhere; }\n .log-tools { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 6px; }\n .log-list { min-height: 160px; max-height: 38vh; overflow: auto; border: 1px solid var(--line); border-radius: 4px; background: #0b0d0b; }\n .log-row { display: grid; grid-template-columns: 88px minmax(0, 1fr); gap: 6px; padding: 5px 7px; border-bottom: 1px solid #1b1f1a; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11px; }\n .log-row[data-error=\"true\"] { background: #1d1414; }\n .log-row:last-child { border-bottom: 0; }\n .log-dir { color: var(--muted); }\n .log-body { min-width: 0; display: grid; gap: 2px; }\n .log-type { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .log-detail { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #e6a5a5; }\n .stage { min-width: 0; min-height: 0; position: relative; background: #050705; }\n .empty-stage { position: absolute; inset: 0; display: grid; place-items: center; color: var(--muted); font-size: 12px; }\n .empty-stage[hidden] { display: none; }\n .tab-panel { position: absolute; inset: 0; min-width: 0; min-height: 0; }\n .tab-panel[hidden] { display: none; }\n iframe { width: 100%; height: 100%; border: 0; background: white; display: block; }\n code { color: var(--text); }\n .dialog-backdrop { position: fixed; inset: 0; z-index: 20; display: grid; place-items: center; padding: 24px; background: rgb(0 0 0 / 0.58); }\n .dialog-backdrop[hidden] { display: none; }\n .dialog { width: min(420px, 100%); border: 1px solid var(--line); border-radius: 6px; background: #181b19; box-shadow: 0 18px 60px rgb(0 0 0 / 0.45); padding: 16px; display: grid; gap: 14px; }\n .dialog-title { font-weight: 700; color: var(--text); }\n .dialog-actions { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: 8px; }\n @media (max-width: 900px) {\n .top { grid-template-columns: minmax(0, 1fr); }\n .top-console { display: none; }\n .top-stage { padding-left: 0; }\n main { grid-template-columns: 1fr; grid-template-rows: minmax(240px, 40vh) minmax(0, 1fr); }\n .console { border-right: 0; border-bottom: 1px solid var(--line); }\n }\n </style>\n </head>\n <body>\n <header class=\"bar top\">\n <div class=\"top-console\">\n <div class=\"brand\">@kehto/<span class=\"brand-product\">paja</span></div>\n <div class=\"target\" title=\"${targetLabel}\">${targetLabel}</div>\n </div>\n <div class=\"top-stage\">\n <div class=\"tabs\" id=\"napplet-tabs\" role=\"tablist\" aria-label=\"Loaded napplets\"></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 </div>\n </header>\n <main>\n <aside class=\"console\" aria-label=\"Paja development controls\">\n ${renderPointerControls(config)}\n <section class=\"section\">\n <div class=\"section-title\">Interfaces</div>\n <div class=\"switch-grid\" id=\"interface-toggles\"></div>\n </section>\n <section class=\"section\">\n <div class=\"section-title\">ACL</div>\n <div class=\"acl-grid\" id=\"acl-controls\"></div>\n </section>\n <section class=\"section\">\n <div class=\"section-title\">Signer</div>\n <div class=\"signer\" id=\"signer-status\">loading</div>\n <div class=\"signer-controls\" id=\"signer-controls\"></div>\n </section>\n <section class=\"section\">\n <div class=\"section-title\">Messages</div>\n <div class=\"log-tools\">\n <input id=\"message-filter\" type=\"search\" autocomplete=\"off\" placeholder=\"filter messages\" aria-label=\"Filter message log\">\n <button type=\"button\" id=\"clear-log\">Clear</button>\n </div>\n <div class=\"log-list\" id=\"message-log\" aria-live=\"polite\"></div>\n </section>\n </aside>\n ${renderStage(config, targetLabel)}\n </main>\n ${renderDuplicateDialog()}\n <footer class=\"bar bottom\">\n <span>mode: <code>${escapeHtml(getModeLabel(config))}</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 renderStage(config: PajaHostConfig, targetLabel: string): string {\n if (config.target.mode === 'runtime-pointer') {\n return `<section class=\"stage\" id=\"napplet-stage\" aria-label=\"Loaded napplet runtimes\">\n <div class=\"empty-stage\" id=\"empty-runtime-stage\">Load a napplet pointer to start a runtime tab.</div>\n </section>`;\n }\n return `<section class=\"stage\" id=\"napplet-stage\">\n <iframe id=\"napplet-frame\" title=\"Napplet development target\" sandbox=\"allow-scripts\" data-target-url=\"${targetLabel}\"></iframe>\n </section>`;\n}\n\nfunction renderDuplicateDialog(): string {\n return `<div class=\"dialog-backdrop\" id=\"duplicate-pointer-dialog\" hidden>\n <div class=\"dialog\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"duplicate-pointer-title\">\n <div class=\"dialog-title\" id=\"duplicate-pointer-title\">this napplet is already running.</div>\n <div class=\"dialog-actions\">\n <button type=\"button\" id=\"duplicate-load-again\">load it again</button>\n <button type=\"button\" id=\"duplicate-open-tab\">open it in tab</button>\n <button type=\"button\" id=\"duplicate-cancel\">cancel</button>\n </div>\n </div>\n </div>`;\n}\n\nfunction renderPointerControls(config: PajaHostConfig): string {\n if (config.target.mode !== 'runtime-pointer') return '';\n const value = escapeAttribute(config.target.pointer?.value ?? '');\n return `<section class=\"section\" id=\"runtime-pointer-section\">\n <div class=\"section-title\">Pointer</div>\n <form class=\"pointer-controls\" id=\"runtime-pointer-form\">\n <input id=\"runtime-pointer-input\" type=\"text\" inputmode=\"url\" autocomplete=\"off\" spellcheck=\"false\" placeholder=\"naddr or nevent\" aria-label=\"Runtime napplet pointer\" value=\"${value}\">\n <button type=\"submit\" id=\"runtime-pointer-load\">Load</button>\n </form>\n <div class=\"pointer-status\" id=\"runtime-pointer-status\" aria-live=\"polite\">idle</div>\n </section>`;\n}\n\nfunction getModeLabel(config: PajaHostConfig): string {\n if (config.target.mode === 'runtime-pointer') return 'runtime-pointer';\n return config.target.command ? 'managed-command' : 'external-target';\n}\n\nfunction getTargetLabel(config: PajaHostConfig): string {\n if (config.target.mode === 'runtime-pointer') {\n return config.target.pointer?.value ?? 'runtime pointer';\n }\n return config.target.url;\n}\n\nfunction escapeAttribute(value: string): string {\n return escapeHtml(value).replaceAll('\"', '&quot;');\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;');\n}\n\nfunction escapeJsonForHtml(value: string): string {\n return value.replaceAll('<', '\\\\u003c');\n}\n","import type { NostrEvent } from 'nostr-tools';\nimport type { Filter } from 'nostr-tools/filter';\nimport { SimplePool } from 'nostr-tools/pool';\nimport { decode } from 'nostr-tools/nip19';\nimport {\n fetchBlob,\n isNappletManifestKind,\n NAPPLET_KIND_NAMED,\n NAPPLET_KINDS,\n openNappletArtifactCache,\n resolveNapplet,\n type ResolvedNapplet,\n} from '@kehto/nip/5d';\n\n/** Named/addressable NIP-5D napplet manifest kind (`35129`). */\nexport const PAJA_NAPPLET_MANIFEST_KIND = NAPPLET_KIND_NAMED;\n/** All NIP-5D napplet manifest kinds accepted by Paja pointers (`5129`, `15129`, `35129`). */\nexport const PAJA_NAPPLET_MANIFEST_KINDS = NAPPLET_KINDS;\n\n/** Decoded naddr/nevent pointer accepted by Paja runtime-pointer mode. */\nexport type PajaDecodedPointer =\n | {\n readonly type: 'naddr';\n readonly value: string;\n readonly identifier: string;\n readonly pubkey: string;\n readonly kind: number;\n readonly relays: readonly string[];\n }\n | {\n readonly type: 'nevent';\n readonly value: string;\n readonly id: string;\n readonly author?: string;\n readonly kind?: number;\n readonly relays: readonly string[];\n };\n\n/** Fully resolved pointer plus verified napplet artifact bytes. */\nexport interface PajaResolvedPointer {\n /** Decoded pointer input. */\n readonly pointer: PajaDecodedPointer;\n /** Manifest event resolved from relays. */\n readonly event: NostrEvent;\n /** Ordered relay URLs queried for the pointer, with embedded hints first. */\n readonly relays: readonly string[];\n /** Blossom server hints used for blob fetches. */\n readonly blossomServers: readonly string[];\n /** Resolved manifest `d` tag. */\n readonly dTag: string;\n /** Verified NIP-5A aggregate hash. */\n readonly aggregateHash: string;\n /** Verified target `/index.html` content. */\n readonly indexHtml: string;\n /** Parsed NIP-5D manifest. */\n readonly manifest: ResolvedNapplet['manifest'];\n}\n\n/** Relay-pool contract for runtime-pointer resolution. */\nexport interface PajaPointerRelayPool {\n /** Query relays synchronously for matching manifest events. */\n querySync(\n relays: string[],\n filter: Filter,\n params?: { readonly maxWait?: number; readonly label?: string; readonly id?: string },\n ): Promise<NostrEvent[]>;\n /** Subscribe until all relays reach EOSE, fail, or the shared deadline expires. */\n subscribeManyEose?(\n relays: string[],\n filter: Filter,\n params: {\n readonly maxWait?: number;\n readonly label?: string;\n readonly id?: string;\n readonly onevent: (event: NostrEvent) => void;\n readonly onclose: (reasons: string[]) => void;\n },\n ): { close(reason?: string): void | Promise<void> };\n close?(relays: string[]): void;\n destroy?(): void;\n}\n\n/** Options for resolving a Paja runtime pointer. */\nexport interface ResolvePajaPointerOptions {\n /** Relay pool override; defaults to a `nostr-tools` `SimplePool`. */\n readonly pool?: PajaPointerRelayPool;\n /** Fetch override used for Blossom blob URLs. */\n readonly fetcher?: (url: string) => Promise<Response>;\n /** Extra relay candidates appended after embedded pointer hints. */\n readonly relays?: readonly string[];\n /** Extra Blossom server hints appended during artifact fetch. */\n readonly blossomServers?: readonly string[];\n /** One overall deadline for relay connection, fanout, and EOSE in milliseconds. */\n readonly maxWaitMs?: number;\n}\n\n/**\n * Decode a NIP-19 naddr/nevent pointer for Paja runtime-pointer mode.\n *\n * @param value - NIP-19 pointer string.\n * @returns Structured pointer metadata.\n */\nexport function decodePajaPointer(value: string): PajaDecodedPointer {\n const trimmed = value.trim();\n const decoded = decode(trimmed);\n if (decoded.type === 'naddr') {\n return {\n type: 'naddr',\n value: trimmed,\n identifier: decoded.data.identifier,\n pubkey: decoded.data.pubkey,\n kind: decoded.data.kind,\n relays: [...(decoded.data.relays ?? [])],\n };\n }\n if (decoded.type === 'nevent') {\n return {\n type: 'nevent',\n value: trimmed,\n id: decoded.data.id,\n ...(decoded.data.author ? { author: decoded.data.author } : {}),\n ...(decoded.data.kind ? { kind: decoded.data.kind } : {}),\n relays: [...(decoded.data.relays ?? [])],\n };\n }\n throw new Error(`Expected naddr or nevent pointer, got ${decoded.type}.`);\n}\n\n/**\n * Resolve a Paja runtime pointer into verified napplet HTML and manifest data.\n *\n * @param value - NIP-19 naddr or nevent pointer.\n * @param options - Relay, fetch, and Blossom overrides.\n * @returns Verified napplet artifact ready for srcdoc injection.\n */\nexport async function resolvePajaPointer(\n value: string,\n options: ResolvePajaPointerOptions = {},\n): Promise<PajaResolvedPointer> {\n const pointer = decodePajaPointer(value);\n const relays = uniqueRelayUrls([...pointer.relays, ...(options.relays ?? [])]);\n if (relays.length === 0) {\n throw new Error('Pointer has no relay hints or enabled configured live relays.');\n }\n\n const pool = options.pool ?? new SimplePool();\n const ownsPool = options.pool === undefined;\n try {\n const event = await resolvePointerEvent(pointer, pool, relays, normalizeMaxWaitMs(options.maxWaitMs));\n const blossomServers = [...(options.blossomServers ?? [])];\n const resolved = await resolveNapplet({\n event,\n cache: await openNappletArtifactCache({ requireStorageEstimate: false }),\n fetchBlob: (sha256Hex, servers) =>\n fetchBlob([...servers, ...blossomServers], sha256Hex, async (url) => {\n const response = await (options.fetcher ?? fetch)(url);\n if (!response.ok) throw new Error(`[paja-runtime] blob ${url}: ${response.status}`);\n return new Uint8Array(await response.arrayBuffer());\n }),\n });\n return {\n pointer,\n event,\n relays,\n blossomServers,\n dTag: resolved.dTag,\n aggregateHash: resolved.aggregateHash,\n indexHtml: resolved.indexHtml,\n manifest: resolved.manifest,\n };\n } finally {\n if (ownsPool) {\n pool.close?.(relays);\n pool.destroy?.();\n }\n }\n}\n\n/**\n * Inject Kehto's Class-1 CSP for verified runtime-pointer srcdoc output.\n * NIP-5D mandates the verified srcdoc and opaque sandbox, but this baseline CSP\n * is Kehto policy rather than a protocol requirement.\n *\n * @param html - Verified target HTML.\n * @param origins - Origins the resolved target may connect to.\n * @returns HTML with a CSP meta tag inserted.\n */\nexport function injectPajaRuntimeCsp(html: string, origins: readonly string[]): string {\n const grantedOrigins = [...new Set(origins)].sort();\n const connectSrc = grantedOrigins.length > 0\n ? `connect-src ${grantedOrigins.join(' ')}`\n : \"connect-src 'none'\";\n const value = [\n \"default-src 'none'\",\n \"script-src 'unsafe-inline'\",\n \"style-src 'unsafe-inline'\",\n 'img-src data: blob:',\n 'font-src data:',\n connectSrc,\n \"worker-src 'none'\",\n \"child-src 'none'\",\n \"frame-src 'none'\",\n \"media-src 'none'\",\n \"object-src 'none'\",\n \"manifest-src 'none'\",\n \"prefetch-src 'none'\",\n \"base-uri 'none'\",\n \"form-action 'none'\",\n \"frame-ancestors 'self'\",\n ].join('; ');\n const meta = `<meta http-equiv=\"Content-Security-Policy\" content=\"${escapeAttribute(value)}\">`;\n if (/<head[^>]*>/i.test(html)) {\n return html.replace(/<head[^>]*>/i, (open) => `${open}${meta}`);\n }\n if (/<html[^>]*>/i.test(html)) {\n return html.replace(/<html[^>]*>/i, (open) => `${open}<head>${meta}</head>`);\n }\n return `${meta}${html}`;\n}\n\nasync function resolvePointerEvent(\n pointer: PajaDecodedPointer,\n pool: PajaPointerRelayPool,\n relays: readonly string[],\n maxWaitMs: number,\n): Promise<NostrEvent> {\n const filter = pointer.type === 'naddr'\n ? addressableFilter(pointer)\n : eventFilter(pointer);\n const result = await queryPointerRelays(pool, relays, filter, maxWaitMs);\n const event = result.events\n .filter((candidate) => matchesPointer(pointer, candidate))\n .sort((a, b) => b.created_at - a.created_at)[0];\n if (!event) {\n if (result.timedOut) {\n throw new Error(\n `Relay resolution timed out after ${maxWaitMs}ms for ${pointer.type} pointer across ${relays.length} relays before complete EOSE.`,\n );\n }\n const failures = relayFailureReasons(result.reasons);\n if (result.error || failures.length > 0) {\n const detail = result.error instanceof Error\n ? result.error.message\n : result.error === undefined\n ? failures.join('; ')\n : String(result.error);\n throw new Error(`Relay query failed for ${pointer.type} pointer before complete EOSE: ${detail}`);\n }\n throw new Error(\n `All ${relays.length} relays reached EOSE without a matching ${pointer.type} napplet manifest event.`,\n );\n }\n if (!isNappletManifestKind(event.kind)) {\n throw new Error(`Pointer resolved kind ${event.kind}; expected ${formatNappletManifestKinds()}.`);\n }\n return event;\n}\n\ninterface PointerRelayQueryResult {\n readonly events: readonly NostrEvent[];\n readonly reasons: readonly string[];\n readonly timedOut: boolean;\n readonly error?: unknown;\n}\n\nfunction queryPointerRelays(\n pool: PajaPointerRelayPool,\n relays: readonly string[],\n filter: Filter,\n maxWaitMs: number,\n): Promise<PointerRelayQueryResult> {\n if (pool.subscribeManyEose) {\n return queryPointerRelaySubscription(pool, relays, filter, maxWaitMs);\n }\n return queryPointerRelaySync(pool, relays, filter, maxWaitMs);\n}\n\nfunction queryPointerRelaySubscription(\n pool: PajaPointerRelayPool,\n relays: readonly string[],\n filter: Filter,\n maxWaitMs: number,\n): Promise<PointerRelayQueryResult> {\n return new Promise((resolve) => {\n const events: NostrEvent[] = [];\n let settled = false;\n let subscription: ReturnType<NonNullable<PajaPointerRelayPool['subscribeManyEose']>> | undefined;\n const finish = (result: Omit<PointerRelayQueryResult, 'events'>) => {\n if (settled) return;\n settled = true;\n clearTimeout(deadline);\n resolve({ events, ...result });\n };\n const deadline = setTimeout(() => {\n finish({ reasons: [], timedOut: true });\n void subscription?.close('Paja pointer relay deadline exceeded');\n }, maxWaitMs);\n\n try {\n subscription = pool.subscribeManyEose!([...relays], filter, {\n maxWait: maxWaitMs,\n label: 'kehto-paja-runtime',\n onevent(event) {\n events.push(event);\n },\n onclose(reasons) {\n finish({ reasons, timedOut: false });\n },\n });\n } catch (error) {\n finish({ reasons: [], timedOut: false, error });\n }\n });\n}\n\nfunction queryPointerRelaySync(\n pool: PajaPointerRelayPool,\n relays: readonly string[],\n filter: Filter,\n maxWaitMs: number,\n): Promise<PointerRelayQueryResult> {\n return new Promise((resolve) => {\n let settled = false;\n const finish = (result: PointerRelayQueryResult) => {\n if (settled) return;\n settled = true;\n clearTimeout(deadline);\n resolve(result);\n };\n const deadline = setTimeout(() => {\n finish({ events: [], reasons: [], timedOut: true });\n }, maxWaitMs);\n\n void pool.querySync([...relays], filter, {\n maxWait: maxWaitMs,\n label: 'kehto-paja-runtime',\n }).then(\n (events) => finish({ events, reasons: [], timedOut: false }),\n (error: unknown) => finish({ events: [], reasons: [], timedOut: false, error }),\n );\n });\n}\n\nfunction relayFailureReasons(reasons: readonly string[]): string[] {\n return [...new Set(reasons\n .map((reason) => reason.trim())\n .filter((reason) => reason.length > 0 && reason !== 'closed automatically on eose')\n .map((reason) => reason.slice(0, 160)))]\n .slice(0, 3);\n}\n\nfunction normalizeMaxWaitMs(value: number | undefined): number {\n if (value === undefined) return 5_000;\n if (!Number.isFinite(value) || value <= 0) {\n throw new Error('Pointer relay deadline must be a positive number of milliseconds.');\n }\n return Math.floor(value);\n}\n\nfunction addressableFilter(pointer: Extract<PajaDecodedPointer, { type: 'naddr' }>): Filter {\n if (pointer.kind !== NAPPLET_KIND_NAMED) {\n throw new Error(`naddr kind ${pointer.kind} is not a named NIP-5D napplet manifest kind.`);\n }\n return {\n kinds: [NAPPLET_KIND_NAMED],\n authors: [pointer.pubkey],\n '#d': [pointer.identifier],\n limit: 1,\n };\n}\n\nfunction eventFilter(pointer: Extract<PajaDecodedPointer, { type: 'nevent' }>): Filter {\n return {\n ids: [pointer.id],\n ...(pointer.kind ? { kinds: [pointer.kind] } : {}),\n ...(pointer.author ? { authors: [pointer.author] } : {}),\n limit: 1,\n };\n}\n\nfunction matchesPointer(pointer: PajaDecodedPointer, event: NostrEvent): boolean {\n if (pointer.type === 'nevent') {\n if (event.id !== pointer.id) return false;\n if (pointer.author && event.pubkey !== pointer.author) return false;\n if (pointer.kind && event.kind !== pointer.kind) return false;\n return true;\n }\n return event.kind === pointer.kind\n && event.pubkey === pointer.pubkey\n && event.tags.some((tag) => tag[0] === 'd' && tag[1] === pointer.identifier);\n}\n\nfunction uniqueRelayUrls(values: readonly string[]): string[] {\n const out: string[] = [];\n const seen = new Set<string>();\n for (const value of values) {\n const url = normalizeRelayUrl(value);\n if (!url || seen.has(url)) continue;\n seen.add(url);\n out.push(url);\n }\n return out;\n}\n\nfunction normalizeRelayUrl(value: string): string | undefined {\n const raw = value.trim();\n if (!raw) return undefined;\n try {\n const url = new URL(raw);\n if (url.protocol !== 'wss:' && url.protocol !== 'ws:') return undefined;\n url.hash = '';\n url.search = '';\n return url.href.replace(/\\/$/, '');\n } catch {\n return undefined;\n }\n}\n\nfunction escapeAttribute(value: string): string {\n return value\n .replaceAll('&', '&amp;')\n .replaceAll('\"', '&quot;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;');\n}\n\nfunction formatNappletManifestKinds(): string {\n return PAJA_NAPPLET_MANIFEST_KINDS.join(' / ');\n}\n","import type { ShellCapabilities } from '@kehto/shell';\n\n/** The exact host-visible shell environment shape shared by bootstrap and init. */\nexport type PajaShellEnvironment = Readonly<{\n capabilities: ShellCapabilities;\n services: readonly string[];\n}>;\n\nconst PAJA_LEGACY_COMPATIBILITY_DOMAIN: string = `i${'fc'}`;\n\n/** Domain list mirrored from the upstream web runtime for parity checks. */\nexport const PAJA_UPSTREAM_WEB_DOMAINS = [\n 'ble',\n 'common',\n 'config',\n 'count',\n 'cvm',\n 'dm',\n 'fs',\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\n/** Domains required during the initial Paja handshake. */\nexport const PAJA_HANDSHAKE_DOMAINS = ['shell'] as const;\n/** Domains intentionally deferred until their runtime service exists. */\nexport const PAJA_DEFERRED_DOMAINS = ['dm', 'fs'] as const;\n\n/** Compatibility aliases for renamed upstream capability domains. */\nexport const PAJA_COMPATIBILITY_ALIASES = {\n [PAJA_LEGACY_COMPATIBILITY_DOMAIN]: 'inc',\n} as const;\n\n/** Domains Paja advertises through its simulated shell capability surface. */\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 'count',\n] as const;\n\n/** Service names Paja expects the host runtime to provide. */\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 'count',\n] as const;\n\n/**\n * Find advertised Paja domains missing from a shell capability snapshot.\n *\n * @param capabilities - Shell capability snapshot to inspect.\n * @returns Advertised domains not present in the snapshot.\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\n/**\n * Find required service names missing from a runtime service list.\n *\n * @param services - Runtime service names to inspect.\n * @returns Required service names that are absent.\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\n/**\n * Compare the observable membership of two independently resolved Paja shell\n * environments. Resolver calls intentionally return different frozen objects.\n */\nexport function hasEqualPajaEnvironmentMembership(\n left: PajaShellEnvironment,\n right: PajaShellEnvironment,\n): boolean {\n return left.capabilities.domains.length === right.capabilities.domains.length\n && left.capabilities.domains.every((domain, index) => domain === right.capabilities.domains[index])\n && left.services.length === right.services.length\n && left.services.every((service, index) => service === right.services[index]);\n}\n","/** Options for polling a target URL until it is ready. */\nexport interface WaitForTargetUrlOptions {\n /** Total wait budget in milliseconds. */\n readonly timeoutMs: number;\n /** Poll interval in milliseconds. Defaults to 250. */\n readonly intervalMs?: number;\n /** Fetch implementation override for tests. */\n readonly fetch?: ReadinessFetch;\n /** Sleep implementation override for tests. */\n readonly sleep?: (ms: number) => Promise<void>;\n /** Clock override for tests. */\n readonly now?: () => number;\n}\n\n/** Fetch-like target readiness probe. */\nexport type ReadinessFetch = (url: string) => Promise<{ readonly status: number }>;\n\n/** Thrown when a target URL does not become ready before the timeout. */\nexport class ReadinessError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ReadinessError';\n }\n}\n\n/**\n * Poll a target URL until it returns a non-5xx response or times out.\n *\n * @param url - Target URL to poll.\n * @param options - Timeout and polling controls.\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","/**\n * Persistent Paja catalog of resolver-verified napplet installations.\n *\n * The catalog deliberately contains only serializable facts copied from a\n * verified pointer result. Runtime frames, sessions, and controller state are\n * owned elsewhere, so closing a tab cannot alter handler eligibility.\n *\n * @packageDocumentation\n */\n\nimport { manifestToIntentCatalogEntry } from '@kehto/services';\nimport type { IntentCatalogEntry } from '@kehto/services';\nimport type { PajaDecodedPointer, PajaResolvedPointer } from './runtime-resolver.js';\n\n/** Serializable verified pointer and manifest facts for one installed napplet. */\nexport interface InstalledNappletRecord {\n /** Verified manifest d-tag used as the handler identity. */\n readonly dTag: string;\n /** Verified NIP-5A aggregate hash for the installed artifact. */\n readonly aggregateHash: string;\n /** Pointer identity that can later be re-resolved and verified. */\n readonly pointer: PajaDecodedPointer;\n /** Optional manifest title for handler selection UI. */\n readonly title?: string;\n /** Verified NAP domains required by the artifact. */\n readonly requires: readonly string[];\n /** Exact manifest convention contracts used for intent eligibility. */\n readonly archetypes: readonly {\n readonly slug: string;\n readonly convention: string;\n }[];\n}\n\n/** Return whether a live runtime target is exactly the installed verified artifact. */\nexport function matchesInstalledNappletRecord(\n record: Pick<InstalledNappletRecord, 'dTag' | 'aggregateHash'>,\n target: Pick<InstalledNappletRecord, 'dTag' | 'aggregateHash'>,\n): boolean {\n return target.dTag === record.dTag && target.aggregateHash === record.aggregateHash;\n}\n\n/** Listener notified when an installed artifact is inserted or removed. */\nexport type InstalledNappletCatalogListener = (dTag: string) => void;\n\n/**\n * Stores verified Paja installations separately from the browser runtime.\n *\n * @example\n * ```ts\n * const catalog = new InstalledNappletCatalog();\n * catalog.install(resolvedPointer);\n * const candidates = catalog.intentCatalog();\n * ```\n */\nexport class InstalledNappletCatalog {\n private readonly records = new Map<string, InstalledNappletRecord>();\n private readonly listeners = new Set<InstalledNappletCatalogListener>();\n\n /** Insert or replace a record from an already resolver-verified pointer. */\n install(resolved: PajaResolvedPointer): InstalledNappletRecord {\n const record = freezeRecord({\n dTag: resolved.dTag,\n aggregateHash: resolved.aggregateHash,\n pointer: copyPointer(resolved.pointer),\n ...(resolved.manifest.title === undefined ? {} : { title: resolved.manifest.title }),\n requires: [...resolved.manifest.requires],\n archetypes: resolved.manifest.archetypes.map((archetype) => ({\n slug: archetype.slug,\n convention: archetype.convention,\n })),\n });\n this.records.set(record.dTag, record);\n this.notify(record.dTag);\n return record;\n }\n\n /** Remove an artifact explicitly; frame teardown never calls this method. */\n remove(dTag: string): boolean {\n const removed = this.records.delete(dTag);\n if (removed) this.notify(dTag);\n return removed;\n }\n\n /** Return whether a verified installation exists for a d-tag. */\n has(dTag: string): boolean {\n return this.records.has(dTag);\n }\n\n /** Return immutable serializable installed-artifact facts. */\n installed(): readonly InstalledNappletRecord[] {\n return [...this.records.values()];\n }\n\n /** Return a verified record by d-tag. */\n get(dTag: string): InstalledNappletRecord | undefined {\n return this.records.get(dTag);\n }\n\n /**\n * Atomically confirm that a resolved target still belongs to the exact record\n * selected before an async operation. The record object is the catalog version\n * token, so even a same-identity replacement cannot pass this check.\n */\n validateCurrent(\n selected: InstalledNappletRecord,\n target: Pick<InstalledNappletRecord, 'dTag' | 'aggregateHash'>,\n ): InstalledNappletRecord | null {\n if (this.records.get(selected.dTag) !== selected) return null;\n return matchesInstalledNappletRecord(selected, target) ? selected : null;\n }\n\n /** Return exact handler candidates derived only from installed manifests. */\n intentCatalog(): IntentCatalogEntry[] {\n return this.installed()\n .filter((record) => record.requires.includes('inc'))\n .map((record) => manifestToIntentCatalogEntry({\n dTag: record.dTag,\n ...(record.title === undefined ? {} : { title: record.title }),\n archetypes: record.archetypes.map((archetype) => ({\n slug: archetype.slug,\n convention: archetype.convention,\n })),\n }));\n }\n\n /** Subscribe to explicit install and artifact-removal changes. */\n onChanged(listener: InstalledNappletCatalogListener): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n private notify(dTag: string): void {\n for (const listener of this.listeners) listener(dTag);\n }\n}\n\nfunction copyPointer(pointer: PajaDecodedPointer): PajaDecodedPointer {\n if (pointer.type === 'naddr') {\n return Object.freeze({\n type: 'naddr' as const,\n value: pointer.value,\n identifier: pointer.identifier,\n pubkey: pointer.pubkey,\n kind: pointer.kind,\n relays: Object.freeze([...pointer.relays]),\n });\n }\n return Object.freeze({\n type: 'nevent' as const,\n value: pointer.value,\n id: pointer.id,\n ...(pointer.author === undefined ? {} : { author: pointer.author }),\n ...(pointer.kind === undefined ? {} : { kind: pointer.kind }),\n relays: Object.freeze([...pointer.relays]),\n });\n}\n\nfunction freezeRecord(record: Omit<InstalledNappletRecord, 'archetypes'> & {\n readonly archetypes: readonly {\n readonly slug: string;\n readonly convention: string;\n }[];\n}): InstalledNappletRecord {\n return Object.freeze({\n ...record,\n requires: Object.freeze([...record.requires]),\n archetypes: Object.freeze(record.archetypes.map((archetype) =>\n Object.freeze({ ...archetype }))),\n });\n}\n","/**\n * Browser-owned NAP-INTENT target lifecycle policy.\n *\n * Retention is intentionally independent from browser frames. The host supplies\n * generation creation/reuse, source-bound readiness, current-generation checks,\n * and convention delivery. The controller resolves only after the target is\n * ready and the delivery is enqueued.\n *\n * @packageDocumentation\n */\n\nimport type {\n IntentDispatchParams,\n IntentTargetController,\n IntentTargetDispatch,\n} from '@kehto/services';\n\n/** Opaque current target generation controlled by the browser host. */\nexport interface BrowserIntentGeneration {\n /** Host-owned stable identifier for one target generation. */\n readonly id: string;\n}\n\n/** Terminal reasons exposed only to host observability and cleanup policy. */\nexport type BrowserIntentTerminalReason =\n | 'open-failed'\n | 'ready-failed'\n | 'no-current-target'\n | 'send-failed';\n\n/** Browser lifecycle callbacks injected by the Paja host. */\nexport interface BrowserIntentControllerOptions {\n /** Open a compatible target or reuse its current generation. */\n openOrReuse(\n params: IntentDispatchParams,\n attempt: number,\n ): BrowserIntentGeneration | null | Promise<BrowserIntentGeneration | null>;\n /** Await source-bound NAP-SHELL readiness for a selected generation. */\n waitForReady(generation: BrowserIntentGeneration): void | Promise<void>;\n /** Return true only while the generation remains the selected current target. */\n isCurrent(generation: BrowserIntentGeneration): boolean | Promise<boolean>;\n /** Return the runtime-assigned window identifier once the target is ready. */\n getWindowId(generation: BrowserIntentGeneration): string | null;\n /** Send the convention through the ordinary carrier to the ready generation. */\n send(\n generation: BrowserIntentGeneration,\n params: IntentDispatchParams,\n ): void | Promise<void>;\n /** Maximum open/replacement attempts. Finite values clamp to 1–10; defaults to two. */\n maxAttempts?: number;\n /** Observe terminal target policy. */\n onTerminal?(params: IntentDispatchParams, reason: BrowserIntentTerminalReason): void;\n}\n\nconst MAX_INTENT_DELIVERY_ATTEMPTS = 10;\n\n/**\n * Creates/focuses a target and enqueues one convention delivery.\n */\nexport class BrowserIntentController implements IntentTargetController {\n private readonly maxAttempts: number;\n\n constructor(private readonly options: BrowserIntentControllerOptions) {\n this.maxAttempts = normalizeAttempts(options.maxAttempts);\n }\n\n async dispatch(params: IntentDispatchParams): Promise<IntentTargetDispatch> {\n const dispatch = freezeDispatch(params);\n let reason: BrowserIntentTerminalReason = 'no-current-target';\n for (let attempt = 1; attempt <= this.maxAttempts; attempt += 1) {\n let generation: BrowserIntentGeneration | null;\n try {\n generation = await this.options.openOrReuse(dispatch, attempt);\n } catch {\n reason = 'open-failed';\n continue;\n }\n if (!generation) {\n reason = 'open-failed';\n continue;\n }\n try {\n await this.options.waitForReady(generation);\n } catch {\n reason = 'ready-failed';\n continue;\n }\n if (!await this.options.isCurrent(generation)) {\n reason = 'no-current-target';\n continue;\n }\n try {\n await this.options.send(generation, dispatch);\n const windowId = this.options.getWindowId(generation);\n if (!windowId) throw new Error('intent target window is unavailable');\n return { windowId };\n } catch {\n this.options.onTerminal?.(dispatch, 'send-failed');\n throw new Error('intent target send failed');\n }\n }\n this.options.onTerminal?.(dispatch, reason);\n throw new Error(`intent target ${reason}`);\n }\n}\n\nfunction normalizeAttempts(value: number | undefined): number {\n if (value === undefined) return 2;\n if (!Number.isFinite(value)) throw new TypeError('maxAttempts must be finite');\n return Math.min(MAX_INTENT_DELIVERY_ATTEMPTS, Math.max(1, Math.floor(value)));\n}\n\nfunction freezeDispatch(params: IntentDispatchParams): IntentDispatchParams {\n if (!params || typeof params.handler !== 'string' || params.handler.length === 0) {\n throw new TypeError('Intent dispatch requires a handler');\n }\n if (\n typeof params.sender !== 'string'\n || params.sender.length === 0\n || typeof params.archetype !== 'string'\n || params.archetype.length === 0\n || typeof params.action !== 'string'\n || params.action.length === 0\n || typeof params.convention !== 'string'\n || params.convention.length === 0\n ) {\n throw new TypeError('Intent dispatch requires canonical routing fields');\n }\n const payload = freezeValue(params.payload);\n const behavior = params.behavior === undefined\n ? undefined\n : freezeValue({ ...params.behavior }) as NonNullable<IntentDispatchParams['behavior']>;\n return Object.freeze({\n handler: params.handler,\n sender: params.sender,\n archetype: params.archetype,\n action: params.action,\n convention: params.convention,\n ...(params.payload === undefined ? {} : { payload }),\n ...(behavior === undefined ? {} : { behavior }),\n });\n}\n\nfunction freezeValue<T>(value: T, seen = new WeakMap<object, unknown>()): T {\n if (typeof value !== 'object' || value === null) return value;\n const existing = seen.get(value);\n if (existing !== undefined) return existing as T;\n if (Array.isArray(value)) {\n const copy: unknown[] = [];\n seen.set(value, copy);\n for (const item of value) copy.push(freezeValue(item, seen));\n return Object.freeze(copy) as T;\n }\n const copy: Record<string, unknown> = {};\n seen.set(value, copy);\n for (const [key, item] of Object.entries(value)) copy[key] = freezeValue(item, seen);\n return Object.freeze(copy) as T;\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';\nimport { probeTargetCors } from './target-cors.js';\n\n/** Options for starting the Paja local HTTP server. */\nexport interface PajaServerOptions {\n /** Raw options accepted by Paja; config-file references are resolved before serving. */\n readonly options: PajaRawOptions;\n /** Clock override used for deterministic host config in tests. */\n readonly now?: Date;\n}\n\n/** Running Paja server handle. */\nexport interface PajaServer {\n /** Runtime URL where the Paja host page is served. */\n readonly url: string;\n /** Current host-page config. */\n readonly hostConfig: PajaHostConfig;\n /** Update the target iframe URL without restarting the server. */\n updateTargetUrl(targetUrl: string): PajaHostConfig;\n /** Stop the HTTP server. */\n close(): Promise<void>;\n}\n\n/**\n * Start the local Paja development HTTP server.\n *\n * @param input - Raw options and optional clock override.\n * @returns Running server handle.\n */\nexport async function startPajaServer(input: PajaServerOptions): Promise<PajaServer> {\n const rawOptions = resolvePajaRawOptions(input.options);\n const options = normalizePajaOptions(rawOptions);\n const createdAt = input.now ?? new Date();\n let hostConfig = createPajaHostConfig(options, createdAt);\n let html = renderPajaHtml(hostConfig);\n let configJson = JSON.stringify(hostConfig, null, 2);\n let currentOptions = options;\n\n const setHostConfig = (nextOptions: PajaOptions): PajaHostConfig => {\n currentOptions = nextOptions;\n hostConfig = createPajaHostConfig(currentOptions, createdAt);\n html = renderPajaHtml(hostConfig);\n configJson = JSON.stringify(hostConfig, null, 2);\n return hostConfig;\n };\n\n const handleRequest = async (requestUrl: string, response: HttpResponse): Promise<void> => {\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/target.html') {\n const targetHtml = await fetchTargetHtml(hostConfig.target.url);\n response.writeHead(200, {\n 'cache-control': 'no-store',\n 'content-type': 'text/html; charset=utf-8',\n });\n response.end(targetHtml);\n return;\n }\n\n if (requestUrl === '/__kehto/target-cors.json') {\n const diagnostic = await probeTargetCors(hostConfig.target.url);\n response.writeHead(200, {\n 'cache-control': 'no-store',\n 'content-type': 'application/json; charset=utf-8',\n });\n response.end(JSON.stringify(diagnostic));\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 const server = createServer((request, response) => {\n void handleRequest(request.url ?? '/', response).catch((error) => {\n const message = error instanceof Error ? error.message : String(error);\n response.writeHead(502, { 'content-type': 'text/plain; charset=utf-8' });\n response.end(message);\n });\n });\n\n await listen(server, options.host, options.port);\n const servedOptions = withBoundPort(options, getBoundPort(server, options.port));\n setHostConfig(servedOptions);\n\n return {\n url: formatPajaUrl(servedOptions),\n get hostConfig() {\n return hostConfig;\n },\n updateTargetUrl(targetUrl) {\n return setHostConfig(withTargetUrl(currentOptions, targetUrl));\n },\n close: () => close(server),\n };\n}\n\nfunction readBrowserHostScript(): string {\n return readFileSync(new URL('./browser-host.js', import.meta.url), 'utf8');\n}\n\nasync function fetchTargetHtml(targetUrl: string): Promise<string> {\n const response = await fetch(targetUrl, {\n headers: {\n accept: 'text/html, application/xhtml+xml;q=0.9, */*;q=0.8',\n },\n });\n if (!response.ok) {\n throw new Error(`Target ${targetUrl} returned ${response.status} ${response.statusText}`);\n }\n return response.text();\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 const forceClose = setTimeout(() => {\n server.closeAllConnections?.();\n }, 500);\n server.close((error?: Error) => {\n clearTimeout(forceClose);\n if (error) {\n reject(error);\n return;\n }\n resolve();\n });\n server.closeIdleConnections?.();\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 closeAllConnections?(): void;\n closeIdleConnections?(): void;\n address(): string | { port: number } | null;\n}\n\ninterface HttpResponse {\n writeHead(statusCode: number, headers: Record<string, string>): void;\n end(chunk: string): void;\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\nfunction withTargetUrl(options: PajaOptions, targetUrl: string): PajaOptions {\n const url = normalizeServerTargetUrl(targetUrl);\n return url === options.targetUrl ? options : { ...options, targetUrl: url };\n}\n\nfunction normalizeServerTargetUrl(value: string): string {\n const raw = value.trim();\n let parsed: URL;\n try {\n parsed = new URL(raw);\n } catch {\n throw new Error(`Invalid managed target URL \"${raw}\". Expected an absolute http(s) URL.`);\n }\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n throw new Error(`Invalid managed target URL \"${raw}\". Only http: and https: URLs are supported.`);\n }\n return parsed.href;\n}\n","/**\n * Target dev-server CORS diagnostics.\n *\n * Paja loads the napplet target into a `srcdoc` iframe sandboxed without\n * `allow-same-origin`, so the napplet document has an opaque origin and sends\n * `Origin: null` on every subresource fetch. `<script type=\"module\">` is always\n * fetched in CORS mode, so a dev server that does not allow the `null` origin\n * blocks the napplet's entry module and the iframe renders blank.\n *\n * These helpers probe the target with an explicit `Origin: null` request so\n * Paja can report the cause instead of leaving an empty frame behind.\n */\n\n/** Whether the target dev server will serve the sandboxed frame's subresources. */\nexport type PajaTargetCorsStatus = 'allowed' | 'blocked' | 'unreachable';\n\n/** Result of probing a target dev server for opaque-origin CORS support. */\nexport interface PajaTargetCorsDiagnostic {\n /** Classification of the probe result. */\n readonly status: PajaTargetCorsStatus;\n /** Target URL that was probed. */\n readonly targetUrl: string;\n /** `access-control-allow-origin` value the target returned, when any. */\n readonly allowOrigin: string | null;\n /** Human-readable explanation of the classification. */\n readonly detail: string;\n /** Actionable remedy, present only when `status` is not `allowed`. */\n readonly hint: string | null;\n}\n\n/** Remedy shown whenever the target rejects the sandboxed frame's `null` origin. */\nexport const PAJA_TARGET_CORS_HINT =\n \"Paja sandboxes the napplet frame without allow-same-origin, so its assets are requested with `Origin: null`. \"\n + \"Allow that origin in the napplet dev server, e.g. Vite `server: { cors: { origin: '*' } }`.\";\n\n/**\n * Classify an `access-control-allow-origin` response value for an opaque origin.\n *\n * @param targetUrl - Target URL the header came from.\n * @param allowOrigin - Raw `access-control-allow-origin` header value, or `null` when absent.\n * @returns Diagnostic describing whether the sandboxed frame can load assets.\n * @example\n * ```ts\n * classifyTargetCors('http://127.0.0.1:5173/', '*').status; // 'allowed'\n * classifyTargetCors('http://127.0.0.1:5173/', null).status; // 'blocked'\n * ```\n */\nexport function classifyTargetCors(\n targetUrl: string,\n allowOrigin: string | null,\n): PajaTargetCorsDiagnostic {\n const value = allowOrigin?.trim() ?? null;\n if (value === '*' || value === 'null') {\n return {\n status: 'allowed',\n targetUrl,\n allowOrigin: value,\n detail: `Target allows the sandboxed frame's null origin (access-control-allow-origin: ${value}).`,\n hint: null,\n };\n }\n if (value === null || value === '') {\n return {\n status: 'blocked',\n targetUrl,\n allowOrigin: null,\n detail: 'Target sent no access-control-allow-origin for an Origin: null request.',\n hint: PAJA_TARGET_CORS_HINT,\n };\n }\n return {\n status: 'blocked',\n targetUrl,\n allowOrigin: value,\n detail: `Target only allows origin \"${value}\", not the sandboxed frame's null origin.`,\n hint: PAJA_TARGET_CORS_HINT,\n };\n}\n\n/** Minimal fetch surface the probe depends on. */\nexport type PajaTargetCorsFetch = (\n input: string,\n init: { method: string; headers: Record<string, string> },\n) => Promise<{ headers: { get(name: string): string | null } }>;\n\nconst defaultTargetCorsFetch: PajaTargetCorsFetch = (input, init) => fetch(input, init);\n\n/**\n * Probe a target dev server for opaque-origin CORS support.\n *\n * Sends `Origin: null` explicitly — a browser cannot forge that header, but the\n * Paja server can, which is why the probe runs server-side.\n *\n * @param targetUrl - Absolute target URL served by the napplet dev server.\n * @param fetchImpl - Fetch implementation; defaults to the global `fetch`.\n * @returns Diagnostic describing whether the sandboxed frame can load assets.\n * @example\n * ```ts\n * const diagnostic = await probeTargetCors('http://127.0.0.1:5173/');\n * if (diagnostic.status === 'blocked') console.warn(diagnostic.hint);\n * ```\n */\nexport async function probeTargetCors(\n targetUrl: string,\n fetchImpl: PajaTargetCorsFetch = defaultTargetCorsFetch,\n): Promise<PajaTargetCorsDiagnostic> {\n try {\n const response = await fetchImpl(targetUrl, {\n method: 'GET',\n headers: {\n origin: 'null',\n accept: 'text/html, application/xhtml+xml;q=0.9, */*;q=0.8',\n },\n });\n return classifyTargetCors(targetUrl, response.headers.get('access-control-allow-origin'));\n } catch (error) {\n return {\n status: 'unreachable',\n targetUrl,\n allowOrigin: null,\n detail: `Target CORS probe failed: ${error instanceof Error ? error.message : String(error)}`,\n hint: 'Confirm the napplet dev server is running and --target-url points at it.',\n };\n }\n}\n"],"mappings":"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","names":["escapeAttribute","resolve","resolve","copy","readFileSync","readFileSync","resolve"]}
package/dist/cli.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  startPajaServer,
10
10
  summarizePajaSimulation,
11
11
  waitForTargetUrl
12
- } from "./chunk-OWVINAW7.js";
12
+ } from "./chunk-EOCGC7A2.js";
13
13
 
14
14
  // src/cli.ts
15
15
  import { spawn } from "child_process";