@powerhousedao/reactor 6.2.1-dev.1 → 6.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,13 +1,13 @@
1
- import { A as parsePagingOptions, C as DuplicateManifestError, D as DocumentDeletedError, E as ModuleNotFoundError, O as DocumentNotFoundError, S as CollectionMembershipCache, T as InvalidModuleError, _ as KyselyWriteCache, a as createForwardingPoolInstrumentation, b as createConsistencyToken, c as DuplicateOperationError, d as KyselyKeyframeStore, f as DocumentModelRegistry, g as EventBus, h as KyselyExecutionScope, i as runMigrations, j as throwIfAborted, k as matchesScope, l as OptimisticLockError, m as DriveCollectionId, n as REACTOR_SCHEMA, o as instrumentPgPool, p as SimpleJobExecutor, r as getMigrationStatus, s as KyselyOperationStore, t as DEFAULT_DRIVE_CONTAINER_TYPES, u as RevisionMismatchError, v as KyselyOperationIndex, w as DuplicateModuleError, x as createEmptyConsistencyToken, y as DocumentMetaCache } from "./drive-container-types-BuFNr0j0.js";
2
- import { n as ReactorEventTypes, t as EventBusAggregateError } from "./types-DMKLa0Ok.js";
1
+ import { A as parsePagingOptions, C as DuplicateManifestError, D as DocumentDeletedError, E as ModuleNotFoundError, O as DocumentNotFoundError, S as CollectionMembershipCache, T as InvalidModuleError, _ as KyselyWriteCache, a as createForwardingPoolInstrumentation, b as createConsistencyToken, c as DuplicateOperationError, d as KyselyKeyframeStore, f as DocumentModelRegistry, g as EventBus, h as KyselyExecutionScope, i as runMigrations, j as throwIfAborted, k as matchesScope, l as OptimisticLockError, m as DriveCollectionId, n as REACTOR_SCHEMA, o as instrumentPgPool, p as SimpleJobExecutor, r as getMigrationStatus, s as KyselyOperationStore, t as DEFAULT_DRIVE_CONTAINER_TYPES, u as RevisionMismatchError, v as KyselyOperationIndex, w as DuplicateModuleError, x as createEmptyConsistencyToken, y as DocumentMetaCache } from "./drive-container-types-BxnXaOAp.js";
2
+ import { n as ReactorEventTypes, t as EventBusAggregateError } from "./types-CxSpmNGK.js";
3
3
  import { i as WorkerInitFailedError, r as WorkerExitedError, t as WorkerAbortTimeoutError } from "./errors-D3S6Eysd.js";
4
- import { a as ReadModelCoordinator, i as KyselyDocumentView, n as ConsistencyTracker, o as BaseReadModel, r as makeConsistencyKey, t as KyselyDocumentIndexer } from "./document-indexer-B6iippzG.js";
4
+ import { a as ReadModelCoordinator, i as KyselyDocumentView, n as ConsistencyTracker, o as BaseReadModel, r as makeConsistencyKey, t as KyselyDocumentIndexer } from "./document-indexer-DLEyUQxU.js";
5
5
  import { n as errorToInfo, r as sanitizeArg, t as createForwardingLogger } from "./forwarding-logger-BBkMSxuJ.js";
6
- import { t as workerEntryPath } from "./worker-Dzrw1YMV.js";
6
+ import { t as workerEntryPath } from "./worker-XYrQaEmt.js";
7
7
  import { actions, actions as documentActions, createPresignedHeader, generateId, hashDocumentStateForScope, replayDocument } from "@powerhousedao/shared/document-model";
8
8
  import { addFile, addFolder, copyNode, deleteNode, driveCreateDocument, generateNodesCopy, getDescendants, handleTargetNameCollisions, isFileNode, isFolderNode, moveNode, updateNode } from "@powerhousedao/shared/document-drive";
9
9
  import { v4 } from "uuid";
10
- import { ConsoleLogger, childLogger } from "document-model";
10
+ import { ConsoleLogger } from "document-model";
11
11
  import { sql } from "kysely";
12
12
  import { RelationalDbProcessor, createRelationalDb } from "@powerhousedao/shared/processors";
13
13
  //#region src/actions/index.ts
@@ -2696,8 +2696,6 @@ var DocumentModelResolver = class {
2696
2696
  loadingModels = /* @__PURE__ */ new Map();
2697
2697
  failedModelTypes = /* @__PURE__ */ new Set();
2698
2698
  broadcastHook = null;
2699
- modelLoadedHook = null;
2700
- logger = childLogger(["reactor", "document-model-resolver"]);
2701
2699
  constructor(registry, loader) {
2702
2700
  this.registry = registry;
2703
2701
  this.loader = loader;
@@ -2710,13 +2708,6 @@ var DocumentModelResolver = class {
2710
2708
  setBroadcastHook(hook) {
2711
2709
  this.broadcastHook = hook;
2712
2710
  }
2713
- /**
2714
- * Post-success hook called with the document type after a model loads, so
2715
- * peers (tabs) can load the same type via the event bus.
2716
- */
2717
- setModelLoadedHook(hook) {
2718
- this.modelLoadedHook = hook;
2719
- }
2720
2711
  async ensureModelLoaded(documentType) {
2721
2712
  try {
2722
2713
  this.registry.getModule(documentType);
@@ -2729,32 +2720,20 @@ var DocumentModelResolver = class {
2729
2720
  if (existing) return existing;
2730
2721
  const loadPromise = (async () => {
2731
2722
  try {
2732
- await this.loadRegisterAndBroadcast(documentType);
2723
+ const module = await this.loader.load(documentType);
2724
+ const [result] = this.registry.registerModules(module);
2725
+ if (result.status === "error" && !DuplicateModuleError.isError(result.error)) throw result.error;
2726
+ await this.broadcastIfPossible(documentType);
2733
2727
  } catch (error) {
2734
2728
  this.failedModelTypes.add(documentType);
2735
2729
  throw error;
2736
2730
  } finally {
2737
2731
  this.loadingModels.delete(documentType);
2738
2732
  }
2739
- await this.notifyPeersModelLoaded(documentType);
2740
2733
  })();
2741
2734
  this.loadingModels.set(documentType, loadPromise);
2742
2735
  return loadPromise;
2743
2736
  }
2744
- async loadRegisterAndBroadcast(documentType) {
2745
- const module = await this.loader.load(documentType);
2746
- const [result] = this.registry.registerModules(module);
2747
- if (result.status === "error" && !DuplicateModuleError.isError(result.error)) throw result.error;
2748
- await this.broadcastIfPossible(documentType);
2749
- }
2750
- async notifyPeersModelLoaded(documentType) {
2751
- if (!this.modelLoadedHook) return;
2752
- try {
2753
- await this.modelLoadedHook(documentType);
2754
- } catch (error) {
2755
- this.logger.warn(`MODEL_LOADED hook failed: ${documentType}`, error);
2756
- }
2757
- }
2758
2737
  async broadcastIfPossible(documentType) {
2759
2738
  if (!this.broadcastHook || !this.loader.resolveSpec) return;
2760
2739
  const entry = await this.loader.resolveSpec(documentType);
@@ -4930,11 +4909,6 @@ function rowToRemoteRecord(row) {
4930
4909
  }
4931
4910
  };
4932
4911
  }
4933
- /**
4934
- * Maps a RemoteRecord to a row. jsonb array columns are JSON-encoded because the
4935
- * pg driver would otherwise emit a Postgres array literal ("{a,b}"), which jsonb
4936
- * rejects (matches sync-dead-letter-storage).
4937
- */
4938
4912
  function remoteRecordToRow(remote) {
4939
4913
  return {
4940
4914
  name: remote.name,
@@ -5381,14 +5355,11 @@ var SyncManager = class {
5381
5355
  for (const record of remoteRecords) {
5382
5356
  const channel = this.channelFactory.instance(record.id, record.name, record.channelConfig, this.cursorStorage, record.collectionId, record.filter, this.operationIndex, record.options);
5383
5357
  const remote = {
5384
- meta: {
5385
- id: record.id,
5386
- name: record.name,
5387
- collectionId: record.collectionId,
5388
- channelConfig: record.channelConfig,
5389
- filter: record.filter,
5390
- options: record.options
5391
- },
5358
+ id: record.id,
5359
+ name: record.name,
5360
+ collectionId: record.collectionId,
5361
+ filter: record.filter,
5362
+ options: record.options,
5392
5363
  channel
5393
5364
  };
5394
5365
  this.remotes.set(record.name, remote);
@@ -5407,7 +5378,7 @@ var SyncManager = class {
5407
5378
  this.backfillAbortControllers.set(record.name, backfillController);
5408
5379
  this.updateOutbox(remote, outboxAckOrdinal, OutboxMode.Backfill, backfillController.signal).catch((error) => {
5409
5380
  if (backfillController.signal.aborted) return;
5410
- this.logger.error("Backfill failed for remote @RemoteName: @Error", remote.meta.name, error instanceof Error ? error : new Error(String(error)));
5381
+ this.logger.error("Backfill failed for remote @RemoteName: @Error", remote.name, error instanceof Error ? error : new Error(String(error)));
5411
5382
  }).finally(() => {
5412
5383
  this.backfillAbortControllers.delete(record.name);
5413
5384
  });
@@ -5451,7 +5422,7 @@ var SyncManager = class {
5451
5422
  return remote;
5452
5423
  }
5453
5424
  getById(id) {
5454
- for (const remote of this.remotes.values()) if (remote.meta.id === id) return remote;
5425
+ for (const remote of this.remotes.values()) if (remote.id === id) return remote;
5455
5426
  throw new Error(`Remote with id '${id}' does not exist`);
5456
5427
  }
5457
5428
  async add(name, collectionId, channelConfig, filter = {
@@ -5478,14 +5449,11 @@ var SyncManager = class {
5478
5449
  await this.remoteStorage.upsert(remoteRecord);
5479
5450
  const channel = this.channelFactory.instance(remoteId, name, channelConfig, this.cursorStorage, collectionId, filter, this.operationIndex, options);
5480
5451
  const remote = {
5481
- meta: {
5482
- id: remoteId,
5483
- name,
5484
- collectionId,
5485
- channelConfig,
5486
- filter,
5487
- options
5488
- },
5452
+ id: remoteId,
5453
+ name,
5454
+ collectionId,
5455
+ filter,
5456
+ options,
5489
5457
  channel
5490
5458
  };
5491
5459
  this.remotes.set(name, remote);
@@ -5502,7 +5470,7 @@ var SyncManager = class {
5502
5470
  this.backfillAbortControllers.set(name, backfillController);
5503
5471
  this.updateOutbox(remote, 0, OutboxMode.Backfill, backfillController.signal).catch((error) => {
5504
5472
  if (backfillController.signal.aborted) return;
5505
- this.logger.error("Backfill failed for remote @RemoteName: @Error", remote.meta.name, error instanceof Error ? error : new Error(String(error)));
5473
+ this.logger.error("Backfill failed for remote @RemoteName: @Error", remote.name, error instanceof Error ? error : new Error(String(error)));
5506
5474
  }).finally(() => {
5507
5475
  this.backfillAbortControllers.delete(name);
5508
5476
  });
@@ -5553,20 +5521,20 @@ var SyncManager = class {
5553
5521
  }
5554
5522
  wireChannelCallbacks(remote) {
5555
5523
  remote.channel.inbox.onAdded((syncOps) => this.handleInboxAdded(remote, syncOps));
5556
- this.syncStatusTracker.trackRemote(remote.meta.name, remote.channel);
5524
+ this.syncStatusTracker.trackRemote(remote.name, remote.channel);
5557
5525
  const unsubscribe = remote.channel.onConnectionStateChange((snapshot) => {
5558
5526
  this.eventBus.emit(SyncEventTypes.CONNECTION_STATE_CHANGED, {
5559
- remoteName: remote.meta.name,
5560
- remoteId: remote.meta.id,
5527
+ remoteName: remote.name,
5528
+ remoteId: remote.id,
5561
5529
  previous: snapshot.state,
5562
5530
  current: snapshot.state,
5563
5531
  snapshot
5564
5532
  }).catch(() => {});
5565
5533
  });
5566
- this.connectionStateUnsubscribes.set(remote.meta.name, unsubscribe);
5534
+ this.connectionStateUnsubscribes.set(remote.name, unsubscribe);
5567
5535
  remote.channel.deadLetter.onAdded((syncOps) => {
5568
5536
  for (const syncOp of syncOps) {
5569
- this.logger.error("Dead letter (@remote, @documentId, @jobId, @error, @dependencies)", remote.meta.name, syncOp.documentId, syncOp.jobId, syncOp.error?.message ?? "unknown", syncOp.jobDependencies);
5537
+ this.logger.error("Dead letter (@remote, @documentId, @jobId, @error, @dependencies)", remote.name, syncOp.documentId, syncOp.jobId, syncOp.error?.message ?? "unknown", syncOp.jobDependencies);
5570
5538
  this.quarantinedDocumentIds.add(syncOp.documentId);
5571
5539
  const record = {
5572
5540
  id: syncOp.id,
@@ -5602,12 +5570,12 @@ var SyncManager = class {
5602
5570
  async loadDeadLetters(remote) {
5603
5571
  let records;
5604
5572
  try {
5605
- records = (await this.deadLetterStorage.list(remote.meta.name, {
5573
+ records = (await this.deadLetterStorage.list(remote.name, {
5606
5574
  cursor: "0",
5607
5575
  limit: this.config.maxDeadLettersPerRemote
5608
5576
  })).results;
5609
5577
  } catch (error) {
5610
- this.logger.error("Failed to load dead letters for remote (@name, @error)", remote.meta.name, error instanceof Error ? error.message : String(error));
5578
+ this.logger.error("Failed to load dead letters for remote (@name, @error)", remote.name, error instanceof Error ? error.message : String(error));
5611
5579
  return;
5612
5580
  }
5613
5581
  if (records.length === 0) return;
@@ -5619,10 +5587,10 @@ var SyncManager = class {
5619
5587
  syncOps.push(syncOp);
5620
5588
  }
5621
5589
  remote.channel.deadLetter.add(...syncOps);
5622
- this.logger.debug("Loaded @count persisted dead letters for remote @name", records.length, remote.meta.name);
5590
+ this.logger.debug("Loaded @count persisted dead letters for remote @name", records.length, remote.name);
5623
5591
  }
5624
5592
  getRemotesForCollection(collectionId) {
5625
- return Array.from(this.remotes.values()).filter((remote) => remote.meta.collectionId.key === collectionId);
5593
+ return Array.from(this.remotes.values()).filter((remote) => remote.collectionId.key === collectionId);
5626
5594
  }
5627
5595
  async processCompleteBatch(batch) {
5628
5596
  if (this.isShutdown) return;
@@ -5668,11 +5636,11 @@ var SyncManager = class {
5668
5636
  const operations = syncOp.operations.map((op) => op.operation);
5669
5637
  let jobInfo;
5670
5638
  try {
5671
- jobInfo = await this.reactor.load(syncOp.documentId, syncOp.branch, operations, this.abortController.signal, { sourceRemote: remote.meta.name });
5639
+ jobInfo = await this.reactor.load(syncOp.documentId, syncOp.branch, operations, this.abortController.signal, { sourceRemote: remote.name });
5672
5640
  } catch (error) {
5673
5641
  if (this.isShutdown) return;
5674
5642
  const err = error instanceof Error ? error : new Error(String(error));
5675
- this.logger.error("Failed to load operations from inbox (@remote, @documentId, @error)", remote.meta.name, syncOp.documentId, err.message);
5643
+ this.logger.error("Failed to load operations from inbox (@remote, @documentId, @error)", remote.name, syncOp.documentId, err.message);
5676
5644
  const channelError = new ChannelError(ChannelErrorSource.Inbox, err);
5677
5645
  syncOp.failed(channelError);
5678
5646
  remote.channel.deadLetter.add(syncOp);
@@ -5685,7 +5653,7 @@ var SyncManager = class {
5685
5653
  } catch (error) {
5686
5654
  if (this.isShutdown) return;
5687
5655
  const err = error instanceof Error ? error : new Error(String(error));
5688
- this.logger.error("Failed to wait for job completion (@remote, @documentId, @jobId, @error)", remote.meta.name, syncOp.documentId, jobInfo.id, err.message);
5656
+ this.logger.error("Failed to wait for job completion (@remote, @documentId, @jobId, @error)", remote.name, syncOp.documentId, jobInfo.id, err.message);
5689
5657
  const channelError = new ChannelError(ChannelErrorSource.Inbox, err);
5690
5658
  syncOp.failed(channelError);
5691
5659
  remote.channel.deadLetter.add(syncOp);
@@ -5695,7 +5663,7 @@ var SyncManager = class {
5695
5663
  if (this.isShutdown) return;
5696
5664
  if (completedJobInfo.status === JobStatus.FAILED) {
5697
5665
  const errorMessage = completedJobInfo.error?.message || "Unknown error";
5698
- this.logger.error("Failed to apply operations from inbox (@remote, @documentId, @jobId, @error)", remote.meta.name, syncOp.documentId, completedJobInfo.id, errorMessage);
5666
+ this.logger.error("Failed to apply operations from inbox (@remote, @documentId, @jobId, @error)", remote.name, syncOp.documentId, completedJobInfo.id, errorMessage);
5699
5667
  const error = new ChannelError(ChannelErrorSource.Inbox, /* @__PURE__ */ new Error(`Failed to apply operations: ${errorMessage}`));
5700
5668
  syncOp.failed(error);
5701
5669
  remote.channel.deadLetter.add(syncOp);
@@ -5703,7 +5671,7 @@ var SyncManager = class {
5703
5671
  remote.channel.inbox.remove(syncOp);
5704
5672
  }
5705
5673
  async applyInboxBatch(items) {
5706
- const sourceRemote = items[0].remote.meta.name;
5674
+ const sourceRemote = items[0].remote.name;
5707
5675
  const chunkKeys = new Set(items.map(({ syncOp }) => syncOp.jobId));
5708
5676
  const jobs = items.map(({ syncOp }) => {
5709
5677
  const dependsOn = [];
@@ -5753,7 +5721,7 @@ var SyncManager = class {
5753
5721
  }
5754
5722
  for (const { remote, syncOp } of items) {
5755
5723
  if (!(syncOp.jobId in result.jobs)) {
5756
- this.logger.error("Job key missing from batch load result (@remote, @documentId, @jobId)", remote.meta.name, syncOp.documentId, syncOp.jobId);
5724
+ this.logger.error("Job key missing from batch load result (@remote, @documentId, @jobId)", remote.name, syncOp.documentId, syncOp.jobId);
5757
5725
  const error = new ChannelError(ChannelErrorSource.Inbox, /* @__PURE__ */ new Error(`Job key '${syncOp.jobId}' missing from batch load result`));
5758
5726
  syncOp.failed(error);
5759
5727
  remote.channel.deadLetter.add(syncOp);
@@ -5787,7 +5755,7 @@ var SyncManager = class {
5787
5755
  let maxOrdinal = ackOrdinal;
5788
5756
  const lastJobByDoc = /* @__PURE__ */ new Map();
5789
5757
  let prevChainJobId;
5790
- const sinceTimestamp = remote.meta.options.sinceTimestampUtcMs;
5758
+ const sinceTimestamp = remote.options.sinceTimestampUtcMs;
5791
5759
  const emitBatches = (operations) => {
5792
5760
  if (operations.length === 0) return;
5793
5761
  const batches = batchOperationsByDocument(operations);
@@ -5798,14 +5766,14 @@ var SyncManager = class {
5798
5766
  const deps = [];
5799
5767
  if (prevJobId) deps.push(prevJobId);
5800
5768
  if (mode === OutboxMode.BatchTriggered && prevChainJobId && prevChainJobId !== prevJobId) deps.push(prevChainJobId);
5801
- const syncOp = new SyncOperation(crypto.randomUUID(), jobId, deps, remote.meta.name, batch.documentId, [batch.scope], batch.branch, batch.operations);
5769
+ const syncOp = new SyncOperation(crypto.randomUUID(), jobId, deps, remote.name, batch.documentId, [batch.scope], batch.branch, batch.operations);
5802
5770
  syncOps.push(syncOp);
5803
5771
  lastJobByDoc.set(batch.documentId, jobId);
5804
5772
  if (mode === OutboxMode.BatchTriggered) prevChainJobId = jobId;
5805
5773
  }
5806
5774
  remote.channel.outbox.add(...syncOps);
5807
5775
  };
5808
- let page = await this.operationIndex.find(remote.meta.collectionId.key, ackOrdinal, { excludeSourceRemote: remote.meta.name }, void 0, composedSignal);
5776
+ let page = await this.operationIndex.find(remote.collectionId.key, ackOrdinal, { excludeSourceRemote: remote.name }, void 0, composedSignal);
5809
5777
  let carry = [];
5810
5778
  let hasMore;
5811
5779
  do {
@@ -5817,7 +5785,7 @@ var SyncManager = class {
5817
5785
  carry = [];
5818
5786
  }
5819
5787
  if (sinceTimestamp && sinceTimestamp !== "0") operations = operations.filter((op) => op.operation.timestampUtcMs >= sinceTimestamp);
5820
- operations = filterOperations(operations, remote.meta.filter);
5788
+ operations = filterOperations(operations, remote.filter);
5821
5789
  operations = operations.filter((op) => !this.quarantinedDocumentIds.has(op.context.documentId));
5822
5790
  hasMore = !!page.next;
5823
5791
  if (operations.length > 0) {
@@ -6747,7 +6715,6 @@ var ReactorBuilder = class {
6747
6715
  const keyframeStore = new KyselyKeyframeStore(database);
6748
6716
  const eventBus = this.eventBus || new EventBus();
6749
6717
  const resolver = this.documentModelLoader ? new DocumentModelResolver(documentModelRegistry, this.documentModelLoader) : new NullDocumentModelResolver(documentModelRegistry);
6750
- if (resolver instanceof DocumentModelResolver) resolver.setModelLoadedHook((documentType) => eventBus.emit(ReactorEventTypes.MODEL_LOADED, { documentType }));
6751
6718
  const queue = this.queueInstance ?? new InMemoryQueue(eventBus, resolver);
6752
6719
  const jobTracker = new InMemoryJobTracker(eventBus);
6753
6720
  const writeCache = new KyselyWriteCache(keyframeStore, operationStore, documentModelRegistry, {
@@ -6863,7 +6830,7 @@ var ReactorBuilder = class {
6863
6830
  poolInstrumentations.push(forwarder);
6864
6831
  this.instrumentedPools.push(forwarder);
6865
6832
  }
6866
- const { ProjectionShardManager } = await import("./projection-shard-manager-BnQKFqQd.js");
6833
+ const { ProjectionShardManager } = await import("./projection-shard-manager-_c7orNo5.js");
6867
6834
  const manager = new ProjectionShardManager({
6868
6835
  shardCount: config.shardCount,
6869
6836
  db,
@@ -6896,7 +6863,7 @@ var ReactorBuilder = class {
6896
6863
  const [{ WorkerHandle }, { createThreadTransport }, { workerEntryPath }] = await Promise.all([
6897
6864
  import("./worker-handle-B1w03nRA.js"),
6898
6865
  import("./transport-ByGviWdZ.js"),
6899
- import("./worker-Dzrw1YMV.js").then((n) => n.n)
6866
+ import("./worker-XYrQaEmt.js").then((n) => n.n)
6900
6867
  ]);
6901
6868
  const db = this.workerDbConfig;
6902
6869
  const signatureVerifier = this.workerSignatureVerifierSpec;