@abloatai/ablo 0.24.0 → 0.26.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 (246) hide show
  1. package/AGENTS.md +5 -3
  2. package/CHANGELOG.md +33 -0
  3. package/README.md +45 -36
  4. package/dist/BaseSyncedStore.d.ts +72 -195
  5. package/dist/BaseSyncedStore.js +240 -625
  6. package/dist/Database.d.ts +8 -9
  7. package/dist/Database.js +9 -14
  8. package/dist/LazyReferenceCollection.js +5 -0
  9. package/dist/Model.js +6 -8
  10. package/dist/ModelRegistry.d.ts +25 -6
  11. package/dist/ModelRegistry.js +12 -6
  12. package/dist/NetworkMonitor.js +1 -1
  13. package/dist/ObjectPool.js +9 -3
  14. package/dist/SyncClient.d.ts +15 -5
  15. package/dist/SyncClient.js +152 -66
  16. package/dist/SyncEngineContext.d.ts +1 -3
  17. package/dist/SyncEngineContext.js +1 -2
  18. package/dist/agent/Agent.d.ts +21 -8
  19. package/dist/agent/Agent.js +26 -13
  20. package/dist/ai-sdk/coordination-context.js +9 -3
  21. package/dist/ai-sdk/wrap.d.ts +1 -1
  22. package/dist/ai-sdk/wrap.js +1 -1
  23. package/dist/auth/credentialPolicy.d.ts +10 -2
  24. package/dist/auth/credentialSource.d.ts +1 -13
  25. package/dist/auth/credentialSource.js +6 -13
  26. package/dist/auth/index.js +3 -3
  27. package/dist/cli.cjs +583 -287
  28. package/dist/client/Ablo.d.ts +35 -764
  29. package/dist/client/Ablo.js +64 -688
  30. package/dist/client/ApiClient.d.ts +14 -1
  31. package/dist/client/ApiClient.js +63 -9
  32. package/dist/client/auth.d.ts +8 -17
  33. package/dist/client/auth.js +42 -6
  34. package/dist/client/consoleLogger.d.ts +36 -0
  35. package/dist/client/consoleLogger.js +45 -0
  36. package/dist/client/createInternalComponents.js +1 -1
  37. package/dist/client/createModelProxy.js +10 -6
  38. package/dist/client/credentialEndpoint.d.ts +63 -0
  39. package/dist/client/credentialEndpoint.js +87 -0
  40. package/dist/client/hostedEndpoints.d.ts +24 -0
  41. package/dist/client/hostedEndpoints.js +24 -0
  42. package/dist/client/httpClient.d.ts +1 -1
  43. package/dist/client/identity.js +2 -1
  44. package/dist/client/modelRegistration.d.ts +14 -0
  45. package/dist/client/modelRegistration.js +321 -0
  46. package/dist/client/options.d.ts +396 -0
  47. package/dist/client/options.js +10 -0
  48. package/dist/client/resourceTypes.d.ts +344 -0
  49. package/dist/client/resourceTypes.js +13 -0
  50. package/dist/client/schemaConfig.d.ts +56 -0
  51. package/dist/client/schemaConfig.js +188 -0
  52. package/dist/client/sessionMint.d.ts +1 -1
  53. package/dist/client/validateAbloOptions.js +1 -1
  54. package/dist/client/wsMutationExecutor.d.ts +33 -0
  55. package/dist/client/wsMutationExecutor.js +77 -0
  56. package/dist/context.js +0 -3
  57. package/dist/coordination/index.d.ts +8 -1
  58. package/dist/coordination/index.js +24 -1
  59. package/dist/coordination/trace.d.ts +0 -1
  60. package/dist/coordination/trace.js +0 -1
  61. package/dist/core/DatabaseManager.d.ts +0 -1
  62. package/dist/core/DatabaseManager.js +26 -24
  63. package/dist/core/QueryProcessor.js +7 -8
  64. package/dist/core/QueryView.d.ts +14 -2
  65. package/dist/core/QueryView.js +4 -5
  66. package/dist/core/StoreManager.d.ts +2 -2
  67. package/dist/core/StoreManager.js +5 -1
  68. package/dist/core/index.d.ts +1 -1
  69. package/dist/core/openIDBWithTimeout.js +15 -11
  70. package/dist/core/query-utils.js +1 -1
  71. package/dist/core/storeContract.d.ts +143 -0
  72. package/dist/core/storeContract.js +16 -0
  73. package/dist/errorCodes.d.ts +11 -2
  74. package/dist/errorCodes.js +155 -137
  75. package/dist/errors.d.ts +18 -7
  76. package/dist/errors.js +14 -1
  77. package/dist/index.js +5 -0
  78. package/dist/interfaces/index.d.ts +6 -20
  79. package/dist/keys/index.js +18 -9
  80. package/dist/mutators/UndoManager.js +6 -1
  81. package/dist/mutators/defineMutators.d.ts +1 -3
  82. package/dist/policy/types.d.ts +1 -1
  83. package/dist/query/client.d.ts +11 -0
  84. package/dist/query/client.js +81 -52
  85. package/dist/react/AbloProvider.d.ts +6 -10
  86. package/dist/react/AbloProvider.js +22 -15
  87. package/dist/react/context.d.ts +2 -118
  88. package/dist/react/useAblo.js +1 -1
  89. package/dist/react/useErrorListener.js +1 -1
  90. package/dist/react/useMutationFailureListener.js +1 -1
  91. package/dist/react/useMutators.js +7 -1
  92. package/dist/react/useReactive.js +0 -1
  93. package/dist/react/useUndoScope.js +2 -2
  94. package/dist/schema/ddlLock.d.ts +39 -0
  95. package/dist/schema/ddlLock.js +51 -0
  96. package/dist/schema/field.js +1 -1
  97. package/dist/schema/index.d.ts +4 -3
  98. package/dist/schema/index.js +15 -5
  99. package/dist/schema/model.d.ts +3 -3
  100. package/dist/schema/model.js +2 -2
  101. package/dist/schema/openapi.js +5 -1
  102. package/dist/schema/queries.d.ts +1 -1
  103. package/dist/schema/queries.js +1 -0
  104. package/dist/schema/residency.d.ts +35 -0
  105. package/dist/schema/residency.js +27 -0
  106. package/dist/schema/roles.d.ts +25 -0
  107. package/dist/schema/roles.js +37 -0
  108. package/dist/schema/schema.d.ts +3 -3
  109. package/dist/schema/schema.js +11 -7
  110. package/dist/schema/serialize.d.ts +8 -8
  111. package/dist/schema/sync-delta-row.d.ts +2 -2
  112. package/dist/schema/sync-delta-row.js +2 -2
  113. package/dist/server/storage-mode.d.ts +8 -1
  114. package/dist/server/storage-mode.js +14 -4
  115. package/dist/source/adapter.d.ts +1 -1
  116. package/dist/source/adapters/drizzle.js +4 -3
  117. package/dist/source/adapters/kysely.js +4 -3
  118. package/dist/source/adapters/memory.js +1 -1
  119. package/dist/source/adapters/prisma.js +5 -4
  120. package/dist/source/conformance.js +10 -8
  121. package/dist/source/connector.js +4 -2
  122. package/dist/source/factory.d.ts +106 -0
  123. package/dist/source/factory.js +273 -0
  124. package/dist/source/index.d.ts +11 -461
  125. package/dist/source/index.js +14 -416
  126. package/dist/source/next.d.ts +1 -1
  127. package/dist/source/next.js +1 -1
  128. package/dist/source/pushQueue.d.ts +1 -1
  129. package/dist/source/pushQueue.js +6 -3
  130. package/dist/source/signing.d.ts +59 -0
  131. package/dist/source/signing.js +142 -0
  132. package/dist/source/types.d.ts +334 -0
  133. package/dist/source/types.js +44 -0
  134. package/dist/stores/ObjectStore.d.ts +1 -1
  135. package/dist/stores/ObjectStore.js +23 -23
  136. package/dist/stores/SyncActionStore.d.ts +1 -1
  137. package/dist/stores/SyncActionStore.js +70 -35
  138. package/dist/surface.d.ts +1 -1
  139. package/dist/surface.js +1 -0
  140. package/dist/sync/AreaOfInterestManager.d.ts +2 -2
  141. package/dist/sync/AreaOfInterestManager.js +1 -1
  142. package/dist/sync/BootstrapHelper.d.ts +1 -3
  143. package/dist/sync/BootstrapHelper.js +29 -8
  144. package/dist/sync/ConnectionManager.d.ts +8 -0
  145. package/dist/sync/ConnectionManager.js +19 -4
  146. package/dist/sync/HydrationCoordinator.d.ts +12 -0
  147. package/dist/sync/HydrationCoordinator.js +25 -5
  148. package/dist/sync/NetworkProbe.d.ts +3 -2
  149. package/dist/sync/NetworkProbe.js +7 -6
  150. package/dist/sync/SyncWebSocket.d.ts +71 -120
  151. package/dist/sync/SyncWebSocket.js +324 -630
  152. package/dist/sync/awaitClaimGrant.js +27 -19
  153. package/dist/sync/bootstrapApply.d.ts +60 -0
  154. package/dist/sync/bootstrapApply.js +65 -0
  155. package/dist/sync/commitFrames.d.ts +43 -0
  156. package/dist/sync/commitFrames.js +94 -0
  157. package/dist/sync/createClaimStream.js +3 -2
  158. package/dist/sync/createSnapshot.d.ts +1 -3
  159. package/dist/sync/credentialLifecycle.d.ts +175 -0
  160. package/dist/sync/credentialLifecycle.js +329 -0
  161. package/dist/sync/deltaPipeline.d.ts +111 -0
  162. package/dist/sync/deltaPipeline.js +262 -0
  163. package/dist/sync/groupChange.d.ts +111 -0
  164. package/dist/sync/groupChange.js +246 -0
  165. package/dist/sync/heartbeat.d.ts +62 -0
  166. package/dist/sync/heartbeat.js +91 -0
  167. package/dist/sync/participants.d.ts +8 -8
  168. package/dist/sync/syncCursor.d.ts +44 -0
  169. package/dist/sync/syncCursor.js +59 -0
  170. package/dist/sync/syncPlan.d.ts +62 -0
  171. package/dist/sync/syncPlan.js +51 -0
  172. package/dist/sync/wsFrameHandlers.d.ts +117 -0
  173. package/dist/sync/wsFrameHandlers.js +378 -0
  174. package/dist/testing/fixtures/bootstrap.d.ts +9 -11
  175. package/dist/testing/fixtures/deltas.d.ts +1 -1
  176. package/dist/testing/fixtures/models.js +1 -0
  177. package/dist/testing/helpers/sync-engine-harness.d.ts +0 -3
  178. package/dist/testing/helpers/sync-engine-harness.js +2 -1
  179. package/dist/testing/index.d.ts +1 -1
  180. package/dist/testing/index.js +1 -1
  181. package/dist/testing/mocks/MockSyncContext.d.ts +1 -17
  182. package/dist/testing/mocks/MockSyncContext.js +1 -32
  183. package/dist/testing/mocks/MockSyncStore.d.ts +4 -4
  184. package/dist/testing/mocks/MockWebSocket.d.ts +2 -2
  185. package/dist/transactions/TransactionQueue.d.ts +20 -56
  186. package/dist/transactions/TransactionQueue.js +101 -487
  187. package/dist/transactions/TransactionStore.d.ts +18 -0
  188. package/dist/transactions/TransactionStore.js +51 -0
  189. package/dist/transactions/coalesceRules.d.ts +34 -0
  190. package/dist/transactions/coalesceRules.js +117 -0
  191. package/dist/transactions/commitPayload.d.ts +134 -0
  192. package/dist/transactions/commitPayload.js +152 -0
  193. package/dist/transactions/deltaConfirmation.d.ts +60 -0
  194. package/dist/transactions/deltaConfirmation.js +223 -0
  195. package/dist/transactions/optimistic.d.ts +24 -0
  196. package/dist/transactions/optimistic.js +45 -0
  197. package/dist/transactions/persistedReplay.d.ts +93 -0
  198. package/dist/transactions/persistedReplay.js +105 -0
  199. package/dist/types/index.d.ts +3 -3
  200. package/dist/types/index.js +0 -5
  201. package/dist/types/modelData.d.ts +12 -0
  202. package/dist/types/modelData.js +11 -0
  203. package/dist/types/participant.d.ts +21 -0
  204. package/dist/types/participant.js +12 -0
  205. package/dist/types/streams.d.ts +8 -14
  206. package/dist/utils/mobx-setup.d.ts +1 -1
  207. package/dist/utils/mobx-setup.js +2 -2
  208. package/dist/wire/errorEnvelope.d.ts +11 -2
  209. package/dist/wire/errorEnvelope.js +14 -2
  210. package/dist/wire/frames.d.ts +90 -0
  211. package/dist/wire/frames.js +55 -1
  212. package/dist/wire/index.d.ts +4 -1
  213. package/dist/wire/index.js +20 -1
  214. package/dist/wire/protocol.d.ts +45 -0
  215. package/dist/wire/protocol.js +45 -0
  216. package/dist/wire/protocolVersion.d.ts +56 -0
  217. package/dist/wire/protocolVersion.js +63 -0
  218. package/docs/api-keys.md +4 -3
  219. package/docs/data-sources.md +12 -5
  220. package/docs/examples/existing-python-backend.md +3 -3
  221. package/docs/identity.md +4 -4
  222. package/docs/integration-guide.md +1 -1
  223. package/docs/react.md +1 -1
  224. package/docs/sessions.md +5 -7
  225. package/llms.txt +4 -2
  226. package/package.json +15 -13
  227. package/dist/client/index.d.ts +0 -36
  228. package/dist/client/index.js +0 -33
  229. package/dist/config/index.d.ts +0 -10
  230. package/dist/config/index.js +0 -12
  231. package/dist/interfaces/headless.d.ts +0 -95
  232. package/dist/interfaces/headless.js +0 -41
  233. package/dist/query/index.d.ts +0 -6
  234. package/dist/query/index.js +0 -5
  235. package/dist/realtime/index.d.ts +0 -10
  236. package/dist/realtime/index.js +0 -9
  237. package/dist/schema/plane.d.ts +0 -23
  238. package/dist/schema/plane.js +0 -19
  239. package/dist/server/next.d.ts +0 -51
  240. package/dist/server/next.js +0 -47
  241. package/dist/sync/OfflineFlush.d.ts +0 -9
  242. package/dist/sync/OfflineFlush.js +0 -22
  243. package/dist/sync/OfflineTransactionStore.d.ts +0 -37
  244. package/dist/sync/OfflineTransactionStore.js +0 -263
  245. package/dist/transactions/index.d.ts +0 -16
  246. package/dist/transactions/index.js +0 -7
@@ -9,17 +9,10 @@
9
9
  */
10
10
  import { EventEmitter } from 'events';
11
11
  import type { MutationOperation } from '../interfaces/index.js';
12
- import type { ClientSyncDelta } from '../schema/sync-delta-wire.js';
12
+ import { type ClientSyncDelta } from '../schema/sync-delta-wire.js';
13
13
  import type { ClaimError, ClaimRejection, StaleNotification, ReadDependency } from '../coordination/schema.js';
14
- /**
15
- * Resolution value of a commit ack. `notifications` is present only when a
16
- * guarded write (`onStale: 'notify') hit a concurrent change — the
17
- * advisory self-heal signal, surfaced both here and via `conflict:notified`.
18
- */
19
- export interface CommitAck {
20
- lastSyncId: number;
21
- notifications?: StaleNotification[];
22
- }
14
+ import { type CommitAck } from './commitFrames.js';
15
+ export type { CommitAck } from './commitFrames.js';
23
16
  import { type AuthTokenGetter } from '../auth/credentialSource.js';
24
17
  /**
25
18
  * The wire delta the client receives. Derived from the canonical
@@ -57,18 +50,6 @@ export interface GroupRemovedPayload {
57
50
  group: string;
58
51
  userId: string;
59
52
  }
60
- export interface VersionVector {
61
- tasks: number;
62
- projects: number;
63
- users: number;
64
- events: number;
65
- inboxitems: number;
66
- teams: number;
67
- assignments: number;
68
- comments: number;
69
- threads: number;
70
- [entityType: string]: number;
71
- }
72
53
  export interface SyncCapabilities {
73
54
  partialBootstrap?: boolean;
74
55
  compressedDeltas?: boolean;
@@ -83,7 +64,6 @@ export interface SyncWebSocketOptions {
83
64
  organizationId: string;
84
65
  lastSyncId?: number;
85
66
  syncGroups?: string[];
86
- versions?: VersionVector;
87
67
  capabilities?: SyncCapabilities;
88
68
  reconnectDelay?: number;
89
69
  maxReconnectDelay?: number;
@@ -181,7 +161,7 @@ export interface PresenceUpdateEvent {
181
161
  /** Server stamps every presence frame with this participant's open
182
162
  * claims so peers see them without a separate channel. Wire
183
163
  * shape mirrors `apps/sync-server/src/hub/types.ts Claim`. */
184
- activeClaims?: Array<{
164
+ activeClaims?: {
185
165
  claimId: string;
186
166
  entityType: string;
187
167
  entityId: string;
@@ -205,7 +185,7 @@ export interface PresenceUpdateEvent {
205
185
  */
206
186
  status?: 'active' | 'committed' | 'expired' | 'canceled';
207
187
  error?: ClaimError;
208
- }>;
188
+ }[];
209
189
  localTime?: string;
210
190
  type?: string;
211
191
  timezone?: string;
@@ -335,20 +315,12 @@ export declare class SyncWebSocket<TCollaboration extends EventMap<TCollaboratio
335
315
  /** Periodic catchup interval — polls for missed deltas every 30s while connected */
336
316
  private catchupInterval;
337
317
  /**
338
- * Application-level heartbeat. The browser WebSocket API hides RFC 6455
339
- * protocol-level ping/pong from JavaScript, so the server's `ws.ping()`
340
- * keepalive can't be observed by client code meaning the client cannot
341
- * tell a healthy idle connection apart from a "zombie" socket where TCP
342
- * silently broke (laptop sleep, NAT timeout, mobile handoff). We send an
343
- * application-level `{ type: 'ping' }` every 30s and force-close the
344
- * socket if no inbound traffic arrives within 10s. ANY inbound message
345
- * counts as proof-of-life — the explicit `pong` is just a guarantee that
346
- * something will arrive even on an idle stream.
347
- */
348
- private heartbeatTimer;
349
- private heartbeatTimeoutTimer;
350
- private static readonly HEARTBEAT_INTERVAL_MS;
351
- private static readonly HEARTBEAT_TIMEOUT_MS;
318
+ * Application-level heartbeat ping every 30s, force-close on a 10s
319
+ * silent watchdog. The full zombie-socket rationale lives with the
320
+ * timers in `sync/heartbeat.ts`; the transport closures below are the
321
+ * only socket access the controller gets.
322
+ */
323
+ private readonly heartbeat;
352
324
  private isConnecting;
353
325
  private isManualClose;
354
326
  /** When true, a session error has been detected (from any path — WS close or HTTP bootstrap).
@@ -376,11 +348,23 @@ export declare class SyncWebSocket<TCollaboration extends EventMap<TCollaboratio
376
348
  private lastCloseReason;
377
349
  private lastForceCloseReason;
378
350
  private sessionErrorAt;
379
- private lastSyncId;
380
- private versionVector;
381
- private syncCursor;
351
+ /**
352
+ * Sync-position state (lastSyncId watermark, version vector, server
353
+ * cursor). The advance discipline stays documented at `sendAck` /
354
+ * `handleDelta`; the state itself lives in `sync/syncCursor.ts`.
355
+ */
356
+ private readonly cursor;
382
357
  /** Registered collaboration event keys (colon format) for dispatch in onmessage */
383
358
  private collaborationEventTypes;
359
+ /**
360
+ * Minimal session adapter handed to the frame dispatch table
361
+ * (`sync/wsFrameHandlers.ts`). Exposes ONLY the members the handlers
362
+ * touch; the closure members read live state so host-side reassignment
363
+ * (e.g. the `pendingSubscriptions` reset on close) can't strand the
364
+ * handlers on a stale reference. Built in the constructor, after the
365
+ * state it captures exists.
366
+ */
367
+ private readonly frameSession;
384
368
  /**
385
369
  * In-flight `commit` mutation requests keyed by clientTxId. Resolved when
386
370
  * a matching `mutation_result` frame arrives from the server, or rejected on
@@ -410,6 +394,14 @@ export declare class SyncWebSocket<TCollaboration extends EventMap<TCollaboratio
410
394
  * Suppresses further reconnection attempts and Sentry error capture.
411
395
  */
412
396
  setSessionErrorDetected(): void;
397
+ /**
398
+ * Clear the session-error latch so `connect()` / `scheduleReconnect()`
399
+ * work again. Called by the store's access-credential recovery path when
400
+ * the close was a re-mintable `ek_`/`rk_` expiry (`4001 credential_expired`),
401
+ * not a login loss — see `isAccessCredentialExpiryCloseReason`. Genuine
402
+ * session losses never clear the latch; re-auth builds a fresh client.
403
+ */
404
+ clearSessionError(): void;
413
405
  /**
414
406
  * Connect to the sync engine WebSocket
415
407
  */
@@ -419,26 +411,39 @@ export declare class SyncWebSocket<TCollaboration extends EventMap<TCollaboratio
419
411
  */
420
412
  private setupEventHandlers;
421
413
  /**
422
- * Normalize a wire delta at the receive boundary. The contract
423
- * (`syncDeltaWireCoreSchema`) says `id: number`, but deployed servers
424
- * have sent the raw Postgres BIGINT serialization a STRING — and
425
- * every downstream watermark gate (`typeof syncId === 'number'` in
426
- * `Database.processDeltaBatch`, the metadata-cursor update, numeric
427
- * `>=` threshold comparisons in TransactionQueue) silently breaks on
428
- * strings: acks are withheld, the resume cursor never advances, and
429
- * every reconnect replays from 0 (or force-bootstraps once the gap
430
- * exceeds maxDeltaGapForPartial). Coerce ONCE here so the rest of the
431
- * client can trust the declared type — and old servers stay compatible.
414
+ * Validate + normalize a wire delta at the receive boundary the ONE
415
+ * seam every inbound delta (`delta` frame, batch element, `sync_response`
416
+ * replay, legacy bare frame) passes through before it is emitted,
417
+ * persisted to IDB, or allowed to advance any watermark.
418
+ *
419
+ * Normalization (older/deployed servers stay compatible):
420
+ * - `id`: the contract says `number`, but deployed servers have sent the
421
+ * raw Postgres BIGINT serialization a STRING and every downstream
422
+ * watermark gate (`typeof syncId === 'number'` in
423
+ * `Database.processDeltaBatch`, the metadata-cursor update, numeric
424
+ * `>=` thresholds in TransactionQueue) silently breaks on strings:
425
+ * acks are withheld, the resume cursor never advances, and every
426
+ * reconnect replays from 0. Coerce ONCE here.
427
+ * - `transactionId` / `createdBy`: the SERVER projection sends these as
428
+ * nullable (and `createdBy` as a nested ParticipantRef); the client
429
+ * contract types them as optional strings and never reads them.
430
+ * Normalize to absent instead of rejecting every real server delta.
431
+ *
432
+ * Validation: `clientSyncDeltaSchema.safeParse` — the canonical Zod wire
433
+ * contract. A frame that fails is DROPPED (returns `null`) with a
434
+ * debug-level log + observability breadcrumb; it is never applied. One
435
+ * parse per delta — callers must not re-parse.
432
436
  */
433
437
  private normalizeWireDelta;
434
438
  /**
435
- * Handle incoming sync delta
439
+ * Handle incoming sync delta (untrusted wire input — validated and
440
+ * normalized by {@link normalizeWireDelta}; malformed deltas are dropped).
436
441
  */
437
442
  private handleDelta;
438
443
  /**
439
444
  * Send acknowledgment for received delta with version vector.
440
445
  *
441
- * This is the SOLE forward-mover of `this.lastSyncId` for live
446
+ * This is the SOLE forward-mover of `this.cursor.lastSyncId` for live
442
447
  * deltas. Called by `BaseSyncedStore.flushPendingDeltas` with the
443
448
  * `persistedSyncId` watermark — i.e. only after the deltas have
444
449
  * actually committed to IDB. Keeping the cursor advance here (rather
@@ -455,16 +460,6 @@ export declare class SyncWebSocket<TCollaboration extends EventMap<TCollaboratio
455
460
  * Send message to server
456
461
  */
457
462
  send(message: any): void;
458
- /**
459
- * Project the SDK's `MutationOperation[]` onto the canonical wire
460
- * `CommitMessage`. This is the single serialize boundary between the SDK op
461
- * type (loose `type: string`, plus an SDK-internal `options` the server never
462
- * reads) and the strict wire contract. The per-field map gives compile-time
463
- * drift detection (a `CommitOperation` shape change breaks here) and the lone
464
- * `as` narrows the validated op `type` to the wire union — the only
465
- * loosening, localized to this boundary.
466
- */
467
- private buildCommitFrame;
468
463
  /**
469
464
  * Send a `commit` mutation request over the existing WebSocket and
470
465
  * resolve when the server's `mutation_result` frame comes back with
@@ -484,22 +479,7 @@ export declare class SyncWebSocket<TCollaboration extends EventMap<TCollaboratio
484
479
  * NOT auto-retry here — the caller's TransactionQueue owns retry +
485
480
  * offline replay semantics and the SDK shouldn't duplicate that logic.
486
481
  */
487
- /**
488
- * Defensively validate the optional `notifications` array off a commit ack.
489
- * Untrusted wire data — a malformed entry is dropped rather than throwing,
490
- * so a bad notification never sinks an otherwise-successful commit.
491
- */
492
- private parseNotifications;
493
- /**
494
- * Single instrumentation point for claim events. Every `claim_*` frame routes
495
- * through here so a developer debugging a collision gets one consistent trace
496
- * — a console line AND a structured capture — without each dispatch case
497
- * re-deriving the row/holder shape. The wire payload is loosely typed
498
- * (`Record<string, unknown>`), so this is the one place that narrows it into
499
- * a {@link ClaimEvent}.
500
- */
501
- private recordClaim;
502
- sendCommit(operations: ReadonlyArray<MutationOperation>, clientTxId: string, timeoutMs?: number, causedByTaskId?: string | null, reads?: readonly ReadDependency[] | null): Promise<CommitAck>;
482
+ sendCommit(operations: readonly MutationOperation[], clientTxId: string, timeoutMs?: number, causedByTaskId?: string | null, reads?: readonly ReadDependency[] | null): Promise<CommitAck>;
503
483
  /**
504
484
  * Send a commit frame without waiting for `mutation_result`.
505
485
  *
@@ -508,7 +488,7 @@ export declare class SyncWebSocket<TCollaboration extends EventMap<TCollaboratio
508
488
  * eventual `mutation_result` frame is intentionally ignored by this
509
489
  * instance because no pending resolver is registered.
510
490
  */
511
- sendCommitQueued(operations: ReadonlyArray<MutationOperation>, clientTxId: string, causedByTaskId?: string | null, reads?: readonly ReadDependency[] | null): void;
491
+ sendCommitQueued(operations: readonly MutationOperation[], clientTxId: string, causedByTaskId?: string | null, reads?: readonly ReadDependency[] | null): void;
512
492
  /**
513
493
  * Activate a participant claim on this connection. Multiplexed
514
494
  * subscription pattern (Phoenix Channels / Pusher) — the same
@@ -526,7 +506,7 @@ export declare class SyncWebSocket<TCollaboration extends EventMap<TCollaboratio
526
506
  * `apps/sync-server/docs/PARTICIPANT_CLAIMS.md` for the migration
527
507
  * framing (Phase A.1).
528
508
  */
529
- sendClaim(claimId: string, syncGroups: ReadonlyArray<string>, options?: {
509
+ sendClaim(claimId: string, syncGroups: readonly string[], options?: {
530
510
  capabilityToken?: string;
531
511
  ttlSeconds?: number;
532
512
  timeoutMs?: number;
@@ -562,7 +542,7 @@ export declare class SyncWebSocket<TCollaboration extends EventMap<TCollaboratio
562
542
  * the read side and carries no capability token of its own; it's bounded
563
543
  * by the connection credential's grant.
564
544
  */
565
- updateSubscription(syncGroups: ReadonlyArray<string>, options?: {
545
+ updateSubscription(syncGroups: readonly string[], options?: {
566
546
  timeoutMs?: number;
567
547
  }): Promise<{
568
548
  syncGroups: string[];
@@ -584,15 +564,15 @@ export declare class SyncWebSocket<TCollaboration extends EventMap<TCollaboratio
584
564
  /**
585
565
  * Send spreadsheet selection presence
586
566
  */
587
- sendSheetSelection(sheetId: string, selectedCells: Array<{
567
+ sendSheetSelection(sheetId: string, selectedCells: {
588
568
  ref: string;
589
- }>): void;
569
+ }[]): void;
590
570
  /**
591
571
  * Send slide layer selection presence
592
572
  */
593
- sendSlideSelection(deckId: string, slideId: string, selectedLayers: Array<{
573
+ sendSlideSelection(deckId: string, slideId: string, selectedLayers: {
594
574
  layerId: string;
595
- }>): void;
575
+ }[]): void;
596
576
  /**
597
577
  * Send slide cursor position for real-time collaboration
598
578
  * Note: Throttling should be handled by the caller (e.g., useSlideCursorBroadcast hook)
@@ -628,26 +608,6 @@ export declare class SyncWebSocket<TCollaboration extends EventMap<TCollaboratio
628
608
  * Disconnect from WebSocket
629
609
  */
630
610
  disconnect(): void;
631
- /**
632
- * Application-level heartbeat. Every `HEARTBEAT_INTERVAL_MS` while
633
- * `OPEN`, send `{ type: 'ping' }` and arm a `HEARTBEAT_TIMEOUT_MS`
634
- * watchdog. Any inbound frame (handled in `onmessage`) clears the
635
- * watchdog. If the watchdog fires, we treat the connection as
636
- * zombie and force-close it — `onclose` then triggers the existing
637
- * reconnect path.
638
- *
639
- * Why both sides need this:
640
- * - The server sends RFC 6455 protocol pings via `ws.ping()` every
641
- * 30s. Browsers auto-respond with a pong but DO NOT expose either
642
- * frame to JavaScript, so the client is blind to its own keepalive.
643
- * - On a half-open TCP (laptop wake, NAT timeout, mobile handoff)
644
- * the browser may keep `readyState === OPEN` for minutes before
645
- * the OS surfaces the broken connection. App-level traffic is
646
- * the only signal we can observe.
647
- */
648
- private startHeartbeat;
649
- private stopHeartbeat;
650
- private clearHeartbeatTimeout;
651
611
  /**
652
612
  * Force-close the socket from the client side using a private 4xxx
653
613
  * code. Callers expect `onclose` to fire; that handler runs the
@@ -697,18 +657,6 @@ export declare class SyncWebSocket<TCollaboration extends EventMap<TCollaboratio
697
657
  * Update last sync ID (for persistence)
698
658
  */
699
659
  setLastSyncId(syncId: number): void;
700
- /**
701
- * Get current version vector
702
- */
703
- getVersionVector(): VersionVector;
704
- /**
705
- * Update version vector for specific entity type
706
- */
707
- updateVersionVector(entityType: string, version: number): void;
708
- /**
709
- * Set version vector (for initialization)
710
- */
711
- setVersionVector(versions: VersionVector): void;
712
660
  /**
713
661
  * Update sync cursor (for incremental sync)
714
662
  */
@@ -730,7 +678,10 @@ export declare class SyncWebSocket<TCollaboration extends EventMap<TCollaboratio
730
678
  */
731
679
  requestBootstrap(entities?: string[]): Promise<void>;
732
680
  /**
733
- * Handle sync response from server
681
+ * Handle sync response from server. Untrusted wire input — the envelope
682
+ * fields are narrowed defensively and every delta is validated through
683
+ * {@link normalizeWireDelta} (exactly once each; malformed ones drop out
684
+ * of the batch).
734
685
  */
735
686
  private handleSyncResponse;
736
687
  /**