@syncular/client 0.30.16 → 0.32.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.
package/README.md CHANGED
@@ -284,7 +284,7 @@ stable code-like values (`A-Z`, `a-z`, `0-9`, dot, underscore, dash).
284
284
  During Vite development, retain the React client resource only while its
285
285
  captured generated schema version and published Syncular runtime identity both
286
286
  match. The
287
- [schema-and-runtime-aware Vite guide](https://syncular.dev/guide-vite/) uses
287
+ [schema-and-runtime-aware Vite guide](https://syncular.dev/platform-web-install/#configure-vite) uses
288
288
  `retainViteSyncClientResource` to close the old worker before constructing a
289
289
  schema-bump or package-upgrade replacement; hot-reloading query code alone does
290
290
  not migrate the worker-owned database.
@@ -404,6 +404,26 @@ current version and links the replacement through `superseded`. Edit can choose
404
404
  a free unique key. Take-server uses `resolved_keep_server`. Revocation and local
405
405
  security purge erase the retained aggregate's protected journal payloads.
406
406
 
407
+ ## Push batching limits
408
+
409
+ `limits` carries three per-request push budgets:
410
+
411
+ - `maxPushCommitsPerRequest`: whole commits per request. Default: unbounded.
412
+ - `maxPushOperationsPerRequest`: operations across those commits. Default:
413
+ 500.
414
+ - `maxPushRequestBytes`: bytes of the complete encoded SSP2 request, including
415
+ the request header, pull header, subscriptions, framing, and E2EE ciphertext.
416
+ Default: unbounded.
417
+
418
+ The client sends whole commits in FIFO order and never splits one. A later
419
+ commit that does not fit defers with the complete suffix. A first commit over
420
+ the operation or byte budget fails with `client.push_request_too_large`
421
+ (non-retryable) and details `{ kind, limit, size, clientCommitId? }`; the
422
+ commit stays queued with its optimistic rows. A request whose fixed frames
423
+ alone exceed the byte budget reports the same code without `clientCommitId`.
424
+ Push limits are integers in `1..=4294967295`; a JSON `null` at the native
425
+ command boundary is treated as omitted.
426
+
407
427
  ## Application-authorized local security purge
408
428
 
409
429
  `purgeLocalData({ purgeId, targets })` is the narrow local-storage primitive
package/dist/client.d.ts CHANGED
@@ -87,6 +87,14 @@ export interface SyncSummary {
87
87
  * queued; sync-needed stays raised and `syncUntilIdle` keeps going. */
88
88
  readonly deferredCommits?: number;
89
89
  }
90
+ /**
91
+ * The result of `syncUntilIdle`. The report aggregates every round that ran;
92
+ * `budgetExhausted` is true when the round budget ran out with the client not
93
+ * idle. An exhausted run is a partial success, never idle.
94
+ */
95
+ export interface SyncIdleResult extends SyncSummary {
96
+ readonly budgetExhausted: boolean;
97
+ }
90
98
  export interface SyncClientLimits {
91
99
  readonly limitCommits?: number;
92
100
  readonly limitSnapshotRows?: number;
@@ -103,6 +111,22 @@ export interface SyncClientLimits {
103
111
  * deleted to satisfy this cap. Defaults to 1,000.
104
112
  */
105
113
  readonly outcomeRetentionMaxEntries?: number;
114
+ /** §7.1: maximum whole commits in one push request. Default: unbounded. */
115
+ readonly maxPushCommitsPerRequest?: number;
116
+ /**
117
+ * §7.1: maximum operations across the push commits in one request. Default
118
+ * 500. A first commit that alone exceeds it is a typed
119
+ * `client.push_request_too_large` capacity error and stays queued.
120
+ */
121
+ readonly maxPushOperationsPerRequest?: number;
122
+ /**
123
+ * §7.1: maximum bytes of the complete encoded SSP2 request (8-byte
124
+ * envelope, request header, push commits, pull header, subscriptions,
125
+ * framing, and any §5.11 ciphertext). Default: unbounded. A request whose
126
+ * fixed frames alone exceed it, or whose first commit alone does not fit,
127
+ * raises `client.push_request_too_large` and stays queued.
128
+ */
129
+ readonly maxPushRequestBytes?: number;
106
130
  }
107
131
  export interface SyncClientConfig {
108
132
  readonly transportEnabled?: boolean;
@@ -276,6 +300,69 @@ export interface QuerySnapshot<Row = SqlRow> {
276
300
  readonly rows: readonly Row[];
277
301
  readonly coverage: CoverageSnapshot;
278
302
  }
303
+ /** §7.5: one read-only statement in an atomic snapshot read. */
304
+ export interface SnapshotStatement {
305
+ readonly sql: string;
306
+ readonly params?: readonly SqlValue[];
307
+ }
308
+ /**
309
+ * §7.5: the catch-up state of one subscription as persisted in the snapshot,
310
+ * never the mutable owner cache. `unknown` means the client does not currently
311
+ * hold the subscription (never registered, forgotten, or removed) and carries
312
+ * no fabricated table or cursor.
313
+ */
314
+ export type SubscriptionCatchup = {
315
+ readonly state: 'unknown';
316
+ readonly id: string;
317
+ } | {
318
+ readonly state: 'known';
319
+ readonly id: string;
320
+ readonly table: string;
321
+ readonly status: 'active' | 'revoked' | 'failed';
322
+ readonly cursor: number;
323
+ readonly hasResumeToken: boolean;
324
+ /** True only for `active` with `cursor >= 0` and no resume token. */
325
+ readonly bootstrapComplete: boolean;
326
+ /** True only for `active` while a resume token remains or `cursor < 0`. */
327
+ readonly knownPendingPages: boolean;
328
+ readonly effectiveScopes?: unknown;
329
+ readonly reasonCode?: string;
330
+ };
331
+ /**
332
+ * §7.5: delivery status for one client commit id. `pending` while the id still
333
+ * has an outbox entry (outbox precedence), otherwise the persisted-journal
334
+ * outcome, otherwise an explicit `unknown` (never held, or pruned by
335
+ * retention). The outcome omits the owner-derived `retainedRows` images.
336
+ */
337
+ export type CommitDelivery = {
338
+ readonly status: 'pending';
339
+ readonly clientCommitId: string;
340
+ } | {
341
+ readonly status: 'known';
342
+ readonly clientCommitId: string;
343
+ readonly outcome: CommitOutcome;
344
+ } | {
345
+ readonly status: 'unknown';
346
+ readonly clientCommitId: string;
347
+ };
348
+ /** §7.5: one atomic read request over a single SQLite read transaction. */
349
+ export interface SnapshotReadRequest {
350
+ readonly statements: readonly SnapshotStatement[];
351
+ readonly coverage?: readonly WindowCoverage[];
352
+ readonly subscriptions?: readonly string[];
353
+ readonly commitIds?: readonly string[];
354
+ /** §7.5 owner: a failed owned read is reported in `queryFailures`. */
355
+ readonly owner?: QueryOwner;
356
+ }
357
+ /** §7.5: one atomic read result: one revision, every statement's rows, the
358
+ * requested coverage, catch-up states, and deliveries. */
359
+ export interface SnapshotRead<Row = SqlRow> {
360
+ readonly revision: LocalRevision;
361
+ readonly queries: readonly (readonly Row[])[];
362
+ readonly coverage: CoverageSnapshot;
363
+ readonly subscriptions: readonly SubscriptionCatchup[];
364
+ readonly deliveries: readonly CommitDelivery[];
365
+ }
279
366
  /**
280
367
  * True iff `unit` is windowed-in AND its bootstrap completed (§4.8 I3):
281
368
  * registered and not pending. A unit with zero server rows still becomes
@@ -283,7 +370,7 @@ export interface QuerySnapshot<Row = SqlRow> {
283
370
  */
284
371
  export declare function windowComplete(state: WindowState, unit: string): boolean;
285
372
  /** Canonical client reads, shared by synchronous cores and promise hosts. */
286
- export type ClientSnapshotMethods = Pick<SyncClient, 'querySnapshot' | 'statusSnapshot' | 'diagnosticsSnapshot' | 'conflicts' | 'rejections' | 'commitOutcome' | 'commitOutcomes' | 'resolveCommitOutcome'>;
373
+ export type ClientSnapshotMethods = Pick<SyncClient, 'querySnapshot' | 'snapshotRead' | 'statusSnapshot' | 'diagnosticsSnapshot' | 'conflicts' | 'rejections' | 'commitOutcome' | 'commitOutcomes' | 'resolveCommitOutcome'>;
287
374
  /** Project a method contract across an asynchronous host boundary. */
288
375
  export type PromiseMethods<Methods> = {
289
376
  [Key in keyof Methods]: Methods[Key] extends (...args: infer Args) => infer Result ? (...args: Args) => Promise<Awaited<Result>> : never;
@@ -336,6 +423,19 @@ export declare class SyncClient {
336
423
  * `windowState()` across separate worker/IPC calls.
337
424
  */
338
425
  querySnapshot<Row = SqlRow>(spec: QueryReadSpec): QuerySnapshot<Row>;
426
+ /**
427
+ * §7.5: resolve several read-only statements, window coverage, subscription
428
+ * catch-up states, and commit deliveries from one SQLite read transaction
429
+ * and one revision. A host that needs those together reads them together;
430
+ * every statement passes the read-only guard and any failure rolls the whole
431
+ * read back.
432
+ */
433
+ snapshotRead<Row = SqlRow>(spec: SnapshotReadRequest): SnapshotRead<Row>;
434
+ /** §7.5: one subscription's persisted catch-up state (never the owner cache). */
435
+ subscriptionCatchup(id: string): SubscriptionCatchup;
436
+ /** §7.5: one client commit's delivery status: pending, its retained outcome,
437
+ * or an explicit unknown (never held, or pruned by retention). */
438
+ commitDelivery(id: string): CommitDelivery;
339
439
  /**
340
440
  * RFC 0005 D7: read captured rows from the previous local schema. `state` is
341
441
  * always `'previousVersion'`; the container never makes `querySnapshot()`
@@ -540,7 +640,7 @@ export declare class SyncClient {
540
640
  * Pull repeatedly until quiescent: no commits delivered, no bootstrap
541
641
  * pages pending, no resets to recover (§4.5 "pull again" SHOULD).
542
642
  */
543
- syncUntilIdle(maxRounds?: number): Promise<SyncSummary>;
643
+ syncUntilIdle(maxRounds?: number): Promise<SyncIdleResult>;
544
644
  connectRealtime(): Promise<void>;
545
645
  disconnectRealtime(): void;
546
646
  }