@abloatai/humans 0.56.0 → 0.58.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/dist/Ablo.d.ts +8 -18
  2. package/dist/client.d.ts +6 -19
  3. package/dist/core.d.ts +1 -1
  4. package/dist/core.js +1 -1
  5. package/dist/local/Database.d.ts +1 -1
  6. package/dist/local/Model.js +1 -1
  7. package/dist/local/SyncClient.d.ts +3 -34
  8. package/dist/local/SyncClient.js +6 -16
  9. package/dist/local/client/createInternalComponents.d.ts +1 -1
  10. package/dist/local/client/createInternalComponents.js +1 -1
  11. package/dist/local/client/{createModelProxy.d.ts → createModelOperations.d.ts} +22 -9
  12. package/dist/local/client/{createModelProxy.js → createModelOperations.js} +341 -335
  13. package/dist/local/client/options.d.ts +2 -2
  14. package/dist/local/client/reactiveEngine.js +38 -45
  15. package/dist/local/client/resourceTypes.d.ts +3 -3
  16. package/dist/local/client/resourceTypes.js +1 -1
  17. package/dist/local/client/wsMutationExecutor.d.ts +4 -4
  18. package/dist/local/client/wsMutationExecutor.js +4 -5
  19. package/dist/local/coordination/ClaimLog.d.ts +3 -3
  20. package/dist/local/coordination/ClaimLog.js +2 -2
  21. package/dist/local/interfaces/index.d.ts +5 -7
  22. package/dist/local/mutators/mutateActions.d.ts +3 -2
  23. package/dist/local/query/types.d.ts +2 -2
  24. package/dist/local/stores/syncAction.d.ts +1 -1
  25. package/dist/local/stores/syncAction.js +1 -1
  26. package/dist/local/sync/ConnectionManager.d.ts +1 -1
  27. package/dist/local/sync/ConnectionManager.js +1 -1
  28. package/dist/local/sync/OnDemandLoader.d.ts +1 -1
  29. package/dist/local/sync/OnDemandLoader.js +1 -1
  30. package/dist/local/sync/SyncWebSocket.d.ts +3 -3
  31. package/dist/local/sync/SyncWebSocket.js +2 -2
  32. package/dist/local/sync/commitFrames.d.ts +1 -1
  33. package/dist/local/sync/commitFrames.js +1 -1
  34. package/dist/local/sync/contextOnChange.d.ts +8 -0
  35. package/dist/local/sync/contextOnChange.js +65 -0
  36. package/dist/local/sync/createClaimStream.d.ts +1 -1
  37. package/dist/local/sync/createClaimStream.js +47 -28
  38. package/dist/local/sync/credentialLifecycle.d.ts +1 -1
  39. package/dist/local/sync/credentialLifecycle.js +1 -1
  40. package/dist/local/sync/participants.d.ts +1 -1
  41. package/dist/local/sync/schemas.d.ts +2 -2
  42. package/dist/local/sync/schemas.js +1 -1
  43. package/dist/local/sync/wsFrameHandlers.d.ts +1 -1
  44. package/dist/local/sync/wsFrameHandlers.js +1 -1
  45. package/dist/local/syncClientTypes.d.ts +41 -0
  46. package/dist/local/syncClientTypes.js +11 -0
  47. package/dist/local/transactions/databaseCommitOutbox.d.ts +2 -2
  48. package/dist/local/transactions/mutations/MutationQueue.d.ts +5 -18
  49. package/dist/local/transactions/mutations/MutationQueue.js +57 -137
  50. package/dist/local/transactions/mutations/batchProcessing.d.ts +2 -13
  51. package/dist/local/transactions/mutations/batchProcessing.js +0 -20
  52. package/dist/local/transactions/mutations/commitApi.d.ts +2 -3
  53. package/dist/local/transactions/mutations/commitApi.js +0 -4
  54. package/dist/local/transactions/mutations/commitLane.d.ts +6 -8
  55. package/dist/local/transactions/mutations/commitLane.js +12 -14
  56. package/dist/local/transactions/mutations/commitPayload.d.ts +2 -4
  57. package/dist/local/transactions/mutations/commitPayload.js +2 -6
  58. package/dist/local/transactions/mutations/commitTransport.d.ts +3 -4
  59. package/dist/local/transactions/mutations/commitTransport.js +2 -5
  60. package/dist/local/transactions/mutations/durableCommitRestore.d.ts +1 -1
  61. package/dist/local/transactions/mutations/durableCommitRestore.js +1 -4
  62. package/dist/local/transactions/mutations/durableWriteStore.d.ts +5 -5
  63. package/dist/local/transactions/mutations/durableWriteStore.js +3 -3
  64. package/dist/local/transactions/mutations/failurePolicy.d.ts +2 -2
  65. package/dist/local/transactions/mutations/mutationInput.d.ts +40 -0
  66. package/dist/local/transactions/mutations/mutationInput.js +53 -0
  67. package/dist/local/transactions/mutations/mutationPersistence.d.ts +1 -1
  68. package/dist/local/transactions/mutations/pendingDrain.d.ts +2 -2
  69. package/dist/local/transactions/mutations/replayValidation.d.ts +0 -20
  70. package/dist/local/transactions/mutations/replayValidation.js +1 -3
  71. package/dist/local/transactions/persistedTransaction.d.ts +0 -2
  72. package/dist/plugin.d.ts +2 -2
  73. package/dist/presenceStream.d.ts +1 -1
  74. package/dist/react/createAbloReact.d.ts +1 -1
  75. package/dist/react/useAblo.d.ts +2 -2
  76. package/dist/react/useAblo.js +1 -1
  77. package/dist/surface.d.ts +1 -1
  78. package/dist/surface.js +2 -2
  79. package/package.json +2 -2
  80. package/src/Ablo.ts +9 -27
  81. package/src/client.ts +6 -22
  82. package/src/core.ts +1 -1
  83. package/src/local/Database.ts +1 -2
  84. package/src/local/Model.ts +1 -1
  85. package/src/local/SyncClient.ts +17 -72
  86. package/src/local/client/createInternalComponents.ts +2 -2
  87. package/src/local/client/{createModelProxy.ts → createModelOperations.ts} +396 -320
  88. package/src/local/client/options.ts +2 -2
  89. package/src/local/client/reactiveEngine.ts +67 -55
  90. package/src/local/client/resourceTypes.ts +4 -4
  91. package/src/local/client/wsMutationExecutor.ts +4 -9
  92. package/src/local/coordination/ClaimLog.ts +3 -3
  93. package/src/local/interfaces/index.ts +5 -7
  94. package/src/local/mutators/mutateActions.ts +3 -2
  95. package/src/local/query/types.ts +2 -2
  96. package/src/local/stores/syncAction.ts +1 -1
  97. package/src/local/sync/ConnectionManager.ts +1 -1
  98. package/src/local/sync/OnDemandLoader.ts +1 -1
  99. package/src/local/sync/SyncWebSocket.ts +3 -3
  100. package/src/local/sync/commitFrames.ts +1 -2
  101. package/src/local/sync/contextOnChange.ts +92 -0
  102. package/src/local/sync/createClaimStream.ts +77 -39
  103. package/src/local/sync/credentialLifecycle.ts +1 -1
  104. package/src/local/sync/participants.ts +1 -1
  105. package/src/local/sync/schemas.ts +1 -1
  106. package/src/local/sync/wsFrameHandlers.ts +1 -1
  107. package/src/local/syncClientTypes.ts +59 -0
  108. package/src/local/transactions/databaseCommitOutbox.ts +2 -2
  109. package/src/local/transactions/mutations/MutationQueue.ts +69 -183
  110. package/src/local/transactions/mutations/batchProcessing.ts +2 -38
  111. package/src/local/transactions/mutations/commitApi.ts +3 -7
  112. package/src/local/transactions/mutations/commitLane.ts +24 -20
  113. package/src/local/transactions/mutations/commitPayload.ts +3 -11
  114. package/src/local/transactions/mutations/commitTransport.ts +3 -7
  115. package/src/local/transactions/mutations/durableCommitRestore.ts +2 -5
  116. package/src/local/transactions/mutations/durableWriteStore.ts +5 -5
  117. package/src/local/transactions/mutations/failurePolicy.ts +2 -2
  118. package/src/local/transactions/mutations/mutationInput.ts +69 -0
  119. package/src/local/transactions/mutations/mutationPersistence.ts +1 -1
  120. package/src/local/transactions/mutations/pendingDrain.ts +2 -2
  121. package/src/local/transactions/mutations/replayValidation.ts +1 -3
  122. package/src/local/transactions/persistedTransaction.ts +0 -3
  123. package/src/plugin.ts +2 -2
  124. package/src/presenceStream.ts +2 -2
  125. package/src/react/createAbloReact.ts +1 -1
  126. package/src/react/useAblo.ts +2 -2
  127. package/src/surface.ts +3 -3
  128. package/dist/local/sync/createSnapshot.d.ts +0 -29
  129. package/dist/local/sync/createSnapshot.js +0 -116
  130. package/src/local/sync/createSnapshot.ts +0 -160
@@ -14,19 +14,17 @@
14
14
  import { EventEmitter } from 'events';
15
15
  import { v4 as uuid } from 'uuid';
16
16
  import { globalRuntime } from '../../context.js';
17
- import { AbloError, AbloConnectionError, AbloIdempotencyError, AbloNotFoundError, AbloValidationError, errorCodeSpec, } from '@abloatai/transaction/errors';
17
+ import { AbloConnectionError, AbloIdempotencyError, } from '@abloatai/transaction/errors';
18
18
  import { LogPosition, } from '../../logPosition.js';
19
- import { mutationCommitResultSchema, } from '@abloatai/transaction/wire/commit';
20
- import { projectCommitPayload, computePriorityScore, normalizeModelKey,
21
- // Includes stale guards as well as request identity/audit barriers.
22
- hasCommitCoalescingBarrier, applyWriteOptions, asTransportError, extractStatusCode, TX_TYPE_TO_MUTATION_OP, } from './commitPayload.js';
19
+ import {} from '@abloatai/transaction/commit';
20
+ import { computePriorityScore, normalizeModelKey, } from './commitPayload.js';
21
+ import { generateTransactionId, mergeMutationData, createDataFor, changesToInput, updateDataFor, previousDataFor, } from './mutationInput.js';
23
22
  import { MutationStore } from './MutationStore.js';
24
- import { entityKey, mergeUpdateData, takeUnsentCreateForModel, findCreateBarrierForDelete, deferDeleteUntilCreateSettles, releaseDeferredDeletesForCreate, } from './coalesceRules.js';
23
+ import { entityKey, takeUnsentCreateForModel, findCreateBarrierForDelete, deferDeleteUntilCreateSettles, releaseDeferredDeletesForCreate, } from './coalesceRules.js';
25
24
  import { DeltaConfirmationTracker } from './deltaConfirmation.js';
26
- import { deserializePersistedTransaction, isNonReplayablePersistedRow, pendingMutationRecordId, legacyPendingMutationRecordSchema, pendingMutationRecordSchema, persistedMutationSchema, } from './replayValidation.js';
25
+ import { deserializePersistedTransaction, isNonReplayablePersistedRow, pendingMutationRecordId, } from './replayValidation.js';
27
26
  import { deserializeLegacyPendingMutation, loadPersistedTransactions, persistQueuedTransaction, removePersistedTransaction, settlePersistedFailure, } from './mutationPersistence.js';
28
- import { createCommitEnvelopeMember, createDurableCommitEnvelope, commitEnvelopeRecordId, durableCommitEnvelopeSchema, } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
29
- import { stableStringify } from '@abloatai/transaction/utils/json';
27
+ import { createCommitEnvelopeMember, } from '@abloatai/transaction/commit';
30
28
  import { createLocalMutationPort, } from './localMutation.js';
31
29
  import { dispatchCommitBounded, parseMutationCommitResult, persistDurableCommitAcceptance, removeDurableCommit, sealDurableCommit, } from './commitTransport.js';
32
30
  import { processCommitLane, waitForCommitReceipt, } from './commitLane.js';
@@ -120,7 +118,7 @@ export class MutationQueue extends EventEmitter {
120
118
  commitOutbox: this.commitOutbox,
121
119
  commitOutboxScope: this.commitOutboxScope,
122
120
  mutationExecutor: this.mutationExecutor,
123
- emitCommitLifecycle: (event, payload) => this.emitCommitLifecycle(event, payload),
121
+ emitCommitLifecycle: (event, payload) => { this.emitCommitLifecycle(event, payload); },
124
122
  };
125
123
  }
126
124
  get commitLaneContext() {
@@ -132,24 +130,22 @@ export class MutationQueue extends EventEmitter {
132
130
  retryBackoff: this.config.retryBackoff,
133
131
  },
134
132
  commitLane: this.commitLane,
135
- commitNotifications: this.commitNotifications,
136
133
  commitMissingIds: this.commitMissingIds,
137
134
  commitProcessing: this.commitProcessing,
138
135
  setCommitProcessing: (value) => { this.commitProcessing = value; },
139
136
  durableReplayBlock: this.durableReplayBlock,
140
137
  sealDurableCommit: (input) => this.sealDurableCommit(input),
141
- assertEnvelopeInsideReplayWindow: (envelope) => this.assertEnvelopeInsideReplayWindow(envelope),
138
+ assertEnvelopeInsideReplayWindow: (envelope) => { this.assertEnvelopeInsideReplayWindow(envelope); },
142
139
  dispatchCommit: async (envelope) => this.parseMutationCommitResult(await this.dispatchCommitBounded(envelope.operations, {
143
140
  idempotencyKey: envelope.idempotencyKey,
144
141
  ...(envelope.commitOptions.reads ? { reads: envelope.commitOptions.reads } : {}),
145
- ...(envelope.commitOptions.track ? { track: envelope.commitOptions.track } : {}),
146
142
  })),
147
143
  persistDurableCommitAcceptance: (envelope, result) => this.persistDurableCommitAcceptance(envelope, result),
148
144
  removeDurableCommit: (idempotencyKey) => this.removeDurableCommit(idempotencyKey),
149
145
  queuedCommitEchoSyncId: (transaction) => this.queuedCommitEchoSyncId(transaction),
150
- completeQueuedCommit: (transaction, syncId) => this.completeQueuedCommit(transaction, syncId),
151
- scheduleReplicationLagTimeout: (transactionId, clientTxId, correlationId) => this.scheduleReplicationLagTimeout(transactionId, clientTxId, correlationId),
152
- noteAck: (syncId) => this.noteAck(syncId),
146
+ completeQueuedCommit: (transaction, syncId) => { this.completeQueuedCommit(transaction, syncId); },
147
+ scheduleReplicationLagTimeout: (transactionId, clientTxId, correlationId) => { this.scheduleReplicationLagTimeout(transactionId, clientTxId, correlationId); },
148
+ noteAck: (syncId) => { this.noteAck(syncId); },
153
149
  isDefinitiveRejection: (error) => this.isDefinitiveRejection(error),
154
150
  isPermanentError: (error) => this.isPermanentError(error),
155
151
  scheduleRetry: (delayMs) => {
@@ -160,13 +156,12 @@ export class MutationQueue extends EventEmitter {
160
156
  void this.processCommitLane();
161
157
  }, delayMs);
162
158
  },
163
- emitCommitLifecycle: (event, payload) => this.emitCommitLifecycle(event, payload),
159
+ emitCommitLifecycle: (event, payload) => { this.emitCommitLifecycle(event, payload); },
164
160
  };
165
161
  }
166
162
  get commitReceiptContext() {
167
163
  return {
168
164
  commitStore: this.commitStore,
169
- commitNotifications: this.commitNotifications,
170
165
  commitMissingIds: this.commitMissingIds,
171
166
  replicationLagErrors: this.replicationLagErrors,
172
167
  on: (event, listener) => this.on(event, listener),
@@ -175,22 +170,22 @@ export class MutationQueue extends EventEmitter {
175
170
  }
176
171
  get commitApiContext() {
177
172
  return {
178
- assertDurableReplayOpen: () => this.assertDurableReplayOpen(),
173
+ assertDurableReplayOpen: () => { this.assertDurableReplayOpen(); },
179
174
  commitStore: this.commitStore,
180
175
  commitLane: this.commitLane,
181
176
  replicationLagErrors: this.replicationLagErrors,
182
- clearReplicationLagState: (transactionId) => this.clearReplicationLagState(transactionId),
177
+ clearReplicationLagState: (transactionId) => { this.clearReplicationLagState(transactionId); },
183
178
  nextCommitSequence: () => this.nextCommitSequence(),
184
179
  sealDurableCommit: (input) => this.sealDurableCommit(input),
185
180
  processCommitLane: () => this.processCommitLane(),
186
- emitCommitLifecycle: (event, payload) => this.emitCommitLifecycle(event, payload),
181
+ emitCommitLifecycle: (event, payload) => { this.emitCommitLifecycle(event, payload); },
187
182
  };
188
183
  }
189
184
  get modelMutationContext() {
190
185
  return {
191
186
  enableOptimistic: this.config.enableOptimistic,
192
187
  persistenceReady: !!this.persistence && !!this.commitOutboxScope,
193
- assertDurableReplayOpen: () => this.assertDurableReplayOpen(),
188
+ assertDurableReplayOpen: () => { this.assertDurableReplayOpen(); },
194
189
  generateId: () => this.generateId(),
195
190
  normalizeModelKey,
196
191
  computePriorityScore: (type, modelName) => this.computePriorityScore(type, modelName),
@@ -199,11 +194,11 @@ export class MutationQueue extends EventEmitter {
199
194
  extractPreviousData: (model, input) => this.extractPreviousData(model, input),
200
195
  mapChangesToInput: (modelName, changes) => this.mapChangesToInput(modelName, changes),
201
196
  isReorderPayload: (input) => this.isReorderPayload(input),
202
- attachConfirmation: (transaction) => this.attachConfirmation(transaction),
203
- add: (transaction) => this.store.add(transaction),
204
- applyOptimisticCreate: (model, transaction) => this.applyOptimisticCreate(model, transaction),
205
- applyOptimisticUpdate: (model, transaction) => this.applyOptimisticUpdate(model, transaction),
206
- applyOptimisticDelete: (model, transaction) => this.applyOptimisticDelete(model, transaction),
197
+ attachConfirmation: (transaction) => { this.attachConfirmation(transaction); },
198
+ add: (transaction) => { this.store.add(transaction); },
199
+ applyOptimisticCreate: (model, transaction) => { this.applyOptimisticCreate(model, transaction); },
200
+ applyOptimisticUpdate: (model, transaction) => { this.applyOptimisticUpdate(model, transaction); },
201
+ applyOptimisticDelete: (model, transaction) => { this.applyOptimisticDelete(model, transaction); },
207
202
  takeUnsentCreateForModel: (modelName, modelId) => this.takeUnsentCreateForModel(modelName, modelId),
208
203
  cancelUnsentCreateForDelete: (transaction) => this.cancelUnsentCreateForDelete(transaction),
209
204
  completeLocalDelete: (model, context, writeOptions, sourceMutationIds) => this.completeLocalDelete(model, context, writeOptions, sourceMutationIds),
@@ -211,11 +206,11 @@ export class MutationQueue extends EventEmitter {
211
206
  pendingMergeByModel: this.pendingMergeByModel,
212
207
  inFlightByModel: this.inFlightByModel,
213
208
  findCreateBarrierForDelete: (modelName, modelId) => this.findCreateBarrierForDelete(modelName, modelId),
214
- deferDeleteUntilCreateSettles: (create, transaction) => this.deferDeleteUntilCreateSettles(create, transaction),
209
+ deferDeleteUntilCreateSettles: (create, transaction) => { this.deferDeleteUntilCreateSettles(create, transaction); },
215
210
  logger: this.runtime.logger,
216
211
  persistAndStage: (transaction, modelData) => this.persistAndStage(transaction, modelData),
217
212
  persistQueuedTransaction: (transaction, modelData) => this.persistQueuedTransaction(transaction, modelData),
218
- stageTransaction: (transaction) => this.stageTransaction(transaction),
213
+ stageTransaction: (transaction) => { this.stageTransaction(transaction); },
219
214
  emit: (event, payload) => this.emit(event, payload),
220
215
  };
221
216
  }
@@ -224,9 +219,9 @@ export class MutationQueue extends EventEmitter {
224
219
  executionQueue: this.executionQueue,
225
220
  inFlightByModel: this.inFlightByModel,
226
221
  pendingMergeByModel: this.pendingMergeByModel,
227
- ensureDerivedFields: (transaction) => this.ensureDerivedFields(transaction),
228
- scheduleProcessing: (immediate) => this.scheduleProcessing(immediate),
229
- storeRemove: (transactionId) => this.store.remove(transactionId),
222
+ ensureDerivedFields: (transaction) => { this.ensureDerivedFields(transaction); },
223
+ scheduleProcessing: (immediate) => { this.scheduleProcessing(immediate); },
224
+ storeRemove: (transactionId) => { this.store.remove(transactionId); },
230
225
  };
231
226
  }
232
227
  get batchProcessingContext() {
@@ -238,7 +233,7 @@ export class MutationQueue extends EventEmitter {
238
233
  isProcessing: this.isProcessing,
239
234
  setIsProcessing: (value) => { this.isProcessing = value; },
240
235
  takeNextExecutionBatch: () => this.takeNextExecutionBatch(),
241
- ensureDerivedFields: (transaction) => this.ensureDerivedFields(transaction),
236
+ ensureDerivedFields: (transaction) => { this.ensureDerivedFields(transaction); },
242
237
  ensureCommitEnvelope: (batch) => this.ensureCommitEnvelope([...batch]),
243
238
  executingCount: this.executingCount,
244
239
  setExecutingCount: (value) => { this.executingCount = value; },
@@ -247,31 +242,28 @@ export class MutationQueue extends EventEmitter {
247
242
  generateId: () => this.generateId(),
248
243
  computePriorityScore: (type, modelName) => this.computePriorityScore(type, modelName),
249
244
  store: this.store,
250
- enqueue: (transaction) => this.enqueue(transaction),
245
+ enqueue: (transaction) => { this.enqueue(transaction); },
251
246
  optimisticUpdates: this.localMutationPort.updates,
252
- commitNotifications: this.commitNotifications,
253
247
  commitMissingIds: this.commitMissingIds,
254
248
  sourceMutationIdsFor: (batch) => this.sourceMutationIdsFor(batch),
255
249
  dispatchCommitBounded: (...args) => this.dispatchCommitBounded(...args),
256
250
  parseMutationCommitResult: (value) => this.parseMutationCommitResult(value),
257
251
  persistDurableCommitAcceptance: (envelope, result) => this.persistDurableCommitAcceptance(envelope, result),
258
252
  removeDurableCommit: (idempotencyKey) => this.removeDurableCommit(idempotencyKey),
259
- assertEnvelopeInsideReplayWindow: (envelope) => this.assertEnvelopeInsideReplayWindow(envelope),
253
+ assertEnvelopeInsideReplayWindow: (envelope) => { this.assertEnvelopeInsideReplayWindow(envelope); },
260
254
  sealDurableCommit: (input) => this.sealDurableCommit(input),
261
- noteAck: (syncId) => this.noteAck(syncId),
262
- classifyReceiptNotifications: (operations, notifications) => this.classifyReceiptNotifications(operations, notifications),
263
- receiptTargetKey: (modelName, modelId) => this.receiptTargetKey(modelName, modelId),
264
- scheduleReplicationLagTimeout: (transactionId, clientTxId, correlationId) => this.scheduleReplicationLagTimeout(transactionId, clientTxId, correlationId),
265
- scheduleDeltaConfirmationTimeout: (transaction, timeoutMs) => this.scheduleDeltaConfirmationTimeout(transaction, timeoutMs),
266
- clearReplicationLagState: (transactionId) => this.clearReplicationLagState(transactionId),
267
- completeQueuedCommit: (transaction, syncId) => this.completeQueuedCommit(transaction, syncId),
255
+ noteAck: (syncId) => { this.noteAck(syncId); },
256
+ scheduleReplicationLagTimeout: (transactionId, clientTxId, correlationId) => { this.scheduleReplicationLagTimeout(transactionId, clientTxId, correlationId); },
257
+ scheduleDeltaConfirmationTimeout: (transaction, timeoutMs) => { this.scheduleDeltaConfirmationTimeout(transaction, timeoutMs); },
258
+ clearReplicationLagState: (transactionId) => { this.clearReplicationLagState(transactionId); },
259
+ completeQueuedCommit: (transaction, syncId) => { this.completeQueuedCommit(transaction, syncId); },
268
260
  queuedCommitMatchesCorrelation: (transaction, correlationId) => this.queuedCommitMatchesCorrelation(transaction, correlationId),
269
261
  recentDeltaCorrelations: this.recentDeltaCorrelations,
270
262
  lastSeenSyncId: this.lastSeenSyncId,
271
- scheduleProcessing: (immediate) => this.scheduleProcessing(immediate),
263
+ scheduleProcessing: (immediate) => { this.scheduleProcessing(immediate); },
272
264
  handleFailure: (transaction, error) => this.handleFailure(transaction, error),
273
265
  isDefinitiveRejection: (error) => this.isDefinitiveRejection(error),
274
- emitCommitLifecycle: (event, payload) => this.emitCommitLifecycle(event, payload),
266
+ emitCommitLifecycle: (event, payload) => { this.emitCommitLifecycle(event, payload); },
275
267
  emit: (event, payload) => this.emit(event, payload),
276
268
  rollbackOptimistic: (transaction, reason, error) => this.rollbackOptimistic(transaction, reason, error),
277
269
  };
@@ -283,19 +275,19 @@ export class MutationQueue extends EventEmitter {
283
275
  store: this.store,
284
276
  isPermanentError: (error) => this.isPermanentError(error),
285
277
  rollbackOptimistic: (transaction, reason, error) => this.rollbackOptimistic(transaction, reason, error),
286
- enqueue: (transaction) => this.enqueue(transaction),
278
+ enqueue: (transaction) => { this.enqueue(transaction); },
287
279
  getLastPermanentErrorSignature: () => this.lastPermanentErrorSig,
288
280
  setLastPermanentErrorSignature: (signature) => { this.lastPermanentErrorSig = signature; },
289
281
  emit: (event, payload) => this.emit(event, payload),
290
282
  };
291
283
  }
292
- get conflictPolicyContext() {
284
+ get conflictResolutionContext() {
293
285
  return {
294
286
  config: this.config,
295
287
  store: this.store,
296
288
  rollbackOptimistic: (transaction, reason) => this.rollbackOptimistic(transaction, reason),
297
289
  mergeData: (local, remote) => this.mergeData(local, remote),
298
- enqueue: (transaction) => this.enqueue(transaction),
290
+ enqueue: (transaction) => { this.enqueue(transaction); },
299
291
  };
300
292
  }
301
293
  get processingSchedulerContext() {
@@ -318,21 +310,21 @@ export class MutationQueue extends EventEmitter {
318
310
  store: this.store,
319
311
  executionQueue: this.executionQueue,
320
312
  optimisticUpdates: this.localMutationPort.updates,
321
- assertDurableReplayOpen: () => this.assertDurableReplayOpen(),
313
+ assertDurableReplayOpen: () => { this.assertDurableReplayOpen(); },
322
314
  processCommitLane: () => this.processCommitLane(),
323
315
  takePendingDrainBatch: (pending) => this.takePendingDrainBatch(pending),
324
316
  ensureCommitEnvelope: (batch) => this.ensureCommitEnvelope(batch),
325
- ensureDerivedFields: (transaction) => this.ensureDerivedFields(transaction),
317
+ ensureDerivedFields: (transaction) => { this.ensureDerivedFields(transaction); },
326
318
  sourceMutationIdsFor: (batch) => this.sourceMutationIdsFor(batch),
327
319
  sealDurableCommit: (input) => this.sealDurableCommit(input),
328
- assertEnvelopeInsideReplayWindow: (envelope) => this.assertEnvelopeInsideReplayWindow(envelope),
320
+ assertEnvelopeInsideReplayWindow: (envelope) => { this.assertEnvelopeInsideReplayWindow(envelope); },
329
321
  parseMutationCommitResult: (value) => this.parseMutationCommitResult(value),
330
322
  dispatchCommitBounded: (...args) => this.dispatchCommitBounded(...args),
331
323
  persistDurableCommitAcceptance: (envelope, result) => this.persistDurableCommitAcceptance(envelope, result),
332
324
  removeDurableCommit: (idempotencyKey) => this.removeDurableCommit(idempotencyKey),
333
- scheduleReplicationLagTimeout: (transactionId, clientTxId, correlationId) => this.scheduleReplicationLagTimeout(transactionId, clientTxId, correlationId),
334
- scheduleDeltaConfirmationTimeout: (transaction, timeoutMs) => this.scheduleDeltaConfirmationTimeout(transaction, timeoutMs),
335
- enqueue: (transaction) => this.enqueue(transaction),
325
+ scheduleReplicationLagTimeout: (transactionId, clientTxId, correlationId) => { this.scheduleReplicationLagTimeout(transactionId, clientTxId, correlationId); },
326
+ scheduleDeltaConfirmationTimeout: (transaction, timeoutMs) => { this.scheduleDeltaConfirmationTimeout(transaction, timeoutMs); },
327
+ enqueue: (transaction) => { this.enqueue(transaction); },
336
328
  recentDeltaCorrelations: this.recentDeltaCorrelations,
337
329
  emit: (event, payload) => this.emit(event, payload),
338
330
  };
@@ -356,7 +348,7 @@ export class MutationQueue extends EventEmitter {
356
348
  commitOutboxScope: this.commitOutboxScope,
357
349
  config: this.config,
358
350
  store: this.store,
359
- enqueue: (transaction) => this.enqueue(transaction),
351
+ enqueue: (transaction) => { this.enqueue(transaction); },
360
352
  computePriorityScore: (type, modelName) => this.computePriorityScore(type, modelName),
361
353
  deserializeTransaction: (data) => this.deserializeTransaction(data),
362
354
  };
@@ -410,59 +402,7 @@ export class MutationQueue extends EventEmitter {
410
402
  entityKey(modelName, modelId) {
411
403
  return entityKey(modelName, modelId);
412
404
  }
413
- /** Collision-safe receipt target identity across models sharing a row id. */
414
- receiptTargetKey(modelName, modelId) {
415
- return stableStringify([normalizeModelKey(modelName), modelId]);
416
- }
417
- /**
418
- * Relates stale notifications back to write targets without assuming the
419
- * server's canonical model name uses the same spelling as the public schema
420
- * key (`Item` versus `items`). Exact `(model,id)` wins; a globally unique id
421
- * is the compatibility fallback. An ambiguous same-id cross-model mismatch
422
- * is deliberately left unclassified, so it cannot falsely settle a queued
423
- * write. A notification with no write-target id (or an explicit group) is a
424
- * declared-read conflict and holds the whole batch.
425
- */
426
- classifyReceiptNotifications(operations, notifications) {
427
- const targets = operations.map((operation) => ({
428
- id: operation.id,
429
- key: this.receiptTargetKey(operation.model, operation.id),
430
- }));
431
- const heldTargets = new Set();
432
- const notificationsByTarget = new Map();
433
- let holdsEntireBatch = false;
434
- for (const notification of notifications) {
435
- // Scope is decided before any target matching. A group premise fires over
436
- // the WHOLE batch by convention, and its `target` now names the row that
437
- // actually moved — which may well be a row this batch is writing, so
438
- // matching first would misread a batch-wide hold as a per-row one.
439
- if (notification.scope === 'group') {
440
- holdsEntireBatch = true;
441
- continue;
442
- }
443
- const candidates = targets.filter((target) => target.id === notification.target.id);
444
- const notificationKey = this.receiptTargetKey(notification.target.model, notification.target.id);
445
- const exactTargets = candidates.filter((target) => target.key === notificationKey);
446
- const candidateKeys = new Set((exactTargets.length > 0 ? exactTargets : candidates).map((target) => target.key));
447
- if (candidates.length === 0) {
448
- holdsEntireBatch = true;
449
- continue;
450
- }
451
- if (candidateKeys.size !== 1) {
452
- // Same id across multiple differently named models with no exact match:
453
- // the id-only compatibility fallback is ambiguous. Await the echo.
454
- continue;
455
- }
456
- const [targetKey] = candidateKeys;
457
- if (!targetKey)
458
- continue;
459
- heldTargets.add(targetKey);
460
- const targetNotifications = notificationsByTarget.get(targetKey) ?? [];
461
- targetNotifications.push(notification);
462
- notificationsByTarget.set(targetKey, targetNotifications);
463
- }
464
- return { holdsEntireBatch, heldTargets, notificationsByTarget };
465
- }
405
+ /* Stale receipt classification was removed; stale premises now reject. */
466
406
  resolveConfirmation(transaction) {
467
407
  const resolver = this.confirmationResolvers.get(transaction.id);
468
408
  if (!resolver)
@@ -544,11 +484,6 @@ export class MutationQueue extends EventEmitter {
544
484
  // Track executing transactions for backpressure
545
485
  executingCount = 0;
546
486
  localMutationPort;
547
- // Stale-context notifications, keyed by transaction id. When the server
548
- // accepts a commit but reports that an operation's premise had moved,
549
- // the notification lands here from the commit acknowledgement and is drained
550
- // by `waitForCommitReceipt`, so the receipt can carry it back to the caller.
551
- commitNotifications = new Map();
552
487
  /** Zero-row targets returned on a successful atomic commit receipt. */
553
488
  commitMissingIds = new Map();
554
489
  // Delta-confirmation tracking (ack watermark advance + the awaiting_delta
@@ -1267,7 +1202,7 @@ export class MutationQueue extends EventEmitter {
1267
1202
  await handleFailure(this.failureHandlingContext, transaction, error);
1268
1203
  }
1269
1204
  async handleConflict(transaction, serverData) {
1270
- await resolveConflict(this.conflictPolicyContext, transaction, serverData);
1205
+ await resolveConflict(this.conflictResolutionContext, transaction, serverData);
1271
1206
  }
1272
1207
  applyOptimisticCreate(model, transaction) {
1273
1208
  this.localMutationPort.applyCreate(model, transaction);
@@ -1390,39 +1325,25 @@ export class MutationQueue extends EventEmitter {
1390
1325
  ];
1391
1326
  }
1392
1327
  /** Generates a unique local transaction id. */
1328
+ // The payload rules live in `mutationInput`; these keep the call sites here
1329
+ // reading as the queue's own vocabulary.
1393
1330
  generateId() {
1394
- return `tx_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
1331
+ return generateTransactionId();
1395
1332
  }
1396
1333
  mergeData(local, remote) {
1397
- return { ...(remote || {}), ...(local || {}) };
1334
+ return mergeMutationData(local, remote);
1398
1335
  }
1399
1336
  extractCreateData(model) {
1400
- return projectCommitPayload(model.getModelName(), model.toJSON(), { dropUndefined: false }, this.runtime);
1337
+ return createDataFor(model, this.runtime);
1401
1338
  }
1402
1339
  mapChangesToInput(modelName, changes) {
1403
- return projectCommitPayload(modelName, changes, { dropUndefined: true }, this.runtime);
1340
+ return changesToInput(modelName, changes, this.runtime);
1404
1341
  }
1405
1342
  extractUpdateData(model) {
1406
- return projectCommitPayload(model.getModelName(), model.getChanges(), { dropUndefined: true }, this.runtime);
1343
+ return updateDataFor(model, this.runtime);
1407
1344
  }
1408
- // Derive previous values for changed fields to support accurate rollback.
1409
- // Model-specific special cases do not belong here; a model that needs to
1410
- // surface previous state beyond `modifiedProperties` should expose a typed
1411
- // `getPreviousData()` accessor for this method to call.
1412
1345
  extractPreviousData(model, updateInput) {
1413
- // When the update's written keys are known, capture a before-image for
1414
- // exactly those keys, so the recorded undo inverse reverts them and nothing
1415
- // else — a full-row inverse would clobber concurrent edits to unrelated
1416
- // fields. `fallbackToLive: false` makes `Model.capturePreviousValues` omit
1417
- // any key it cannot resolve, and `buildUndoOps` then drops an un-revertible
1418
- // inverse rather than inventing one. With no `updateInput` (a full extract)
1419
- // it falls back to every tracked field. `Model.capturePreviousValues` is the
1420
- // single before-image source, shared with
1421
- // `RecordingMutation.snapshotFields`.
1422
- const keys = updateInput
1423
- ? Object.keys(updateInput)
1424
- : [...(model.modifiedProperties instanceof Map ? model.modifiedProperties.keys() : [])];
1425
- return { id: model.id, ...model.capturePreviousValues(keys, { fallbackToLive: false }) };
1346
+ return previousDataFor(model, updateInput);
1426
1347
  }
1427
1348
  /** Returns a snapshot of queue counts and the current configuration. */
1428
1349
  getStats() {
@@ -1533,7 +1454,6 @@ export class MutationQueue extends EventEmitter {
1533
1454
  this.recentDeltaCorrelations.clear();
1534
1455
  this.commitLane = [];
1535
1456
  this.commitStore.clear();
1536
- this.commitNotifications.clear();
1537
1457
  this.commitMissingIds.clear();
1538
1458
  // Clear event listeners
1539
1459
  this.removeAllListeners();
@@ -3,9 +3,8 @@ import type { MutationQueueConfig } from './MutationQueue.js';
3
3
  import type { MutationInput, QueuedMutation } from './commitPayload.js';
4
4
  import type { MutationStore } from './MutationStore.js';
5
5
  import type { OptimisticUpdateEntry } from './localMutation.js';
6
- import type { StaleNotification } from '@abloatai/transaction/coordination/schema';
7
- import type { MutationCommitResult } from '@abloatai/transaction/wire/commit';
8
- import type { DurableCommitEnvelope } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
6
+ import type { MutationCommitResult } from '@abloatai/transaction/commit';
7
+ import type { DurableCommitEnvelope } from '@abloatai/transaction/commit';
9
8
  export interface BatchProcessingContext {
10
9
  readonly runtime: RuntimeContext;
11
10
  readonly config: MutationQueueConfig;
@@ -28,7 +27,6 @@ export interface BatchProcessingContext {
28
27
  readonly store: MutationStore;
29
28
  readonly enqueue: (transaction: QueuedMutation) => void;
30
29
  readonly optimisticUpdates: Map<string, OptimisticUpdateEntry>;
31
- readonly commitNotifications: Map<string, StaleNotification[]>;
32
30
  readonly commitMissingIds: Map<string, string[]>;
33
31
  readonly sourceMutationIdsFor: (batch: readonly QueuedMutation[]) => string[];
34
32
  readonly dispatchCommitBounded: (...args: Parameters<import('../../interfaces/index.js').MutationExecutor['commit']>) => ReturnType<import('../../interfaces/index.js').MutationExecutor['commit']>;
@@ -38,15 +36,6 @@ export interface BatchProcessingContext {
38
36
  readonly assertEnvelopeInsideReplayWindow: (envelope: DurableCommitEnvelope) => void;
39
37
  readonly sealDurableCommit: (input: Parameters<typeof import('./commitTransport.js').sealDurableCommit>[1]) => Promise<DurableCommitEnvelope>;
40
38
  readonly noteAck: (syncId: number | undefined) => void;
41
- readonly classifyReceiptNotifications: (operations: readonly {
42
- model: string;
43
- id: string;
44
- }[], notifications: readonly StaleNotification[]) => {
45
- holdsEntireBatch: boolean;
46
- heldTargets: Set<string>;
47
- notificationsByTarget: Map<string, StaleNotification[]>;
48
- };
49
- readonly receiptTargetKey: (modelName: string, modelId: string) => string;
50
39
  readonly scheduleReplicationLagTimeout: (transactionId: string, clientTxId?: string, correlationId?: string) => void;
51
40
  readonly scheduleDeltaConfirmationTimeout: (transaction: QueuedMutation, timeoutMs: number) => void;
52
41
  readonly clearReplicationLagState: (transactionId: string) => void;
@@ -87,17 +87,6 @@ export async function processBatch(ctx) {
87
87
  }));
88
88
  await ctx.persistDurableCommitAcceptance(durableEnvelope, result);
89
89
  const lastSyncId = result.lastSyncId;
90
- const notifications = result.notifications;
91
- const { holdsEntireBatch, heldTargets, notificationsByTarget, } = ctx.classifyReceiptNotifications(batchOps.map(({ op }) => ({ model: op.model, id: op.id })), notifications ?? []);
92
- for (const { tx } of batchOps) {
93
- const txTarget = ctx.receiptTargetKey(tx.modelKey, tx.modelId);
94
- const txNotifs = holdsEntireBatch
95
- ? notifications
96
- : notificationsByTarget.get(txTarget);
97
- if (txNotifs && txNotifs.length > 0) {
98
- ctx.commitNotifications.set(tx.id, txNotifs);
99
- }
100
- }
101
90
  const missingIds = new Set(result.missingIds ?? []);
102
91
  const settlingBatchOps = [];
103
92
  for (const entry of batchOps) {
@@ -106,15 +95,6 @@ export async function processBatch(ctx) {
106
95
  await ctx.handleFailure(tx, new AbloNotFoundError(`${tx.modelName}/${tx.modelId} was not found or is outside this credential's scope.`, [tx.modelId]));
107
96
  continue;
108
97
  }
109
- if (holdsEntireBatch ||
110
- heldTargets.has(ctx.receiptTargetKey(tx.modelKey, tx.modelId))) {
111
- await ctx.rollbackOptimistic(tx, 'conflict_server_wins');
112
- ctx.store.updateStatus(tx.id, 'completed');
113
- ctx.emit('transaction:completed', tx);
114
- ctx.emit(`transaction:completed:${tx.id}`, tx);
115
- ctx.optimisticUpdates.delete(tx.id);
116
- continue;
117
- }
118
98
  settlingBatchOps.push(entry);
119
99
  }
120
100
  // A forwarded write has been accepted, but the source database
@@ -1,5 +1,5 @@
1
- import type { ReadDependency, TrackDependency } from '@abloatai/transaction/coordination/schema';
2
- import type { DurableCommitEnvelope } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
1
+ import type { ReadDependency } from '@abloatai/transaction/coordination/schema';
2
+ import type { DurableCommitEnvelope } from '@abloatai/transaction/commit';
3
3
  import type { CommitTransaction } from './commitLane.js';
4
4
  import type { SealDurableCommitInput } from './commitTransport.js';
5
5
  export interface CommitApiContext {
@@ -15,5 +15,4 @@ export interface CommitApiContext {
15
15
  }
16
16
  export declare function enqueueCommit(ctx: CommitApiContext, clientTxId: string, operations: CommitTransaction['operations'], options?: {
17
17
  reads?: ReadDependency[] | null;
18
- track?: TrackDependency[] | null;
19
18
  }): Promise<void>;
@@ -8,12 +8,10 @@ export async function enqueueCommit(ctx, clientTxId, operations, options = {}) {
8
8
  const existingIntent = stableStringify({
9
9
  operations: existing.operations,
10
10
  reads: existing.reads ?? null,
11
- track: existing.track ?? null,
12
11
  });
13
12
  const incomingIntent = stableStringify({
14
13
  operations,
15
14
  reads: options.reads ?? null,
16
- track: options.track ?? null,
17
15
  });
18
16
  if (existingIntent !== incomingIntent) {
19
17
  throw new AbloIdempotencyError('Idempotency key reused with a different atomic commit request', { code: 'idempotency_conflict' });
@@ -34,7 +32,6 @@ export async function enqueueCommit(ctx, clientTxId, operations, options = {}) {
34
32
  kind: 'commit',
35
33
  operations: [...operations],
36
34
  ...(options.reads ? { reads: options.reads } : {}),
37
- ...(options.track ? { track: options.track } : {}),
38
35
  status: 'pending',
39
36
  createdAt: now,
40
37
  attempts: 0,
@@ -48,7 +45,6 @@ export async function enqueueCommit(ctx, clientTxId, operations, options = {}) {
48
45
  operations: tx.operations,
49
46
  commitOptions: {
50
47
  ...(tx.reads ? { reads: tx.reads } : {}),
51
- ...(tx.track ? { track: tx.track } : {}),
52
48
  },
53
49
  createdAt: tx.createdAt,
54
50
  sealedAt: tx.sealedAt,
@@ -1,7 +1,7 @@
1
1
  import type { RuntimeContext } from '../../RuntimeContext.js';
2
- import type { ReadDependency, TrackDependency, OnStaleMode, StaleNotification } from '@abloatai/transaction/coordination/schema';
3
- import type { MutationCommitResult } from '@abloatai/transaction/wire/commit';
4
- import type { DurableCommitEnvelope, DurableCommitOperation } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
2
+ import type { ReadDependency } from '@abloatai/transaction/coordination/schema';
3
+ import type { CommitOperationResult, MutationCommitResult } from '@abloatai/transaction/commit';
4
+ import type { DurableCommitEnvelope, DurableCommitOperation } from '@abloatai/transaction/commit';
5
5
  import type { SealDurableCommitInput } from './commitTransport.js';
6
6
  export interface CommitTransaction {
7
7
  id: string;
@@ -13,16 +13,16 @@ export interface CommitTransaction {
13
13
  input?: Record<string, unknown>;
14
14
  transactionId?: string;
15
15
  readAt?: number | null;
16
- onStale?: OnStaleMode | null;
17
16
  }[];
18
17
  reads?: ReadDependency[] | null;
19
- track?: TrackDependency[] | null;
20
18
  status: 'pending' | 'executing' | 'awaiting_delta' | 'completed' | 'failed';
21
19
  createdAt: number;
22
20
  attempts: number;
23
21
  transientAttempts?: number;
24
22
  firstTransientFailureAt?: number;
25
23
  lastSyncId?: number;
24
+ /** Fresh transport rows. Deliberately transient: durable server replays redact row data. */
25
+ operationResults?: CommitOperationResult[];
26
26
  correlationId?: string;
27
27
  error?: Error;
28
28
  sealedAt: number;
@@ -42,7 +42,6 @@ export interface CommitLaneContext {
42
42
  };
43
43
  };
44
44
  readonly commitLane: CommitTransaction[];
45
- readonly commitNotifications: Map<string, StaleNotification[]>;
46
45
  readonly commitMissingIds: Map<string, string[]>;
47
46
  readonly commitProcessing: boolean;
48
47
  readonly setCommitProcessing: (value: boolean) => void;
@@ -63,7 +62,6 @@ export interface CommitLaneContext {
63
62
  }
64
63
  export interface CommitReceiptContext {
65
64
  readonly commitStore: Map<string, CommitTransaction>;
66
- readonly commitNotifications: Map<string, StaleNotification[]>;
67
65
  readonly commitMissingIds: Map<string, string[]>;
68
66
  readonly replicationLagErrors: Map<string, Error>;
69
67
  readonly on: (event: string, listener: (payload: object) => void) => void;
@@ -71,7 +69,7 @@ export interface CommitReceiptContext {
71
69
  }
72
70
  export declare function waitForCommitReceipt(ctx: CommitReceiptContext, clientTxId: string): Promise<{
73
71
  lastSyncId: number;
74
- notifications?: StaleNotification[];
75
72
  missingIds?: string[];
73
+ operationResults?: CommitOperationResult[];
76
74
  }>;
77
75
  export declare function processCommitLane(ctx: CommitLaneContext): Promise<void>;
@@ -1,12 +1,5 @@
1
1
  import { transientRetryDelayMs } from './failureHandling.js';
2
2
  export function waitForCommitReceipt(ctx, clientTxId) {
3
- const drainNotifications = () => {
4
- const notifications = ctx.commitNotifications.get(clientTxId);
5
- if (!notifications)
6
- return undefined;
7
- ctx.commitNotifications.delete(clientTxId);
8
- return notifications.length > 0 ? notifications : undefined;
9
- };
10
3
  const drainMissingIds = () => {
11
4
  const ids = ctx.commitMissingIds.get(clientTxId);
12
5
  if (!ids)
@@ -14,18 +7,20 @@ export function waitForCommitReceipt(ctx, clientTxId) {
14
7
  ctx.commitMissingIds.delete(clientTxId);
15
8
  return ids.length > 0 ? ids : undefined;
16
9
  };
17
- const receipt = (lastSyncId) => {
10
+ const receipt = (transaction, lastSyncId) => {
18
11
  const missingIds = drainMissingIds();
19
12
  return {
20
13
  lastSyncId,
21
- notifications: drainNotifications(),
14
+ ...(transaction.operationResults
15
+ ? { operationResults: transaction.operationResults }
16
+ : {}),
22
17
  ...(missingIds ? { missingIds } : {}),
23
18
  };
24
19
  };
25
20
  return new Promise((resolve, reject) => {
26
21
  const existing = ctx.commitStore.get(clientTxId);
27
22
  if (existing?.status === 'completed') {
28
- resolve(receipt(existing.lastSyncId ?? 0));
23
+ resolve(receipt(existing, existing.lastSyncId ?? 0));
29
24
  return;
30
25
  }
31
26
  if (existing?.status === 'failed' && existing.error) {
@@ -37,7 +32,11 @@ export function waitForCommitReceipt(ctx, clientTxId) {
37
32
  reject(lagError);
38
33
  return;
39
34
  }
40
- const onCompleted = (tx) => { cleanup(); resolve(receipt(tx.lastSyncId ?? 0)); };
35
+ const onCompleted = (tx) => {
36
+ cleanup();
37
+ const completed = tx;
38
+ resolve(receipt(completed, completed.lastSyncId ?? 0));
39
+ };
41
40
  const onFailed = (payload) => { cleanup(); reject(payload.error); };
42
41
  const onLagged = (payload) => { cleanup(); reject(payload.error); };
43
42
  const cleanup = () => {
@@ -74,7 +73,6 @@ export async function processCommitLane(ctx) {
74
73
  sourceMutationIds: tx.sourceMutationIds,
75
74
  commitOptions: {
76
75
  ...(tx.reads ? { reads: tx.reads } : {}),
77
- ...(tx.track ? { track: tx.track } : {}),
78
76
  },
79
77
  createdAt: tx.createdAt,
80
78
  sealedAt: tx.sealedAt,
@@ -86,8 +84,8 @@ export async function processCommitLane(ctx) {
86
84
  const result = await ctx.dispatchCommit(durableEnvelope);
87
85
  tx.durableEnvelope = await ctx.persistDurableCommitAcceptance(durableEnvelope, result);
88
86
  tx.lastSyncId = result.lastSyncId;
89
- if (result.notifications?.length)
90
- ctx.commitNotifications.set(tx.id, result.notifications);
87
+ if (result.operationResults?.length)
88
+ tx.operationResults = [...result.operationResults];
91
89
  if (result.missingIds?.length)
92
90
  ctx.commitMissingIds.set(tx.id, result.missingIds);
93
91
  ctx.commitLane.shift();