@lunora/client 1.0.0-alpha.20 → 1.0.0-alpha.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/index.d.mts +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +6 -6
- package/dist/packem_shared/{LunoraClient-hrmLXEHd.mjs → LunoraClient-kXpHNyaE.mjs} +62 -13
- package/dist/packem_shared/SubscriptionRegistry-DjGKZsqq.mjs +1 -0
- package/dist/packem_shared/{applyDelta-4jFGTPA3.mjs → applyDelta-CRKZ1PBt.mjs} +21 -1
- package/dist/packem_shared/{createInMemoryPersistence-Ds7z8n8d.mjs → createInMemoryPersistence-DZ2VHWgm.mjs} +7 -47
- package/dist/packem_shared/{createInMemoryQueryCache-iWtKPrid.mjs → createInMemoryQueryCache-DiaGZkA2.mjs} +7 -47
- package/dist/packem_shared/createLocalStore-jRoqmazl.mjs +2 -0
- package/dist/packem_shared/{createServerClient-CKKZrXLc.mjs → createServerClient-DF-3mLmb.mjs} +1 -1
- package/dist/packem_shared/idb-utility-DrSVX43Q.mjs +48 -0
- package/dist/packem_shared/{local-store-BNgN3Dw3.mjs → local-store-BveBeFEo.mjs} +7 -12
- package/dist/packem_shared/{lunora-client.d-DVdVtJV8.d.mts → lunora-client.d-BYkEjCEJ.d.mts} +29 -1
- package/dist/packem_shared/{lunora-client.d-DVdVtJV8.d.ts → lunora-client.d-BYkEjCEJ.d.ts} +29 -1
- package/dist/packem_shared/{preload.d-Bb69VRgE.d.ts → preload.d-B-vyHnml.d.ts} +1 -1
- package/dist/packem_shared/{preload.d-BXFvxpiv.d.mts → preload.d-DrfuisCE.d.mts} +1 -1
- package/dist/packem_shared/{subscription-DoyO04-2.mjs → subscription-BjynOXCU.mjs} +4 -1
- package/dist/query/index.d.mts +2 -2
- package/dist/query/index.d.ts +2 -2
- package/dist/ssr/index.d.mts +3 -3
- package/dist/ssr/index.d.ts +3 -3
- package/dist/ssr/index.mjs +1 -1
- package/package.json +2 -2
- package/dist/packem_shared/SubscriptionRegistry-Cxr70og-.mjs +0 -1
- package/dist/packem_shared/createLocalStore-IOur0jHF.mjs +0 -1
package/dist/auth/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { U as User, L as LunoraClient } from "../packem_shared/lunora-client.d-
|
|
1
|
+
import { U as User, L as LunoraClient } from "../packem_shared/lunora-client.d-BYkEjCEJ.mjs";
|
|
2
2
|
import '@lunora/runtime';
|
|
3
3
|
interface IdentityStore {
|
|
4
4
|
/** Read the current resolved user, or `null` when signed out / not yet resolved. */
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { U as User, L as LunoraClient } from "../packem_shared/lunora-client.d-
|
|
1
|
+
import { U as User, L as LunoraClient } from "../packem_shared/lunora-client.d-BYkEjCEJ.js";
|
|
2
2
|
import '@lunora/runtime';
|
|
3
3
|
interface IdentityStore {
|
|
4
4
|
/** Read the current resolved user, or `null` when signed out / not yet resolved. */
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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-
|
|
2
|
-
export { type e as BatchSlot, C as CONFLICT_ERROR_CODE, type f as CachedQuery, type g as ClientMessage, type h as ClientShapeSubscribeMessage, type i as ClientShapeUnsubscribeMessage, type j as ConnectionStatus, D as DEFAULT_MAX_BUFFER, type k as FunctionArgumentDescriptor, type l as FunctionDescriptor, type G as GlobalFacetResult, type m as GlobalFacetValue, type n as GlobalFilterClause, type o as GlobalTableInfo, type p as GlobalTablePage, L as LunoraClient, type q as LunoraClientError, type r as LunoraClientOptions, type s as LunoraErrorCode, type t as MutationSettledEvent, type u as OptimisticLocalStore, type v as OptimisticUpdate, type w as OutboxMutation, type x as OutboxSink, type y as PersistedMutation, type P as Preloaded, type z as RowOp, type E as RpcEnvelope, type H as RpcResponseBody, type I as ScheduleRecord, type J as SchedulerPoolStatus, type K as SchedulerStatus, type N as ServerMessage, type T as ServerPokeEndMessage, type V as ServerPokePartMessage, type W as ServerPokeStartMessage, type X as ShardTrafficEntry, type Y as ShardTrafficResult, type Z as StorageListPage, type _ as StorageObject, type $ as StreamHandle, type a0 as StreamIterable, type a1 as SubscriptionCallback, type S as SubscriptionError, type b as SubscriptionErrorCallback, a2 as SubscriptionRegistry, type a3 as SubscriptionState, type a4 as SyncWatermark, type a as Unsubscribe, type U as User, type a5 as WorkflowInstanceAction, type a6 as WorkflowInstanceDetail, type a7 as WorkflowInstancePage, type a8 as WorkflowInstanceStatus, type a9 as WorkflowInstanceSummary, type aa as WorkflowStepDetail, ab as createLocalStore, ac as createStream, ad as getErrorCode, ae as getRetryAfterMs, af as isConflictError, ag as isForbiddenError, ah as isRateLimitedError, ai as isUnauthorizedError } from "./packem_shared/lunora-client.d-
|
|
3
|
-
export { p as preloadQuery, a as preloadedQueryResult } from "./packem_shared/preload.d-
|
|
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-BYkEjCEJ.mjs";
|
|
2
|
+
export { type e as BatchSlot, C as CONFLICT_ERROR_CODE, type f as CachedQuery, type g as ClientMessage, type h as ClientShapeSubscribeMessage, type i as ClientShapeUnsubscribeMessage, type j as ConnectionStatus, D as DEFAULT_MAX_BUFFER, type k as FunctionArgumentDescriptor, type l as FunctionDescriptor, type G as GlobalFacetResult, type m as GlobalFacetValue, type n as GlobalFilterClause, type o as GlobalTableInfo, type p as GlobalTablePage, L as LunoraClient, type q as LunoraClientError, type r as LunoraClientOptions, type s as LunoraErrorCode, type t as MutationSettledEvent, type u as OptimisticLocalStore, type v as OptimisticUpdate, type w as OutboxMutation, type x as OutboxSink, type y as PersistedMutation, type P as Preloaded, type z as RowOp, type E as RpcEnvelope, type H as RpcResponseBody, type I as ScheduleRecord, type J as SchedulerPoolStatus, type K as SchedulerStatus, type N as ServerMessage, type T as ServerPokeEndMessage, type V as ServerPokePartMessage, type W as ServerPokeStartMessage, type X as ShardTrafficEntry, type Y as ShardTrafficResult, type Z as StorageListPage, type _ as StorageObject, type $ as StreamHandle, type a0 as StreamIterable, type a1 as SubscriptionCallback, type S as SubscriptionError, type b as SubscriptionErrorCallback, a2 as SubscriptionRegistry, type a3 as SubscriptionState, type a4 as SyncWatermark, type a as Unsubscribe, type U as User, type a5 as WorkflowInstanceAction, type a6 as WorkflowInstanceDetail, type a7 as WorkflowInstancePage, type a8 as WorkflowInstanceStatus, type a9 as WorkflowInstanceSummary, type aa as WorkflowStepDetail, ab as createLocalStore, ac as createStream, ad as getErrorCode, ae as getRetryAfterMs, af as isConflictError, ag as isForbiddenError, ah as isRateLimitedError, ai as isUnauthorizedError } from "./packem_shared/lunora-client.d-BYkEjCEJ.mjs";
|
|
3
|
+
export { p as preloadQuery, a as preloadedQueryResult } from "./packem_shared/preload.d-DrfuisCE.mjs";
|
|
4
4
|
export type { AuthCapabilities, AuthConfigInfo, AuthImpersonation, AuthPage, AuthSession, AuthUser, AuthUserFieldSpec, CronJobInfo, KvKeyEntry, KvKeyListResult, KvNamespaceSummary, KvValueResult, VectorIndexSummary, VectorQueryMatch } from '@lunora/runtime';
|
|
5
5
|
/**
|
|
6
6
|
* The slice of React Native's `AsyncStorage` (or any async key/value store —
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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-
|
|
2
|
-
export { type e as BatchSlot, C as CONFLICT_ERROR_CODE, type f as CachedQuery, type g as ClientMessage, type h as ClientShapeSubscribeMessage, type i as ClientShapeUnsubscribeMessage, type j as ConnectionStatus, D as DEFAULT_MAX_BUFFER, type k as FunctionArgumentDescriptor, type l as FunctionDescriptor, type G as GlobalFacetResult, type m as GlobalFacetValue, type n as GlobalFilterClause, type o as GlobalTableInfo, type p as GlobalTablePage, L as LunoraClient, type q as LunoraClientError, type r as LunoraClientOptions, type s as LunoraErrorCode, type t as MutationSettledEvent, type u as OptimisticLocalStore, type v as OptimisticUpdate, type w as OutboxMutation, type x as OutboxSink, type y as PersistedMutation, type P as Preloaded, type z as RowOp, type E as RpcEnvelope, type H as RpcResponseBody, type I as ScheduleRecord, type J as SchedulerPoolStatus, type K as SchedulerStatus, type N as ServerMessage, type T as ServerPokeEndMessage, type V as ServerPokePartMessage, type W as ServerPokeStartMessage, type X as ShardTrafficEntry, type Y as ShardTrafficResult, type Z as StorageListPage, type _ as StorageObject, type $ as StreamHandle, type a0 as StreamIterable, type a1 as SubscriptionCallback, type S as SubscriptionError, type b as SubscriptionErrorCallback, a2 as SubscriptionRegistry, type a3 as SubscriptionState, type a4 as SyncWatermark, type a as Unsubscribe, type U as User, type a5 as WorkflowInstanceAction, type a6 as WorkflowInstanceDetail, type a7 as WorkflowInstancePage, type a8 as WorkflowInstanceStatus, type a9 as WorkflowInstanceSummary, type aa as WorkflowStepDetail, ab as createLocalStore, ac as createStream, ad as getErrorCode, ae as getRetryAfterMs, af as isConflictError, ag as isForbiddenError, ah as isRateLimitedError, ai as isUnauthorizedError } from "./packem_shared/lunora-client.d-
|
|
3
|
-
export { p as preloadQuery, a as preloadedQueryResult } from "./packem_shared/preload.d-
|
|
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-BYkEjCEJ.js";
|
|
2
|
+
export { type e as BatchSlot, C as CONFLICT_ERROR_CODE, type f as CachedQuery, type g as ClientMessage, type h as ClientShapeSubscribeMessage, type i as ClientShapeUnsubscribeMessage, type j as ConnectionStatus, D as DEFAULT_MAX_BUFFER, type k as FunctionArgumentDescriptor, type l as FunctionDescriptor, type G as GlobalFacetResult, type m as GlobalFacetValue, type n as GlobalFilterClause, type o as GlobalTableInfo, type p as GlobalTablePage, L as LunoraClient, type q as LunoraClientError, type r as LunoraClientOptions, type s as LunoraErrorCode, type t as MutationSettledEvent, type u as OptimisticLocalStore, type v as OptimisticUpdate, type w as OutboxMutation, type x as OutboxSink, type y as PersistedMutation, type P as Preloaded, type z as RowOp, type E as RpcEnvelope, type H as RpcResponseBody, type I as ScheduleRecord, type J as SchedulerPoolStatus, type K as SchedulerStatus, type N as ServerMessage, type T as ServerPokeEndMessage, type V as ServerPokePartMessage, type W as ServerPokeStartMessage, type X as ShardTrafficEntry, type Y as ShardTrafficResult, type Z as StorageListPage, type _ as StorageObject, type $ as StreamHandle, type a0 as StreamIterable, type a1 as SubscriptionCallback, type S as SubscriptionError, type b as SubscriptionErrorCallback, a2 as SubscriptionRegistry, type a3 as SubscriptionState, type a4 as SyncWatermark, type a as Unsubscribe, type U as User, type a5 as WorkflowInstanceAction, type a6 as WorkflowInstanceDetail, type a7 as WorkflowInstancePage, type a8 as WorkflowInstanceStatus, type a9 as WorkflowInstanceSummary, type aa as WorkflowStepDetail, ab as createLocalStore, ac as createStream, ad as getErrorCode, ae as getRetryAfterMs, af as isConflictError, ag as isForbiddenError, ah as isRateLimitedError, ai as isUnauthorizedError } from "./packem_shared/lunora-client.d-BYkEjCEJ.js";
|
|
3
|
+
export { p as preloadQuery, a as preloadedQueryResult } from "./packem_shared/preload.d-B-vyHnml.js";
|
|
4
4
|
export type { AuthCapabilities, AuthConfigInfo, AuthImpersonation, AuthPage, AuthSession, AuthUser, AuthUserFieldSpec, CronJobInfo, KvKeyEntry, KvKeyListResult, KvNamespaceSummary, KvValueResult, VectorIndexSummary, VectorQueryMatch } from '@lunora/runtime';
|
|
5
5
|
/**
|
|
6
6
|
* The slice of React Native's `AsyncStorage` (or any async key/value store —
|
package/dist/index.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
export { createAsyncStoragePersistence } from './packem_shared/createAsyncStoragePersistence-1Z5BZ8RC.mjs';
|
|
2
2
|
export { default as createInMemoryBookmarkStorage } from './packem_shared/createInMemoryBookmarkStorage-BoN7a7TH.mjs';
|
|
3
|
-
export { applyDelta, isMutationDelta } from './packem_shared/applyDelta-
|
|
3
|
+
export { applyDelta, isMutationDelta } from './packem_shared/applyDelta-CRKZ1PBt.mjs';
|
|
4
4
|
export { CONFLICT_ERROR_CODE, getErrorCode, getRetryAfterMs, isConflictError, isForbiddenError, isRateLimitedError, isUnauthorizedError } from './packem_shared/CONFLICT_ERROR_CODE-B8gQ8tyU.mjs';
|
|
5
|
-
export { c as createLocalStore } from './packem_shared/local-store-
|
|
6
|
-
export { LunoraClient } from './packem_shared/LunoraClient-
|
|
5
|
+
export { c as createLocalStore } from './packem_shared/local-store-BveBeFEo.mjs';
|
|
6
|
+
export { LunoraClient } from './packem_shared/LunoraClient-kXpHNyaE.mjs';
|
|
7
7
|
export { createMutationRunner } from './packem_shared/createMutationRunner-BqsavzvG.mjs';
|
|
8
8
|
export { createMutatorRunner } from './packem_shared/createMutatorRunner-BETvCd0p.mjs';
|
|
9
9
|
export { O as OfflineQueue } from './packem_shared/offline-queue-B9vfdSqp.mjs';
|
|
10
|
-
export { createInMemoryPersistence, createIndexedDbPersistence } from './packem_shared/createInMemoryPersistence-
|
|
10
|
+
export { createInMemoryPersistence, createIndexedDbPersistence } from './packem_shared/createInMemoryPersistence-DZ2VHWgm.mjs';
|
|
11
11
|
export { preloadQuery, preloadedQueryResult } from './packem_shared/preloadQuery-lobFkD2Z.mjs';
|
|
12
|
-
export { createInMemoryQueryCache, createIndexedDbQueryCache, queryCacheKey } from './packem_shared/createInMemoryQueryCache-
|
|
12
|
+
export { createInMemoryQueryCache, createIndexedDbQueryCache, queryCacheKey } from './packem_shared/createInMemoryQueryCache-DiaGZkA2.mjs';
|
|
13
13
|
export { createReconnect } from './packem_shared/createReconnect-Di_-oHH7.mjs';
|
|
14
14
|
export { DEFAULT_MAX_BUFFER, createStream } from './packem_shared/DEFAULT_MAX_BUFFER-7hFnzNk9.mjs';
|
|
15
|
-
export { S as SubscriptionRegistry } from './packem_shared/subscription-
|
|
15
|
+
export { S as SubscriptionRegistry } from './packem_shared/subscription-BjynOXCU.mjs';
|
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
import { LunoraError } from '@lunora/errors';
|
|
2
|
-
import { S as SubscriptionRegistry, s as stableStringify } from './subscription-
|
|
2
|
+
import { S as SubscriptionRegistry, s as stableStringify } from './subscription-BjynOXCU.mjs';
|
|
3
3
|
import createInMemoryBookmarkStorage from './createInMemoryBookmarkStorage-BoN7a7TH.mjs';
|
|
4
|
-
import { isMutationDelta, applyDelta } from './applyDelta-
|
|
5
|
-
import { a as applyOptimisticLayer, d as dropConfirmedLayers, n as notifySubscription, f as foldOptimistic, c as createLocalStore } from './local-store-
|
|
4
|
+
import { isMutationDelta, applyDelta } from './applyDelta-CRKZ1PBt.mjs';
|
|
5
|
+
import { a as applyOptimisticLayer, d as dropConfirmedLayers, n as notifySubscription, f as foldOptimistic, c as createLocalStore } from './local-store-BveBeFEo.mjs';
|
|
6
6
|
import { O as OfflineQueue, n as nextId, i as isStaleVersion, r as reportPersistenceError } from './offline-queue-B9vfdSqp.mjs';
|
|
7
|
-
import { resolvePersistenceAdapter } from './createInMemoryPersistence-
|
|
8
|
-
import { resolveQueryCacheAdapter, queryCacheKey } from './createInMemoryQueryCache-
|
|
7
|
+
import { resolvePersistenceAdapter } from './createInMemoryPersistence-DZ2VHWgm.mjs';
|
|
8
|
+
import { resolveQueryCacheAdapter, queryCacheKey } from './createInMemoryQueryCache-DiaGZkA2.mjs';
|
|
9
9
|
import { createReconnect } from './createReconnect-Di_-oHH7.mjs';
|
|
10
10
|
import { createStream } from './DEFAULT_MAX_BUFFER-7hFnzNk9.mjs';
|
|
11
11
|
|
|
12
12
|
const MAX_BATCH_ENTRIES = 500;
|
|
13
13
|
|
|
14
|
+
const evictOldestEntry = (map, capacity) => {
|
|
15
|
+
if (map.size < capacity) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const oldest = map.keys().next().value;
|
|
19
|
+
if (oldest !== void 0) {
|
|
20
|
+
map.delete(oldest);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
14
24
|
const TAG = "$lunora.wire$";
|
|
15
25
|
const MAX_DEPTH = 64;
|
|
16
26
|
const MAX_BIGINT_DIGITS = 1024;
|
|
@@ -2380,7 +2390,7 @@ class LunoraClient {
|
|
|
2380
2390
|
* mutation or leave a partial patch live.
|
|
2381
2391
|
*/
|
|
2382
2392
|
applyOptimisticUpdate(optimisticUpdate, args, shardKey, optimisticRollbacks, optimisticConfirms) {
|
|
2383
|
-
const { confirms, rollbacks, store } = createLocalStore(this.subscriptions, shardKey
|
|
2393
|
+
const { confirms, rollbacks, store } = createLocalStore(this.subscriptions, shardKey);
|
|
2384
2394
|
try {
|
|
2385
2395
|
optimisticUpdate(store, args);
|
|
2386
2396
|
} catch {
|
|
@@ -2709,6 +2719,13 @@ class LunoraClient {
|
|
|
2709
2719
|
conn.wsState = "idle";
|
|
2710
2720
|
this.emitConnectionStatus();
|
|
2711
2721
|
this.markShardPendingAck(conn.shardKey);
|
|
2722
|
+
const pendingStreamIds = new Set((conn.pendingStreams ?? []).map((message) => message.id));
|
|
2723
|
+
for (const [id, stream] of this.streams) {
|
|
2724
|
+
if (connectionKey(stream.shardKey) === connectionKey(conn.shardKey) && !pendingStreamIds.has(id)) {
|
|
2725
|
+
stream.handle.fail(new LunoraError("STREAM_DISCONNECTED", "stream terminated: WebSocket disconnected"));
|
|
2726
|
+
this.streams.delete(id);
|
|
2727
|
+
}
|
|
2728
|
+
}
|
|
2712
2729
|
if (this.WebSocketImpl === void 0) {
|
|
2713
2730
|
return;
|
|
2714
2731
|
}
|
|
@@ -2881,12 +2898,7 @@ class LunoraClient {
|
|
|
2881
2898
|
}
|
|
2882
2899
|
}
|
|
2883
2900
|
handlePokeStart(message) {
|
|
2884
|
-
|
|
2885
|
-
const oldest = this.pokeBuffers.keys().next().value;
|
|
2886
|
-
if (oldest !== void 0) {
|
|
2887
|
-
this.pokeBuffers.delete(oldest);
|
|
2888
|
-
}
|
|
2889
|
-
}
|
|
2901
|
+
evictOldestEntry(this.pokeBuffers, LunoraClient.MAX_POKE_BUFFERS);
|
|
2890
2902
|
this.pokeBuffers.set(message.pokeId, { baseCheckpoint: message.baseCheckpoint, epoch: message.epoch, lastMutationId: /* @__PURE__ */ new Map(), parts: /* @__PURE__ */ new Map() });
|
|
2891
2903
|
}
|
|
2892
2904
|
handlePokePart(message) {
|
|
@@ -3108,6 +3120,24 @@ class LunoraClient {
|
|
|
3108
3120
|
if (token === null) {
|
|
3109
3121
|
return null;
|
|
3110
3122
|
}
|
|
3123
|
+
return this.hashToken(token);
|
|
3124
|
+
}
|
|
3125
|
+
/**
|
|
3126
|
+
* Stable token-hash fingerprint of a bearer token (the `<len>:<fnv>:<djb2>`
|
|
3127
|
+
* format a token-stamped queued write carries). Extracted so the replay gate
|
|
3128
|
+
* can recompute the hash of the current credential and recognise a write
|
|
3129
|
+
* stamped under it — even after the fingerprint was relabelled to a subject.
|
|
3130
|
+
*
|
|
3131
|
+
* Two independent 32-bit passes (FNV-1a + djb2) give a ~64-bit digest, so
|
|
3132
|
+
* two distinct equal-length tokens are astronomically unlikely to share a
|
|
3133
|
+
* fingerprint. A single 32-bit hash collides ~1-in-4e9 per equal-length
|
|
3134
|
+
* pair — enough that, on a shared device, user B could hydrate A's cached
|
|
3135
|
+
* reads. Different algorithms (not the same FNV with a different seed, which
|
|
3136
|
+
* would be affine-related) keep the two passes genuinely independent.
|
|
3137
|
+
* Still synchronous (no crypto) and stable across surrogate pairs.
|
|
3138
|
+
*/
|
|
3139
|
+
// eslint-disable-next-line class-methods-use-this -- pure helper; a method for locality with identityFingerprint, reads no shared state
|
|
3140
|
+
hashToken(token) {
|
|
3111
3141
|
let fnv = 2166136261;
|
|
3112
3142
|
let djb2 = 5381;
|
|
3113
3143
|
for (let index = 0; index < token.length; index += 1) {
|
|
@@ -3118,6 +3148,25 @@ class LunoraClient {
|
|
|
3118
3148
|
}
|
|
3119
3149
|
return `${token.length.toString(36)}:${(fnv >>> 0).toString(36)}:${(djb2 >>> 0).toString(36)}`;
|
|
3120
3150
|
}
|
|
3151
|
+
/**
|
|
3152
|
+
* True when `stamped` is a token-hash of the SAME credential still held now,
|
|
3153
|
+
* even though the live identity has since been relabelled to a subject. Covers
|
|
3154
|
+
* `setAuthToken(token, userId)` where the subject resolved a tick after the
|
|
3155
|
+
* token was set: a write persisted (or requeued) under the token hash must
|
|
3156
|
+
* still replay — the credential never changed, only its label — instead of
|
|
3157
|
+
* being dropped as an identity mismatch. This is the durable counterpart to
|
|
3158
|
+
* {@link restampQueuedIdentity}, which only relabels the in-memory live stamp
|
|
3159
|
+
* (consumed on the first flush) and never touches `item.identity` or the
|
|
3160
|
+
* persisted record, so a reload or a transient-failure requeue would otherwise
|
|
3161
|
+
* fall back to the stale token-hash and wrongly reject the same user's write.
|
|
3162
|
+
*/
|
|
3163
|
+
isSameCredentialUnderTokenHash(stamped) {
|
|
3164
|
+
if (stamped === null || stamped.startsWith("subj:")) {
|
|
3165
|
+
return false;
|
|
3166
|
+
}
|
|
3167
|
+
const token = this.authToken;
|
|
3168
|
+
return token === null ? false : this.hashToken(token) === stamped;
|
|
3169
|
+
}
|
|
3121
3170
|
/**
|
|
3122
3171
|
* Drain every in-memory offline write and reject it because the auth
|
|
3123
3172
|
* identity changed. Durable entries are also dropped from persistence so a
|
|
@@ -3246,7 +3295,7 @@ class LunoraClient {
|
|
|
3246
3295
|
passesReplayIdentityGate(item, currentIdentity) {
|
|
3247
3296
|
const liveStamp = item.id === void 0 ? void 0 : this.queuedIdentities.get(item.id);
|
|
3248
3297
|
const stamped = liveStamp === void 0 ? item.identity : liveStamp;
|
|
3249
|
-
if (stamped !== void 0 && stamped !== currentIdentity) {
|
|
3298
|
+
if (stamped !== void 0 && stamped !== currentIdentity && !this.isSameCredentialUnderTokenHash(stamped)) {
|
|
3250
3299
|
this.queuedIdentities.delete(item.id ?? "");
|
|
3251
3300
|
this.unpersist(item.id);
|
|
3252
3301
|
const error = new Error("offline mutation skipped: auth identity changed before replay");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { S as SubscriptionRegistry } from './subscription-BjynOXCU.mjs';
|
|
@@ -7,14 +7,34 @@ const rowId = (row) => {
|
|
|
7
7
|
const id = row[ID_FIELD];
|
|
8
8
|
return typeof id === "string" ? id : void 0;
|
|
9
9
|
};
|
|
10
|
+
const isDescending = (list) => {
|
|
11
|
+
let previous;
|
|
12
|
+
for (const existingRow of list) {
|
|
13
|
+
const existing = existingRow[CREATION_FIELD];
|
|
14
|
+
if (typeof existing !== "number") {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (previous !== void 0) {
|
|
18
|
+
if (existing < previous) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
if (existing > previous) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
previous = existing;
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
};
|
|
10
29
|
const insertionIndex = (list, row) => {
|
|
11
30
|
const creation = row[CREATION_FIELD];
|
|
12
31
|
if (typeof creation !== "number") {
|
|
13
32
|
return list.length;
|
|
14
33
|
}
|
|
34
|
+
const descending = isDescending(list);
|
|
15
35
|
for (const [index, existingRow] of list.entries()) {
|
|
16
36
|
const existing = existingRow[CREATION_FIELD];
|
|
17
|
-
if (typeof existing === "number" && existing > creation) {
|
|
37
|
+
if (typeof existing === "number" && (descending ? existing < creation : existing > creation)) {
|
|
18
38
|
return index;
|
|
19
39
|
}
|
|
20
40
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
import { p as promisifyRequest, c as createWithStore, a as createDatabaseOpener } from './idb-utility-DrSVX43Q.mjs';
|
|
2
3
|
|
|
3
4
|
const createInMemoryPersistence = () => {
|
|
4
5
|
const entries = /* @__PURE__ */ new Map();
|
|
@@ -30,14 +31,6 @@ const createInMemoryPersistence = () => {
|
|
|
30
31
|
const DEFAULT_DATABASE = "lunora-outbox";
|
|
31
32
|
const DEFAULT_STORE = "offline-mutations";
|
|
32
33
|
const ID_INDEX = "by_id";
|
|
33
|
-
const promisifyRequest = (request) => new Promise((resolve, reject) => {
|
|
34
|
-
request.addEventListener("success", () => {
|
|
35
|
-
resolve(request.result);
|
|
36
|
-
});
|
|
37
|
-
request.addEventListener("error", () => {
|
|
38
|
-
reject(request.error ?? new Error("IndexedDB request failed"));
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
34
|
const createIndexedDbPersistence = (options = {}) => {
|
|
42
35
|
const factory = options.indexedDB ?? (typeof indexedDB === "undefined" ? void 0 : indexedDB);
|
|
43
36
|
if (!factory) {
|
|
@@ -45,46 +38,13 @@ const createIndexedDbPersistence = (options = {}) => {
|
|
|
45
38
|
}
|
|
46
39
|
const databaseName = options.databaseName ?? DEFAULT_DATABASE;
|
|
47
40
|
const storeName = options.storeName ?? DEFAULT_STORE;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
41
|
+
const openDatabase = createDatabaseOpener(factory, databaseName, 1, (database) => {
|
|
42
|
+
if (!database.objectStoreNames.contains(storeName)) {
|
|
43
|
+
const store = database.createObjectStore(storeName, { autoIncrement: true });
|
|
44
|
+
store.createIndex(ID_INDEX, "id", { unique: true });
|
|
52
45
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
request.addEventListener("upgradeneeded", () => {
|
|
56
|
-
const database = request.result;
|
|
57
|
-
if (!database.objectStoreNames.contains(storeName)) {
|
|
58
|
-
const store = database.createObjectStore(storeName, { autoIncrement: true });
|
|
59
|
-
store.createIndex(ID_INDEX, "id", { unique: true });
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
request.addEventListener("success", () => {
|
|
63
|
-
resolve(request.result);
|
|
64
|
-
});
|
|
65
|
-
request.addEventListener("error", () => {
|
|
66
|
-
reject(request.error ?? new Error("IndexedDB open failed"));
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
return databasePromise;
|
|
70
|
-
};
|
|
71
|
-
const withStore = async (mode, run) => {
|
|
72
|
-
const database = await openDatabase();
|
|
73
|
-
const transaction = database.transaction(storeName, mode);
|
|
74
|
-
const result = await run(transaction.objectStore(storeName));
|
|
75
|
-
await new Promise((resolve, reject) => {
|
|
76
|
-
transaction.addEventListener("complete", () => {
|
|
77
|
-
resolve();
|
|
78
|
-
});
|
|
79
|
-
transaction.addEventListener("error", () => {
|
|
80
|
-
reject(transaction.error ?? new Error("IndexedDB transaction failed"));
|
|
81
|
-
});
|
|
82
|
-
transaction.addEventListener("abort", () => {
|
|
83
|
-
reject(transaction.error ?? new Error("IndexedDB transaction aborted"));
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
return result;
|
|
87
|
-
};
|
|
46
|
+
});
|
|
47
|
+
const withStore = createWithStore(openDatabase, storeName);
|
|
88
48
|
return {
|
|
89
49
|
append: async (mutation) => {
|
|
90
50
|
await withStore("readwrite", (store) => promisifyRequest(store.add(mutation)));
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
import { p as promisifyRequest, c as createWithStore, a as createDatabaseOpener } from './idb-utility-DrSVX43Q.mjs';
|
|
2
3
|
|
|
3
4
|
const queryCacheKey = (functionPath, argsKey, shardKey) => `${functionPath}::${argsKey}::${shardKey ?? ""}`;
|
|
4
5
|
const DEFAULT_MAX_ENTRIES = 500;
|
|
@@ -41,14 +42,6 @@ const DEFAULT_DATABASE = "lunora-query-cache";
|
|
|
41
42
|
const DEFAULT_STORE = "query-cache";
|
|
42
43
|
const TS_INDEX = "by_ts";
|
|
43
44
|
const DATABASE_VERSION = 1;
|
|
44
|
-
const promisifyRequest = (request) => new Promise((resolve, reject) => {
|
|
45
|
-
request.addEventListener("success", () => {
|
|
46
|
-
resolve(request.result);
|
|
47
|
-
});
|
|
48
|
-
request.addEventListener("error", () => {
|
|
49
|
-
reject(request.error ?? new Error("IndexedDB request failed"));
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
45
|
const createIndexedDbQueryCache = (options = {}) => {
|
|
53
46
|
const factory = options.indexedDB ?? (typeof indexedDB === "undefined" ? void 0 : indexedDB);
|
|
54
47
|
if (!factory) {
|
|
@@ -57,46 +50,13 @@ const createIndexedDbQueryCache = (options = {}) => {
|
|
|
57
50
|
const databaseName = options.databaseName ?? DEFAULT_DATABASE;
|
|
58
51
|
const storeName = options.storeName ?? DEFAULT_STORE;
|
|
59
52
|
const maxEntries = options.maxEntries ?? DEFAULT_MAX_ENTRIES;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
53
|
+
const openDatabase = createDatabaseOpener(factory, databaseName, DATABASE_VERSION, (database) => {
|
|
54
|
+
if (!database.objectStoreNames.contains(storeName)) {
|
|
55
|
+
const store = database.createObjectStore(storeName, { keyPath: "key" });
|
|
56
|
+
store.createIndex(TS_INDEX, "ts", { unique: false });
|
|
64
57
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
request.addEventListener("upgradeneeded", () => {
|
|
68
|
-
const database = request.result;
|
|
69
|
-
if (!database.objectStoreNames.contains(storeName)) {
|
|
70
|
-
const store = database.createObjectStore(storeName, { keyPath: "key" });
|
|
71
|
-
store.createIndex(TS_INDEX, "ts", { unique: false });
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
request.addEventListener("success", () => {
|
|
75
|
-
resolve(request.result);
|
|
76
|
-
});
|
|
77
|
-
request.addEventListener("error", () => {
|
|
78
|
-
reject(request.error ?? new Error("IndexedDB open failed"));
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
return databasePromise;
|
|
82
|
-
};
|
|
83
|
-
const withStore = async (mode, run) => {
|
|
84
|
-
const database = await openDatabase();
|
|
85
|
-
const transaction = database.transaction(storeName, mode);
|
|
86
|
-
const result = await run(transaction.objectStore(storeName));
|
|
87
|
-
await new Promise((resolve, reject) => {
|
|
88
|
-
transaction.addEventListener("complete", () => {
|
|
89
|
-
resolve();
|
|
90
|
-
});
|
|
91
|
-
transaction.addEventListener("error", () => {
|
|
92
|
-
reject(transaction.error ?? new Error("IndexedDB transaction failed"));
|
|
93
|
-
});
|
|
94
|
-
transaction.addEventListener("abort", () => {
|
|
95
|
-
reject(transaction.error ?? new Error("IndexedDB transaction aborted"));
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
return result;
|
|
99
|
-
};
|
|
58
|
+
});
|
|
59
|
+
const withStore = createWithStore(openDatabase, storeName);
|
|
100
60
|
const evict = async (store) => {
|
|
101
61
|
const count = await promisifyRequest(store.count());
|
|
102
62
|
let overflow = count - maxEntries;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const promisifyRequest = (request) => new Promise((resolve, reject) => {
|
|
2
|
+
request.addEventListener("success", () => {
|
|
3
|
+
resolve(request.result);
|
|
4
|
+
});
|
|
5
|
+
request.addEventListener("error", () => {
|
|
6
|
+
reject(request.error ?? new Error("IndexedDB request failed"));
|
|
7
|
+
});
|
|
8
|
+
});
|
|
9
|
+
const createDatabaseOpener = (factory, databaseName, version, upgrade) => {
|
|
10
|
+
let databasePromise;
|
|
11
|
+
return () => {
|
|
12
|
+
if (databasePromise) {
|
|
13
|
+
return databasePromise;
|
|
14
|
+
}
|
|
15
|
+
databasePromise = new Promise((resolve, reject) => {
|
|
16
|
+
const request = factory.open(databaseName, version);
|
|
17
|
+
request.addEventListener("upgradeneeded", () => {
|
|
18
|
+
upgrade(request.result);
|
|
19
|
+
});
|
|
20
|
+
request.addEventListener("success", () => {
|
|
21
|
+
resolve(request.result);
|
|
22
|
+
});
|
|
23
|
+
request.addEventListener("error", () => {
|
|
24
|
+
reject(request.error ?? new Error("IndexedDB open failed"));
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
return databasePromise;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
const createWithStore = (open, storeName) => async (mode, run) => {
|
|
31
|
+
const database = await open();
|
|
32
|
+
const transaction = database.transaction(storeName, mode);
|
|
33
|
+
const result = await run(transaction.objectStore(storeName));
|
|
34
|
+
await new Promise((resolve, reject) => {
|
|
35
|
+
transaction.addEventListener("complete", () => {
|
|
36
|
+
resolve();
|
|
37
|
+
});
|
|
38
|
+
transaction.addEventListener("error", () => {
|
|
39
|
+
reject(transaction.error ?? new Error("IndexedDB transaction failed"));
|
|
40
|
+
});
|
|
41
|
+
transaction.addEventListener("abort", () => {
|
|
42
|
+
reject(transaction.error ?? new Error("IndexedDB transaction aborted"));
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
return result;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export { createDatabaseOpener as a, createWithStore as c, promisifyRequest as p };
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { S as SubscriptionRegistry } from './subscription-BjynOXCU.mjs';
|
|
2
|
+
|
|
1
3
|
const foldOptimistic = (base, layers) => {
|
|
2
4
|
let value = base;
|
|
3
5
|
for (const layer of layers) {
|
|
@@ -68,33 +70,26 @@ const dropConfirmedLayers = (state, cursor) => {
|
|
|
68
70
|
return state.optimisticLayers.length !== before;
|
|
69
71
|
};
|
|
70
72
|
|
|
71
|
-
const createLocalStore = (subscriptions, shardKey
|
|
73
|
+
const createLocalStore = (subscriptions, shardKey) => {
|
|
72
74
|
const confirms = [];
|
|
73
75
|
const rollbacks = [];
|
|
74
|
-
const findState = (functionRef,
|
|
75
|
-
for (const state of subscriptions.all()) {
|
|
76
|
-
if (state.fn.__lunoraRef === functionRef && state.shardKey === shardKey && state.argsKey === argsKey) {
|
|
77
|
-
return state;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
return void 0;
|
|
81
|
-
};
|
|
76
|
+
const findState = (functionRef, args) => subscriptions.get(SubscriptionRegistry.key(functionRef, args, shardKey));
|
|
82
77
|
const store = {
|
|
83
78
|
getAllQueries: (function_) => {
|
|
84
79
|
const matches = [];
|
|
85
80
|
for (const state of subscriptions.all()) {
|
|
86
|
-
if (state.fn.__lunoraRef === function_.__lunoraRef && state.shardKey === shardKey) {
|
|
81
|
+
if (state.fn.__lunoraRef === function_.__lunoraRef && (state.shardKey ?? "") === (shardKey ?? "")) {
|
|
87
82
|
matches.push({ args: state.args, value: state.lastValue });
|
|
88
83
|
}
|
|
89
84
|
}
|
|
90
85
|
return matches;
|
|
91
86
|
},
|
|
92
87
|
getQuery: (function_, args) => {
|
|
93
|
-
const state = findState(function_.__lunoraRef,
|
|
88
|
+
const state = findState(function_.__lunoraRef, args ?? {});
|
|
94
89
|
return state?.lastValue;
|
|
95
90
|
},
|
|
96
91
|
setQuery: (function_, args, value) => {
|
|
97
|
-
const state = findState(function_.__lunoraRef,
|
|
92
|
+
const state = findState(function_.__lunoraRef, args ?? {});
|
|
98
93
|
if (!state) {
|
|
99
94
|
return;
|
|
100
95
|
}
|
package/dist/packem_shared/{lunora-client.d-DVdVtJV8.d.mts → lunora-client.d-BYkEjCEJ.d.mts}
RENAMED
|
@@ -1076,7 +1076,7 @@ type OptimisticUpdate<Args> = (localStore: OptimisticLocalStore, args: Args) =>
|
|
|
1076
1076
|
* `confirm` (success) and `rollback` (failure) closures every `setQuery` produced,
|
|
1077
1077
|
* so the caller settles the whole batch when the mutation does.
|
|
1078
1078
|
*/
|
|
1079
|
-
declare const createLocalStore: (subscriptions: SubscriptionRegistry, shardKey: string | undefined
|
|
1079
|
+
declare const createLocalStore: (subscriptions: SubscriptionRegistry, shardKey: string | undefined) => {
|
|
1080
1080
|
confirms: ((commitCursor: number | undefined) => void)[];
|
|
1081
1081
|
rollbacks: (() => void)[];
|
|
1082
1082
|
store: OptimisticLocalStore;
|
|
@@ -2412,6 +2412,34 @@ declare class LunoraClient {
|
|
|
2412
2412
|
*/
|
|
2413
2413
|
private identityFingerprint;
|
|
2414
2414
|
/**
|
|
2415
|
+
* Stable token-hash fingerprint of a bearer token (the `<len>:<fnv>:<djb2>`
|
|
2416
|
+
* format a token-stamped queued write carries). Extracted so the replay gate
|
|
2417
|
+
* can recompute the hash of the current credential and recognise a write
|
|
2418
|
+
* stamped under it — even after the fingerprint was relabelled to a subject.
|
|
2419
|
+
*
|
|
2420
|
+
* Two independent 32-bit passes (FNV-1a + djb2) give a ~64-bit digest, so
|
|
2421
|
+
* two distinct equal-length tokens are astronomically unlikely to share a
|
|
2422
|
+
* fingerprint. A single 32-bit hash collides ~1-in-4e9 per equal-length
|
|
2423
|
+
* pair — enough that, on a shared device, user B could hydrate A's cached
|
|
2424
|
+
* reads. Different algorithms (not the same FNV with a different seed, which
|
|
2425
|
+
* would be affine-related) keep the two passes genuinely independent.
|
|
2426
|
+
* Still synchronous (no crypto) and stable across surrogate pairs.
|
|
2427
|
+
*/
|
|
2428
|
+
private hashToken;
|
|
2429
|
+
/**
|
|
2430
|
+
* True when `stamped` is a token-hash of the SAME credential still held now,
|
|
2431
|
+
* even though the live identity has since been relabelled to a subject. Covers
|
|
2432
|
+
* `setAuthToken(token, userId)` where the subject resolved a tick after the
|
|
2433
|
+
* token was set: a write persisted (or requeued) under the token hash must
|
|
2434
|
+
* still replay — the credential never changed, only its label — instead of
|
|
2435
|
+
* being dropped as an identity mismatch. This is the durable counterpart to
|
|
2436
|
+
* {@link restampQueuedIdentity}, which only relabels the in-memory live stamp
|
|
2437
|
+
* (consumed on the first flush) and never touches `item.identity` or the
|
|
2438
|
+
* persisted record, so a reload or a transient-failure requeue would otherwise
|
|
2439
|
+
* fall back to the stale token-hash and wrongly reject the same user's write.
|
|
2440
|
+
*/
|
|
2441
|
+
private isSameCredentialUnderTokenHash;
|
|
2442
|
+
/**
|
|
2415
2443
|
* Drain every in-memory offline write and reject it because the auth
|
|
2416
2444
|
* identity changed. Durable entries are also dropped from persistence so a
|
|
2417
2445
|
* later `hydrate` can't resurrect another user's writes. Stamps are cleared
|
|
@@ -1076,7 +1076,7 @@ type OptimisticUpdate<Args> = (localStore: OptimisticLocalStore, args: Args) =>
|
|
|
1076
1076
|
* `confirm` (success) and `rollback` (failure) closures every `setQuery` produced,
|
|
1077
1077
|
* so the caller settles the whole batch when the mutation does.
|
|
1078
1078
|
*/
|
|
1079
|
-
declare const createLocalStore: (subscriptions: SubscriptionRegistry, shardKey: string | undefined
|
|
1079
|
+
declare const createLocalStore: (subscriptions: SubscriptionRegistry, shardKey: string | undefined) => {
|
|
1080
1080
|
confirms: ((commitCursor: number | undefined) => void)[];
|
|
1081
1081
|
rollbacks: (() => void)[];
|
|
1082
1082
|
store: OptimisticLocalStore;
|
|
@@ -2412,6 +2412,34 @@ declare class LunoraClient {
|
|
|
2412
2412
|
*/
|
|
2413
2413
|
private identityFingerprint;
|
|
2414
2414
|
/**
|
|
2415
|
+
* Stable token-hash fingerprint of a bearer token (the `<len>:<fnv>:<djb2>`
|
|
2416
|
+
* format a token-stamped queued write carries). Extracted so the replay gate
|
|
2417
|
+
* can recompute the hash of the current credential and recognise a write
|
|
2418
|
+
* stamped under it — even after the fingerprint was relabelled to a subject.
|
|
2419
|
+
*
|
|
2420
|
+
* Two independent 32-bit passes (FNV-1a + djb2) give a ~64-bit digest, so
|
|
2421
|
+
* two distinct equal-length tokens are astronomically unlikely to share a
|
|
2422
|
+
* fingerprint. A single 32-bit hash collides ~1-in-4e9 per equal-length
|
|
2423
|
+
* pair — enough that, on a shared device, user B could hydrate A's cached
|
|
2424
|
+
* reads. Different algorithms (not the same FNV with a different seed, which
|
|
2425
|
+
* would be affine-related) keep the two passes genuinely independent.
|
|
2426
|
+
* Still synchronous (no crypto) and stable across surrogate pairs.
|
|
2427
|
+
*/
|
|
2428
|
+
private hashToken;
|
|
2429
|
+
/**
|
|
2430
|
+
* True when `stamped` is a token-hash of the SAME credential still held now,
|
|
2431
|
+
* even though the live identity has since been relabelled to a subject. Covers
|
|
2432
|
+
* `setAuthToken(token, userId)` where the subject resolved a tick after the
|
|
2433
|
+
* token was set: a write persisted (or requeued) under the token hash must
|
|
2434
|
+
* still replay — the credential never changed, only its label — instead of
|
|
2435
|
+
* being dropped as an identity mismatch. This is the durable counterpart to
|
|
2436
|
+
* {@link restampQueuedIdentity}, which only relabels the in-memory live stamp
|
|
2437
|
+
* (consumed on the first flush) and never touches `item.identity` or the
|
|
2438
|
+
* persisted record, so a reload or a transient-failure requeue would otherwise
|
|
2439
|
+
* fall back to the stale token-hash and wrongly reject the same user's write.
|
|
2440
|
+
*/
|
|
2441
|
+
private isSameCredentialUnderTokenHash;
|
|
2442
|
+
/**
|
|
2415
2443
|
* Drain every in-memory offline write and reject it because the auth
|
|
2416
2444
|
* identity changed. Durable entries are also dropped from persistence so a
|
|
2417
2445
|
* later `hydrate` can't resurrect another user's writes. Stamps are cleared
|
|
@@ -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-
|
|
1
|
+
import { F as FunctionReference, L as LunoraClient, A as ArgsOf, R as ReturnOf, P as Preloaded } from "./lunora-client.d-BYkEjCEJ.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
|
|
@@ -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-
|
|
1
|
+
import { F as FunctionReference, L as LunoraClient, A as ArgsOf, R as ReturnOf, P as Preloaded } from "./lunora-client.d-BYkEjCEJ.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
|
|
@@ -54,7 +54,10 @@ class SubscriptionRegistry {
|
|
|
54
54
|
this.byId.set(state.id, state);
|
|
55
55
|
}
|
|
56
56
|
remove(state) {
|
|
57
|
-
|
|
57
|
+
const key = SubscriptionRegistry.key(state.fn.__lunoraRef, state.args, state.shardKey);
|
|
58
|
+
if (this.byKey.get(key) === state) {
|
|
59
|
+
this.byKey.delete(key);
|
|
60
|
+
}
|
|
58
61
|
this.byId.delete(state.id);
|
|
59
62
|
}
|
|
60
63
|
all() {
|
package/dist/query/index.d.mts
CHANGED
|
@@ -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-
|
|
2
|
-
export type { b as SubscriptionErrorCallback } from "../packem_shared/lunora-client.d-
|
|
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-BYkEjCEJ.mjs";
|
|
2
|
+
export type { b as SubscriptionErrorCallback } from "../packem_shared/lunora-client.d-BYkEjCEJ.mjs";
|
|
3
3
|
import '@lunora/runtime';
|
|
4
4
|
/**
|
|
5
5
|
* The sentinel a framework adapter resolves its reactive args to when it wants
|
package/dist/query/index.d.ts
CHANGED
|
@@ -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-
|
|
2
|
-
export type { b as SubscriptionErrorCallback } from "../packem_shared/lunora-client.d-
|
|
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-BYkEjCEJ.js";
|
|
2
|
+
export type { b as SubscriptionErrorCallback } from "../packem_shared/lunora-client.d-BYkEjCEJ.js";
|
|
3
3
|
import '@lunora/runtime';
|
|
4
4
|
/**
|
|
5
5
|
* The sentinel a framework adapter resolves its reactive args to when it wants
|
package/dist/ssr/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { P as Preloaded, L as LunoraClient } from "../packem_shared/lunora-client.d-
|
|
2
|
-
export type { A as ArgsOf, F as FunctionReference, R as ReturnOf } from "../packem_shared/lunora-client.d-
|
|
3
|
-
export { p as preloadQuery, a as preloadedQueryResult } from "../packem_shared/preload.d-
|
|
1
|
+
import { P as Preloaded, L as LunoraClient } from "../packem_shared/lunora-client.d-BYkEjCEJ.mjs";
|
|
2
|
+
export type { A as ArgsOf, F as FunctionReference, R as ReturnOf } from "../packem_shared/lunora-client.d-BYkEjCEJ.mjs";
|
|
3
|
+
export { p as preloadQuery, a as preloadedQueryResult } from "../packem_shared/preload.d-DrfuisCE.mjs";
|
|
4
4
|
import '@lunora/runtime';
|
|
5
5
|
/**
|
|
6
6
|
* Structural shape of a better-auth `getSession` call's resolved value.
|
package/dist/ssr/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { P as Preloaded, L as LunoraClient } from "../packem_shared/lunora-client.d-
|
|
2
|
-
export type { A as ArgsOf, F as FunctionReference, R as ReturnOf } from "../packem_shared/lunora-client.d-
|
|
3
|
-
export { p as preloadQuery, a as preloadedQueryResult } from "../packem_shared/preload.d-
|
|
1
|
+
import { P as Preloaded, L as LunoraClient } from "../packem_shared/lunora-client.d-BYkEjCEJ.js";
|
|
2
|
+
export type { A as ArgsOf, F as FunctionReference, R as ReturnOf } from "../packem_shared/lunora-client.d-BYkEjCEJ.js";
|
|
3
|
+
export { p as preloadQuery, a as preloadedQueryResult } from "../packem_shared/preload.d-B-vyHnml.js";
|
|
4
4
|
import '@lunora/runtime';
|
|
5
5
|
/**
|
|
6
6
|
* Structural shape of a better-auth `getSession` call's resolved value.
|
package/dist/ssr/index.mjs
CHANGED
|
@@ -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-
|
|
3
|
+
export { createServerClient } from '../packem_shared/createServerClient-DF-3mLmb.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.
|
|
3
|
+
"version": "1.0.0-alpha.21",
|
|
4
4
|
"description": "Lunora browser SDK: WebSocket transport, optimistic updates, and an offline mutation queue",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"access": "public"
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"@lunora/errors": "1.0.0-alpha.
|
|
65
|
+
"@lunora/errors": "1.0.0-alpha.4"
|
|
66
66
|
},
|
|
67
67
|
"engines": {
|
|
68
68
|
"node": "^22.15.0 || >=24.11.0"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { S as SubscriptionRegistry } from './subscription-DoyO04-2.mjs';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { c as createLocalStore } from './local-store-BNgN3Dw3.mjs';
|