@powerhousedao/reactor 6.2.0-dev.3 → 6.2.0-dev.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { S as CollectionMembershipCache, _ as KyselyWriteCache, d as KyselyKeyframeStore, f as DocumentModelRegistry, g as EventBus, h as KyselyExecutionScope, n as REACTOR_SCHEMA, p as SimpleJobExecutor, s as KyselyOperationStore, t as DEFAULT_DRIVE_CONTAINER_TYPES, v as KyselyOperationIndex, y as DocumentMetaCache } from "./drive-container-types-BNpMlgT_.js";
1
+ import { S as CollectionMembershipCache, _ as KyselyWriteCache, d as KyselyKeyframeStore, f as DocumentModelRegistry, g as EventBus, h as KyselyExecutionScope, n as REACTOR_SCHEMA, p as SimpleJobExecutor, s as KyselyOperationStore, t as DEFAULT_DRIVE_CONTAINER_TYPES, v as KyselyOperationIndex, y as DocumentMetaCache } from "./drive-container-types-BxnXaOAp.js";
2
2
  import { n as ReactorEventTypes } from "./types-CxSpmNGK.js";
3
3
  //#region src/executor/worker/build-worker-executor.ts
4
4
  async function defaultLoadFactory(spec) {
@@ -80,4 +80,4 @@ async function buildWorkerExecutor(options) {
80
80
  //#endregion
81
81
  export { defaultLoadFactory as n, buildWorkerExecutor as t };
82
82
 
83
- //# sourceMappingURL=build-worker-executor-DDVXB921.js.map
83
+ //# sourceMappingURL=build-worker-executor-DeJ2DW16.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-worker-executor-DDVXB921.js","names":[],"sources":["../src/executor/worker/build-worker-executor.ts"],"sourcesContent":["import type {\n DocumentModelModule,\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} from \"../../events/types.js\";\nimport { DocumentModelRegistry } from \"../../registry/implementation.js\";\nimport type { JobMeta } from \"../../shared/types.js\";\nimport type { SignatureVerificationHandler } from \"../../signer/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 { 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};\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 signatureVerifier: SignatureVerificationHandler | undefined;\n try {\n signatureVerifier = (await loadFactory(\n init.signatureVerifier,\n )) as SignatureVerificationHandler;\n } catch (error) {\n logger.error(\n \"worker failed to load signature verifier: @spec @error\",\n init.signatureVerifier,\n error,\n );\n throw error;\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 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 signatureVerifier,\n executionScope,\n );\n\n return {\n executor,\n registry,\n takeLastWriteReady(): WorkerWriteReadyCapture | null {\n const captured = lastWriteReady;\n lastWriteReady = null;\n return captured;\n },\n };\n}\n"],"mappings":";;;AAqEA,eAAsB,mBAAmB,MAAqC;CAC5E,MAAM,MAAM,KAAK;CAMjB,MAAM,YADO,OAHX,cAAc,MAAA,OACV,IAAI,IAAI,UAAU,IAAI,WAAW,CAAC,QAAA,OAClC,IAAI,eAEW,IAAI;AACzB,KAAI,OAAO,aAAa,WACtB,QAAQ,SAAwC,KAAK,SAAS;AAEhE,QAAO;;AAGT,eAAe,kBACb,SACA,aACA,UACA,QACe;AACf,MAAK,MAAM,SAAS,SAAS;EAC3B,IAAI;AACJ,MAAI;AACF,YAAU,MAAM,YAAY,MAAM,KAAK;WAChC,OAAO;AACd,UAAO,MACL,uDACA,OACA,MACD;AACD,SAAM;;EAER,MAAM,CAAC,UAAU,SAAS,gBAAgB,OAAO;AACjD,MAAI,OAAO,WAAW,SAAS;AAC7B,UAAO,MACL,2DACA,OACA,OAAO,MACR;AACD,SAAM,OAAO;;;;;;;;;;;;;AAcnB,eAAsB,oBACpB,SAC8B;CAC9B,MAAM,EAAE,MAAM,UAAU,cAAc,WAAW;CACjD,MAAM,sBACJ,QAAQ,uBAAuB;CACjC,MAAM,cAAc,QAAQ,eAAe;CAE3C,MAAM,WAAW,IAAI,uBAAuB;AAC5C,OAAM,kBAAkB,KAAK,QAAQ,aAAa,UAAU,OAAO;CAEnE,IAAI;AACJ,KAAI;AACF,sBAAqB,MAAM,YACzB,KAAK,kBACN;UACM,OAAO;AACd,SAAO,MACL,0DACA,KAAK,mBACL,MACD;AACD,QAAM;;CAGR,MAAM,WAAW,aAAa,WAAW,eAAe;CACxD,MAAM,iBAAiB,IAAI,qBACzB,SACD;CACD,MAAM,gBAAgB,IAAI,oBACxB,SACD;CAOD,MAAM,aAAa,IAAI,iBACrB,eACA,gBACA,UARoC;EACpC,cAAc;EACd,gBAAgB;EAChB,kBAAkB;EACnB,CAMA;AACD,OAAM,WAAW,SAAS;CAE1B,MAAM,iBAAiB,IAAI,qBACzB,SACD;CAED,MAAM,oBAAoB,IAAI,kBAAkB,gBAAgB,EAC9D,cAAc,KACf,CAAC;AACF,OAAM,kBAAkB,SAAS;CAEjC,MAAM,4BAA4B,IAAI,0BACpC,eACD;CAED,MAAM,iBAAiB,IAAI,qBACzB,UACA,gBACA,gBACA,eACA,YACA,mBACA,0BACD;CAED,MAAM,WAAW,IAAI,UAAU;CAC/B,IAAI,iBAAiD;AACrD,UAAS,UACP,kBAAkB,kBACjB,IAAY,UAA8B;AACzC,mBAAiB;GACf,YAAY,MAAM;GAClB,SAAS,MAAM;GAChB;GAEJ;AAkBD,QAAO;EACL,UAhBe,IAAI,kBACnB,QACA,UACA,gBACA,UACA,YACA,gBACA,mBACA,2BACA,qBAVqB,QAAQ,kBAAkB,EAAE,EAYjD,mBACA,eACD;EAIC;EACA,qBAAqD;GACnD,MAAM,WAAW;AACjB,oBAAiB;AACjB,UAAO;;EAEV"}
1
+ {"version":3,"file":"build-worker-executor-DeJ2DW16.js","names":[],"sources":["../src/executor/worker/build-worker-executor.ts"],"sourcesContent":["import type {\n DocumentModelModule,\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} from \"../../events/types.js\";\nimport { DocumentModelRegistry } from \"../../registry/implementation.js\";\nimport type { JobMeta } from \"../../shared/types.js\";\nimport type { SignatureVerificationHandler } from \"../../signer/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 { 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};\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 signatureVerifier: SignatureVerificationHandler | undefined;\n try {\n signatureVerifier = (await loadFactory(\n init.signatureVerifier,\n )) as SignatureVerificationHandler;\n } catch (error) {\n logger.error(\n \"worker failed to load signature verifier: @spec @error\",\n init.signatureVerifier,\n error,\n );\n throw error;\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 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 signatureVerifier,\n executionScope,\n );\n\n return {\n executor,\n registry,\n takeLastWriteReady(): WorkerWriteReadyCapture | null {\n const captured = lastWriteReady;\n lastWriteReady = null;\n return captured;\n },\n };\n}\n"],"mappings":";;;AAqEA,eAAsB,mBAAmB,MAAqC;CAC5E,MAAM,MAAM,KAAK;CAMjB,MAAM,YADO,OAHX,cAAc,MAAA,OACV,IAAI,IAAI,UAAU,IAAI,WAAW,CAAC,QAAA,OAClC,IAAI,eAEW,IAAI;AACzB,KAAI,OAAO,aAAa,WACtB,QAAQ,SAAwC,KAAK,SAAS;AAEhE,QAAO;;AAGT,eAAe,kBACb,SACA,aACA,UACA,QACe;AACf,MAAK,MAAM,SAAS,SAAS;EAC3B,IAAI;AACJ,MAAI;AACF,YAAU,MAAM,YAAY,MAAM,KAAK;WAChC,OAAO;AACd,UAAO,MACL,uDACA,OACA,MACD;AACD,SAAM;;EAER,MAAM,CAAC,UAAU,SAAS,gBAAgB,OAAO;AACjD,MAAI,OAAO,WAAW,SAAS;AAC7B,UAAO,MACL,2DACA,OACA,OAAO,MACR;AACD,SAAM,OAAO;;;;;;;;;;;;;AAcnB,eAAsB,oBACpB,SAC8B;CAC9B,MAAM,EAAE,MAAM,UAAU,cAAc,WAAW;CACjD,MAAM,sBACJ,QAAQ,uBAAuB;CACjC,MAAM,cAAc,QAAQ,eAAe;CAE3C,MAAM,WAAW,IAAI,uBAAuB;AAC5C,OAAM,kBAAkB,KAAK,QAAQ,aAAa,UAAU,OAAO;CAEnE,IAAI;AACJ,KAAI;AACF,sBAAqB,MAAM,YACzB,KAAK,kBACN;UACM,OAAO;AACd,SAAO,MACL,0DACA,KAAK,mBACL,MACD;AACD,QAAM;;CAGR,MAAM,WAAW,aAAa,WAAW,eAAe;CACxD,MAAM,iBAAiB,IAAI,qBACzB,SACD;CACD,MAAM,gBAAgB,IAAI,oBACxB,SACD;CAOD,MAAM,aAAa,IAAI,iBACrB,eACA,gBACA,UARoC;EACpC,cAAc;EACd,gBAAgB;EAChB,kBAAkB;EACnB,CAMA;AACD,OAAM,WAAW,SAAS;CAE1B,MAAM,iBAAiB,IAAI,qBACzB,SACD;CAED,MAAM,oBAAoB,IAAI,kBAAkB,gBAAgB,EAC9D,cAAc,KACf,CAAC;AACF,OAAM,kBAAkB,SAAS;CAEjC,MAAM,4BAA4B,IAAI,0BACpC,eACD;CAED,MAAM,iBAAiB,IAAI,qBACzB,UACA,gBACA,gBACA,eACA,YACA,mBACA,0BACD;CAED,MAAM,WAAW,IAAI,UAAU;CAC/B,IAAI,iBAAiD;AACrD,UAAS,UACP,kBAAkB,kBACjB,IAAY,UAA8B;AACzC,mBAAiB;GACf,YAAY,MAAM;GAClB,SAAS,MAAM;GAChB;GAEJ;AAkBD,QAAO;EACL,UAhBe,IAAI,kBACnB,QACA,UACA,gBACA,UACA,YACA,gBACA,mBACA,2BACA,qBAVqB,QAAQ,kBAAkB,EAAE,EAYjD,mBACA,eACD;EAIC;EACA,qBAAqD;GACnD,MAAM,WAAW;AACjB,oBAAiB;AACjB,UAAO;;EAEV"}
@@ -1,5 +1,5 @@
1
1
  import { n as ReactorEventTypes, t as EventBusAggregateError } from "./types-CxSpmNGK.js";
2
- import { createPresignedHeader, defaultBaseState, deriveOperationId, isUndoRedo } from "@powerhousedao/shared/document-model";
2
+ import { DowngradeNotSupportedError, applyDeleteDocumentAction, applyDeleteDocumentAction as applyDeleteDocumentAction$1, applyUpgradeDocumentAction, applyUpgradeDocumentAction as applyUpgradeDocumentAction$1, createPresignedHeader, defaultBaseState, deriveOperationId, isUndoRedo } from "@powerhousedao/shared/document-model";
3
3
  import { v4 } from "uuid";
4
4
  import { Migrator, sql } from "kysely";
5
5
  //#region \0rolldown/runtime.js
@@ -86,22 +86,6 @@ var InvalidSignatureError = class InvalidSignatureError extends Error {
86
86
  }
87
87
  };
88
88
  /**
89
- * Error thrown when attempting to downgrade a document version.
90
- */
91
- var DowngradeNotSupportedError$1 = class DowngradeNotSupportedError$1 extends Error {
92
- documentType;
93
- fromVersion;
94
- toVersion;
95
- constructor(documentType, fromVersion, toVersion) {
96
- super(`Downgrade not supported for ${documentType}: cannot upgrade from version ${fromVersion} to ${toVersion}`);
97
- this.name = "DowngradeNotSupportedError";
98
- this.documentType = documentType;
99
- this.fromVersion = fromVersion;
100
- this.toVersion = toVersion;
101
- Error.captureStackTrace(this, DowngradeNotSupportedError$1);
102
- }
103
- };
104
- /**
105
89
  * Error thrown when a document is not found (no operations exist for the document ID).
106
90
  */
107
91
  var DocumentNotFoundError = class DocumentNotFoundError extends Error {
@@ -179,15 +163,6 @@ var ManifestNotFoundError = class extends Error {
179
163
  }
180
164
  };
181
165
  /**
182
- * Error thrown when attempting a downgrade operation.
183
- */
184
- var DowngradeNotSupportedError = class extends Error {
185
- constructor(documentType, fromVersion, toVersion) {
186
- super(`Downgrade not supported for ${documentType}: cannot go from version ${fromVersion} to ${toVersion}`);
187
- this.name = "DowngradeNotSupportedError";
188
- }
189
- };
190
- /**
191
166
  * Error thrown when a required upgrade transition is missing from the manifest.
192
167
  */
193
168
  var MissingUpgradeTransitionError = class extends Error {
@@ -277,68 +252,6 @@ function createDocumentFromAction(action) {
277
252
  };
278
253
  }
279
254
  /**
280
- * Applies an UPGRADE_DOCUMENT action to a document.
281
- * Handles all upgrade scenarios including initial upgrades, no-ops, and multi-step upgrades.
282
- *
283
- * Behavior based on fromVersion/toVersion:
284
- * - fromVersion === toVersion (and fromVersion > 0): No-op - return unchanged document
285
- * - fromVersion > toVersion: Throw DowngradeNotSupportedError
286
- * - All other cases: Apply upgradePath transitions (if provided), then apply initialState, set version
287
- *
288
- * The initialState from the action is always applied (if provided) to maintain backward
289
- * compatibility with the original implementation.
290
- *
291
- * @param document - The document to upgrade
292
- * @param action - The UPGRADE_DOCUMENT action
293
- * @param upgradePath - Optional pre-computed upgrade path for multi-step upgrades
294
- * @returns The upgraded document (unchanged if no-op)
295
- * @throws DowngradeNotSupportedError if attempting to downgrade
296
- */
297
- function applyUpgradeDocumentAction(document, action, upgradePath) {
298
- const fromVersion = action.input.fromVersion;
299
- const toVersion = action.input.toVersion;
300
- if (fromVersion === toVersion && fromVersion > 0) return document;
301
- if (fromVersion > toVersion) throw new DowngradeNotSupportedError$1(document.header.documentType, fromVersion, toVersion);
302
- if (upgradePath) for (const transition of upgradePath) document = transition.upgradeReducer(document, action);
303
- applyInitialState(document, action);
304
- document.state.document = {
305
- ...document.state.document,
306
- version: toVersion
307
- };
308
- return document;
309
- }
310
- function applyInitialState(document, action) {
311
- const input = action.input;
312
- const newState = input.initialState || input.state;
313
- if (newState) {
314
- document.state = {
315
- ...document.state,
316
- ...newState
317
- };
318
- document.initialState = document.state;
319
- }
320
- }
321
- /**
322
- * Applies a DELETE_DOCUMENT action to a document.
323
- * Marks the document as deleted in the document scope state.
324
- *
325
- * @param document - The document to mark as deleted
326
- * @param action - The DELETE_DOCUMENT action
327
- * @returns The updated document (mutates in place and returns for convenience)
328
- */
329
- function applyDeleteDocumentAction(document, action) {
330
- const deletedAt = action.timestampUtcMs || (/* @__PURE__ */ new Date()).toISOString();
331
- document.state = {
332
- ...document.state,
333
- document: {
334
- ...document.state.document,
335
- isDeleted: true,
336
- deletedAtUtcIso: deletedAt
337
- }
338
- };
339
- return document;
340
- }
341
- /**
342
255
  * Calculate the next operation index for a specific scope.
343
256
  * Each scope maintains its own independent index sequence.
344
257
  *
@@ -616,8 +529,8 @@ var DocumentMetaCache = class DocumentMetaCache {
616
529
  documentScopeRevision = op.index;
617
530
  if (op.action.type === "UPGRADE_DOCUMENT") {
618
531
  const upgradeAction = op.action;
619
- document = applyUpgradeDocumentAction(document, upgradeAction);
620
- } else if (op.action.type === "DELETE_DOCUMENT") document = applyDeleteDocumentAction(document, op.action);
532
+ document = applyUpgradeDocumentAction$1(document, upgradeAction);
533
+ } else if (op.action.type === "DELETE_DOCUMENT") document = applyDeleteDocumentAction$1(document, op.action);
621
534
  }
622
535
  return {
623
536
  state: document.state.document,
@@ -1201,10 +1114,33 @@ var KyselyWriteCache = class KyselyWriteCache {
1201
1114
  let document;
1202
1115
  let startRevision;
1203
1116
  let documentType;
1117
+ const validatedUpgrades = [];
1204
1118
  if (keyframe) {
1205
1119
  document = keyframe.document;
1206
1120
  startRevision = keyframe.revision;
1207
1121
  documentType = keyframe.document.header.documentType;
1122
+ const docScopeOpsAfterKeyframe = await this.operationStore.getSince(documentId, "document", branch, keyframe.revision, void 0, void 0, signal);
1123
+ for (const operation of docScopeOpsAfterKeyframe.results) if (operation.action.type === "UPGRADE_DOCUMENT") {
1124
+ const upgradeAction = operation.action;
1125
+ const fromVersion = upgradeAction.input.fromVersion;
1126
+ const toVersion = upgradeAction.input.toVersion;
1127
+ if (fromVersion > 0 && fromVersion < toVersion) {
1128
+ let upgradePath;
1129
+ try {
1130
+ upgradePath = this.registry.computeUpgradePath(documentType, fromVersion, toVersion);
1131
+ } catch (err) {
1132
+ if (upgradeAction.input.initialState !== void 0) upgradePath = void 0;
1133
+ else throw new Error(`Failed to rebuild document ${documentId}: no upgrade manifest for ${documentType} v${fromVersion}→v${toVersion} and no initialState snapshot. ${err instanceof Error ? err.message : String(err)}`, { cause: err });
1134
+ }
1135
+ validatedUpgrades.push({
1136
+ fromVersion,
1137
+ toVersion,
1138
+ revision: upgradeAction.input.revision,
1139
+ timestampUtcMs: operation.timestampUtcMs
1140
+ });
1141
+ document = applyUpgradeDocumentAction(document, upgradeAction, upgradePath);
1142
+ }
1143
+ } else if (operation.action.type === "DELETE_DOCUMENT") applyDeleteDocumentAction(document, operation.action);
1208
1144
  } else {
1209
1145
  startRevision = -1;
1210
1146
  const createOpResult = await this.operationStore.getSince(documentId, "document", branch, -1, void 0, {
@@ -1224,7 +1160,24 @@ var KyselyWriteCache = class KyselyWriteCache {
1224
1160
  if (operation.index === 0) continue;
1225
1161
  if (operation.action.type === "UPGRADE_DOCUMENT") {
1226
1162
  const upgradeAction = operation.action;
1227
- document = applyUpgradeDocumentAction(document, upgradeAction);
1163
+ const fromVersion = upgradeAction.input.fromVersion;
1164
+ const toVersion = upgradeAction.input.toVersion;
1165
+ let upgradePath;
1166
+ if (fromVersion > 0 && fromVersion < toVersion) {
1167
+ try {
1168
+ upgradePath = this.registry.computeUpgradePath(documentType, fromVersion, toVersion);
1169
+ } catch (err) {
1170
+ if (upgradeAction.input.initialState !== void 0) upgradePath = void 0;
1171
+ else throw new Error(`Failed to rebuild document ${documentId}: no upgrade manifest for ${documentType} v${fromVersion}→v${toVersion} and no initialState snapshot. ${err instanceof Error ? err.message : String(err)}`, { cause: err });
1172
+ }
1173
+ validatedUpgrades.push({
1174
+ fromVersion,
1175
+ toVersion,
1176
+ revision: upgradeAction.input.revision,
1177
+ timestampUtcMs: operation.timestampUtcMs
1178
+ });
1179
+ }
1180
+ document = applyUpgradeDocumentAction(document, upgradeAction, upgradePath);
1228
1181
  docModule = this.registry.getModule(documentType, extractModuleVersion(document));
1229
1182
  } else if (operation.action.type === "DELETE_DOCUMENT") applyDeleteDocumentAction(document, operation.action);
1230
1183
  else {
@@ -1236,7 +1189,16 @@ var KyselyWriteCache = class KyselyWriteCache {
1236
1189
  }
1237
1190
  }
1238
1191
  }
1239
- const module = this.registry.getModule(documentType, extractModuleVersion(document));
1192
+ const moduleCache = /* @__PURE__ */ new Map();
1193
+ const getModuleCached = (version) => {
1194
+ const key = version ?? 0;
1195
+ let mod = moduleCache.get(key);
1196
+ if (!mod) {
1197
+ mod = this.registry.getModule(documentType, version);
1198
+ moduleCache.set(key, mod);
1199
+ }
1200
+ return mod;
1201
+ };
1240
1202
  let cursor = void 0;
1241
1203
  const pageSize = 100;
1242
1204
  let hasMorePages;
@@ -1250,8 +1212,9 @@ var KyselyWriteCache = class KyselyWriteCache {
1250
1212
  const result = await this.operationStore.getSince(documentId, scope, branch, startRevision, void 0, paging, signal);
1251
1213
  for (const operation of result.results) {
1252
1214
  if (targetRevision !== void 0 && operation.index > targetRevision) break;
1215
+ const moduleVersion = this.resolveModuleVersionForOp(operation.index, operation.timestampUtcMs, scope, validatedUpgrades, extractModuleVersion(document));
1253
1216
  const protocolVersion = document.header.protocolVersions?.["base-reducer"] ?? 1;
1254
- document = module.reducer(document, operation.action, void 0, {
1217
+ document = getModuleCached(moduleVersion).reducer(document, operation.action, void 0, {
1255
1218
  skip: operation.skip,
1256
1219
  protocolVersion
1257
1220
  });
@@ -1268,9 +1231,31 @@ var KyselyWriteCache = class KyselyWriteCache {
1268
1231
  document.header.lastModifiedAtUtcIso = revisions.latestTimestamp;
1269
1232
  return document;
1270
1233
  }
1234
+ /**
1235
+ * Resolves which module version to use for a given operation in phase 2.
1236
+ *
1237
+ * Uses the validated-upgrade boundary rules from D7:
1238
+ * - If `input.revision` is present: op.index < revision[scope] → before the upgrade boundary
1239
+ * - Otherwise: timestamp fallback
1240
+ * - Falls back to final module version when neither is decidable
1241
+ */
1242
+ resolveModuleVersionForOp(opIndex, opTimestamp, scope, validatedUpgrades, finalVersion) {
1243
+ if (validatedUpgrades.length === 0) return finalVersion;
1244
+ let currentVersion = validatedUpgrades[0]?.fromVersion;
1245
+ for (const upgrade of validatedUpgrades) {
1246
+ let beforeUpgrade;
1247
+ if (upgrade.revision !== void 0) beforeUpgrade = opIndex < (upgrade.revision[scope] ?? 0);
1248
+ else beforeUpgrade = opTimestamp < upgrade.timestampUtcMs;
1249
+ if (beforeUpgrade) return currentVersion;
1250
+ currentVersion = upgrade.toVersion;
1251
+ }
1252
+ return currentVersion;
1253
+ }
1271
1254
  async warmMissRebuild(baseDocument, baseRevision, documentId, scope, branch, targetRevision, signal) {
1272
1255
  const documentType = baseDocument.header.documentType;
1273
- const module = this.registry.getModule(documentType);
1256
+ const docScopeNextIndex = baseDocument.header.revision["document"] ?? 0;
1257
+ if ((await this.operationStore.getSince(documentId, "document", branch, docScopeNextIndex - 1, void 0, void 0, signal)).results.some((op) => op.action.type === "UPGRADE_DOCUMENT")) return this.coldMissRebuild(documentId, scope, branch, targetRevision, signal);
1258
+ const module = this.registry.getModule(documentType, extractModuleVersion(baseDocument));
1274
1259
  let document = baseDocument;
1275
1260
  try {
1276
1261
  const pagedResults = await this.operationStore.getSince(documentId, scope, branch, baseRevision, void 0, void 0, signal);
@@ -1456,9 +1441,48 @@ function reshuffleByTimestamp(startIndex, opsA, opsB) {
1456
1441
  }
1457
1442
  //#endregion
1458
1443
  //#region src/cache/operation-index-types.ts
1459
- function driveCollectionId(branch, driveId) {
1460
- return `drive.${branch}.${driveId}`;
1461
- }
1444
+ const DRIVE_COLLECTION_PREFIX = "drive.";
1445
+ /**
1446
+ * Identifies the collection a remote synchronizes. Collections are drive-level
1447
+ * abstractions (document-drive and reactor-drive), so a collection id is the
1448
+ * drive document id plus the branch it scopes to rather than an opaque string.
1449
+ *
1450
+ * The canonical string form (`drive.${branch}.${driveId}`) is produced only by
1451
+ * `key` and parsed only by `fromKey`; that string is the wire and storage
1452
+ * representation and is byte-for-byte identical to the legacy
1453
+ * `driveCollectionId(branch, driveId)` output, so existing `document_collections`
1454
+ * rows and persisted remotes remain valid without migration.
1455
+ */
1456
+ var DriveCollectionId = class DriveCollectionId {
1457
+ constructor(driveId, branch) {
1458
+ this.driveId = driveId;
1459
+ this.branch = branch;
1460
+ }
1461
+ static forDrive(driveId, branch = "main") {
1462
+ return new DriveCollectionId(driveId, branch);
1463
+ }
1464
+ /**
1465
+ * The single deserializer for the wire/storage form. `branch` may contain
1466
+ * dots, while `driveId` is a dot-free document id, so the drive id is the
1467
+ * final dot-delimited segment.
1468
+ */
1469
+ static fromKey(key) {
1470
+ if (!key.startsWith(DRIVE_COLLECTION_PREFIX)) throw new Error(`Unsupported collection id: ${key}`);
1471
+ const rest = key.slice(6);
1472
+ const lastDot = rest.lastIndexOf(".");
1473
+ if (lastDot === -1 || lastDot === rest.length - 1) throw new Error(`Malformed drive collection id: ${key}`);
1474
+ return new DriveCollectionId(rest.slice(lastDot + 1), rest.slice(0, lastDot));
1475
+ }
1476
+ get key() {
1477
+ return `${DRIVE_COLLECTION_PREFIX}${this.branch}.${this.driveId}`;
1478
+ }
1479
+ toString() {
1480
+ return this.key;
1481
+ }
1482
+ equals(other) {
1483
+ return this.driveId === other.driveId && this.branch === other.branch;
1484
+ }
1485
+ };
1462
1486
  //#endregion
1463
1487
  //#region src/executor/document-action-handler.ts
1464
1488
  var DocumentActionHandler = class {
@@ -1514,7 +1538,7 @@ var DocumentActionHandler = class {
1514
1538
  sourceRemote
1515
1539
  }]);
1516
1540
  if (this.driveContainerTypes.has(document.header.documentType)) {
1517
- const collectionId = driveCollectionId(job.branch, document.header.id);
1541
+ const collectionId = DriveCollectionId.forDrive(document.header.id, job.branch).key;
1518
1542
  indexTxn.createCollection(collectionId);
1519
1543
  indexTxn.addToCollection(collectionId, document.header.id);
1520
1544
  }
@@ -1542,7 +1566,7 @@ var DocumentActionHandler = class {
1542
1566
  scope: job.scope,
1543
1567
  branch: job.branch
1544
1568
  });
1545
- applyDeleteDocumentAction(document, action);
1569
+ applyDeleteDocumentAction$1(document, action);
1546
1570
  const resultingStateObj = {
1547
1571
  header: document.header,
1548
1572
  document: document.state.document
@@ -1601,7 +1625,7 @@ var DocumentActionHandler = class {
1601
1625
  duration: Date.now() - startTime
1602
1626
  };
1603
1627
  try {
1604
- document = applyUpgradeDocumentAction(document, action, upgradePath);
1628
+ document = applyUpgradeDocumentAction$1(document, action, upgradePath);
1605
1629
  } catch (error) {
1606
1630
  return buildErrorResult(job, error instanceof Error ? error : new Error(String(error)), startTime);
1607
1631
  }
@@ -1642,7 +1666,7 @@ var DocumentActionHandler = class {
1642
1666
  executeAddRelationship(job, action, startTime, indexTxn, stores, sourceRemote = "", signal) {
1643
1667
  return this.withRelationshipAction("ADD_RELATIONSHIP", job, action, startTime, indexTxn, stores, sourceRemote, signal, (input) => input.sourceId === input.targetId ? /* @__PURE__ */ new Error("ADD_RELATIONSHIP: sourceId and targetId cannot be the same (self-relationships not allowed)") : null, ({ indexTxn: txn, stores: s, sourceDoc, input, job: j }) => {
1644
1668
  if (this.driveContainerTypes.has(sourceDoc.header.documentType)) {
1645
- const collectionId = driveCollectionId(j.branch, input.sourceId);
1669
+ const collectionId = DriveCollectionId.forDrive(input.sourceId, j.branch).key;
1646
1670
  txn.addToCollection(collectionId, input.targetId);
1647
1671
  s.collectionMembershipCache.invalidate(input.targetId);
1648
1672
  }
@@ -1651,7 +1675,7 @@ var DocumentActionHandler = class {
1651
1675
  executeRemoveRelationship(job, action, startTime, indexTxn, stores, sourceRemote = "", signal) {
1652
1676
  return this.withRelationshipAction("REMOVE_RELATIONSHIP", job, action, startTime, indexTxn, stores, sourceRemote, signal, null, ({ indexTxn: txn, stores: s, sourceDoc, input, job: j }) => {
1653
1677
  if (this.driveContainerTypes.has(sourceDoc.header.documentType)) {
1654
- const collectionId = driveCollectionId(j.branch, input.sourceId);
1678
+ const collectionId = DriveCollectionId.forDrive(input.sourceId, j.branch).key;
1655
1679
  txn.removeFromCollection(collectionId, input.targetId);
1656
1680
  s.collectionMembershipCache.invalidate(input.targetId);
1657
1681
  }
@@ -2959,6 +2983,6 @@ async function getMigrationStatus(db, schema = REACTOR_SCHEMA) {
2959
2983
  //#region src/core/drive-container-types.ts
2960
2984
  const DEFAULT_DRIVE_CONTAINER_TYPES = new Set(["powerhouse/document-drive", "powerhouse/reactor-drive"]);
2961
2985
  //#endregion
2962
- export { parsePagingOptions as A, DuplicateManifestError as C, DocumentDeletedError as D, ModuleNotFoundError as E, __exportAll as M, DocumentNotFoundError as O, CollectionMembershipCache as S, InvalidModuleError as T, KyselyWriteCache as _, createForwardingPoolInstrumentation as a, createConsistencyToken as b, DuplicateOperationError as c, KyselyKeyframeStore as d, DocumentModelRegistry as f, EventBus as g, KyselyExecutionScope as h, runMigrations as i, throwIfAborted as j, matchesScope as k, OptimisticLockError as l, driveCollectionId as m, REACTOR_SCHEMA as n, instrumentPgPool as o, SimpleJobExecutor as p, getMigrationStatus as r, KyselyOperationStore as s, DEFAULT_DRIVE_CONTAINER_TYPES as t, RevisionMismatchError as u, KyselyOperationIndex as v, DuplicateModuleError as w, createEmptyConsistencyToken as x, DocumentMetaCache as y };
2986
+ export { parsePagingOptions as A, DuplicateManifestError as C, DocumentDeletedError as D, ModuleNotFoundError as E, __exportAll as M, DocumentNotFoundError as O, CollectionMembershipCache as S, InvalidModuleError as T, KyselyWriteCache as _, createForwardingPoolInstrumentation as a, createConsistencyToken as b, DuplicateOperationError as c, KyselyKeyframeStore as d, DocumentModelRegistry as f, EventBus as g, KyselyExecutionScope as h, runMigrations as i, throwIfAborted as j, matchesScope as k, OptimisticLockError as l, DriveCollectionId as m, REACTOR_SCHEMA as n, instrumentPgPool as o, SimpleJobExecutor as p, getMigrationStatus as r, KyselyOperationStore as s, DEFAULT_DRIVE_CONTAINER_TYPES as t, RevisionMismatchError as u, KyselyOperationIndex as v, DuplicateModuleError as w, createEmptyConsistencyToken as x, DocumentMetaCache as y };
2963
2987
 
2964
- //# sourceMappingURL=drive-container-types-BNpMlgT_.js.map
2988
+ //# sourceMappingURL=drive-container-types-BxnXaOAp.js.map