@lunora/client 1.0.0-alpha.24 → 1.0.0-alpha.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/auth/index.d.mts +10 -10
- package/dist/auth/index.d.ts +10 -10
- package/dist/index.d.mts +342 -380
- package/dist/index.d.ts +342 -380
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/{LunoraClient-D3h4P7hg.mjs → LunoraClient-DKATLGHY.mjs} +18 -0
- package/dist/packem_shared/{createServerClient-DzeC2J3A.mjs → createServerClient-Bp2r9tcB.mjs} +1 -1
- package/dist/packem_shared/lunora-client.d-B1iZb2Ph.d.mts +2845 -0
- package/dist/packem_shared/lunora-client.d-B1iZb2Ph.d.ts +2845 -0
- package/dist/packem_shared/preload.d-CLwoXl3R.d.mts +20 -0
- package/dist/packem_shared/preload.d-Cqb4Kh2I.d.ts +20 -0
- package/dist/pagination/index.d.mts +42 -42
- package/dist/pagination/index.d.ts +42 -42
- package/dist/query/index.d.mts +42 -42
- package/dist/query/index.d.ts +42 -42
- package/dist/ssr/index.d.mts +79 -79
- package/dist/ssr/index.d.ts +79 -79
- package/dist/ssr/index.mjs +1 -1
- package/package.json +2 -2
- package/dist/packem_shared/lunora-client.d-B8bdwHLr.d.mts +0 -2836
- package/dist/packem_shared/lunora-client.d-B8bdwHLr.d.ts +0 -2836
- package/dist/packem_shared/preload.d-BPy9qajK.d.ts +0 -20
- package/dist/packem_shared/preload.d-Ccrgw2z0.d.mts +0 -20
package/dist/index.d.mts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { c as PersistenceAdapter, B as BookmarkStorage, S as SubscriptionError, H as HttpStreamRef, d as HttpStreamArgsOf, e as HttpStreamChunkOf, f as StreamIterable, F as FunctionReference, A as ArgsOf, M as MutationCallOptions, R as ReturnOf, O as OfflineQueueOptions, Q as QueryCacheAdapter, g as ReconnectOptions, L as LunoraClient } from "./packem_shared/lunora-client.d-
|
|
2
|
-
export { type h as BatchSlot, C as CONFLICT_ERROR_CODE, type i as CachedQuery, type j as ClientMessage, type k as ClientQueryRef, type l as ClientShapeSubscribeMessage, type m as ClientShapeUnsubscribeMessage, type n as ConnectionStatus, D as DEFAULT_MAX_BUFFER, type o as FunctionArgumentDescriptor, type p as FunctionDescriptor, type G as GlobalFacetResult, type q as GlobalFacetValue, type r as GlobalFilterClause, type s as GlobalTableInfo, type t as GlobalTablePage, type u as HttpStreamCallArgs, type v as LunoraClientError, type w as LunoraClientOptions, type x as LunoraErrorCode, type y as MutationSettledEvent, type z as OptimisticLocalStore, type E as OptimisticUpdate, type I as OutboxMutation, type J as OutboxSink, type K as PersistedMutation, type P as Preloaded, type N as RowOp, type T as RpcEnvelope, type V as RpcResponseBody, type W as ScheduleRecord, type X as SchedulerPoolStatus, type Y as SchedulerStatus, type Z as ServerMessage, type _ as ServerPokeEndMessage, type $ as ServerPokePartMessage, type a0 as ServerPokeStartMessage, type a1 as ShardTrafficEntry, type a2 as ShardTrafficResult, type a3 as StorageListPage, type a4 as StorageObject, type a5 as StreamHandle, type a6 as SubscriptionCallback, type b as SubscriptionErrorCallback, a7 as SubscriptionRegistry, type a8 as SubscriptionState, type a9 as SyncWatermark, type a as Unsubscribe, type U as User, type aa as WorkflowInstanceAction, type ab as WorkflowInstanceDetail, type ac as WorkflowInstancePage, type ad as WorkflowInstanceStatus, type ae as WorkflowInstanceSummary, type af as WorkflowStepDetail, type ag as WsTokenProvider, ah as createClientQuery, ai as createLocalStore, aj as createStream, ak as getErrorCode, al as getRetryAfterMs, am as isConflictError, an as isForbiddenError, ao as isRateLimitedError, ap as isUnauthorizedError } from "./packem_shared/lunora-client.d-
|
|
3
|
-
export { p as preloadQuery, a as preloadedQueryResult } from "./packem_shared/preload.d-
|
|
4
|
-
export type { AuthCapabilities, AuthConfigInfo, AuthImpersonation, AuthPage, AuthSession, AuthUser, AuthUserFieldSpec, CronJobInfo, KvKeyEntry, KvKeyListResult, KvNamespaceSummary, KvValueResult, VectorIndexSummary, VectorQueryMatch } from '@lunora/runtime';
|
|
5
|
-
/**
|
|
6
|
-
* The slice of React Native's `AsyncStorage` (or any async key/value store —
|
|
7
|
-
* Expo `SecureStore`, a wrapped `localForage`, an in-memory map in tests) this
|
|
8
|
-
* adapter needs. Matches `@react-native-async-storage/async-storage`'s core
|
|
9
|
-
* surface, so you can pass the module straight in.
|
|
10
|
-
*/
|
|
1
|
+
import { c as PersistenceAdapter, B as BookmarkStorage, S as SubscriptionError, H as HttpStreamRef, d as HttpStreamArgsOf, e as HttpStreamChunkOf, f as StreamIterable, F as FunctionReference, A as ArgsOf, M as MutationCallOptions, R as ReturnOf, O as OfflineQueueOptions, Q as QueryCacheAdapter, g as ReconnectOptions, L as LunoraClient } from "./packem_shared/lunora-client.d-B1iZb2Ph.mjs";
|
|
2
|
+
export { type h as BatchSlot, C as CONFLICT_ERROR_CODE, type i as CachedQuery, type j as ClientMessage, type k as ClientQueryRef, type l as ClientShapeSubscribeMessage, type m as ClientShapeUnsubscribeMessage, type n as ConnectionStatus, D as DEFAULT_MAX_BUFFER, type o as FunctionArgumentDescriptor, type p as FunctionDescriptor, type G as GlobalFacetResult, type q as GlobalFacetValue, type r as GlobalFilterClause, type s as GlobalTableInfo, type t as GlobalTablePage, type u as HttpStreamCallArgs, type v as LunoraClientError, type w as LunoraClientOptions, type x as LunoraErrorCode, type y as MutationSettledEvent, type z as OptimisticLocalStore, type E as OptimisticUpdate, type I as OutboxMutation, type J as OutboxSink, type K as PersistedMutation, type P as Preloaded, type N as RowOp, type T as RpcEnvelope, type V as RpcResponseBody, type W as ScheduleRecord, type X as SchedulerPoolStatus, type Y as SchedulerStatus, type Z as ServerMessage, type _ as ServerPokeEndMessage, type $ as ServerPokePartMessage, type a0 as ServerPokeStartMessage, type a1 as ShardTrafficEntry, type a2 as ShardTrafficResult, type a3 as StorageListPage, type a4 as StorageObject, type a5 as StreamHandle, type a6 as SubscriptionCallback, type b as SubscriptionErrorCallback, a7 as SubscriptionRegistry, type a8 as SubscriptionState, type a9 as SyncWatermark, type a as Unsubscribe, type U as User, type aa as WorkflowInstanceAction, type ab as WorkflowInstanceDetail, type ac as WorkflowInstancePage, type ad as WorkflowInstanceStatus, type ae as WorkflowInstanceSummary, type af as WorkflowStepDetail, type ag as WsTokenProvider, ah as createClientQuery, ai as createLocalStore, aj as createStream, ak as getErrorCode, al as getRetryAfterMs, am as isConflictError, an as isForbiddenError, ao as isRateLimitedError, ap as isUnauthorizedError } from "./packem_shared/lunora-client.d-B1iZb2Ph.mjs";
|
|
3
|
+
export { p as preloadQuery, a as preloadedQueryResult } from "./packem_shared/preload.d-CLwoXl3R.mjs";
|
|
4
|
+
export type { AuthCapabilities, AuthConfigInfo, AuthImpersonation, AuthPage, AuthSession, AuthUser, AuthUserFieldSpec, CronJobInfo, KvKeyEntry, KvKeyListResult, KvNamespaceSummary, KvValueResult, PipelineLogColumnMap, PipelineLogCursor, PipelineLogField, PipelineLogPage, PipelineLogQuery, PipelineLogRow, VectorIndexSummary, VectorQueryMatch } from '@lunora/runtime';
|
|
5
|
+
/**
|
|
6
|
+
* The slice of React Native's `AsyncStorage` (or any async key/value store —
|
|
7
|
+
* Expo `SecureStore`, a wrapped `localForage`, an in-memory map in tests) this
|
|
8
|
+
* adapter needs. Matches `@react-native-async-storage/async-storage`'s core
|
|
9
|
+
* surface, so you can pass the module straight in.
|
|
10
|
+
*/
|
|
11
11
|
interface AsyncStorageLike {
|
|
12
12
|
getItem: (key: string) => Promise<string | null>;
|
|
13
13
|
removeItem: (key: string) => Promise<void>;
|
|
@@ -20,48 +20,48 @@ interface AsyncStoragePersistenceOptions {
|
|
|
20
20
|
storage: AsyncStorageLike;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
|
-
* Builds a {@link PersistenceAdapter} over an async key/value store — the React
|
|
24
|
-
* Native / Expo counterpart to the IndexedDB adapter (`createIndexedDbPersistence`).
|
|
25
|
-
* The whole FIFO mutation log is serialized to JSON under a single key (`key`),
|
|
26
|
-
* so enqueue order is preserved and `load()` returns freshly-parsed records that
|
|
27
|
-
* callers can't alias.
|
|
28
|
-
*
|
|
29
|
-
* AsyncStorage has no transactions, so every read-modify-write is funnelled
|
|
30
|
-
* through a single promise chain — concurrent `append`/`remove` calls run one at
|
|
31
|
-
* a time and can't clobber each other's writes.
|
|
32
|
-
*/
|
|
23
|
+
* Builds a {@link PersistenceAdapter} over an async key/value store — the React
|
|
24
|
+
* Native / Expo counterpart to the IndexedDB adapter (`createIndexedDbPersistence`).
|
|
25
|
+
* The whole FIFO mutation log is serialized to JSON under a single key (`key`),
|
|
26
|
+
* so enqueue order is preserved and `load()` returns freshly-parsed records that
|
|
27
|
+
* callers can't alias.
|
|
28
|
+
*
|
|
29
|
+
* AsyncStorage has no transactions, so every read-modify-write is funnelled
|
|
30
|
+
* through a single promise chain — concurrent `append`/`remove` calls run one at
|
|
31
|
+
* a time and can't clobber each other's writes.
|
|
32
|
+
*/
|
|
33
33
|
declare const createAsyncStoragePersistence: (options: AsyncStoragePersistenceOptions) => PersistenceAdapter;
|
|
34
34
|
/** Default in-memory bookmark store. Survives the lifetime of the client. */
|
|
35
35
|
declare const createInMemoryBookmarkStorage: () => BookmarkStorage;
|
|
36
36
|
interface TabCoordinatorOptions {
|
|
37
37
|
/**
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
* BroadcastChannel name. Defaults to `"lunora-bridge"`.
|
|
39
|
+
*/
|
|
40
40
|
channelName?: string;
|
|
41
41
|
/**
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
* Interval (ms) between leader heartbeats. Defaults to 1000.
|
|
43
|
+
*/
|
|
44
44
|
heartbeatInterval?: number;
|
|
45
45
|
/**
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
* Milliseconds without a heartbeat to consider the leader dead. Must be
|
|
47
|
+
* larger than `heartbeatInterval`. Defaults to 3000.
|
|
48
|
+
*/
|
|
49
49
|
leaderTimeout?: number;
|
|
50
50
|
/**
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
* Called when this tab becomes the leader (should open WS connections).
|
|
52
|
+
*/
|
|
53
53
|
onBecomeLeader?: () => void;
|
|
54
54
|
/**
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
* Called when this tab loses leadership (should close WS connections).
|
|
56
|
+
*/
|
|
57
57
|
onStopBeingLeader?: () => void;
|
|
58
58
|
/**
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
* Called when the leader broadcasts subscription data.
|
|
60
|
+
*/
|
|
61
61
|
onSubscriptionData?: (key: string, data: unknown) => void;
|
|
62
62
|
/**
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
* Called when the leader broadcasts a subscription error.
|
|
64
|
+
*/
|
|
65
65
|
onSubscriptionError?: (key: string, error: SubscriptionError) => void;
|
|
66
66
|
}
|
|
67
67
|
declare class TabCoordinator {
|
|
@@ -86,14 +86,14 @@ declare class TabCoordinator {
|
|
|
86
86
|
private readonly onSubscriptionError;
|
|
87
87
|
constructor(options?: TabCoordinatorOptions);
|
|
88
88
|
/**
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
* Start the coordinator: attempt to claim leadership and begin the
|
|
90
|
+
* heartbeat/leader-check cycle. Safe to call multiple times.
|
|
91
|
+
*/
|
|
92
92
|
start(): void;
|
|
93
93
|
/**
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
* Stop the coordinator: yield leadership (if held), close the channel, and
|
|
95
|
+
* clear all timers. Safe to call multiple times.
|
|
96
|
+
*/
|
|
97
97
|
stop(): void;
|
|
98
98
|
/** `true` when this tab is the current WebSocket leader. */
|
|
99
99
|
isLeader(): boolean;
|
|
@@ -104,63 +104,63 @@ declare class TabCoordinator {
|
|
|
104
104
|
/** `true` when the coordinator has been started and is not yet stopped. */
|
|
105
105
|
get isRunning(): boolean;
|
|
106
106
|
/**
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
* Broadcast subscription data to all follower tabs. Only the leader should
|
|
108
|
+
* call this.
|
|
109
|
+
*/
|
|
110
110
|
broadcastSubscriptionData(key: string, data: unknown): void;
|
|
111
111
|
/**
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
* Broadcast a subscription error to all follower tabs. Only the leader
|
|
113
|
+
* should call this.
|
|
114
|
+
*/
|
|
115
115
|
broadcastSubscriptionError(key: string, error: SubscriptionError): void;
|
|
116
116
|
private broadcast;
|
|
117
117
|
private handleMessage;
|
|
118
118
|
private handleClaimLeadership;
|
|
119
119
|
private handleHeartbeat;
|
|
120
120
|
/**
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
121
|
+
* Resolve two leaders existing at once — e.g. this tab was backgrounded
|
|
122
|
+
* and its heartbeat/health timers were throttled while a foreground
|
|
123
|
+
* follower's were not, so the follower's `checkLeaderHealth` timed out
|
|
124
|
+
* the (still-alive) leader and self-promoted. `BroadcastChannel` message
|
|
125
|
+
* delivery isn't subject to the same timer-throttling clamp, so even a
|
|
126
|
+
* backgrounded leader eventually observes the pretender's heartbeat here
|
|
127
|
+
* — resolve the split-brain deterministically with the same
|
|
128
|
+
* lexicographically-smaller-tabId rule used at claim-adoption. If the
|
|
129
|
+
* other tab wins, step down; if we win, reassert immediately so the
|
|
130
|
+
* pretender demotes itself the moment it processes our heartbeat.
|
|
131
|
+
*/
|
|
132
132
|
private resolveLeaderVsLeaderTieBreak;
|
|
133
133
|
private becomeLeader;
|
|
134
134
|
private sendHeartbeat;
|
|
135
135
|
private checkLeaderHealth;
|
|
136
136
|
}
|
|
137
137
|
/**
|
|
138
|
-
* Client-side incremental merging of structured mutation deltas.
|
|
139
|
-
*
|
|
140
|
-
* Lunora's live-query fan-out has two server paths:
|
|
141
|
-
*
|
|
142
|
-
* 1. Server re-execution (subscriptions carrying a `functionPath`) pushes a
|
|
143
|
-
* full `data` snapshot whenever a write touches a table the query reads. These
|
|
144
|
-
* already carry the authoritative result and are applied wholesale.
|
|
145
|
-
* 2. Legacy delta fan-out (`broadcastDelta`) pushes a structured `MutationDelta`
|
|
146
|
-
* as a `delta` frame to subscribers matched by table + args. The delta describes
|
|
147
|
-
* a single row change (`insert` / `update` / `delete`) keyed by row id, so the
|
|
148
|
-
* client can splice it into the cached list result without a full re-send.
|
|
149
|
-
*
|
|
150
|
-
* Historically the client treated the `delta` field as an opaque blob and
|
|
151
|
-
* replaced the whole cached value with it on every message — which only made
|
|
152
|
-
* sense for the rare delta payloads that already carried the full result. This
|
|
153
|
-
* module lets the client recognise a structured delta and merge it into the
|
|
154
|
-
* existing array (preserving order, no dup/loss), falling back to full
|
|
155
|
-
* replacement when the payload isn't a recognisable row delta or can't be
|
|
156
|
-
* applied cleanly against the current cached shape.
|
|
157
|
-
*/
|
|
158
|
-
/**
|
|
159
|
-
* One row change as emitted by `@lunora/do`'s `broadcastDelta`. Mirrors
|
|
160
|
-
* `MutationDelta` in `@lunora/do` structurally so the client carries no
|
|
161
|
-
* dependency on it. `row` is absent on `delete` events (and may be absent on
|
|
162
|
-
* older servers for any op).
|
|
163
|
-
*/
|
|
138
|
+
* Client-side incremental merging of structured mutation deltas.
|
|
139
|
+
*
|
|
140
|
+
* Lunora's live-query fan-out has two server paths:
|
|
141
|
+
*
|
|
142
|
+
* 1. Server re-execution (subscriptions carrying a `functionPath`) pushes a
|
|
143
|
+
* full `data` snapshot whenever a write touches a table the query reads. These
|
|
144
|
+
* already carry the authoritative result and are applied wholesale.
|
|
145
|
+
* 2. Legacy delta fan-out (`broadcastDelta`) pushes a structured `MutationDelta`
|
|
146
|
+
* as a `delta` frame to subscribers matched by table + args. The delta describes
|
|
147
|
+
* a single row change (`insert` / `update` / `delete`) keyed by row id, so the
|
|
148
|
+
* client can splice it into the cached list result without a full re-send.
|
|
149
|
+
*
|
|
150
|
+
* Historically the client treated the `delta` field as an opaque blob and
|
|
151
|
+
* replaced the whole cached value with it on every message — which only made
|
|
152
|
+
* sense for the rare delta payloads that already carried the full result. This
|
|
153
|
+
* module lets the client recognise a structured delta and merge it into the
|
|
154
|
+
* existing array (preserving order, no dup/loss), falling back to full
|
|
155
|
+
* replacement when the payload isn't a recognisable row delta or can't be
|
|
156
|
+
* applied cleanly against the current cached shape.
|
|
157
|
+
*/
|
|
158
|
+
/**
|
|
159
|
+
* One row change as emitted by `@lunora/do`'s `broadcastDelta`. Mirrors
|
|
160
|
+
* `MutationDelta` in `@lunora/do` structurally so the client carries no
|
|
161
|
+
* dependency on it. `row` is absent on `delete` events (and may be absent on
|
|
162
|
+
* older servers for any op).
|
|
163
|
+
*/
|
|
164
164
|
interface MutationDelta {
|
|
165
165
|
/** Row id (`_id`) the change applies to. */
|
|
166
166
|
key: string;
|
|
@@ -169,43 +169,43 @@ interface MutationDelta {
|
|
|
169
169
|
table: string;
|
|
170
170
|
}
|
|
171
171
|
/**
|
|
172
|
-
* Structural guard: is `value` a `MutationDelta` the client knows how to merge?
|
|
173
|
-
* We require `op`, `table`, and a string `key` so opaque payloads that merely
|
|
174
|
-
* happen to be objects (e.g. an aggregate `{ count: 1 }` a query returns
|
|
175
|
-
* verbatim) are never mistaken for a row delta and keep replacing the cached
|
|
176
|
-
* value wholesale.
|
|
177
|
-
*/
|
|
172
|
+
* Structural guard: is `value` a `MutationDelta` the client knows how to merge?
|
|
173
|
+
* We require `op`, `table`, and a string `key` so opaque payloads that merely
|
|
174
|
+
* happen to be objects (e.g. an aggregate `{ count: 1 }` a query returns
|
|
175
|
+
* verbatim) are never mistaken for a row delta and keep replacing the cached
|
|
176
|
+
* value wholesale.
|
|
177
|
+
*/
|
|
178
178
|
declare const isMutationDelta: (value: unknown) => value is MutationDelta;
|
|
179
179
|
/**
|
|
180
|
-
* Apply a structured `MutationDelta` to a cached array result, returning a new
|
|
181
|
-
* array (never mutating the input). Returns `undefined` when the delta can't be
|
|
182
|
-
* applied cleanly — the caller should then fall back to the existing
|
|
183
|
-
* full-replacement behaviour (or trust the next snapshot to reconcile).
|
|
184
|
-
*
|
|
185
|
-
* Mergeable shape: a plain array of id-bearing row objects, e.g. the result of
|
|
186
|
-
* `db.query().collect()`.
|
|
187
|
-
*
|
|
188
|
-
* Insert / update / delete are matched by row `_id`:
|
|
189
|
-
* - `insert`: appended (or placed by `_creationTime` order) if absent; treated
|
|
190
|
-
* as an update if a row with the same id already exists (idempotent — guards
|
|
191
|
-
* against a delta replayed after a snapshot already included it).
|
|
192
|
-
* - `update`: replaces the matching row in place, preserving its position.
|
|
193
|
-
* - `delete`: removes the matching row.
|
|
194
|
-
*
|
|
195
|
-
* Returns `undefined` when `current` isn't an array of id-keyable objects, or
|
|
196
|
-
* when an `insert`/`update` delta carries no `row` to splice in.
|
|
197
|
-
*/
|
|
180
|
+
* Apply a structured `MutationDelta` to a cached array result, returning a new
|
|
181
|
+
* array (never mutating the input). Returns `undefined` when the delta can't be
|
|
182
|
+
* applied cleanly — the caller should then fall back to the existing
|
|
183
|
+
* full-replacement behaviour (or trust the next snapshot to reconcile).
|
|
184
|
+
*
|
|
185
|
+
* Mergeable shape: a plain array of id-bearing row objects, e.g. the result of
|
|
186
|
+
* `db.query().collect()`.
|
|
187
|
+
*
|
|
188
|
+
* Insert / update / delete are matched by row `_id`:
|
|
189
|
+
* - `insert`: appended (or placed by `_creationTime` order) if absent; treated
|
|
190
|
+
* as an update if a row with the same id already exists (idempotent — guards
|
|
191
|
+
* against a delta replayed after a snapshot already included it).
|
|
192
|
+
* - `update`: replaces the matching row in place, preserving its position.
|
|
193
|
+
* - `delete`: removes the matching row.
|
|
194
|
+
*
|
|
195
|
+
* Returns `undefined` when `current` isn't an array of id-keyable objects, or
|
|
196
|
+
* when an `insert`/`update` delta carries no `row` to splice in.
|
|
197
|
+
*/
|
|
198
198
|
declare const applyDelta: (current: unknown, delta: MutationDelta) => undefined | unknown[];
|
|
199
199
|
/**
|
|
200
|
-
* Options accepted by {@link httpStream}.
|
|
201
|
-
* @experimental Part of the HTTP-SSE stream surface.
|
|
202
|
-
*/
|
|
200
|
+
* Options accepted by {@link httpStream}.
|
|
201
|
+
* @experimental Part of the HTTP-SSE stream surface.
|
|
202
|
+
*/
|
|
203
203
|
interface HttpStreamOptions {
|
|
204
204
|
/**
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
205
|
+
* Origin (or origin + prefix) the route path is appended to, e.g.
|
|
206
|
+
* `https://my-app.example.com`. Defaults to `""` — a relative URL, which
|
|
207
|
+
* resolves against the page origin in a browser.
|
|
208
|
+
*/
|
|
209
209
|
baseUrl?: string;
|
|
210
210
|
/** `fetch` implementation override; defaults to the global `fetch`. */
|
|
211
211
|
fetch?: typeof fetch;
|
|
@@ -217,32 +217,32 @@ interface HttpStreamOptions {
|
|
|
217
217
|
signal?: AbortSignal;
|
|
218
218
|
}
|
|
219
219
|
/**
|
|
220
|
-
* Open a typed HTTP-SSE stream route and iterate its chunks:
|
|
221
|
-
*
|
|
222
|
-
* ```ts
|
|
223
|
-
* const stream = httpStream(httpStreams.http.tokens, { searchParams: { prompt } }, { baseUrl });
|
|
224
|
-
* for await (const token of stream) {
|
|
225
|
-
* render(token); // typed as the route handler's yielded chunk
|
|
226
|
-
* }
|
|
227
|
-
* ```
|
|
228
|
-
*
|
|
229
|
-
* The returned iterable terminates when the server writes `event: complete`;
|
|
230
|
-
* an `event: error` frame (or a transport failure) surfaces as a coded
|
|
231
|
-
* rejection on the next `next()`. `.cancel()` — or aborting `options.signal` —
|
|
232
|
-
* aborts the underlying fetch, which the server observes via `request.signal`.
|
|
233
|
-
* @experimental Reconnect/POST-body/wire-fidelity design questions are still open, so the shape may change.
|
|
234
|
-
*/
|
|
220
|
+
* Open a typed HTTP-SSE stream route and iterate its chunks:
|
|
221
|
+
*
|
|
222
|
+
* ```ts
|
|
223
|
+
* const stream = httpStream(httpStreams.http.tokens, { searchParams: { prompt } }, { baseUrl });
|
|
224
|
+
* for await (const token of stream) {
|
|
225
|
+
* render(token); // typed as the route handler's yielded chunk
|
|
226
|
+
* }
|
|
227
|
+
* ```
|
|
228
|
+
*
|
|
229
|
+
* The returned iterable terminates when the server writes `event: complete`;
|
|
230
|
+
* an `event: error` frame (or a transport failure) surfaces as a coded
|
|
231
|
+
* rejection on the next `next()`. `.cancel()` — or aborting `options.signal` —
|
|
232
|
+
* aborts the underlying fetch, which the server observes via `request.signal`.
|
|
233
|
+
* @experimental Reconnect/POST-body/wire-fidelity design questions are still open, so the shape may change.
|
|
234
|
+
*/
|
|
235
235
|
declare const httpStream: <Ref extends HttpStreamRef>(route: Ref, args?: HttpStreamArgsOf<Ref>, options?: HttpStreamOptions) => StreamIterable<HttpStreamChunkOf<Ref>>;
|
|
236
236
|
/** The single transport method a mutation runner needs — narrowed so adapters can test against a stub. */
|
|
237
237
|
interface MutationCapableClient<F extends FunctionReference> {
|
|
238
238
|
mutation: (function_: F, args: ArgsOf<F>, options?: MutationCallOptions<unknown, unknown, ArgsOf<F>>) => Promise<ReturnOf<F>>;
|
|
239
239
|
}
|
|
240
240
|
/**
|
|
241
|
-
* Reactive sinks an adapter binds to its own primitive's setters (a Solid
|
|
242
|
-
* signal, a Vue ref, a Svelte store). The runner pushes into them; how they
|
|
243
|
-
* store the value is the adapter's concern (e.g. Solid wraps function-valued
|
|
244
|
-
* results in a thunk).
|
|
245
|
-
*/
|
|
241
|
+
* Reactive sinks an adapter binds to its own primitive's setters (a Solid
|
|
242
|
+
* signal, a Vue ref, a Svelte store). The runner pushes into them; how they
|
|
243
|
+
* store the value is the adapter's concern (e.g. Solid wraps function-valued
|
|
244
|
+
* results in a thunk).
|
|
245
|
+
*/
|
|
246
246
|
interface MutationRunnerSinks<R> {
|
|
247
247
|
/** Receives the normalized {@link Error} when an invocation rejects. */
|
|
248
248
|
setError: (error: Error) => void;
|
|
@@ -252,41 +252,41 @@ interface MutationRunnerSinks<R> {
|
|
|
252
252
|
setResult: (result: R) => void;
|
|
253
253
|
}
|
|
254
254
|
/**
|
|
255
|
-
* Build the framework-neutral `mutate` half of an adapter's mutation hook.
|
|
256
|
-
*
|
|
257
|
-
* Owns the orchestration every adapter otherwise copy-pastes: ref-counts
|
|
258
|
-
* overlapping invocations into `setPending` (so it only clears once the last
|
|
259
|
-
* settles), normalizes a thrown non-`Error`, and routes success/failure to
|
|
260
|
-
* `setResult`/`setError` before re-throwing. Each adapter (`@lunora/react`,
|
|
261
|
-
* `/solid`, `/svelte`, `/vue`) binds the three sinks to its own reactive
|
|
262
|
-
* setters, so this logic lives in exactly one place. Optimistic-update options
|
|
263
|
-
* pass straight through to `client.mutation`.
|
|
264
|
-
*/
|
|
255
|
+
* Build the framework-neutral `mutate` half of an adapter's mutation hook.
|
|
256
|
+
*
|
|
257
|
+
* Owns the orchestration every adapter otherwise copy-pastes: ref-counts
|
|
258
|
+
* overlapping invocations into `setPending` (so it only clears once the last
|
|
259
|
+
* settles), normalizes a thrown non-`Error`, and routes success/failure to
|
|
260
|
+
* `setResult`/`setError` before re-throwing. Each adapter (`@lunora/react`,
|
|
261
|
+
* `/solid`, `/svelte`, `/vue`) binds the three sinks to its own reactive
|
|
262
|
+
* setters, so this logic lives in exactly one place. Optimistic-update options
|
|
263
|
+
* pass straight through to `client.mutation`.
|
|
264
|
+
*/
|
|
265
265
|
declare const createMutationRunner: <F extends FunctionReference>(client: MutationCapableClient<F>, function_: F, sinks: MutationRunnerSinks<ReturnOf<F>>) => ((args: ArgsOf<F>, options?: MutationCallOptions<unknown, unknown, ArgsOf<F>>) => Promise<ReturnOf<F>>);
|
|
266
266
|
/**
|
|
267
|
-
* The structural surface of a TanStack `Transaction` a bound custom mutator
|
|
268
|
-
* returns — its `isPersisted.promise` resolves once the write is persisted and
|
|
269
|
-
* rejects on failure. Typed structurally so the framework adapters need not
|
|
270
|
-
* depend on `@tanstack/db` or `@lunora/db` (the handle is created app-side by
|
|
271
|
-
* `bindMutators`).
|
|
272
|
-
*/
|
|
267
|
+
* The structural surface of a TanStack `Transaction` a bound custom mutator
|
|
268
|
+
* returns — its `isPersisted.promise` resolves once the write is persisted and
|
|
269
|
+
* rejects on failure. Typed structurally so the framework adapters need not
|
|
270
|
+
* depend on `@tanstack/db` or `@lunora/db` (the handle is created app-side by
|
|
271
|
+
* `bindMutators`).
|
|
272
|
+
*/
|
|
273
273
|
interface MutatorTransaction {
|
|
274
274
|
isPersisted: {
|
|
275
275
|
promise: Promise<unknown>;
|
|
276
276
|
};
|
|
277
277
|
}
|
|
278
278
|
/**
|
|
279
|
-
* A bound custom-mutator handle produced by `bindMutators(client, ctx, mutators)`
|
|
280
|
-
* in `@lunora/db`. Calling it applies the optimistic overlay to the local
|
|
281
|
-
* collections and pushes the authoritative server write; it returns the TanStack
|
|
282
|
-
* transaction whose `isPersisted` promise tracks completion.
|
|
283
|
-
*/
|
|
279
|
+
* A bound custom-mutator handle produced by `bindMutators(client, ctx, mutators)`
|
|
280
|
+
* in `@lunora/db`. Calling it applies the optimistic overlay to the local
|
|
281
|
+
* collections and pushes the authoritative server write; it returns the TanStack
|
|
282
|
+
* transaction whose `isPersisted` promise tracks completion.
|
|
283
|
+
*/
|
|
284
284
|
type MutatorHandle<TArgs> = (args: TArgs) => MutatorTransaction;
|
|
285
285
|
/**
|
|
286
|
-
* Reactive sinks an adapter binds to its own primitive's setters (a React
|
|
287
|
-
* `useState`, a Solid signal, a Vue ref, a Svelte store). The runner pushes into
|
|
288
|
-
* them; how they store the value is the adapter's concern.
|
|
289
|
-
*/
|
|
286
|
+
* Reactive sinks an adapter binds to its own primitive's setters (a React
|
|
287
|
+
* `useState`, a Solid signal, a Vue ref, a Svelte store). The runner pushes into
|
|
288
|
+
* them; how they store the value is the adapter's concern.
|
|
289
|
+
*/
|
|
290
290
|
interface MutatorRunnerSinks {
|
|
291
291
|
/** Receives the normalized {@link Error} when an invocation rejects, or `undefined` on success / reset. */
|
|
292
292
|
setError: (error: Error | undefined) => void;
|
|
@@ -294,24 +294,24 @@ interface MutatorRunnerSinks {
|
|
|
294
294
|
setPending: (pending: boolean) => void;
|
|
295
295
|
}
|
|
296
296
|
/**
|
|
297
|
-
* Build the framework-neutral `mutate` / `reset` pair of an adapter's
|
|
298
|
-
* custom-mutator hook (`useMutator` / `createMutator` / `mutator`).
|
|
299
|
-
*
|
|
300
|
-
* Owns the orchestration every adapter otherwise copy-pastes: ref-counts
|
|
301
|
-
* overlapping invocations into `setPending` (so it only clears once the last
|
|
302
|
-
* settles), awaits the bound handle's `isPersisted` promise, normalizes a thrown
|
|
303
|
-
* non-`Error`, and routes failure to `setError` (clearing it on success) before
|
|
304
|
-
* re-throwing. Each adapter (`@lunora/react`, `/solid`, `/svelte`, `/vue`) binds
|
|
305
|
-
* the two sinks to its own reactive setters, so this logic lives in exactly one
|
|
306
|
-
* place. The optimistic overlay + server push are owned by the bound handle.
|
|
307
|
-
*
|
|
308
|
-
* `error` tracks the LATEST invocation, not the last to settle: overlapping
|
|
309
|
-
* calls can resolve out of order, so an earlier call that finishes later must
|
|
310
|
-
* not clobber a newer call's outcome. Each invocation takes a monotonic token
|
|
311
|
-
* and only writes `setError` while it is still the most recent one — otherwise
|
|
312
|
-
* `error`/`isError` could surface a stale success or failure (the documented
|
|
313
|
-
* "latest invocation's error" contract every adapter advertises).
|
|
314
|
-
*/
|
|
297
|
+
* Build the framework-neutral `mutate` / `reset` pair of an adapter's
|
|
298
|
+
* custom-mutator hook (`useMutator` / `createMutator` / `mutator`).
|
|
299
|
+
*
|
|
300
|
+
* Owns the orchestration every adapter otherwise copy-pastes: ref-counts
|
|
301
|
+
* overlapping invocations into `setPending` (so it only clears once the last
|
|
302
|
+
* settles), awaits the bound handle's `isPersisted` promise, normalizes a thrown
|
|
303
|
+
* non-`Error`, and routes failure to `setError` (clearing it on success) before
|
|
304
|
+
* re-throwing. Each adapter (`@lunora/react`, `/solid`, `/svelte`, `/vue`) binds
|
|
305
|
+
* the two sinks to its own reactive setters, so this logic lives in exactly one
|
|
306
|
+
* place. The optimistic overlay + server push are owned by the bound handle.
|
|
307
|
+
*
|
|
308
|
+
* `error` tracks the LATEST invocation, not the last to settle: overlapping
|
|
309
|
+
* calls can resolve out of order, so an earlier call that finishes later must
|
|
310
|
+
* not clobber a newer call's outcome. Each invocation takes a monotonic token
|
|
311
|
+
* and only writes `setError` while it is still the most recent one — otherwise
|
|
312
|
+
* `error`/`isError` could surface a stale success or failure (the documented
|
|
313
|
+
* "latest invocation's error" contract every adapter advertises).
|
|
314
|
+
*/
|
|
315
315
|
declare const createMutatorRunner: <TArgs>(handle: MutatorHandle<TArgs>, sinks: MutatorRunnerSinks) => {
|
|
316
316
|
mutate: (args: TArgs) => Promise<void>;
|
|
317
317
|
reset: () => void;
|
|
@@ -322,31 +322,31 @@ interface QueuedMutation<T = unknown> {
|
|
|
322
322
|
/** Stable id used to remove the entry from durable storage once replayed; assigned by the queue when absent. */
|
|
323
323
|
id?: string;
|
|
324
324
|
/**
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
325
|
+
* Issuing identity fingerprint carried through to durable storage (`null` =
|
|
326
|
+
* signed out). Absent on hydrated legacy records, which replay ambiently.
|
|
327
|
+
*/
|
|
328
328
|
readonly identity?: string | null;
|
|
329
329
|
/**
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
330
|
+
* `true` when a live caller is still awaiting this write's `mutation()`
|
|
331
|
+
* Promise; `false`/absent for a write restored from durable storage after a
|
|
332
|
+
* reload (its original awaiter is gone). Carried so terminal-verdict
|
|
333
|
+
* observers can distinguish "the caller already saw this" from "nothing else
|
|
334
|
+
* will report this". Maps to the public `MutationSettledEvent.hadAwaiter`.
|
|
335
|
+
*/
|
|
336
336
|
liveAwaiter?: boolean;
|
|
337
337
|
/**
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
338
|
+
* Invoked on a successful replay with the server's echoed commit CDC cursor,
|
|
339
|
+
* so a live per-call optimistic layer drops gaplessly once a frame reaches it.
|
|
340
|
+
* Absent on hydrated records (the optimistic write lived in a prior session).
|
|
341
|
+
*/
|
|
342
342
|
readonly onCommit?: (commitCursor: number | undefined) => void;
|
|
343
343
|
/**
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
344
|
+
* Optional sync predicate evaluated just before replay. When it returns
|
|
345
|
+
* `false` the write is dropped instead of replaying, handling the case
|
|
346
|
+
* where the mutation's preconditions are no longer valid (e.g. the
|
|
347
|
+
* document it referred to was deleted while offline). Absent or `true`
|
|
348
|
+
* means "ok to replay".
|
|
349
|
+
*/
|
|
350
350
|
readonly precondition?: () => boolean;
|
|
351
351
|
/** Rejects if the mutation can no longer be replayed. */
|
|
352
352
|
readonly reject: (error: unknown) => void;
|
|
@@ -355,11 +355,11 @@ interface QueuedMutation<T = unknown> {
|
|
|
355
355
|
readonly shardKey?: string;
|
|
356
356
|
}
|
|
357
357
|
/**
|
|
358
|
-
* Invoked when the queue itself discards an entry on overflow (capacity
|
|
359
|
-
* eviction), so the client can surface the dropped write on its
|
|
360
|
-
* terminal-verdict observer even when the entry has no live awaiter (a hydrated
|
|
361
|
-
* record). The `error` carries the `OFFLINE_QUEUE_OVERFLOW` code.
|
|
362
|
-
*/
|
|
358
|
+
* Invoked when the queue itself discards an entry on overflow (capacity
|
|
359
|
+
* eviction), so the client can surface the dropped write on its
|
|
360
|
+
* terminal-verdict observer even when the entry has no live awaiter (a hydrated
|
|
361
|
+
* record). The `error` carries the `OFFLINE_QUEUE_OVERFLOW` code.
|
|
362
|
+
*/
|
|
363
363
|
type EvictHandler = (entry: QueuedMutation, error: Error & {
|
|
364
364
|
code?: string;
|
|
365
365
|
}) => void;
|
|
@@ -375,28 +375,17 @@ interface OfflineQueueDeps {
|
|
|
375
375
|
version?: string;
|
|
376
376
|
}
|
|
377
377
|
/**
|
|
378
|
-
*
|
|
379
|
-
*
|
|
380
|
-
*
|
|
381
|
-
*
|
|
382
|
-
*
|
|
383
|
-
*
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
* Bounded FIFO queue. Mutations issued while the client is offline are
|
|
390
|
-
* enqueued and replayed in the order they were submitted once the WS
|
|
391
|
-
* reconnects and identifies. If the queue exceeds `maxItems` the oldest
|
|
392
|
-
* entry is rejected with `OFFLINE_QUEUE_OVERFLOW`.
|
|
393
|
-
*
|
|
394
|
-
* When a {@link PersistenceAdapter} is supplied, enqueued mutations are mirrored
|
|
395
|
-
* to durable storage so they survive a reload — {@link OfflineQueue.hydrate} restores them on
|
|
396
|
-
* the next startup and the client replays them on reconnect. Durable removal is
|
|
397
|
-
* the caller's responsibility *after* a successful replay (see `LunoraClient`);
|
|
398
|
-
* the queue only persists on enqueue and un-persists on overflow.
|
|
399
|
-
*/
|
|
378
|
+
* Bounded FIFO queue. Mutations issued while the client is offline are
|
|
379
|
+
* enqueued and replayed in the order they were submitted once the WS
|
|
380
|
+
* reconnects and identifies. If the queue exceeds `maxItems` the oldest
|
|
381
|
+
* entry is rejected with `OFFLINE_QUEUE_OVERFLOW`.
|
|
382
|
+
*
|
|
383
|
+
* When a {@link PersistenceAdapter} is supplied, enqueued mutations are mirrored
|
|
384
|
+
* to durable storage so they survive a reload — {@link OfflineQueue.hydrate} restores them on
|
|
385
|
+
* the next startup and the client replays them on reconnect. Durable removal is
|
|
386
|
+
* the caller's responsibility *after* a successful replay (see `LunoraClient`);
|
|
387
|
+
* the queue only persists on enqueue and un-persists on overflow.
|
|
388
|
+
*/
|
|
400
389
|
declare class OfflineQueue {
|
|
401
390
|
/** Opt-in to queueing mutations before the targeted shard's first connect. */
|
|
402
391
|
readonly queueBeforeFirstConnect: boolean;
|
|
@@ -412,58 +401,58 @@ declare class OfflineQueue {
|
|
|
412
401
|
get size(): number;
|
|
413
402
|
enqueue<T>(entry: QueuedMutation<T>): void;
|
|
414
403
|
/**
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
404
|
+
* Restore mutations persisted in a prior session and re-queue them in FIFO
|
|
405
|
+
* order. Restored entries already live in durable storage, so they are not
|
|
406
|
+
* re-appended; they carry no-op `resolve`/`reject` (the original awaiter is
|
|
407
|
+
* gone after a reload). No-op when no persistence adapter is configured.
|
|
408
|
+
* Returns the distinct shard keys of the restored writes so the caller can
|
|
409
|
+
* open their sockets to trigger a flush.
|
|
410
|
+
*
|
|
411
|
+
* `hydrate()` runs post-construction (the caller awaits an async durable-store
|
|
412
|
+
* load), so a mutation issued while offline during that boot window is
|
|
413
|
+
* enqueued into `items` *before* this method's `await` resolves. Restored
|
|
414
|
+
* records are therefore `unshift`-ed ahead of whatever is already queued
|
|
415
|
+
* rather than `push`-ed to the end: the durable store's persist order is
|
|
416
|
+
* authoritative (a prior-session write is always older than anything from
|
|
417
|
+
* this session), so replaying a same-session boot-time write before an
|
|
418
|
+
* older restored write on the same document would let last-writer-wins
|
|
419
|
+
* silently clobber the newer data with the stale one.
|
|
420
|
+
*/
|
|
432
421
|
hydrate(): Promise<(string | undefined)[]>;
|
|
433
422
|
/**
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
423
|
+
* Remove and return queued mutations. With no `predicate`, drains the whole
|
|
424
|
+
* queue. With one, drains only matching entries (preserving FIFO order) and
|
|
425
|
+
* leaves the rest queued — used to flush a single shard's writes when its
|
|
426
|
+
* socket reconnects while other shards are still down.
|
|
427
|
+
*/
|
|
439
428
|
drain(predicate?: (item: QueuedMutation) => boolean): QueuedMutation[];
|
|
440
429
|
/**
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
430
|
+
* Return previously-drained mutations to the front of the queue, preserving
|
|
431
|
+
* their FIFO order, without re-persisting them — they were never unpersisted,
|
|
432
|
+
* so durable storage still holds them. Used when a flush aborts on a transient
|
|
433
|
+
* transport failure: the unreplayed writes stay queued for the next reconnect.
|
|
434
|
+
*/
|
|
446
435
|
requeue(items: QueuedMutation[]): void;
|
|
447
436
|
/**
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
437
|
+
* Remove mutations whose precondition evaluates to `false` (stale/dirty
|
|
438
|
+
* writes that should not replay) and reject each with an
|
|
439
|
+
* `OFFLINE_PRECONDITION_FAILED` error. The valid (admitted) mutations stay
|
|
440
|
+
* queued in FIFO order. Returns the drained stale entries.
|
|
441
|
+
*
|
|
442
|
+
* Called during reconnect before the flush cycle to weed out writes whose
|
|
443
|
+
* assumptions no longer hold (e.g. a document was deleted by another client).
|
|
444
|
+
*/
|
|
456
445
|
drainConflict(): QueuedMutation[];
|
|
457
446
|
clear(): void;
|
|
458
447
|
/** Notify the size observer (the client's pending-sync count) after any change. */
|
|
459
448
|
private notifySize;
|
|
460
449
|
}
|
|
461
450
|
/**
|
|
462
|
-
* In-memory {@link PersistenceAdapter}. Doesn't survive a reload — it exists so
|
|
463
|
-
* the persistence wiring can be exercised without IndexedDB (tests, SSR, or as
|
|
464
|
-
* a deliberate "no durable store" choice that still satisfies the interface).
|
|
465
|
-
* Preserves enqueue order; `clone` keeps callers from mutating stored args.
|
|
466
|
-
*/
|
|
451
|
+
* In-memory {@link PersistenceAdapter}. Doesn't survive a reload — it exists so
|
|
452
|
+
* the persistence wiring can be exercised without IndexedDB (tests, SSR, or as
|
|
453
|
+
* a deliberate "no durable store" choice that still satisfies the interface).
|
|
454
|
+
* Preserves enqueue order; `clone` keeps callers from mutating stored args.
|
|
455
|
+
*/
|
|
467
456
|
declare const createInMemoryPersistence: () => PersistenceAdapter;
|
|
468
457
|
interface IndexedDbPersistenceOptions {
|
|
469
458
|
/** Database name; defaults to `"lunora-outbox"` (its own DB, separate from the read cache). */
|
|
@@ -474,47 +463,29 @@ interface IndexedDbPersistenceOptions {
|
|
|
474
463
|
storeName?: string;
|
|
475
464
|
}
|
|
476
465
|
/**
|
|
477
|
-
* IndexedDB-backed {@link PersistenceAdapter}. Each mutation is stored under an
|
|
478
|
-
* autoincrementing key (so `load()` returns them in enqueue order regardless of
|
|
479
|
-
* the string ids) with a unique secondary index on `id` for `remove()`.
|
|
480
|
-
*
|
|
481
|
-
* The store handle is opened lazily and the open promise is cached, so repeated
|
|
482
|
-
* ops reuse one connection. Throws eagerly if no `IDBFactory` is available —
|
|
483
|
-
* callers in non-browser environments should use {@link createInMemoryPersistence}.
|
|
484
|
-
*/
|
|
466
|
+
* IndexedDB-backed {@link PersistenceAdapter}. Each mutation is stored under an
|
|
467
|
+
* autoincrementing key (so `load()` returns them in enqueue order regardless of
|
|
468
|
+
* the string ids) with a unique secondary index on `id` for `remove()`.
|
|
469
|
+
*
|
|
470
|
+
* The store handle is opened lazily and the open promise is cached, so repeated
|
|
471
|
+
* ops reuse one connection. Throws eagerly if no `IDBFactory` is available —
|
|
472
|
+
* callers in non-browser environments should use {@link createInMemoryPersistence}.
|
|
473
|
+
*/
|
|
485
474
|
declare const createIndexedDbPersistence: (options?: IndexedDbPersistenceOptions) => PersistenceAdapter;
|
|
486
475
|
/**
|
|
487
|
-
*
|
|
488
|
-
*
|
|
489
|
-
*
|
|
490
|
-
*
|
|
491
|
-
|
|
492
|
-
* IndexedDB when the global is present (browsers) and `autoProbe` is set,
|
|
493
|
-
* otherwise `undefined` — so SSR/Node/React-Native keep today's in-memory
|
|
494
|
-
* behaviour and only environments that can persist do.
|
|
495
|
-
*
|
|
496
|
-
* `autoProbe` is `false` when the `@lunora/db` outbox is wired: that sink is the
|
|
497
|
-
* single durable write path, so the built-in queue must stay in memory rather
|
|
498
|
-
* than persist a second, never-flushed copy. An explicit adapter is still
|
|
499
|
-
* honoured (the caller asked for it); only the implicit default is suppressed.
|
|
500
|
-
*
|
|
501
|
-
* The IndexedDB adapter opens its connection lazily, so constructing it here is
|
|
502
|
-
* cheap and never throws (the `indexedDB` global is verified present first).
|
|
503
|
-
*/
|
|
504
|
-
/**
|
|
505
|
-
* Compose the read-cache key for a subscription. Mirrors how
|
|
506
|
-
* `SubscriptionRegistry` keys live subscriptions so a hydrated value lines up
|
|
507
|
-
* with the subscription that will consume it. `shardKey` defaults to `""` (the
|
|
508
|
-
* root shard) exactly as the registry does.
|
|
509
|
-
*/
|
|
476
|
+
* Compose the read-cache key for a subscription. Mirrors how
|
|
477
|
+
* `SubscriptionRegistry` keys live subscriptions so a hydrated value lines up
|
|
478
|
+
* with the subscription that will consume it. `shardKey` defaults to `""` (the
|
|
479
|
+
* root shard) exactly as the registry does.
|
|
480
|
+
*/
|
|
510
481
|
declare const queryCacheKey: (functionPath: string, argsKey: string, shardKey?: string) => string;
|
|
511
482
|
/**
|
|
512
|
-
* In-memory {@link QueryCacheAdapter}. Doesn't survive a reload — it exists so
|
|
513
|
-
* the read-cache wiring can be exercised without IndexedDB (tests, SSR, or as a
|
|
514
|
-
* deliberate "no durable store" choice that still satisfies the interface).
|
|
515
|
-
* Enforces the same LRU row cap as the IndexedDB adapter; `clone` keeps callers
|
|
516
|
-
* from mutating stored values.
|
|
517
|
-
*/
|
|
483
|
+
* In-memory {@link QueryCacheAdapter}. Doesn't survive a reload — it exists so
|
|
484
|
+
* the read-cache wiring can be exercised without IndexedDB (tests, SSR, or as a
|
|
485
|
+
* deliberate "no durable store" choice that still satisfies the interface).
|
|
486
|
+
* Enforces the same LRU row cap as the IndexedDB adapter; `clone` keeps callers
|
|
487
|
+
* from mutating stored values.
|
|
488
|
+
*/
|
|
518
489
|
declare const createInMemoryQueryCache: (options?: {
|
|
519
490
|
maxEntries?: number;
|
|
520
491
|
}) => QueryCacheAdapter;
|
|
@@ -529,34 +500,25 @@ interface IndexedDbQueryCacheOptions {
|
|
|
529
500
|
storeName?: string;
|
|
530
501
|
}
|
|
531
502
|
/**
|
|
532
|
-
* IndexedDB-backed {@link QueryCacheAdapter}. Each query is stored under its
|
|
533
|
-
* composite key (`functionPath::argsKey::shardKey`) with a `ts` index driving
|
|
534
|
-
* LRU eviction. The store handle is opened lazily and cached, so repeated ops
|
|
535
|
-
* reuse one connection.
|
|
536
|
-
*
|
|
537
|
-
* The store lives in its own `lunora-query-cache` database — deliberately
|
|
538
|
-
* separate from the offline-mutation outbox's `lunora-outbox` database so the two
|
|
539
|
-
* independently-toggleable adapters never share (and drift on) a schema version.
|
|
540
|
-
* Throws eagerly if no `IDBFactory` is available — callers in non-browser
|
|
541
|
-
* environments should use {@link createInMemoryQueryCache}.
|
|
542
|
-
*/
|
|
503
|
+
* IndexedDB-backed {@link QueryCacheAdapter}. Each query is stored under its
|
|
504
|
+
* composite key (`functionPath::argsKey::shardKey`) with a `ts` index driving
|
|
505
|
+
* LRU eviction. The store handle is opened lazily and cached, so repeated ops
|
|
506
|
+
* reuse one connection.
|
|
507
|
+
*
|
|
508
|
+
* The store lives in its own `lunora-query-cache` database — deliberately
|
|
509
|
+
* separate from the offline-mutation outbox's `lunora-outbox` database so the two
|
|
510
|
+
* independently-toggleable adapters never share (and drift on) a schema version.
|
|
511
|
+
* Throws eagerly if no `IDBFactory` is available — callers in non-browser
|
|
512
|
+
* environments should use {@link createInMemoryQueryCache}.
|
|
513
|
+
*/
|
|
543
514
|
declare const createIndexedDbQueryCache: (options?: IndexedDbQueryCacheOptions) => QueryCacheAdapter;
|
|
544
515
|
/**
|
|
545
|
-
*
|
|
546
|
-
*
|
|
547
|
-
* `
|
|
548
|
-
*
|
|
549
|
-
*
|
|
550
|
-
|
|
551
|
-
* - `undefined` (the default) auto-probes IndexedDB (browsers), else `undefined`.
|
|
552
|
-
*/
|
|
553
|
-
/**
|
|
554
|
-
* Exponential backoff calculator with optional jitter.
|
|
555
|
-
*
|
|
556
|
-
* `next()` doubles the delay each call up to `maxDelayMs`. When `jitter` is
|
|
557
|
-
* enabled the returned value is randomized in `[delay/2, delay]` so a fleet
|
|
558
|
-
* of clients reconnecting at the same time spread out their retries.
|
|
559
|
-
*/
|
|
516
|
+
* Exponential backoff calculator with optional jitter.
|
|
517
|
+
*
|
|
518
|
+
* `next()` doubles the delay each call up to `maxDelayMs`. When `jitter` is
|
|
519
|
+
* enabled the returned value is randomized in `[delay/2, delay]` so a fleet
|
|
520
|
+
* of clients reconnecting at the same time spread out their retries.
|
|
521
|
+
*/
|
|
560
522
|
interface ReconnectCalculator {
|
|
561
523
|
/** Returns the delay to wait before the next reconnect attempt. */
|
|
562
524
|
next: () => number;
|
|
@@ -565,34 +527,34 @@ interface ReconnectCalculator {
|
|
|
565
527
|
}
|
|
566
528
|
declare const createReconnect: (options?: ReconnectOptions, random?: () => number) => ReconnectCalculator;
|
|
567
529
|
/**
|
|
568
|
-
* Capture a snapshot of the current live query value at call time and produce a
|
|
569
|
-
* `() => boolean` precondition that compares it against the value at replay time.
|
|
570
|
-
*
|
|
571
|
-
* When the precondition is checked (on queue drain / reconnect) it re-reads the
|
|
572
|
-
* query's current value via {@link LunoraClient.peekActiveQueryValue}. If the
|
|
573
|
-
* value differs from what was captured at call time the precondition returns
|
|
574
|
-
* `false` and the offline mutation is dropped as stale.
|
|
575
|
-
* @example
|
|
576
|
-
* ```ts
|
|
577
|
-
* client.mutation(api.todos.update, { id, text }, {
|
|
578
|
-
* precondition: createSnapshotPrecondition(client, api.todos.list, { userId }),
|
|
579
|
-
* });
|
|
580
|
-
* ```
|
|
581
|
-
*/
|
|
530
|
+
* Capture a snapshot of the current live query value at call time and produce a
|
|
531
|
+
* `() => boolean` precondition that compares it against the value at replay time.
|
|
532
|
+
*
|
|
533
|
+
* When the precondition is checked (on queue drain / reconnect) it re-reads the
|
|
534
|
+
* query's current value via {@link LunoraClient.peekActiveQueryValue}. If the
|
|
535
|
+
* value differs from what was captured at call time the precondition returns
|
|
536
|
+
* `false` and the offline mutation is dropped as stale.
|
|
537
|
+
* @example
|
|
538
|
+
* ```ts
|
|
539
|
+
* client.mutation(api.todos.update, { id, text }, {
|
|
540
|
+
* precondition: createSnapshotPrecondition(client, api.todos.list, { userId }),
|
|
541
|
+
* });
|
|
542
|
+
* ```
|
|
543
|
+
*/
|
|
582
544
|
declare const createSnapshotPrecondition: (client: LunoraClient, functionRef: FunctionReference, args: Record<string, unknown>, shardKey?: string) => (() => boolean);
|
|
583
545
|
/**
|
|
584
|
-
* Client-side service-worker registration and lifecycle management.
|
|
585
|
-
*
|
|
586
|
-
* Usage:
|
|
587
|
-
* ```ts
|
|
588
|
-
* const sw = new ClientServiceWorker({ swUrl: "/sw.js" });
|
|
589
|
-
* await sw.register();
|
|
590
|
-
*
|
|
591
|
-
* if (sw.active) {
|
|
592
|
-
* sw.postMessage({ type: "sync" });
|
|
593
|
-
* }
|
|
594
|
-
* ```
|
|
595
|
-
*/
|
|
546
|
+
* Client-side service-worker registration and lifecycle management.
|
|
547
|
+
*
|
|
548
|
+
* Usage:
|
|
549
|
+
* ```ts
|
|
550
|
+
* const sw = new ClientServiceWorker({ swUrl: "/sw.js" });
|
|
551
|
+
* await sw.register();
|
|
552
|
+
*
|
|
553
|
+
* if (sw.active) {
|
|
554
|
+
* sw.postMessage({ type: "sync" });
|
|
555
|
+
* }
|
|
556
|
+
* ```
|
|
557
|
+
*/
|
|
596
558
|
type ServiceWorkerStatus = "unsupported" | "unregistered" | "registering" | "active" | "error";
|
|
597
559
|
interface ClientSwOptions {
|
|
598
560
|
/** Called when the status changes. */
|
|
@@ -603,9 +565,9 @@ interface ClientSwOptions {
|
|
|
603
565
|
swUrl: string;
|
|
604
566
|
}
|
|
605
567
|
/**
|
|
606
|
-
* Manages service-worker registration and provides a simple API for
|
|
607
|
-
* sending messages and listening for responses.
|
|
608
|
-
*/
|
|
568
|
+
* Manages service-worker registration and provides a simple API for
|
|
569
|
+
* sending messages and listening for responses.
|
|
570
|
+
*/
|
|
609
571
|
declare class ClientServiceWorker {
|
|
610
572
|
#private;
|
|
611
573
|
readonly swUrl: string;
|
|
@@ -618,30 +580,30 @@ declare class ClientServiceWorker {
|
|
|
618
580
|
/** Whether the SW is currently controlling this page. */
|
|
619
581
|
get active(): boolean;
|
|
620
582
|
/**
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
583
|
+
* Register the service worker.
|
|
584
|
+
*
|
|
585
|
+
* Returns `false` when the browser does not support service workers.
|
|
586
|
+
*/
|
|
625
587
|
register(): Promise<boolean>;
|
|
626
588
|
/**
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
589
|
+
* Remove the active service worker registration and clear listeners.
|
|
590
|
+
*
|
|
591
|
+
* Returns `false` when no registration is currently held.
|
|
592
|
+
*/
|
|
631
593
|
unregister(): Promise<boolean>;
|
|
632
594
|
/**
|
|
633
|
-
|
|
634
|
-
|
|
595
|
+
* Send a message to the active service worker.
|
|
596
|
+
*/
|
|
635
597
|
postMessage(message: unknown): void;
|
|
636
598
|
/**
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
599
|
+
* Register a handler for messages **from** the service worker.
|
|
600
|
+
* @returns Unsubscribe function.
|
|
601
|
+
*/
|
|
640
602
|
onMessage(handler: (event: MessageEvent) => void): () => void;
|
|
641
603
|
}
|
|
642
604
|
/**
|
|
643
|
-
* Outbound message from the client to the SW.
|
|
644
|
-
*/
|
|
605
|
+
* Outbound message from the client to the SW.
|
|
606
|
+
*/
|
|
645
607
|
interface ClientToSwMessage {
|
|
646
608
|
/** Opaque correlation ID for request/response patterns. */
|
|
647
609
|
correlationId?: string;
|
|
@@ -649,8 +611,8 @@ interface ClientToSwMessage {
|
|
|
649
611
|
type: string;
|
|
650
612
|
}
|
|
651
613
|
/**
|
|
652
|
-
* Inbound message from the SW to the client.
|
|
653
|
-
*/
|
|
614
|
+
* Inbound message from the SW to the client.
|
|
615
|
+
*/
|
|
654
616
|
interface SwToClientMessage {
|
|
655
617
|
/** Echoes the correlation ID from the client request, if any. */
|
|
656
618
|
correlationId?: string;
|
|
@@ -658,14 +620,14 @@ interface SwToClientMessage {
|
|
|
658
620
|
type: string;
|
|
659
621
|
}
|
|
660
622
|
/**
|
|
661
|
-
* Send a typed message to the service worker and optionally await a
|
|
662
|
-
* matching response.
|
|
663
|
-
* @returns A promise that resolves when the SW sends a reply with the
|
|
664
|
-
* same `correlationId` (if `expectResponse` is true).
|
|
665
|
-
*/
|
|
623
|
+
* Send a typed message to the service worker and optionally await a
|
|
624
|
+
* matching response.
|
|
625
|
+
* @returns A promise that resolves when the SW sends a reply with the
|
|
626
|
+
* same `correlationId` (if `expectResponse` is true).
|
|
627
|
+
*/
|
|
666
628
|
declare const sendToSw: (sw: ServiceWorker | null, message: ClientToSwMessage, expectResponse?: boolean) => Promise<unknown>;
|
|
667
629
|
/**
|
|
668
|
-
* Create a reply for a client message (call from inside the SW).
|
|
669
|
-
*/
|
|
630
|
+
* Create a reply for a client message (call from inside the SW).
|
|
631
|
+
*/
|
|
670
632
|
declare const createReply: (original: ClientToSwMessage, payload?: unknown) => SwToClientMessage;
|
|
671
633
|
export { type ArgsOf, type AsyncStorageLike, type AsyncStoragePersistenceOptions, type BookmarkStorage, ClientServiceWorker, type ClientSwOptions, type ClientToSwMessage, type FunctionReference, type HttpStreamArgsOf, type HttpStreamChunkOf, type HttpStreamOptions, type HttpStreamRef, type IndexedDbPersistenceOptions, type IndexedDbQueryCacheOptions, LunoraClient, type MutationCallOptions, type MutationDelta, type MutationRunnerSinks, type MutatorHandle, type MutatorRunnerSinks, type MutatorTransaction, OfflineQueue, type OfflineQueueOptions, type PersistenceAdapter, type QueryCacheAdapter, type QueuedMutation, type ReconnectCalculator, type ReconnectOptions, type ReturnOf, type ServiceWorkerStatus, type StreamIterable, type SubscriptionError, type SwToClientMessage, TabCoordinator, applyDelta, createAsyncStoragePersistence, createInMemoryBookmarkStorage, createInMemoryPersistence, createInMemoryQueryCache, createIndexedDbPersistence, createIndexedDbQueryCache, createMutationRunner, createMutatorRunner, createReconnect, createReply, createSnapshotPrecondition, httpStream, isMutationDelta, queryCacheKey, sendToSw };
|