@lunora/client 1.0.0-alpha.21 → 1.0.0-alpha.23
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/auth/index.d.mts +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/index.d.mts +249 -4
- package/dist/index.d.ts +249 -4
- package/dist/index.mjs +10 -4
- package/dist/packem_shared/ClientServiceWorker-C3PAFwy0.mjs +100 -0
- package/dist/packem_shared/{LunoraClient-kXpHNyaE.mjs → LunoraClient-BBCQjjbl.mjs} +382 -243
- package/dist/packem_shared/{OfflineQueue-GGYJRmhF.mjs → OfflineQueue-B4HUF7rt.mjs} +1 -1
- package/dist/packem_shared/SubscriptionRegistry-CxS_Inha.mjs +31 -0
- package/dist/packem_shared/TabCoordinator-BwRR8H06.mjs +222 -0
- package/dist/packem_shared/createClientQuery-CQ51bWAE.mjs +71 -0
- package/dist/packem_shared/createLocalStore-BtqUmOQA.mjs +2 -0
- package/dist/packem_shared/createReply-lI4tVS2w.mjs +36 -0
- package/dist/packem_shared/{createServerClient-DF-3mLmb.mjs → createServerClient-CTTAmvMx.mjs} +1 -1
- package/dist/packem_shared/createSnapshotPrecondition-CxQ1T4ZP.mjs +18 -0
- package/dist/packem_shared/httpStream-BJU-aflc.mjs +159 -0
- package/dist/packem_shared/{local-store-BveBeFEo.mjs → local-store-DIq-UWfD.mjs} +1 -1
- package/dist/packem_shared/{lunora-client.d-BYkEjCEJ.d.mts → lunora-client.d-JvtVpf8A.d.mts} +302 -18
- package/dist/packem_shared/{lunora-client.d-BYkEjCEJ.d.ts → lunora-client.d-JvtVpf8A.d.ts} +302 -18
- package/dist/packem_shared/{offline-queue-B9vfdSqp.mjs → offline-queue-CF4_Co5k.mjs} +29 -0
- package/dist/packem_shared/{preload.d-B-vyHnml.d.ts → preload.d-C4_d_l5v.d.ts} +1 -1
- package/dist/packem_shared/{preload.d-DrfuisCE.d.mts → preload.d-DKbjGN5O.d.mts} +1 -1
- package/dist/packem_shared/wire-key-Djie6aaR.mjs +266 -0
- package/dist/query/index.d.mts +2 -2
- package/dist/query/index.d.ts +2 -2
- package/dist/ssr/index.d.mts +3 -3
- package/dist/ssr/index.d.ts +3 -3
- package/dist/ssr/index.mjs +1 -1
- package/package.json +2 -2
- package/dist/packem_shared/SubscriptionRegistry-DjGKZsqq.mjs +0 -1
- package/dist/packem_shared/createLocalStore-jRoqmazl.mjs +0 -2
- package/dist/packem_shared/subscription-BjynOXCU.mjs +0 -68
package/dist/packem_shared/{lunora-client.d-BYkEjCEJ.d.mts → lunora-client.d-JvtVpf8A.d.mts}
RENAMED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
import { CronJobInfo, VectorIndexSummary, VectorQueryMatch, KvNamespaceSummary, KvKeyListResult, KvValueResult, AuthUser, AuthPage, AuthImpersonation, AuthCapabilities, AuthConfigInfo, AuthSession } from '@lunora/runtime';
|
|
2
2
|
/**
|
|
3
|
+
* Reactive key-value store for local-only client state.
|
|
4
|
+
*
|
|
5
|
+
* Unlike a server {@link SubscriptionState} (which tracks a live WS connection,
|
|
6
|
+
* an `acked` flag, `serverBase`, optimistic layers, and the full subscription
|
|
7
|
+
* machinery), a `ClientQueryRef` is purely local — no server round-trip, no
|
|
8
|
+
* WebSocket, no persistence. It exists so framework adapters can offer a
|
|
9
|
+
* `useClientQuery` hook whose values survive component remounts and are shared
|
|
10
|
+
* across every consumer of the same ref, with none of the ceremony or coupling
|
|
11
|
+
* of a dedicated context provider.
|
|
12
|
+
*
|
|
13
|
+
* The store lives inside `LunoraClient` (a private field) and is surfaced through
|
|
14
|
+
* `client.getClientQuery(ref)` / `setClientQuery(ref, value)` /
|
|
15
|
+
* `subscribeClientQuery(ref, callback)`.
|
|
16
|
+
*/
|
|
17
|
+
/** Opaque handle for a typed client-local query slot. */
|
|
18
|
+
interface ClientQueryRef<T = unknown> {
|
|
19
|
+
/** Default value when no value has been set explicitly. */
|
|
20
|
+
readonly defaultValue: T;
|
|
21
|
+
/** Stable identity for the slot. Must be unique within a client instance. */
|
|
22
|
+
readonly key: string;
|
|
23
|
+
}
|
|
24
|
+
/** A subscriber callback for value changes to a {@link ClientQueryRef}. */
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Create a typed {@link ClientQueryRef}. Call once per slot at module scope
|
|
28
|
+
* (or inside a component module) — the ref object is the stable identity.
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* // lunora/client-queries.ts
|
|
32
|
+
* import { createClientQuery } from "@lunora/client";
|
|
33
|
+
*
|
|
34
|
+
* export const sidebarOpen = createClientQuery("sidebarOpen", true);
|
|
35
|
+
* export const selectedMessageId = createClientQuery("selectedMessageId", undefined as string | undefined);
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
declare const createClientQuery: <T>(key: string, defaultValue: T) => ClientQueryRef<T>;
|
|
39
|
+
/**
|
|
3
40
|
* The machine-readable error codes a client can observe on a failed
|
|
4
41
|
* RPC/batch/subscription. Mirrors the server's `CODE_STATUS` keys
|
|
5
42
|
* (`@lunora/server`'s `error.ts`) by hand — the client is framework-neutral and
|
|
@@ -80,6 +117,55 @@ interface FunctionReference<Kind extends FunctionKind = FunctionKind, Args = unk
|
|
|
80
117
|
type ArgsOf<F> = F extends FunctionReference<infer _K, infer A, infer _R> ? A : never;
|
|
81
118
|
/** Extract the return type from a {@link FunctionReference}. */
|
|
82
119
|
type ReturnOf<F> = F extends FunctionReference<infer _K, infer _A, infer R> ? R : never;
|
|
120
|
+
/**
|
|
121
|
+
* Typed reference to an HTTP-SSE stream route (`httpRoute.<verb>(path).stream()`)
|
|
122
|
+
* emitted by `@lunora/codegen` as `httpStreams.<namespace>.<name>`.
|
|
123
|
+
*
|
|
124
|
+
* Distinct from {@link FunctionReference}: this is the **HTTP-SSE route stream**
|
|
125
|
+
* (opened with `fetch` + `ReadableStream` against the route's own URL), not the
|
|
126
|
+
* WS procedure stream (`kind: "stream"`). At runtime it carries the HTTP verb
|
|
127
|
+
* and the route path; the phantom marker carries the chunk / searchParams /
|
|
128
|
+
* params types so `httpStream` (and the framework hooks over it) infer the
|
|
129
|
+
* chunk type end-to-end.
|
|
130
|
+
* @experimental Reconnect/POST-body/wire-fidelity design questions are still open, so the shape may change.
|
|
131
|
+
*/
|
|
132
|
+
interface HttpStreamRef<Chunk = unknown, SearchParams = unknown, Params = unknown> {
|
|
133
|
+
/**
|
|
134
|
+
* Phantom marker carrying the `Chunk`/`SearchParams`/`Params` type
|
|
135
|
+
* parameters for inference. Never present at runtime; declared in a
|
|
136
|
+
* covariant (output) position so a concrete reference stays assignable to
|
|
137
|
+
* a widened one.
|
|
138
|
+
*/
|
|
139
|
+
readonly __lunoraHttpStream?: {
|
|
140
|
+
chunk: Chunk;
|
|
141
|
+
params: Params;
|
|
142
|
+
searchParams: SearchParams;
|
|
143
|
+
};
|
|
144
|
+
/** HTTP verb the route binds to (uppercased), e.g. `"GET"`. */
|
|
145
|
+
readonly method: string;
|
|
146
|
+
/** The route path as declared, e.g. `/api/tokens/:id` — `:name` segments are filled from `params`. */
|
|
147
|
+
readonly path: string;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* The call-side args of an HTTP-SSE stream route: `:name` path params plus URL query params.
|
|
151
|
+
* @experimental Part of the HTTP-SSE stream surface.
|
|
152
|
+
*/
|
|
153
|
+
interface HttpStreamCallArgs<SearchParams = unknown, Params = unknown> {
|
|
154
|
+
/** Values for the route path's `:name` segments. */
|
|
155
|
+
params?: Params;
|
|
156
|
+
/** URL query params, appended to the request URL (undefined entries are skipped). */
|
|
157
|
+
searchParams?: SearchParams;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Extract the chunk type from a {@link HttpStreamRef}.
|
|
161
|
+
* @experimental Part of the HTTP-SSE stream surface.
|
|
162
|
+
*/
|
|
163
|
+
type HttpStreamChunkOf<R> = R extends HttpStreamRef<infer Chunk, infer _S, infer _P> ? Chunk : never;
|
|
164
|
+
/**
|
|
165
|
+
* Extract the call-side args type from a {@link HttpStreamRef}.
|
|
166
|
+
* @experimental Part of the HTTP-SSE stream surface.
|
|
167
|
+
*/
|
|
168
|
+
type HttpStreamArgsOf<R> = R extends HttpStreamRef<infer _C, infer S, infer P> ? HttpStreamCallArgs<S, P> : never;
|
|
83
169
|
type Unsubscribe = () => void;
|
|
84
170
|
/**
|
|
85
171
|
* Serializable result of `preloadQuery`. Produced on the server during SSR,
|
|
@@ -272,6 +358,15 @@ interface QueryCacheAdapter {
|
|
|
272
358
|
/** Remove one cached query by key. */
|
|
273
359
|
remove: (key: string) => Promise<void>;
|
|
274
360
|
}
|
|
361
|
+
/**
|
|
362
|
+
* Resolves the WS `?token=` credential fresh at every (re)connect — the channel
|
|
363
|
+
* for short-lived tokens (e.g. the ephemeral admin sub-token the worker mints
|
|
364
|
+
* at `POST /_lunora/admin/ws-token`) instead of a static secret in the URL.
|
|
365
|
+
* May return the token synchronously or as a Promise; returning `undefined`
|
|
366
|
+
* connects without a token. A thrown error / rejected Promise fails that
|
|
367
|
+
* connect attempt, and the client retries with its normal reconnect backoff.
|
|
368
|
+
*/
|
|
369
|
+
type WsTokenProvider = () => Promise<string | undefined> | string | undefined;
|
|
275
370
|
interface LunoraClientOptions {
|
|
276
371
|
/**
|
|
277
372
|
* Base path the worker mounts better-auth at, used by the client's
|
|
@@ -308,6 +403,16 @@ interface LunoraClientOptions {
|
|
|
308
403
|
* Defaults to 10000 (10s); set to `0` (or negative) to disable.
|
|
309
404
|
*/
|
|
310
405
|
connectTimeoutMs?: number;
|
|
406
|
+
/**
|
|
407
|
+
* When `true`, tabs sharing the same origin coordinate via BroadcastChannel
|
|
408
|
+
* so only one tab (the "leader") opens WebSocket connections to the server.
|
|
409
|
+
* Follower tabs receive subscription data through the channel instead.
|
|
410
|
+
*
|
|
411
|
+
* Reduces simultaneous WS connections, bandwidth, and cross-tab state drift.
|
|
412
|
+
* Requires `BroadcastChannel` (browser-only); silently ignored otherwise.
|
|
413
|
+
* Defaults to `false`.
|
|
414
|
+
*/
|
|
415
|
+
crossTabSync?: boolean;
|
|
311
416
|
fetch?: typeof fetch;
|
|
312
417
|
/**
|
|
313
418
|
* Interval (ms) between keepalive pings sent on each open subscription
|
|
@@ -317,6 +422,15 @@ interface LunoraClientOptions {
|
|
|
317
422
|
* `0` (or a negative value) to disable the heartbeat entirely.
|
|
318
423
|
*/
|
|
319
424
|
heartbeatIntervalMs?: number;
|
|
425
|
+
/**
|
|
426
|
+
* When `true` and a `queryCache` is active, framework hooks (React, Vue, …)
|
|
427
|
+
* wait for the durable cache to finish hydrating before their first render
|
|
428
|
+
* with an enabled subscription, so users see cached data instead of an
|
|
429
|
+
* undefined flash before the socket round-trip. Defaults to `false`.
|
|
430
|
+
*
|
|
431
|
+
* Requires `queryCache` to be set (not `false`); silently ignored otherwise.
|
|
432
|
+
*/
|
|
433
|
+
hydrateOnStart?: boolean;
|
|
320
434
|
offlineQueue?: OfflineQueueOptions;
|
|
321
435
|
/**
|
|
322
436
|
* Durable outbox seam for offline writes. When supplied (the `@lunora/db`
|
|
@@ -365,15 +479,21 @@ interface LunoraClientOptions {
|
|
|
365
479
|
url: string;
|
|
366
480
|
WebSocket?: typeof WebSocket;
|
|
367
481
|
/**
|
|
368
|
-
*
|
|
369
|
-
* against `LUNORA_WS_BEARER` (to clear the upgrade gate) and/or
|
|
482
|
+
* Credential appended to the WebSocket URL as `?token=…`. The server matches
|
|
483
|
+
* it against `LUNORA_WS_BEARER` (to clear the upgrade gate) and/or
|
|
370
484
|
* `LUNORA_ADMIN_TOKEN` (to authorize `__lunora_admin__:*` subscriptions —
|
|
371
|
-
* what the studio
|
|
372
|
-
*
|
|
373
|
-
*
|
|
374
|
-
*
|
|
485
|
+
* what the studio supplies). Browsers can't set headers on the `WebSocket`
|
|
486
|
+
* constructor, so the query parameter is the only channel; it ends up in
|
|
487
|
+
* server logs and history, so prefer a short-lived rotating token in
|
|
488
|
+
* production over a static secret.
|
|
489
|
+
*
|
|
490
|
+
* Pass a {@link WsTokenProvider} function to resolve the token fresh at
|
|
491
|
+
* every (re)connect — the channel for short-lived credentials such as the
|
|
492
|
+
* ephemeral admin sub-token minted by `POST /_lunora/admin/ws-token`: the
|
|
493
|
+
* provider re-mints on each reconnect, including the one following a `4001`
|
|
494
|
+
* token-expired drop, so a static master token never has to ride the URL.
|
|
375
495
|
*/
|
|
376
|
-
wsToken?: string;
|
|
496
|
+
wsToken?: string | WsTokenProvider;
|
|
377
497
|
wsUrl?: string;
|
|
378
498
|
}
|
|
379
499
|
/** Wire envelope sent on `POST /_lunora/rpc`. */
|
|
@@ -941,9 +1061,10 @@ interface SubscriptionState {
|
|
|
941
1061
|
acked: boolean;
|
|
942
1062
|
readonly args: Record<string, unknown>;
|
|
943
1063
|
/**
|
|
944
|
-
* Stable-
|
|
945
|
-
* optimistic-update fan-out can compare against a
|
|
946
|
-
* re-serializing every subscription's args on
|
|
1064
|
+
* Stable wire-key of `args` (`stableWireKey`), computed once at subscribe
|
|
1065
|
+
* time. Cached so the optimistic-update fan-out can compare against a
|
|
1066
|
+
* mutation's args key without re-serializing every subscription's args on
|
|
1067
|
+
* every mutation.
|
|
947
1068
|
*/
|
|
948
1069
|
readonly argsKey: string;
|
|
949
1070
|
readonly callbacks: Set<SubscriptionCallback>;
|
|
@@ -1012,11 +1133,13 @@ interface SubscriptionState {
|
|
|
1012
1133
|
}
|
|
1013
1134
|
/**
|
|
1014
1135
|
* Active subscription registry. The client keys subscriptions by
|
|
1015
|
-
* `(functionPath,
|
|
1136
|
+
* `(functionPath, stableWireKey(args), shardKey)` so duplicate calls share a
|
|
1016
1137
|
* single server-side registration. Args are stably encoded (keys sorted at every
|
|
1017
1138
|
* depth) so two structurally-equal arg records constructed with a different key
|
|
1018
1139
|
* order (`{ a, b }` vs `{ b, a }`) collapse to the same key instead of leaking a
|
|
1019
|
-
* duplicate subscription.
|
|
1140
|
+
* duplicate subscription. Encoding the args' **wire form** keeps the key
|
|
1141
|
+
* byte-identical for pure-JSON args while giving wire-typed args (`bigint`,
|
|
1142
|
+
* `Date`, bytes, …) distinct stable tokens instead of a throw.
|
|
1020
1143
|
*/
|
|
1021
1144
|
declare class SubscriptionRegistry {
|
|
1022
1145
|
static key(functionPath: string, args: Record<string, unknown>, shardKey?: string): string;
|
|
@@ -1178,6 +1301,14 @@ interface MutationCallOptions<TCurrent = unknown, TValue = unknown, TArgs = unkn
|
|
|
1178
1301
|
* once; every write is rolled back atomically if the mutation fails.
|
|
1179
1302
|
*/
|
|
1180
1303
|
optimisticUpdate?: OptimisticUpdate<TArgs>;
|
|
1304
|
+
/**
|
|
1305
|
+
* Sync predicate evaluated just before the offline queue replays this
|
|
1306
|
+
* write on reconnect. When it returns `false` the mutation is dropped
|
|
1307
|
+
* instead of replayed — use it to guard against replaying writes whose
|
|
1308
|
+
* assumptions are no longer valid (e.g. the document it referred to was
|
|
1309
|
+
* deleted by another client while this tab was offline).
|
|
1310
|
+
*/
|
|
1311
|
+
precondition?: () => boolean;
|
|
1181
1312
|
shardKey?: string;
|
|
1182
1313
|
}
|
|
1183
1314
|
/** Callback a shape subscription invokes with its materialized rowset on every applied poke. */
|
|
@@ -1226,8 +1357,19 @@ type BatchSlot = {
|
|
|
1226
1357
|
declare class LunoraClient {
|
|
1227
1358
|
/** Hard cap on concurrently-buffered pokes — a backstop that reclaims buffers abandoned by a mid-poke disconnect (no `pokeEnd`). Far above any real concurrent-in-flight count. */
|
|
1228
1359
|
private static readonly MAX_POKE_BUFFERS;
|
|
1360
|
+
/**
|
|
1361
|
+
* Create a typed {@link ClientQueryRef}. Convenience wrapper around
|
|
1362
|
+
* {@link createClientQuery} so you don't need a separate import.
|
|
1363
|
+
* @example
|
|
1364
|
+
* ```ts
|
|
1365
|
+
* const sidebarOpen = LunoraClient.createClientQuery("sidebarOpen", true);
|
|
1366
|
+
* ```
|
|
1367
|
+
*/
|
|
1368
|
+
static createClientQuery<T>(key: string, defaultValue: T): ClientQueryRef<T>;
|
|
1229
1369
|
readonly url: string;
|
|
1230
1370
|
readonly wsUrl: string;
|
|
1371
|
+
/** Local reactive store for {@link ClientQueryRef} values — no server round-trip. Private; reach it via `getClientQuery` / `setClientQuery` / `subscribeClientQuery`. */
|
|
1372
|
+
private readonly clientQueryStore;
|
|
1231
1373
|
private wsToken;
|
|
1232
1374
|
/** Better-auth base path (trailing slash stripped) for the `get-session` lookup. */
|
|
1233
1375
|
private readonly authBasePath;
|
|
@@ -1249,6 +1391,20 @@ declare class LunoraClient {
|
|
|
1249
1391
|
/** Stable per-client id stamped onto every `OutboxMutation` (custom-mutator watermark). */
|
|
1250
1392
|
private readonly clientId;
|
|
1251
1393
|
/**
|
|
1394
|
+
* `true` when the constructor's hydration microtask has finished loading the
|
|
1395
|
+
* durable read cache (Pillar 2) into `hydratedQueryCache`. Signals that
|
|
1396
|
+
* the cache is ready for synchronous `peekHydratedQuery` reads.
|
|
1397
|
+
*/
|
|
1398
|
+
private readyResolved;
|
|
1399
|
+
/** Resolvers for `whenReady()` — called once hydration completes. */
|
|
1400
|
+
private readyResolve;
|
|
1401
|
+
/**
|
|
1402
|
+
* Promise that resolves once the durable read cache has been loaded. When
|
|
1403
|
+
* `hydrateOnStart` is not set or no query cache is configured, resolves
|
|
1404
|
+
* immediately (the constructor creates an already-resolved promise).
|
|
1405
|
+
*/
|
|
1406
|
+
private readonly readyPromise;
|
|
1407
|
+
/**
|
|
1252
1408
|
* Highest custom-mutator watermark the server has echoed for this client,
|
|
1253
1409
|
* keyed by shard bucket (`shardKey ?? ""`) since the DO tracks one
|
|
1254
1410
|
* `__client_watermark` per shard. `callMutator` bumps it from every
|
|
@@ -1281,6 +1437,12 @@ declare class LunoraClient {
|
|
|
1281
1437
|
private readonly pendingCacheWrites;
|
|
1282
1438
|
private cacheFlushTimer;
|
|
1283
1439
|
private readonly subscriptions;
|
|
1440
|
+
/**
|
|
1441
|
+
* Cross-tab coordinator; created only when `crossTabSync: true`. When the
|
|
1442
|
+
* client is not the elected leader, all WebSocket operations are skipped.
|
|
1443
|
+
* Not `readonly` — `close()` clears it (mirrors `outboxLeaderRelease`).
|
|
1444
|
+
*/
|
|
1445
|
+
private tabCoordinator;
|
|
1284
1446
|
/** One {@link ShardConnection} per shard key (keyed by `shardKey ?? ""`). */
|
|
1285
1447
|
private readonly connections;
|
|
1286
1448
|
/** Default `connect`-envelope context applied to a shard with no explicit override. */
|
|
@@ -1444,10 +1606,12 @@ declare class LunoraClient {
|
|
|
1444
1606
|
* Replace the token appended to WS upgrade URLs as `?token=…` and close
|
|
1445
1607
|
* every open shard socket so the reconnect picks up the new value. Call
|
|
1446
1608
|
* this whenever the user's WS credential changes (rotating the admin token
|
|
1447
|
-
* in the studio, switching workspaces, etc.).
|
|
1448
|
-
*
|
|
1609
|
+
* in the studio, switching workspaces, etc.). Accepts a static string or a
|
|
1610
|
+
* {@link WsTokenProvider} resolved fresh at every (re)connect — the channel
|
|
1611
|
+
* for short-lived credentials like the minted ephemeral admin sub-token.
|
|
1612
|
+
* Bearer tokens for HTTP RPC are independent — see {@link setAuthToken}.
|
|
1449
1613
|
*/
|
|
1450
|
-
setWsToken(token: string | undefined): void;
|
|
1614
|
+
setWsToken(token: string | undefined | WsTokenProvider): void;
|
|
1451
1615
|
/**
|
|
1452
1616
|
* Register (or clear, with `undefined`) the app context sent in the `connect`
|
|
1453
1617
|
* envelope for a shard's socket, overriding the client-wide
|
|
@@ -1559,6 +1723,93 @@ declare class LunoraClient {
|
|
|
1559
1723
|
* unsubscribe function. See {@link MutationSettledEvent}.
|
|
1560
1724
|
*/
|
|
1561
1725
|
onMutationSettled(listener: (event: MutationSettledEvent) => void): Unsubscribe;
|
|
1726
|
+
/**
|
|
1727
|
+
* Read the current value for a {@link ClientQueryRef}. Returns
|
|
1728
|
+
* `ref.defaultValue` when no value has been explicitly set.
|
|
1729
|
+
*/
|
|
1730
|
+
getClientQuery<T>(ref: ClientQueryRef<T>): T;
|
|
1731
|
+
/**
|
|
1732
|
+
* Set a new value for `ref` and notify every subscriber. Pass `undefined`
|
|
1733
|
+
* to reset the slot to `ref.defaultValue`.
|
|
1734
|
+
*/
|
|
1735
|
+
setClientQuery<T>(ref: ClientQueryRef<T>, value: T): void;
|
|
1736
|
+
/**
|
|
1737
|
+
* Subscribe to changes for `ref`. The callback is NOT invoked on
|
|
1738
|
+
* registration — call {@link getClientQuery} for the current value.
|
|
1739
|
+
* Returns an unsubscribe function.
|
|
1740
|
+
*/
|
|
1741
|
+
subscribeClientQuery(ref: ClientQueryRef, callback: (value: unknown) => void): Unsubscribe;
|
|
1742
|
+
/**
|
|
1743
|
+
* Reset a {@link ClientQueryRef} to its default value, notifying every
|
|
1744
|
+
* subscriber. Equivalent to `setClientQuery(ref, ref.defaultValue)` but
|
|
1745
|
+
* removes the stored entry so a future {@link getClientQuery} returns
|
|
1746
|
+
* the default rather than an explicitly-set value.
|
|
1747
|
+
*/
|
|
1748
|
+
resetClientQuery(ref: ClientQueryRef): void;
|
|
1749
|
+
/**
|
|
1750
|
+
* Capture a snapshot of the current live query value at call time and
|
|
1751
|
+
* produce a `() => boolean` precondition that compares it against the
|
|
1752
|
+
* value at replay time (on queue drain / reconnect).
|
|
1753
|
+
*
|
|
1754
|
+
* When the precondition is checked it re-reads the query's current value
|
|
1755
|
+
* via `peekActiveQueryValue`. If the value differs from what was
|
|
1756
|
+
* captured at call time the precondition returns `false` and the offline
|
|
1757
|
+
* mutation is dropped as stale.
|
|
1758
|
+
*
|
|
1759
|
+
* This is a method wrapper around `createSnapshotPrecondition` that
|
|
1760
|
+
* binds the client instance for you — no need to pass `client` explicitly.
|
|
1761
|
+
* @example
|
|
1762
|
+
* ```ts
|
|
1763
|
+
* client.mutation(api.todos.update, { id, text }, {
|
|
1764
|
+
* precondition: client.snapshotPrecondition(api.todos.list, { userId }),
|
|
1765
|
+
* });
|
|
1766
|
+
* ```
|
|
1767
|
+
*/
|
|
1768
|
+
snapshotPrecondition(functionRef: FunctionReference, args: Record<string, unknown>, shardKey?: string): () => boolean;
|
|
1769
|
+
/**
|
|
1770
|
+
* Resolves once the durable read cache has been loaded into memory. When
|
|
1771
|
+
* `hydrateOnStart` is not configured or no query cache adapter is active,
|
|
1772
|
+
* returns an already-resolved promise so callers can always await it
|
|
1773
|
+
* unconditionally.
|
|
1774
|
+
*
|
|
1775
|
+
* Framework adapters (React, Vue, etc.) use this to gate the first
|
|
1776
|
+
* (enabled) render of a live query behind hydration, so the user sees
|
|
1777
|
+
* cached data instead of an undefined flash before the socket round-trip.
|
|
1778
|
+
*/
|
|
1779
|
+
whenReady(): Promise<void>;
|
|
1780
|
+
/**
|
|
1781
|
+
* Synchronously reports whether {@link whenReady} has already resolved (the
|
|
1782
|
+
* durable read cache is loaded, or none is configured). Framework adapters
|
|
1783
|
+
* read this to seed the hydration-gate state on the first render without
|
|
1784
|
+
* awaiting, then subscribe via {@link whenReady} for the pending case.
|
|
1785
|
+
*/
|
|
1786
|
+
get isReady(): boolean;
|
|
1787
|
+
/**
|
|
1788
|
+
* Synchronously peek at a value the durable read cache loaded for the given
|
|
1789
|
+
* function path + args + shard key. Returns `undefined` when:
|
|
1790
|
+
*
|
|
1791
|
+
* - No query cache adapter is configured.
|
|
1792
|
+
* - Hydration hasn't completed yet (race — await {@link whenReady} first).
|
|
1793
|
+
* - The cached value's identity fingerprint doesn't match the current auth.
|
|
1794
|
+
*
|
|
1795
|
+
* Unlike the internal {@link takeHydratedCache}, this is a READ-ONLY peek:
|
|
1796
|
+
* the cached entry stays in `hydratedQueryCache` so the subscription created
|
|
1797
|
+
* later by {@link subscribe} consumes it normally.
|
|
1798
|
+
*/
|
|
1799
|
+
peekHydratedQuery(functionPath: string, args: Record<string, unknown>, shardKey?: string): unknown;
|
|
1800
|
+
/**
|
|
1801
|
+
* Peek at the **current live value** of an active subscription, if one
|
|
1802
|
+
* exists. Returns the subscription's `lastValue` (which includes any
|
|
1803
|
+
* optimistic overlay) or `undefined` if no subscription is active for the
|
|
1804
|
+
* given `(functionPath, args, shardKey)`.
|
|
1805
|
+
*
|
|
1806
|
+
* Unlike {@link peekHydratedQuery} (which reads from the durable read cache
|
|
1807
|
+
* and is independent of active subscriptions), this method reflects the
|
|
1808
|
+
* current in-memory state of an already-opened subscription — useful for
|
|
1809
|
+
* offline mutation preconditions that need to snapshot the value at call time
|
|
1810
|
+
* and compare it at replay time.
|
|
1811
|
+
*/
|
|
1812
|
+
peekActiveQueryValue(functionPath: string, args: Record<string, unknown>, shardKey?: string): unknown;
|
|
1562
1813
|
query<F extends FunctionReference>(function_: F, args: ArgsOf<F>, options?: {
|
|
1563
1814
|
shardKey?: string;
|
|
1564
1815
|
}): Promise<ReturnOf<F>>;
|
|
@@ -1687,8 +1938,10 @@ declare class LunoraClient {
|
|
|
1687
1938
|
* Subscribe to the live scheduled-jobs list over the SchedulerDO's admin
|
|
1688
1939
|
* WebSocket. `onJobs` fires with the full list on connect and on every
|
|
1689
1940
|
* change (schedule / cancel / alarm-fire). Reconnects with the client's
|
|
1690
|
-
* configured backoff. Requires `wsToken` to be set to
|
|
1691
|
-
* browser can't send an `Authorization` header on a WS)
|
|
1941
|
+
* configured backoff. Requires `wsToken` to be set to an admin credential
|
|
1942
|
+
* (the browser can't send an `Authorization` header on a WS) — the master
|
|
1943
|
+
* token, or preferably a {@link WsTokenProvider} minting the ephemeral
|
|
1944
|
+
* sub-token so the master credential stays out of the URL. Returns an
|
|
1692
1945
|
* unsubscribe function that closes the socket and stops reconnecting.
|
|
1693
1946
|
*/
|
|
1694
1947
|
subscribeScheduledJobs(onJobs: (jobs: ScheduleRecord[]) => void): Unsubscribe;
|
|
@@ -2188,6 +2441,25 @@ declare class LunoraClient {
|
|
|
2188
2441
|
maxBuffer?: number;
|
|
2189
2442
|
shardKey?: string;
|
|
2190
2443
|
}): StreamIterable<ReturnOf<F>>;
|
|
2444
|
+
/**
|
|
2445
|
+
* Open a typed **HTTP-SSE route stream** (`httpRoute.<verb>(path).stream()`).
|
|
2446
|
+
* Distinct from {@link LunoraClient.stream}, which consumes the WS procedure
|
|
2447
|
+
* stream (`kind: "stream"`): this one opens the route's own URL with `fetch`
|
|
2448
|
+
* and parses the Server-Sent Events framing the route pump writes (`data:`
|
|
2449
|
+
* chunks, a final `event: complete`, an `event: error` on throw).
|
|
2450
|
+
*
|
|
2451
|
+
* The reference comes from the generated `httpStreams.*` registry, so the
|
|
2452
|
+
* yielded chunk type is the route handler's yielded type. Cancelling the
|
|
2453
|
+
* returned iterable (or aborting `options.signal`) aborts the fetch, which
|
|
2454
|
+
* the server handler observes via its `signal`. The client's bearer token
|
|
2455
|
+
* (when set) rides as an `authorization` header.
|
|
2456
|
+
* @experimental Reconnect/POST-body/wire-fidelity design questions are still open, so the shape may change.
|
|
2457
|
+
*/
|
|
2458
|
+
httpStream<Ref extends HttpStreamRef>(route: Ref, args?: HttpStreamArgsOf<Ref>, options?: {
|
|
2459
|
+
headers?: Record<string, string>;
|
|
2460
|
+
maxBuffer?: number;
|
|
2461
|
+
signal?: AbortSignal;
|
|
2462
|
+
}): StreamIterable<HttpStreamChunkOf<Ref>>;
|
|
2191
2463
|
close(): void;
|
|
2192
2464
|
/**
|
|
2193
2465
|
* Persist a mutation that can't go out on the wire right now (offline, or
|
|
@@ -2333,6 +2605,18 @@ declare class LunoraClient {
|
|
|
2333
2605
|
*/
|
|
2334
2606
|
private resendShapeSubscriptions;
|
|
2335
2607
|
private ensureSocket;
|
|
2608
|
+
/**
|
|
2609
|
+
* Resolve the {@link WsTokenProvider} and open the shard socket with the
|
|
2610
|
+
* minted token. The connection is already in the `connecting` state, so the
|
|
2611
|
+
* async gap is race-guarded: a client `close()`, a `setWsToken` bounce, or a
|
|
2612
|
+
* competing connect that landed first all abandon this attempt. A provider
|
|
2613
|
+
* failure fails the attempt through {@link handleDisconnect}, which arms the
|
|
2614
|
+
* normal reconnect backoff — a broken mint endpoint degrades to retries, not
|
|
2615
|
+
* a silent tokenless socket the admin gate would reject.
|
|
2616
|
+
*/
|
|
2617
|
+
private openSocketWithProvidedToken;
|
|
2618
|
+
/** Construct the shard socket and wire its lifecycle handlers. The connection must already be in the `connecting` state. */
|
|
2619
|
+
private openSocket;
|
|
2336
2620
|
private handleDisconnect;
|
|
2337
2621
|
/**
|
|
2338
2622
|
* Begin the keepalive heartbeat on an open connection. Each tick sends a
|
|
@@ -2537,4 +2821,4 @@ declare class LunoraClient {
|
|
|
2537
2821
|
*/
|
|
2538
2822
|
private settleReplayBatchSlots;
|
|
2539
2823
|
}
|
|
2540
|
-
export {
|
|
2824
|
+
export { ServerPokePartMessage as $, ArgsOf as A, BookmarkStorage as B, CONFLICT_ERROR_CODE as C, DEFAULT_MAX_BUFFER as D, OptimisticUpdate as E, FunctionReference as F, GlobalFacetResult as G, HttpStreamRef as H, OutboxMutation as I, OutboxSink as J, PersistedMutation as K, LunoraClient as L, MutationCallOptions as M, RowOp as N, OfflineQueueOptions as O, Preloaded as P, QueryCacheAdapter as Q, ReturnOf as R, SubscriptionError as S, RpcEnvelope as T, User as U, RpcResponseBody as V, ScheduleRecord as W, SchedulerPoolStatus as X, SchedulerStatus as Y, ServerMessage as Z, ServerPokeEndMessage as _, Unsubscribe as a, ServerPokeStartMessage as a0, ShardTrafficEntry as a1, ShardTrafficResult as a2, StorageListPage as a3, StorageObject as a4, StreamHandle as a5, SubscriptionCallback as a6, SubscriptionRegistry as a7, SubscriptionState as a8, SyncWatermark as a9, WorkflowInstanceAction as aa, WorkflowInstanceDetail as ab, WorkflowInstancePage as ac, WorkflowInstanceStatus as ad, WorkflowInstanceSummary as ae, WorkflowStepDetail as af, WsTokenProvider as ag, createClientQuery as ah, createLocalStore as ai, createStream as aj, getErrorCode as ak, getRetryAfterMs as al, isConflictError as am, isForbiddenError as an, isRateLimitedError as ao, isUnauthorizedError as ap, SubscriptionErrorCallback as b, PersistenceAdapter as c, HttpStreamArgsOf as d, HttpStreamChunkOf as e, StreamIterable as f, ReconnectOptions as g, BatchSlot as h, CachedQuery as i, ClientMessage as j, ClientQueryRef as k, ClientShapeSubscribeMessage as l, ClientShapeUnsubscribeMessage as m, ConnectionStatus as n, FunctionArgumentDescriptor as o, FunctionDescriptor as p, GlobalFacetValue as q, GlobalFilterClause as r, GlobalTableInfo as s, GlobalTablePage as t, HttpStreamCallArgs as u, LunoraClientError as v, LunoraClientOptions as w, LunoraErrorCode as x, MutationSettledEvent as y, OptimisticLocalStore as z };
|