@gonvex/client 0.1.18 → 0.1.20

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
@@ -66,6 +66,42 @@ await client.clearQueryCache({ allScopes: true });
66
66
  Dexie is loaded asynchronously only after a cache-capable session is confirmed,
67
67
  so IndexedDB setup does not delay the WebSocket query path.
68
68
 
69
+ ## Durable Sync Collections
70
+
71
+ Sync functions materialize bounded, authorized single-table collections in a
72
+ normalized IndexedDB store and resume them from a durable Postgres cursor:
73
+
74
+ ```ts
75
+ const watch = client.watchSync<Task>(
76
+ { kind: "sync", path: "tasks.recent" },
77
+ { workspaceId: "workspace-a" },
78
+ );
79
+
80
+ const stop = watch.onUpdate(() => {
81
+ render(watch.localSyncResult() ?? []);
82
+ console.log(watch.status()); // { isLoading, isUpToDate }
83
+ });
84
+ ```
85
+
86
+ Configure or disable the sync store when constructing the client:
87
+
88
+ ```ts
89
+ const client = new GonvexClient(url, {
90
+ sync: {
91
+ databaseName: "my-product-sync",
92
+ maxBytes: 150 * 1024 * 1024,
93
+ },
94
+ });
95
+
96
+ const memoryOnly = new GonvexClient(url, { sync: false });
97
+ ```
98
+
99
+ The default global IndexedDB budget is 100 MiB. Server-declared per-collection
100
+ row/byte budgets still apply, and least-recently-used collections are evicted
101
+ first. Storage is isolated by runtime, project, tenant, authenticated identity,
102
+ and permissions. Sync is not an offline write queue; mutations and actions
103
+ retain the fail-closed policy below.
104
+
69
105
  ## Lightweight Error Tracking
70
106
 
71
107
  Capture global browser failures and failed Gonvex operations with the same
@@ -145,6 +181,7 @@ The package exports:
145
181
  - `ConvexReactClient` compatibility alias
146
182
  - `GonvexClientError`, `ConnectionState`, timeout defaults
147
183
  - transparent persistent query caching and lower-level experimental cache helpers
184
+ - `subscribeSync`, `watchSync`, and normalized persistent sync storage
148
185
  - browser capability and telemetry helpers
149
186
  - `GonvexErrorReporter` and automatic operation error reporting
150
187
 
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { BrowserTelemetryInfo, JsonValue, MessageTrace, ServerMessage } from "@gonvex/protocol";
1
+ import type { BrowserTelemetryInfo, JsonValue, MessageTrace, ServerCapabilities, ServerMessage } from "@gonvex/protocol";
2
2
  import { type QueryCacheOptions, type QueryCacheStatus } from "./query-cache.js";
3
3
  import { type SyncStoreOptions } from "./sync-store.js";
4
4
  import { type ErrorReporterOptions } from "./error-reporter.js";
@@ -84,6 +84,11 @@ export type GonvexClientOptions = GonvexClientAuth & {
84
84
  * Defaults to 250ms; set a longer bounded window for local-first apps.
85
85
  */
86
86
  querySubscriptionRetentionMs?: number;
87
+ /**
88
+ * Keep listenerless durable syncs open briefly across React remounts.
89
+ * Defaults to 250ms, preventing close/open/snapshot churn in StrictMode.
90
+ */
91
+ syncSubscriptionRetentionMs?: number;
87
92
  sync?: false | SyncStoreOptions;
88
93
  errorReporting?: false | Omit<ErrorReporterOptions, "endpoint" | "project" | "tenant">;
89
94
  timeouts?: GonvexTimeoutOptions;
@@ -111,18 +116,24 @@ export declare class GonvexClient {
111
116
  private readonly telemetryHandlers;
112
117
  private readonly pendingMessages;
113
118
  private readonly pendingSyncOpens;
119
+ private readonly pendingQuerySubscribes;
120
+ private readonly syncPersistence;
114
121
  private syncOpenFlushTimer;
122
+ private querySubscribeFlushTimer;
115
123
  private serverCapabilities;
116
124
  private auth;
117
125
  private authInFlight;
126
+ private authWatchdogTimer;
118
127
  private telemetryEnabled;
119
128
  private readonly queryCache;
120
129
  private readonly queryCacheWaitForScope;
121
130
  private readonly queryCacheReadTimeoutMs;
122
131
  private readonly querySubscriptionRetentionMs;
132
+ private readonly syncSubscriptionRetentionMs;
123
133
  private readonly syncStore;
124
134
  private queryCacheDirective;
125
135
  private queryCacheGeneration;
136
+ private syncScopeGeneration;
126
137
  private queryCacheNegotiatedSocketGeneration;
127
138
  private syncIdentityGeneration;
128
139
  private readonly sessionScopeHandlers;
@@ -139,6 +150,8 @@ export declare class GonvexClient {
139
150
  private readonly timeouts;
140
151
  constructor(url: string, options?: GonvexClientOptions);
141
152
  connectionState(): ConnectionState;
153
+ /** Metadata advertised by the runtime in its latest session.ready frame. */
154
+ serverInfo(): Readonly<ServerCapabilities>;
142
155
  subscribeToConnectionState(handler: ConnectionStateHandler): () => void;
143
156
  private notifyConnectionState;
144
157
  setAuth(auth: GonvexClientAuth): void;
@@ -168,7 +181,9 @@ export declare class GonvexClient {
168
181
  onUpdate(handler: WatchUpdateHandler): () => void;
169
182
  };
170
183
  private handleSyncMessage;
184
+ private acceptSyncReady;
171
185
  private emitSyncMessage;
186
+ private markSyncSubscriptionsOutOfDate;
172
187
  private startSync;
173
188
  private sendSyncOpen;
174
189
  private syncOpenRequest;
@@ -185,9 +200,28 @@ export declare class GonvexClient {
185
200
  * nothing is subscribed to this query.
186
201
  */
187
202
  retryQuery(ref: FunctionReference, args?: JsonValue): void;
203
+ /**
204
+ * Flush a queue of mutations in one `mutation.callMany` frame (queue order,
205
+ * one websocket round trip). Each entry settles independently — a failed
206
+ * call does not reject the batch — so offline queues can apply per-row
207
+ * outcomes. Falls back to sequential `mutation` calls on runtimes that do
208
+ * not advertise the `mutationBatch` capability.
209
+ */
210
+ mutationMany<T = JsonValue>(calls: Array<{
211
+ ref: FunctionReference;
212
+ args?: JsonValue;
213
+ }>, options?: CallOptions): Promise<Array<{
214
+ status: "ok";
215
+ result: T;
216
+ } | {
217
+ status: "error";
218
+ error: GonvexClientError;
219
+ }>>;
188
220
  private call;
221
+ private registerCall;
189
222
  private unsubscribeQueryListener;
190
223
  private sendSubscription;
224
+ private flushQuerySubscribes;
191
225
  private resumeQuerySubscriptions;
192
226
  private enqueueSyncPersistence;
193
227
  private scheduleSyncRetry;
@@ -199,6 +233,8 @@ export declare class GonvexClient {
199
233
  private installQueryCacheDirective;
200
234
  private recoverWarmSyncDirective;
201
235
  private resetQueryCacheScope;
236
+ private resetQueryResultCacheState;
237
+ private resetSyncCacheState;
202
238
  private startQueryCacheRead;
203
239
  private persistQueryResult;
204
240
  private deleteCachedQuery;
@@ -207,6 +243,7 @@ export declare class GonvexClient {
207
243
  private emitTelemetry;
208
244
  private reportTelemetry;
209
245
  private sendAuth;
246
+ private armAuthWatchdog;
210
247
  private send;
211
248
  private sendNow;
212
249
  private flushPendingMessages;