@lunora/client 1.0.0-alpha.10 → 1.0.0-alpha.12

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.
@@ -0,0 +1 @@
1
+ export { S as SubscriptionRegistry } from './subscription-DoyO04-2.mjs';
@@ -101,5 +101,17 @@ const createIndexedDbPersistence = (options = {}) => {
101
101
  }
102
102
  };
103
103
  };
104
+ const resolvePersistenceAdapter = (option, autoProbe = true) => {
105
+ if (option === false) {
106
+ return void 0;
107
+ }
108
+ if (option) {
109
+ return option;
110
+ }
111
+ if (!autoProbe || typeof indexedDB === "undefined") {
112
+ return void 0;
113
+ }
114
+ return createIndexedDbPersistence();
115
+ };
104
116
 
105
- export { createInMemoryPersistence, createIndexedDbPersistence };
117
+ export { createInMemoryPersistence, createIndexedDbPersistence, resolvePersistenceAdapter };
@@ -134,5 +134,17 @@ const createIndexedDbQueryCache = (options = {}) => {
134
134
  }
135
135
  };
136
136
  };
137
+ const resolveQueryCacheAdapter = (option) => {
138
+ if (option === false) {
139
+ return void 0;
140
+ }
141
+ if (option) {
142
+ return option;
143
+ }
144
+ if (typeof indexedDB === "undefined") {
145
+ return void 0;
146
+ }
147
+ return createIndexedDbQueryCache();
148
+ };
137
149
 
138
- export { createInMemoryQueryCache, createIndexedDbQueryCache, queryCacheKey };
150
+ export { createInMemoryQueryCache, createIndexedDbQueryCache, queryCacheKey, resolveQueryCacheAdapter };
@@ -1,4 +1,4 @@
1
- import { LunoraClient } from './LunoraClient-CgZ6FhKP.mjs';
1
+ import { LunoraClient } from './LunoraClient-wh6w9Ivn.mjs';
2
2
 
3
3
  const createServerClient = (options) => {
4
4
  const client = new LunoraClient({ fetch: options.fetch, url: options.url });
@@ -271,8 +271,16 @@ interface LunoraClientOptions {
271
271
  * standalone client, which keeps using {@link LunoraClientOptions.persistence}.
272
272
  */
273
273
  outbox?: OutboxSink;
274
- /** Durable store for the offline mutation queue; omit to keep it in memory. */
275
- persistence?: PersistenceAdapter;
274
+ /**
275
+ * Durable store for the offline mutation queue. Tri-state — an explicit
276
+ * {@link PersistenceAdapter} is used as-is; `false` opts out (the queue stays
277
+ * in memory, lost on reload); omitted (the default) auto-probes a durable
278
+ * IndexedDB store when the `indexedDB` global is present (browsers), otherwise
279
+ * in-memory, so SSR/Node/React-Native keep the in-memory behaviour and only
280
+ * environments that can persist do. Pass `createAsyncStoragePersistence()` on
281
+ * React Native.
282
+ */
283
+ persistence?: false | PersistenceAdapter;
276
284
  /**
277
285
  * App/schema version stamped onto every persisted queued write and cached
278
286
  * read. Bump it on a breaking change to a function signature or query shape:
@@ -289,11 +297,13 @@ interface LunoraClientOptions {
289
297
  */
290
298
  persistenceVersion?: string;
291
299
  /**
292
- * Durable store for the read cache (Pillar 2). When supplied, query results
300
+ * Durable store for the read cache (Pillar 2). When active, query results
293
301
  * are persisted as their subscriptions advance and hydrated on construction
294
302
  * so a reload renders cached data before the socket reconnects, then resumes
295
- * the live subscription from the persisted cursor. Omit (or pass `false`) to
296
- * keep reads in memory only the default, unchanged behaviour.
303
+ * the live subscription from the persisted cursor. Tri-state an explicit
304
+ * {@link QueryCacheAdapter} is used as-is; `false` opts out (reads stay in
305
+ * memory only); omitted (the default) auto-probes IndexedDB exactly like
306
+ * {@link LunoraClientOptions.persistence}.
297
307
  */
298
308
  queryCache?: QueryCacheAdapter | false;
299
309
  reconnect?: ReconnectOptions;
@@ -348,6 +358,7 @@ interface RpcEnvelope {
348
358
  type RpcResponseBody = {
349
359
  error: {
350
360
  code: string;
361
+ data?: unknown;
351
362
  message: string;
352
363
  };
353
364
  } | {
@@ -1141,6 +1152,19 @@ interface SyncWatermark {
1141
1152
  checkpoint?: number;
1142
1153
  mutationId?: number;
1143
1154
  }
1155
+ /** An `Error` carrying the server's machine-readable `code` and (for a `LunoraError`) structured `data`. The client's public error contract for RPC/batch failures. */
1156
+ type LunoraClientError = Error & {
1157
+ code?: string;
1158
+ data?: unknown;
1159
+ };
1160
+ /** One demuxed result slot of a {@link LunoraClient.batch} call (plan 088). */
1161
+ type BatchSlot = {
1162
+ error: LunoraClientError;
1163
+ ok: false;
1164
+ } | {
1165
+ ok: true;
1166
+ value: unknown;
1167
+ };
1144
1168
  /**
1145
1169
  * Lunora browser/edge client. Talks RPC over HTTP and real-time deltas over
1146
1170
  * a single multiplexed WebSocket.
@@ -1488,6 +1512,25 @@ declare class LunoraClient {
1488
1512
  shardKey?: string;
1489
1513
  }): Promise<ReturnOf<F>>;
1490
1514
  /**
1515
+ * Batch several independent calls into ONE round trip (plan 088). Each call is
1516
+ * dispatched server-side exactly as an individual RPC — per-shard
1517
+ * authorization, `(identity, mutationId)` idempotency, and custom-mutator
1518
+ * watermark ordering are all preserved — and the worker splits the batch by
1519
+ * shard so calls to different shards fan out to their own DOs. Results are
1520
+ * demuxed back in input order; a failing call does NOT fail the batch (its
1521
+ * slot carries `{ ok: false, error }`, with `.code`/`.data` reconstructed like
1522
+ * a single call). Args/results ride the value codec (bytes/bigint survive).
1523
+ *
1524
+ * No promise pipelining and no capability passing — a call's args cannot
1525
+ * reference another call's result (see plan 088 §fence; capabilities are
1526
+ * incompatible with DO hibernation).
1527
+ */
1528
+ batch(calls: ReadonlyArray<{
1529
+ args?: Record<string, unknown>;
1530
+ fn: FunctionReference;
1531
+ shardKey?: string;
1532
+ }>): Promise<BatchSlot[]>;
1533
+ /**
1491
1534
  * Invoke a mutation. Errors propagate as rejections.
1492
1535
  *
1493
1536
  * Offline-queue semantics: a mutation is queued (and replayed on reconnect)
@@ -2192,5 +2235,77 @@ declare class LunoraClient {
2192
2235
  */
2193
2236
  private clearQueryCacheForIdentityChange;
2194
2237
  private flushOfflineQueue;
2238
+ /**
2239
+ * Partition already-gated writes into the encodable ones (returned) and reject
2240
+ * the rest terminally. A write whose args can't be wire-encoded (e.g. a RegExp
2241
+ * or class instance in a `v.any()` field) can NEVER replay — the codec failure
2242
+ * is deterministic, not transient. Rejecting here is essential: otherwise
2243
+ * `encodeWire` throws mid-flush, is classified as transient (a codec error has
2244
+ * no `.code`), and re-queues forever — a silent hang where the caller's Promise
2245
+ * never settles and the optimistic write never rolls back. Encoding is cheap;
2246
+ * the flush is the slow reconnect path.
2247
+ */
2248
+ private encodableOrSettleTerminal;
2249
+ /**
2250
+ * Identity guard for one queued write about to replay: a write stamped under
2251
+ * one identity must never replay under another. The live `queuedIdentities`
2252
+ * map is the source of truth for the current session; a hydrated write whose
2253
+ * id isn't in the map falls back to the stamp persisted with the record
2254
+ * (`item.identity`), so a reload can't replay another user's queued writes.
2255
+ * Only legacy records (persisted before stamps were durable —
2256
+ * `item.identity === undefined`) replay under whatever identity is current.
2257
+ *
2258
+ * `Map.get` returns `undefined` for unstamped/hydrated ids and `item.identity`
2259
+ * is `undefined` for legacy records; a persisted `null` (queued while signed
2260
+ * out) is a real value that must not collapse into `undefined` — hence the
2261
+ * explicit `=== undefined` check rather than `??`. Returns `true` when the
2262
+ * write may replay; otherwise settles it `OFFLINE_IDENTITY_CHANGED` and returns
2263
+ * `false`. Either way the live stamp is consumed.
2264
+ */
2265
+ private passesReplayIdentityGate;
2266
+ /** Settle a write that replayed successfully: confirm its optimistic layer against the echoed commit cursor BEFORE resolving, so the gapless drop is in place when the awaiter (and any confirming frame) observes the settle. */
2267
+ private settleReplaySuccess;
2268
+ /** Settle a write the server reached a coded verdict on: replaying would re-trigger the same failure (a poison-message loop), so drop it. */
2269
+ private settleReplayTerminal;
2270
+ /**
2271
+ * Replay already-identity-gated writes one at a time on the single-call `/rpc`
2272
+ * path, preserving FIFO order (parallel `.then()` chains would race the
2273
+ * ordering callers depend on). Each replays under its stable `mutationId` so
2274
+ * the server dedups a write it already committed (exactly-once). A coded error
2275
+ * is a server verdict (drop it); a codeless (transport/transient) failure stops
2276
+ * the flush and re-queues this write and every unreplayed one for the next
2277
+ * reconnect — their callers stay pending, and the identity guard re-applies on
2278
+ * retry via each record's persisted stamp.
2279
+ */
2280
+ private replaySequential;
2281
+ /**
2282
+ * Coalesce already-identity-gated writes for a single shard into ONE
2283
+ * `/_lunora/rpc-batch` round trip (plan 088 follow-on). The worker forwards
2284
+ * them to the shard DO, which replays each through its single-call dispatch, so
2285
+ * per-entry `mutationId` idempotency and in-order application are inherited from
2286
+ * the proven path. Per-slot demux mirrors {@link replaySequential}'s
2287
+ * classification: success confirms the optimistic layer against the echoed
2288
+ * `commitCursor`; a coded application verdict is terminal; a transient shard
2289
+ * failure (`SHARD_UNAVAILABLE`/`SHARD_ERROR`), a missing slot, or a whole-batch
2290
+ * transport failure re-queues for the next reconnect (never dropping a durable
2291
+ * write). A whole-batch coded rejection (bad request / authorization denial the
2292
+ * server reached a verdict on) is terminal for every entry.
2293
+ *
2294
+ * Returns the writes that must be re-queued and `stop` — `true` when the whole
2295
+ * chunk failed at the transport level, so the caller leaves later chunks queued
2296
+ * rather than sending on. The caller re-queues once, in order, so requeuing is
2297
+ * NOT done here.
2298
+ */
2299
+ private replayBatched;
2300
+ /**
2301
+ * Demux a `/_lunora/rpc-batch` reply back onto the queued writes it replayed,
2302
+ * in input order. Each slot's envelope classifies its write the same way
2303
+ * {@link replaySequential} does: a success confirms the optimistic layer
2304
+ * against the echoed `commitCursor`; a coded application verdict is terminal;
2305
+ * a transient shard failure ({@link TRANSIENT_BATCH_ERROR_CODES}) or a slot the
2306
+ * server never returned is returned for the caller to re-queue.
2307
+ * @returns the writes that must be re-queued (transient slots), in input order
2308
+ */
2309
+ private settleReplayBatchSlots;
2195
2310
  }
2196
- export { SubscriptionState as $, ArgsOf as A, BookmarkStorage as B, CachedQuery as C, DEFAULT_MAX_BUFFER as D, SchedulerStatus as E, FunctionReference as F, GlobalFacetResult as G, ServerMessage as H, ServerPokeEndMessage as I, ServerPokePartMessage as J, ServerPokeStartMessage as K, LunoraClient as L, MutationCallOptions as M, ShardTrafficEntry as N, OfflineQueueOptions as O, Preloaded as P, QueryCacheAdapter as Q, ReturnOf as R, SubscriptionError as S, ShardTrafficResult as T, User as U, StorageListPage as V, StorageObject as W, StreamHandle as X, StreamIterable as Y, SubscriptionCallback as Z, SubscriptionRegistry as _, Unsubscribe as a, SyncWatermark as a0, WorkflowInstanceAction as a1, WorkflowInstanceDetail as a2, WorkflowInstancePage as a3, WorkflowInstanceStatus as a4, WorkflowInstanceSummary as a5, WorkflowStepDetail as a6, createLocalStore as a7, createStream as a8, SubscriptionErrorCallback as b, PersistenceAdapter as c, ReconnectOptions as d, ClientMessage as e, ClientShapeSubscribeMessage as f, ClientShapeUnsubscribeMessage as g, ConnectionStatus as h, FunctionArgumentDescriptor as i, FunctionDescriptor as j, GlobalFacetValue as k, GlobalFilterClause as l, GlobalTableInfo as m, GlobalTablePage as n, LunoraClientOptions as o, MutationSettledEvent as p, OptimisticLocalStore as q, OptimisticUpdate as r, OutboxMutation as s, OutboxSink as t, PersistedMutation as u, RowOp as v, RpcEnvelope as w, RpcResponseBody as x, ScheduleRecord as y, SchedulerPoolStatus as z };
2311
+ export { SubscriptionCallback as $, ArgsOf as A, BookmarkStorage as B, CachedQuery as C, DEFAULT_MAX_BUFFER as D, ScheduleRecord as E, FunctionReference as F, GlobalFacetResult as G, SchedulerPoolStatus as H, SchedulerStatus as I, ServerMessage as J, ServerPokeEndMessage as K, LunoraClient as L, MutationCallOptions as M, ServerPokePartMessage as N, OfflineQueueOptions as O, Preloaded as P, QueryCacheAdapter as Q, ReturnOf as R, SubscriptionError as S, ServerPokeStartMessage as T, User as U, ShardTrafficEntry as V, ShardTrafficResult as W, StorageListPage as X, StorageObject as Y, StreamHandle as Z, StreamIterable as _, Unsubscribe as a, SubscriptionRegistry as a0, SubscriptionState as a1, SyncWatermark as a2, WorkflowInstanceAction as a3, WorkflowInstanceDetail as a4, WorkflowInstancePage as a5, WorkflowInstanceStatus as a6, WorkflowInstanceSummary as a7, WorkflowStepDetail as a8, createLocalStore as a9, createStream as aa, SubscriptionErrorCallback as b, PersistenceAdapter as c, ReconnectOptions as d, BatchSlot as e, ClientMessage as f, ClientShapeSubscribeMessage as g, ClientShapeUnsubscribeMessage as h, ConnectionStatus as i, FunctionArgumentDescriptor as j, FunctionDescriptor as k, GlobalFacetValue as l, GlobalFilterClause as m, GlobalTableInfo as n, GlobalTablePage as o, LunoraClientError as p, LunoraClientOptions as q, MutationSettledEvent as r, OptimisticLocalStore as s, OptimisticUpdate as t, OutboxMutation as u, OutboxSink as v, PersistedMutation as w, RowOp as x, RpcEnvelope as y, RpcResponseBody as z };
@@ -271,8 +271,16 @@ interface LunoraClientOptions {
271
271
  * standalone client, which keeps using {@link LunoraClientOptions.persistence}.
272
272
  */
273
273
  outbox?: OutboxSink;
274
- /** Durable store for the offline mutation queue; omit to keep it in memory. */
275
- persistence?: PersistenceAdapter;
274
+ /**
275
+ * Durable store for the offline mutation queue. Tri-state — an explicit
276
+ * {@link PersistenceAdapter} is used as-is; `false` opts out (the queue stays
277
+ * in memory, lost on reload); omitted (the default) auto-probes a durable
278
+ * IndexedDB store when the `indexedDB` global is present (browsers), otherwise
279
+ * in-memory, so SSR/Node/React-Native keep the in-memory behaviour and only
280
+ * environments that can persist do. Pass `createAsyncStoragePersistence()` on
281
+ * React Native.
282
+ */
283
+ persistence?: false | PersistenceAdapter;
276
284
  /**
277
285
  * App/schema version stamped onto every persisted queued write and cached
278
286
  * read. Bump it on a breaking change to a function signature or query shape:
@@ -289,11 +297,13 @@ interface LunoraClientOptions {
289
297
  */
290
298
  persistenceVersion?: string;
291
299
  /**
292
- * Durable store for the read cache (Pillar 2). When supplied, query results
300
+ * Durable store for the read cache (Pillar 2). When active, query results
293
301
  * are persisted as their subscriptions advance and hydrated on construction
294
302
  * so a reload renders cached data before the socket reconnects, then resumes
295
- * the live subscription from the persisted cursor. Omit (or pass `false`) to
296
- * keep reads in memory only the default, unchanged behaviour.
303
+ * the live subscription from the persisted cursor. Tri-state an explicit
304
+ * {@link QueryCacheAdapter} is used as-is; `false` opts out (reads stay in
305
+ * memory only); omitted (the default) auto-probes IndexedDB exactly like
306
+ * {@link LunoraClientOptions.persistence}.
297
307
  */
298
308
  queryCache?: QueryCacheAdapter | false;
299
309
  reconnect?: ReconnectOptions;
@@ -348,6 +358,7 @@ interface RpcEnvelope {
348
358
  type RpcResponseBody = {
349
359
  error: {
350
360
  code: string;
361
+ data?: unknown;
351
362
  message: string;
352
363
  };
353
364
  } | {
@@ -1141,6 +1152,19 @@ interface SyncWatermark {
1141
1152
  checkpoint?: number;
1142
1153
  mutationId?: number;
1143
1154
  }
1155
+ /** An `Error` carrying the server's machine-readable `code` and (for a `LunoraError`) structured `data`. The client's public error contract for RPC/batch failures. */
1156
+ type LunoraClientError = Error & {
1157
+ code?: string;
1158
+ data?: unknown;
1159
+ };
1160
+ /** One demuxed result slot of a {@link LunoraClient.batch} call (plan 088). */
1161
+ type BatchSlot = {
1162
+ error: LunoraClientError;
1163
+ ok: false;
1164
+ } | {
1165
+ ok: true;
1166
+ value: unknown;
1167
+ };
1144
1168
  /**
1145
1169
  * Lunora browser/edge client. Talks RPC over HTTP and real-time deltas over
1146
1170
  * a single multiplexed WebSocket.
@@ -1488,6 +1512,25 @@ declare class LunoraClient {
1488
1512
  shardKey?: string;
1489
1513
  }): Promise<ReturnOf<F>>;
1490
1514
  /**
1515
+ * Batch several independent calls into ONE round trip (plan 088). Each call is
1516
+ * dispatched server-side exactly as an individual RPC — per-shard
1517
+ * authorization, `(identity, mutationId)` idempotency, and custom-mutator
1518
+ * watermark ordering are all preserved — and the worker splits the batch by
1519
+ * shard so calls to different shards fan out to their own DOs. Results are
1520
+ * demuxed back in input order; a failing call does NOT fail the batch (its
1521
+ * slot carries `{ ok: false, error }`, with `.code`/`.data` reconstructed like
1522
+ * a single call). Args/results ride the value codec (bytes/bigint survive).
1523
+ *
1524
+ * No promise pipelining and no capability passing — a call's args cannot
1525
+ * reference another call's result (see plan 088 §fence; capabilities are
1526
+ * incompatible with DO hibernation).
1527
+ */
1528
+ batch(calls: ReadonlyArray<{
1529
+ args?: Record<string, unknown>;
1530
+ fn: FunctionReference;
1531
+ shardKey?: string;
1532
+ }>): Promise<BatchSlot[]>;
1533
+ /**
1491
1534
  * Invoke a mutation. Errors propagate as rejections.
1492
1535
  *
1493
1536
  * Offline-queue semantics: a mutation is queued (and replayed on reconnect)
@@ -2192,5 +2235,77 @@ declare class LunoraClient {
2192
2235
  */
2193
2236
  private clearQueryCacheForIdentityChange;
2194
2237
  private flushOfflineQueue;
2238
+ /**
2239
+ * Partition already-gated writes into the encodable ones (returned) and reject
2240
+ * the rest terminally. A write whose args can't be wire-encoded (e.g. a RegExp
2241
+ * or class instance in a `v.any()` field) can NEVER replay — the codec failure
2242
+ * is deterministic, not transient. Rejecting here is essential: otherwise
2243
+ * `encodeWire` throws mid-flush, is classified as transient (a codec error has
2244
+ * no `.code`), and re-queues forever — a silent hang where the caller's Promise
2245
+ * never settles and the optimistic write never rolls back. Encoding is cheap;
2246
+ * the flush is the slow reconnect path.
2247
+ */
2248
+ private encodableOrSettleTerminal;
2249
+ /**
2250
+ * Identity guard for one queued write about to replay: a write stamped under
2251
+ * one identity must never replay under another. The live `queuedIdentities`
2252
+ * map is the source of truth for the current session; a hydrated write whose
2253
+ * id isn't in the map falls back to the stamp persisted with the record
2254
+ * (`item.identity`), so a reload can't replay another user's queued writes.
2255
+ * Only legacy records (persisted before stamps were durable —
2256
+ * `item.identity === undefined`) replay under whatever identity is current.
2257
+ *
2258
+ * `Map.get` returns `undefined` for unstamped/hydrated ids and `item.identity`
2259
+ * is `undefined` for legacy records; a persisted `null` (queued while signed
2260
+ * out) is a real value that must not collapse into `undefined` — hence the
2261
+ * explicit `=== undefined` check rather than `??`. Returns `true` when the
2262
+ * write may replay; otherwise settles it `OFFLINE_IDENTITY_CHANGED` and returns
2263
+ * `false`. Either way the live stamp is consumed.
2264
+ */
2265
+ private passesReplayIdentityGate;
2266
+ /** Settle a write that replayed successfully: confirm its optimistic layer against the echoed commit cursor BEFORE resolving, so the gapless drop is in place when the awaiter (and any confirming frame) observes the settle. */
2267
+ private settleReplaySuccess;
2268
+ /** Settle a write the server reached a coded verdict on: replaying would re-trigger the same failure (a poison-message loop), so drop it. */
2269
+ private settleReplayTerminal;
2270
+ /**
2271
+ * Replay already-identity-gated writes one at a time on the single-call `/rpc`
2272
+ * path, preserving FIFO order (parallel `.then()` chains would race the
2273
+ * ordering callers depend on). Each replays under its stable `mutationId` so
2274
+ * the server dedups a write it already committed (exactly-once). A coded error
2275
+ * is a server verdict (drop it); a codeless (transport/transient) failure stops
2276
+ * the flush and re-queues this write and every unreplayed one for the next
2277
+ * reconnect — their callers stay pending, and the identity guard re-applies on
2278
+ * retry via each record's persisted stamp.
2279
+ */
2280
+ private replaySequential;
2281
+ /**
2282
+ * Coalesce already-identity-gated writes for a single shard into ONE
2283
+ * `/_lunora/rpc-batch` round trip (plan 088 follow-on). The worker forwards
2284
+ * them to the shard DO, which replays each through its single-call dispatch, so
2285
+ * per-entry `mutationId` idempotency and in-order application are inherited from
2286
+ * the proven path. Per-slot demux mirrors {@link replaySequential}'s
2287
+ * classification: success confirms the optimistic layer against the echoed
2288
+ * `commitCursor`; a coded application verdict is terminal; a transient shard
2289
+ * failure (`SHARD_UNAVAILABLE`/`SHARD_ERROR`), a missing slot, or a whole-batch
2290
+ * transport failure re-queues for the next reconnect (never dropping a durable
2291
+ * write). A whole-batch coded rejection (bad request / authorization denial the
2292
+ * server reached a verdict on) is terminal for every entry.
2293
+ *
2294
+ * Returns the writes that must be re-queued and `stop` — `true` when the whole
2295
+ * chunk failed at the transport level, so the caller leaves later chunks queued
2296
+ * rather than sending on. The caller re-queues once, in order, so requeuing is
2297
+ * NOT done here.
2298
+ */
2299
+ private replayBatched;
2300
+ /**
2301
+ * Demux a `/_lunora/rpc-batch` reply back onto the queued writes it replayed,
2302
+ * in input order. Each slot's envelope classifies its write the same way
2303
+ * {@link replaySequential} does: a success confirms the optimistic layer
2304
+ * against the echoed `commitCursor`; a coded application verdict is terminal;
2305
+ * a transient shard failure ({@link TRANSIENT_BATCH_ERROR_CODES}) or a slot the
2306
+ * server never returned is returned for the caller to re-queue.
2307
+ * @returns the writes that must be re-queued (transient slots), in input order
2308
+ */
2309
+ private settleReplayBatchSlots;
2195
2310
  }
2196
- export { SubscriptionState as $, ArgsOf as A, BookmarkStorage as B, CachedQuery as C, DEFAULT_MAX_BUFFER as D, SchedulerStatus as E, FunctionReference as F, GlobalFacetResult as G, ServerMessage as H, ServerPokeEndMessage as I, ServerPokePartMessage as J, ServerPokeStartMessage as K, LunoraClient as L, MutationCallOptions as M, ShardTrafficEntry as N, OfflineQueueOptions as O, Preloaded as P, QueryCacheAdapter as Q, ReturnOf as R, SubscriptionError as S, ShardTrafficResult as T, User as U, StorageListPage as V, StorageObject as W, StreamHandle as X, StreamIterable as Y, SubscriptionCallback as Z, SubscriptionRegistry as _, Unsubscribe as a, SyncWatermark as a0, WorkflowInstanceAction as a1, WorkflowInstanceDetail as a2, WorkflowInstancePage as a3, WorkflowInstanceStatus as a4, WorkflowInstanceSummary as a5, WorkflowStepDetail as a6, createLocalStore as a7, createStream as a8, SubscriptionErrorCallback as b, PersistenceAdapter as c, ReconnectOptions as d, ClientMessage as e, ClientShapeSubscribeMessage as f, ClientShapeUnsubscribeMessage as g, ConnectionStatus as h, FunctionArgumentDescriptor as i, FunctionDescriptor as j, GlobalFacetValue as k, GlobalFilterClause as l, GlobalTableInfo as m, GlobalTablePage as n, LunoraClientOptions as o, MutationSettledEvent as p, OptimisticLocalStore as q, OptimisticUpdate as r, OutboxMutation as s, OutboxSink as t, PersistedMutation as u, RowOp as v, RpcEnvelope as w, RpcResponseBody as x, ScheduleRecord as y, SchedulerPoolStatus as z };
2311
+ export { SubscriptionCallback as $, ArgsOf as A, BookmarkStorage as B, CachedQuery as C, DEFAULT_MAX_BUFFER as D, ScheduleRecord as E, FunctionReference as F, GlobalFacetResult as G, SchedulerPoolStatus as H, SchedulerStatus as I, ServerMessage as J, ServerPokeEndMessage as K, LunoraClient as L, MutationCallOptions as M, ServerPokePartMessage as N, OfflineQueueOptions as O, Preloaded as P, QueryCacheAdapter as Q, ReturnOf as R, SubscriptionError as S, ServerPokeStartMessage as T, User as U, ShardTrafficEntry as V, ShardTrafficResult as W, StorageListPage as X, StorageObject as Y, StreamHandle as Z, StreamIterable as _, Unsubscribe as a, SubscriptionRegistry as a0, SubscriptionState as a1, SyncWatermark as a2, WorkflowInstanceAction as a3, WorkflowInstanceDetail as a4, WorkflowInstancePage as a5, WorkflowInstanceStatus as a6, WorkflowInstanceSummary as a7, WorkflowStepDetail as a8, createLocalStore as a9, createStream as aa, SubscriptionErrorCallback as b, PersistenceAdapter as c, ReconnectOptions as d, BatchSlot as e, ClientMessage as f, ClientShapeSubscribeMessage as g, ClientShapeUnsubscribeMessage as h, ConnectionStatus as i, FunctionArgumentDescriptor as j, FunctionDescriptor as k, GlobalFacetValue as l, GlobalFilterClause as m, GlobalTableInfo as n, GlobalTablePage as o, LunoraClientError as p, LunoraClientOptions as q, MutationSettledEvent as r, OptimisticLocalStore as s, OptimisticUpdate as t, OutboxMutation as u, OutboxSink as v, PersistedMutation as w, RowOp as x, RpcEnvelope as y, RpcResponseBody as z };
@@ -1,4 +1,4 @@
1
- import { F as FunctionReference, L as LunoraClient, A as ArgsOf, R as ReturnOf, P as Preloaded } from "./lunora-client.d-B5vWSgvD.mjs";
1
+ import { F as FunctionReference, L as LunoraClient, A as ArgsOf, R as ReturnOf, P as Preloaded } from "./lunora-client.d-DTwbfUWF.mjs";
2
2
  /**
3
3
  * Run a query once on the server (during SSR) and capture its result in a
4
4
  * serializable {@link Preloaded} token. Embed the token in the rendered HTML and
@@ -1,4 +1,4 @@
1
- import { F as FunctionReference, L as LunoraClient, A as ArgsOf, R as ReturnOf, P as Preloaded } from "./lunora-client.d-B5vWSgvD.js";
1
+ import { F as FunctionReference, L as LunoraClient, A as ArgsOf, R as ReturnOf, P as Preloaded } from "./lunora-client.d-DTwbfUWF.js";
2
2
  /**
3
3
  * Run a query once on the server (during SSR) and capture its result in a
4
4
  * serializable {@link Preloaded} token. Embed the token in the rendered HTML and
@@ -8,12 +8,22 @@ const stableStringify = (value) => {
8
8
  if (value === void 0) {
9
9
  return "null";
10
10
  }
11
+ if (typeof value === "bigint") {
12
+ throw new TypeError("stableStringify: cannot use a bigint in a cache key (query/subscription/shape args) — pass it as a string");
13
+ }
11
14
  if (value === null || typeof value !== "object") {
12
15
  return JSON.stringify(value);
13
16
  }
14
17
  if (Array.isArray(value)) {
15
18
  return `[${value.map((item) => stableStringify(item)).join(",")}]`;
16
19
  }
20
+ const proto = Object.getPrototypeOf(value);
21
+ if (proto !== null && proto !== Object.prototype) {
22
+ const name = value.constructor?.name ?? "value";
23
+ throw new TypeError(
24
+ `stableStringify: cannot use a ${name} in a cache key (query/subscription/shape args) — only plain objects, arrays, and JSON primitives are supported`
25
+ );
26
+ }
17
27
  const record = value;
18
28
  const keys = Object.keys(record).toSorted(compareKeys);
19
29
  const parts = [];
@@ -1,5 +1,5 @@
1
- import { S as SubscriptionError, F as FunctionReference, A as ArgsOf, R as ReturnOf, L as LunoraClient, a as Unsubscribe } from "../packem_shared/lunora-client.d-B5vWSgvD.mjs";
2
- export type { b as SubscriptionErrorCallback } from "../packem_shared/lunora-client.d-B5vWSgvD.mjs";
1
+ import { S as SubscriptionError, F as FunctionReference, A as ArgsOf, R as ReturnOf, L as LunoraClient, a as Unsubscribe } from "../packem_shared/lunora-client.d-DTwbfUWF.mjs";
2
+ export type { b as SubscriptionErrorCallback } from "../packem_shared/lunora-client.d-DTwbfUWF.mjs";
3
3
  import '@lunora/runtime';
4
4
  /**
5
5
  * The sentinel a framework adapter resolves its reactive args to when it wants
@@ -1,5 +1,5 @@
1
- import { S as SubscriptionError, F as FunctionReference, A as ArgsOf, R as ReturnOf, L as LunoraClient, a as Unsubscribe } from "../packem_shared/lunora-client.d-B5vWSgvD.js";
2
- export type { b as SubscriptionErrorCallback } from "../packem_shared/lunora-client.d-B5vWSgvD.js";
1
+ import { S as SubscriptionError, F as FunctionReference, A as ArgsOf, R as ReturnOf, L as LunoraClient, a as Unsubscribe } from "../packem_shared/lunora-client.d-DTwbfUWF.js";
2
+ export type { b as SubscriptionErrorCallback } from "../packem_shared/lunora-client.d-DTwbfUWF.js";
3
3
  import '@lunora/runtime';
4
4
  /**
5
5
  * The sentinel a framework adapter resolves its reactive args to when it wants
@@ -1,6 +1,6 @@
1
- import { P as Preloaded, L as LunoraClient } from "../packem_shared/lunora-client.d-B5vWSgvD.mjs";
2
- export type { A as ArgsOf, F as FunctionReference, R as ReturnOf } from "../packem_shared/lunora-client.d-B5vWSgvD.mjs";
3
- export { p as preloadQuery, a as preloadedQueryResult } from "../packem_shared/preload.d-3XJD-2hM.mjs";
1
+ import { P as Preloaded, L as LunoraClient } from "../packem_shared/lunora-client.d-DTwbfUWF.mjs";
2
+ export type { A as ArgsOf, F as FunctionReference, R as ReturnOf } from "../packem_shared/lunora-client.d-DTwbfUWF.mjs";
3
+ export { p as preloadQuery, a as preloadedQueryResult } from "../packem_shared/preload.d-BEp0JJeu.mjs";
4
4
  import '@lunora/runtime';
5
5
  /**
6
6
  * Structural shape of a better-auth `getSession` call's resolved value.
@@ -1,6 +1,6 @@
1
- import { P as Preloaded, L as LunoraClient } from "../packem_shared/lunora-client.d-B5vWSgvD.js";
2
- export type { A as ArgsOf, F as FunctionReference, R as ReturnOf } from "../packem_shared/lunora-client.d-B5vWSgvD.js";
3
- export { p as preloadQuery, a as preloadedQueryResult } from "../packem_shared/preload.d-CKZR675M.js";
1
+ import { P as Preloaded, L as LunoraClient } from "../packem_shared/lunora-client.d-DTwbfUWF.js";
2
+ export type { A as ArgsOf, F as FunctionReference, R as ReturnOf } from "../packem_shared/lunora-client.d-DTwbfUWF.js";
3
+ export { p as preloadQuery, a as preloadedQueryResult } from "../packem_shared/preload.d-CK2IYf5B.js";
4
4
  import '@lunora/runtime';
5
5
  /**
6
6
  * Structural shape of a better-auth `getSession` call's resolved value.
@@ -1,4 +1,4 @@
1
1
  export { getServerSession } from '../packem_shared/getServerSession-8jXewqxd.mjs';
2
2
  export { deserializePreloaded, serializePreloaded } from '../packem_shared/deserializePreloaded-C0eJTY_W.mjs';
3
- export { createServerClient } from '../packem_shared/createServerClient-BxkNcRlR.mjs';
3
+ export { createServerClient } from '../packem_shared/createServerClient-C5GMCGSQ.mjs';
4
4
  export { preloadQuery, preloadedQueryResult } from '../packem_shared/preloadQuery-lobFkD2Z.mjs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/client",
3
- "version": "1.0.0-alpha.10",
3
+ "version": "1.0.0-alpha.12",
4
4
  "description": "Lunora browser SDK: WebSocket transport, optimistic updates, and an offline mutation queue",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -1 +0,0 @@
1
- export { S as SubscriptionRegistry } from './subscription-C1Jy7HiF.mjs';