@abloatai/humans 0.57.0 → 0.59.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 +10 -1
  7. package/dist/local/SyncClient.js +5 -0
  8. package/dist/local/client/createInternalComponents.d.ts +1 -1
  9. package/dist/local/client/createInternalComponents.js +1 -1
  10. package/dist/local/client/{createModelProxy.d.ts → createModelOperations.d.ts} +11 -10
  11. package/dist/local/client/{createModelProxy.js → createModelOperations.js} +240 -313
  12. package/dist/local/client/options.d.ts +2 -2
  13. package/dist/local/client/reactiveEngine.js +34 -45
  14. package/dist/local/client/resourceTypes.d.ts +3 -3
  15. package/dist/local/client/resourceTypes.js +1 -1
  16. package/dist/local/client/schemaConfig.js +1 -0
  17. package/dist/local/client/wsMutationExecutor.d.ts +4 -4
  18. package/dist/local/client/wsMutationExecutor.js +3 -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 +10 -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/BootstrapFetcher.js +4 -4
  27. package/dist/local/sync/ConnectionManager.d.ts +1 -1
  28. package/dist/local/sync/ConnectionManager.js +1 -1
  29. package/dist/local/sync/OnDemandLoader.d.ts +1 -1
  30. package/dist/local/sync/OnDemandLoader.js +1 -1
  31. package/dist/local/sync/SyncWebSocket.d.ts +3 -3
  32. package/dist/local/sync/SyncWebSocket.js +2 -2
  33. package/dist/local/sync/commitFrames.d.ts +1 -1
  34. package/dist/local/sync/commitFrames.js +1 -1
  35. package/dist/local/sync/contextOnChange.d.ts +8 -0
  36. package/dist/local/sync/contextOnChange.js +65 -0
  37. package/dist/local/sync/createClaimStream.d.ts +1 -1
  38. package/dist/local/sync/createClaimStream.js +47 -28
  39. package/dist/local/sync/credentialLifecycle.d.ts +1 -1
  40. package/dist/local/sync/credentialLifecycle.js +1 -1
  41. package/dist/local/sync/participants.d.ts +1 -1
  42. package/dist/local/sync/schemaDrift.d.ts +15 -1
  43. package/dist/local/sync/schemaDrift.js +30 -13
  44. package/dist/local/sync/schemas.d.ts +2 -2
  45. package/dist/local/sync/schemas.js +1 -1
  46. package/dist/local/sync/wsFrameHandlers.d.ts +1 -1
  47. package/dist/local/sync/wsFrameHandlers.js +1 -1
  48. package/dist/local/transactions/databaseCommitOutbox.d.ts +2 -2
  49. package/dist/local/transactions/mutations/MutationQueue.d.ts +4 -19
  50. package/dist/local/transactions/mutations/MutationQueue.js +5 -70
  51. package/dist/local/transactions/mutations/batchProcessing.d.ts +2 -13
  52. package/dist/local/transactions/mutations/batchProcessing.js +0 -20
  53. package/dist/local/transactions/mutations/commitApi.d.ts +2 -3
  54. package/dist/local/transactions/mutations/commitApi.js +0 -4
  55. package/dist/local/transactions/mutations/commitLane.d.ts +3 -8
  56. package/dist/local/transactions/mutations/commitLane.js +0 -11
  57. package/dist/local/transactions/mutations/commitPayload.d.ts +2 -4
  58. package/dist/local/transactions/mutations/commitPayload.js +2 -6
  59. package/dist/local/transactions/mutations/commitTransport.d.ts +3 -4
  60. package/dist/local/transactions/mutations/commitTransport.js +2 -5
  61. package/dist/local/transactions/mutations/durableCommitRestore.d.ts +1 -1
  62. package/dist/local/transactions/mutations/durableCommitRestore.js +1 -4
  63. package/dist/local/transactions/mutations/durableWriteStore.d.ts +5 -5
  64. package/dist/local/transactions/mutations/durableWriteStore.js +3 -3
  65. package/dist/local/transactions/mutations/failurePolicy.d.ts +2 -2
  66. package/dist/local/transactions/mutations/mutationPersistence.d.ts +1 -1
  67. package/dist/local/transactions/mutations/pendingDrain.d.ts +2 -2
  68. package/dist/local/transactions/mutations/replayValidation.d.ts +0 -20
  69. package/dist/local/transactions/mutations/replayValidation.js +1 -3
  70. package/dist/local/transactions/persistedTransaction.d.ts +0 -2
  71. package/dist/plugin.d.ts +2 -2
  72. package/dist/presenceStream.d.ts +1 -1
  73. package/dist/react/createAbloReact.d.ts +1 -1
  74. package/dist/react/useAblo.d.ts +2 -2
  75. package/dist/react/useAblo.js +1 -1
  76. package/dist/surface.d.ts +1 -1
  77. package/dist/surface.js +1 -2
  78. package/package.json +2 -2
  79. package/src/Ablo.ts +9 -27
  80. package/src/client.ts +6 -22
  81. package/src/core.ts +1 -1
  82. package/src/local/Database.ts +1 -1
  83. package/src/local/Model.ts +12 -1
  84. package/src/local/SyncClient.ts +5 -0
  85. package/src/local/client/createInternalComponents.ts +2 -2
  86. package/src/local/client/{createModelProxy.ts → createModelOperations.ts} +292 -367
  87. package/src/local/client/options.ts +2 -2
  88. package/src/local/client/reactiveEngine.ts +63 -55
  89. package/src/local/client/resourceTypes.ts +4 -4
  90. package/src/local/client/schemaConfig.ts +3 -0
  91. package/src/local/client/wsMutationExecutor.ts +3 -9
  92. package/src/local/coordination/ClaimLog.ts +3 -3
  93. package/src/local/interfaces/index.ts +7 -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/BootstrapFetcher.ts +5 -4
  98. package/src/local/sync/ConnectionManager.ts +1 -1
  99. package/src/local/sync/OnDemandLoader.ts +1 -1
  100. package/src/local/sync/SyncWebSocket.ts +3 -3
  101. package/src/local/sync/commitFrames.ts +1 -2
  102. package/src/local/sync/contextOnChange.ts +92 -0
  103. package/src/local/sync/createClaimStream.ts +77 -39
  104. package/src/local/sync/credentialLifecycle.ts +1 -1
  105. package/src/local/sync/participants.ts +1 -1
  106. package/src/local/sync/schemaDrift.ts +32 -16
  107. package/src/local/sync/schemas.ts +1 -1
  108. package/src/local/sync/wsFrameHandlers.ts +1 -1
  109. package/src/local/transactions/databaseCommitOutbox.ts +2 -2
  110. package/src/local/transactions/mutations/MutationQueue.ts +8 -95
  111. package/src/local/transactions/mutations/batchProcessing.ts +2 -38
  112. package/src/local/transactions/mutations/commitApi.ts +3 -7
  113. package/src/local/transactions/mutations/commitLane.ts +3 -17
  114. package/src/local/transactions/mutations/commitPayload.ts +3 -11
  115. package/src/local/transactions/mutations/commitTransport.ts +3 -7
  116. package/src/local/transactions/mutations/durableCommitRestore.ts +2 -5
  117. package/src/local/transactions/mutations/durableWriteStore.ts +5 -5
  118. package/src/local/transactions/mutations/failurePolicy.ts +2 -2
  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 +2 -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
@@ -1,7 +1,7 @@
1
1
  import { AbloIdempotencyError } from '@abloatai/transaction/errors';
2
- import type { ReadDependency, TrackDependency } from '@abloatai/transaction/coordination/schema';
2
+ import type { ReadDependency } from '@abloatai/transaction/coordination/schema';
3
3
  import { stableStringify } from '@abloatai/transaction/utils/json';
4
- import type { DurableCommitEnvelope } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
4
+ import type { DurableCommitEnvelope } from '@abloatai/transaction/commit';
5
5
  import type { CommitTransaction } from './commitLane.js';
6
6
  import type { SealDurableCommitInput } from './commitTransport.js';
7
7
 
@@ -21,7 +21,7 @@ export async function enqueueCommit(
21
21
  ctx: CommitApiContext,
22
22
  clientTxId: string,
23
23
  operations: CommitTransaction['operations'],
24
- options: { reads?: ReadDependency[] | null; track?: TrackDependency[] | null } = {},
24
+ options: { reads?: ReadDependency[] | null } = {},
25
25
  ): Promise<void> {
26
26
  ctx.assertDurableReplayOpen();
27
27
  const existing = ctx.commitStore.get(clientTxId);
@@ -30,12 +30,10 @@ export async function enqueueCommit(
30
30
  const existingIntent = stableStringify({
31
31
  operations: existing.operations,
32
32
  reads: existing.reads ?? null,
33
- track: existing.track ?? null,
34
33
  });
35
34
  const incomingIntent = stableStringify({
36
35
  operations,
37
36
  reads: options.reads ?? null,
38
- track: options.track ?? null,
39
37
  });
40
38
  if (existingIntent !== incomingIntent) {
41
39
  throw new AbloIdempotencyError(
@@ -59,7 +57,6 @@ export async function enqueueCommit(
59
57
  kind: 'commit',
60
58
  operations: [...operations],
61
59
  ...(options.reads ? { reads: options.reads } : {}),
62
- ...(options.track ? { track: options.track } : {}),
63
60
  status: 'pending',
64
61
  createdAt: now,
65
62
  attempts: 0,
@@ -73,7 +70,6 @@ export async function enqueueCommit(
73
70
  operations: tx.operations,
74
71
  commitOptions: {
75
72
  ...(tx.reads ? { reads: tx.reads } : {}),
76
- ...(tx.track ? { track: tx.track } : {}),
77
73
  },
78
74
  createdAt: tx.createdAt,
79
75
  sealedAt: tx.sealedAt,
@@ -1,13 +1,13 @@
1
1
  import type { RuntimeContext } from '../../RuntimeContext.js';
2
- import type { ReadDependency, TrackDependency, OnStaleMode, StaleNotification } from '@abloatai/transaction/coordination/schema';
2
+ import type { ReadDependency } from '@abloatai/transaction/coordination/schema';
3
3
  import type {
4
4
  CommitOperationResult,
5
5
  MutationCommitResult,
6
- } from '@abloatai/transaction/wire/commit';
6
+ } from '@abloatai/transaction/commit';
7
7
  import type {
8
8
  DurableCommitEnvelope,
9
9
  DurableCommitOperation,
10
- } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
10
+ } from '@abloatai/transaction/commit';
11
11
  import type { SealDurableCommitInput } from './commitTransport.js';
12
12
  import { transientRetryDelayMs } from './failureHandling.js';
13
13
 
@@ -21,10 +21,8 @@ export interface CommitTransaction {
21
21
  input?: Record<string, unknown>;
22
22
  transactionId?: string;
23
23
  readAt?: number | null;
24
- onStale?: OnStaleMode | null;
25
24
  }[];
26
25
  reads?: ReadDependency[] | null;
27
- track?: TrackDependency[] | null;
28
26
  status: 'pending' | 'executing' | 'awaiting_delta' | 'completed' | 'failed';
29
27
  createdAt: number;
30
28
  attempts: number;
@@ -50,7 +48,6 @@ export interface CommitLaneContext {
50
48
  retryBackoff: { baseMs: number; capMs: number };
51
49
  };
52
50
  readonly commitLane: CommitTransaction[];
53
- readonly commitNotifications: Map<string, StaleNotification[]>;
54
51
  readonly commitMissingIds: Map<string, string[]>;
55
52
  readonly commitProcessing: boolean;
56
53
  readonly setCommitProcessing: (value: boolean) => void;
@@ -72,7 +69,6 @@ export interface CommitLaneContext {
72
69
 
73
70
  export interface CommitReceiptContext {
74
71
  readonly commitStore: Map<string, CommitTransaction>;
75
- readonly commitNotifications: Map<string, StaleNotification[]>;
76
72
  readonly commitMissingIds: Map<string, string[]>;
77
73
  readonly replicationLagErrors: Map<string, Error>;
78
74
  readonly on: (event: string, listener: (payload: object) => void) => void;
@@ -84,16 +80,9 @@ export function waitForCommitReceipt(
84
80
  clientTxId: string,
85
81
  ): Promise<{
86
82
  lastSyncId: number;
87
- notifications?: StaleNotification[];
88
83
  missingIds?: string[];
89
84
  operationResults?: CommitOperationResult[];
90
85
  }> {
91
- const drainNotifications = (): StaleNotification[] | undefined => {
92
- const notifications = ctx.commitNotifications.get(clientTxId);
93
- if (!notifications) return undefined;
94
- ctx.commitNotifications.delete(clientTxId);
95
- return notifications.length > 0 ? notifications : undefined;
96
- };
97
86
  const drainMissingIds = (): string[] | undefined => {
98
87
  const ids = ctx.commitMissingIds.get(clientTxId);
99
88
  if (!ids) return undefined;
@@ -104,7 +93,6 @@ export function waitForCommitReceipt(
104
93
  const missingIds = drainMissingIds();
105
94
  return {
106
95
  lastSyncId,
107
- notifications: drainNotifications(),
108
96
  ...(transaction.operationResults
109
97
  ? { operationResults: transaction.operationResults }
110
98
  : {}),
@@ -157,7 +145,6 @@ export async function processCommitLane(ctx: CommitLaneContext): Promise<void> {
157
145
  sourceMutationIds: tx.sourceMutationIds,
158
146
  commitOptions: {
159
147
  ...(tx.reads ? { reads: tx.reads } : {}),
160
- ...(tx.track ? { track: tx.track } : {}),
161
148
  },
162
149
  createdAt: tx.createdAt,
163
150
  sealedAt: tx.sealedAt,
@@ -170,7 +157,6 @@ export async function processCommitLane(ctx: CommitLaneContext): Promise<void> {
170
157
  tx.durableEnvelope = await ctx.persistDurableCommitAcceptance(durableEnvelope, result);
171
158
  tx.lastSyncId = result.lastSyncId;
172
159
  if (result.operationResults?.length) tx.operationResults = [...result.operationResults];
173
- if (result.notifications?.length) ctx.commitNotifications.set(tx.id, result.notifications);
174
160
  if (result.missingIds?.length) ctx.commitMissingIds.set(tx.id, result.missingIds);
175
161
  ctx.commitLane.shift();
176
162
  if (result.status === 'queued') {
@@ -13,9 +13,8 @@ import { globalRuntime } from '../../context.js';
13
13
  import type { RuntimeContext } from '../../RuntimeContext.js';
14
14
  import { MutationOperationType } from '@abloatai/transaction/types';
15
15
  import { snapshotJsonValue } from '@abloatai/transaction/utils/json';
16
- import type { OnStaleMode } from '@abloatai/transaction/coordination/schema';
17
16
  import type { MutationOptions, WriteOptions } from '../../interfaces/index.js';
18
- import type { CommitEnvelopeMember } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
17
+ import type { CommitEnvelopeMember } from '@abloatai/transaction/commit';
19
18
 
20
19
  export interface UserContext {
21
20
  userId: string;
@@ -198,10 +197,7 @@ export const TX_TYPE_TO_MUTATION_OP: Record<QueuedMutation['type'], MutationOper
198
197
  };
199
198
 
200
199
  export function hasStaleWriteOptions(options?: WriteOptions): boolean {
201
- return (
202
- options?.readAt !== undefined ||
203
- options?.onStale !== undefined
204
- );
200
+ return options?.readAt !== undefined;
205
201
  }
206
202
 
207
203
  /** Options whose identity/audit semantics forbid merging two caller writes. */
@@ -217,7 +213,6 @@ export function hasCommitCoalescingBarrier(options?: WriteOptions): boolean {
217
213
 
218
214
  export interface WriteOperationFields {
219
215
  readAt?: number | null;
220
- onStale?: OnStaleMode | null;
221
216
  fenceToken?: number | null;
222
217
  claimId?: string;
223
218
  options?: Pick<MutationOptions, 'idempotencyKey' | 'label'>;
@@ -225,7 +220,7 @@ export interface WriteOperationFields {
225
220
 
226
221
  /**
227
222
  * Copies a transaction's `writeOptions` onto the wire operation. The
228
- * stale-context guards (`readAt` and `onStale`) sit at the operation's root,
223
+ * stale-context guard (`readAt`) sits at the operation's root,
229
224
  * while `idempotencyKey` and `label` go in its `options` slot — the
230
225
  * `mutation_log` cache key and audit tag. This is the one place caller-supplied
231
226
  * write options cross onto the wire.
@@ -240,9 +235,6 @@ export function applyWriteOptions<T extends object>(
240
235
  if (writeOptions.readAt !== undefined) {
241
236
  operation.readAt = writeOptions.readAt;
242
237
  }
243
- if (writeOptions.onStale !== undefined) {
244
- operation.onStale = writeOptions.onStale;
245
- }
246
238
  if (writeOptions.fenceToken !== undefined) {
247
239
  operation.fenceToken = writeOptions.fenceToken;
248
240
  }
@@ -1,6 +1,6 @@
1
1
  import type { RuntimeContext } from '../../RuntimeContext.js';
2
2
  import type { MutationExecutor } from '../../interfaces/index.js';
3
- import type { ReadDependency, TrackDependency } from '@abloatai/transaction/coordination/schema';
3
+ import type { ReadDependency } from '@abloatai/transaction/coordination/schema';
4
4
  import {
5
5
  AbloConnectionError,
6
6
  AbloError,
@@ -9,7 +9,7 @@ import {
9
9
  import {
10
10
  mutationCommitResultSchema,
11
11
  type MutationCommitResult,
12
- } from '@abloatai/transaction/wire/commit';
12
+ } from '@abloatai/transaction/commit';
13
13
  import {
14
14
  createDurableCommitEnvelope,
15
15
  commitEnvelopeRecordId,
@@ -17,7 +17,7 @@ import {
17
17
  type CommitOutboxScope,
18
18
  type DurableCommitEnvelope,
19
19
  type DurableCommitOperation,
20
- } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
20
+ } from '@abloatai/transaction/commit';
21
21
  import type { DurableWriteStore } from './durableWriteStore.js';
22
22
 
23
23
  export interface CommitTransportContext {
@@ -39,7 +39,6 @@ export interface SealDurableCommitInput {
39
39
  sourceMutationIds?: string[];
40
40
  commitOptions?: {
41
41
  reads?: readonly ReadDependency[] | null;
42
- track?: readonly TrackDependency[] | null;
43
42
  };
44
43
  createdAt: number;
45
44
  sealedAt: number;
@@ -63,9 +62,6 @@ export async function sealDurableCommit(
63
62
  ...(input.commitOptions?.reads !== undefined
64
63
  ? { reads: input.commitOptions.reads === null ? null : [...input.commitOptions.reads] }
65
64
  : {}),
66
- ...(input.commitOptions?.track !== undefined
67
- ? { track: input.commitOptions.track === null ? null : [...input.commitOptions.track] }
68
- : {}),
69
65
  },
70
66
  ...(ctx.commitOutboxScope ? { scope: ctx.commitOutboxScope } : {}),
71
67
  createdAt: input.createdAt,
@@ -1,9 +1,9 @@
1
1
  import { AbloIdempotencyError, AbloValidationError } from '@abloatai/transaction/errors';
2
2
  import type { RuntimeContext } from '../../RuntimeContext.js';
3
3
  import type { CommitTransaction } from './commitLane.js';
4
- import type { DurableCommitEnvelope, CommitOutboxScope } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
4
+ import type { DurableCommitEnvelope, CommitOutboxScope } from '@abloatai/transaction/commit';
5
5
  import type { DurableWriteStore } from './durableWriteStore.js';
6
- import { durableCommitEnvelopeSchema } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
6
+ import { durableCommitEnvelopeSchema } from '@abloatai/transaction/commit';
7
7
 
8
8
  export interface DurableCommitRestoreContext {
9
9
  readonly config: { enablePersistence: boolean };
@@ -95,9 +95,6 @@ export async function restoreDurableCommits(ctx: DurableCommitRestoreContext): P
95
95
  ...(envelope.commitOptions.reads
96
96
  ? { reads: [...envelope.commitOptions.reads] }
97
97
  : {}),
98
- ...(envelope.commitOptions.track
99
- ? { track: [...envelope.commitOptions.track] }
100
- : {}),
101
98
  status: 'pending',
102
99
  createdAt: envelope.createdAt,
103
100
  sealedAt: envelope.sealedAt,
@@ -6,16 +6,16 @@
6
6
  *
7
7
  * The port and its config live in the core's `durableWrites` module (a behavior
8
8
  * contract, not a persisted shape); the records that cross it are owned by
9
- * `transactions/confirmation/pendingWrite`.
9
+ * `commit/confirmation/pendingWrite`.
10
10
  */
11
11
 
12
12
  export {
13
13
  durableWriteStoreSchema,
14
14
  durableWritesConfigSchema,
15
- } from '@abloatai/transaction/durableWrites';
15
+ } from '@abloatai/transaction/commit';
16
16
  export type {
17
17
  DurableWriteStore,
18
18
  DurableWritesConfig,
19
- } from '@abloatai/transaction/durableWrites';
20
- export { pendingWriteSchema } from '@abloatai/transaction/transactions/confirmation/pendingWrite';
21
- export type { PendingWrite } from '@abloatai/transaction/transactions/confirmation/pendingWrite';
19
+ } from '@abloatai/transaction/commit';
20
+ export { pendingWriteSchema } from '@abloatai/transaction/commit';
21
+ export type { PendingWrite } from '@abloatai/transaction/commit';
@@ -25,7 +25,7 @@ export function isDefinitiveRejection(error: Error): boolean {
25
25
  return status !== undefined && status >= 400 && status < 500 && status !== 429;
26
26
  }
27
27
 
28
- export interface ConflictPolicyContext {
28
+ export interface ConflictResolutionContext {
29
29
  readonly config: Pick<MutationQueueConfig, 'conflictResolution'>;
30
30
  readonly store: MutationStore;
31
31
  readonly rollbackOptimistic: (transaction: QueuedMutation, reason: string) => Promise<void>;
@@ -34,7 +34,7 @@ export interface ConflictPolicyContext {
34
34
  }
35
35
 
36
36
  export async function handleConflict(
37
- ctx: ConflictPolicyContext,
37
+ ctx: ConflictResolutionContext,
38
38
  transaction: QueuedMutation,
39
39
  serverData: MutationInput,
40
40
  ): Promise<void> {
@@ -1,7 +1,7 @@
1
1
  import type { RuntimeContext } from '../../RuntimeContext.js';
2
2
  import type { MutationPersistencePort } from '../../mutationPersistence.js';
3
3
  import type { MutationQueueConfig } from './MutationQueue.js';
4
- import type { CommitOutboxScope } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
4
+ import type { CommitOutboxScope } from '@abloatai/transaction/commit';
5
5
  import type { QueuedMutation } from './commitPayload.js';
6
6
  import { MutationStore } from './MutationStore.js';
7
7
  import { normalizeModelKey } from './commitPayload.js';
@@ -2,8 +2,8 @@ import type { RuntimeContext } from '../../RuntimeContext.js';
2
2
  import type { QueuedMutation } from './commitPayload.js';
3
3
  import type { MutationStore } from './MutationStore.js';
4
4
  import type { OptimisticUpdateEntry } from './localMutation.js';
5
- import type { MutationCommitResult } from '@abloatai/transaction/wire/commit';
6
- import type { DurableCommitEnvelope } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
5
+ import type { MutationCommitResult } from '@abloatai/transaction/commit';
6
+ import type { DurableCommitEnvelope } from '@abloatai/transaction/commit';
7
7
  import { applyWriteOptions, TX_TYPE_TO_MUTATION_OP } from './commitPayload.js';
8
8
 
9
9
  export interface PendingDrainContext {
@@ -23,14 +23,12 @@ import type { RuntimeContext } from '../../RuntimeContext.js';
23
23
  import {
24
24
  commitEnvelopeMemberSchema,
25
25
  commitOutboxScopeSchema,
26
- } from '@abloatai/transaction/transactions/confirmation/commitEnvelope';
27
- import { onStaleModeSchema } from '@abloatai/transaction/coordination/schema';
26
+ } from '@abloatai/transaction/commit';
28
27
 
29
28
  /** The subset of a write's options that is stored with each transaction or queued mutation. */
30
29
  const persistedWriteOptionsSchema = z
31
30
  .object({
32
31
  readAt: z.number().nullable().optional(),
33
- onStale: onStaleModeSchema.nullable().optional(),
34
32
  idempotencyKey: z.string().optional(),
35
33
  label: z.string().optional(),
36
34
  // Aligned with the `WriteOptions` type: a claimed write persisted locally
@@ -1,5 +1,3 @@
1
- import type { OnStaleMode } from '@abloatai/transaction/coordination/schema';
2
-
3
1
  type ModelData = Record<string, unknown>;
4
2
 
5
3
  /** One mutation retained in the durable local transaction journal. */
@@ -10,7 +8,6 @@ interface PersistedMutation {
10
8
  timestamp: string;
11
9
  writeOptions?: {
12
10
  readAt?: number | null;
13
- onStale?: OnStaleMode | null;
14
11
  };
15
12
  }
16
13
 
package/src/plugin.ts CHANGED
@@ -19,9 +19,9 @@ import type { ParticipantKind } from '@abloatai/transaction/types/participant';
19
19
  import type { ErrorCodeSpec } from '@abloatai/transaction/errorCodes';
20
20
  import type { Logger } from '@abloatai/transaction/logger';
21
21
  import type { CoordinationObservability } from '@abloatai/transaction/observability';
22
- import type { WsTransport } from '@abloatai/transaction/transport/wsTransport';
22
+ import type { WsTransport } from '@abloatai/transaction/transport/websocket';
23
23
  import type { AuthCredentialSource } from '@abloatai/transaction/auth/credentialSource';
24
- import type { SyncDeltaWireCore } from '@abloatai/transaction/wire/delta';
24
+ import type { SyncDeltaWireCore } from '@abloatai/transaction/observation';
25
25
  import type { ModelData } from '@abloatai/transaction/types/modelData';
26
26
 
27
27
  /**
@@ -23,8 +23,8 @@
23
23
  * `leave`.
24
24
  */
25
25
 
26
- import type { WsTransport } from '@abloatai/transaction/transport/wsTransport';
27
- import type { PresenceUpdate } from '@abloatai/transaction/transport/wsTransport';
26
+ import type { WsTransport } from '@abloatai/transaction/transport/websocket';
27
+ import type { PresenceUpdate } from '@abloatai/transaction/transport/websocket';
28
28
  import type {
29
29
  Activity,
30
30
  Peer,
@@ -36,7 +36,7 @@ import {
36
36
  type UseAbloModelResult,
37
37
  } from './useAblo.js';
38
38
  import type { AbloClient as Ablo } from '../client.js';
39
- import type { ModelOperations } from '../local/client/createModelProxy.js';
39
+ import type { ModelOperations } from '../local/client/createModelOperations.js';
40
40
  import type { Schema, SchemaRecord } from '@abloatai/transaction/schema/schema';
41
41
 
42
42
  /** What a binding returns: the provider and the hook, with `S` fixed. */
@@ -7,7 +7,7 @@ import type { ModelClaim } from '@abloatai/transaction/coordination';
7
7
  import {
8
8
  getModelClientMeta,
9
9
  type ModelOperations,
10
- } from '../local/client/createModelProxy.js';
10
+ } from '../local/client/createModelOperations.js';
11
11
  import { Model } from '../local/Model.js';
12
12
  import type { SchemaRecord } from '@abloatai/transaction/schema/schema';
13
13
  import type { ResolveSchema } from '@abloatai/transaction/types/global';
@@ -138,7 +138,7 @@ function snapshotValue<T>(value: T): T {
138
138
  * // With the Register augmentation (recommended):
139
139
  * const ablo = useAblo();
140
140
  * if (!ablo) return <Loading />;
141
- * const doc = await ablo.records.get({ id }); // async server read
141
+ * const doc = await ablo.records.get({ id }); // observational async server read
142
142
  *
143
143
  * // Reactive selector (a synchronous local snapshot). The selector's reads
144
144
  * // are typed as snapshot rows — data fields + computeds, no relation
package/src/surface.ts CHANGED
@@ -14,7 +14,7 @@
14
14
  * written by hand, since prose cannot be type-checked.
15
15
  */
16
16
 
17
- import type { ModelOperations, LocalReadOptions } from './local/client/createModelProxy.js';
17
+ import type { ModelOperations, LocalReadOptions } from './local/client/createModelOperations.js';
18
18
  import type { AbloOptions } from './Ablo.js';
19
19
 
20
20
  // ── compile-time exact-equality (no runtime, no casts) ─────────────────────
@@ -33,7 +33,7 @@ type Expect<T extends true> = T;
33
33
  */
34
34
  export const PUBLIC_MODEL_VERBS = [
35
35
  'get',
36
- 'retrieve',
36
+ 'read',
37
37
  'list',
38
38
  'listAll',
39
39
  'local',
@@ -41,7 +41,6 @@ export const PUBLIC_MODEL_VERBS = [
41
41
  'update',
42
42
  'delete',
43
43
  'claim',
44
- 'track',
45
44
  'join',
46
45
  'onChange',
47
46
  ] as const;
@@ -1,29 +0,0 @@
1
- /**
2
- * Captures a local {@link Snapshot} of a chosen set of entities, along with a
3
- * watermark, so a caller can detect when that state has gone stale. This is
4
- * what an LLM caller threads into a prompt: `stamp` flows into later writes as
5
- * `readAt`, so the server rejects a mutation premised on data that has since
6
- * changed; `signal` is an `AbortSignal` that fires as soon as any captured
7
- * entity receives a delta, so a mid-generation invalidation can abort the token
8
- * stream instead of producing output against stale context.
9
- *
10
- * It reads the current entity state from the in-memory pool, reads the engine's
11
- * current `lastSyncId` as the watermark, and subscribes to delta frames on the
12
- * existing sync connection — no second connection.
13
- */
14
- import type { InstanceCache } from '../InstanceCache.js';
15
- import type { Schema } from '@abloatai/transaction/schema/schema';
16
- import type { SyncWebSocket } from './SyncWebSocket.js';
17
- import type { Snapshot } from '@abloatai/transaction/types/streams';
18
- export interface CreateSnapshotArgs<TSchema extends Schema = Schema, K extends keyof TSchema['models'] & string = keyof TSchema['models'] & string> {
19
- pool: InstanceCache;
20
- /** Live transport for delta subscriptions. May be null if the engine
21
- * hasn't connected yet — the snapshot still resolves with current
22
- * pool state, but `signal` won't fire until reconnect. */
23
- transport: SyncWebSocket | null;
24
- /** Returns the engine's current `lastSyncId`. Read at snapshot time
25
- * to stamp the watermark; not re-read after. */
26
- getLastSyncId: () => number;
27
- entities: Readonly<Record<K, string | readonly string[]>>;
28
- }
29
- export declare function createSnapshot<TSchema extends Schema, K extends keyof TSchema['models'] & string>(args: CreateSnapshotArgs<TSchema, K>): Snapshot<TSchema, K>;
@@ -1,116 +0,0 @@
1
- /**
2
- * Captures a local {@link Snapshot} of a chosen set of entities, along with a
3
- * watermark, so a caller can detect when that state has gone stale. This is
4
- * what an LLM caller threads into a prompt: `stamp` flows into later writes as
5
- * `readAt`, so the server rejects a mutation premised on data that has since
6
- * changed; `signal` is an `AbortSignal` that fires as soon as any captured
7
- * entity receives a delta, so a mid-generation invalidation can abort the token
8
- * stream instead of producing output against stale context.
9
- *
10
- * It reads the current entity state from the in-memory pool, reads the engine's
11
- * current `lastSyncId` as the watermark, and subscribes to delta frames on the
12
- * existing sync connection — no second connection.
13
- */
14
- import { AbloValidationError } from '@abloatai/transaction/errors';
15
- import { modelAsRow } from '../Model.js';
16
- /**
17
- * The snapshot result exposes `stamp`, `signal`, and `onChange` at its top
18
- * level, alongside one bucket per model. If a schema declares a model with one
19
- * of these names, the two would collide, so snapshot creation throws instead.
20
- */
21
- const RESERVED_SNAPSHOT_KEYS = new Set([
22
- 'stamp',
23
- 'signal',
24
- 'onChange',
25
- ]);
26
- export function createSnapshot(args) {
27
- const { pool, transport, getLastSyncId, entities } = args;
28
- // ── Validate keys ────────────────────────────────────────────────
29
- for (const key of Object.keys(entities)) {
30
- if (RESERVED_SNAPSHOT_KEYS.has(key)) {
31
- throw new AbloValidationError(`engine.snapshot: model key "${key}" collides with a reserved ` +
32
- `snapshot field (stamp / signal / onChange). Rename the model ` +
33
- 'in your schema.', { code: 'snapshot_reserved_key' });
34
- }
35
- }
36
- // ── Watermark ────────────────────────────────────────────────────
37
- const stamp = getLastSyncId();
38
- // ── Capture data + watched set ───────────────────────────────────
39
- const watched = new Set(); // `${type}:${id}`
40
- const data = {};
41
- for (const [type, idOrIds] of Object.entries(entities)) {
42
- const ids = Array.isArray(idOrIds)
43
- ? idOrIds
44
- : [idOrIds];
45
- const bucket = {};
46
- for (const id of ids) {
47
- const m = pool.get(id);
48
- // Only include if the model actually has the requested type —
49
- // pool keys models globally by id, so `pool.get(id)` could
50
- // return a different model that happens to share the id (rare,
51
- // but type guards keep the surface honest).
52
- if (m &&
53
- typeof m.getModelName === 'function' &&
54
- m.getModelName() === type) {
55
- bucket[id] = modelAsRow(m);
56
- }
57
- watched.add(`${type}:${id}`);
58
- }
59
- data[type] = bucket;
60
- }
61
- // ── Invalidation wiring ──────────────────────────────────────────
62
- const listeners = new Set();
63
- const controller = new AbortController();
64
- const fireChange = (change) => {
65
- if (!controller.signal.aborted) {
66
- controller.abort(new Error('snapshot invalidated — underlying entity received a delta'));
67
- }
68
- for (const l of listeners) {
69
- try {
70
- l(change);
71
- }
72
- catch {
73
- /* listener errors don't break siblings */
74
- }
75
- }
76
- };
77
- let unsubDelta = null;
78
- if (transport) {
79
- unsubDelta = transport.subscribe('delta', (delta) => {
80
- const key = `${delta.modelName}:${delta.modelId}`;
81
- if (!watched.has(key))
82
- return;
83
- // Every delta to a captured entity is reported as 'semantic' severity.
84
- fireChange({
85
- model: delta.modelName,
86
- id: delta.modelId,
87
- severity: 'semantic',
88
- });
89
- });
90
- }
91
- // ── Build the flat result ────────────────────────────────────────
92
- const result = {
93
- stamp,
94
- signal: controller.signal,
95
- onChange: (listener) => {
96
- listeners.add(listener);
97
- // The caller unsubscribes its own listener via the returned function.
98
- // The underlying delta subscription lives for the snapshot's lifetime;
99
- // there is no explicit dispose because a snapshot is short-lived (one
100
- // LLM call's worth) and the subscription is cheap.
101
- return () => {
102
- listeners.delete(listener);
103
- // Once the last listener is gone and the abort has fired, drop the
104
- // delta subscription too — nothing is listening anymore.
105
- if (listeners.size === 0 && controller.signal.aborted && unsubDelta) {
106
- unsubDelta();
107
- unsubDelta = null;
108
- }
109
- };
110
- },
111
- };
112
- for (const [modelName, bucket] of Object.entries(data)) {
113
- result[modelName] = bucket;
114
- }
115
- return result;
116
- }