@lunora/client 0.0.0 → 1.0.0-alpha.2
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/LICENSE.md +105 -0
- package/README.md +111 -9
- package/__assets__/package-og.svg +14 -0
- package/dist/auth/index.d.mts +20 -0
- package/dist/auth/index.d.ts +20 -0
- package/dist/auth/index.mjs +60 -0
- package/dist/index.d.mts +281 -0
- package/dist/index.d.ts +281 -0
- package/dist/index.mjs +14 -0
- package/dist/packem_shared/CONFLICT_ERROR_CODE-aUdVbEDw.mjs +4 -0
- package/dist/packem_shared/DEFAULT_MAX_BUFFER-BDkqO5PW.mjs +107 -0
- package/dist/packem_shared/LunoraClient-UiULzH_1.mjs +2165 -0
- package/dist/packem_shared/OfflineQueue-D5p_QgF_.mjs +127 -0
- package/dist/packem_shared/SKIP-vItZChkw.mjs +50 -0
- package/dist/packem_shared/SubscriptionRegistry-B-Qx_Gux.mjs +26 -0
- package/dist/packem_shared/applyDelta-4jFGTPA3.mjs +61 -0
- package/dist/packem_shared/createAsyncStoragePersistence-1Z5BZ8RC.mjs +45 -0
- package/dist/packem_shared/createInMemoryBookmarkStorage-BoN7a7TH.mjs +11 -0
- package/dist/packem_shared/createInMemoryPersistence-CW82inU5.mjs +105 -0
- package/dist/packem_shared/createInMemoryQueryCache-B1PQ9Twl.mjs +138 -0
- package/dist/packem_shared/createLocalStore-DSUfoLqY.mjs +36 -0
- package/dist/packem_shared/createMutationRunner-BqsavzvG.mjs +21 -0
- package/dist/packem_shared/createReconnect-Di_-oHH7.mjs +22 -0
- package/dist/packem_shared/createServerClient-BjZc3gD8.mjs +11 -0
- package/dist/packem_shared/deserializePreloaded-C0eJTY_W.mjs +4 -0
- package/dist/packem_shared/getServerSession-8jXewqxd.mjs +13 -0
- package/dist/packem_shared/lunora-client.d-DGvyuJ_p.d.mts +1597 -0
- package/dist/packem_shared/lunora-client.d-DGvyuJ_p.d.ts +1597 -0
- package/dist/packem_shared/preload.d-BoDmFqSG.d.ts +20 -0
- package/dist/packem_shared/preload.d-dSaRMuhL.d.mts +20 -0
- package/dist/packem_shared/preloadQuery-lobFkD2Z.mjs +13 -0
- package/dist/pagination/index.d.mts +82 -0
- package/dist/pagination/index.d.ts +82 -0
- package/dist/pagination/index.mjs +61 -0
- package/dist/query/index.d.mts +62 -0
- package/dist/query/index.d.ts +62 -0
- package/dist/query/index.mjs +1 -0
- package/dist/ssr/index.d.mts +115 -0
- package/dist/ssr/index.d.ts +115 -0
- package/dist/ssr/index.mjs +4 -0
- package/package.json +53 -17
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { U as User, L as LunoraClient } from "../packem_shared/lunora-client.d-DGvyuJ_p.mjs";
|
|
2
|
+
import '@lunora/runtime';
|
|
3
|
+
interface IdentityStore {
|
|
4
|
+
/** Read the current resolved user, or `null` when signed out / not yet resolved. */
|
|
5
|
+
getUser: () => User | null;
|
|
6
|
+
/**
|
|
7
|
+
* Subscribe to identity changes. `onChange` is called whenever the user or
|
|
8
|
+
* token changes. Returns an unsubscribe handle.
|
|
9
|
+
*/
|
|
10
|
+
subscribe: (onChange: () => void) => () => void;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Return the per-client identity store, creating it on first access.
|
|
14
|
+
*
|
|
15
|
+
* The store is cached via a `WeakMap` so it is GC'd when the client is dropped,
|
|
16
|
+
* and creation is idempotent — calling this multiple times with the same client
|
|
17
|
+
* returns the same store, keeping the single-fetch / fan-out invariant.
|
|
18
|
+
*/
|
|
19
|
+
declare const getIdentityStore: (client: LunoraClient) => IdentityStore;
|
|
20
|
+
export { type IdentityStore, getIdentityStore };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { U as User, L as LunoraClient } from "../packem_shared/lunora-client.d-DGvyuJ_p.js";
|
|
2
|
+
import '@lunora/runtime';
|
|
3
|
+
interface IdentityStore {
|
|
4
|
+
/** Read the current resolved user, or `null` when signed out / not yet resolved. */
|
|
5
|
+
getUser: () => User | null;
|
|
6
|
+
/**
|
|
7
|
+
* Subscribe to identity changes. `onChange` is called whenever the user or
|
|
8
|
+
* token changes. Returns an unsubscribe handle.
|
|
9
|
+
*/
|
|
10
|
+
subscribe: (onChange: () => void) => () => void;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Return the per-client identity store, creating it on first access.
|
|
14
|
+
*
|
|
15
|
+
* The store is cached via a `WeakMap` so it is GC'd when the client is dropped,
|
|
16
|
+
* and creation is idempotent — calling this multiple times with the same client
|
|
17
|
+
* returns the same store, keeping the single-fetch / fan-out invariant.
|
|
18
|
+
*/
|
|
19
|
+
declare const getIdentityStore: (client: LunoraClient) => IdentityStore;
|
|
20
|
+
export { type IdentityStore, getIdentityStore };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
const stores = /* @__PURE__ */ new WeakMap();
|
|
2
|
+
const createIdentityStore = (client) => {
|
|
3
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
4
|
+
let user = null;
|
|
5
|
+
let started = false;
|
|
6
|
+
const notify = () => {
|
|
7
|
+
for (const listener of listeners) {
|
|
8
|
+
listener();
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
let generation = 0;
|
|
12
|
+
const setUser = (next) => {
|
|
13
|
+
if (user !== next) {
|
|
14
|
+
user = next;
|
|
15
|
+
notify();
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const refresh = () => {
|
|
19
|
+
generation += 1;
|
|
20
|
+
const current = generation;
|
|
21
|
+
if (client.getAuthToken() === null) {
|
|
22
|
+
setUser(null);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
client.getCurrentUser().then((next) => {
|
|
26
|
+
if (current === generation) {
|
|
27
|
+
setUser(next);
|
|
28
|
+
}
|
|
29
|
+
return void 0;
|
|
30
|
+
}).catch(() => {
|
|
31
|
+
if (current === generation) {
|
|
32
|
+
setUser(null);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
client.onAuthTokenChange(refresh);
|
|
37
|
+
return {
|
|
38
|
+
getUser: () => user,
|
|
39
|
+
subscribe: (onChange) => {
|
|
40
|
+
listeners.add(onChange);
|
|
41
|
+
if (!started) {
|
|
42
|
+
started = true;
|
|
43
|
+
refresh();
|
|
44
|
+
}
|
|
45
|
+
return () => {
|
|
46
|
+
listeners.delete(onChange);
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
const getIdentityStore = (client) => {
|
|
52
|
+
let store = stores.get(client);
|
|
53
|
+
if (!store) {
|
|
54
|
+
store = createIdentityStore(client);
|
|
55
|
+
stores.set(client, store);
|
|
56
|
+
}
|
|
57
|
+
return store;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export { getIdentityStore };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { c as PersistenceAdapter, B as BookmarkStorage, F as FunctionReference, A as ArgsOf, M as MutationCallOptions, R as ReturnOf, O as OfflineQueueOptions, Q as QueryCacheAdapter, d as ReconnectOptions } from "./packem_shared/lunora-client.d-DGvyuJ_p.mjs";
|
|
2
|
+
export { type C as CachedQuery, type e as ClientMessage, type f as ConnectionStatus, D as DEFAULT_MAX_BUFFER, type g as FunctionArgumentDescriptor, type h as FunctionDescriptor, type G as GlobalFacetResult, type i as GlobalFacetValue, type j as GlobalFilterClause, type k as GlobalTableInfo, type l as GlobalTablePage, L as LunoraClient, type m as LunoraClientOptions, type n as OptimisticLocalStore, type o as OptimisticUpdate, type p as PersistedMutation, type P as Preloaded, type q as RpcEnvelope, type r as RpcResponseBody, type s as ScheduleRecord, type t as SchedulerPoolStatus, type u as SchedulerStatus, type v as ServerMessage, type w as ShardTrafficEntry, type x as ShardTrafficResult, type y as StorageListPage, type z as StorageObject, type E as StreamHandle, type H as StreamIterable, type I as SubscriptionCallback, type S as SubscriptionError, type b as SubscriptionErrorCallback, J as SubscriptionRegistry, type K as SubscriptionState, type a as Unsubscribe, type U as User, type W as WorkflowInstanceAction, type N as WorkflowInstanceDetail, type T as WorkflowInstancePage, type V as WorkflowInstanceStatus, type X as WorkflowInstanceSummary, type Y as WorkflowStepDetail, Z as createLocalStore, _ as createStream } from "./packem_shared/lunora-client.d-DGvyuJ_p.mjs";
|
|
3
|
+
export { p as preloadQuery, a as preloadedQueryResult } from "./packem_shared/preload.d-dSaRMuhL.mjs";
|
|
4
|
+
export type { AuthCapabilities, AuthImpersonation, AuthPage, AuthSession, AuthUser, CronJobInfo, 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
|
+
interface AsyncStorageLike {
|
|
12
|
+
getItem: (key: string) => Promise<string | null>;
|
|
13
|
+
removeItem: (key: string) => Promise<void>;
|
|
14
|
+
setItem: (key: string, value: string) => Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
interface AsyncStoragePersistenceOptions {
|
|
17
|
+
/** Storage key the FIFO mutation log is serialized under; defaults to `"lunora:offline-mutations"`. */
|
|
18
|
+
key?: string;
|
|
19
|
+
/** The async key/value store the log is read from and written to (e.g. React Native `AsyncStorage`). */
|
|
20
|
+
storage: AsyncStorageLike;
|
|
21
|
+
}
|
|
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
|
+
*/
|
|
33
|
+
declare const createAsyncStoragePersistence: (options: AsyncStoragePersistenceOptions) => PersistenceAdapter;
|
|
34
|
+
/** Default in-memory bookmark store. Survives the lifetime of the client. */
|
|
35
|
+
declare const createInMemoryBookmarkStorage: () => BookmarkStorage;
|
|
36
|
+
/**
|
|
37
|
+
* Client-side incremental merging of structured mutation deltas.
|
|
38
|
+
*
|
|
39
|
+
* Lunora's live-query fan-out has two server paths:
|
|
40
|
+
*
|
|
41
|
+
* 1. Server re-execution (subscriptions carrying a `functionPath`) pushes a
|
|
42
|
+
* full `data` snapshot whenever a write touches a table the query reads. These
|
|
43
|
+
* already carry the authoritative result and are applied wholesale.
|
|
44
|
+
* 2. Legacy delta fan-out (`broadcastDelta`) pushes a structured `MutationDelta`
|
|
45
|
+
* as a `delta` frame to subscribers matched by table + args. The delta describes
|
|
46
|
+
* a single row change (`insert` / `update` / `delete`) keyed by row id, so the
|
|
47
|
+
* client can splice it into the cached list result without a full re-send.
|
|
48
|
+
*
|
|
49
|
+
* Historically the client treated the `delta` field as an opaque blob and
|
|
50
|
+
* replaced the whole cached value with it on every message — which only made
|
|
51
|
+
* sense for the rare delta payloads that already carried the full result. This
|
|
52
|
+
* module lets the client recognise a structured delta and merge it into the
|
|
53
|
+
* existing array (preserving order, no dup/loss), falling back to full
|
|
54
|
+
* replacement when the payload isn't a recognisable row delta or can't be
|
|
55
|
+
* applied cleanly against the current cached shape.
|
|
56
|
+
*/
|
|
57
|
+
/**
|
|
58
|
+
* One row change as emitted by `@lunora/do`'s `broadcastDelta`. Mirrors
|
|
59
|
+
* `MutationDelta` in `@lunora/do` structurally so the client carries no
|
|
60
|
+
* dependency on it. `row` is absent on `delete` events (and may be absent on
|
|
61
|
+
* older servers for any op).
|
|
62
|
+
*/
|
|
63
|
+
interface MutationDelta {
|
|
64
|
+
/** Row id (`_id`) the change applies to. */
|
|
65
|
+
key: string;
|
|
66
|
+
op: "delete" | "insert" | "update";
|
|
67
|
+
row?: Record<string, unknown>;
|
|
68
|
+
table: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Structural guard: is `value` a `MutationDelta` the client knows how to merge?
|
|
72
|
+
* We require `op`, `table`, and a string `key` so opaque payloads that merely
|
|
73
|
+
* happen to be objects (e.g. an aggregate `{ count: 1 }` a query returns
|
|
74
|
+
* verbatim) are never mistaken for a row delta and keep replacing the cached
|
|
75
|
+
* value wholesale.
|
|
76
|
+
*/
|
|
77
|
+
declare const isMutationDelta: (value: unknown) => value is MutationDelta;
|
|
78
|
+
/**
|
|
79
|
+
* Apply a structured `MutationDelta` to a cached array result, returning a new
|
|
80
|
+
* array (never mutating the input). Returns `undefined` when the delta can't be
|
|
81
|
+
* applied cleanly — the caller should then fall back to the existing
|
|
82
|
+
* full-replacement behaviour (or trust the next snapshot to reconcile).
|
|
83
|
+
*
|
|
84
|
+
* Mergeable shape: a plain array of id-bearing row objects, e.g. the result of
|
|
85
|
+
* `db.query().collect()`.
|
|
86
|
+
*
|
|
87
|
+
* Insert / update / delete are matched by row `_id`:
|
|
88
|
+
* - `insert`: appended (or placed by `_creationTime` order) if absent; treated
|
|
89
|
+
* as an update if a row with the same id already exists (idempotent — guards
|
|
90
|
+
* against a delta replayed after a snapshot already included it).
|
|
91
|
+
* - `update`: replaces the matching row in place, preserving its position.
|
|
92
|
+
* - `delete`: removes the matching row.
|
|
93
|
+
*
|
|
94
|
+
* Returns `undefined` when `current` isn't an array of id-keyable objects, or
|
|
95
|
+
* when an `insert`/`update` delta carries no `row` to splice in.
|
|
96
|
+
*/
|
|
97
|
+
declare const applyDelta: (current: unknown, delta: MutationDelta) => undefined | unknown[];
|
|
98
|
+
/** Error code the server uses for optimistic-concurrency conflicts (HTTP 409). */
|
|
99
|
+
declare const CONFLICT_ERROR_CODE = "CONFLICT";
|
|
100
|
+
/**
|
|
101
|
+
* Whether an unknown rejection is an optimistic-concurrency conflict — the
|
|
102
|
+
* server lost a write race and the caller should refetch and retry (or surface
|
|
103
|
+
* the conflict). Structural check on the `code` property the client attaches
|
|
104
|
+
* when decoding the worker's `{ error: { code, message } }` envelope.
|
|
105
|
+
*/
|
|
106
|
+
declare const isConflictError: (error: unknown) => error is Error & {
|
|
107
|
+
code: "CONFLICT";
|
|
108
|
+
};
|
|
109
|
+
/** The single transport method a mutation runner needs — narrowed so adapters can test against a stub. */
|
|
110
|
+
interface MutationCapableClient<F extends FunctionReference> {
|
|
111
|
+
mutation: (function_: F, args: ArgsOf<F>, options?: MutationCallOptions<unknown, unknown, ArgsOf<F>>) => Promise<ReturnOf<F>>;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Reactive sinks an adapter binds to its own primitive's setters (a Solid
|
|
115
|
+
* signal, a Vue ref, a Svelte store). The runner pushes into them; how they
|
|
116
|
+
* store the value is the adapter's concern (e.g. Solid wraps function-valued
|
|
117
|
+
* results in a thunk).
|
|
118
|
+
*/
|
|
119
|
+
interface MutationRunnerSinks<R> {
|
|
120
|
+
/** Receives the normalized {@link Error} when an invocation rejects. */
|
|
121
|
+
setError: (error: Error) => void;
|
|
122
|
+
/** Receives `true` while at least one invocation is in flight (ref-counted across overlapping calls), else `false`. */
|
|
123
|
+
setPending: (pending: boolean) => void;
|
|
124
|
+
/** Receives the resolved value when an invocation succeeds. */
|
|
125
|
+
setResult: (result: R) => void;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Build the framework-neutral `mutate` half of an adapter's mutation hook.
|
|
129
|
+
*
|
|
130
|
+
* Owns the orchestration every adapter otherwise copy-pastes: ref-counts
|
|
131
|
+
* overlapping invocations into `setPending` (so it only clears once the last
|
|
132
|
+
* settles), normalizes a thrown non-`Error`, and routes success/failure to
|
|
133
|
+
* `setResult`/`setError` before re-throwing. Each adapter (`@lunora/react`,
|
|
134
|
+
* `/solid`, `/svelte`, `/vue`) binds the three sinks to its own reactive
|
|
135
|
+
* setters, so this logic lives in exactly one place. Optimistic-update options
|
|
136
|
+
* pass straight through to `client.mutation`.
|
|
137
|
+
*/
|
|
138
|
+
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>>);
|
|
139
|
+
interface QueuedMutation<T = unknown> {
|
|
140
|
+
readonly args: Record<string, unknown>;
|
|
141
|
+
readonly functionPath: string;
|
|
142
|
+
/** Stable id used to remove the entry from durable storage once replayed; assigned by the queue when absent. */
|
|
143
|
+
id?: string;
|
|
144
|
+
/**
|
|
145
|
+
* Issuing identity fingerprint carried through to durable storage (`null` =
|
|
146
|
+
* signed out). Absent on hydrated legacy records, which replay ambiently.
|
|
147
|
+
*/
|
|
148
|
+
readonly identity?: string | null;
|
|
149
|
+
/** Rejects if the mutation can no longer be replayed. */
|
|
150
|
+
readonly reject: (error: unknown) => void;
|
|
151
|
+
/** Resolves once the mutation has been replayed against the server. */
|
|
152
|
+
readonly resolve: (value: T) => void;
|
|
153
|
+
readonly shardKey?: string;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Bounded FIFO queue. Mutations issued while the client is offline are
|
|
157
|
+
* enqueued and replayed in the order they were submitted once the WS
|
|
158
|
+
* reconnects and identifies. If the queue exceeds `maxItems` the oldest
|
|
159
|
+
* entry is rejected with `OFFLINE_QUEUE_OVERFLOW`.
|
|
160
|
+
*
|
|
161
|
+
* When a {@link PersistenceAdapter} is supplied, enqueued mutations are mirrored
|
|
162
|
+
* to durable storage so they survive a reload — {@link OfflineQueue.hydrate} restores them on
|
|
163
|
+
* the next startup and the client replays them on reconnect. Durable removal is
|
|
164
|
+
* the caller's responsibility *after* a successful replay (see `LunoraClient`);
|
|
165
|
+
* the queue only persists on enqueue and un-persists on overflow.
|
|
166
|
+
*/
|
|
167
|
+
declare class OfflineQueue {
|
|
168
|
+
/** Opt-in to queueing mutations before the targeted shard's first connect. */
|
|
169
|
+
readonly queueBeforeFirstConnect: boolean;
|
|
170
|
+
private readonly maxItems;
|
|
171
|
+
private readonly onPersistenceError;
|
|
172
|
+
private readonly persistence;
|
|
173
|
+
private readonly items;
|
|
174
|
+
constructor(options?: OfflineQueueOptions, persistence?: PersistenceAdapter);
|
|
175
|
+
get size(): number;
|
|
176
|
+
enqueue<T>(entry: QueuedMutation<T>): void;
|
|
177
|
+
/**
|
|
178
|
+
* Restore mutations persisted in a prior session and re-queue them in FIFO
|
|
179
|
+
* order. Restored entries already live in durable storage, so they are not
|
|
180
|
+
* re-appended; they carry no-op `resolve`/`reject` (the original awaiter is
|
|
181
|
+
* gone after a reload). No-op when no persistence adapter is configured.
|
|
182
|
+
* Returns the distinct shard keys of the restored writes so the caller can
|
|
183
|
+
* open their sockets to trigger a flush.
|
|
184
|
+
*/
|
|
185
|
+
hydrate(): Promise<(string | undefined)[]>;
|
|
186
|
+
/**
|
|
187
|
+
* Remove and return queued mutations. With no `predicate`, drains the whole
|
|
188
|
+
* queue. With one, drains only matching entries (preserving FIFO order) and
|
|
189
|
+
* leaves the rest queued — used to flush a single shard's writes when its
|
|
190
|
+
* socket reconnects while other shards are still down.
|
|
191
|
+
*/
|
|
192
|
+
drain(predicate?: (item: QueuedMutation) => boolean): QueuedMutation[];
|
|
193
|
+
/**
|
|
194
|
+
* Return previously-drained mutations to the front of the queue, preserving
|
|
195
|
+
* their FIFO order, without re-persisting them — they were never unpersisted,
|
|
196
|
+
* so durable storage still holds them. Used when a flush aborts on a transient
|
|
197
|
+
* transport failure: the unreplayed writes stay queued for the next reconnect.
|
|
198
|
+
*/
|
|
199
|
+
requeue(items: QueuedMutation[]): void;
|
|
200
|
+
clear(): void;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* In-memory {@link PersistenceAdapter}. Doesn't survive a reload — it exists so
|
|
204
|
+
* the persistence wiring can be exercised without IndexedDB (tests, SSR, or as
|
|
205
|
+
* a deliberate "no durable store" choice that still satisfies the interface).
|
|
206
|
+
* Preserves enqueue order; `clone` keeps callers from mutating stored args.
|
|
207
|
+
*/
|
|
208
|
+
declare const createInMemoryPersistence: () => PersistenceAdapter;
|
|
209
|
+
interface IndexedDbPersistenceOptions {
|
|
210
|
+
/** Database name; defaults to `"lunora"`. */
|
|
211
|
+
databaseName?: string;
|
|
212
|
+
/** Injectable `IDBFactory` (e.g. `fake-indexeddb` in tests); defaults to the global `indexedDB`. */
|
|
213
|
+
indexedDB?: IDBFactory;
|
|
214
|
+
/** Object-store name; defaults to `"offline-mutations"`. */
|
|
215
|
+
storeName?: string;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* IndexedDB-backed {@link PersistenceAdapter}. Each mutation is stored under an
|
|
219
|
+
* autoincrementing key (so `load()` returns them in enqueue order regardless of
|
|
220
|
+
* the string ids) with a unique secondary index on `id` for `remove()`.
|
|
221
|
+
*
|
|
222
|
+
* The store handle is opened lazily and the open promise is cached, so repeated
|
|
223
|
+
* ops reuse one connection. Throws eagerly if no `IDBFactory` is available —
|
|
224
|
+
* callers in non-browser environments should use {@link createInMemoryPersistence}.
|
|
225
|
+
*/
|
|
226
|
+
declare const createIndexedDbPersistence: (options?: IndexedDbPersistenceOptions) => PersistenceAdapter;
|
|
227
|
+
/**
|
|
228
|
+
* Compose the read-cache key for a subscription. Mirrors how
|
|
229
|
+
* `SubscriptionRegistry` keys live subscriptions so a hydrated value lines up
|
|
230
|
+
* with the subscription that will consume it. `shardKey` defaults to `""` (the
|
|
231
|
+
* root shard) exactly as the registry does.
|
|
232
|
+
*/
|
|
233
|
+
declare const queryCacheKey: (functionPath: string, argsKey: string, shardKey?: string) => string;
|
|
234
|
+
/**
|
|
235
|
+
* In-memory {@link QueryCacheAdapter}. Doesn't survive a reload — it exists so
|
|
236
|
+
* the read-cache wiring can be exercised without IndexedDB (tests, SSR, or as a
|
|
237
|
+
* deliberate "no durable store" choice that still satisfies the interface).
|
|
238
|
+
* Enforces the same LRU row cap as the IndexedDB adapter; `clone` keeps callers
|
|
239
|
+
* from mutating stored values.
|
|
240
|
+
*/
|
|
241
|
+
declare const createInMemoryQueryCache: (options?: {
|
|
242
|
+
maxEntries?: number;
|
|
243
|
+
}) => QueryCacheAdapter;
|
|
244
|
+
interface IndexedDbQueryCacheOptions {
|
|
245
|
+
/** Database name; defaults to `"lunora"` (shared with the offline-mutation store). */
|
|
246
|
+
databaseName?: string;
|
|
247
|
+
/** Injectable `IDBFactory` (e.g. `fake-indexeddb` in tests); defaults to the global `indexedDB`. */
|
|
248
|
+
indexedDB?: IDBFactory;
|
|
249
|
+
/** LRU row cap; defaults to 500. The oldest rows by `ts` are pruned on `put` once exceeded. */
|
|
250
|
+
maxEntries?: number;
|
|
251
|
+
/** Object-store name; defaults to `"query-cache"`. */
|
|
252
|
+
storeName?: string;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* IndexedDB-backed {@link QueryCacheAdapter}. Each query is stored under its
|
|
256
|
+
* composite key (`functionPath::argsKey::shardKey`) with a `ts` index driving
|
|
257
|
+
* LRU eviction. The store handle is opened lazily and cached, so repeated ops
|
|
258
|
+
* reuse one connection.
|
|
259
|
+
*
|
|
260
|
+
* The store lives in the same `lunora` database as the offline-mutation queue
|
|
261
|
+
* (bumped to schema v2). Opening it upgrades a v1 database in place, adding the
|
|
262
|
+
* `query-cache` store without touching `offline-mutations`. Throws eagerly if no
|
|
263
|
+
* `IDBFactory` is available — callers in non-browser environments should use
|
|
264
|
+
* {@link createInMemoryQueryCache}.
|
|
265
|
+
*/
|
|
266
|
+
declare const createIndexedDbQueryCache: (options?: IndexedDbQueryCacheOptions) => QueryCacheAdapter;
|
|
267
|
+
/**
|
|
268
|
+
* Exponential backoff calculator with optional jitter.
|
|
269
|
+
*
|
|
270
|
+
* `next()` doubles the delay each call up to `maxDelayMs`. When `jitter` is
|
|
271
|
+
* enabled the returned value is randomized in `[delay/2, delay]` so a fleet
|
|
272
|
+
* of clients reconnecting at the same time spread out their retries.
|
|
273
|
+
*/
|
|
274
|
+
interface ReconnectCalculator {
|
|
275
|
+
/** Returns the delay to wait before the next reconnect attempt. */
|
|
276
|
+
next: () => number;
|
|
277
|
+
/** Resets the backoff to the initial delay (call on successful reconnect). */
|
|
278
|
+
reset: () => void;
|
|
279
|
+
}
|
|
280
|
+
declare const createReconnect: (options?: ReconnectOptions, random?: () => number) => ReconnectCalculator;
|
|
281
|
+
export { type ArgsOf, type AsyncStorageLike, type AsyncStoragePersistenceOptions, type BookmarkStorage, CONFLICT_ERROR_CODE, type FunctionReference, type IndexedDbPersistenceOptions, type IndexedDbQueryCacheOptions, type MutationCallOptions, type MutationDelta, type MutationRunnerSinks, OfflineQueue, type OfflineQueueOptions, type PersistenceAdapter, type QueryCacheAdapter, type QueuedMutation, type ReconnectCalculator, type ReconnectOptions, type ReturnOf, applyDelta, createAsyncStoragePersistence, createInMemoryBookmarkStorage, createInMemoryPersistence, createInMemoryQueryCache, createIndexedDbPersistence, createIndexedDbQueryCache, createMutationRunner, createReconnect, isConflictError, isMutationDelta, queryCacheKey };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { c as PersistenceAdapter, B as BookmarkStorage, F as FunctionReference, A as ArgsOf, M as MutationCallOptions, R as ReturnOf, O as OfflineQueueOptions, Q as QueryCacheAdapter, d as ReconnectOptions } from "./packem_shared/lunora-client.d-DGvyuJ_p.js";
|
|
2
|
+
export { type C as CachedQuery, type e as ClientMessage, type f as ConnectionStatus, D as DEFAULT_MAX_BUFFER, type g as FunctionArgumentDescriptor, type h as FunctionDescriptor, type G as GlobalFacetResult, type i as GlobalFacetValue, type j as GlobalFilterClause, type k as GlobalTableInfo, type l as GlobalTablePage, L as LunoraClient, type m as LunoraClientOptions, type n as OptimisticLocalStore, type o as OptimisticUpdate, type p as PersistedMutation, type P as Preloaded, type q as RpcEnvelope, type r as RpcResponseBody, type s as ScheduleRecord, type t as SchedulerPoolStatus, type u as SchedulerStatus, type v as ServerMessage, type w as ShardTrafficEntry, type x as ShardTrafficResult, type y as StorageListPage, type z as StorageObject, type E as StreamHandle, type H as StreamIterable, type I as SubscriptionCallback, type S as SubscriptionError, type b as SubscriptionErrorCallback, J as SubscriptionRegistry, type K as SubscriptionState, type a as Unsubscribe, type U as User, type W as WorkflowInstanceAction, type N as WorkflowInstanceDetail, type T as WorkflowInstancePage, type V as WorkflowInstanceStatus, type X as WorkflowInstanceSummary, type Y as WorkflowStepDetail, Z as createLocalStore, _ as createStream } from "./packem_shared/lunora-client.d-DGvyuJ_p.js";
|
|
3
|
+
export { p as preloadQuery, a as preloadedQueryResult } from "./packem_shared/preload.d-BoDmFqSG.js";
|
|
4
|
+
export type { AuthCapabilities, AuthImpersonation, AuthPage, AuthSession, AuthUser, CronJobInfo, 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
|
+
interface AsyncStorageLike {
|
|
12
|
+
getItem: (key: string) => Promise<string | null>;
|
|
13
|
+
removeItem: (key: string) => Promise<void>;
|
|
14
|
+
setItem: (key: string, value: string) => Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
interface AsyncStoragePersistenceOptions {
|
|
17
|
+
/** Storage key the FIFO mutation log is serialized under; defaults to `"lunora:offline-mutations"`. */
|
|
18
|
+
key?: string;
|
|
19
|
+
/** The async key/value store the log is read from and written to (e.g. React Native `AsyncStorage`). */
|
|
20
|
+
storage: AsyncStorageLike;
|
|
21
|
+
}
|
|
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
|
+
*/
|
|
33
|
+
declare const createAsyncStoragePersistence: (options: AsyncStoragePersistenceOptions) => PersistenceAdapter;
|
|
34
|
+
/** Default in-memory bookmark store. Survives the lifetime of the client. */
|
|
35
|
+
declare const createInMemoryBookmarkStorage: () => BookmarkStorage;
|
|
36
|
+
/**
|
|
37
|
+
* Client-side incremental merging of structured mutation deltas.
|
|
38
|
+
*
|
|
39
|
+
* Lunora's live-query fan-out has two server paths:
|
|
40
|
+
*
|
|
41
|
+
* 1. Server re-execution (subscriptions carrying a `functionPath`) pushes a
|
|
42
|
+
* full `data` snapshot whenever a write touches a table the query reads. These
|
|
43
|
+
* already carry the authoritative result and are applied wholesale.
|
|
44
|
+
* 2. Legacy delta fan-out (`broadcastDelta`) pushes a structured `MutationDelta`
|
|
45
|
+
* as a `delta` frame to subscribers matched by table + args. The delta describes
|
|
46
|
+
* a single row change (`insert` / `update` / `delete`) keyed by row id, so the
|
|
47
|
+
* client can splice it into the cached list result without a full re-send.
|
|
48
|
+
*
|
|
49
|
+
* Historically the client treated the `delta` field as an opaque blob and
|
|
50
|
+
* replaced the whole cached value with it on every message — which only made
|
|
51
|
+
* sense for the rare delta payloads that already carried the full result. This
|
|
52
|
+
* module lets the client recognise a structured delta and merge it into the
|
|
53
|
+
* existing array (preserving order, no dup/loss), falling back to full
|
|
54
|
+
* replacement when the payload isn't a recognisable row delta or can't be
|
|
55
|
+
* applied cleanly against the current cached shape.
|
|
56
|
+
*/
|
|
57
|
+
/**
|
|
58
|
+
* One row change as emitted by `@lunora/do`'s `broadcastDelta`. Mirrors
|
|
59
|
+
* `MutationDelta` in `@lunora/do` structurally so the client carries no
|
|
60
|
+
* dependency on it. `row` is absent on `delete` events (and may be absent on
|
|
61
|
+
* older servers for any op).
|
|
62
|
+
*/
|
|
63
|
+
interface MutationDelta {
|
|
64
|
+
/** Row id (`_id`) the change applies to. */
|
|
65
|
+
key: string;
|
|
66
|
+
op: "delete" | "insert" | "update";
|
|
67
|
+
row?: Record<string, unknown>;
|
|
68
|
+
table: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Structural guard: is `value` a `MutationDelta` the client knows how to merge?
|
|
72
|
+
* We require `op`, `table`, and a string `key` so opaque payloads that merely
|
|
73
|
+
* happen to be objects (e.g. an aggregate `{ count: 1 }` a query returns
|
|
74
|
+
* verbatim) are never mistaken for a row delta and keep replacing the cached
|
|
75
|
+
* value wholesale.
|
|
76
|
+
*/
|
|
77
|
+
declare const isMutationDelta: (value: unknown) => value is MutationDelta;
|
|
78
|
+
/**
|
|
79
|
+
* Apply a structured `MutationDelta` to a cached array result, returning a new
|
|
80
|
+
* array (never mutating the input). Returns `undefined` when the delta can't be
|
|
81
|
+
* applied cleanly — the caller should then fall back to the existing
|
|
82
|
+
* full-replacement behaviour (or trust the next snapshot to reconcile).
|
|
83
|
+
*
|
|
84
|
+
* Mergeable shape: a plain array of id-bearing row objects, e.g. the result of
|
|
85
|
+
* `db.query().collect()`.
|
|
86
|
+
*
|
|
87
|
+
* Insert / update / delete are matched by row `_id`:
|
|
88
|
+
* - `insert`: appended (or placed by `_creationTime` order) if absent; treated
|
|
89
|
+
* as an update if a row with the same id already exists (idempotent — guards
|
|
90
|
+
* against a delta replayed after a snapshot already included it).
|
|
91
|
+
* - `update`: replaces the matching row in place, preserving its position.
|
|
92
|
+
* - `delete`: removes the matching row.
|
|
93
|
+
*
|
|
94
|
+
* Returns `undefined` when `current` isn't an array of id-keyable objects, or
|
|
95
|
+
* when an `insert`/`update` delta carries no `row` to splice in.
|
|
96
|
+
*/
|
|
97
|
+
declare const applyDelta: (current: unknown, delta: MutationDelta) => undefined | unknown[];
|
|
98
|
+
/** Error code the server uses for optimistic-concurrency conflicts (HTTP 409). */
|
|
99
|
+
declare const CONFLICT_ERROR_CODE = "CONFLICT";
|
|
100
|
+
/**
|
|
101
|
+
* Whether an unknown rejection is an optimistic-concurrency conflict — the
|
|
102
|
+
* server lost a write race and the caller should refetch and retry (or surface
|
|
103
|
+
* the conflict). Structural check on the `code` property the client attaches
|
|
104
|
+
* when decoding the worker's `{ error: { code, message } }` envelope.
|
|
105
|
+
*/
|
|
106
|
+
declare const isConflictError: (error: unknown) => error is Error & {
|
|
107
|
+
code: "CONFLICT";
|
|
108
|
+
};
|
|
109
|
+
/** The single transport method a mutation runner needs — narrowed so adapters can test against a stub. */
|
|
110
|
+
interface MutationCapableClient<F extends FunctionReference> {
|
|
111
|
+
mutation: (function_: F, args: ArgsOf<F>, options?: MutationCallOptions<unknown, unknown, ArgsOf<F>>) => Promise<ReturnOf<F>>;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Reactive sinks an adapter binds to its own primitive's setters (a Solid
|
|
115
|
+
* signal, a Vue ref, a Svelte store). The runner pushes into them; how they
|
|
116
|
+
* store the value is the adapter's concern (e.g. Solid wraps function-valued
|
|
117
|
+
* results in a thunk).
|
|
118
|
+
*/
|
|
119
|
+
interface MutationRunnerSinks<R> {
|
|
120
|
+
/** Receives the normalized {@link Error} when an invocation rejects. */
|
|
121
|
+
setError: (error: Error) => void;
|
|
122
|
+
/** Receives `true` while at least one invocation is in flight (ref-counted across overlapping calls), else `false`. */
|
|
123
|
+
setPending: (pending: boolean) => void;
|
|
124
|
+
/** Receives the resolved value when an invocation succeeds. */
|
|
125
|
+
setResult: (result: R) => void;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Build the framework-neutral `mutate` half of an adapter's mutation hook.
|
|
129
|
+
*
|
|
130
|
+
* Owns the orchestration every adapter otherwise copy-pastes: ref-counts
|
|
131
|
+
* overlapping invocations into `setPending` (so it only clears once the last
|
|
132
|
+
* settles), normalizes a thrown non-`Error`, and routes success/failure to
|
|
133
|
+
* `setResult`/`setError` before re-throwing. Each adapter (`@lunora/react`,
|
|
134
|
+
* `/solid`, `/svelte`, `/vue`) binds the three sinks to its own reactive
|
|
135
|
+
* setters, so this logic lives in exactly one place. Optimistic-update options
|
|
136
|
+
* pass straight through to `client.mutation`.
|
|
137
|
+
*/
|
|
138
|
+
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>>);
|
|
139
|
+
interface QueuedMutation<T = unknown> {
|
|
140
|
+
readonly args: Record<string, unknown>;
|
|
141
|
+
readonly functionPath: string;
|
|
142
|
+
/** Stable id used to remove the entry from durable storage once replayed; assigned by the queue when absent. */
|
|
143
|
+
id?: string;
|
|
144
|
+
/**
|
|
145
|
+
* Issuing identity fingerprint carried through to durable storage (`null` =
|
|
146
|
+
* signed out). Absent on hydrated legacy records, which replay ambiently.
|
|
147
|
+
*/
|
|
148
|
+
readonly identity?: string | null;
|
|
149
|
+
/** Rejects if the mutation can no longer be replayed. */
|
|
150
|
+
readonly reject: (error: unknown) => void;
|
|
151
|
+
/** Resolves once the mutation has been replayed against the server. */
|
|
152
|
+
readonly resolve: (value: T) => void;
|
|
153
|
+
readonly shardKey?: string;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Bounded FIFO queue. Mutations issued while the client is offline are
|
|
157
|
+
* enqueued and replayed in the order they were submitted once the WS
|
|
158
|
+
* reconnects and identifies. If the queue exceeds `maxItems` the oldest
|
|
159
|
+
* entry is rejected with `OFFLINE_QUEUE_OVERFLOW`.
|
|
160
|
+
*
|
|
161
|
+
* When a {@link PersistenceAdapter} is supplied, enqueued mutations are mirrored
|
|
162
|
+
* to durable storage so they survive a reload — {@link OfflineQueue.hydrate} restores them on
|
|
163
|
+
* the next startup and the client replays them on reconnect. Durable removal is
|
|
164
|
+
* the caller's responsibility *after* a successful replay (see `LunoraClient`);
|
|
165
|
+
* the queue only persists on enqueue and un-persists on overflow.
|
|
166
|
+
*/
|
|
167
|
+
declare class OfflineQueue {
|
|
168
|
+
/** Opt-in to queueing mutations before the targeted shard's first connect. */
|
|
169
|
+
readonly queueBeforeFirstConnect: boolean;
|
|
170
|
+
private readonly maxItems;
|
|
171
|
+
private readonly onPersistenceError;
|
|
172
|
+
private readonly persistence;
|
|
173
|
+
private readonly items;
|
|
174
|
+
constructor(options?: OfflineQueueOptions, persistence?: PersistenceAdapter);
|
|
175
|
+
get size(): number;
|
|
176
|
+
enqueue<T>(entry: QueuedMutation<T>): void;
|
|
177
|
+
/**
|
|
178
|
+
* Restore mutations persisted in a prior session and re-queue them in FIFO
|
|
179
|
+
* order. Restored entries already live in durable storage, so they are not
|
|
180
|
+
* re-appended; they carry no-op `resolve`/`reject` (the original awaiter is
|
|
181
|
+
* gone after a reload). No-op when no persistence adapter is configured.
|
|
182
|
+
* Returns the distinct shard keys of the restored writes so the caller can
|
|
183
|
+
* open their sockets to trigger a flush.
|
|
184
|
+
*/
|
|
185
|
+
hydrate(): Promise<(string | undefined)[]>;
|
|
186
|
+
/**
|
|
187
|
+
* Remove and return queued mutations. With no `predicate`, drains the whole
|
|
188
|
+
* queue. With one, drains only matching entries (preserving FIFO order) and
|
|
189
|
+
* leaves the rest queued — used to flush a single shard's writes when its
|
|
190
|
+
* socket reconnects while other shards are still down.
|
|
191
|
+
*/
|
|
192
|
+
drain(predicate?: (item: QueuedMutation) => boolean): QueuedMutation[];
|
|
193
|
+
/**
|
|
194
|
+
* Return previously-drained mutations to the front of the queue, preserving
|
|
195
|
+
* their FIFO order, without re-persisting them — they were never unpersisted,
|
|
196
|
+
* so durable storage still holds them. Used when a flush aborts on a transient
|
|
197
|
+
* transport failure: the unreplayed writes stay queued for the next reconnect.
|
|
198
|
+
*/
|
|
199
|
+
requeue(items: QueuedMutation[]): void;
|
|
200
|
+
clear(): void;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* In-memory {@link PersistenceAdapter}. Doesn't survive a reload — it exists so
|
|
204
|
+
* the persistence wiring can be exercised without IndexedDB (tests, SSR, or as
|
|
205
|
+
* a deliberate "no durable store" choice that still satisfies the interface).
|
|
206
|
+
* Preserves enqueue order; `clone` keeps callers from mutating stored args.
|
|
207
|
+
*/
|
|
208
|
+
declare const createInMemoryPersistence: () => PersistenceAdapter;
|
|
209
|
+
interface IndexedDbPersistenceOptions {
|
|
210
|
+
/** Database name; defaults to `"lunora"`. */
|
|
211
|
+
databaseName?: string;
|
|
212
|
+
/** Injectable `IDBFactory` (e.g. `fake-indexeddb` in tests); defaults to the global `indexedDB`. */
|
|
213
|
+
indexedDB?: IDBFactory;
|
|
214
|
+
/** Object-store name; defaults to `"offline-mutations"`. */
|
|
215
|
+
storeName?: string;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* IndexedDB-backed {@link PersistenceAdapter}. Each mutation is stored under an
|
|
219
|
+
* autoincrementing key (so `load()` returns them in enqueue order regardless of
|
|
220
|
+
* the string ids) with a unique secondary index on `id` for `remove()`.
|
|
221
|
+
*
|
|
222
|
+
* The store handle is opened lazily and the open promise is cached, so repeated
|
|
223
|
+
* ops reuse one connection. Throws eagerly if no `IDBFactory` is available —
|
|
224
|
+
* callers in non-browser environments should use {@link createInMemoryPersistence}.
|
|
225
|
+
*/
|
|
226
|
+
declare const createIndexedDbPersistence: (options?: IndexedDbPersistenceOptions) => PersistenceAdapter;
|
|
227
|
+
/**
|
|
228
|
+
* Compose the read-cache key for a subscription. Mirrors how
|
|
229
|
+
* `SubscriptionRegistry` keys live subscriptions so a hydrated value lines up
|
|
230
|
+
* with the subscription that will consume it. `shardKey` defaults to `""` (the
|
|
231
|
+
* root shard) exactly as the registry does.
|
|
232
|
+
*/
|
|
233
|
+
declare const queryCacheKey: (functionPath: string, argsKey: string, shardKey?: string) => string;
|
|
234
|
+
/**
|
|
235
|
+
* In-memory {@link QueryCacheAdapter}. Doesn't survive a reload — it exists so
|
|
236
|
+
* the read-cache wiring can be exercised without IndexedDB (tests, SSR, or as a
|
|
237
|
+
* deliberate "no durable store" choice that still satisfies the interface).
|
|
238
|
+
* Enforces the same LRU row cap as the IndexedDB adapter; `clone` keeps callers
|
|
239
|
+
* from mutating stored values.
|
|
240
|
+
*/
|
|
241
|
+
declare const createInMemoryQueryCache: (options?: {
|
|
242
|
+
maxEntries?: number;
|
|
243
|
+
}) => QueryCacheAdapter;
|
|
244
|
+
interface IndexedDbQueryCacheOptions {
|
|
245
|
+
/** Database name; defaults to `"lunora"` (shared with the offline-mutation store). */
|
|
246
|
+
databaseName?: string;
|
|
247
|
+
/** Injectable `IDBFactory` (e.g. `fake-indexeddb` in tests); defaults to the global `indexedDB`. */
|
|
248
|
+
indexedDB?: IDBFactory;
|
|
249
|
+
/** LRU row cap; defaults to 500. The oldest rows by `ts` are pruned on `put` once exceeded. */
|
|
250
|
+
maxEntries?: number;
|
|
251
|
+
/** Object-store name; defaults to `"query-cache"`. */
|
|
252
|
+
storeName?: string;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* IndexedDB-backed {@link QueryCacheAdapter}. Each query is stored under its
|
|
256
|
+
* composite key (`functionPath::argsKey::shardKey`) with a `ts` index driving
|
|
257
|
+
* LRU eviction. The store handle is opened lazily and cached, so repeated ops
|
|
258
|
+
* reuse one connection.
|
|
259
|
+
*
|
|
260
|
+
* The store lives in the same `lunora` database as the offline-mutation queue
|
|
261
|
+
* (bumped to schema v2). Opening it upgrades a v1 database in place, adding the
|
|
262
|
+
* `query-cache` store without touching `offline-mutations`. Throws eagerly if no
|
|
263
|
+
* `IDBFactory` is available — callers in non-browser environments should use
|
|
264
|
+
* {@link createInMemoryQueryCache}.
|
|
265
|
+
*/
|
|
266
|
+
declare const createIndexedDbQueryCache: (options?: IndexedDbQueryCacheOptions) => QueryCacheAdapter;
|
|
267
|
+
/**
|
|
268
|
+
* Exponential backoff calculator with optional jitter.
|
|
269
|
+
*
|
|
270
|
+
* `next()` doubles the delay each call up to `maxDelayMs`. When `jitter` is
|
|
271
|
+
* enabled the returned value is randomized in `[delay/2, delay]` so a fleet
|
|
272
|
+
* of clients reconnecting at the same time spread out their retries.
|
|
273
|
+
*/
|
|
274
|
+
interface ReconnectCalculator {
|
|
275
|
+
/** Returns the delay to wait before the next reconnect attempt. */
|
|
276
|
+
next: () => number;
|
|
277
|
+
/** Resets the backoff to the initial delay (call on successful reconnect). */
|
|
278
|
+
reset: () => void;
|
|
279
|
+
}
|
|
280
|
+
declare const createReconnect: (options?: ReconnectOptions, random?: () => number) => ReconnectCalculator;
|
|
281
|
+
export { type ArgsOf, type AsyncStorageLike, type AsyncStoragePersistenceOptions, type BookmarkStorage, CONFLICT_ERROR_CODE, type FunctionReference, type IndexedDbPersistenceOptions, type IndexedDbQueryCacheOptions, type MutationCallOptions, type MutationDelta, type MutationRunnerSinks, OfflineQueue, type OfflineQueueOptions, type PersistenceAdapter, type QueryCacheAdapter, type QueuedMutation, type ReconnectCalculator, type ReconnectOptions, type ReturnOf, applyDelta, createAsyncStoragePersistence, createInMemoryBookmarkStorage, createInMemoryPersistence, createInMemoryQueryCache, createIndexedDbPersistence, createIndexedDbQueryCache, createMutationRunner, createReconnect, isConflictError, isMutationDelta, queryCacheKey };
|