import { AsyncLocalStorage } from "node:async_hooks"; import crypto from "node:crypto"; import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import WebSocket from "ws"; import z, { type ZodTypeAny, type output as ZodOutput } from "zod"; import { BootRequestParamsSchema, CallRequestParamsSchema, ContextCloseRequestParamsSchema, ContextOpenRequestParamsSchema, EventSubscribeRequestParamsSchema, EventUnsubscribeRequestParamsSchema, type RuntimeErrorRequestParams, ServerMessageSchema, TargetContextOpenRequestParamsSchema, ValueGetRequestParamsSchema, ValueUnwatchRequestParamsSchema, ValueWatchRequestParamsSchema, parseJson, sendClientMessage, } from "./rpc.js"; export * from "./rpc.js"; export type PayloadMode = "snapshot" | "delta"; export type SchemaAnnotation = { type: string; [key: string]: unknown; }; export type PackageFunctionSchema = { description: string; annotations?: SchemaAnnotation[]; inputSchema: ZodTypeAny; outputSchema: ZodTypeAny; }; type StaticResourceSchema = { description: string; annotations?: SchemaAnnotation[]; dataSchema: ZodTypeAny; history?: boolean; payloadMode?: PayloadMode; }; type ParameterizedResourceSchema = StaticResourceSchema & { paramsSchema: ZodTypeAny; }; export type StaticEventSchema = StaticResourceSchema; export type ParameterizedEventSchema = ParameterizedResourceSchema; export type EventSchema = StaticEventSchema | ParameterizedEventSchema; export type EventSchemaMap = Record; export type StaticValueSchema = StaticResourceSchema; export type ParameterizedValueSchema = ParameterizedResourceSchema; export type ValueSchema = StaticValueSchema | ParameterizedValueSchema; export type ValueSchemaMap = Record; export type PackageSchema< Functions extends Record = Record< string, PackageFunctionSchema >, Events extends EventSchemaMap = EventSchemaMap, Values extends ValueSchemaMap = ValueSchemaMap, > = { schemaVersion: 1; majorVersion: number; description: string; annotations?: SchemaAnnotation[]; functions: Functions; events: Events; values: Values; }; export const QUIXOS_MEDIA_JSON_SCHEMA_KEY = "x-quixos-media"; export type QuixosDataUrlAnnotation = { transport: "data-url"; mimeType: string; extension?: string; }; type QuixosSchemaMetaRecord = Record; const readSchemaMeta = (schema: ZodTypeAny): QuixosSchemaMetaRecord => { try { const meta = schema.meta(); if (meta && typeof meta === "object") { return { ...(meta as QuixosSchemaMetaRecord) }; } } catch { // ignore } return {}; }; export const annotateDataUrlSchema = ( schema: Schema, params: { mimeType: string; extension?: string }, ): Schema => schema.meta({ ...readSchemaMeta(schema), [QUIXOS_MEDIA_JSON_SCHEMA_KEY]: { transport: "data-url", mimeType: params.mimeType, ...(params.extension ? { extension: params.extension } : {}), } satisfies QuixosDataUrlAnnotation, }) as Schema; export const quixosMedia = { dataUrlString: (params: { mimeType: string; extension?: string }) => annotateDataUrlSchema(z.string(), params), annotateDataUrl: annotateDataUrlSchema, }; type FunctionInput = ZodOutput< Schema["inputSchema"] >; type FunctionOutput = ZodOutput< Schema["outputSchema"] >; type SchemaParams< Schema extends StaticResourceSchema | ParameterizedResourceSchema, > = Schema extends { paramsSchema: infer ParamsSchema extends ZodTypeAny } ? ZodOutput : undefined; type EventParams = SchemaParams; type EventData = ZodOutput; type ValueParams = SchemaParams; type ValueData = ZodOutput; export type SubscriptionOptions = { signal?: AbortSignal; subscriptionNamespace?: string; }; export type SubscriptionHandle = { unsubscribe: () => Promise; }; export type UsePackageOptions = { contextNamespace?: string; stateContextId?: string; }; type ScopedResource = T & { withStateContext: (stateContextId: string) => T; withContextNamespace: (contextNamespace?: string) => T; }; type EventConsumer = ( data: EventData, ) => void | Promise; type ValueConsumer = ( data: ValueData, ) => void | Promise; type StaticEventClientBase = { consume: ( handler: EventConsumer, options?: SubscriptionOptions, ) => Promise; }; type ParameterizedEventClientBase = { consume: ( params: EventParams, handler: EventConsumer, options?: SubscriptionOptions, ) => Promise; }; export type EventClient = Schema extends ParameterizedEventSchema ? ScopedResource> : ScopedResource>; export type EventClients = { [Key in keyof Schema]: EventClient; }; type StaticValueClientBase = { get: () => Promise>; watch: ( handler: ValueConsumer, options?: SubscriptionOptions, ) => Promise; }; type ParameterizedValueClientBase = { get: (params: ValueParams) => Promise>; watch: ( params: ValueParams, handler: ValueConsumer, options?: SubscriptionOptions, ) => Promise; }; export type ValueClient = Schema extends ParameterizedValueSchema ? ScopedResource> : ScopedResource>; export type ValueClients = { [Key in keyof Schema]: ValueClient; }; export type PackageContext = { stateContext: string; stateDirectory: string; usePackage: ( schema: Schema, options?: UsePackageOptions, ) => PackageClient; }; export type PackageFunction< Schema extends PackageFunctionSchema, Context = any, > = ( ctx: Context, params: FunctionInput, ) => FunctionOutput | Promise>; export type PackageFunctions< Functions extends Record, Context = any, > = { [Key in keyof Functions]: PackageFunction; }; export type EventSink = { subscriptionId: string; emit: (data: EventData) => Promise; }; type EventHandler = { subscribe: ( ctx: Context, params: EventParams, sink: EventSink, ) => | void | (() => void | Promise) | Promise void | Promise)>; }; export type PackageEvents< Events extends EventSchemaMap, Context = any, > = { [Key in keyof Events]: EventHandler; }; export type ValueSink = { subscriptionId: string; set: (data: ValueData) => Promise; }; type ValueHandler = { get: ( ctx: Context, params: ValueParams, ) => ValueData | Promise>; watch?: ( ctx: Context, params: ValueParams, sink: ValueSink, ) => | void | (() => void | Promise) | Promise void | Promise)>; }; export type PackageValues< Values extends ValueSchemaMap, Context = any, > = { [Key in keyof Values]: ValueHandler; }; type InternalUsePackageOptions = UsePackageOptions & { callerStateContextId?: string; }; export type PackageFunctionCaller = ScopedResource<( params: FunctionInput, ) => Promise>>; type PackageFunctionCallers< Functions extends Record, > = { [Key in keyof Functions]: PackageFunctionCaller; }; export type PackageClient = { functions: PackageFunctionCallers; events: EventClients; values: ValueClients; withStateContext: (stateContextId: string) => PackageClient; withContextNamespace: ( contextNamespace?: string, ) => PackageClient; }; export type CreatePackageOptions< Schema extends PackageSchema, Context extends PackageContext = PackageContext, > = { schema: Schema; functions: PackageFunctions; events: PackageEvents; values: PackageValues; onCreate?: () => void | Promise; onContextOpen?: (ctx: Context) => void | Promise; onContextClose?: (ctx: Context) => void | Promise; onDestroy?: () => void | Promise; }; type LifecycleManager = {}; type PendingRequest = { resolve: (value: unknown) => void; reject: (error: Error) => void; timeout: NodeJS.Timeout; }; type ClientSubscriptionEntry = { deliver: (data: unknown) => void; closeLocal: (error?: Error) => void; }; type ServerSubscriptionEntry = { stateContextId: string; kind: "event" | "value"; resourceName: string; closeRemote: () => Promise; }; type QuixosSchemaMeta = { name?: string | null; type?: string | null; url?: string | null; rev?: string | null; flakeRef?: string | null; }; type QuixosSchema = PackageSchema & { __quixos?: QuixosSchemaMeta }; type RuntimeExecutionContext = PackageContext; export type RuntimeErrorPhase = RuntimeErrorRequestParams["phase"]; export type RuntimeErrorReportParams = { phase: RuntimeErrorPhase; error: unknown; stateContextId?: string; functionName?: string; resourceKind?: "event" | "value"; resourceName?: string; surfaceId?: string; hostSessionId?: string; stack?: string; }; const pendingRequests = new Map(); const clientSubscriptions = new Map(); const serverSubscriptions = new Map(); const runtimeContextStorage = new AsyncLocalStorage(); const openedRuntimeStateContexts = new Set(); const DEFAULT_REQUEST_TIMEOUT_MS = 60_000; const PACKAGE_BOOT_TIMEOUT_MS = 300_000; const TARGET_CONTEXT_OPEN_TIMEOUT_MS = 300_000; let socketPromise: Promise | null = null; let socketResolve: ((socket: WebSocket) => void) | null = null; let socketRef: WebSocket | null = null; let socketAuthenticated = false; let packageOptions: CreatePackageOptions | null = null; let runtimeExitTimer: NodeJS.Timeout | null = null; let runtimeExitRequested = false; const clearRuntimeExitTimer = () => { if (runtimeExitTimer) { clearTimeout(runtimeExitTimer); runtimeExitTimer = null; } }; const scheduleRuntimeExit = (code: number, reason: string) => { if (runtimeExitRequested) { return; } runtimeExitRequested = true; clearRuntimeExitTimer(); runtimeExitTimer = setTimeout(() => { console.warn(`[quixos-runtime] exiting (${reason})`); process.exit(code); }, 100); }; const closeServerSubscription = async (subscriptionId: string) => { const subscription = serverSubscriptions.get(subscriptionId); if (!subscription) { return; } serverSubscriptions.delete(subscriptionId); try { await subscription.closeRemote(); } catch (error) { await reportPackageRuntimeError({ phase: subscription.kind === "event" ? "event-cleanup" : "value-cleanup", error, stateContextId: subscription.stateContextId, resourceKind: subscription.kind, resourceName: subscription.resourceName, }); throw error; } }; const normalizeError = (error: unknown) => error instanceof Error ? error : new Error(String(error)); const createRuntimeErrorPayload = (params: RuntimeErrorReportParams) => { const normalized = normalizeError(params.error); return { phase: params.phase, stateContextId: params.stateContextId, functionName: params.functionName, resourceKind: params.resourceKind, resourceName: params.resourceName, surfaceId: params.surfaceId, hostSessionId: params.hostSessionId, message: normalized.message || "Unknown error", stack: params.stack ?? normalized.stack, }; }; export const reportPackageRuntimeError = async ( params: RuntimeErrorReportParams, ) => { try { await sendRequest("runtime-error", createRuntimeErrorPayload(params), 5_000); } catch { // Best-effort reporting only. } }; const resetSocket = () => { const shouldExitForSocketClose = socketAuthenticated && packageOptions !== null && Boolean(process.env.QUIXOS_ORCH_SECRET); socketRef = null; socketPromise = null; socketResolve = null; socketAuthenticated = false; for (const pending of pendingRequests.values()) { clearTimeout(pending.timeout); pending.reject(new Error("Socket closed")); } pendingRequests.clear(); for (const subscription of clientSubscriptions.values()) { subscription.closeLocal(new Error("Socket closed")); } clientSubscriptions.clear(); const activeServerSubscriptionIds = [...serverSubscriptions.keys()]; for (const subscriptionId of activeServerSubscriptionIds) { void closeServerSubscription(subscriptionId).catch(() => {}); } if (shouldExitForSocketClose) { scheduleRuntimeExit(0, "orchestrator-socket-closed"); } }; const getCurrentStateContextId = () => runtimeContextStorage.getStore()?.stateContext; const getStateDirectoryRoot = () => { const xdgDataHome = process.env.XDG_DATA_HOME; if (xdgDataHome && xdgDataHome.length > 0) { return path.join(xdgDataHome, "quixos", "state-contexts"); } return path.join(os.homedir(), ".local", "share", "quixos", "state-contexts"); }; const sanitizePackageNameForPath = (packageName: string) => encodeURIComponent(packageName); const resolveCurrentPackageName = () => { const meta = (packageOptions?.schema as QuixosSchema | undefined)?.__quixos; if (meta) { return resolveTargetPackageName(meta); } const packageRef = process.env.QUIXOS_PACKAGE_REF; if (packageRef) { return normalizePackageName(packageNameFromFlakeRef(packageRef)); } throw new Error("Unable to determine current package name for runtime context."); }; const getStateDirectoryForContext = ( packageName: string, stateContextId: string, ) => path.join( getStateDirectoryRoot(), sanitizePackageNameForPath(packageName), stateContextId, ); const withRuntimeContext = async ( ctx: RuntimeExecutionContext, fn: () => T | Promise, ) => await runtimeContextStorage.run(ctx, fn); export const runWithStateContext = async ( stateContextId: string, fn: () => T | Promise, ) => await withRuntimeContext( createRuntimeContext(stateContextId), fn, ); function createRuntimeContext(stateContextId: string): PackageContext { const packageName = resolveCurrentPackageName(); const stateDirectory = getStateDirectoryForContext(packageName, stateContextId); fs.mkdirSync(stateDirectory, { recursive: true }); return { stateContext: stateContextId, stateDirectory, usePackage: ( schema: Schema, options: UsePackageOptions = {}, ) => createPackageClient(schema, { ...options, callerStateContextId: stateContextId, }), }; } const closeRuntimeContext = async (stateContextId: string) => { const hasOpenedContext = openedRuntimeStateContexts.has(stateContextId); const activeServerSubscriptionIds = [...serverSubscriptions.entries()] .filter(([, subscription]) => subscription.stateContextId === stateContextId) .map(([subscriptionId]) => subscriptionId); if (!hasOpenedContext && activeServerSubscriptionIds.length === 0) { return; } for (const subscriptionId of activeServerSubscriptionIds) { await closeServerSubscription(subscriptionId); } if (!hasOpenedContext) { return; } const ctx = createRuntimeContext(stateContextId); try { await withRuntimeContext(ctx, async () => { await packageOptions?.onContextClose?.(ctx as any); }); } finally { openedRuntimeStateContexts.delete(stateContextId); } }; const hasParamsSchema = ( schema: StaticResourceSchema | ParameterizedResourceSchema, ): schema is ParameterizedResourceSchema => "paramsSchema" in schema; const parseResourceParams = ( resourceKind: "event" | "value", resourceName: string, schema: Schema, params: unknown, ) => { if (!hasParamsSchema(schema)) { if (params !== undefined) { throw new Error(`${resourceKind} ${resourceName} does not take params`); } return undefined as SchemaParams; } const parsed = schema.paramsSchema.safeParse(params); if (!parsed.success) { throw new Error(`Invalid params for ${resourceKind} ${resourceName}`); } return parsed.data as SchemaParams; }; const parseResourceData = ( resourceKind: "event" | "value", resourceName: string, schema: Schema, data: unknown, ) => { const parsed = schema.dataSchema.safeParse(data); if (!parsed.success) { throw new Error(`Invalid data for ${resourceKind} ${resourceName}`); } return parsed.data as ZodOutput; }; const normalizePackageName = (value: string) => { const normalized = value.startsWith("@quixos-package-schemas/") ? value.slice("@quixos-package-schemas/".length) : value; return normalized.endsWith(".git") ? normalized.slice(0, -".git".length) : normalized; }; const packageNameFromFlakeRef = (flakeRef: string) => { const withoutQuery = flakeRef.split("?")[0] ?? flakeRef; const withoutGitPrefix = withoutQuery.startsWith("git+") ? withoutQuery.slice(4) : withoutQuery; try { const parsed = new URL(withoutGitPrefix); const segments = parsed.pathname.split("/").filter(Boolean); const packageName = segments.at(-1); if (packageName) { return normalizePackageName(packageName); } } catch { // Fall through to a simple path split for non-URL flake refs. } const segments = withoutGitPrefix.split("/").filter(Boolean); const packageName = segments.at(-1); if (!packageName) { throw new Error(`Unable to determine package name for ${flakeRef}`); } return normalizePackageName(packageName); }; const resolveTargetPackageName = (meta: QuixosSchemaMeta) => { if (meta.name) { return normalizePackageName(meta.name); } if (meta.flakeRef) { return packageNameFromFlakeRef(meta.flakeRef); } throw new Error("Package schema is missing package name metadata."); }; const sendErrorResponse = ( socket: WebSocket, requestId: string, error: unknown, ) => { const normalized = normalizeError(error); sendClientMessage(socket, { type: "response", requestId, ok: false, error: normalized.message || "Unknown error", }); }; const reportAndSendErrorResponse = async ( socket: WebSocket, requestId: string, params: { phase: RuntimeErrorPhase; error: unknown; stateContextId?: string; functionName?: string; resourceKind?: "event" | "value"; resourceName?: string; }, ) => { void reportPackageRuntimeError(params); sendErrorResponse(socket, requestId, params.error); }; const handleRequest = async (socket: WebSocket, message: any) => { if (!packageOptions) { sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: false, error: "Package not initialized", }); return; } if (message.method === "stop") { try { const activeStateContextIds = [...openedRuntimeStateContexts]; for (const stateContextId of activeStateContextIds) { await closeRuntimeContext(stateContextId); } await packageOptions.onDestroy?.(); sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: true, }); scheduleRuntimeExit(0, "stop-request"); } catch (error) { await reportAndSendErrorResponse(socket, message.requestId, { phase: "on-destroy", error, }); } return; } if (message.method === "context-open") { const parsedParams = ContextOpenRequestParamsSchema.safeParse( message.params, ); if (!parsedParams.success) { sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: false, error: "Invalid context open params", }); return; } const ctx = createRuntimeContext(parsedParams.data.stateContextId); try { await withRuntimeContext(ctx, async () => { await packageOptions?.onContextOpen?.(ctx); }); openedRuntimeStateContexts.add(ctx.stateContext); sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: true, }); } catch (error) { await reportAndSendErrorResponse(socket, message.requestId, { phase: "on-context-open", error, stateContextId: ctx.stateContext, }); } return; } if (message.method === "context-close") { const parsedParams = ContextCloseRequestParamsSchema.safeParse( message.params, ); if (!parsedParams.success) { sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: false, error: "Invalid context close params", }); return; } try { await closeRuntimeContext(parsedParams.data.stateContextId); sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: true, }); } catch (error) { await reportAndSendErrorResponse(socket, message.requestId, { phase: "on-context-close", error, stateContextId: parsedParams.data.stateContextId, }); } return; } if (message.method === "call") { const parsedParams = CallRequestParamsSchema.safeParse(message.params); if (!parsedParams.success) { sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: false, error: "Invalid call params", }); return; } const { functionName, params, stateContextId } = parsedParams.data; if (!stateContextId) { sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: false, error: "Missing state context", }); return; } const fn = packageOptions.functions?.[functionName]; if (!fn) { sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: false, error: `Unknown function: ${functionName}`, }); return; } const ctx = createRuntimeContext(stateContextId); try { const result = await withRuntimeContext( ctx, async () => await fn(ctx, params), ); sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: true, result, }); } catch (error) { await reportAndSendErrorResponse(socket, message.requestId, { phase: "function", error, stateContextId, functionName, }); } return; } if (message.method === "boot") { const parsedParams = BootRequestParamsSchema.safeParse(message.params); if (!parsedParams.success) { sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: false, error: "Invalid boot params", }); return; } sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: true, }); return; } if (message.method === "event-subscribe") { const parsedParams = EventSubscribeRequestParamsSchema.safeParse( message.params, ); if (!parsedParams.success) { sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: false, error: "Invalid event subscribe params", }); return; } const { eventName, params, stateContextId } = parsedParams.data; if (!stateContextId) { sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: false, error: "Missing state context", }); return; } const eventSchema = packageOptions.schema.events?.[eventName]; const eventHandler = packageOptions.events?.[eventName]; if (!eventSchema || !eventHandler) { sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: false, error: `Unknown event: ${eventName}`, }); return; } const ctx = createRuntimeContext(stateContextId); const subscriptionId = crypto.randomUUID(); try { const parsedResourceParams = parseResourceParams( "event", eventName, eventSchema, params, ); const cleanup = await withRuntimeContext(ctx, async () => await eventHandler.subscribe(ctx, parsedResourceParams, { subscriptionId, emit: async (data) => { const parsedData = parseResourceData( "event", eventName, eventSchema, data, ); await publishToSubscription(subscriptionId, parsedData); }, }), ); serverSubscriptions.set(subscriptionId, { stateContextId: ctx.stateContext, kind: "event", resourceName: eventName, closeRemote: async () => { if (typeof cleanup === "function") { await runWithStateContext(ctx.stateContext, cleanup); } }, }); sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: true, result: { subscriptionId, }, }); } catch (error) { await reportAndSendErrorResponse(socket, message.requestId, { phase: "event-subscribe", error, stateContextId, resourceKind: "event", resourceName: eventName, }); } return; } if (message.method === "event-unsubscribe") { const parsedParams = EventUnsubscribeRequestParamsSchema.safeParse( message.params, ); if (!parsedParams.success) { sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: false, error: "Invalid event unsubscribe params", }); return; } try { await closeServerSubscription(parsedParams.data.subscriptionId); sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: true, }); } catch (error) { sendErrorResponse(socket, message.requestId, error); } return; } if (message.method === "value-get") { const parsedParams = ValueGetRequestParamsSchema.safeParse(message.params); if (!parsedParams.success) { sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: false, error: "Invalid value get params", }); return; } const { valueName, params, stateContextId } = parsedParams.data; if (!stateContextId) { sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: false, error: "Missing state context", }); return; } const valueSchema = packageOptions.schema.values?.[valueName]; const valueHandler = packageOptions.values?.[valueName]; if (!valueSchema || !valueHandler) { sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: false, error: `Unknown value: ${valueName}`, }); return; } const ctx = createRuntimeContext(stateContextId); try { const parsedResourceParams = parseResourceParams( "value", valueName, valueSchema, params, ); const result = await withRuntimeContext(ctx, async () => await valueHandler.get(ctx, parsedResourceParams), ); const parsedResult = parseResourceData( "value", valueName, valueSchema, result, ); sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: true, result: parsedResult, }); } catch (error) { await reportAndSendErrorResponse(socket, message.requestId, { phase: "value-get", error, stateContextId, resourceKind: "value", resourceName: valueName, }); } return; } if (message.method === "value-watch") { const parsedParams = ValueWatchRequestParamsSchema.safeParse( message.params, ); if (!parsedParams.success) { sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: false, error: "Invalid value watch params", }); return; } const { valueName, params, stateContextId } = parsedParams.data; if (!stateContextId) { sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: false, error: "Missing state context", }); return; } const valueSchema = packageOptions.schema.values?.[valueName]; const valueHandler = packageOptions.values?.[valueName]; if (!valueSchema || !valueHandler?.watch) { sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: false, error: `Unknown watchable value: ${valueName}`, }); return; } const ctx = createRuntimeContext(stateContextId); const subscriptionId = crypto.randomUUID(); try { const parsedResourceParams = parseResourceParams( "value", valueName, valueSchema, params, ); const cleanup = await withRuntimeContext(ctx, async () => await valueHandler.watch?.(ctx, parsedResourceParams, { subscriptionId, set: async (data) => { const parsedData = parseResourceData( "value", valueName, valueSchema, data, ); await publishToSubscription(subscriptionId, parsedData); }, }), ); serverSubscriptions.set(subscriptionId, { stateContextId: ctx.stateContext, kind: "value", resourceName: valueName, closeRemote: async () => { if (typeof cleanup === "function") { await runWithStateContext(ctx.stateContext, cleanup); } }, }); sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: true, result: { subscriptionId, }, }); } catch (error) { await reportAndSendErrorResponse(socket, message.requestId, { phase: "value-watch", error, stateContextId, resourceKind: "value", resourceName: valueName, }); } return; } if (message.method === "value-unwatch") { const parsedParams = ValueUnwatchRequestParamsSchema.safeParse( message.params, ); if (!parsedParams.success) { sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: false, error: "Invalid value unwatch params", }); return; } try { await closeServerSubscription(parsedParams.data.subscriptionId); sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: true, }); } catch (error) { sendErrorResponse(socket, message.requestId, error); } return; } sendClientMessage(socket, { type: "response", requestId: message.requestId, ok: false, error: "Unknown method", }); }; const handleMessage = (socket: WebSocket, data: WebSocket.RawData) => { const parsed = parseJson(data.toString()); if (!parsed.ok) { return; } const messageResult = ServerMessageSchema.safeParse(parsed.value); if (!messageResult.success) { return; } const message = messageResult.data; if (message.type === "auth-ack") { socketAuthenticated = true; runtimeExitRequested = false; clearRuntimeExitTimer(); if (socketResolve) { socketResolve(socket); socketResolve = null; } return; } if (message.type === "subscription-data") { const subscription = clientSubscriptions.get(message.subscriptionId); if (!subscription) { return; } subscription.deliver(message.data); return; } if (message.type === "response") { const pending = pendingRequests.get(message.requestId); if (!pending) { return; } pendingRequests.delete(message.requestId); clearTimeout(pending.timeout); if (message.ok === false) { pending.reject(new Error(message.error ?? "Unknown error")); } else { pending.resolve(message.result); } return; } if (message.type === "request") { void handleRequest(socket, message); } }; const ensureSocket = async (requireAuth: boolean) => { if (requireAuth && !process.env.QUIXOS_ORCH_SECRET) { throw new Error("QUIXOS_ORCH_SECRET is not set; cannot use orchestrator"); } if (!socketPromise) { socketPromise = new Promise((resolve) => { socketResolve = resolve; }); const socket = new WebSocket("ws://127.0.0.1:6245"); socketRef = socket; socket.on("open", () => { const secret = process.env.QUIXOS_ORCH_SECRET; if (secret) { sendClientMessage(socket, { type: "auth", secret, pid: process.pid, }); } else if (socketResolve) { socketResolve(socket); socketResolve = null; } }); socket.on("message", (eventData) => handleMessage(socket, eventData)); socket.on("close", resetSocket); socket.on("error", resetSocket); } const socket = await socketPromise; if (requireAuth && !socketAuthenticated) { return await socketPromise; } return socket; }; const sendRequest = async ( method: | "stop" | "call" | "boot" | "target-context-open" | "runtime-error" | "context-open" | "context-close" | "event-subscribe" | "subscription-ready" | "event-unsubscribe" | "value-get" | "value-watch" | "value-unwatch" | "subscription-publish", params: Record, timeoutMs?: number, ) => { const socket = await ensureSocket(true); const requestId = crypto.randomUUID(); const effectiveTimeoutMs = timeoutMs ?? (method === "boot" ? PACKAGE_BOOT_TIMEOUT_MS : method === "target-context-open" || method === "context-open" ? TARGET_CONTEXT_OPEN_TIMEOUT_MS : DEFAULT_REQUEST_TIMEOUT_MS); return await new Promise((resolve, reject) => { const timeout = setTimeout(() => { pendingRequests.delete(requestId); reject(new Error("Request timed out")); }, effectiveTimeoutMs); pendingRequests.set(requestId, { resolve, reject, timeout }); sendClientMessage(socket, { type: "request", requestId, method, params, }); }); }; export const publishToSubscription = async ( subscriptionId: string, data: unknown, ) => { await sendRequest("subscription-publish", { subscriptionId, data, }); }; const createPackageClient = ( schema: Schema, baseOptions: InternalUsePackageOptions = {}, ): PackageClient => { const meta = (schema as QuixosSchema).__quixos; if (!meta?.flakeRef) { throw new Error( "Package schema is missing __quixos metadata. Rebuild the schema with quixos helpers.", ); } const targetPackageName = resolveTargetPackageName(meta); let bootError: Error | null = null; let bootPromise: Promise | null = null; const ensureBooted = async () => { if (!bootPromise) { bootPromise = (async () => { try { await sendRequest("boot", { target: meta.flakeRef, }); } catch (error) { bootError = error instanceof Error ? error : new Error(String(error)); } })(); } await bootPromise; if (bootError) { throw bootError; } }; const createClient = ( scope: InternalUsePackageOptions, ): PackageClient => { let readyError: Error | null = null; let readyPromise: Promise | null = null; const resolveRouting = (callerStateContextId?: string) => ({ callerStateContextId: scope.callerStateContextId ?? callerStateContextId, targetStateContextId: scope.stateContextId, contextNamespace: scope.stateContextId ? undefined : scope.contextNamespace, }); const missingStateContextError = () => new Error( `No active state context for package ${targetPackageName}. Move this call into \`onContextOpen(ctx)\` or another handler with \`ctx.usePackage(...)\`, or pass \`stateContextId\` explicitly.`, ); const ensurePackageReady = async (callerStateContextId?: string) => { if (!readyPromise) { readyPromise = (async () => { try { await ensureBooted(); const routing = resolveRouting(callerStateContextId); if (!routing.callerStateContextId && !routing.targetStateContextId) { return; } await sendRequest("target-context-open", { target: meta.flakeRef, targetPackageName, callerStateContextId: routing.callerStateContextId, stateContextId: routing.targetStateContextId, contextNamespace: routing.contextNamespace, }); } catch (error) { readyError = error instanceof Error ? error : new Error(String(error)); } })(); } await readyPromise; if (readyError) { throw readyError; } }; const scopedResourceMethods = ( lookup: (client: PackageClient) => T, ) => ({ withStateContext: (stateContextId: string) => lookup( createClient({ ...scope, stateContextId, }), ), withContextNamespace: (contextNamespace?: string) => lookup( createClient({ ...scope, contextNamespace, }), ), }); const createManagedSubscription = ( subscriptionId: string, resourceKind: "event" | "value", resourceName: string, schemaType: SchemaType, handler: ( data: ZodOutput, ) => void | Promise, unsubscribeMethod: "event-unsubscribe" | "value-unwatch", subscriberStateContextId?: string, options?: SubscriptionOptions, ): SubscriptionHandle => { let closed = false; let abortHandler: (() => void) | null = null; let deliveryChain: Promise = Promise.resolve(); if (clientSubscriptions.has(subscriptionId)) { throw new Error( `Subscription ${subscriptionId} is already attached. Pass \`subscriptionNamespace\` to create a distinct logical subscription.`, ); } const closeLocal = (_error?: Error) => { if (closed) { return; } closed = true; clientSubscriptions.delete(subscriptionId); if (options?.signal && abortHandler) { options.signal.removeEventListener("abort", abortHandler); } }; const sendUnsubscribe = async () => { try { await sendRequest(unsubscribeMethod, { subscriptionId, }); } catch { // Ignore unsubscribe errors; local close already happened. } }; const unsubscribe = async () => { if (closed) { return; } closeLocal(); await sendUnsubscribe(); }; const fail = (error: Error) => { closeLocal(error); void sendUnsubscribe(); }; const deliver = (data: unknown) => { if (closed) { return; } let parsedData: ZodOutput; try { parsedData = parseResourceData( resourceKind, resourceName, schemaType, data, ); } catch (error) { fail(error instanceof Error ? error : new Error(String(error))); return; } deliveryChain = deliveryChain .then(async () => { if (closed) { return; } const invoke = async () => { await handler(parsedData); }; if (subscriberStateContextId) { await runWithStateContext(subscriberStateContextId, invoke); return; } await invoke(); }) .catch((error) => { fail(error instanceof Error ? error : new Error(String(error))); }); }; clientSubscriptions.set(subscriptionId, { deliver, closeLocal, }); if (options?.signal) { abortHandler = () => { void unsubscribe(); }; if (options.signal.aborted) { void unsubscribe(); } else { options.signal.addEventListener("abort", abortHandler); } } return { unsubscribe, }; }; const consumeEvent = async ( eventName: string, eventSchema: EventSchema, params: unknown, handler: (data: unknown) => void | Promise, options?: SubscriptionOptions, ) => { const callerStateContextId = getCurrentStateContextId(); await ensurePackageReady(callerStateContextId); const routing = resolveRouting(callerStateContextId); if (!routing.callerStateContextId && !routing.targetStateContextId) { throw missingStateContextError(); } const result = await sendRequest("event-subscribe", { target: meta.flakeRef, targetPackageName, eventName, params, callerStateContextId: routing.callerStateContextId, stateContextId: routing.targetStateContextId, contextNamespace: routing.contextNamespace, subscriptionNamespace: options?.subscriptionNamespace, }); const subscriptionId = (result as { subscriptionId?: string }) ?.subscriptionId; if (!subscriptionId) { throw new Error(`Subscription failed for event ${eventName}`); } const handle = createManagedSubscription( subscriptionId, "event", eventName, eventSchema, handler, "event-unsubscribe", callerStateContextId, options, ); try { await sendRequest("subscription-ready", { subscriptionId, }); } catch (error) { await handle.unsubscribe(); throw error; } return handle; }; const getValue = async ( valueName: string, valueSchema: ValueSchema, params: unknown, ) => { const callerStateContextId = getCurrentStateContextId(); await ensurePackageReady(callerStateContextId); const routing = resolveRouting(callerStateContextId); if (!routing.callerStateContextId && !routing.targetStateContextId) { throw missingStateContextError(); } const result = await sendRequest("value-get", { target: meta.flakeRef, targetPackageName, valueName, params, callerStateContextId: routing.callerStateContextId, stateContextId: routing.targetStateContextId, contextNamespace: routing.contextNamespace, }); return parseResourceData("value", valueName, valueSchema, result); }; const watchValue = async ( valueName: string, valueSchema: ValueSchema, params: unknown, handler: (data: unknown) => void | Promise, options?: SubscriptionOptions, ) => { const callerStateContextId = getCurrentStateContextId(); await ensurePackageReady(callerStateContextId); const routing = resolveRouting(callerStateContextId); if (!routing.callerStateContextId && !routing.targetStateContextId) { throw missingStateContextError(); } const result = await sendRequest("value-watch", { target: meta.flakeRef, targetPackageName, valueName, params, callerStateContextId: routing.callerStateContextId, stateContextId: routing.targetStateContextId, contextNamespace: routing.contextNamespace, subscriptionNamespace: options?.subscriptionNamespace, }); const subscriptionId = (result as { subscriptionId?: string }) ?.subscriptionId; if (!subscriptionId) { throw new Error(`Watch failed for value ${valueName}`); } const handle = createManagedSubscription( subscriptionId, "value", valueName, valueSchema, handler, "value-unwatch", callerStateContextId, options, ); try { await sendRequest("subscription-ready", { subscriptionId, }); } catch (error) { await handle.unsubscribe(); throw error; } return handle; }; const functions = new Proxy( {}, { get: (_target, prop) => { if (typeof prop !== "string") { return undefined; } const call = async (params: unknown) => { const callerStateContextId = getCurrentStateContextId(); await ensurePackageReady(callerStateContextId); const routing = resolveRouting(callerStateContextId); if (!routing.callerStateContextId && !routing.targetStateContextId) { throw missingStateContextError(); } return await sendRequest("call", { target: meta.flakeRef, targetPackageName, functionName: prop, params, callerStateContextId: routing.callerStateContextId, stateContextId: routing.targetStateContextId, contextNamespace: routing.contextNamespace, }); }; return Object.assign( call, scopedResourceMethods((client) => client.functions[prop]), ); }, }, ) as PackageFunctionCallers; const events = {} as EventClients; const eventEntries = Object.entries( (schema.events ?? {}) as EventSchemaMap, ); for (const [eventName, eventSchema] of eventEntries) { if (hasParamsSchema(eventSchema)) { (events as Record)[eventName] = Object.assign({ consume: async ( params: unknown, handler: (data: unknown) => void | Promise, options?: SubscriptionOptions, ) => { const parsedParams = eventSchema.paramsSchema.safeParse(params); if (!parsedParams.success) { throw new Error(`Invalid params for event ${eventName}`); } return await consumeEvent( eventName, eventSchema, parsedParams.data, handler, options, ); }, }, scopedResourceMethods((client) => client.events[eventName])); } else { (events as Record)[eventName] = Object.assign({ consume: async ( handler: (data: unknown) => void | Promise, options?: SubscriptionOptions, ) => await consumeEvent( eventName, eventSchema, undefined, handler, options, ), }, scopedResourceMethods((client) => client.events[eventName])); } } const values = {} as ValueClients; const valueEntries = Object.entries( (schema.values ?? {}) as ValueSchemaMap, ); for (const [valueName, valueSchema] of valueEntries) { if (hasParamsSchema(valueSchema)) { (values as Record)[valueName] = Object.assign({ get: async (params: unknown) => { const parsedParams = valueSchema.paramsSchema.safeParse(params); if (!parsedParams.success) { throw new Error(`Invalid params for value ${valueName}`); } return await getValue(valueName, valueSchema, parsedParams.data); }, watch: async ( params: unknown, handler: (data: unknown) => void | Promise, options?: SubscriptionOptions, ) => { const parsedParams = valueSchema.paramsSchema.safeParse(params); if (!parsedParams.success) { throw new Error(`Invalid params for value ${valueName}`); } return await watchValue( valueName, valueSchema, parsedParams.data, handler, options, ); }, }, scopedResourceMethods((client) => client.values[valueName])); } else { (values as Record)[valueName] = Object.assign({ get: async () => await getValue(valueName, valueSchema, undefined), watch: async ( handler: (data: unknown) => void | Promise, options?: SubscriptionOptions, ) => await watchValue( valueName, valueSchema, undefined, handler, options, ), }, scopedResourceMethods((client) => client.values[valueName])); } } const eagerCallerStateContextId = scope.callerStateContextId ?? getCurrentStateContextId(); if (eagerCallerStateContextId || scope.stateContextId) { void ensurePackageReady(eagerCallerStateContextId).catch((error) => { console.warn( `Failed to eagerly open child context for ${targetPackageName}: ${ error instanceof Error ? error.message : String(error) }`, ); }); } return { functions, events, values, withStateContext: (stateContextId: string) => createClient({ ...scope, stateContextId, }), withContextNamespace: (contextNamespace?: string) => createClient({ ...scope, contextNamespace, }), }; }; return createClient(baseOptions); }; export const createPackage = < Schema extends PackageSchema, Context extends PackageContext = PackageContext, >( options: CreatePackageOptions, ): LifecycleManager => { packageOptions = options; void ensureSocket(false); void (async () => { try { await options.onCreate?.(); } catch (error) { await reportPackageRuntimeError({ phase: "on-create", error, }); console.error( "[quixos-runtime] onCreate failed:", normalizeError(error).stack ?? normalizeError(error).message, ); } })(); return {}; };