@gonvex/client 0.1.24 → 0.1.26
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/dist/index.d.ts +100 -2
- package/dist/index.js +318 -16
- package/dist/index.js.map +1 -1
- package/dist/optimistic.d.ts +41 -0
- package/dist/optimistic.js +98 -0
- package/dist/optimistic.js.map +1 -0
- package/dist/outbox.d.ts +86 -0
- package/dist/outbox.js +324 -0
- package/dist/outbox.js.map +1 -0
- package/dist/signals.d.ts +20 -0
- package/dist/signals.js +259 -0
- package/dist/signals.js.map +1 -0
- package/dist/sync-store.d.ts +5 -0
- package/dist/sync-store.js +4 -0
- package/dist/sync-store.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { BrowserTelemetryInfo, JsonValue, MessageTrace, ServerCapabilities,
|
|
|
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";
|
|
5
|
+
import { OptimisticOverlay, type OptimisticPatch } from "./optimistic.js";
|
|
5
6
|
export * from "./cache.js";
|
|
6
7
|
export * from "./cache-coordinator.js";
|
|
7
8
|
export * from "./browser-cache.js";
|
|
@@ -12,8 +13,21 @@ export * from "./persistent-cache.js";
|
|
|
12
13
|
export * from "./query-cache.js";
|
|
13
14
|
export * from "./sync-store.js";
|
|
14
15
|
export * from "./error-reporter.js";
|
|
16
|
+
export * from "./optimistic.js";
|
|
17
|
+
export * from "./outbox.js";
|
|
18
|
+
export * from "./signals.js";
|
|
15
19
|
export type { QueryCacheDirective } from "@gonvex/protocol";
|
|
16
20
|
type SubscriptionHandler = (message: ServerMessage) => void;
|
|
21
|
+
export type SyncReadyMessage = Extract<ServerMessage, {
|
|
22
|
+
type: "sync.ready";
|
|
23
|
+
}> & {
|
|
24
|
+
/** True when the server cut this collection at its row or byte budget. */
|
|
25
|
+
truncated?: boolean;
|
|
26
|
+
};
|
|
27
|
+
export type SyncMessage = Extract<ServerMessage, {
|
|
28
|
+
type: "sync.snapshot" | "sync.delta" | "sync.needHashes" | "sync.syncing" | "sync.reset" | "sync.error";
|
|
29
|
+
}> | SyncReadyMessage;
|
|
30
|
+
export type SyncSubscriptionHandler = (message: SyncMessage) => void;
|
|
17
31
|
type WatchUpdateHandler = () => void;
|
|
18
32
|
type TelemetryHandler = (event: GonvexTelemetryEvent) => void;
|
|
19
33
|
type ConnectionStateHandler = (state: ConnectionState) => void;
|
|
@@ -31,7 +45,7 @@ export type GonvexClientErrorCode = "server" | "timeout" | "disconnected" | "clo
|
|
|
31
45
|
* - `timeout`: no response arrived within the operation timeout. For
|
|
32
46
|
* mutations/actions the write may or may not have been applied.
|
|
33
47
|
* - `disconnected`: the socket dropped while the operation was pending.
|
|
34
|
-
* Mutations/actions fail closed
|
|
48
|
+
* Mutations/actions fail closed unless a mutation opted into the outbox.
|
|
35
49
|
* - `closed`: the client was explicitly closed.
|
|
36
50
|
* - `auth`: authentication was rejected.
|
|
37
51
|
*/
|
|
@@ -69,12 +83,50 @@ export declare const DEFAULT_ACTION_TIMEOUT_MS = 60000;
|
|
|
69
83
|
export type CallOptions = {
|
|
70
84
|
/** Per-call override of the operation timeout. `0` disables. */
|
|
71
85
|
timeoutMs?: number;
|
|
86
|
+
/** Ordered row changes to expose until the mutation settles. */
|
|
87
|
+
optimistic?: OptimisticPatch[];
|
|
88
|
+
/** Queue transport failures durably instead of rejecting. Default `reject`. */
|
|
89
|
+
offline?: "queue" | "reject";
|
|
90
|
+
};
|
|
91
|
+
/** Returned when an offline mutation has been accepted by the local outbox. */
|
|
92
|
+
export type QueuedMutationOutcome = {
|
|
93
|
+
status: "queued";
|
|
94
|
+
mutationId: string;
|
|
72
95
|
};
|
|
96
|
+
export type GonvexAuthTokenFetcher = (args: {
|
|
97
|
+
/** True when the server just rejected the current token — bypass any cache. */
|
|
98
|
+
forceRefreshToken: boolean;
|
|
99
|
+
}) => Promise<string | null | undefined>;
|
|
73
100
|
export type GonvexClientAuth = {
|
|
74
101
|
project?: string;
|
|
75
102
|
token?: string;
|
|
76
103
|
tenant?: string;
|
|
77
104
|
telemetry?: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Async source of the auth token, mirroring Convex's `fetchToken` contract.
|
|
107
|
+
* When installed, the client re-fetches before every auth send — on first
|
|
108
|
+
* connect, on every reconnect, and once more with `forceRefreshToken: true`
|
|
109
|
+
* when the server rejects the current token — so a socket that outlives a
|
|
110
|
+
* short-lived JWT (e.g. an ~1h Firebase ID token) reauthenticates with a
|
|
111
|
+
* live credential instead of replaying the expired one. A `token` passed in
|
|
112
|
+
* the same `setAuth` call is trusted and sent as-is; resolving `null` signs
|
|
113
|
+
* the session out; a rejected fetch keeps the currently installed token so
|
|
114
|
+
* an offline start is not signed out.
|
|
115
|
+
*/
|
|
116
|
+
fetchToken?: GonvexAuthTokenFetcher;
|
|
117
|
+
/**
|
|
118
|
+
* Non-secret identity hint ({@link https://datatracker.ietf.org/doc/html/rfc7519 JWT}
|
|
119
|
+
* `sub` and `iss` claims) that stands in for a token when deriving the local
|
|
120
|
+
* cache identity. Lets a cold start with no usable token — e.g. an offline
|
|
121
|
+
* tab whose identity provider cannot refresh — recover the warm query-cache
|
|
122
|
+
* directive and serve cached reads. Never sent to the server; a parseable
|
|
123
|
+
* token always takes precedence, and both must derive the same key for the
|
|
124
|
+
* same user (persist the claims of the last token you installed).
|
|
125
|
+
*/
|
|
126
|
+
identity?: {
|
|
127
|
+
sub: string;
|
|
128
|
+
iss?: string;
|
|
129
|
+
};
|
|
78
130
|
};
|
|
79
131
|
export type GonvexClientOptions = GonvexClientAuth & {
|
|
80
132
|
queryCache?: false | QueryCacheOptions;
|
|
@@ -90,6 +142,14 @@ export type GonvexClientOptions = GonvexClientAuth & {
|
|
|
90
142
|
*/
|
|
91
143
|
syncSubscriptionRetentionMs?: number;
|
|
92
144
|
sync?: false | SyncStoreOptions;
|
|
145
|
+
/**
|
|
146
|
+
* Durable mutation queue settings. Every replay keeps its original
|
|
147
|
+
* idempotency key, making an accidental cross-tab double-send server-safe.
|
|
148
|
+
*/
|
|
149
|
+
outbox?: {
|
|
150
|
+
databaseName?: string;
|
|
151
|
+
enabled?: boolean;
|
|
152
|
+
};
|
|
93
153
|
errorReporting?: false | Omit<ErrorReporterOptions, "endpoint" | "project" | "tenant">;
|
|
94
154
|
timeouts?: GonvexTimeoutOptions;
|
|
95
155
|
};
|
|
@@ -124,6 +184,9 @@ export declare class GonvexClient {
|
|
|
124
184
|
private auth;
|
|
125
185
|
private authInFlight;
|
|
126
186
|
private authWatchdogTimer;
|
|
187
|
+
private authFetchGeneration;
|
|
188
|
+
private authRetriedAfterError;
|
|
189
|
+
private readonly authErrorHandlers;
|
|
127
190
|
private telemetryEnabled;
|
|
128
191
|
private readonly queryCache;
|
|
129
192
|
private readonly queryCacheWaitForScope;
|
|
@@ -131,6 +194,14 @@ export declare class GonvexClient {
|
|
|
131
194
|
private readonly querySubscriptionRetentionMs;
|
|
132
195
|
private readonly syncSubscriptionRetentionMs;
|
|
133
196
|
private readonly syncStore;
|
|
197
|
+
private readonly mutationOutbox;
|
|
198
|
+
private readonly overlay;
|
|
199
|
+
private readonly optimisticMutationIds;
|
|
200
|
+
private readonly outboxReady;
|
|
201
|
+
private readonly unsubscribeOutbox;
|
|
202
|
+
private readonly unsubscribeOverlay;
|
|
203
|
+
private drainingOutbox;
|
|
204
|
+
private outboxDrainTimer;
|
|
134
205
|
private queryCacheDirective;
|
|
135
206
|
private queryCacheGeneration;
|
|
136
207
|
private syncScopeGeneration;
|
|
@@ -149,12 +220,24 @@ export declare class GonvexClient {
|
|
|
149
220
|
private connectionCount;
|
|
150
221
|
private readonly timeouts;
|
|
151
222
|
constructor(url: string, options?: GonvexClientOptions);
|
|
223
|
+
/** The client's materialized optimistic state for pending-row indicators. */
|
|
224
|
+
get optimisticOverlay(): OptimisticOverlay;
|
|
225
|
+
/** Number of mutations waiting for a definitive server result. */
|
|
226
|
+
outboxCount(): Promise<number>;
|
|
152
227
|
connectionState(): ConnectionState;
|
|
153
228
|
/** Metadata advertised by the runtime in its latest session.ready frame. */
|
|
154
229
|
serverInfo(): Readonly<ServerCapabilities>;
|
|
155
230
|
subscribeToConnectionState(handler: ConnectionStateHandler): () => void;
|
|
156
231
|
private notifyConnectionState;
|
|
157
232
|
setAuth(auth: GonvexClientAuth): void;
|
|
233
|
+
/**
|
|
234
|
+
* Subscribe to unrecoverable auth rejections: the server refused the
|
|
235
|
+
* credentials and, when a token fetcher is installed, a force-refreshed
|
|
236
|
+
* token did not fix it. Lets apps route to sign-in instead of silently
|
|
237
|
+
* degrading to an unauthenticated session.
|
|
238
|
+
*/
|
|
239
|
+
onAuthError(handler: (error: string) => void): () => void;
|
|
240
|
+
private applyAuth;
|
|
158
241
|
connect(): void;
|
|
159
242
|
close(): void;
|
|
160
243
|
private rejectPendingCalls;
|
|
@@ -171,7 +254,7 @@ export declare class GonvexClient {
|
|
|
171
254
|
localQueryResult(): T | undefined;
|
|
172
255
|
onUpdate(handler: WatchUpdateHandler): () => void;
|
|
173
256
|
};
|
|
174
|
-
subscribeSync(ref: FunctionReference, args: JsonValue | undefined, onMessage:
|
|
257
|
+
subscribeSync(ref: FunctionReference, args: JsonValue | undefined, onMessage: SyncSubscriptionHandler): () => void;
|
|
175
258
|
watchSync<T extends JsonValue = JsonValue>(ref: FunctionReference, args?: JsonValue): {
|
|
176
259
|
localSyncResult(): T[] | undefined;
|
|
177
260
|
status(): {
|
|
@@ -183,6 +266,8 @@ export declare class GonvexClient {
|
|
|
183
266
|
private handleSyncMessage;
|
|
184
267
|
private acceptSyncReady;
|
|
185
268
|
private emitSyncMessage;
|
|
269
|
+
private materializeSyncMessage;
|
|
270
|
+
private emitOptimisticCollection;
|
|
186
271
|
private markSyncSubscriptionsOutOfDate;
|
|
187
272
|
private startSync;
|
|
188
273
|
private sendSyncOpen;
|
|
@@ -191,6 +276,15 @@ export declare class GonvexClient {
|
|
|
191
276
|
private unsubscribeSyncListener;
|
|
192
277
|
private persistSyncSnapshot;
|
|
193
278
|
private persistSyncDelta;
|
|
279
|
+
private restoreOutbox;
|
|
280
|
+
private addOptimisticMutation;
|
|
281
|
+
private settleOptimisticMutation;
|
|
282
|
+
private rejectOptimisticMutation;
|
|
283
|
+
private drainOutbox;
|
|
284
|
+
private scheduleOutboxDrain;
|
|
285
|
+
mutation<T = JsonValue>(ref: FunctionReference, args: JsonValue, options: CallOptions & {
|
|
286
|
+
offline: "queue";
|
|
287
|
+
}): Promise<T | QueuedMutationOutcome>;
|
|
194
288
|
mutation<T = JsonValue>(ref: FunctionReference, args?: JsonValue, options?: CallOptions): Promise<T>;
|
|
195
289
|
action<T = JsonValue>(ref: FunctionReference, args?: JsonValue, options?: CallOptions): Promise<T>;
|
|
196
290
|
query<T = JsonValue>(ref: FunctionReference, args?: JsonValue, options?: CallOptions): Promise<T>;
|
|
@@ -243,6 +337,10 @@ export declare class GonvexClient {
|
|
|
243
337
|
private emitTelemetry;
|
|
244
338
|
private reportTelemetry;
|
|
245
339
|
private sendAuth;
|
|
340
|
+
private sendAuthFrame;
|
|
341
|
+
private fetchAndSendAuth;
|
|
342
|
+
private refreshRejectedAuth;
|
|
343
|
+
private notifyAuthError;
|
|
246
344
|
private armAuthWatchdog;
|
|
247
345
|
private send;
|
|
248
346
|
private sendNow;
|