@powerhousedao/reactor 6.2.3-dev.43 → 6.2.3-dev.45

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.
Files changed (30) hide show
  1. package/dist/{document-indexer-B3yKal-y.js → document-indexer-lfgXu9ph.js} +13 -4
  2. package/dist/document-indexer-lfgXu9ph.js.map +1 -0
  3. package/dist/drive-container-types-CifLQjd3.js +3766 -0
  4. package/dist/drive-container-types-CifLQjd3.js.map +1 -0
  5. package/dist/entry.js +99 -3
  6. package/dist/entry.js.map +1 -1
  7. package/dist/index-81SYQKda.d.ts +6353 -0
  8. package/dist/index-81SYQKda.d.ts.map +1 -0
  9. package/dist/index.d.ts +16 -6339
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +53 -49
  12. package/dist/index.js.map +1 -1
  13. package/dist/load-spec-f2ppXyKZ.js +3848 -0
  14. package/dist/load-spec-f2ppXyKZ.js.map +1 -0
  15. package/dist/projection-entry.js +2 -3
  16. package/dist/projection-entry.js.map +1 -1
  17. package/dist/{projection-shard-manager-BZPCQK-4.js → projection-shard-manager-XMam-rTs.js} +2 -2
  18. package/dist/{projection-shard-manager-BZPCQK-4.js.map → projection-shard-manager-XMam-rTs.js.map} +1 -1
  19. package/dist/rpc.d.ts +318 -0
  20. package/dist/rpc.d.ts.map +1 -0
  21. package/dist/rpc.js +570 -0
  22. package/dist/rpc.js.map +1 -0
  23. package/dist/{worker-handle-CefOwokd.js → worker-handle-BKuaSp9T.js} +2 -2
  24. package/dist/{worker-handle-CefOwokd.js.map → worker-handle-BKuaSp9T.js.map} +1 -1
  25. package/package.json +10 -4
  26. package/dist/build-worker-executor-Bonu2jUB.js +0 -105
  27. package/dist/build-worker-executor-Bonu2jUB.js.map +0 -1
  28. package/dist/document-indexer-B3yKal-y.js.map +0 -1
  29. package/dist/forwarding-logger-BKDP4JnD.js +0 -7593
  30. package/dist/forwarding-logger-BKDP4JnD.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"worker-handle-CefOwokd.js","names":[],"sources":["../src/executor/worker/worker-handle.ts"],"sourcesContent":["/**\n * Parent-side IPC wrapper around a single executor worker.\n *\n * Implements {@link IExecutorWorker} on top of an injectable\n * {@link IWorkerTransport}. The handle owns one worker's lifecycle (init ->\n * ready -> execute/result rounds -> abort/shutdown -> terminate) and bounds\n * its in-flight slot to a single job — `SimpleJobExecutor` is single-threaded\n * inside the worker, and concurrent dispatches would race its caches.\n *\n * @see Executor Worker Pool Design wiki page\n * (Powerhouse board wiki id: d400d711-f07e-4389-a226-4e9fdd4fa8ba)\n */\n\nimport type { ILogger } from \"document-model\";\nimport { randomUUID } from \"node:crypto\";\nimport type {\n IExecutorWorker,\n WorkerExecutionOutcome,\n WorkerInFlightSnapshot,\n} from \"../interfaces.js\";\nimport type { Job } from \"../../queue/types.js\";\nimport type { JobExecutorConfig } from \"../types.js\";\nimport { fromErrorInfo } from \"./error-info.js\";\nimport {\n WorkerAbortTimeoutError,\n WorkerBusyError,\n WorkerExitedError,\n WorkerInitFailedError,\n WorkerLoadModelFailedError,\n WorkerShutdownTimeoutError,\n} from \"./errors.js\";\nimport type { ForwardingPoolInstrumentation } from \"../../storage/pool-instrumentation.js\";\nimport type {\n DbConfig,\n FactorySpec,\n HeartbeatMessage,\n LogMessage,\n MetricsMessage,\n ModelLoadFailedMessage,\n ModelLoadedMessage,\n ModelManifestEntry,\n PoolAcquireSamplesMessage,\n ResultMessage,\n WorkerMessage,\n WorkerPoolConfig,\n} from \"./protocol.js\";\nimport type { IWorkerTransport, WorkerTransportListener } from \"./transport.js\";\n\nconst DEFAULT_ABORT_GRACE_MS = 5_000;\nconst DEFAULT_SHUTDOWN_GRACE_MS = 5_000;\n\n/**\n * Payload the parent ships in the `init` message (everything except the\n * envelope fields the handle fills in itself).\n */\nexport type WorkerInitPayload = {\n poolConfig: WorkerPoolConfig;\n db: DbConfig;\n models: ModelManifestEntry[];\n /** Omitted = the worker builds its executor with the built-in defaults. */\n executorConfig?: JobExecutorConfig;\n /** Builds the worker's signer for synthesized operations. */\n signer?: FactorySpec;\n /** Builds the worker's signature trust policy. */\n trustPolicy?: FactorySpec;\n};\n\nexport type WorkerHandleOptions = {\n workerId: string;\n index: number;\n transport: IWorkerTransport;\n initPayload: WorkerInitPayload;\n logger: ILogger;\n /** Grace period before an outstanding `abort` escalates to terminate. */\n abortGraceMs?: number;\n /** Default grace period applied to graceful `shutdown` when not overridden. */\n defaultShutdownGraceMs?: number;\n /**\n * Forwarding instrumentation the host registers per worker. The handle\n * pumps `pool-acquire-samples` messages into this object so the host's\n * OpenTelemetry instrumentation records acquire-wait latencies as if the\n * worker's pool were local.\n */\n poolInstrumentation?: ForwardingPoolInstrumentation;\n};\n\ntype PendingEntry =\n | {\n kind: \"init\";\n resolve: () => void;\n reject: (err: Error) => void;\n }\n | {\n kind: \"execute\";\n jobId: string;\n resolve: (outcome: WorkerExecutionOutcome) => void;\n reject: (err: Error) => void;\n }\n | {\n kind: \"shutdown\";\n resolve: () => void;\n reject: (err: Error) => void;\n }\n | {\n kind: \"load-model\";\n documentType: string;\n version: string;\n resolve: () => void;\n reject: (err: Error) => void;\n };\n\ntype Phase = \"fresh\" | \"starting\" | \"ready\" | \"shutting-down\" | \"terminated\";\n\nexport class WorkerHandle implements IExecutorWorker {\n readonly workerId: string;\n readonly index: number;\n\n private readonly transport: IWorkerTransport;\n private readonly initPayload: WorkerInitPayload;\n private readonly logger: ILogger;\n private readonly abortGraceMs: number;\n private readonly defaultShutdownGraceMs: number;\n private readonly poolInstrumentation?: ForwardingPoolInstrumentation;\n\n private readonly pending = new Map<string, PendingEntry>();\n private inFlight: { correlationId: string; jobId: string } | null = null;\n private phase: Phase = \"fresh\";\n private lastExitError: Error | null = null;\n private lastCorrelationId: string | null = null;\n private abortTimer: NodeJS.Timeout | null = null;\n private lastHeartbeatAt: number | null = null;\n private lastMetrics: {\n counters: Record<string, number>;\n gauges: Record<string, number>;\n timestamp: number;\n } | null = null;\n\n private readonly onMessage: WorkerTransportListener<\"message\">;\n private readonly onError: WorkerTransportListener<\"error\">;\n private readonly onExit: WorkerTransportListener<\"exit\">;\n\n constructor(options: WorkerHandleOptions) {\n this.workerId = options.workerId;\n this.index = options.index;\n this.transport = options.transport;\n this.initPayload = options.initPayload;\n this.logger = options.logger;\n this.abortGraceMs = options.abortGraceMs ?? DEFAULT_ABORT_GRACE_MS;\n this.defaultShutdownGraceMs =\n options.defaultShutdownGraceMs ?? DEFAULT_SHUTDOWN_GRACE_MS;\n this.poolInstrumentation = options.poolInstrumentation;\n\n this.onMessage = (msg) => this.handleMessage(msg);\n this.onError = (err) => this.handleTransportError(err);\n this.onExit = (code) => this.handleExit(code);\n\n this.transport.on(\"message\", this.onMessage);\n this.transport.on(\"error\", this.onError);\n this.transport.on(\"exit\", this.onExit);\n }\n\n public async start(): Promise<void> {\n if (this.phase !== \"fresh\") {\n throw new WorkerInitFailedError(\n this.workerId,\n `cannot start worker in phase ${this.phase}`,\n );\n }\n this.phase = \"starting\";\n const correlationId = this.nextCorrelationId();\n const ready = new Promise<void>((resolve, reject) => {\n this.pending.set(correlationId, {\n kind: \"init\",\n resolve,\n reject,\n });\n });\n this.transport.postMessage({\n type: \"init\",\n correlationId,\n workerId: this.workerId,\n poolConfig: this.initPayload.poolConfig,\n db: this.initPayload.db,\n models: this.initPayload.models,\n executorConfig: this.initPayload.executorConfig,\n signer: this.initPayload.signer,\n trustPolicy: this.initPayload.trustPolicy,\n });\n await ready;\n this.phase = \"ready\";\n }\n\n public execute(\n job: Job,\n signal?: AbortSignal,\n ): Promise<WorkerExecutionOutcome> {\n if (this.phase === \"terminated\") {\n return Promise.reject(\n this.lastExitError ??\n new WorkerExitedError(this.workerId, -1, this.lastCorrelationId),\n );\n }\n if (this.phase !== \"ready\") {\n return Promise.reject(\n new WorkerInitFailedError(\n this.workerId,\n `worker not ready (phase=${this.phase})`,\n ),\n );\n }\n if (this.inFlight !== null) {\n return Promise.reject(new WorkerBusyError(this.workerId, job.id));\n }\n\n const correlationId = this.nextCorrelationId();\n this.lastCorrelationId = correlationId;\n this.inFlight = { correlationId, jobId: job.id };\n\n let abortListener: (() => void) | null = null;\n const detachSignal = () => {\n if (signal && abortListener) {\n signal.removeEventListener(\"abort\", abortListener);\n abortListener = null;\n }\n };\n\n const promise = new Promise<WorkerExecutionOutcome>((resolve, reject) => {\n this.pending.set(correlationId, {\n kind: \"execute\",\n jobId: job.id,\n resolve: (outcome) => {\n detachSignal();\n resolve(outcome);\n },\n reject: (err) => {\n detachSignal();\n reject(err);\n },\n });\n });\n\n if (signal) {\n if (signal.aborted) {\n this.abort(correlationId, \"aborted before dispatch\");\n } else {\n abortListener = () => this.abort(correlationId, \"caller signal\");\n signal.addEventListener(\"abort\", abortListener, { once: true });\n }\n }\n\n this.transport.postMessage({\n type: \"execute\",\n correlationId,\n job,\n });\n\n return promise;\n }\n\n public abort(correlationId: string, reason?: string): void {\n if (this.phase === \"terminated\") {\n return;\n }\n if (!this.inFlight || this.inFlight.correlationId !== correlationId) {\n return;\n }\n if (this.abortTimer) {\n return;\n }\n this.transport.postMessage({\n type: \"abort\",\n correlationId: this.nextCorrelationId(),\n targetCorrelationId: correlationId,\n reason,\n });\n this.abortTimer = setTimeout(() => {\n this.abortTimer = null;\n const entry = this.pending.get(correlationId);\n if (!entry || entry.kind !== \"execute\") {\n return;\n }\n const err = new WorkerAbortTimeoutError(\n this.workerId,\n correlationId,\n this.abortGraceMs,\n );\n this.failPending(correlationId, err);\n this.inFlight = null;\n void this.forceTerminate(err);\n }, this.abortGraceMs);\n }\n\n public async shutdown(graceful: boolean, graceMs?: number): Promise<void> {\n if (this.phase === \"terminated\") {\n return;\n }\n if (!graceful) {\n this.phase = \"shutting-down\";\n await this.forceTerminate(null);\n return;\n }\n\n const effectiveGrace = graceMs ?? this.defaultShutdownGraceMs;\n this.phase = \"shutting-down\";\n const correlationId = this.nextCorrelationId();\n const drained = new Promise<void>((resolve, reject) => {\n this.pending.set(correlationId, {\n kind: \"shutdown\",\n resolve,\n reject,\n });\n });\n this.transport.postMessage({\n type: \"shutdown\",\n correlationId,\n graceMs: effectiveGrace,\n });\n\n let timer!: NodeJS.Timeout;\n const timeout = new Promise<void>((_, reject) => {\n timer = setTimeout(() => {\n reject(new WorkerShutdownTimeoutError(this.workerId, effectiveGrace));\n }, effectiveGrace);\n });\n\n try {\n await Promise.race([drained, timeout]);\n } catch (err) {\n this.logger.warn(\n `worker ${this.workerId} shutdown timed out after ${effectiveGrace}ms`,\n err,\n );\n } finally {\n clearTimeout(timer);\n }\n\n await this.forceTerminate(null);\n }\n\n public loadModel(\n entry: ModelManifestEntry,\n signal?: AbortSignal,\n ): Promise<void> {\n if (this.phase === \"terminated\") {\n return Promise.reject(\n this.lastExitError ??\n new WorkerExitedError(this.workerId, -1, this.lastCorrelationId),\n );\n }\n if (this.phase !== \"ready\") {\n return Promise.reject(\n new WorkerInitFailedError(\n this.workerId,\n `worker not ready (phase=${this.phase})`,\n ),\n );\n }\n\n const correlationId = this.nextCorrelationId();\n let abortListener: (() => void) | null = null;\n const detachSignal = () => {\n if (signal && abortListener) {\n signal.removeEventListener(\"abort\", abortListener);\n abortListener = null;\n }\n };\n\n const promise = new Promise<void>((resolve, reject) => {\n this.pending.set(correlationId, {\n kind: \"load-model\",\n documentType: entry.documentType,\n version: entry.version,\n resolve: () => {\n detachSignal();\n resolve();\n },\n reject: (err) => {\n detachSignal();\n reject(err);\n },\n });\n });\n\n if (signal) {\n if (signal.aborted) {\n this.failPending(\n correlationId,\n new WorkerLoadModelFailedError(\n this.workerId,\n entry.documentType,\n entry.version,\n \"aborted before dispatch\",\n ),\n );\n return promise;\n }\n abortListener = () => {\n this.failPending(\n correlationId,\n new WorkerLoadModelFailedError(\n this.workerId,\n entry.documentType,\n entry.version,\n \"caller signal\",\n ),\n );\n };\n signal.addEventListener(\"abort\", abortListener, { once: true });\n }\n\n this.transport.postMessage({\n type: \"load-model\",\n correlationId,\n model: entry,\n });\n\n return promise;\n }\n\n public evictPurged(documentIds: string[]): void {\n if (this.phase !== \"ready\" || documentIds.length === 0) {\n return;\n }\n this.transport.postMessage({ type: \"evict-purged\", documentIds });\n }\n\n public isIdle(): boolean {\n return this.inFlight === null && this.phase === \"ready\";\n }\n\n public getInFlight(): WorkerInFlightSnapshot | null {\n if (!this.inFlight) {\n return null;\n }\n return {\n correlationId: this.inFlight.correlationId,\n jobId: this.inFlight.jobId,\n };\n }\n\n private nextCorrelationId(): string {\n return randomUUID();\n }\n\n private handleMessage(msg: WorkerMessage): void {\n switch (msg.type) {\n case \"ready\":\n this.handleReady(msg.correlationId);\n return;\n case \"result\":\n this.handleResult(msg);\n return;\n case \"model-loaded\":\n this.handleModelLoaded(msg);\n return;\n case \"model-load-failed\":\n this.handleModelLoadFailed(msg);\n return;\n case \"log\":\n this.handleLog(msg);\n return;\n case \"heartbeat\":\n this.handleHeartbeat(msg);\n return;\n case \"metrics\":\n this.handleMetrics(msg);\n return;\n case \"pool-acquire-samples\":\n this.handlePoolAcquireSamples(msg);\n return;\n default: {\n const exhaustive: never = msg;\n void exhaustive;\n }\n }\n }\n\n private handlePoolAcquireSamples(msg: PoolAcquireSamplesMessage): void {\n if (!this.poolInstrumentation) {\n return;\n }\n this.poolInstrumentation.updateStats({\n size: msg.size,\n idle: msg.idle,\n waiting: msg.waiting,\n });\n this.poolInstrumentation.pushSamples(msg.durations);\n }\n\n private handleReady(correlationId: string): void {\n const entry = this.pending.get(correlationId);\n if (!entry || entry.kind !== \"init\") {\n return;\n }\n this.pending.delete(correlationId);\n entry.resolve();\n }\n\n private handleResult(msg: ResultMessage): void {\n const entry = this.pending.get(msg.correlationId);\n if (!entry || entry.kind !== \"execute\") {\n return;\n }\n this.pending.delete(msg.correlationId);\n if (this.inFlight?.correlationId === msg.correlationId) {\n this.inFlight = null;\n }\n if (this.abortTimer) {\n clearTimeout(this.abortTimer);\n this.abortTimer = null;\n }\n\n const outcome: WorkerExecutionOutcome = msg.error\n ? {\n result: {\n ...msg.result,\n success: false,\n error: fromErrorInfo(msg.error),\n },\n signatureRefusals: msg.signatureRefusals,\n }\n : {\n result: msg.result,\n writeReady: msg.writeReady,\n signatureRefusals: msg.signatureRefusals,\n };\n entry.resolve(outcome);\n\n if (this.phase === \"shutting-down\") {\n const shutdownEntry = [...this.pending.values()].find(\n (e) => e.kind === \"shutdown\",\n );\n if (shutdownEntry) {\n shutdownEntry.resolve();\n }\n }\n }\n\n private handleModelLoaded(msg: ModelLoadedMessage): void {\n const entry = this.pending.get(msg.correlationId);\n if (!entry || entry.kind !== \"load-model\") {\n return;\n }\n this.pending.delete(msg.correlationId);\n entry.resolve();\n }\n\n private handleModelLoadFailed(msg: ModelLoadFailedMessage): void {\n const entry = this.pending.get(msg.correlationId);\n if (!entry || entry.kind !== \"load-model\") {\n return;\n }\n this.pending.delete(msg.correlationId);\n entry.reject(\n new WorkerLoadModelFailedError(\n this.workerId,\n msg.documentType,\n msg.version,\n msg.error.message,\n { cause: fromErrorInfo(msg.error) },\n ),\n );\n }\n\n private handleLog(msg: LogMessage): void {\n const args = msg.args;\n switch (msg.level) {\n case \"debug\":\n this.logger.debug(msg.message, ...args);\n return;\n case \"info\":\n this.logger.info(msg.message, ...args);\n return;\n case \"warn\":\n this.logger.warn(msg.message, ...args);\n return;\n case \"error\":\n this.logger.error(msg.message, ...args);\n return;\n default: {\n const exhaustive: never = msg.level;\n void exhaustive;\n }\n }\n }\n\n private handleHeartbeat(msg: HeartbeatMessage): void {\n this.lastHeartbeatAt = msg.timestamp;\n }\n\n private handleMetrics(msg: MetricsMessage): void {\n this.lastMetrics = {\n counters: msg.counters,\n gauges: msg.gauges,\n timestamp: msg.timestamp,\n };\n }\n\n private handleTransportError(err: Error): void {\n this.logger.error(\n `worker ${this.workerId} transport error: @message`,\n err.message,\n err,\n );\n }\n\n private handleExit(code: number): void {\n if (this.phase === \"terminated\") {\n return;\n }\n const wasGraceful = this.phase === \"shutting-down\" && code === 0;\n this.phase = \"terminated\";\n const err = wasGraceful\n ? null\n : new WorkerExitedError(this.workerId, code, this.lastCorrelationId);\n this.lastExitError = err;\n if (this.abortTimer) {\n clearTimeout(this.abortTimer);\n this.abortTimer = null;\n }\n this.detachTransportListeners();\n this.drainPending(err);\n this.inFlight = null;\n }\n\n private detachTransportListeners(): void {\n this.transport.off(\"message\", this.onMessage);\n this.transport.off(\"error\", this.onError);\n this.transport.off(\"exit\", this.onExit);\n }\n\n private drainPending(err: Error | null): void {\n for (const [, entry] of this.pending) {\n if (err) {\n entry.reject(err);\n } else if (entry.kind === \"shutdown\") {\n entry.resolve();\n } else if (entry.kind === \"init\") {\n entry.reject(new WorkerInitFailedError(this.workerId, \"worker exited\"));\n } else if (entry.kind === \"load-model\") {\n entry.reject(\n new WorkerLoadModelFailedError(\n this.workerId,\n entry.documentType,\n entry.version,\n \"worker exited before responding\",\n ),\n );\n } else {\n entry.reject(\n new WorkerExitedError(this.workerId, 0, this.lastCorrelationId),\n );\n }\n }\n this.pending.clear();\n }\n\n private failPending(correlationId: string, err: Error): void {\n const entry = this.pending.get(correlationId);\n if (!entry) {\n return;\n }\n this.pending.delete(correlationId);\n entry.reject(err);\n }\n\n private async forceTerminate(reason: Error | null): Promise<void> {\n if (this.phase === \"terminated\") {\n return;\n }\n try {\n await this.transport.terminate();\n } catch (err) {\n this.logger.warn(\n `worker ${this.workerId} terminate threw: ${(err as Error).message}`,\n );\n }\n const phaseAfter = this.phase as Phase;\n if (phaseAfter === \"terminated\") {\n return;\n }\n this.phase = \"terminated\";\n this.lastExitError = reason;\n this.detachTransportListeners();\n this.drainPending(reason);\n this.inFlight = null;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"worker-handle-BKuaSp9T.js","names":[],"sources":["../src/executor/worker/worker-handle.ts"],"sourcesContent":["/**\n * Parent-side IPC wrapper around a single executor worker.\n *\n * Implements {@link IExecutorWorker} on top of an injectable\n * {@link IWorkerTransport}. The handle owns one worker's lifecycle (init ->\n * ready -> execute/result rounds -> abort/shutdown -> terminate) and bounds\n * its in-flight slot to a single job — `SimpleJobExecutor` is single-threaded\n * inside the worker, and concurrent dispatches would race its caches.\n *\n * @see Executor Worker Pool Design wiki page\n * (Powerhouse board wiki id: d400d711-f07e-4389-a226-4e9fdd4fa8ba)\n */\n\nimport type { ILogger } from \"document-model\";\nimport { randomUUID } from \"node:crypto\";\nimport type {\n IExecutorWorker,\n WorkerExecutionOutcome,\n WorkerInFlightSnapshot,\n} from \"../interfaces.js\";\nimport type { Job } from \"../../queue/types.js\";\nimport type { JobExecutorConfig } from \"../types.js\";\nimport { fromErrorInfo } from \"./error-info.js\";\nimport {\n WorkerAbortTimeoutError,\n WorkerBusyError,\n WorkerExitedError,\n WorkerInitFailedError,\n WorkerLoadModelFailedError,\n WorkerShutdownTimeoutError,\n} from \"./errors.js\";\nimport type { ForwardingPoolInstrumentation } from \"../../storage/pool-instrumentation.js\";\nimport type {\n DbConfig,\n FactorySpec,\n HeartbeatMessage,\n LogMessage,\n MetricsMessage,\n ModelLoadFailedMessage,\n ModelLoadedMessage,\n ModelManifestEntry,\n PoolAcquireSamplesMessage,\n ResultMessage,\n WorkerMessage,\n WorkerPoolConfig,\n} from \"./protocol.js\";\nimport type { IWorkerTransport, WorkerTransportListener } from \"./transport.js\";\n\nconst DEFAULT_ABORT_GRACE_MS = 5_000;\nconst DEFAULT_SHUTDOWN_GRACE_MS = 5_000;\n\n/**\n * Payload the parent ships in the `init` message (everything except the\n * envelope fields the handle fills in itself).\n */\nexport type WorkerInitPayload = {\n poolConfig: WorkerPoolConfig;\n db: DbConfig;\n models: ModelManifestEntry[];\n /** Omitted = the worker builds its executor with the built-in defaults. */\n executorConfig?: JobExecutorConfig;\n /** Builds the worker's signer for synthesized operations. */\n signer?: FactorySpec;\n /** Builds the worker's signature trust policy. */\n trustPolicy?: FactorySpec;\n};\n\nexport type WorkerHandleOptions = {\n workerId: string;\n index: number;\n transport: IWorkerTransport;\n initPayload: WorkerInitPayload;\n logger: ILogger;\n /** Grace period before an outstanding `abort` escalates to terminate. */\n abortGraceMs?: number;\n /** Default grace period applied to graceful `shutdown` when not overridden. */\n defaultShutdownGraceMs?: number;\n /**\n * Forwarding instrumentation the host registers per worker. The handle\n * pumps `pool-acquire-samples` messages into this object so the host's\n * OpenTelemetry instrumentation records acquire-wait latencies as if the\n * worker's pool were local.\n */\n poolInstrumentation?: ForwardingPoolInstrumentation;\n};\n\ntype PendingEntry =\n | {\n kind: \"init\";\n resolve: () => void;\n reject: (err: Error) => void;\n }\n | {\n kind: \"execute\";\n jobId: string;\n resolve: (outcome: WorkerExecutionOutcome) => void;\n reject: (err: Error) => void;\n }\n | {\n kind: \"shutdown\";\n resolve: () => void;\n reject: (err: Error) => void;\n }\n | {\n kind: \"load-model\";\n documentType: string;\n version: string;\n resolve: () => void;\n reject: (err: Error) => void;\n };\n\ntype Phase = \"fresh\" | \"starting\" | \"ready\" | \"shutting-down\" | \"terminated\";\n\nexport class WorkerHandle implements IExecutorWorker {\n readonly workerId: string;\n readonly index: number;\n\n private readonly transport: IWorkerTransport;\n private readonly initPayload: WorkerInitPayload;\n private readonly logger: ILogger;\n private readonly abortGraceMs: number;\n private readonly defaultShutdownGraceMs: number;\n private readonly poolInstrumentation?: ForwardingPoolInstrumentation;\n\n private readonly pending = new Map<string, PendingEntry>();\n private inFlight: { correlationId: string; jobId: string } | null = null;\n private phase: Phase = \"fresh\";\n private lastExitError: Error | null = null;\n private lastCorrelationId: string | null = null;\n private abortTimer: NodeJS.Timeout | null = null;\n private lastHeartbeatAt: number | null = null;\n private lastMetrics: {\n counters: Record<string, number>;\n gauges: Record<string, number>;\n timestamp: number;\n } | null = null;\n\n private readonly onMessage: WorkerTransportListener<\"message\">;\n private readonly onError: WorkerTransportListener<\"error\">;\n private readonly onExit: WorkerTransportListener<\"exit\">;\n\n constructor(options: WorkerHandleOptions) {\n this.workerId = options.workerId;\n this.index = options.index;\n this.transport = options.transport;\n this.initPayload = options.initPayload;\n this.logger = options.logger;\n this.abortGraceMs = options.abortGraceMs ?? DEFAULT_ABORT_GRACE_MS;\n this.defaultShutdownGraceMs =\n options.defaultShutdownGraceMs ?? DEFAULT_SHUTDOWN_GRACE_MS;\n this.poolInstrumentation = options.poolInstrumentation;\n\n this.onMessage = (msg) => this.handleMessage(msg);\n this.onError = (err) => this.handleTransportError(err);\n this.onExit = (code) => this.handleExit(code);\n\n this.transport.on(\"message\", this.onMessage);\n this.transport.on(\"error\", this.onError);\n this.transport.on(\"exit\", this.onExit);\n }\n\n public async start(): Promise<void> {\n if (this.phase !== \"fresh\") {\n throw new WorkerInitFailedError(\n this.workerId,\n `cannot start worker in phase ${this.phase}`,\n );\n }\n this.phase = \"starting\";\n const correlationId = this.nextCorrelationId();\n const ready = new Promise<void>((resolve, reject) => {\n this.pending.set(correlationId, {\n kind: \"init\",\n resolve,\n reject,\n });\n });\n this.transport.postMessage({\n type: \"init\",\n correlationId,\n workerId: this.workerId,\n poolConfig: this.initPayload.poolConfig,\n db: this.initPayload.db,\n models: this.initPayload.models,\n executorConfig: this.initPayload.executorConfig,\n signer: this.initPayload.signer,\n trustPolicy: this.initPayload.trustPolicy,\n });\n await ready;\n this.phase = \"ready\";\n }\n\n public execute(\n job: Job,\n signal?: AbortSignal,\n ): Promise<WorkerExecutionOutcome> {\n if (this.phase === \"terminated\") {\n return Promise.reject(\n this.lastExitError ??\n new WorkerExitedError(this.workerId, -1, this.lastCorrelationId),\n );\n }\n if (this.phase !== \"ready\") {\n return Promise.reject(\n new WorkerInitFailedError(\n this.workerId,\n `worker not ready (phase=${this.phase})`,\n ),\n );\n }\n if (this.inFlight !== null) {\n return Promise.reject(new WorkerBusyError(this.workerId, job.id));\n }\n\n const correlationId = this.nextCorrelationId();\n this.lastCorrelationId = correlationId;\n this.inFlight = { correlationId, jobId: job.id };\n\n let abortListener: (() => void) | null = null;\n const detachSignal = () => {\n if (signal && abortListener) {\n signal.removeEventListener(\"abort\", abortListener);\n abortListener = null;\n }\n };\n\n const promise = new Promise<WorkerExecutionOutcome>((resolve, reject) => {\n this.pending.set(correlationId, {\n kind: \"execute\",\n jobId: job.id,\n resolve: (outcome) => {\n detachSignal();\n resolve(outcome);\n },\n reject: (err) => {\n detachSignal();\n reject(err);\n },\n });\n });\n\n if (signal) {\n if (signal.aborted) {\n this.abort(correlationId, \"aborted before dispatch\");\n } else {\n abortListener = () => this.abort(correlationId, \"caller signal\");\n signal.addEventListener(\"abort\", abortListener, { once: true });\n }\n }\n\n this.transport.postMessage({\n type: \"execute\",\n correlationId,\n job,\n });\n\n return promise;\n }\n\n public abort(correlationId: string, reason?: string): void {\n if (this.phase === \"terminated\") {\n return;\n }\n if (!this.inFlight || this.inFlight.correlationId !== correlationId) {\n return;\n }\n if (this.abortTimer) {\n return;\n }\n this.transport.postMessage({\n type: \"abort\",\n correlationId: this.nextCorrelationId(),\n targetCorrelationId: correlationId,\n reason,\n });\n this.abortTimer = setTimeout(() => {\n this.abortTimer = null;\n const entry = this.pending.get(correlationId);\n if (!entry || entry.kind !== \"execute\") {\n return;\n }\n const err = new WorkerAbortTimeoutError(\n this.workerId,\n correlationId,\n this.abortGraceMs,\n );\n this.failPending(correlationId, err);\n this.inFlight = null;\n void this.forceTerminate(err);\n }, this.abortGraceMs);\n }\n\n public async shutdown(graceful: boolean, graceMs?: number): Promise<void> {\n if (this.phase === \"terminated\") {\n return;\n }\n if (!graceful) {\n this.phase = \"shutting-down\";\n await this.forceTerminate(null);\n return;\n }\n\n const effectiveGrace = graceMs ?? this.defaultShutdownGraceMs;\n this.phase = \"shutting-down\";\n const correlationId = this.nextCorrelationId();\n const drained = new Promise<void>((resolve, reject) => {\n this.pending.set(correlationId, {\n kind: \"shutdown\",\n resolve,\n reject,\n });\n });\n this.transport.postMessage({\n type: \"shutdown\",\n correlationId,\n graceMs: effectiveGrace,\n });\n\n let timer!: NodeJS.Timeout;\n const timeout = new Promise<void>((_, reject) => {\n timer = setTimeout(() => {\n reject(new WorkerShutdownTimeoutError(this.workerId, effectiveGrace));\n }, effectiveGrace);\n });\n\n try {\n await Promise.race([drained, timeout]);\n } catch (err) {\n this.logger.warn(\n `worker ${this.workerId} shutdown timed out after ${effectiveGrace}ms`,\n err,\n );\n } finally {\n clearTimeout(timer);\n }\n\n await this.forceTerminate(null);\n }\n\n public loadModel(\n entry: ModelManifestEntry,\n signal?: AbortSignal,\n ): Promise<void> {\n if (this.phase === \"terminated\") {\n return Promise.reject(\n this.lastExitError ??\n new WorkerExitedError(this.workerId, -1, this.lastCorrelationId),\n );\n }\n if (this.phase !== \"ready\") {\n return Promise.reject(\n new WorkerInitFailedError(\n this.workerId,\n `worker not ready (phase=${this.phase})`,\n ),\n );\n }\n\n const correlationId = this.nextCorrelationId();\n let abortListener: (() => void) | null = null;\n const detachSignal = () => {\n if (signal && abortListener) {\n signal.removeEventListener(\"abort\", abortListener);\n abortListener = null;\n }\n };\n\n const promise = new Promise<void>((resolve, reject) => {\n this.pending.set(correlationId, {\n kind: \"load-model\",\n documentType: entry.documentType,\n version: entry.version,\n resolve: () => {\n detachSignal();\n resolve();\n },\n reject: (err) => {\n detachSignal();\n reject(err);\n },\n });\n });\n\n if (signal) {\n if (signal.aborted) {\n this.failPending(\n correlationId,\n new WorkerLoadModelFailedError(\n this.workerId,\n entry.documentType,\n entry.version,\n \"aborted before dispatch\",\n ),\n );\n return promise;\n }\n abortListener = () => {\n this.failPending(\n correlationId,\n new WorkerLoadModelFailedError(\n this.workerId,\n entry.documentType,\n entry.version,\n \"caller signal\",\n ),\n );\n };\n signal.addEventListener(\"abort\", abortListener, { once: true });\n }\n\n this.transport.postMessage({\n type: \"load-model\",\n correlationId,\n model: entry,\n });\n\n return promise;\n }\n\n public evictPurged(documentIds: string[]): void {\n if (this.phase !== \"ready\" || documentIds.length === 0) {\n return;\n }\n this.transport.postMessage({ type: \"evict-purged\", documentIds });\n }\n\n public isIdle(): boolean {\n return this.inFlight === null && this.phase === \"ready\";\n }\n\n public getInFlight(): WorkerInFlightSnapshot | null {\n if (!this.inFlight) {\n return null;\n }\n return {\n correlationId: this.inFlight.correlationId,\n jobId: this.inFlight.jobId,\n };\n }\n\n private nextCorrelationId(): string {\n return randomUUID();\n }\n\n private handleMessage(msg: WorkerMessage): void {\n switch (msg.type) {\n case \"ready\":\n this.handleReady(msg.correlationId);\n return;\n case \"result\":\n this.handleResult(msg);\n return;\n case \"model-loaded\":\n this.handleModelLoaded(msg);\n return;\n case \"model-load-failed\":\n this.handleModelLoadFailed(msg);\n return;\n case \"log\":\n this.handleLog(msg);\n return;\n case \"heartbeat\":\n this.handleHeartbeat(msg);\n return;\n case \"metrics\":\n this.handleMetrics(msg);\n return;\n case \"pool-acquire-samples\":\n this.handlePoolAcquireSamples(msg);\n return;\n default: {\n const exhaustive: never = msg;\n void exhaustive;\n }\n }\n }\n\n private handlePoolAcquireSamples(msg: PoolAcquireSamplesMessage): void {\n if (!this.poolInstrumentation) {\n return;\n }\n this.poolInstrumentation.updateStats({\n size: msg.size,\n idle: msg.idle,\n waiting: msg.waiting,\n });\n this.poolInstrumentation.pushSamples(msg.durations);\n }\n\n private handleReady(correlationId: string): void {\n const entry = this.pending.get(correlationId);\n if (!entry || entry.kind !== \"init\") {\n return;\n }\n this.pending.delete(correlationId);\n entry.resolve();\n }\n\n private handleResult(msg: ResultMessage): void {\n const entry = this.pending.get(msg.correlationId);\n if (!entry || entry.kind !== \"execute\") {\n return;\n }\n this.pending.delete(msg.correlationId);\n if (this.inFlight?.correlationId === msg.correlationId) {\n this.inFlight = null;\n }\n if (this.abortTimer) {\n clearTimeout(this.abortTimer);\n this.abortTimer = null;\n }\n\n const outcome: WorkerExecutionOutcome = msg.error\n ? {\n result: {\n ...msg.result,\n success: false,\n error: fromErrorInfo(msg.error),\n },\n signatureRefusals: msg.signatureRefusals,\n }\n : {\n result: msg.result,\n writeReady: msg.writeReady,\n signatureRefusals: msg.signatureRefusals,\n };\n entry.resolve(outcome);\n\n if (this.phase === \"shutting-down\") {\n const shutdownEntry = [...this.pending.values()].find(\n (e) => e.kind === \"shutdown\",\n );\n if (shutdownEntry) {\n shutdownEntry.resolve();\n }\n }\n }\n\n private handleModelLoaded(msg: ModelLoadedMessage): void {\n const entry = this.pending.get(msg.correlationId);\n if (!entry || entry.kind !== \"load-model\") {\n return;\n }\n this.pending.delete(msg.correlationId);\n entry.resolve();\n }\n\n private handleModelLoadFailed(msg: ModelLoadFailedMessage): void {\n const entry = this.pending.get(msg.correlationId);\n if (!entry || entry.kind !== \"load-model\") {\n return;\n }\n this.pending.delete(msg.correlationId);\n entry.reject(\n new WorkerLoadModelFailedError(\n this.workerId,\n msg.documentType,\n msg.version,\n msg.error.message,\n { cause: fromErrorInfo(msg.error) },\n ),\n );\n }\n\n private handleLog(msg: LogMessage): void {\n const args = msg.args;\n switch (msg.level) {\n case \"debug\":\n this.logger.debug(msg.message, ...args);\n return;\n case \"info\":\n this.logger.info(msg.message, ...args);\n return;\n case \"warn\":\n this.logger.warn(msg.message, ...args);\n return;\n case \"error\":\n this.logger.error(msg.message, ...args);\n return;\n default: {\n const exhaustive: never = msg.level;\n void exhaustive;\n }\n }\n }\n\n private handleHeartbeat(msg: HeartbeatMessage): void {\n this.lastHeartbeatAt = msg.timestamp;\n }\n\n private handleMetrics(msg: MetricsMessage): void {\n this.lastMetrics = {\n counters: msg.counters,\n gauges: msg.gauges,\n timestamp: msg.timestamp,\n };\n }\n\n private handleTransportError(err: Error): void {\n this.logger.error(\n `worker ${this.workerId} transport error: @message`,\n err.message,\n err,\n );\n }\n\n private handleExit(code: number): void {\n if (this.phase === \"terminated\") {\n return;\n }\n const wasGraceful = this.phase === \"shutting-down\" && code === 0;\n this.phase = \"terminated\";\n const err = wasGraceful\n ? null\n : new WorkerExitedError(this.workerId, code, this.lastCorrelationId);\n this.lastExitError = err;\n if (this.abortTimer) {\n clearTimeout(this.abortTimer);\n this.abortTimer = null;\n }\n this.detachTransportListeners();\n this.drainPending(err);\n this.inFlight = null;\n }\n\n private detachTransportListeners(): void {\n this.transport.off(\"message\", this.onMessage);\n this.transport.off(\"error\", this.onError);\n this.transport.off(\"exit\", this.onExit);\n }\n\n private drainPending(err: Error | null): void {\n for (const [, entry] of this.pending) {\n if (err) {\n entry.reject(err);\n } else if (entry.kind === \"shutdown\") {\n entry.resolve();\n } else if (entry.kind === \"init\") {\n entry.reject(new WorkerInitFailedError(this.workerId, \"worker exited\"));\n } else if (entry.kind === \"load-model\") {\n entry.reject(\n new WorkerLoadModelFailedError(\n this.workerId,\n entry.documentType,\n entry.version,\n \"worker exited before responding\",\n ),\n );\n } else {\n entry.reject(\n new WorkerExitedError(this.workerId, 0, this.lastCorrelationId),\n );\n }\n }\n this.pending.clear();\n }\n\n private failPending(correlationId: string, err: Error): void {\n const entry = this.pending.get(correlationId);\n if (!entry) {\n return;\n }\n this.pending.delete(correlationId);\n entry.reject(err);\n }\n\n private async forceTerminate(reason: Error | null): Promise<void> {\n if (this.phase === \"terminated\") {\n return;\n }\n try {\n await this.transport.terminate();\n } catch (err) {\n this.logger.warn(\n `worker ${this.workerId} terminate threw: ${(err as Error).message}`,\n );\n }\n const phaseAfter = this.phase as Phase;\n if (phaseAfter === \"terminated\") {\n return;\n }\n this.phase = \"terminated\";\n this.lastExitError = reason;\n this.detachTransportListeners();\n this.drainPending(reason);\n this.inFlight = null;\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@powerhousedao/reactor",
3
- "version": "6.2.3-dev.43",
3
+ "version": "6.2.3-dev.45",
4
4
  "description": "Core Powerhouse reactor — stores documents, resolves conflicts, and reprocesses operation histories. Supports local, cloud, and decentralized storage backends.",
5
5
  "repository": {
6
6
  "url": "https://github.com/powerhouse-inc/powerhouse",
@@ -14,6 +14,11 @@
14
14
  "source": "./index.ts",
15
15
  "types": "./dist/index.d.ts",
16
16
  "import": "./dist/index.js"
17
+ },
18
+ "./rpc": {
19
+ "source": "./src/rpc/index.ts",
20
+ "types": "./dist/rpc.d.ts",
21
+ "import": "./dist/rpc.js"
17
22
  }
18
23
  },
19
24
  "files": [
@@ -42,13 +47,14 @@
42
47
  "@electric-sql/pglite": "0.3.15",
43
48
  "pg": "8.18.0",
44
49
  "@sindresorhus/fnv1a": "3.1.0",
45
- "@powerhousedao/shared": "6.2.3-dev.43",
46
- "document-model": "6.2.3-dev.43"
50
+ "@powerhousedao/shared": "6.2.3-dev.45",
51
+ "document-model": "6.2.3-dev.45"
47
52
  },
48
53
  "devDependencies": {
49
54
  "@informalsystems/quint": "0.32.0",
50
- "@powerhousedao/pglite-fs": "6.2.3-dev.43",
55
+ "@types/cross-spawn": "6.0.6",
51
56
  "@types/pg": "8.16.0",
57
+ "cross-spawn": "7.0.6",
52
58
  "@vitest/coverage-v8": "4.1.1",
53
59
  "tinybench": "^2.9.0",
54
60
  "tsx": "4.23.13",
@@ -1,105 +0,0 @@
1
- import { At as ReactorEventTypes, C as KyselyWriteCache, I as DocumentMetaCache, L as CollectionMembershipCache, S as EventBus, _ as KyselyExecutionScope, a as DEFAULT_DRIVE_CONTAINER_TYPES, d as KyselyOperationStore, f as KyselyKeyframeStore, m as SimpleJobExecutor, o as REACTOR_SCHEMA, p as DocumentModelRegistry, w as KyselyOperationIndex } from "./forwarding-logger-BKDP4JnD.js";
2
- //#region src/executor/worker/build-worker-executor.ts
3
- async function defaultLoadFactory(spec) {
4
- const ref = spec.module;
5
- const exported = (await ("filePath" in ref ? import(new URL(`file://${ref.filePath}`).href) : import(ref.packageName)))[ref.exportName];
6
- if (typeof exported === "function") return exported(spec.initArgs);
7
- return exported;
8
- }
9
- async function loadModelManifest(entries, loadFactory, registry, logger) {
10
- for (const entry of entries) {
11
- let module;
12
- try {
13
- module = await loadFactory(entry.spec);
14
- } catch (error) {
15
- logger.error("worker failed to load document model: @entry @error", entry, error);
16
- throw error;
17
- }
18
- const [result] = registry.registerModules(module);
19
- if (result.status === "error") {
20
- logger.error("worker failed to register document model: @entry @error", entry, result.error);
21
- throw result.error;
22
- }
23
- }
24
- }
25
- /**
26
- * Assembles the in-worker storage stack plus a {@link SimpleJobExecutor}
27
- * bound to a pre-built Kysely instance. The parent owns the wire protocol
28
- * and routing; the worker owns everything below `SimpleJobExecutor`.
29
- *
30
- * The local event bus exists only to satisfy the executor's contract: its
31
- * JOB_WRITE_READY emissions are captured here and shipped to the parent
32
- * via {@link WorkerExecutorStack.takeLastWriteReady}.
33
- */
34
- async function buildWorkerExecutor(options) {
35
- const { init, database: baseDatabase, logger } = options;
36
- const driveContainerTypes = options.driveContainerTypes ?? DEFAULT_DRIVE_CONTAINER_TYPES;
37
- const loadFactory = options.loadFactory ?? defaultLoadFactory;
38
- const registry = new DocumentModelRegistry();
39
- await loadModelManifest(init.models, loadFactory, registry, logger);
40
- let signer;
41
- if (init.signer) try {
42
- signer = await loadFactory(init.signer);
43
- } catch (error) {
44
- logger.error("worker failed to load signer: @spec @error", init.signer.module, error);
45
- throw error;
46
- }
47
- let trustPolicy;
48
- if (init.trustPolicy) try {
49
- trustPolicy = await loadFactory(init.trustPolicy);
50
- } catch (error) {
51
- logger.error("worker failed to load trust policy: @spec @error", init.trustPolicy.module, error);
52
- throw error;
53
- }
54
- const database = baseDatabase.withSchema(REACTOR_SCHEMA);
55
- const operationStore = new KyselyOperationStore(database);
56
- const keyframeStore = new KyselyKeyframeStore(database);
57
- const writeCache = new KyselyWriteCache(keyframeStore, operationStore, registry, {
58
- maxDocuments: 100,
59
- ringBufferSize: 10,
60
- keyframeInterval: 10
61
- });
62
- await writeCache.startup();
63
- const operationIndex = new KyselyOperationIndex(database);
64
- const documentMetaCache = new DocumentMetaCache(operationStore, { maxDocuments: 1e3 });
65
- await documentMetaCache.startup();
66
- const collectionMembershipCache = new CollectionMembershipCache(operationIndex);
67
- const executionScope = new KyselyExecutionScope(database, operationStore, operationIndex, keyframeStore, writeCache, documentMetaCache, collectionMembershipCache);
68
- const eventBus = new EventBus();
69
- let lastWriteReady = null;
70
- eventBus.subscribe(ReactorEventTypes.JOB_WRITE_READY, (_t, event) => {
71
- lastWriteReady = {
72
- operations: event.operations,
73
- jobMeta: event.jobMeta
74
- };
75
- });
76
- let signatureRefusals = [];
77
- eventBus.subscribe(ReactorEventTypes.SIGNATURE_REFUSED, (_t, event) => {
78
- signatureRefusals.push(event);
79
- });
80
- const executorConfig = options.executorConfig ?? {};
81
- return {
82
- executor: new SimpleJobExecutor(logger, registry, operationStore, eventBus, writeCache, operationIndex, documentMetaCache, collectionMembershipCache, driveContainerTypes, executorConfig, executionScope, signer, trustPolicy),
83
- registry,
84
- takeLastWriteReady() {
85
- const captured = lastWriteReady;
86
- lastWriteReady = null;
87
- return captured;
88
- },
89
- takeSignatureRefusals() {
90
- const captured = signatureRefusals;
91
- signatureRefusals = [];
92
- return captured;
93
- },
94
- evictPurged(documentIds) {
95
- for (const documentId of documentIds) {
96
- writeCache.invalidate(documentId);
97
- documentMetaCache.invalidate(documentId);
98
- }
99
- }
100
- };
101
- }
102
- //#endregion
103
- export { defaultLoadFactory as n, buildWorkerExecutor as t };
104
-
105
- //# sourceMappingURL=build-worker-executor-Bonu2jUB.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"build-worker-executor-Bonu2jUB.js","names":[],"sources":["../src/executor/worker/build-worker-executor.ts"],"sourcesContent":["import type {\n DocumentModelModule,\n ISigner,\n OperationWithContext,\n} from \"@powerhousedao/shared/document-model\";\nimport type { ILogger } from \"document-model\";\nimport type { Kysely } from \"kysely\";\nimport { CollectionMembershipCache } from \"../../cache/collection-membership-cache.js\";\nimport { DocumentMetaCache } from \"../../cache/document-meta-cache.js\";\nimport { KyselyOperationIndex } from \"../../cache/kysely-operation-index.js\";\nimport { KyselyWriteCache } from \"../../cache/kysely-write-cache.js\";\nimport type { WriteCacheConfig } from \"../../cache/write-cache-types.js\";\nimport { DEFAULT_DRIVE_CONTAINER_TYPES } from \"../../core/drive-container-types.js\";\nimport type { Database } from \"../../core/types.js\";\nimport { EventBus } from \"../../events/event-bus.js\";\nimport {\n ReactorEventTypes,\n type JobWriteReadyEvent,\n type SignatureRefusedEvent,\n} from \"../../events/types.js\";\nimport { DocumentModelRegistry } from \"../../registry/implementation.js\";\nimport type { JobMeta } from \"../../shared/types.js\";\nimport { KyselyKeyframeStore } from \"../../storage/kysely/keyframe-store.js\";\nimport { KyselyOperationStore } from \"../../storage/kysely/store.js\";\nimport type { Database as StorageDatabase } from \"../../storage/kysely/types.js\";\nimport { REACTOR_SCHEMA } from \"../../storage/migrations/migrator.js\";\nimport { KyselyExecutionScope } from \"../execution-scope.js\";\nimport { SimpleJobExecutor } from \"../simple-job-executor.js\";\nimport type { SignatureTrustPolicy } from \"../../signer/types.js\";\nimport type { JobExecutorConfig } from \"../types.js\";\nimport type {\n FactorySpec,\n InitMessage,\n ModelManifestEntry,\n} from \"./protocol.js\";\n\n/**\n * In-worker capture of the JOB_WRITE_READY event emitted by the executor.\n * The worker forwards `operations` and `jobMeta` back to the parent; the\n * parent re-enriches `collectionMemberships` at emit time.\n */\nexport type WorkerWriteReadyCapture = {\n operations: OperationWithContext[];\n jobMeta: JobMeta;\n};\n\nexport type WorkerExecutorStack = {\n executor: SimpleJobExecutor;\n registry: DocumentModelRegistry;\n /**\n * Synchronously pops the most-recent JOB_WRITE_READY captured on this\n * worker's local event bus and clears it. Returns null if the executor\n * did not produce one for this job.\n */\n takeLastWriteReady(): WorkerWriteReadyCapture | null;\n /** Drains the refusals this worker's executor emitted since the last call. */\n takeSignatureRefusals(): SignatureRefusedEvent[];\n /** Drops purged ids from this worker's write and meta caches. */\n evictPurged(documentIds: string[]): void;\n};\n\nexport type BuildWorkerExecutorOptions = {\n init: InitMessage;\n database: Kysely<Database>;\n logger: ILogger;\n executorConfig?: JobExecutorConfig;\n driveContainerTypes?: ReadonlySet<string>;\n /**\n * Override the module loader used to materialize factory specs. Tests\n * can inject a deterministic resolver instead of touching the real\n * Node module loader.\n */\n loadFactory?: (spec: FactorySpec) => Promise<unknown>;\n};\n\nexport async function defaultLoadFactory(spec: FactorySpec): Promise<unknown> {\n const ref = spec.module;\n const specifier =\n \"filePath\" in ref\n ? new URL(`file://${ref.filePath}`).href\n : ref.packageName;\n const mod = (await import(specifier)) as Record<string, unknown>;\n const exported = mod[ref.exportName];\n if (typeof exported === \"function\") {\n return (exported as (args: unknown) => unknown)(spec.initArgs);\n }\n return exported;\n}\n\nasync function loadModelManifest(\n entries: ModelManifestEntry[],\n loadFactory: (spec: FactorySpec) => Promise<unknown>,\n registry: DocumentModelRegistry,\n logger: ILogger,\n): Promise<void> {\n for (const entry of entries) {\n let module: DocumentModelModule;\n try {\n module = (await loadFactory(entry.spec)) as DocumentModelModule;\n } catch (error) {\n logger.error(\n \"worker failed to load document model: @entry @error\",\n entry,\n error,\n );\n throw error;\n }\n const [result] = registry.registerModules(module);\n if (result.status === \"error\") {\n logger.error(\n \"worker failed to register document model: @entry @error\",\n entry,\n result.error,\n );\n throw result.error;\n }\n }\n}\n\n/**\n * Assembles the in-worker storage stack plus a {@link SimpleJobExecutor}\n * bound to a pre-built Kysely instance. The parent owns the wire protocol\n * and routing; the worker owns everything below `SimpleJobExecutor`.\n *\n * The local event bus exists only to satisfy the executor's contract: its\n * JOB_WRITE_READY emissions are captured here and shipped to the parent\n * via {@link WorkerExecutorStack.takeLastWriteReady}.\n */\nexport async function buildWorkerExecutor(\n options: BuildWorkerExecutorOptions,\n): Promise<WorkerExecutorStack> {\n const { init, database: baseDatabase, logger } = options;\n const driveContainerTypes =\n options.driveContainerTypes ?? DEFAULT_DRIVE_CONTAINER_TYPES;\n const loadFactory = options.loadFactory ?? defaultLoadFactory;\n\n const registry = new DocumentModelRegistry();\n await loadModelManifest(init.models, loadFactory, registry, logger);\n\n let signer: ISigner | undefined;\n if (init.signer) {\n try {\n signer = (await loadFactory(init.signer)) as ISigner;\n } catch (error) {\n logger.error(\n \"worker failed to load signer: @spec @error\",\n init.signer.module,\n error,\n );\n throw error;\n }\n }\n\n let trustPolicy: SignatureTrustPolicy | undefined;\n if (init.trustPolicy) {\n try {\n trustPolicy = (await loadFactory(\n init.trustPolicy,\n )) as SignatureTrustPolicy;\n } catch (error) {\n logger.error(\n \"worker failed to load trust policy: @spec @error\",\n init.trustPolicy.module,\n error,\n );\n throw error;\n }\n }\n\n const database = baseDatabase.withSchema(REACTOR_SCHEMA);\n const operationStore = new KyselyOperationStore(\n database as unknown as Kysely<StorageDatabase>,\n );\n const keyframeStore = new KyselyKeyframeStore(\n database as unknown as Kysely<StorageDatabase>,\n );\n\n const cacheConfig: WriteCacheConfig = {\n maxDocuments: 100,\n ringBufferSize: 10,\n keyframeInterval: 10,\n };\n const writeCache = new KyselyWriteCache(\n keyframeStore,\n operationStore,\n registry,\n cacheConfig,\n );\n await writeCache.startup();\n\n const operationIndex = new KyselyOperationIndex(\n database as unknown as Kysely<StorageDatabase>,\n );\n\n const documentMetaCache = new DocumentMetaCache(operationStore, {\n maxDocuments: 1000,\n });\n await documentMetaCache.startup();\n\n const collectionMembershipCache = new CollectionMembershipCache(\n operationIndex,\n );\n\n const executionScope = new KyselyExecutionScope(\n database as unknown as Kysely<StorageDatabase>,\n operationStore,\n operationIndex,\n keyframeStore,\n writeCache,\n documentMetaCache,\n collectionMembershipCache,\n );\n\n const eventBus = new EventBus();\n let lastWriteReady: WorkerWriteReadyCapture | null = null;\n eventBus.subscribe(\n ReactorEventTypes.JOB_WRITE_READY,\n (_t: number, event: JobWriteReadyEvent) => {\n lastWriteReady = {\n operations: event.operations,\n jobMeta: event.jobMeta,\n };\n },\n );\n\n let signatureRefusals: SignatureRefusedEvent[] = [];\n eventBus.subscribe(\n ReactorEventTypes.SIGNATURE_REFUSED,\n (_t: number, event: SignatureRefusedEvent) => {\n signatureRefusals.push(event);\n },\n );\n\n const executorConfig = options.executorConfig ?? {};\n const executor = new SimpleJobExecutor(\n logger,\n registry,\n operationStore,\n eventBus,\n writeCache,\n operationIndex,\n documentMetaCache,\n collectionMembershipCache,\n driveContainerTypes,\n executorConfig,\n executionScope,\n signer,\n trustPolicy,\n );\n\n return {\n executor,\n registry,\n takeLastWriteReady(): WorkerWriteReadyCapture | null {\n const captured = lastWriteReady;\n lastWriteReady = null;\n return captured;\n },\n takeSignatureRefusals(): SignatureRefusedEvent[] {\n const captured = signatureRefusals;\n signatureRefusals = [];\n return captured;\n },\n evictPurged(documentIds: string[]): void {\n for (const documentId of documentIds) {\n writeCache.invalidate(documentId);\n documentMetaCache.invalidate(documentId);\n }\n },\n };\n}\n"],"mappings":"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"}