@lunora/client 1.0.0-alpha.85 → 1.0.0-alpha.87
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 +1 -1
- package/dist/packem_shared/LunoraClient-DArMFG67.mjs +1 -0
- package/dist/packem_shared/{createServerClient-C74FjEQv.mjs → createServerClient-BrNyme3I.mjs} +1 -1
- package/dist/packem_shared/{httpStream-x6q-x4yK.mjs → httpStream-CPdblK2G.mjs} +4 -4
- package/dist/packem_shared/{lunora-client.d-D6g91j8X.d.mts → lunora-client.d-C5tvkz8x.d.mts} +152 -16
- package/dist/packem_shared/{lunora-client.d-DiKeST-Z.d.ts → lunora-client.d-CK3FxGNH.d.ts} +152 -16
- package/dist/packem_shared/{preload.d-BfLwnKiD.d.mts → preload.d-CAXl1Y8Y.d.mts} +1 -1
- package/dist/packem_shared/{preload.d-BWPg1lFK.d.ts → preload.d-Csjxr5HM.d.ts} +1 -1
- package/dist/query/index.d.mts +2 -2
- package/dist/query/index.d.ts +2 -2
- package/dist/ssr/index.d.mts +2 -2
- package/dist/ssr/index.d.ts +2 -2
- package/dist/ssr/index.mjs +1 -1
- package/package.json +2 -2
- package/dist/packem_shared/LunoraClient-JdIc6fPb.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-C5tvkz8x.mjs";
|
|
2
2
|
import '@lunora/errors';
|
|
3
3
|
import "../packem_shared/function-reference.d-Br_hsKje.mjs";
|
|
4
4
|
import '@lunora/runtime';
|
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-CK3FxGNH.js";
|
|
2
2
|
import '@lunora/errors';
|
|
3
3
|
import "../packem_shared/function-reference.d-Br_hsKje.js";
|
|
4
4
|
import '@lunora/runtime';
|
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { c as PersistenceAdapter, Q as QueryCacheAdapter, B as BookmarkStorage, C as ConnectionStatus, S as SubscriptionError, H as HttpStreamRef, d as HttpStreamArgsOf, e as HttpStreamChunkOf, f as StreamIterable, O as OfflineQueueOptions, R as ReconnectOptions, L as LunoraClient } from "./packem_shared/lunora-client.d-
|
|
2
|
-
export { type A as ActionCallOptions, type g as BatchSlot, type h as CachedQuery, type i as ClientDebugShard, type j as ClientDebugSnapshot, type k as ClientDebugSubscription, type l as ClientMessage, type m as ClientQueryRef, type n as ClientShapeSubscribeMessage, type o as ClientShapeUnsubscribeMessage, D as DEFAULT_MAX_BUFFER, type F as FunctionArgumentDescriptor, type p as FunctionDescriptor, type G as GlobalFacetResult, type q as GlobalFacetValue, type r as GlobalFilterClause, type s as GlobalTableInfo, type t as GlobalTablePage, type u as HttpStreamCallArgs, type v as LunoraClientError, type w as LunoraClientOptions, type M as MutationCallOptions, type x as MutationSettledEvent, type y as OptimisticLocalStore, type z as OptimisticUpdate, type E as OutboxMutation, type I as OutboxSink, type J as PersistedMutation, type P as Preloaded, type K as RowOp, type N as RpcEnvelope, type T as RpcResponseBody, type V as ScheduleRecord, type W as ScheduleRetryPolicy, type X as SchedulerPoolStatus, type Y as SchedulerStatus, type Z as ServerMessage, type _ as ServerPokeEndMessage, type $ as ServerPokePartMessage, type a0 as ServerPokeStartMessage, type a1 as ShardTrafficEntry, type a2 as ShardTrafficResult, type a3 as StorageListPage, type a4 as StorageObject, type a5 as StoredQuery, type a6 as StreamHandle, type a7 as SubscriptionCallback, type b as SubscriptionErrorCallback, a8 as SubscriptionRegistry, type a9 as SubscriptionState, type aa as SyncWatermark, type a as Unsubscribe, type U as User, type ab as WorkflowInstanceAction, type ac as WorkflowInstanceDetail, type ad as WorkflowInstancePage, type ae as WorkflowInstanceStatus, type af as WorkflowInstanceSummary, type ag as WorkflowStepDetail, type ah as WsTokenProvider, ai as createClientQuery, aj as createLocalStore, ak as createStream } from "./packem_shared/lunora-client.d-
|
|
1
|
+
import { c as PersistenceAdapter, Q as QueryCacheAdapter, B as BookmarkStorage, C as ConnectionStatus, S as SubscriptionError, H as HttpStreamRef, d as HttpStreamArgsOf, e as HttpStreamChunkOf, f as StreamIterable, O as OfflineQueueOptions, R as ReconnectOptions, L as LunoraClient } from "./packem_shared/lunora-client.d-C5tvkz8x.mjs";
|
|
2
|
+
export { type A as ActionCallOptions, type g as BatchSlot, type h as CachedQuery, type i as ClientDebugShard, type j as ClientDebugSnapshot, type k as ClientDebugSubscription, type l as ClientMessage, type m as ClientQueryRef, type n as ClientShapeSubscribeMessage, type o as ClientShapeUnsubscribeMessage, D as DEFAULT_MAX_BUFFER, type F as FunctionArgumentDescriptor, type p as FunctionDescriptor, type G as GlobalFacetResult, type q as GlobalFacetValue, type r as GlobalFilterClause, type s as GlobalTableInfo, type t as GlobalTablePage, type u as HttpStreamCallArgs, type v as LunoraClientError, type w as LunoraClientOptions, type M as MutationCallOptions, type x as MutationSettledEvent, type y as OptimisticLocalStore, type z as OptimisticUpdate, type E as OutboxMutation, type I as OutboxSink, type J as PersistedMutation, type P as Preloaded, type K as RowOp, type N as RpcEnvelope, type T as RpcResponseBody, type V as ScheduleRecord, type W as ScheduleRetryPolicy, type X as SchedulerPoolStatus, type Y as SchedulerStatus, type Z as ServerMessage, type _ as ServerPokeEndMessage, type $ as ServerPokePartMessage, type a0 as ServerPokeStartMessage, type a1 as ShardTrafficEntry, type a2 as ShardTrafficResult, type a3 as StorageListPage, type a4 as StorageObject, type a5 as StoredQuery, type a6 as StreamHandle, type a7 as SubscriptionCallback, type b as SubscriptionErrorCallback, a8 as SubscriptionRegistry, type a9 as SubscriptionState, type aa as SyncWatermark, type a as Unsubscribe, type U as User, type ab as WorkflowInstanceAction, type ac as WorkflowInstanceDetail, type ad as WorkflowInstancePage, type ae as WorkflowInstanceStatus, type af as WorkflowInstanceSummary, type ag as WorkflowStepDetail, type ah as WsTokenProvider, ai as createClientQuery, aj as createLocalStore, ak as createStream } from "./packem_shared/lunora-client.d-C5tvkz8x.mjs";
|
|
3
3
|
import { LunoraError, LunoraErrorCode } from '@lunora/errors';
|
|
4
4
|
export type { LunoraErrorCode } from '@lunora/errors';
|
|
5
|
-
export { p as preloadQuery, a as preloadedQueryResult } from "./packem_shared/preload.d-
|
|
5
|
+
export { p as preloadQuery, a as preloadedQueryResult } from "./packem_shared/preload.d-CAXl1Y8Y.mjs";
|
|
6
6
|
import { F as FunctionReference } from "./packem_shared/function-reference.d-Br_hsKje.mjs";
|
|
7
7
|
export type { A as ArgsOf, R as ReturnOf } from "./packem_shared/function-reference.d-Br_hsKje.mjs";
|
|
8
8
|
export type { AuthCapabilities, AuthConfigInfo, AuthImpersonation, AuthPage, AuthSession, AuthUser, AuthUserFieldSpec, CronJobInfo, KvKeyEntry, KvKeyListResult, KvNamespaceSummary, KvValueResult, PipelineLogColumnMap, PipelineLogCursor, PipelineLogField, PipelineLogPage, PipelineLogQuery, PipelineLogRow, VectorIndexSummary, VectorQueryMatch } from '@lunora/runtime';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { c as PersistenceAdapter, Q as QueryCacheAdapter, B as BookmarkStorage, C as ConnectionStatus, S as SubscriptionError, H as HttpStreamRef, d as HttpStreamArgsOf, e as HttpStreamChunkOf, f as StreamIterable, O as OfflineQueueOptions, R as ReconnectOptions, L as LunoraClient } from "./packem_shared/lunora-client.d-
|
|
2
|
-
export { type A as ActionCallOptions, type g as BatchSlot, type h as CachedQuery, type i as ClientDebugShard, type j as ClientDebugSnapshot, type k as ClientDebugSubscription, type l as ClientMessage, type m as ClientQueryRef, type n as ClientShapeSubscribeMessage, type o as ClientShapeUnsubscribeMessage, D as DEFAULT_MAX_BUFFER, type F as FunctionArgumentDescriptor, type p as FunctionDescriptor, type G as GlobalFacetResult, type q as GlobalFacetValue, type r as GlobalFilterClause, type s as GlobalTableInfo, type t as GlobalTablePage, type u as HttpStreamCallArgs, type v as LunoraClientError, type w as LunoraClientOptions, type M as MutationCallOptions, type x as MutationSettledEvent, type y as OptimisticLocalStore, type z as OptimisticUpdate, type E as OutboxMutation, type I as OutboxSink, type J as PersistedMutation, type P as Preloaded, type K as RowOp, type N as RpcEnvelope, type T as RpcResponseBody, type V as ScheduleRecord, type W as ScheduleRetryPolicy, type X as SchedulerPoolStatus, type Y as SchedulerStatus, type Z as ServerMessage, type _ as ServerPokeEndMessage, type $ as ServerPokePartMessage, type a0 as ServerPokeStartMessage, type a1 as ShardTrafficEntry, type a2 as ShardTrafficResult, type a3 as StorageListPage, type a4 as StorageObject, type a5 as StoredQuery, type a6 as StreamHandle, type a7 as SubscriptionCallback, type b as SubscriptionErrorCallback, a8 as SubscriptionRegistry, type a9 as SubscriptionState, type aa as SyncWatermark, type a as Unsubscribe, type U as User, type ab as WorkflowInstanceAction, type ac as WorkflowInstanceDetail, type ad as WorkflowInstancePage, type ae as WorkflowInstanceStatus, type af as WorkflowInstanceSummary, type ag as WorkflowStepDetail, type ah as WsTokenProvider, ai as createClientQuery, aj as createLocalStore, ak as createStream } from "./packem_shared/lunora-client.d-
|
|
1
|
+
import { c as PersistenceAdapter, Q as QueryCacheAdapter, B as BookmarkStorage, C as ConnectionStatus, S as SubscriptionError, H as HttpStreamRef, d as HttpStreamArgsOf, e as HttpStreamChunkOf, f as StreamIterable, O as OfflineQueueOptions, R as ReconnectOptions, L as LunoraClient } from "./packem_shared/lunora-client.d-CK3FxGNH.js";
|
|
2
|
+
export { type A as ActionCallOptions, type g as BatchSlot, type h as CachedQuery, type i as ClientDebugShard, type j as ClientDebugSnapshot, type k as ClientDebugSubscription, type l as ClientMessage, type m as ClientQueryRef, type n as ClientShapeSubscribeMessage, type o as ClientShapeUnsubscribeMessage, D as DEFAULT_MAX_BUFFER, type F as FunctionArgumentDescriptor, type p as FunctionDescriptor, type G as GlobalFacetResult, type q as GlobalFacetValue, type r as GlobalFilterClause, type s as GlobalTableInfo, type t as GlobalTablePage, type u as HttpStreamCallArgs, type v as LunoraClientError, type w as LunoraClientOptions, type M as MutationCallOptions, type x as MutationSettledEvent, type y as OptimisticLocalStore, type z as OptimisticUpdate, type E as OutboxMutation, type I as OutboxSink, type J as PersistedMutation, type P as Preloaded, type K as RowOp, type N as RpcEnvelope, type T as RpcResponseBody, type V as ScheduleRecord, type W as ScheduleRetryPolicy, type X as SchedulerPoolStatus, type Y as SchedulerStatus, type Z as ServerMessage, type _ as ServerPokeEndMessage, type $ as ServerPokePartMessage, type a0 as ServerPokeStartMessage, type a1 as ShardTrafficEntry, type a2 as ShardTrafficResult, type a3 as StorageListPage, type a4 as StorageObject, type a5 as StoredQuery, type a6 as StreamHandle, type a7 as SubscriptionCallback, type b as SubscriptionErrorCallback, a8 as SubscriptionRegistry, type a9 as SubscriptionState, type aa as SyncWatermark, type a as Unsubscribe, type U as User, type ab as WorkflowInstanceAction, type ac as WorkflowInstanceDetail, type ad as WorkflowInstancePage, type ae as WorkflowInstanceStatus, type af as WorkflowInstanceSummary, type ag as WorkflowStepDetail, type ah as WsTokenProvider, ai as createClientQuery, aj as createLocalStore, ak as createStream } from "./packem_shared/lunora-client.d-CK3FxGNH.js";
|
|
3
3
|
import { LunoraError, LunoraErrorCode } from '@lunora/errors';
|
|
4
4
|
export type { LunoraErrorCode } from '@lunora/errors';
|
|
5
|
-
export { p as preloadQuery, a as preloadedQueryResult } from "./packem_shared/preload.d-
|
|
5
|
+
export { p as preloadQuery, a as preloadedQueryResult } from "./packem_shared/preload.d-Csjxr5HM.js";
|
|
6
6
|
import { F as FunctionReference } from "./packem_shared/function-reference.d-Br_hsKje.js";
|
|
7
7
|
export type { A as ArgsOf, R as ReturnOf } from "./packem_shared/function-reference.d-Br_hsKje.js";
|
|
8
8
|
export type { AuthCapabilities, AuthConfigInfo, AuthImpersonation, AuthPage, AuthSession, AuthUser, AuthUserFieldSpec, CronJobInfo, KvKeyEntry, KvKeyListResult, KvNamespaceSummary, KvValueResult, PipelineLogColumnMap, PipelineLogCursor, PipelineLogField, PipelineLogPage, PipelineLogQuery, PipelineLogRow, VectorIndexSummary, VectorQueryMatch } from '@lunora/runtime';
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{anyApi as o}from"./packem_shared/anyApi-CBOws2ZA.mjs";import{RETIRE_AFTER_DURABLE_SEQ_ADVANCE as a,maxSeq as c,reconcileOptimistic as p}from"./packem_shared/RETIRE_AFTER_DURABLE_SEQ_ADVANCE-DoEHtuR8.mjs";import{createAsyncStoragePersistence as m}from"./packem_shared/createAsyncStoragePersistence-CeUW9NTj.mjs";import{createAsyncStorageQueryCache as f}from"./packem_shared/createAsyncStorageQueryCache-BfZkthAE.mjs";import{default as x}from"./packem_shared/createInMemoryBookmarkStorage-BooZhW0n.mjs";import{createCallRunner as l}from"./packem_shared/createCallRunner-Bwcrfh76.mjs";import{createClientQuery as d}from"./packem_shared/createClientQuery-B8Nfj-7o.mjs";import{TabCoordinator as R}from"./packem_shared/TabCoordinator-CXD7vulJ.mjs";import{a as S,i as A}from"./packem_shared/delta-merge-vxvH3PvF.mjs";import{CONFLICT_ERROR_CODE as Q,TransportError as _,getErrorCode as h,getRetryAfterMs as I,isConflictError as M,isForbiddenError as T,isRateLimitedError as g,isUnauthorizedError as F}from"./packem_shared/CONFLICT_ERROR_CODE-BOeeP_Wl.mjs";import{httpStream as O}from"./packem_shared/httpStream-
|
|
1
|
+
import{anyApi as o}from"./packem_shared/anyApi-CBOws2ZA.mjs";import{RETIRE_AFTER_DURABLE_SEQ_ADVANCE as a,maxSeq as c,reconcileOptimistic as p}from"./packem_shared/RETIRE_AFTER_DURABLE_SEQ_ADVANCE-DoEHtuR8.mjs";import{createAsyncStoragePersistence as m}from"./packem_shared/createAsyncStoragePersistence-CeUW9NTj.mjs";import{createAsyncStorageQueryCache as f}from"./packem_shared/createAsyncStorageQueryCache-BfZkthAE.mjs";import{default as x}from"./packem_shared/createInMemoryBookmarkStorage-BooZhW0n.mjs";import{createCallRunner as l}from"./packem_shared/createCallRunner-Bwcrfh76.mjs";import{createClientQuery as d}from"./packem_shared/createClientQuery-B8Nfj-7o.mjs";import{TabCoordinator as R}from"./packem_shared/TabCoordinator-CXD7vulJ.mjs";import{a as S,i as A}from"./packem_shared/delta-merge-vxvH3PvF.mjs";import{CONFLICT_ERROR_CODE as Q,TransportError as _,getErrorCode as h,getRetryAfterMs as I,isConflictError as M,isForbiddenError as T,isRateLimitedError as g,isUnauthorizedError as F}from"./packem_shared/CONFLICT_ERROR_CODE-BOeeP_Wl.mjs";import{httpStream as O}from"./packem_shared/httpStream-CPdblK2G.mjs";import{c as P}from"./packem_shared/local-store-CVfQDdXy.mjs";import{LunoraClient as k}from"./packem_shared/LunoraClient-DArMFG67.mjs";import{createMutatorRunner as q}from"./packem_shared/createMutatorRunner-CuMRJpUx.mjs";import{O as v}from"./packem_shared/offline-queue-xntsWiKt.mjs";import{createInMemoryPersistence as z,createIndexedDbPersistence as K}from"./packem_shared/createInMemoryPersistence-Cz2W6XVj.mjs";import{preloadQuery as W,preloadedQueryResult as X}from"./packem_shared/preloadQuery-uFy24PCR.mjs";import{createInMemoryQueryCache as G,createIndexedDbQueryCache as H,queryCacheKey as J}from"./packem_shared/createInMemoryQueryCache-D2uNHLfM.mjs";import{createReconnect as Z}from"./packem_shared/createReconnect-CjTmjJDH.mjs";import{default as ee}from"./packem_shared/createSnapshotPrecondition-GRVKxPsh.mjs";import{DEFAULT_MAX_BUFFER as oe,createStream as te}from"./packem_shared/DEFAULT_MAX_BUFFER-D3QH2iaq.mjs";import{SubscriptionRegistry as ce}from"./packem_shared/SubscriptionRegistry-CS-AFUI9.mjs";import{ClientServiceWorker as ne}from"./packem_shared/ClientServiceWorker-DXnBXeWK.mjs";import{createReply as ie,sendToSw as fe}from"./packem_shared/createReply-CwFABEJs.mjs";export{Q as CONFLICT_ERROR_CODE,ne as ClientServiceWorker,oe as DEFAULT_MAX_BUFFER,k as LunoraClient,v as OfflineQueue,a as RETIRE_AFTER_DURABLE_SEQ_ADVANCE,ce as SubscriptionRegistry,R as TabCoordinator,_ as TransportError,o as anyApi,S as applyDelta,m as createAsyncStoragePersistence,f as createAsyncStorageQueryCache,l as createCallRunner,d as createClientQuery,x as createInMemoryBookmarkStorage,z as createInMemoryPersistence,G as createInMemoryQueryCache,K as createIndexedDbPersistence,H as createIndexedDbQueryCache,P as createLocalStore,q as createMutatorRunner,Z as createReconnect,ie as createReply,ee as createSnapshotPrecondition,te as createStream,h as getErrorCode,I as getRetryAfterMs,O as httpStream,M as isConflictError,T as isForbiddenError,A as isMutationDelta,g as isRateLimitedError,F as isUnauthorizedError,c as maxSeq,W as preloadQuery,X as preloadedQueryResult,J as queryCacheKey,p as reconcileOptimistic,fe as sendToSw};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{LunoraError as m}from"@lunora/errors";import{i as oe,a as ce,P as he}from"./delta-merge-vxvH3PvF.mjs";import{e as K,d as T}from"./wire-codec-Sw1rAu-Z.mjs";import{s as q}from"./wire-key-HsUDTlQ7.mjs";import de from"./createInMemoryBookmarkStorage-BooZhW0n.mjs";import{ClientQueryStore as ue}from"./createClientQuery-B8Nfj-7o.mjs";import{TabCoordinator as le}from"./TabCoordinator-CXD7vulJ.mjs";import{TransportError as R,getRetryAfterMs as Z}from"./CONFLICT_ERROR_CODE-BOeeP_Wl.mjs";import{httpStream as fe}from"./httpStream-CPdblK2G.mjs";import{d as L,n as _,f as A,a as me,c as pe}from"./local-store-CVfQDdXy.mjs";import{O as ye,n as W,i as Se,r as be}from"./offline-queue-xntsWiKt.mjs";import{resolvePersistenceAdapter as Te}from"./createInMemoryPersistence-Cz2W6XVj.mjs";import{resolveQueryCacheAdapter as ve,queryCacheKey as E}from"./createInMemoryQueryCache-D2uNHLfM.mjs";import{createReconnect as $}from"./createReconnect-CjTmjJDH.mjs";import ge from"./createSnapshotPrecondition-GRVKxPsh.mjs";import{createStream as ke}from"./DEFAULT_MAX_BUFFER-D3QH2iaq.mjs";import{SubscriptionRegistry as g}from"./SubscriptionRegistry-CS-AFUI9.mjs";const U=500,Ce=async o=>{const e=[];let t;for(;;){const s=await o(t);if(e.push(...Array.isArray(s.records)?s.records:[]),s.truncated!==!0||typeof s.cursor!="string"||s.cursor.length===0)return e;if(s.cursor===t)throw new Error("collectPages: the list did not advance its cursor — refusing to page forever");t=s.cursor}},G=(o,e)=>{if(o.size<e)return;const t=o.keys().next().value;t!==void 0&&o.delete(t)};class I{listeners=new Set;add(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}emit(...e){const[t]=e;for(const s of this.listeners)try{s(t)}catch{}}clear(){this.listeners.clear()}}const ee=new Set(["RATE_LIMITED","SHARD_ERROR","SHARD_UNAVAILABLE","TOO_MANY_REQUESTS"]),te=new Set(["TOKEN_EXPIRED","UNAUTHENTICATED","UNAUTHORIZED"]),we=o=>te.has(o?.code??""),Ee=o=>{if(o instanceof R)return!0;const e=o?.code;return e===void 0||ee.has(e)||te.has(e)},se=6e4,_e=1e3,re=o=>{if(o===null)return;const e=Number(o);if(Number.isFinite(e))return e>0?e*1e3:void 0;const t=Date.parse(o);if(Number.isNaN(t))return;const s=t-Date.now();return s>0?s:void 0},Ae={401:"UNAUTHORIZED",403:"FORBIDDEN",404:"NOT_FOUND",413:"PAYLOAD_TOO_LARGE",429:"TOO_MANY_REQUESTS"},P=(o,e,t)=>{const s=re(t),r=s===void 0?void 0:{retryAfterMs:s},i=`LunoraClient: response carried no error envelope (status ${o.toString()}${e?` ${e}`:""})`;return o<400||o>=500||o===408?new R(i,r):new m(Ae[o]??"BAD_REQUEST",i,{data:r})},Ie=(o,e)=>{const t=re(e);if(!(t===void 0||Z(o)!==void 0))return o.data===void 0?{retryAfterMs:t}:typeof o.data=="object"&&o.data!==null&&!Array.isArray(o.data)?{...o.data,retryAfterMs:t}:void 0},Oe=(o,e=Math.random)=>{const t=Math.min(_e*2**Math.max(o-1,0),se);return Math.round(t*(.5+e()*.5))},Re=o=>o instanceof R||ee.has(o?.code??""),Pe=(o,e,t)=>{const s=Z(o);return s!==void 0&&s>0?Math.min(s,se):Re(o)?Oe(e,t):void 0},Me=983040,Fe=o=>typeof TextEncoder>"u"?o.length:new TextEncoder().encode(o).length,He="/_lunora/rpc",j="/_lunora/rpc-batch",Le="/_lunora/ws",N=o=>o===void 0||o===""?"":`&bucket=${encodeURIComponent(o)}`,M=o=>{for(let e=o.length-1;e>=0;e-=1)o[e]?.()},V=Symbol("lunora.unmergeableDelta"),Ue=(o,e)=>{for(const t of e)t.op==="delete"?o.delete(t.key):t.value!==void 0&&o.set(t.key,t.value)},Ne="lunora-ping",xe=3e4,De=1e4,Be=250,Qe=5e3,Ke=64,qe=8,We="/_lunora/admin/shard-traffic",$e="/_lunora/admin/scheduled",Ge="/_lunora/admin/scheduled/status",je="/_lunora/admin/scheduled/ws",Ve="/_lunora/admin/scheduled/cancel",z="/_lunora/admin/scheduled/dead",ze="/_lunora/admin/scheduled/dead/retry",Ye="/_lunora/admin/scheduled/dead/cancel",Je="/_lunora/admin/workflows/instances",Xe="/_lunora/admin/workflows/instance",Ze="/_lunora/admin/workflows/status",x="/_lunora/admin/storage",et="/_lunora/admin/storage/url",tt="/_lunora/admin/storage/buckets",st="/_lunora/admin/functions",rt="/_lunora/admin/cron-jobs",it="/_lunora/admin/cron-jobs/run",nt="/_lunora/admin/openapi",at="/_lunora/admin/openrpc",ot="/_lunora/admin/global/tables",ct="/_lunora/admin/global/table",ht="/_lunora/admin/global/facet",dt="/_lunora/admin/vector/indexes",ut="/_lunora/admin/vector/query",lt="/_lunora/admin/logs/archive",ft="/_lunora/admin/kv/namespaces",mt="/_lunora/admin/kv/keys",D="/_lunora/admin/kv/value",pt="/_lunora/admin/auth/users",yt="/_lunora/admin/auth/sessions",St="/_lunora/admin/auth/users/create",bt="/_lunora/admin/auth/users/role",Tt="/_lunora/admin/auth/users/ban",vt="/_lunora/admin/auth/users/unban",gt="/_lunora/admin/auth/users/password",kt="/_lunora/admin/auth/users/remove",Ct="/_lunora/admin/auth/users/impersonate",wt="/_lunora/admin/auth/sessions/revoke",Et="/_lunora/admin/auth/sessions/revoke-all",_t="/_lunora/admin/auth/capabilities",At="/_lunora/admin/auth/users/update",It="/_lunora/admin/auth/accounts",Ot="/_lunora/admin/auth/accounts/unlink",Rt="/_lunora/admin/auth/passkeys",Pt="/_lunora/admin/auth/passkeys/delete",Mt="/_lunora/admin/auth/two-factor/disable",Ft="/_lunora/admin/auth/organizations",Ht="/_lunora/admin/auth/organizations/members",Lt="/_lunora/admin/auth/organizations/invitations",Ut="/_lunora/admin/auth/organizations/members/remove",Nt="/_lunora/admin/auth/organizations/invitations/cancel",xt="/_lunora/admin/auth/config",Dt="/_lunora/admin/auth/sign-up-invitations",Bt="/_lunora/admin/auth/sign-up-invitations/create",Qt="/_lunora/admin/auth/sign-up-invitations/revoke",Kt="/_lunora/admin/auth/organizations/create",qt="/_lunora/admin/auth/organizations/update",Wt="/_lunora/admin/auth/organizations/remove",$t="/_lunora/admin/auth/organizations/members/add",Gt="/_lunora/admin/auth/organizations/members/invite",jt="/_lunora/admin/auth/organizations/members/role",Vt="/_lunora/admin/auth/organizations/teams",zt="/_lunora/admin/auth/organizations/teams/create",Yt="/_lunora/admin/auth/organizations/teams/update",Jt="/_lunora/admin/auth/organizations/teams/remove",Xt="/_lunora/admin/auth/organizations/teams/members",Zt="/_lunora/admin/auth/organizations/teams/members/add",es="/_lunora/admin/auth/organizations/teams/members/remove",ts="/_lunora/admin/auth/organizations/roles",ss="/_lunora/admin/auth/organizations/roles/create",rs="/_lunora/admin/auth/organizations/roles/update",is="/_lunora/admin/auth/organizations/roles/remove",ns="/api/auth",as="/get-session",Y=o=>o.startsWith("https://")?`wss://${o.slice(8)}`:o.startsWith("http://")?`ws://${o.slice(7)}`:o,C=(o,e)=>`${o.endsWith("/")?o.slice(0,-1):o}${e}`,y=(o,e)=>{const t=new URLSearchParams;for(const[r,i]of Object.entries(e))i!==void 0&&i!==""&&t.set(r,String(i));const s=t.toString();return s===""?o:`${o}?${s}`},os=[he],l=o=>o??"",ie=(o,e)=>{const t=o.error,s=typeof t?.code=="string"?t.code:void 0,r=typeof t?.message=="string"?t.message:void 0;return{code:s,messageText:(typeof o.message=="string"?o.message:void 0)??r??e}},cs=o=>{const{code:e,messageText:t}=ie(o,"stream error");return e===void 0?new Error(t):new m(e,t)},J=o=>{const{code:e,messageText:t}=ie(o,"subscription error");return{message:t,...e===void 0?{}:{code:e}}};function B(o){if(o!==void 0)return e=>{o(e)}}const O=(o,e)=>{for(const t of o)try{t(e)}catch{}},hs=new TextDecoder,ds=o=>{if(typeof o=="string")return o;if(o instanceof ArrayBuffer)return hs.decode(o)},b=(o,e)=>{if(!o.socket||o.wsState!=="open")return!1;try{return o.socket.send(JSON.stringify(e)),!0}catch{return!1}},F=o=>{const e=new Error(o.message??"request failed");return e.code=o.code,o.data!==void 0&&(e.data=T(o.data)),o.hint!==void 0&&(e.hint=o.hint),o.docsUrl!==void 0&&(e.docsUrl=o.docsUrl),e},X=(o,e)=>{const t=F(o),s=Ie(t,e);return s!==void 0&&(t.data=s),t},k=(o,e)=>{try{return K(o)}catch(t){const s=t instanceof Error?t.message:String(t);throw new TypeError(`LunoraClient: cannot encode ${e} — ${s}`,t instanceof Error?{cause:t}:void 0)}},Q=o=>"args"in o?{...o,args:T(o.args)}:o,us=(o,e)=>{const t=Array.from({length:e});for(const s of o){if(typeof s.id!="number"||s.id<0||s.id>=e)continue;const r=s.body;t[s.id]=r&&"error"in r&&r.error?{error:F(r.error),ok:!1}:{ok:!0,value:T(r?.result)}}return t.map(s=>s??{error:new Error("batch call returned no result"),ok:!1})},ls=Promise.resolve();class ne{static MAX_POKE_BUFFERS=256;static createClientQuery(e,t){return{defaultValue:t,key:e}}url;wsUrl;clientQueryStore;wsToken;authBasePath;fetchImpl;WebSocketImpl;bookmark;reconnectOptions;connectTimeoutMs;heartbeatIntervalMs;offlineQueue;outbox;clientId;shardCursors=new Map;defaultShardKey;readyResolved=!1;readyResolve;readyPromise;clientWatermarks=new Map;outboxMutationCounter=0;onPersistenceError;persistence;persistenceVersion;outboxLeaderRelease;queryCache;hydratedQueryCache=new Map;cacheSeededQueries=new Map;pendingCacheWrites=new Map;cacheFlushTimer;subscriptions=new g;tabCoordinator;leaderStatus;leaderWasEverConnected=!1;connections=new Map;defaultConnectionContext;connectionContexts=new Map;connectionContextHolders=new Map;authToken=null;authSubject=void 0;subjectToken=null;queuedIdentities=new Map;queuedOfflineShardKeys=new Set;closed=!1;authTokenListeners=new I;statusListeners=new I;tokenExpiredListeners=new I;authRefusalNotifiedFor;mutationSettledListeners=new I;pendingChangeListeners=new I;whisperHandlers=new Map;lastStatus="idle";nextSubId=0;nextStreamId=0;streams=new Map;adminSocketTeardowns=new Set;offlineFlushes=new Map;replayRetryState=new Map;replayRetryTimers=new Map;shapeSubscriptions=new Map;pokeBuffers=new Map;nextShapeId=0;constructor(e){this.url=e.url,this.wsUrl=e.wsUrl??C(Y(e.url),Le),this.wsToken=e.wsToken;const t=e.authBasePath??ns;this.authBasePath=t.endsWith("/")?t.slice(0,-1):t,this.fetchImpl=e.fetch??(typeof fetch=="function"?fetch.bind(globalThis):void 0),this.WebSocketImpl=e.WebSocket??(typeof WebSocket=="function"?WebSocket:void 0),this.bookmark=e.bookmarkStorage??de(),this.reconnectOptions=e.reconnect,this.heartbeatIntervalMs=e.heartbeatIntervalMs??xe,this.connectTimeoutMs=e.connectTimeoutMs??De,this.defaultConnectionContext=e.connectionContext,this.persistence=Te(e.persistence,e.outbox===void 0),this.persistenceVersion=e.persistenceVersion,this.queryCache=ve(e.queryCache),this.onPersistenceError=e.offlineQueue?.onPersistenceError,this.clientQueryStore=new ue,e.crossTabSync?(this.tabCoordinator=this.createTabCoordinator(),this.tabCoordinator.start()):this.tabCoordinator=void 0,e.hydrateOnStart&&this.queryCache?this.readyPromise=new Promise(s=>{this.readyResolve=s}):(this.readyResolved=!0,this.readyPromise=ls),this.offlineQueue=new ye(e.offlineQueue,{onEvict:(s,r)=>{this.emitItemSettled(s,"rejected",r)},onSizeChange:s=>{this.pendingChangeListeners.emit(s)},persistence:this.persistence,version:e.persistenceVersion}),this.outbox=e.outbox,this.clientId=e.clientId??`client-${W()}`,this.persistence&&queueMicrotask(()=>{this.hydrateAsOutboxLeader()}),this.queryCache&&queueMicrotask(()=>{(async()=>{try{await this.hydrateQueryCache()}catch{}finally{this.readyResolved=!0,this.readyResolve?.()}})().catch(()=>{})})}setAuthToken(e,t){const s=this.authToken!==e,r=this.identityFingerprint(),i=this.authSubject===void 0||this.subjectToken===this.authToken,n=this.subjectAwaitingReconfirm();this.authToken=e,t!==void 0?(this.authSubject=t,this.subjectToken=e):e===null&&(this.authSubject=void 0,this.subjectToken=null);const a=this.identityFingerprint();if(a!==r&&(!s&&i?(this.restampQueuedIdentity(r,a),this.restampWatermarks(r,a),this.restampConnectionIdentity(r,a),this.reseedFromHydratedCache()):this.rejectQueuedForIdentityChange(r),this.tabCoordinator)){const c=this.tabCoordinator.isLeader();this.tabCoordinator.stop(),this.tabCoordinator=this.createTabCoordinator(),this.tabCoordinator.start(),c&&this.tabCoordinator.promoteImmediately()}this.syncReadCacheToCredential(n),s&&this.authTokenListeners.emit(e),this.offlineQueue.size>0&&this.computeStatus()==="connected"&&this.flushAllOfflineQueues()}getAuthToken(){return this.authToken}currentIdentity(){return this.identityFingerprint()}replayIdentityVerdict(e){if(this.subjectAwaitingReconfirm())return"unknown";const t=this.identityFingerprint();return e===t||e!==void 0&&this.isSameCredentialUnderTokenHash(e)?"match":t===null?"unknown":"mismatch"}clientIdentifier(){return this.clientId}confirmedMutationWatermark(e){return this.clientWatermarks.get(this.identityFingerprint()??"")?.get(e??"")??0}async callMutator(e,t,s){const r=s?.clientSeq;if(r!==void 0&&(!Number.isInteger(r)||r<=0))throw new m("INTERNAL",`callMutator: clientSeq must be a positive integer, got ${String(r)}`);const i=s?.shardKey??"",n=this.identityFingerprint();let a;const c=await this.rpc(e,t,s?.shardKey,{captureBookmark:!0,clientId:this.clientId,clientSeq:r,onMutationAck:d=>{a=d}});if(a!==void 0&&a>(this.clientWatermarks.get(n??"")?.get(i)??0)){let d=this.clientWatermarks.get(n??"");d===void 0&&(G(this.clientWatermarks,qe),d=new Map,this.clientWatermarks.set(n??"",d)),d.set(i,a)}return{applied:a===void 0||a===r,result:c}}onAuthTokenChange(e){return this.authTokenListeners.add(e)}async getCurrentUser(){if(this.closed||!this.fetchImpl)return null;const e={},t=this.authToken;this.authToken&&(e.authorization=`Bearer ${this.authToken}`);try{const s=await this.fetchImpl(C(this.url,`${this.authBasePath}${as}`),{credentials:"include",headers:e,method:"GET"});if(!s.ok)return null;const i=(await s.json())?.user??null;return this.adoptResolvedSubject(t,i),i}catch{return null}}setWsToken(e){if(this.wsToken!==e){this.wsToken=e;for(const t of this.connections.values())if(t.socket)try{t.socket.close()}catch{}}}setConnectionContext(e,t={}){this.assertLeaderOwnedSurface("setConnectionContext");const s=l(t.shardKey);e===void 0?this.connectionContexts.delete(s):this.connectionContexts.set(s,e),this.refreshConnectionContext(s)}acquireConnectionContext(e,t={}){if(this.followsAnotherTab())return()=>{};const s=l(t.shardKey),r={context:e},i=this.connectionContextHolders.get(s);i?i.push(r):this.connectionContextHolders.set(s,[r]),this.refreshConnectionContext(s);let n=!1;return()=>{if(n)return;n=!0;const a=this.connectionContextHolders.get(s);if(!a)return;const c=a.indexOf(r);c!==-1&&a.splice(c,1),a.length===0&&this.connectionContextHolders.delete(s),this.refreshConnectionContext(s)}}whisperSubscribe(e,t,s={}){this.assertLeaderOwnedSurface("whisperSubscribe");const r=l(s.shardKey);let i=this.whisperHandlers.get(r);i||(i=new Map,this.whisperHandlers.set(r,i));let n=i.get(e);const a=n===void 0;if(n||(n=new Set,i.set(e,n)),n.add(t),this.ensureSocket(s.shardKey),a){const c=this.getConnection(s.shardKey);c&&b(c,{topic:e,type:"whisper_subscribe"})}return()=>{const c=this.whisperHandlers.get(r),h=c?.get(e);if(!h?.delete(t)||h.size>0)return;c?.delete(e),c?.size===0&&this.whisperHandlers.delete(r);const d=this.getConnection(s.shardKey);d&&b(d,{topic:e,type:"whisper_unsubscribe"})}}whisper(e,t,s={}){this.assertLeaderOwnedSurface("whisper"),this.ensureSocket(s.shardKey);const r=this.getConnection(s.shardKey);r&&b(r,{data:k(t??null,`whisper data for topic '${e}'`),topic:e,type:"whisper"})}onTokenExpired(e){return this.tokenExpiredListeners.add(e)}connectionStatus(){return this.computeStatus()}onConnectionStatus(e){const t=this.statusListeners.add(e);return e(this.computeStatus()),t}pendingCount(){return this.offlineQueue.size}debug(){const e=[],t=this.clientWatermarks.get(this.identityFingerprint()??""),s=new Set([...this.connections.keys(),...t?.keys()??[]]);for(const i of s){const n=this.connections.get(i);e.push({confirmedMutationWatermark:t?.get(i)??0,hasSocket:n?.socket!==void 0,shardKey:i===""?void 0:i,wasEverConnected:n?.wasEverConnected??!1,wsState:n?.wsState??"idle"})}const r=this.subscriptions.all().map(i=>({acked:i.acked,functionPath:i.fn.__lunoraRef,id:i.id,kind:"query",lastMutationId:i.lastMutationId,pendingOptimisticLayers:i.optimisticLayers.length,serverCursor:i.serverCursor,shardKey:i.shardKey,subscriberCount:i.callbacks.size}));for(const i of this.shapeSubscriptions.values())r.push({acked:i.serverCursor!==void 0,functionPath:`shape:${i.name}`,id:i.id,kind:"shape",lastMutationId:i.lastMutationId,pendingOptimisticLayers:0,rowCount:i.rows.size,serverCursor:i.serverCursor,shardKey:i.shardKey,subscriberCount:i.callbacks.size});return{clientId:this.clientId,closed:this.closed,connectionStatus:this.computeStatus(),pendingWrites:this.offlineQueue.size,shards:e.toSorted((i,n)=>(i.shardKey??"").localeCompare(n.shardKey??"")),subscriptions:r.toSorted((i,n)=>i.functionPath.localeCompare(n.functionPath))}}onPendingChange(e){const t=this.pendingChangeListeners.add(e);return e(this.offlineQueue.size),t}onMutationSettled(e){return this.mutationSettledListeners.add(e)}getWebSocketImpl(){return this.WebSocketImpl}getClientQuery(e){return this.clientQueryStore.get(e)}setClientQuery(e,t){this.clientQueryStore.set(e,t)}subscribeClientQuery(e,t){return this.clientQueryStore.subscribe(e,t)}resetClientQuery(e){this.clientQueryStore.reset(e)}snapshotPrecondition(e,t,s){return ge(this,e,t,s)}whenReady(){return this.readyPromise}get isReady(){return this.readyResolved}peekHydratedQuery(e,t,s){if(!this.readyResolved)return;const r=q(t),i=E(e,r,s),n=this.hydratedQueryCache.get(i);if(n!==void 0)return this.cachedQueryMatchesIdentity(n)?n.value:void 0}peekActiveQuerySnapshot(e,t,s){const r=g.key(e,t,s),i=this.subscriptions.get(r);return{present:i!==void 0,value:i?.lastValue}}async query(e,t,s={}){return this.assertOpen(),await this.rpc(e.__lunoraRef,t,s.shardKey,{attachBookmark:!0})}async batch(e){if(this.assertOpen(),!this.fetchImpl)throw new m("INTERNAL","LunoraClient: no `fetch` implementation available");if(e.length===0)return[];const t=await this.fetchImpl(C(this.url,j),{body:JSON.stringify({calls:e.map((i,n)=>({args:k(i.args??{},`args for batch call '${i.fn.__lunoraRef}'`),functionPath:i.fn.__lunoraRef,id:n,shardKey:i.shardKey}))}),headers:this.rpcRequestHeaders({attachBookmark:!0}),method:"POST"}),s=t.headers.get("x-d1-bookmark");s&&this.bookmark.set(s);let r;try{r=await t.json()}catch{throw new m("INTERNAL",`LunoraClient: batch response was not JSON (status ${t.status.toString()})`)}if(!t.ok||r.error&&!r.results)throw r.error?F(r.error):new m("INTERNAL",`LunoraClient: batch request failed (status ${t.status.toString()})`);for(const i of r.results??[]){const n=i.body?.commitCursor;typeof i.id=="number"&&typeof n=="number"&&this.recordShardCursor(e[i.id]?.shardKey,n)}return us(r.results??[],e.length)}async mutation(e,t,s={}){this.assertOpen();const r=t,i=s.mutationId??W(),{confirms:n,rollbacks:a}=this.applyOptimisticUpdates(e.__lunoraRef,r,s.shardKey,s.optimistic);s.optimisticUpdate&&this.applyOptimisticUpdate(s.optimisticUpdate,t,s.shardKey,a,n);const c=this.offlineFlushes.get(l(s.shardKey));c!==void 0&&await c;const{hasSocket:h,wasEverConnected:d,wsState:u}=this.connectionGateState(s.shardKey),{queueBeforeFirstConnect:f}=this.offlineQueue,S=d||f,p=this.WebSocketImpl!==void 0&&S;if(u!=="open"&&!h&&p||u==="connecting"&&S)return this.enqueueOfflineMutation(e,r,s.shardKey,i,a,n,s.precondition);try{let w;const ae=await this.rpc(e.__lunoraRef,r,s.shardKey,{captureBookmark:!0,mutationId:i,onCommitCursor:H=>{w=H}});for(const H of n)H(w);return ae}catch(w){throw M(a),w}}async action(e,t,s={}){return this.assertOpen(),await this.rpc(e.__lunoraRef,t,s.shardKey,{attachBookmark:!0,captureBookmark:!0})}async importRows(e,t,s={}){this.assertOpen();const r=Math.max(1,Math.trunc(s.chunkSize??500)),i=s.toArgs??(h=>({rows:h})),n=t.length;let a=0,c=0;for(let h=0;h<n;h+=r){const d=t.slice(h,h+r),u=c;await this.mutation(e,i(d),{...s.importId===void 0?{}:{mutationId:`${s.importId}:${String(u)}`},shardKey:s.shardKey}),c+=1,a+=d.length,s.onProgress?.({done:a,total:n})}return{chunks:c,imported:a}}async shardTraffic(e){this.assertOpen();const t=await this.adminFetch(We,"POST",{table:e});return{failed:t.failed??0,ok:t.ok??0,shards:t.shards??[]}}async listScheduledJobs(){return this.assertOpen(),((await this.adminFetch($e,"GET")).records??[]).map(t=>Q(t))}async schedulerStatus(){this.assertOpen();const e=await this.adminFetch(Ge,"GET");return{backlog:e.backlog??0,inFlight:e.inFlight??0,pools:e.pools??[]}}async cancelScheduledJob(e){return this.assertOpen(),{cancelled:(await this.adminFetch(Ve,"POST",{id:e})).cancelled===!0}}async listDeadJobs(){return this.assertOpen(),(await Ce(async t=>await this.adminFetch(t===void 0?z:`${z}?cursor=${encodeURIComponent(t)}`,"GET"))).map(t=>Q(t))}async retryDeadJob(e){return this.assertOpen(),{retried:(await this.adminFetch(ze,"POST",{id:e})).retried===!0}}async removeDeadJob(e){return this.assertOpen(),{removed:(await this.adminFetch(Ye,"POST",{id:e})).removed===!0}}async listWorkflowInstances(e){this.assertOpen();const t=new URLSearchParams({name:e.name});e.status!==void 0&&t.set("status",e.status),e.page!==void 0&&t.set("page",String(e.page)),e.perPage!==void 0&&t.set("perPage",String(e.perPage));const s=await this.adminFetch(`${Je}?${t.toString()}`,"GET");return{configured:s.configured,instances:s.instances??[],page:s.page??1,perPage:s.perPage??e.perPage??0,totalCount:s.totalCount}}async getWorkflowInstance(e){this.assertOpen();const t=new URLSearchParams({id:e.id,name:e.name}),s=await this.adminFetch(`${Xe}?${t.toString()}`,"GET");return{createdOn:s.createdOn,endedOn:s.endedOn,error:s.error,id:s.id??e.id,output:s.output,params:s.params,startedOn:s.startedOn,status:s.status??"unknown",steps:s.steps??[]}}async setWorkflowInstanceStatus(e){return this.assertOpen(),{status:(await this.adminFetch(Ze,"POST",{action:e.action,id:e.id,name:e.name})).status??"unknown"}}subscribeScheduledJobs(e){if(this.assertOpen(),this.WebSocketImpl===void 0)return()=>{};const t=C(Y(this.url),je),s=$(this.reconnectOptions),r={connectTimer:void 0,heartbeatTimer:void 0,lastFrameAt:0,socket:void 0};let i,n=!1;const a=()=>{n||this.closed||(i=setTimeout(d,s.next()))},c=f=>{if(n||this.WebSocketImpl===void 0)return;const S=f===void 0?t:`${t}?token=${encodeURIComponent(f)}`;this.openManagedSocket(r,S,this.connectTimeoutMs,{onClose:()=>{a()},onMessage:p=>{let v;try{v=JSON.parse(typeof p.data=="string"?p.data:"")}catch{return}v.type==="jobs"&&Array.isArray(v.records)&&(s.reset(),e(v.records.map(w=>Q(w))))}})},h=async f=>{let S;try{S=await f()}catch{a();return}c(S)},d=()=>{if(n||this.WebSocketImpl===void 0)return;const{wsToken:f}=this;if(typeof f=="function"){h(f).catch(()=>{});return}c(f)};d();const u=()=>{n=!0,i!==void 0&&(clearTimeout(i),i=void 0),r.connectTimer!==void 0&&(clearTimeout(r.connectTimer),r.connectTimer=void 0),this.stopHeartbeat(r),r.socket?.close(),r.socket=void 0};return this.adminSocketTeardowns.add(u),()=>{this.adminSocketTeardowns.delete(u),u()}}async listFunctions(){return this.assertOpen(),(await this.adminFetch(st,"GET")).functions??[]}async getCronJobs(){return this.assertOpen(),(await this.adminFetch(rt,"GET")).jobs??[]}async runCronJob(e){this.assertOpen();const t=await this.adminFetch(it,"POST",{name:e});return{name:t.name??e,ran:t.ran===!0}}async fetchOpenApi(){return this.assertOpen(),await this.adminFetch(nt,"GET")}async fetchOpenRpc(){return this.assertOpen(),await this.adminFetch(at,"GET")}async listStorageObjects(e={}){this.assertOpen();const t=y(x,{bucket:e.bucket,cursor:e.cursor,limit:e.limit,prefix:e.prefix}),s=await this.adminFetch(t,"GET");return{cursor:s.cursor,objects:s.objects??[]}}async deleteStorageObject(e,t){this.assertOpen();const s=`${x}?key=${encodeURIComponent(e)}${N(t?.bucket)}`,r=await this.adminFetch(s,"DELETE");return{deleted:r.deleted===!0,key:r.key??e}}async listStorageBuckets(){return this.assertOpen(),(await this.adminFetch(tt,"GET")).buckets??[]}async uploadStorageObject(e){this.assertOpen();const t=`${x}?key=${encodeURIComponent(e.key)}${N(e.bucket)}`,s=await this.adminFetch(t,"PUT",e.body,e.contentType);return{etag:s.etag,key:s.key??e.key}}async signedStorageUrl(e,t){this.assertOpen();const s=t?.expiresInSeconds,r=s===void 0?"":`&expiresIn=${encodeURIComponent(s.toString())}`,i=`${et}?key=${encodeURIComponent(e)}${r}${N(t?.bucket)}`,n=await this.adminFetch(i,"GET");if(typeof n.url!="string")throw new TypeError("LunoraClient: storage URL endpoint returned no `url`");return n.url}async listGlobalTables(){return this.assertOpen(),await this.adminFetch(ot,"GET")}async readGlobalTablePage(e){this.assertOpen();const t=new URLSearchParams({table:e.table});return e.limit!==void 0&&t.set("limit",String(e.limit)),e.offset!==void 0&&t.set("offset",String(e.offset)),e.filters!==void 0&&e.filters.length>0&&t.set("filters",JSON.stringify(K(e.filters))),T(await this.adminFetch(`${ct}?${t.toString()}`,"GET"))}async facetGlobalColumn(e){this.assertOpen();const t=new URLSearchParams({column:e.column,table:e.table});return e.limit!==void 0&&t.set("limit",String(e.limit)),e.filters!==void 0&&e.filters.length>0&&t.set("filters",JSON.stringify(K(e.filters))),T(await this.adminFetch(`${ht}?${t.toString()}`,"GET"))}async listVectorIndexes(){return this.assertOpen(),(await this.adminFetch(dt,"GET")).indexes??[]}async queryVectorIndex(e){return this.assertOpen(),(await this.adminFetch(ut,"POST",e)).matches??[]}async queryLogArchive(e={}){this.assertOpen();const t=await this.adminFetch(lt,"POST",e);return{nextCursor:t.nextCursor,rows:t.rows??[]}}async listKvNamespaces(){return this.assertOpen(),(await this.adminFetch(ft,"GET")).namespaces??[]}async listKvKeys(e){this.assertOpen();const t=y(mt,{cursor:e.cursor,limit:e.limit,namespace:e.namespace,prefix:e.prefix});return await this.adminFetch(t,"GET")}async getKvValue(e){this.assertOpen();const t=y(D,{key:e.key,namespace:e.namespace});return await this.adminFetch(t,"GET")}async putKvValue(e){this.assertOpen(),await this.adminFetch(D,"PUT",e)}async deleteKvKey(e){this.assertOpen();const t=y(D,{key:e.key,namespace:e.namespace});await this.adminFetch(t,"DELETE")}async listAuthUsers(e={}){this.assertOpen();const t=y(pt,{filterField:e.filterField,filterValue:e.filterValue,limit:e.limit,offset:e.offset,search:e.search,searchField:e.searchField,sortBy:e.sortBy,sortDirection:e.sortDirection});return await this.adminFetch(t,"GET")}async createAuthUser(e){return await this.adminFetch(St,"POST",e)}async setAuthUserRole(e){return await this.adminFetch(bt,"POST",e)}async banAuthUser(e){return await this.adminFetch(Tt,"POST",e)}async unbanAuthUser(e){return await this.adminFetch(vt,"POST",e)}async setAuthUserPassword(e){await this.adminFetch(gt,"POST",e)}async removeAuthUser(e){await this.adminFetch(kt,"POST",e)}async impersonateAuthUser(e){return await this.adminFetch(Ct,"POST",e)}async revokeAuthSession(e){await this.adminFetch(wt,"POST",e)}async revokeAuthUserSessions(e){await this.adminFetch(Et,"POST",e)}async getAuthCapabilities(){return await this.adminFetch(_t,"GET")}async updateAuthUser(e){return await this.adminFetch(At,"POST",e)}async listAuthAccounts(e){return await this.adminFetch(y(It,{userId:e.userId}),"GET")}async unlinkAuthAccount(e){await this.adminFetch(Ot,"POST",e)}async listAuthPasskeys(e){return await this.adminFetch(y(Rt,{userId:e.userId}),"GET")}async deleteAuthPasskey(e){await this.adminFetch(Pt,"POST",e)}async disableAuthTwoFactor(e){await this.adminFetch(Mt,"POST",e)}async listAuthOrganizations(e={}){return await this.adminFetch(y(Ft,{limit:e.limit,offset:e.offset}),"GET")}async listAuthOrgMembers(e){const t=y(Ht,{limit:e.limit,offset:e.offset,organizationId:e.organizationId});return await this.adminFetch(t,"GET")}async listAuthOrgInvitations(e){const t=y(Lt,{limit:e.limit,offset:e.offset,organizationId:e.organizationId});return await this.adminFetch(t,"GET")}async listAuthSignUpInvitations(e={}){const t=y(Dt,{limit:e.limit,offset:e.offset});return await this.adminFetch(t,"GET")}async createAuthSignUpInvitation(e){return await this.adminFetch(Bt,"POST",e)}async revokeAuthSignUpInvitation(e){await this.adminFetch(Qt,"POST",e)}async removeAuthOrgMember(e){await this.adminFetch(Ut,"POST",e)}async cancelAuthOrgInvitation(e){await this.adminFetch(Nt,"POST",e)}async getAuthConfig(){return await this.adminFetch(xt,"GET")}async createAuthOrganization(e){return await this.adminFetch(Kt,"POST",e)}async updateAuthOrganization(e){return await this.adminFetch(qt,"POST",e)}async deleteAuthOrganization(e){await this.adminFetch(Wt,"POST",e)}async addAuthOrgMember(e){return await this.adminFetch($t,"POST",e)}async inviteAuthOrgMember(e){return await this.adminFetch(Gt,"POST",e)}async setAuthOrgMemberRole(e){return await this.adminFetch(jt,"POST",e)}async listAuthOrgTeams(e){const t=y(Vt,{limit:e.limit,offset:e.offset,organizationId:e.organizationId});return await this.adminFetch(t,"GET")}async createAuthOrgTeam(e){return await this.adminFetch(zt,"POST",e)}async updateAuthOrgTeam(e){return await this.adminFetch(Yt,"POST",e)}async removeAuthOrgTeam(e){await this.adminFetch(Jt,"POST",e)}async listAuthOrgTeamMembers(e){const t=y(Xt,{limit:e.limit,offset:e.offset,teamId:e.teamId});return await this.adminFetch(t,"GET")}async addAuthOrgTeamMember(e){return await this.adminFetch(Zt,"POST",e)}async removeAuthOrgTeamMember(e){await this.adminFetch(es,"POST",e)}async listAuthOrgRoles(e){const t=y(ts,{limit:e.limit,offset:e.offset,organizationId:e.organizationId});return await this.adminFetch(t,"GET")}async createAuthOrgRole(e){return await this.adminFetch(ss,"POST",e)}async updateAuthOrgRole(e){return await this.adminFetch(rs,"POST",e)}async deleteAuthOrgRole(e){await this.adminFetch(is,"POST",e)}async listAuthSessions(e={}){this.assertOpen();const t=y(yt,{limit:e.limit,offset:e.offset,userId:e.userId});return await this.adminFetch(t,"GET")}subscribe(e,t,s,r={}){this.assertOpen();const i=t??{},n=g.key(e.__lunoraRef,i,r.shardKey);let a=this.subscriptions.get(n);const c=B(s),h=B(r.onError),d=B(r.onCheckpoint);if(!a){this.nextSubId+=1;const f=`sub_${this.nextSubId.toString()}`,S=q(i),p=this.takeHydratedCache(e.__lunoraRef,S,r.shardKey);a={acked:!1,args:i,argsKey:S,callbacks:new Set,checkpointCallbacks:new Set,errorCallbacks:new Set,fn:e,id:f,lastValue:p?.value,optimisticLayers:[],serverBase:p?.value,serverCursor:p?.serverCursor,shardKey:r.shardKey,wireArgs:k(i,`args for '${e.__lunoraRef}'`),...p?.serverEpoch===void 0?{}:{serverEpoch:p.serverEpoch}},this.subscriptions.add(a),p!==void 0&&this.cacheSeededQueries.set(n,p)}if(a.callbacks.add(c),h&&a.errorCallbacks.add(h),d&&a.checkpointCallbacks.add(d),a.lastValue!==void 0)try{c(a.lastValue)}catch{}this.ensureSocket(r.shardKey),this.sendSubscribeIfOpen(a);const u=a;return()=>{u.callbacks.delete(c),h&&u.errorCallbacks.delete(h),d&&u.checkpointCallbacks.delete(d),u.callbacks.size===0&&(this.sendOrQueueUnsubscribe(u.shardKey,u.id,"unsubscribe"),this.subscriptions.remove(u))}}subscribeShape(e,t,s={}){if(this.assertOpen(),this.followsAnotherTab()){const{onError:n}=s;return n!==void 0&&queueMicrotask(()=>{n({code:"NOT_IMPLEMENTED",message:"LunoraClient: `subscribeShape` is unavailable on a cross-tab follower tab. The `crossTabSync` channel only carries data from the leader tab outward and shape pokes are not part of that broadcast set, so this subscription could never resolve. Turn off `crossTabSync`, or use a `list`-backed collection, which IS relayed."})}),()=>{}}this.nextShapeId+=1;const r=`shape_${this.nextShapeId.toString()}`,i={args:e.args,callbacks:new Set([t]),errorCallbacks:s.onError?new Set([s.onError]):new Set,id:r,name:e.name,onCheckpoint:s.onCheckpoint,rows:new Map,shardKey:s.shardKey,wireArgs:e.args===void 0?void 0:k(e.args,`shape args for '${e.name}'`)};return this.shapeSubscriptions.set(r,i),this.ensureSocket(s.shardKey),this.sendShapeSubscribeIfOpen(i),()=>{this.shapeSubscriptions.delete(r),this.sendOrQueueUnsubscribe(i.shardKey,r,"shape_unsubscribe")}}stream(e,t,s={}){if(this.assertOpen(),this.WebSocketImpl===void 0)throw new m("INTERNAL","LunoraClient: streams require a WebSocket implementation");this.nextStreamId+=1;const r=`stream_${this.nextStreamId.toString()}`,{shardKey:i}=s,n=t??{},{handle:a,iterable:c}=ke({maxBuffer:s.maxBuffer,onCancel:()=>{this.cancelStream(r,i)}});this.ensureSocket(i);const h=this.getConnection(i),d={id:r,query:{args:k(n,`stream args for '${e.__lunoraRef}'`),functionPath:e.__lunoraRef,shardKey:i},type:"stream"},u={durable:s.durable===!0,generation:void 0,handle:a,lastSeq:0,message:d,shardKey:i,started:!1};this.streams.set(r,u);const f=h?.wsState==="open"&&b(h,d);if(u.started=f,!f&&h===void 0)return this.streams.delete(r),a.fail(new m("STREAM_DISCONNECTED","stream unavailable: this tab is not the cross-tab WebSocket leader, so it holds no socket to stream over")),c;if(!f){for(h.pendingStreams=h.pendingStreams??[];h.pendingStreams.length>=Ke;){const p=h.pendingStreams.shift()?.id,v=p?this.streams.get(p):void 0;v&&(v.handle.fail(new m("STREAM_QUEUE_OVERFLOW","stream-start frame evicted while socket was unreachable")),this.streams.delete(p))}h.pendingStreams.push(d)}return c}httpStream(e,t,s={}){if(this.closed)throw new m("CLIENT_CLOSED","LunoraClient is closed");if(!this.fetchImpl)throw new m("INTERNAL","LunoraClient: no `fetch` implementation available");const r={...this.authToken?{authorization:`Bearer ${this.authToken}`}:{},...s.headers};return fe(e,t,{baseUrl:this.url,fetch:this.fetchImpl,headers:r,maxBuffer:s.maxBuffer,signal:s.signal})}close(){this.closed=!0,this.outboxLeaderRelease?.(),this.outboxLeaderRelease=void 0;for(const e of this.streams.values())e.handle.fail(new m("CLIENT_CLOSED","LunoraClient closed"));this.streams.clear();for(const e of this.connections.values())this.teardownConnection(e);for(const e of this.adminSocketTeardowns)e();this.adminSocketTeardowns.clear();for(const e of this.replayRetryTimers.values())clearTimeout(e);this.replayRetryTimers.clear(),this.replayRetryState.clear(),this.offlineQueue.clear(),this.queuedIdentities.clear(),this.cacheFlushTimer!==void 0&&(clearTimeout(this.cacheFlushTimer),this.cacheFlushTimer=void 0),this.pendingCacheWrites.size>0&&this.flushQueryCacheWrites().catch(()=>{}),this.authTokenListeners.clear(),this.statusListeners.clear(),this.tokenExpiredListeners.clear(),this.mutationSettledListeners.clear(),this.pendingChangeListeners.clear(),this.whisperHandlers.clear(),this.shapeSubscriptions.clear(),this.pokeBuffers.clear(),this.subscriptions.clear(),this.clientQueryStore.clear(),this.hydratedQueryCache.clear(),this.cacheSeededQueries.clear(),this.tabCoordinator?.stop(),this.tabCoordinator=void 0}assertOpen(){if(this.closed)throw new m("INTERNAL","LunoraClient is closed")}followsAnotherTab(){const e=this.tabCoordinator;if(e===void 0||e.isLeader())return!1;const t=e.leaderTabId;return t!==void 0&&t!==e.id}assertLeaderOwnedSurface(e){if(this.followsAnotherTab())throw new m("NOT_IMPLEMENTED",`LunoraClient: \`${e}\` is unavailable on a cross-tab follower tab. The \`crossTabSync\` channel only carries data from the leader tab outward, so this call could never reach the server. Turn off \`crossTabSync\`, or keep \`${e}\` on the leader tab.`)}clearConnectionTimers(e){clearTimeout(e.reconnectTimer),clearTimeout(e.connectTimer),clearTimeout(e.stableTimer),e.reconnectTimer=void 0,e.connectTimer=void 0,e.stableTimer=void 0}teardownConnection(e){const t=l(e.shardKey);for(const[s,r]of this.streams)l(r.shardKey)===t&&(r.handle.fail(new m("STREAM_DISCONNECTED","stream terminated: the connection carrying it was torn down")),this.streams.delete(s));if(e.pendingStreams=void 0,e.pendingUnsubscribes=[],this.clearConnectionTimers(e),this.stopHeartbeat(e),e.socket){try{e.socket.close()}catch{}e.socket=void 0}e.wsState="closed"}createTabCoordinator(){const e=`lunora-bridge::${this.url}::${this.identityFingerprint()??"anon"}`;return new le({channelName:e,onBecomeLeader:()=>{for(const t of this.subscriptions.all())this.ensureSocket(t.shardKey),this.sendSubscribeIfOpen(t);for(const t of this.queuedOfflineShardKeys)this.ensureSocket(t);this.tabCoordinator?.broadcastConnectionStatus(this.computeStatus(),this.identityFingerprint())},onStopBeingLeader:()=>{for(const[t,s]of this.connections)this.teardownConnection(s),this.connections.delete(t);this.leaderStatus=void 0,this.leaderWasEverConnected=!1},onConnectionStatus:(t,s)=>{if(s!==void 0&&s!==this.identityFingerprint())return;const r=t==="connected"&&this.leaderStatus!=="connected";this.leaderStatus=t,t==="connected"&&(this.leaderWasEverConnected=!0),this.emitConnectionStatus(),r&&this.flushAllOfflineQueues()},onSubscriptionData:(t,s,r,i,n)=>{if(n!==void 0&&n!==this.identityFingerprint())return;const a=this.subscriptions.get(t);a&&(a.serverBase=s,this.dropCacheSeed(t),r!==void 0&&(a.serverCursor=r,i!==void 0&&(a.serverEpoch=i),L(a,r)),_(a,A(s,a.optimisticLayers)))},onLeaderClaimAnswered:()=>{this.tabCoordinator?.isLeader()&&this.tabCoordinator.broadcastConnectionStatus(this.computeStatus(),this.identityFingerprint())},onSubscriptionError:(t,s,r)=>{if(r!==void 0&&r!==this.identityFingerprint())return;const i=this.subscriptions.get(t);i&&O(i.errorCallbacks,s)},onSubscriptionSettled:(t,s,r,i,n,a)=>{if(a!==void 0&&a!==this.identityFingerprint())return;const c=this.subscriptions.get(t);if(c){this.ackAndAdvanceCursor(c,s,r),i!==void 0&&n===this.clientId&&(c.lastMutationId=Math.max(c.lastMutationId??0,i));for(const h of c.checkpointCallbacks)h({checkpoint:c.serverCursor,mutationId:c.lastMutationId})}}})}async enqueueOfflineMutation(e,t,s,r,i,n,a){const c=this.identityFingerprint();if(this.outbox){this.outboxMutationCounter+=1;const h=this.outboxMutationCounter;try{await this.outbox.enqueue({args:t,clientId:this.clientId,functionPath:e.__lunoraRef,idempotencyKey:`${this.clientId}:${String(h)}`,identity:c,mutationId:h,shardKey:s})}catch(d){throw M(i),d instanceof Error?d:new Error(String(d))}for(const d of n)d(void 0);return}return new Promise((h,d)=>{const u={args:t,functionPath:e.__lunoraRef,liveAwaiter:!0,id:r,clientId:this.clientId,identity:c,precondition:a,onCommit:f=>{for(const S of n)S(f)},reject:f=>{this.queuedIdentities.delete(r),M(i),d(f instanceof Error?f:new Error(String(f)))},resolve:h,shardKey:s};this.offlineQueue.enqueue(u),this.queuedOfflineShardKeys.add(s),u.id!==void 0&&this.queuedIdentities.set(u.id,c)})}async hydratePersistedQueue(){try{const e=await this.offlineQueue.hydrate();for(const t of e)this.queuedOfflineShardKeys.add(t),this.ensureSocket(t)}catch{}}hydrateAsOutboxLeader(){const e=()=>{this.hydratePersistedQueue().catch(()=>{})},t=globalThis.navigator?.locks;if(!t){e();return}t.request(`lunora:outbox-leader:${this.url}`,()=>(this.closed||e(),new Promise(s=>{if(this.closed){s();return}this.outboxLeaderRelease=s}))).catch(e)}async hydrateQueryCache(){if(this.queryCache)try{const e=await this.queryCache.load(),t=new Map;for(const s of this.subscriptions.all())t.set(E(s.fn.__lunoraRef,s.argsKey,s.shardKey),s);for(const{key:s,...r}of e){if(Se(this.persistenceVersion,r.version)){this.queryCache.remove(s).catch(()=>{});continue}const i=t.get(s);if(i&&this.cachedQueryMatchesIdentity(r)){this.seedSubscriptionFromCache(i,r);continue}this.hydratedQueryCache.set(s,r)}}catch{}}seedSubscriptionFromCache(e,t){e.serverBase!==void 0||e.lastValue!==void 0||!this.cachedQueryMatchesIdentity(t)||(e.serverBase=t.value,e.serverCursor=t.serverCursor,t.serverEpoch!==void 0&&(e.serverEpoch=t.serverEpoch),this.cacheSeededQueries.set(E(e.fn.__lunoraRef,e.argsKey,e.shardKey),t),_(e,A(t.value,e.optimisticLayers)))}syncReadCacheToCredential(e){this.subjectAwaitingReconfirm()?this.revokeCacheSeededValues():e&&this.reseedFromHydratedCache()}dropCacheSeed(e){this.cacheSeededQueries.delete(e),this.hydratedQueryCache.delete(e)}revokeCacheSeededValues(){if(this.cacheSeededQueries.size!==0){for(const[e,t]of this.cacheSeededQueries){const s=this.subscriptions.get(e);s!==void 0&&(s.serverBase=void 0,s.serverCursor=void 0,s.serverEpoch=void 0,_(s,A(void 0,s.optimisticLayers))),this.hydratedQueryCache.set(e,t)}this.cacheSeededQueries.clear()}}takeHydratedCache(e,t,s){const r=E(e,t,s),i=this.hydratedQueryCache.get(r);if(!(i===void 0||!this.cachedQueryMatchesIdentity(i)))return this.hydratedQueryCache.delete(r),i}reseedFromHydratedCache(){if(this.hydratedQueryCache.size!==0)for(const e of this.subscriptions.all()){const t=E(e.fn.__lunoraRef,e.argsKey,e.shardKey),s=this.hydratedQueryCache.get(t);s!==void 0&&this.cachedQueryMatchesIdentity(s)&&(this.hydratedQueryCache.delete(t),this.seedSubscriptionFromCache(e,s))}}persistQueryValue(e){const t=e.serverBase;if(!this.queryCache||t===void 0)return;const s=E(e.fn.__lunoraRef,e.argsKey,e.shardKey),r=this.getConnection(e.shardKey)?.identity,i=r===void 0?this.identityFingerprint():r;this.pendingCacheWrites.set(s,{identity:i,serverCursor:e.serverCursor,ts:Date.now(),value:t,...i===this.identityFingerprint()&&!this.subjectAwaitingReconfirm()?this.credentialStamp():{},...e.serverEpoch===void 0?{}:{serverEpoch:e.serverEpoch},...this.persistenceVersion===void 0?{}:{version:this.persistenceVersion}}),this.cacheFlushTimer??=setTimeout(()=>{this.flushQueryCacheWrites().catch(()=>{})},Be)}async flushQueryCacheWrites(){this.cacheFlushTimer=void 0;const{queryCache:e}=this;if(!e){this.pendingCacheWrites.clear();return}const t=[...this.pendingCacheWrites.entries()];this.pendingCacheWrites.clear(),await Promise.allSettled(t.map(async([s,r])=>e.put(s,r)))}computeStatus(){if(this.tabCoordinator&&!this.tabCoordinator.isLeader())return this.leaderStatus??"idle";const e=[...this.connections.values()];return e.length===0?"idle":e.some(t=>t.wsState==="open")?"connected":e.some(t=>t.wsState==="connecting")?"connecting":"offline"}emitConnectionStatus(){const e=this.computeStatus();e!==this.lastStatus&&(this.lastStatus=e,this.statusListeners.emit(e),this.tabCoordinator?.isLeader()&&this.tabCoordinator.broadcastConnectionStatus(e,this.identityFingerprint()))}emitItemSettled(e,t,s){this.mutationSettledListeners.emit({args:e.args,code:s===void 0?void 0:s.code,error:s,functionPath:e.functionPath,hadAwaiter:e.liveAwaiter??!1,id:e.id??"",shardKey:e.shardKey,status:t})}applyOptimisticUpdates(e,t,s,r){const i=[],n=[];if(!r)return{confirms:i,rollbacks:n};const a=g.key(e,t,s),c=this.subscriptions.get(a);if(c){const h=me(c,r);h&&(i.push(h.confirm),n.push(h.rollback))}return{confirms:i,rollbacks:n}}applyOptimisticUpdate(e,t,s,r,i){const{confirms:n,rollbacks:a,store:c}=pe(this.subscriptions,s);try{e(c,t)}catch{M(a);return}r.push(...a),i.push(...n)}getConnection(e){return this.connections.get(l(e))}sendOrQueueUnsubscribe(e,t,s){const r=this.getConnection(e);r&&!b(r,{id:t,type:s})&&r.pendingUnsubscribes.push({id:t,type:s})}connectionGateState(e){if(this.tabCoordinator&&!this.tabCoordinator.isLeader()){let s="idle";return this.leaderStatus==="connected"?s="open":this.leaderStatus==="connecting"&&(s="connecting"),{hasSocket:!1,wasEverConnected:this.leaderWasEverConnected,wsState:s}}const t=this.getConnection(e);return{hasSocket:t?.socket!==void 0,wasEverConnected:t?.wasEverConnected??!1,wsState:t?.wsState??"idle"}}getOrCreateConnection(e){const t=l(e);let s=this.connections.get(t);return s||(s={connectTimer:void 0,heartbeatTimer:void 0,lastFrameAt:0,pendingUnsubscribes:[],reconnect:$(this.reconnectOptions),reconnectTimer:void 0,shardKey:e,socket:void 0,stableTimer:void 0,wasEverConnected:!1,wsState:"idle"},this.connections.set(t,s)),s}wsUrlFor(e,t){const s=[];if(e!==void 0&&s.push(`shard=${encodeURIComponent(e)}`),t!==void 0&&s.push(`token=${encodeURIComponent(t)}`),s.length===0)return this.wsUrl;const r=this.wsUrl.includes("?")?"&":"?";return`${this.wsUrl}${r}${s.join("&")}`}rpcRequestHeaders(e,t){const s={"content-type":"application/json"},r=this.shardCursors.get(this.cursorKeyFor(t));if(r!==void 0&&(s["x-lunora-min-seq"]=r.toString()),this.authToken&&(s.authorization=`Bearer ${this.authToken}`),e.mutationId&&(s["x-lunora-mutation-id"]=e.mutationId),(e.clientId!==void 0||e.mutationId!==void 0)&&(s["x-lunora-client-id"]=e.clientId??this.clientId),e.clientSeq!==void 0&&(s["x-lunora-client-seq"]=e.clientSeq.toString()),e.attachBookmark){const i=this.bookmark.get();i&&(s["x-d1-bookmark"]=i)}return s}async rpc(e,t,s,r={}){if(!this.fetchImpl)throw new R("LunoraClient: no `fetch` implementation available");const i=this.rpcRequestHeaders(r,s),n=await this.fetchImpl(C(this.url,He),{body:JSON.stringify({args:k(t,`args for '${e}'`),functionPath:e,shardKey:s}),headers:i,method:"POST"});if(r.captureBookmark){const c=n.headers.get("x-d1-bookmark");c&&this.bookmark.set(c)}let a;try{a=await n.json()}catch{throw P(n.status,n.statusText,n.headers.get("retry-after"))}if("error"in a)throw X(a.error,n.headers.get("retry-after"));if(!n.ok)throw P(n.status,n.statusText,n.headers.get("retry-after"));return r.onMutationAck?.(a.lastMutationId),r.onCommitCursor?.(a.commitCursor),this.learnDefaultShardKey(n,s),this.recordShardCursor(s,a.commitCursor),T(a.result)}async adminFetch(e,t,s,r){if(!this.fetchImpl)throw new m("INTERNAL","LunoraClient: no `fetch` implementation available");const i={};this.authToken&&(i.authorization=`Bearer ${this.authToken}`);const n=s instanceof ArrayBuffer||s instanceof Blob;let a;s===void 0?a=void 0:n?(a=s,r!==void 0&&(i["content-type"]=r)):(a=JSON.stringify(s),i["content-type"]="application/json");const c=await this.fetchImpl(C(this.url,e),{body:a,headers:i,method:t});let h;try{h=await c.json()}catch{const d=c.statusText?` ${c.statusText}`:"";throw new m("INTERNAL",`LunoraClient: response was not JSON (status ${c.status.toString()}${d})`)}if(typeof h=="object"&&h!==null&&"error"in h){const d=h.error,u=new Error(d.message??"admin request failed");throw u.code=d.code,u}if(!c.ok){const d=c.statusText?` ${c.statusText}`:"";throw new m("INTERNAL",`LunoraClient: admin request failed (status ${c.status.toString()}${d})`)}return h}effectiveConnectionContext(e){const t=this.connectionContextHolders.get(e);return t&&t.length>0?t[t.length-1]?.context:this.connectionContexts.get(e)??this.defaultConnectionContext}refreshConnectionContext(e){const t=this.connections.get(e);t?.wsState==="open"&&this.sendConnectEnvelope(t)}sendConnectEnvelope(e){const t=this.effectiveConnectionContext(l(e.shardKey));b(e,{caps:os,clientId:this.clientId,id:"connect",type:"connect",...t===void 0?{}:{context:t}})}resendShapeSubscriptions(e){for(const t of this.shapeSubscriptions.values())l(t.shardKey)===l(e)&&this.sendShapeSubscribeIfOpen(t)}ensureSocket(e){if(this.closed||this.WebSocketImpl===void 0||this.tabCoordinator&&!this.tabCoordinator.isLeader())return;const t=this.getOrCreateConnection(e);if(!(t.wsState==="open"||t.wsState==="connecting")){if(t.wsState="connecting",this.emitConnectionStatus(),typeof this.wsToken=="function"){this.openSocketWithProvidedToken(t,e,this.wsToken).catch(()=>{});return}this.openSocket(t,e,this.wsToken)}}async openSocketWithProvidedToken(e,t,s){let r;try{r=await s()}catch{this.handleDisconnect(e);return}this.closed||this.WebSocketImpl===void 0||e.wsState!=="connecting"||e.socket!==void 0||this.openSocket(e,t,r)}openManagedSocket(e,t,s,r){const{WebSocketImpl:i}=this;if(i===void 0)throw new m("INTERNAL","no WebSocket implementation available");const n=new i(t);e.socket=n;const a=()=>{this.stopHeartbeat(e),e.connectTimer!==void 0&&(clearTimeout(e.connectTimer),e.connectTimer=void 0),e.socket===n&&(e.socket=void 0)},c=h=>{a(),r.onClose(h)};s>0&&(e.connectTimer=setTimeout(()=>{if(e.connectTimer=void 0,e.socket===n){try{n.close()}catch{}c()}},s)),n.addEventListener("open",()=>{if(e.socket===n){e.connectTimer!==void 0&&(clearTimeout(e.connectTimer),e.connectTimer=void 0),e.lastFrameAt=Date.now();try{r.onOpen?.()}catch(h){console.error("[lunora] connection open handler threw",h)}this.startHeartbeat(e,c)}}),n.addEventListener("message",h=>{if(e.socket===n){e.lastFrameAt=Date.now();try{r.onMessage(h)}catch(d){console.error("[lunora] server frame handler threw",d)}}}),n.addEventListener("close",h=>{e.socket===n&&c(h)}),n.addEventListener("error",()=>{e.socket===n&&c()})}openSocket(e,t,s){this.WebSocketImpl!==void 0&&(e.identity=this.identityFingerprint(),this.openManagedSocket(e,this.wsUrlFor(t,s),this.connectTimeoutMs,{onClose:r=>{r?.code===4001&&this.notifyTokenExpired(),this.handleDisconnect(e)},onMessage:r=>{this.handleServerMessage(r.data,t)},onOpen:()=>{e.wsState="open",e.wasEverConnected=!0,clearTimeout(e.stableTimer),e.stableTimer=setTimeout(()=>{e.wsState==="open"&&e.reconnect.reset()},Qe),this.emitConnectionStatus(),this.sendConnectEnvelope(e),this.markShardPendingAck(t);for(const i of this.subscriptions.all())l(i.shardKey)===l(t)&&this.sendSubscribeIfOpen(i);if(this.resendShapeSubscriptions(t),e.pendingUnsubscribes.length>0){const i=e.pendingUnsubscribes;e.pendingUnsubscribes=[];for(const{id:n,type:a}of i)b(e,{id:n,type:a})}this.flushPendingStreams(e);const r=this.whisperHandlers.get(l(t));if(r)for(const i of r.keys())b(e,{topic:i,type:"whisper_subscribe"});this.flushOfflineQueue(t).catch(()=>{})}}))}flushPendingStreams(e){if(!e.pendingStreams||e.pendingStreams.length===0)return;const t=e.pendingStreams;e.pendingStreams=[];for(const s of t){const r=b(e,s)?this.streams.get(String(s.id)):void 0;r&&(r.started=!0)}}cancelStream(e,t){const s=this.getConnection(t),r=this.streams.get(e);s&&(s.pendingStreams=s.pendingStreams?.filter(i=>i.id!==e),!b(s,{id:e,type:"unsubscribe"})&&r?.durable===!0&&r.started&&s.pendingUnsubscribes.push({id:e,type:"unsubscribe"})),this.streams.delete(e)}handleDisconnect(e){if(this.closed||e.wsState==="idle"||e.wsState==="closed")return;this.stopHeartbeat(e),this.clearConnectionTimers(e),e.socket=void 0,e.wsState="idle",this.emitConnectionStatus(),this.markShardPendingAck(e.shardKey);const t=new Set((e.pendingStreams??[]).map(r=>r.id));for(const[r,i]of this.streams)if(!(l(i.shardKey)!==l(e.shardKey)||t.has(r))){if(i.durable){const n={...i.message,...i.generation===void 0?{}:{generation:i.generation},sinceChunk:i.lastSeq};i.message=n,e.pendingStreams=[...(e.pendingStreams??[]).filter(a=>a.id!==r),n];continue}i.handle.fail(new m("STREAM_DISCONNECTED","stream terminated: WebSocket disconnected")),this.streams.delete(r)}if(this.WebSocketImpl===void 0)return;const s=e.reconnect.next();e.reconnectTimer=setTimeout(()=>{e.reconnectTimer=void 0,this.ensureSocket(e.shardKey)},s)}startHeartbeat(e,t){this.stopHeartbeat(e),!(this.heartbeatIntervalMs<=0)&&(e.heartbeatTimer=setInterval(()=>{if(!e.socket)return;const{socket:s}=e;if(Date.now()-e.lastFrameAt>this.heartbeatIntervalMs*2.5){try{s.close()}catch{}t();return}try{s.send(Ne)}catch{}},this.heartbeatIntervalMs))}stopHeartbeat(e){e.heartbeatTimer!==void 0&&(clearInterval(e.heartbeatTimer),e.heartbeatTimer=void 0)}markShardPendingAck(e){const t=l(e);for(const s of this.subscriptions.all())l(s.shardKey)===t&&(s.acked=!1)}sendSubscribeIfOpen(e){const t=this.getConnection(e.shardKey);if(t?.wsState!=="open"||e.acked)return;const s=e.fn.__lunoraTable??e.fn.__lunoraRef,r=e.serverCursor!==void 0&&e.serverBase!==void 0;b(t,{id:e.id,query:{args:e.wireArgs,functionPath:e.fn.__lunoraRef,table:s,...r?{sinceSeq:e.serverCursor}:{},...r&&e.serverEpoch!==void 0?{sinceEpoch:e.serverEpoch}:{}},type:"subscribe"})}sendShapeSubscribeIfOpen(e){const t=this.getConnection(e.shardKey);t?.wsState==="open"&&b(t,{id:e.id,shape:{name:e.name,...e.wireArgs===void 0?{}:{args:e.wireArgs}},type:"shape_subscribe",...e.serverCursor===void 0?{}:{sinceCheckpoint:e.serverCursor},...e.serverEpoch===void 0?{}:{sinceEpoch:e.serverEpoch}})}handleServerMessage(e,t){const s=ds(e);if(s===void 0)return;let r;try{r=JSON.parse(s)}catch{return}switch(r.type!=="error"&&this.getConnection(t)?.reconnect.reset(),r.type){case"ack":{const i=this.subscriptions.getById(r.id);i&&(i.acked=!0);return}case"chunk":{const{data:i,generation:n,id:a,seq:c}=r,h=this.streams.get(a);h&&typeof c=="number"&&(h.lastSeq=c,typeof n=="number"&&(h.generation=n),h.durable=!0),h?.handle.push(T(i));return}case"complete":{this.handleCompleteMessage(r.id);return}case"data":case"delta":{this.handleDataMessage(r);return}case"error":{this.handleErrorMessage(r);break}case"pokeEnd":{this.handlePokeEnd(r,t);break}case"pokePart":{this.handlePokePart(r,t);break}case"pokeStart":{this.handlePokeStart(r,t);break}case"resume":{this.handleResumeMessage(r);break}case"settled":{this.handleSettledMessage(r);break}case"whisper":{this.dispatchWhisper(r,t);break}}}handleErrorMessage(e){if(e.error?.code==="TOKEN_EXPIRED"){this.notifyTokenExpired();return}const{id:s}=e,r=s===void 0?void 0:this.streams.get(s);if(r&&s!==void 0){r.handle.fail(cs(e)),this.streams.delete(s);return}const i=s===void 0?void 0:this.subscriptions.getById(s);if(i){const a=J(e),c=this.identityFingerprint(),h=g.keyOf(i);O(i.errorCallbacks,a),this.tabCoordinator?.isLeader()&&this.tabCoordinator.broadcastSubscriptionError(h,a,c);return}const n=s===void 0?void 0:this.shapeSubscriptions.get(s);n&&O(n.errorCallbacks,J(e))}pokeBufferKey(e,t){return`${l(e)}\0${t}`}handlePokeStart(e,t){G(this.pokeBuffers,ne.MAX_POKE_BUFFERS),this.pokeBuffers.set(this.pokeBufferKey(t,e.pokeId),{baseCheckpoint:e.baseCheckpoint,bases:new Map,epoch:e.epoch,lastMutationId:new Map,parts:new Map,resets:new Set})}handlePokePart(e,t){const s=this.pokeBuffers.get(this.pokeBufferKey(t,e.pokeId));if(!s)return;const r=s.parts.get(e.shapeId)??[];for(const n of e.rowsPatch)r.push(n.value===void 0?n:{...n,value:T(n.value)});s.parts.set(e.shapeId,r),e.lastMutationId!==void 0&&s.lastMutationId.set(e.shapeId,e.lastMutationId);const i=e.baseCheckpoint??s.baseCheckpoint;i!==void 0&&s.bases.set(e.shapeId,i),e.reset===!0&&s.resets.add(e.shapeId)}handlePokeEnd(e,t){const s=this.pokeBufferKey(t,e.pokeId),r=this.pokeBuffers.get(s);if(r){this.pokeBuffers.delete(s);for(const i of r.parts.keys()){const n=this.shapeSubscriptions.get(i);n&&this.applyPokePart(n,r,e)}}}applyPokePart(e,t,s){const r=t.parts.get(e.id)??[],i=t.resets.has(e.id),n=t.bases.get(e.id),a=t.epoch!==void 0&&e.serverEpoch!==void 0&&t.epoch!==e.serverEpoch,c=n!==void 0&&e.serverCursor!==void 0&&e.serverCursor!==n;if(!i&&(a||c)){e.rows.clear(),e.serverCursor=void 0,e.serverEpoch=void 0,this.emitShapeRows(e),this.sendShapeSubscribeIfOpen(e);return}i&&e.rows.clear(),Ue(e.rows,r),s.checkpoint!==void 0&&(e.serverCursor=s.checkpoint),s.epoch!==void 0&&(e.serverEpoch=s.epoch);const h=t.lastMutationId.get(e.id);h!==void 0&&(e.lastMutationId=h),this.emitShapeRows(e),e.onCheckpoint?.({checkpoint:e.serverCursor,mutationId:e.lastMutationId})}resnapshotSubscription(e){e.acked=!1,e.serverCursor=void 0,e.serverEpoch=void 0,console.warn("[lunora] could not merge a row delta into the cached result; re-subscribing for a full snapshot"),this.sendSubscribeIfOpen(e)}emitShapeRows(e){const t=[...e.rows.values()];for(const s of e.callbacks)try{s(t)}catch{}}handleDataMessage(e){const{id:t}=e,s=t?this.subscriptions.getById(t):void 0;if(!s)return;let r;try{r=this.resolveDataPayload(e,s)}catch(i){O(s.errorCallbacks,{code:"WIRE_DECODE_FAILED",message:`could not decode a server frame for this subscription — ${i instanceof Error?i.message:String(i)}`});return}if(r===V){this.resnapshotSubscription(s);return}if(s.serverBase=r,this.dropCacheSeed(g.keyOf(s)),e.cursor!==void 0&&(s.serverCursor=e.cursor),e.epoch!==void 0&&(s.serverEpoch=e.epoch),e.lastMutationId!==void 0){s.lastMutationId=Math.max(s.lastMutationId??0,e.lastMutationId);for(const i of s.checkpointCallbacks)i({checkpoint:s.serverCursor,mutationId:s.lastMutationId,rowsFollow:!0})}if(this.persistQueryValue(s),L(s,s.serverCursor),_(s,A(r,s.optimisticLayers)),this.tabCoordinator?.isLeader()){const i=g.keyOf(s);this.tabCoordinator.broadcastSubscriptionData(i,r,s.serverCursor,s.serverEpoch,this.identityFingerprint())}}handleResumeMessage(e){const t=this.subscriptions.getById(e.id);t&&this.ackAndAdvanceCursor(t,e.cursor,e.epoch)}handleSettledMessage(e){const t=this.subscriptions.getById(e.id);if(t){this.ackAndAdvanceCursor(t,e.cursor,e.epoch),e.lastMutationId!==void 0&&(t.lastMutationId=Math.max(t.lastMutationId??0,e.lastMutationId));for(const s of t.checkpointCallbacks)s({checkpoint:t.serverCursor,mutationId:t.lastMutationId});if(this.tabCoordinator?.isLeader()){const s=g.keyOf(t);this.tabCoordinator.broadcastSubscriptionSettled(s,t.serverCursor,t.serverEpoch,t.lastMutationId,this.clientId,this.identityFingerprint())}}}ackAndAdvanceCursor(e,t,s){e.acked=!0,(t!==void 0&&t!==e.serverCursor||s!==void 0&&s!==e.serverEpoch)&&(t!==void 0&&(e.serverCursor=t),s!==void 0&&(e.serverEpoch=s),this.persistQueryValue(e),L(e,e.serverCursor)&&_(e,A(e.serverBase,e.optimisticLayers)))}resolveDataPayload(e,t){if("data"in e&&e.data!==void 0)return T(e.data);const s=T(e.delta);return oe(s)?t.serverBase===void 0?s:ce(t.serverBase,s)??V:s}dispatchWhisper(e,t){const s=this.whisperHandlers.get(l(t))?.get(e.topic);if(!s)return;const r=T(e.data);for(const i of s)try{i(r,e.from)}catch{}}notifyTokenExpired(){this.tokenExpiredListeners.emit()}handleCompleteMessage(e){const t=this.streams.get(e);if(t){t.handle.complete(),this.streams.delete(e);return}const s=this.subscriptions.getById(e);s&&(s.acked=!1,O(s.errorCallbacks,{code:"SUBSCRIPTION_CANCELLED",message:"subscription was cancelled by the server"}))}unpersist(e){e&&this.persistence?.remove(e).catch(t=>{be(this.onPersistenceError,"remove",t,e)})}identityFingerprint(){if(this.authSubject!==void 0)return this.authSubject===null?null:`subj:${this.authSubject}`;const e=this.authToken;return e===null?null:this.hashToken(e)}hashToken(e){let t=2166136261,s=5381;for(let r=0;r<e.length;r+=1){const i=e.charCodeAt(r);t^=i,t=Math.imul(t,16777619),s=Math.imul(s,33)+i}return`${e.length.toString(36)}:${(t>>>0).toString(36)}:${(s>>>0).toString(36)}`}credentialStamp(){const e=this.authToken;return e===null?{}:{credential:this.hashToken(e)}}cachedQueryMatchesIdentity(e){return!this.subjectAwaitingReconfirm()&&e.identity===this.identityFingerprint()||this.isSameCredentialUnderTokenHash(e.identity)?!0:e.credential!==void 0&&e.credential===this.credentialStamp().credential}isSameCredentialUnderTokenHash(e){if(e===null||e.startsWith("subj:"))return!1;const t=this.authToken;return t===null?!1:this.hashToken(t)===e}adoptResolvedSubject(e,t){this.closed||t===null||this.authToken!==e||this.setAuthToken(e,t.id)}subjectAwaitingReconfirm(){return this.authSubject!==void 0&&this.authSubject!==null&&this.subjectToken!==this.authToken}stampOf(e){const t=e.id===void 0?void 0:this.queuedIdentities.get(e.id);return t===void 0?e.identity:t}rejectQueuedForIdentityChange(e){const t=this.offlineQueue.drain(),s=[];for(const r of t){if(this.replayIdentityVerdict(this.stampOf(r))!=="mismatch"){s.push(r);continue}this.queuedIdentities.delete(r.id??""),this.unpersist(r.id);const i=new Error("offline mutation discarded: auth identity changed before replay");i.code="OFFLINE_IDENTITY_CHANGED",r.reject(i),this.emitItemSettled(r,"rejected",i)}this.offlineQueue.requeue(s),e!==null&&this.clearQueryCacheForIdentityChange()}restampConnectionIdentity(e,t){for(const s of this.connections.values())s.identity===e&&(s.identity=t)}restampQueuedIdentity(e,t){for(const[s,r]of this.queuedIdentities)r===e&&this.queuedIdentities.set(s,t);this.offlineQueue.restampIdentity(e,t)}restampWatermarks(e,t){const s=e??"",r=this.clientWatermarks.get(s);if(r===void 0)return;this.clientWatermarks.delete(s);const i=t??"",n=this.clientWatermarks.get(i);if(n===void 0)this.clientWatermarks.set(i,r);else for(const[a,c]of r)n.set(a,c)}clearQueryCacheForIdentityChange(){this.revokeCacheSeededValues(),this.cacheFlushTimer!==void 0&&(clearTimeout(this.cacheFlushTimer),this.cacheFlushTimer=void 0),this.pendingCacheWrites.clear(),this.hydratedQueryCache.clear(),this.queryCache?.clear().catch(()=>{})}flushAllOfflineQueues(){for(const e of this.queuedOfflineShardKeys)this.flushOfflineQueue(e).catch(()=>{})}async flushOfflineQueue(e){const t=l(e),s=this.offlineFlushes.get(t);if(s===void 0&&this.offlineQueue.size===0)return;const r=(async()=>{await(s??Promise.resolve());try{await this.drainOfflineQueue(e)}catch{}})();this.offlineFlushes.set(t,r),await r,this.offlineFlushes.get(t)===r&&this.offlineFlushes.delete(t)}async drainOfflineQueue(e){const t=this.offlineQueue.drainConflict();for(const h of t){this.unpersist(h.id),this.queuedIdentities.delete(h.id??"");const d=new Error("offline mutation skipped: precondition failed before replay");d.code="OFFLINE_PRECONDITION_FAILED",this.emitItemSettled(h,"rejected",d)}const s=l(e),r=this.offlineQueue.drain(h=>l(h.shardKey)===s);if(r.length===0)return;const i=[],n=[];for(const h of r){const d=this.replayGateVerdict(h);d==="send"?i.push(h):d==="hold"&&n.push(h)}if(this.offlineQueue.requeue(n),n.length>0&&this.subjectAwaitingReconfirm()&&this.getCurrentUser().catch(()=>{}),i.length===0)return;const a=this.encodableOrSettleTerminal(i);if(a.length===0)return;if(a.length===1){await this.replaySequential(a,e),this.scheduleRateLimitedRetry(e);return}const c=[];for(let h=0;h<a.length;h+=U){const d=a.slice(h,h+U),u=await this.replayBatched(d,e);if(c.push(...u.requeue),u.stop){c.push(...a.slice(h+U));break}}c.length>0&&this.offlineQueue.requeue(c),this.scheduleRateLimitedRetry(e)}noteReplayRetryDelay(e,t){const s=l(e),r=this.replayRetryState.get(s),i=(r?.attempts??0)+1,n=Pe(t,i);this.replayRetryState.set(s,{attempts:i,delayMs:n===void 0?r?.delayMs:Math.max(r?.delayMs??0,n)})}scheduleRateLimitedRetry(e){const t=l(e),s=this.replayRetryState.get(t),r=s?.delayMs;if(s===void 0||r===void 0||this.closed||this.offlineQueue.size===0){this.replayRetryState.delete(t);return}s.delayMs=void 0;const i=this.replayRetryTimers.get(t);i!==void 0&&clearTimeout(i),this.replayRetryTimers.set(t,setTimeout(()=>{this.replayRetryTimers.delete(t),this.flushOfflineQueue(e).catch(()=>{})},r))}encodableOrSettleTerminal(e){const t=[];for(const s of e)try{k(s.args,`args for '${s.functionPath}'`),t.push(s)}catch(r){this.settleReplayTerminal(s,r instanceof Error?r:new Error(String(r)))}return t}replayGateVerdict(e){const t=this.stampOf(e);if(t===void 0)return this.queuedIdentities.delete(e.id??""),"send";const s=this.replayIdentityVerdict(t);if(s==="unknown")return"hold";if(this.queuedIdentities.delete(e.id??""),s==="match")return"send";this.unpersist(e.id);const r=new Error("offline mutation skipped: auth identity changed before replay");return r.code="OFFLINE_IDENTITY_CHANGED",e.reject(r),this.emitItemSettled(e,"rejected",r),"reject"}settleReplaySuccess(e,t,s){this.unpersist(e.id),this.recordShardCursor(e.shardKey,s),e.onCommit?.(s),e.resolve(t),this.emitItemSettled(e,"committed")}cursorKeyFor(e){return e??this.defaultShardKey??""}learnDefaultShardKey(e,t){const s=e.headers.get("x-lunora-shard-key");if(s===null||t!==void 0||this.defaultShardKey===s)return;this.defaultShardKey=s;const r=this.shardCursors.get("");r!==void 0&&(this.shardCursors.set(s,Math.max(this.shardCursors.get(s)??0,r)),this.shardCursors.delete(""))}recordShardCursor(e,t){if(typeof t!="number")return;const s=this.cursorKeyFor(e);this.shardCursors.set(s,Math.max(this.shardCursors.get(s)??0,t))}shouldRequeueReplayFailure(e){if(we(e)){const t=this.hashToken(this.authToken??"");return this.authRefusalNotifiedFor!==t&&(this.authRefusalNotifiedFor=t,this.notifyTokenExpired()),!0}return Ee(e)}settleReplayTerminal(e,t){this.unpersist(e.id),e.reject(t),this.emitItemSettled(e,"rejected",t)}async replaySequential(e,t){for(let s=0;s<e.length;s+=1){const r=e[s];if(r)try{let i;const n=await this.rpc(r.functionPath,r.args,r.shardKey,{captureBookmark:!0,clientId:r.clientId??this.clientId,mutationId:r.id,onCommitCursor:a=>{i=a}});this.settleReplaySuccess(r,n,i)}catch(i){if(!this.shouldRequeueReplayFailure(i)){this.settleReplayTerminal(r,i);continue}this.noteReplayRetryDelay(t,i),this.offlineQueue.requeue(e.slice(s));return}}}async replayBatched(e,t){if(!this.fetchImpl)return{requeue:e,stop:!0};const s=JSON.stringify({calls:e.map((c,h)=>({args:k(c.args,`args for '${c.functionPath}'`),functionPath:c.functionPath,id:h,clientId:c.clientId??this.clientId,mutationId:c.id,shardKey:c.shardKey}))});if(e.length>1&&Fe(s)>Me)return await this.replayBatchedHalves(e,t);let r;try{r=await this.fetchImpl(C(this.url,j),{body:s,headers:this.rpcRequestHeaders({attachBookmark:!0}),method:"POST"})}catch{return{requeue:e,stop:!0}}const i=r.headers.get("x-d1-bookmark");if(i&&this.bookmark.set(i),r.status===413&&e.length>1)return await this.replayBatchedHalves(e,t);let n;const a=r.headers.get("retry-after");try{n=await r.json()}catch{return this.settleWholeBatchError(e,P(r.status,r.statusText,a),t)}if(!n.results){const c=n.error===void 0?P(r.status,r.statusText,a):X(n.error,a);return this.settleWholeBatchError(e,c,t)}return{requeue:this.settleReplayBatchSlots(e,n.results,t),stop:!1}}settleWholeBatchError(e,t,s){if(t instanceof R||t.code!==void 0&&this.shouldRequeueReplayFailure(t))return this.noteReplayRetryDelay(s,t),{requeue:e,stop:!0};for(const r of e)this.settleReplayTerminal(r,t);return{requeue:[],stop:!1}}async replayBatchedHalves(e,t){const s=Math.ceil(e.length/2),r=await this.replayBatched(e.slice(0,s),t);if(r.stop)return{requeue:[...r.requeue,...e.slice(s)],stop:!0};const i=await this.replayBatched(e.slice(s),t);return{requeue:[...r.requeue,...i.requeue],stop:i.stop}}settleReplayBatchSlots(e,t,s){const r=new Map;for(const n of t)typeof n.id=="number"&&n.body!==void 0&&r.set(n.id,n.body);const i=[];for(const[n,a]of e.entries()){const c=r.get(n);if(c===void 0)i.push(a);else if("error"in c){const h=F(c.error);this.shouldRequeueReplayFailure(h)?(this.noteReplayRetryDelay(s,h),i.push(a)):this.settleReplayTerminal(a,h)}else this.settleReplaySuccess(a,T(c.result),c.commitCursor)}return i}}export{ne as LunoraClient};
|
package/dist/packem_shared/{createServerClient-C74FjEQv.mjs → createServerClient-BrNyme3I.mjs}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{LunoraClient as r}from"./LunoraClient-
|
|
1
|
+
import{LunoraClient as r}from"./LunoraClient-DArMFG67.mjs";const c=e=>{const t=new r({fetch:e.fetch,url:e.url});return e.token!==void 0&&t.setAuthToken(e.token),t};export{c as createServerClient};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import{LunoraError as l}from"@lunora/errors";import{createStream as
|
|
1
|
+
import{LunoraError as l}from"@lunora/errors";import{d as h}from"./wire-codec-Sw1rAu-Z.mjs";import{createStream as u}from"./DEFAULT_MAX_BUFFER-D3QH2iaq.mjs";const m=/^ /u,p=t=>typeof t=="object"&&t!==null?JSON.stringify(t):String(t),S=t=>{let r="";const e=[];for(const n of t.split(`
|
|
2
2
|
`))n.startsWith("event:")?r=n.slice(6).replace(m,""):n.startsWith("data:")&&e.push(n.slice(5).replace(m,""));return{data:e.join(`
|
|
3
|
-
`),event:r}},
|
|
3
|
+
`),event:r}},T=(t,r,e)=>{const n=r.params??{},o=t.path.split("/").map(c=>{if(!c.startsWith(":"))return c;const f=c.slice(1),a=n[f];if(a===void 0)throw new l("HTTP_STREAM_MISSING_PARAM",`httpStream: missing path param ":${f}" for route ${t.path}`);return encodeURIComponent(p(a))}).join("/"),i=new URLSearchParams;for(const[c,f]of Object.entries(r.searchParams??{}))f!==void 0&&i.set(c,p(f));const s=i.toString();return`${e.endsWith("/")?e.slice(0,-1):e}${o}${s===""?"":`?${s}`}`},E=(t,r)=>{if(t.event==="complete")return r.complete(),!0;if(t.event==="error"){let e={};try{e=JSON.parse(t.data)}catch{}const n=typeof e.message=="string"?e.message:"stream error",o=typeof e.code=="string"?e.code:"HTTP_STREAM_ERROR";return r.fail(new l(o,n)),!0}if((t.event===""||t.event==="message")&&t.data!=="")try{r.push(h(JSON.parse(t.data)))}catch{return r.fail(new l("HTTP_STREAM_BAD_CHUNK","httpStream: malformed SSE chunk (invalid JSON)")),!0}return!1},b=async(t,r)=>{const e=t.getReader(),n=new TextDecoder;let o="";const i=()=>{let s=o.indexOf(`
|
|
4
4
|
|
|
5
|
-
`);for(;s!==-1;){const d=
|
|
5
|
+
`);for(;s!==-1;){const d=S(o.slice(0,s));if(o=o.slice(s+2),E(d,r))return!0;s=o.indexOf(`
|
|
6
6
|
|
|
7
7
|
`)}return!1};for(;;){const{done:s,value:d}=await e.read();if(s)break;if(o+=n.decode(d,{stream:!0}).replaceAll(`\r
|
|
8
8
|
`,`
|
|
9
9
|
`),i()){await e.cancel().catch(()=>{});return}}o+=n.decode().replaceAll(`\r
|
|
10
10
|
`,`
|
|
11
|
-
`),i()||r.fail(new l("HTTP_STREAM_INTERRUPTED","httpStream: stream ended without a complete frame"))},
|
|
11
|
+
`),i()||r.fail(new l("HTTP_STREAM_INTERRUPTED","httpStream: stream ended without a complete frame"))},_=(t,r,e={})=>{const n=e.fetch??(typeof fetch=="function"?fetch.bind(globalThis):void 0);if(!n)throw new l("INTERNAL","httpStream: no `fetch` implementation available");const o=T(t,r??{},e.baseUrl??""),i=new AbortController;let s;e.signal&&(e.signal.aborted?i.abort():(s=()=>{i.abort()},e.signal.addEventListener("abort",s,{once:!0})));const d=()=>{s&&e.signal?.removeEventListener("abort",s)},{handle:c,iterable:f}=u({maxBuffer:e.maxBuffer,onCancel:()=>{i.abort()}});return(async()=>{try{const a=await n(o,{headers:{accept:"text/event-stream",...e.headers},method:t.method,signal:i.signal});if(!a.ok){await a.body?.cancel().catch(()=>{}),c.fail(new l("HTTP_STREAM_STATUS",`httpStream: request failed (status ${a.status.toString()})`,{status:a.status}));return}if(!a.body){c.fail(new l("HTTP_STREAM_NO_BODY","httpStream: response has no body"));return}await b(a.body,c)}finally{d()}})().catch(a=>{if(i.signal.aborted){c.complete();return}if(a instanceof Error&&"code"in a){c.fail(a);return}c.fail(new l("HTTP_STREAM_TRANSPORT",a instanceof Error?a.message:String(a),{cause:a}))}),f};export{_ as httpStream};
|
package/dist/packem_shared/{lunora-client.d-D6g91j8X.d.mts → lunora-client.d-C5tvkz8x.d.mts}
RENAMED
|
@@ -252,6 +252,20 @@ interface OutboxSink {
|
|
|
252
252
|
* needed to render offline on reload and to resume the live subscription.
|
|
253
253
|
*/
|
|
254
254
|
interface CachedQuery {
|
|
255
|
+
/**
|
|
256
|
+
* Token-hash fingerprint of the bearer the value was cached under, when the
|
|
257
|
+
* entry was written by the identity the client currently advertises.
|
|
258
|
+
*
|
|
259
|
+
* The second half of the identity gate, and the half that makes the cache
|
|
260
|
+
* usable at all for a bearer-token app. `identity` settles on the resolved
|
|
261
|
+
* subject (`subj:<id>`) once the session resolves, but on the NEXT reload
|
|
262
|
+
* every adapter can only offer the stored token first — the subject arrives
|
|
263
|
+
* a round trip later, and offline it never arrives at all. Matching the
|
|
264
|
+
* credential the entry was written under is what lets the seed happen before
|
|
265
|
+
* (or without) that round trip. Absent when signed out, or when the value
|
|
266
|
+
* arrived over a socket authenticated as someone else.
|
|
267
|
+
*/
|
|
268
|
+
credential?: string;
|
|
255
269
|
/**
|
|
256
270
|
* Issuing identity fingerprint (same shape the offline queue stamps). A
|
|
257
271
|
* cached value only hydrates when it matches the current identity, so a
|
|
@@ -1645,6 +1659,20 @@ declare class LunoraClient {
|
|
|
1645
1659
|
* the cache only ever seeds the initial value — live frames take over after.
|
|
1646
1660
|
*/
|
|
1647
1661
|
private readonly hydratedQueryCache;
|
|
1662
|
+
/**
|
|
1663
|
+
* The read-cache entries currently ON DISPLAY in a live subscription, by the
|
|
1664
|
+
* same key — every entry consumed out of `hydratedQueryCache` and not yet
|
|
1665
|
+
* overwritten by a server frame.
|
|
1666
|
+
*
|
|
1667
|
+
* Gating the cache at read time only protects a value not handed over YET.
|
|
1668
|
+
* A credential can change while a cached value is already on screen (the
|
|
1669
|
+
* account-switch shape: an established subject, a token it was never checked
|
|
1670
|
+
* against), and the fingerprint does not move with it — so nothing else
|
|
1671
|
+
* would notice. `revokeCacheSeededValues` takes those values back off
|
|
1672
|
+
* screen and returns the entries to `hydratedQueryCache`, where the ordinary
|
|
1673
|
+
* identity gate decides whether they may ever be shown again.
|
|
1674
|
+
*/
|
|
1675
|
+
private readonly cacheSeededQueries;
|
|
1648
1676
|
/**
|
|
1649
1677
|
* Coalesced read-cache writes: the latest value per key, flushed to
|
|
1650
1678
|
* the `queryCache` on a short debounce so a burst of deltas persists once.
|
|
@@ -1748,6 +1776,8 @@ declare class LunoraClient {
|
|
|
1748
1776
|
private readonly statusListeners;
|
|
1749
1777
|
/** Subscribers notified when the server drops a socket for an expired token (see `onTokenExpired`). */
|
|
1750
1778
|
private readonly tokenExpiredListeners;
|
|
1779
|
+
/** Token hash the last durable-replay auth refusal fired `onTokenExpired` for — see `shouldRequeueReplayFailure`. */
|
|
1780
|
+
private authRefusalNotifiedFor;
|
|
1751
1781
|
/** Subscribers to offline-queued mutation verdicts (see `onMutationSettled`). */
|
|
1752
1782
|
private readonly mutationSettledListeners;
|
|
1753
1783
|
/** Subscribers to the offline-queue pending-count (see `onPendingChange`). */
|
|
@@ -3161,14 +3191,61 @@ declare class LunoraClient {
|
|
|
3161
3191
|
* always beats the cache. Identity-gated exactly like `takeHydratedCache`.
|
|
3162
3192
|
*/
|
|
3163
3193
|
private seedSubscriptionFromCache;
|
|
3194
|
+
/**
|
|
3195
|
+
* Move the durable read cache in or out of view as the CREDENTIAL changes —
|
|
3196
|
+
* which the identity fingerprint does not track: a sticky subject rides
|
|
3197
|
+
* across a token change (the account-switch shape), leaving the label
|
|
3198
|
+
* unmoved, so `setAuthToken`'s identity-change block never runs for it.
|
|
3199
|
+
* Revoke while that pairing is unchecked, and hand the values back once the
|
|
3200
|
+
* next session resolve confirms the credential really is that subject's.
|
|
3201
|
+
*/
|
|
3202
|
+
private syncReadCacheToCredential;
|
|
3203
|
+
/**
|
|
3204
|
+
* A server frame owns this key now, so the read cache may neither take its
|
|
3205
|
+
* seeded value back ({@link revokeCacheSeededValues}) nor hold an entry for
|
|
3206
|
+
* a later `subscribe()` of the same key to replay a stale session over.
|
|
3207
|
+
*/
|
|
3208
|
+
private dropCacheSeed;
|
|
3209
|
+
/**
|
|
3210
|
+
* Take every value the durable read cache is currently displaying back off
|
|
3211
|
+
* screen, and return its entry to {@link hydratedQueryCache} so the identity
|
|
3212
|
+
* gate — not this call — decides whether it is ever shown again. A
|
|
3213
|
+
* same-credential refresh gets its offline-first value back the moment the
|
|
3214
|
+
* next session resolve re-confirms the subject; a genuine account switch
|
|
3215
|
+
* never does, and {@link clearQueryCacheForIdentityChange} wipes it.
|
|
3216
|
+
*
|
|
3217
|
+
* Only cache-seeded values: a server frame has been delivered under a socket
|
|
3218
|
+
* whose own identity is pinned and checked ({@link persistQueryValue}), and
|
|
3219
|
+
* dropping those would blank a live query on every token refresh.
|
|
3220
|
+
*/
|
|
3221
|
+
private revokeCacheSeededValues;
|
|
3164
3222
|
/**
|
|
3165
3223
|
* Consume the hydrated read-cache entry for a key (if any), gated on
|
|
3166
|
-
* identity
|
|
3167
|
-
*
|
|
3168
|
-
*
|
|
3169
|
-
*
|
|
3224
|
+
* identity ({@link cachedQueryMatchesIdentity}). A mismatch yields
|
|
3225
|
+
* `undefined`, so a cache written under a different identity never leaks
|
|
3226
|
+
* into a new session.
|
|
3227
|
+
*
|
|
3228
|
+
* Only a MATCH is removed. The cache seeds a subscription's first value
|
|
3229
|
+
* once, so consuming a match is right — but destroying a mismatch is what
|
|
3230
|
+
* made a late-resolving identity unrecoverable: the subject typically lands
|
|
3231
|
+
* a `/get-session` after the first `subscribe()`, and by then the entry that
|
|
3232
|
+
* would have matched was gone. Left in place, {@link reseedFromHydratedCache}
|
|
3233
|
+
* can still hand it over when the identity settles.
|
|
3170
3234
|
*/
|
|
3171
3235
|
private takeHydratedCache;
|
|
3236
|
+
/**
|
|
3237
|
+
* Hand every still-held read-cache entry to the subscription that is open on
|
|
3238
|
+
* its key, now that the identity has settled onto a resolved subject.
|
|
3239
|
+
*
|
|
3240
|
+
* `subscribe()` runs long before `/get-session` answers, so on a reload the
|
|
3241
|
+
* gate is asked its question with only a raw token in hand. When the token
|
|
3242
|
+
* itself matches, {@link cachedQueryMatchesIdentity} already says yes there
|
|
3243
|
+
* and then; when it has been refreshed since the value was cached, the only
|
|
3244
|
+
* honest answer at that moment is "unknown" — and this is where it becomes
|
|
3245
|
+
* knowable. {@link seedSubscriptionFromCache} is a no-op for any subscription
|
|
3246
|
+
* the socket has already fed, so a live value always wins.
|
|
3247
|
+
*/
|
|
3248
|
+
private reseedFromHydratedCache;
|
|
3172
3249
|
/**
|
|
3173
3250
|
* Queue a coalesced read-cache write for a subscription's current value.
|
|
3174
3251
|
* Latest-wins per key; flushed on a short debounce so a delta burst writes
|
|
@@ -3468,6 +3545,42 @@ declare class LunoraClient {
|
|
|
3468
3545
|
* Still synchronous (no crypto) and stable across surrogate pairs.
|
|
3469
3546
|
*/
|
|
3470
3547
|
private hashToken;
|
|
3548
|
+
/**
|
|
3549
|
+
* The `credential` field a read-cache write carries: the token hash of the
|
|
3550
|
+
* bearer currently held, or nothing at all when signed out (there is no
|
|
3551
|
+
* credential to match against, and the `null` identity already covers it).
|
|
3552
|
+
*/
|
|
3553
|
+
private credentialStamp;
|
|
3554
|
+
/**
|
|
3555
|
+
* Whether a read-cache entry belongs to the identity in effect right now —
|
|
3556
|
+
* the ONE gate the hydrated peek, the subscribe-time take and the late seed
|
|
3557
|
+
* all share.
|
|
3558
|
+
*
|
|
3559
|
+
* Three ways to be the same identity, because the label and the credential
|
|
3560
|
+
* resolve at different times:
|
|
3561
|
+
*
|
|
3562
|
+
* 1. The fingerprints are equal — the plain case.
|
|
3563
|
+
* 2. The entry is stamped under a token hash and the live identity has since
|
|
3564
|
+
* been relabelled to the subject that credential resolved to
|
|
3565
|
+
* ({@link isSameCredentialUnderTokenHash}).
|
|
3566
|
+
* 3. The entry is stamped under a subject and THIS session has only the raw
|
|
3567
|
+
* token so far, but it is byte-for-byte the credential the entry was written
|
|
3568
|
+
* under. This is the direction the strict comparison missed entirely, and it
|
|
3569
|
+
* is the normal shape of every reload: every adapter calls
|
|
3570
|
+
* `setAuthToken(token)` from storage and only learns the subject a
|
|
3571
|
+
* `/get-session` round trip later — which offline never completes at all.
|
|
3572
|
+
* Without it the durable read cache never seeded for a bearer-token app.
|
|
3573
|
+
*
|
|
3574
|
+
* Case 1 is suspended while the subject awaits re-confirmation
|
|
3575
|
+
* ({@link subjectAwaitingReconfirm}): the fingerprint then labels a
|
|
3576
|
+
* credential nothing has checked it against, which is precisely the
|
|
3577
|
+
* account-switch shape — `setAuthToken(otherAccountsToken)` with no subject,
|
|
3578
|
+
* what every adapter does on a reload, still reading `subj:<previous user>`.
|
|
3579
|
+
* Matching on that label alone hands the new account the previous account's
|
|
3580
|
+
* cached rows. Cases 2 and 3 both PROVE the credential, so the reload this
|
|
3581
|
+
* gate exists for still seeds.
|
|
3582
|
+
*/
|
|
3583
|
+
private cachedQueryMatchesIdentity;
|
|
3471
3584
|
/**
|
|
3472
3585
|
* True when `stamped` is a token-hash of the SAME credential still held now,
|
|
3473
3586
|
* even though the live identity has since been relabelled to a subject. Covers
|
|
@@ -3683,6 +3796,28 @@ declare class LunoraClient {
|
|
|
3683
3796
|
* predates a write this client already saw.
|
|
3684
3797
|
*/
|
|
3685
3798
|
private recordShardCursor;
|
|
3799
|
+
/**
|
|
3800
|
+
* Whether a replay failure leaves the durable write queued rather than
|
|
3801
|
+
* settling it terminally — the ONE classification the single-call, per-slot
|
|
3802
|
+
* and whole-batch paths share, so a write's fate never depends on how many
|
|
3803
|
+
* siblings rode along.
|
|
3804
|
+
*
|
|
3805
|
+
* {@link isTransientReplayFailure} answers the "no verdict was reached" half.
|
|
3806
|
+
* The other half is a refused CREDENTIAL ({@link isAuthReplayFailure}): the
|
|
3807
|
+
* queue flushes on the shard's `open` handler with whatever bearer survived
|
|
3808
|
+
* the offline window, so an expired token is the expected outcome of a long
|
|
3809
|
+
* disconnect, not a verdict on the write. Notifying {@link onTokenExpired}
|
|
3810
|
+
* here is what closes the loop — the HTTP replay path has no equivalent of
|
|
3811
|
+
* the WS `4001` close frame, so without this nothing tells the app to
|
|
3812
|
+
* refresh, and `setAuthToken` (which re-flushes) is never called.
|
|
3813
|
+
*
|
|
3814
|
+
* Notified once per credential, not once per write: a flush of a hundred
|
|
3815
|
+
* queued writes earns a hundred identical refusals, and firing the hook for
|
|
3816
|
+
* each would put a hundred token refreshes on the app. The stamp re-arms as
|
|
3817
|
+
* soon as the credential moves, which is the only thing that can change the
|
|
3818
|
+
* answer.
|
|
3819
|
+
*/
|
|
3820
|
+
private shouldRequeueReplayFailure;
|
|
3686
3821
|
/** Settle a write the server reached a coded verdict on: replaying would re-trigger the same failure (a poison-message loop), so drop it. */
|
|
3687
3822
|
private settleReplayTerminal;
|
|
3688
3823
|
/**
|
|
@@ -3706,11 +3841,11 @@ declare class LunoraClient {
|
|
|
3706
3841
|
* per-entry `mutationId` idempotency and in-order application are inherited from
|
|
3707
3842
|
* the proven path. Per-slot demux mirrors {@link replaySequential}'s
|
|
3708
3843
|
* classification: success confirms the optimistic layer against the echoed
|
|
3709
|
-
* `commitCursor`; a coded application verdict is terminal; a
|
|
3710
|
-
*
|
|
3844
|
+
* `commitCursor`; a coded application verdict is terminal; a failure
|
|
3845
|
+
* {@link shouldRequeueReplayFailure} keeps, a missing slot, or a whole-batch
|
|
3711
3846
|
* transport failure re-queues for the next reconnect (never dropping a durable
|
|
3712
|
-
* write). A whole-batch coded rejection (bad request
|
|
3713
|
-
*
|
|
3847
|
+
* write). A whole-batch coded rejection (a bad request the server reached a
|
|
3848
|
+
* verdict on) is terminal for every entry.
|
|
3714
3849
|
*
|
|
3715
3850
|
* The body is also held under {@link MAX_BATCH_BODY_BYTES}: the worker caps a
|
|
3716
3851
|
* batch body at 1 MiB and answers `413`, which is ONE refusal covering every
|
|
@@ -3727,11 +3862,12 @@ declare class LunoraClient {
|
|
|
3727
3862
|
private replayBatched;
|
|
3728
3863
|
/**
|
|
3729
3864
|
* Classify a `/_lunora/rpc-batch` reply that carried no per-slot results — one
|
|
3730
|
-
* outcome covering every entry in the chunk. A
|
|
3731
|
-
*
|
|
3732
|
-
* {@link TransportError} (an
|
|
3733
|
-
*
|
|
3734
|
-
* the request itself, and
|
|
3865
|
+
* outcome covering every entry in the chunk. A code
|
|
3866
|
+
* {@link shouldRequeueReplayFailure} keeps (an unreachable shard, a
|
|
3867
|
+
* rate-limit refusal, a refused credential) or a {@link TransportError} (an
|
|
3868
|
+
* edge reply with no verdict in it) leaves every write durable for the next
|
|
3869
|
+
* attempt; anything else is a verdict reached on the request itself, and
|
|
3870
|
+
* settles all of them.
|
|
3735
3871
|
*/
|
|
3736
3872
|
private settleWholeBatchError;
|
|
3737
3873
|
/**
|
|
@@ -3746,9 +3882,9 @@ declare class LunoraClient {
|
|
|
3746
3882
|
* in input order. Each slot's envelope classifies its write the same way
|
|
3747
3883
|
* {@link replaySequential} does: a success confirms the optimistic layer
|
|
3748
3884
|
* against the echoed `commitCursor`; a coded application verdict is terminal;
|
|
3749
|
-
* a
|
|
3750
|
-
*
|
|
3751
|
-
* @returns the writes that must be re-queued (
|
|
3885
|
+
* a failure {@link shouldRequeueReplayFailure} keeps, or a slot the server
|
|
3886
|
+
* never returned, is returned for the caller to re-queue.
|
|
3887
|
+
* @returns the writes that must be re-queued (kept slots), in input order
|
|
3752
3888
|
*/
|
|
3753
3889
|
private settleReplayBatchSlots;
|
|
3754
3890
|
}
|
|
@@ -252,6 +252,20 @@ interface OutboxSink {
|
|
|
252
252
|
* needed to render offline on reload and to resume the live subscription.
|
|
253
253
|
*/
|
|
254
254
|
interface CachedQuery {
|
|
255
|
+
/**
|
|
256
|
+
* Token-hash fingerprint of the bearer the value was cached under, when the
|
|
257
|
+
* entry was written by the identity the client currently advertises.
|
|
258
|
+
*
|
|
259
|
+
* The second half of the identity gate, and the half that makes the cache
|
|
260
|
+
* usable at all for a bearer-token app. `identity` settles on the resolved
|
|
261
|
+
* subject (`subj:<id>`) once the session resolves, but on the NEXT reload
|
|
262
|
+
* every adapter can only offer the stored token first — the subject arrives
|
|
263
|
+
* a round trip later, and offline it never arrives at all. Matching the
|
|
264
|
+
* credential the entry was written under is what lets the seed happen before
|
|
265
|
+
* (or without) that round trip. Absent when signed out, or when the value
|
|
266
|
+
* arrived over a socket authenticated as someone else.
|
|
267
|
+
*/
|
|
268
|
+
credential?: string;
|
|
255
269
|
/**
|
|
256
270
|
* Issuing identity fingerprint (same shape the offline queue stamps). A
|
|
257
271
|
* cached value only hydrates when it matches the current identity, so a
|
|
@@ -1645,6 +1659,20 @@ declare class LunoraClient {
|
|
|
1645
1659
|
* the cache only ever seeds the initial value — live frames take over after.
|
|
1646
1660
|
*/
|
|
1647
1661
|
private readonly hydratedQueryCache;
|
|
1662
|
+
/**
|
|
1663
|
+
* The read-cache entries currently ON DISPLAY in a live subscription, by the
|
|
1664
|
+
* same key — every entry consumed out of `hydratedQueryCache` and not yet
|
|
1665
|
+
* overwritten by a server frame.
|
|
1666
|
+
*
|
|
1667
|
+
* Gating the cache at read time only protects a value not handed over YET.
|
|
1668
|
+
* A credential can change while a cached value is already on screen (the
|
|
1669
|
+
* account-switch shape: an established subject, a token it was never checked
|
|
1670
|
+
* against), and the fingerprint does not move with it — so nothing else
|
|
1671
|
+
* would notice. `revokeCacheSeededValues` takes those values back off
|
|
1672
|
+
* screen and returns the entries to `hydratedQueryCache`, where the ordinary
|
|
1673
|
+
* identity gate decides whether they may ever be shown again.
|
|
1674
|
+
*/
|
|
1675
|
+
private readonly cacheSeededQueries;
|
|
1648
1676
|
/**
|
|
1649
1677
|
* Coalesced read-cache writes: the latest value per key, flushed to
|
|
1650
1678
|
* the `queryCache` on a short debounce so a burst of deltas persists once.
|
|
@@ -1748,6 +1776,8 @@ declare class LunoraClient {
|
|
|
1748
1776
|
private readonly statusListeners;
|
|
1749
1777
|
/** Subscribers notified when the server drops a socket for an expired token (see `onTokenExpired`). */
|
|
1750
1778
|
private readonly tokenExpiredListeners;
|
|
1779
|
+
/** Token hash the last durable-replay auth refusal fired `onTokenExpired` for — see `shouldRequeueReplayFailure`. */
|
|
1780
|
+
private authRefusalNotifiedFor;
|
|
1751
1781
|
/** Subscribers to offline-queued mutation verdicts (see `onMutationSettled`). */
|
|
1752
1782
|
private readonly mutationSettledListeners;
|
|
1753
1783
|
/** Subscribers to the offline-queue pending-count (see `onPendingChange`). */
|
|
@@ -3161,14 +3191,61 @@ declare class LunoraClient {
|
|
|
3161
3191
|
* always beats the cache. Identity-gated exactly like `takeHydratedCache`.
|
|
3162
3192
|
*/
|
|
3163
3193
|
private seedSubscriptionFromCache;
|
|
3194
|
+
/**
|
|
3195
|
+
* Move the durable read cache in or out of view as the CREDENTIAL changes —
|
|
3196
|
+
* which the identity fingerprint does not track: a sticky subject rides
|
|
3197
|
+
* across a token change (the account-switch shape), leaving the label
|
|
3198
|
+
* unmoved, so `setAuthToken`'s identity-change block never runs for it.
|
|
3199
|
+
* Revoke while that pairing is unchecked, and hand the values back once the
|
|
3200
|
+
* next session resolve confirms the credential really is that subject's.
|
|
3201
|
+
*/
|
|
3202
|
+
private syncReadCacheToCredential;
|
|
3203
|
+
/**
|
|
3204
|
+
* A server frame owns this key now, so the read cache may neither take its
|
|
3205
|
+
* seeded value back ({@link revokeCacheSeededValues}) nor hold an entry for
|
|
3206
|
+
* a later `subscribe()` of the same key to replay a stale session over.
|
|
3207
|
+
*/
|
|
3208
|
+
private dropCacheSeed;
|
|
3209
|
+
/**
|
|
3210
|
+
* Take every value the durable read cache is currently displaying back off
|
|
3211
|
+
* screen, and return its entry to {@link hydratedQueryCache} so the identity
|
|
3212
|
+
* gate — not this call — decides whether it is ever shown again. A
|
|
3213
|
+
* same-credential refresh gets its offline-first value back the moment the
|
|
3214
|
+
* next session resolve re-confirms the subject; a genuine account switch
|
|
3215
|
+
* never does, and {@link clearQueryCacheForIdentityChange} wipes it.
|
|
3216
|
+
*
|
|
3217
|
+
* Only cache-seeded values: a server frame has been delivered under a socket
|
|
3218
|
+
* whose own identity is pinned and checked ({@link persistQueryValue}), and
|
|
3219
|
+
* dropping those would blank a live query on every token refresh.
|
|
3220
|
+
*/
|
|
3221
|
+
private revokeCacheSeededValues;
|
|
3164
3222
|
/**
|
|
3165
3223
|
* Consume the hydrated read-cache entry for a key (if any), gated on
|
|
3166
|
-
* identity
|
|
3167
|
-
*
|
|
3168
|
-
*
|
|
3169
|
-
*
|
|
3224
|
+
* identity ({@link cachedQueryMatchesIdentity}). A mismatch yields
|
|
3225
|
+
* `undefined`, so a cache written under a different identity never leaks
|
|
3226
|
+
* into a new session.
|
|
3227
|
+
*
|
|
3228
|
+
* Only a MATCH is removed. The cache seeds a subscription's first value
|
|
3229
|
+
* once, so consuming a match is right — but destroying a mismatch is what
|
|
3230
|
+
* made a late-resolving identity unrecoverable: the subject typically lands
|
|
3231
|
+
* a `/get-session` after the first `subscribe()`, and by then the entry that
|
|
3232
|
+
* would have matched was gone. Left in place, {@link reseedFromHydratedCache}
|
|
3233
|
+
* can still hand it over when the identity settles.
|
|
3170
3234
|
*/
|
|
3171
3235
|
private takeHydratedCache;
|
|
3236
|
+
/**
|
|
3237
|
+
* Hand every still-held read-cache entry to the subscription that is open on
|
|
3238
|
+
* its key, now that the identity has settled onto a resolved subject.
|
|
3239
|
+
*
|
|
3240
|
+
* `subscribe()` runs long before `/get-session` answers, so on a reload the
|
|
3241
|
+
* gate is asked its question with only a raw token in hand. When the token
|
|
3242
|
+
* itself matches, {@link cachedQueryMatchesIdentity} already says yes there
|
|
3243
|
+
* and then; when it has been refreshed since the value was cached, the only
|
|
3244
|
+
* honest answer at that moment is "unknown" — and this is where it becomes
|
|
3245
|
+
* knowable. {@link seedSubscriptionFromCache} is a no-op for any subscription
|
|
3246
|
+
* the socket has already fed, so a live value always wins.
|
|
3247
|
+
*/
|
|
3248
|
+
private reseedFromHydratedCache;
|
|
3172
3249
|
/**
|
|
3173
3250
|
* Queue a coalesced read-cache write for a subscription's current value.
|
|
3174
3251
|
* Latest-wins per key; flushed on a short debounce so a delta burst writes
|
|
@@ -3468,6 +3545,42 @@ declare class LunoraClient {
|
|
|
3468
3545
|
* Still synchronous (no crypto) and stable across surrogate pairs.
|
|
3469
3546
|
*/
|
|
3470
3547
|
private hashToken;
|
|
3548
|
+
/**
|
|
3549
|
+
* The `credential` field a read-cache write carries: the token hash of the
|
|
3550
|
+
* bearer currently held, or nothing at all when signed out (there is no
|
|
3551
|
+
* credential to match against, and the `null` identity already covers it).
|
|
3552
|
+
*/
|
|
3553
|
+
private credentialStamp;
|
|
3554
|
+
/**
|
|
3555
|
+
* Whether a read-cache entry belongs to the identity in effect right now —
|
|
3556
|
+
* the ONE gate the hydrated peek, the subscribe-time take and the late seed
|
|
3557
|
+
* all share.
|
|
3558
|
+
*
|
|
3559
|
+
* Three ways to be the same identity, because the label and the credential
|
|
3560
|
+
* resolve at different times:
|
|
3561
|
+
*
|
|
3562
|
+
* 1. The fingerprints are equal — the plain case.
|
|
3563
|
+
* 2. The entry is stamped under a token hash and the live identity has since
|
|
3564
|
+
* been relabelled to the subject that credential resolved to
|
|
3565
|
+
* ({@link isSameCredentialUnderTokenHash}).
|
|
3566
|
+
* 3. The entry is stamped under a subject and THIS session has only the raw
|
|
3567
|
+
* token so far, but it is byte-for-byte the credential the entry was written
|
|
3568
|
+
* under. This is the direction the strict comparison missed entirely, and it
|
|
3569
|
+
* is the normal shape of every reload: every adapter calls
|
|
3570
|
+
* `setAuthToken(token)` from storage and only learns the subject a
|
|
3571
|
+
* `/get-session` round trip later — which offline never completes at all.
|
|
3572
|
+
* Without it the durable read cache never seeded for a bearer-token app.
|
|
3573
|
+
*
|
|
3574
|
+
* Case 1 is suspended while the subject awaits re-confirmation
|
|
3575
|
+
* ({@link subjectAwaitingReconfirm}): the fingerprint then labels a
|
|
3576
|
+
* credential nothing has checked it against, which is precisely the
|
|
3577
|
+
* account-switch shape — `setAuthToken(otherAccountsToken)` with no subject,
|
|
3578
|
+
* what every adapter does on a reload, still reading `subj:<previous user>`.
|
|
3579
|
+
* Matching on that label alone hands the new account the previous account's
|
|
3580
|
+
* cached rows. Cases 2 and 3 both PROVE the credential, so the reload this
|
|
3581
|
+
* gate exists for still seeds.
|
|
3582
|
+
*/
|
|
3583
|
+
private cachedQueryMatchesIdentity;
|
|
3471
3584
|
/**
|
|
3472
3585
|
* True when `stamped` is a token-hash of the SAME credential still held now,
|
|
3473
3586
|
* even though the live identity has since been relabelled to a subject. Covers
|
|
@@ -3683,6 +3796,28 @@ declare class LunoraClient {
|
|
|
3683
3796
|
* predates a write this client already saw.
|
|
3684
3797
|
*/
|
|
3685
3798
|
private recordShardCursor;
|
|
3799
|
+
/**
|
|
3800
|
+
* Whether a replay failure leaves the durable write queued rather than
|
|
3801
|
+
* settling it terminally — the ONE classification the single-call, per-slot
|
|
3802
|
+
* and whole-batch paths share, so a write's fate never depends on how many
|
|
3803
|
+
* siblings rode along.
|
|
3804
|
+
*
|
|
3805
|
+
* {@link isTransientReplayFailure} answers the "no verdict was reached" half.
|
|
3806
|
+
* The other half is a refused CREDENTIAL ({@link isAuthReplayFailure}): the
|
|
3807
|
+
* queue flushes on the shard's `open` handler with whatever bearer survived
|
|
3808
|
+
* the offline window, so an expired token is the expected outcome of a long
|
|
3809
|
+
* disconnect, not a verdict on the write. Notifying {@link onTokenExpired}
|
|
3810
|
+
* here is what closes the loop — the HTTP replay path has no equivalent of
|
|
3811
|
+
* the WS `4001` close frame, so without this nothing tells the app to
|
|
3812
|
+
* refresh, and `setAuthToken` (which re-flushes) is never called.
|
|
3813
|
+
*
|
|
3814
|
+
* Notified once per credential, not once per write: a flush of a hundred
|
|
3815
|
+
* queued writes earns a hundred identical refusals, and firing the hook for
|
|
3816
|
+
* each would put a hundred token refreshes on the app. The stamp re-arms as
|
|
3817
|
+
* soon as the credential moves, which is the only thing that can change the
|
|
3818
|
+
* answer.
|
|
3819
|
+
*/
|
|
3820
|
+
private shouldRequeueReplayFailure;
|
|
3686
3821
|
/** Settle a write the server reached a coded verdict on: replaying would re-trigger the same failure (a poison-message loop), so drop it. */
|
|
3687
3822
|
private settleReplayTerminal;
|
|
3688
3823
|
/**
|
|
@@ -3706,11 +3841,11 @@ declare class LunoraClient {
|
|
|
3706
3841
|
* per-entry `mutationId` idempotency and in-order application are inherited from
|
|
3707
3842
|
* the proven path. Per-slot demux mirrors {@link replaySequential}'s
|
|
3708
3843
|
* classification: success confirms the optimistic layer against the echoed
|
|
3709
|
-
* `commitCursor`; a coded application verdict is terminal; a
|
|
3710
|
-
*
|
|
3844
|
+
* `commitCursor`; a coded application verdict is terminal; a failure
|
|
3845
|
+
* {@link shouldRequeueReplayFailure} keeps, a missing slot, or a whole-batch
|
|
3711
3846
|
* transport failure re-queues for the next reconnect (never dropping a durable
|
|
3712
|
-
* write). A whole-batch coded rejection (bad request
|
|
3713
|
-
*
|
|
3847
|
+
* write). A whole-batch coded rejection (a bad request the server reached a
|
|
3848
|
+
* verdict on) is terminal for every entry.
|
|
3714
3849
|
*
|
|
3715
3850
|
* The body is also held under {@link MAX_BATCH_BODY_BYTES}: the worker caps a
|
|
3716
3851
|
* batch body at 1 MiB and answers `413`, which is ONE refusal covering every
|
|
@@ -3727,11 +3862,12 @@ declare class LunoraClient {
|
|
|
3727
3862
|
private replayBatched;
|
|
3728
3863
|
/**
|
|
3729
3864
|
* Classify a `/_lunora/rpc-batch` reply that carried no per-slot results — one
|
|
3730
|
-
* outcome covering every entry in the chunk. A
|
|
3731
|
-
*
|
|
3732
|
-
* {@link TransportError} (an
|
|
3733
|
-
*
|
|
3734
|
-
* the request itself, and
|
|
3865
|
+
* outcome covering every entry in the chunk. A code
|
|
3866
|
+
* {@link shouldRequeueReplayFailure} keeps (an unreachable shard, a
|
|
3867
|
+
* rate-limit refusal, a refused credential) or a {@link TransportError} (an
|
|
3868
|
+
* edge reply with no verdict in it) leaves every write durable for the next
|
|
3869
|
+
* attempt; anything else is a verdict reached on the request itself, and
|
|
3870
|
+
* settles all of them.
|
|
3735
3871
|
*/
|
|
3736
3872
|
private settleWholeBatchError;
|
|
3737
3873
|
/**
|
|
@@ -3746,9 +3882,9 @@ declare class LunoraClient {
|
|
|
3746
3882
|
* in input order. Each slot's envelope classifies its write the same way
|
|
3747
3883
|
* {@link replaySequential} does: a success confirms the optimistic layer
|
|
3748
3884
|
* against the echoed `commitCursor`; a coded application verdict is terminal;
|
|
3749
|
-
* a
|
|
3750
|
-
*
|
|
3751
|
-
* @returns the writes that must be re-queued (
|
|
3885
|
+
* a failure {@link shouldRequeueReplayFailure} keeps, or a slot the server
|
|
3886
|
+
* never returned, is returned for the caller to re-queue.
|
|
3887
|
+
* @returns the writes that must be re-queued (kept slots), in input order
|
|
3752
3888
|
*/
|
|
3753
3889
|
private settleReplayBatchSlots;
|
|
3754
3890
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { L as LunoraClient, P as Preloaded } from "./lunora-client.d-
|
|
1
|
+
import { L as LunoraClient, P as Preloaded } from "./lunora-client.d-C5tvkz8x.mjs";
|
|
2
2
|
import { F as FunctionReference, A as ArgsOf, R as ReturnOf } from "./function-reference.d-Br_hsKje.mjs";
|
|
3
3
|
/**
|
|
4
4
|
* Run a query once on the server (during SSR) and capture its result in a
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { L as LunoraClient, P as Preloaded } from "./lunora-client.d-
|
|
1
|
+
import { L as LunoraClient, P as Preloaded } from "./lunora-client.d-CK3FxGNH.js";
|
|
2
2
|
import { F as FunctionReference, A as ArgsOf, R as ReturnOf } from "./function-reference.d-Br_hsKje.js";
|
|
3
3
|
/**
|
|
4
4
|
* Run a query once on the server (during SSR) and capture its result in a
|
package/dist/query/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S as SubscriptionError, L as LunoraClient, a as Unsubscribe } from "../packem_shared/lunora-client.d-
|
|
1
|
+
import { S as SubscriptionError, L as LunoraClient, a as Unsubscribe } from "../packem_shared/lunora-client.d-C5tvkz8x.mjs";
|
|
2
2
|
export type {
|
|
3
3
|
/**
|
|
4
4
|
* `@lunora/client/query` — the framework-neutral live-query state machine shared
|
|
@@ -10,7 +10,7 @@ export type {
|
|
|
10
10
|
* framework — each adapter supplies thin sinks that write into its own ref /
|
|
11
11
|
* store / signal / cache.
|
|
12
12
|
*/
|
|
13
|
-
b as SubscriptionErrorCallback } from "../packem_shared/lunora-client.d-
|
|
13
|
+
b as SubscriptionErrorCallback } from "../packem_shared/lunora-client.d-C5tvkz8x.mjs";
|
|
14
14
|
import { F as FunctionReference, A as ArgsOf, R as ReturnOf } from "../packem_shared/function-reference.d-Br_hsKje.mjs";
|
|
15
15
|
import '@lunora/errors';
|
|
16
16
|
import '@lunora/runtime';
|
package/dist/query/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S as SubscriptionError, L as LunoraClient, a as Unsubscribe } from "../packem_shared/lunora-client.d-
|
|
1
|
+
import { S as SubscriptionError, L as LunoraClient, a as Unsubscribe } from "../packem_shared/lunora-client.d-CK3FxGNH.js";
|
|
2
2
|
export type {
|
|
3
3
|
/**
|
|
4
4
|
* `@lunora/client/query` — the framework-neutral live-query state machine shared
|
|
@@ -10,7 +10,7 @@ export type {
|
|
|
10
10
|
* framework — each adapter supplies thin sinks that write into its own ref /
|
|
11
11
|
* store / signal / cache.
|
|
12
12
|
*/
|
|
13
|
-
b as SubscriptionErrorCallback } from "../packem_shared/lunora-client.d-
|
|
13
|
+
b as SubscriptionErrorCallback } from "../packem_shared/lunora-client.d-CK3FxGNH.js";
|
|
14
14
|
import { F as FunctionReference, A as ArgsOf, R as ReturnOf } from "../packem_shared/function-reference.d-Br_hsKje.js";
|
|
15
15
|
import '@lunora/errors';
|
|
16
16
|
import '@lunora/runtime';
|
package/dist/ssr/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { P as Preloaded, L as LunoraClient } from "../packem_shared/lunora-client.d-
|
|
1
|
+
import { P as Preloaded, L as LunoraClient } from "../packem_shared/lunora-client.d-C5tvkz8x.mjs";
|
|
2
2
|
export type { A as ArgsOf, F as FunctionReference, R as ReturnOf } from "../packem_shared/function-reference.d-Br_hsKje.mjs";
|
|
3
3
|
export {
|
|
4
4
|
/**
|
|
@@ -20,7 +20,7 @@ p as preloadQuery,
|
|
|
20
20
|
* WebSocket or touches a UI framework, so it is safe to import from any SSR
|
|
21
21
|
* loader.
|
|
22
22
|
*/
|
|
23
|
-
a as preloadedQueryResult } from "../packem_shared/preload.d-
|
|
23
|
+
a as preloadedQueryResult } from "../packem_shared/preload.d-CAXl1Y8Y.mjs";
|
|
24
24
|
import '@lunora/errors';
|
|
25
25
|
import '@lunora/runtime';
|
|
26
26
|
/**
|
package/dist/ssr/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { P as Preloaded, L as LunoraClient } from "../packem_shared/lunora-client.d-
|
|
1
|
+
import { P as Preloaded, L as LunoraClient } from "../packem_shared/lunora-client.d-CK3FxGNH.js";
|
|
2
2
|
export type { A as ArgsOf, F as FunctionReference, R as ReturnOf } from "../packem_shared/function-reference.d-Br_hsKje.js";
|
|
3
3
|
export {
|
|
4
4
|
/**
|
|
@@ -20,7 +20,7 @@ p as preloadQuery,
|
|
|
20
20
|
* WebSocket or touches a UI framework, so it is safe to import from any SSR
|
|
21
21
|
* loader.
|
|
22
22
|
*/
|
|
23
|
-
a as preloadedQueryResult } from "../packem_shared/preload.d-
|
|
23
|
+
a as preloadedQueryResult } from "../packem_shared/preload.d-Csjxr5HM.js";
|
|
24
24
|
import '@lunora/errors';
|
|
25
25
|
import '@lunora/runtime';
|
|
26
26
|
/**
|
package/dist/ssr/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getServerSession as o}from"../packem_shared/getServerSession-BaOoo1p6.mjs";import{deserializePreloaded as l,serializePreloaded as t}from"../packem_shared/deserializePreloaded-C6NTQdFa.mjs";import{createServerClient as i}from"../packem_shared/createServerClient-
|
|
1
|
+
import{getServerSession as o}from"../packem_shared/getServerSession-BaOoo1p6.mjs";import{deserializePreloaded as l,serializePreloaded as t}from"../packem_shared/deserializePreloaded-C6NTQdFa.mjs";import{createServerClient as i}from"../packem_shared/createServerClient-BrNyme3I.mjs";import{preloadQuery as s,preloadedQueryResult as f}from"../packem_shared/preloadQuery-uFy24PCR.mjs";export{i as createServerClient,l as deserializePreloaded,o as getServerSession,s as preloadQuery,f as preloadedQueryResult,t as serializePreloaded};
|
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.87",
|
|
4
4
|
"description": "Lunora browser SDK: WebSocket transport, optimistic updates, and an offline mutation queue",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"access": "public"
|
|
71
71
|
},
|
|
72
72
|
"dependencies": {
|
|
73
|
-
"@lunora/errors": "1.0.0-alpha.
|
|
73
|
+
"@lunora/errors": "1.0.0-alpha.35",
|
|
74
74
|
"@visulima/storage-client": "1.0.2"
|
|
75
75
|
},
|
|
76
76
|
"peerDependencies": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{LunoraError as m}from"@lunora/errors";import{i as ae,a as oe,P as ce}from"./delta-merge-vxvH3PvF.mjs";import{e as q,d as T}from"./wire-codec-Sw1rAu-Z.mjs";import{s as Q}from"./wire-key-HsUDTlQ7.mjs";import he from"./createInMemoryBookmarkStorage-BooZhW0n.mjs";import{ClientQueryStore as de}from"./createClientQuery-B8Nfj-7o.mjs";import{TabCoordinator as ue}from"./TabCoordinator-CXD7vulJ.mjs";import{TransportError as I,getRetryAfterMs as ee}from"./CONFLICT_ERROR_CODE-BOeeP_Wl.mjs";import{httpStream as le}from"./httpStream-x6q-x4yK.mjs";import{d as U,n as O,f as R,a as fe,c as me}from"./local-store-CVfQDdXy.mjs";import{O as pe,n as $,i as ye,r as Se}from"./offline-queue-xntsWiKt.mjs";import{resolvePersistenceAdapter as be}from"./createInMemoryPersistence-Cz2W6XVj.mjs";import{resolveQueryCacheAdapter as Te,queryCacheKey as P}from"./createInMemoryQueryCache-D2uNHLfM.mjs";import{createReconnect as G}from"./createReconnect-CjTmjJDH.mjs";import ve from"./createSnapshotPrecondition-GRVKxPsh.mjs";import{createStream as ge}from"./DEFAULT_MAX_BUFFER-D3QH2iaq.mjs";import{SubscriptionRegistry as k}from"./SubscriptionRegistry-CS-AFUI9.mjs";const N=500,ke=async a=>{const e=[];let t;for(;;){const s=await a(t);if(e.push(...Array.isArray(s.records)?s.records:[]),s.truncated!==!0||typeof s.cursor!="string"||s.cursor.length===0)return e;if(s.cursor===t)throw new Error("collectPages: the list did not advance its cursor — refusing to page forever");t=s.cursor}},j=(a,e)=>{if(a.size<e)return;const t=a.keys().next().value;t!==void 0&&a.delete(t)};class E{listeners=new Set;add(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}emit(...e){const[t]=e;for(const s of this.listeners)try{s(t)}catch{}}clear(){this.listeners.clear()}}const F=new Set(["RATE_LIMITED","SHARD_ERROR","SHARD_UNAVAILABLE","TOO_MANY_REQUESTS"]),Ce=a=>{if(a instanceof I)return!0;const e=a?.code;return e===void 0||F.has(e)},te=6e4,we=1e3,se=a=>{if(a===null)return;const e=Number(a);if(Number.isFinite(e))return e>0?e*1e3:void 0;const t=Date.parse(a);if(Number.isNaN(t))return;const s=t-Date.now();return s>0?s:void 0},Ee={401:"UNAUTHORIZED",403:"FORBIDDEN",404:"NOT_FOUND",413:"PAYLOAD_TOO_LARGE",429:"TOO_MANY_REQUESTS"},M=(a,e,t)=>{const s=se(t),r=s===void 0?void 0:{retryAfterMs:s},i=`LunoraClient: response carried no error envelope (status ${a.toString()}${e?` ${e}`:""})`;return a<400||a>=500||a===408?new I(i,r):new m(Ee[a]??"BAD_REQUEST",i,{data:r})},_e=(a,e)=>{const t=se(e);if(!(t===void 0||ee(a)!==void 0))return a.data===void 0?{retryAfterMs:t}:typeof a.data=="object"&&a.data!==null&&!Array.isArray(a.data)?{...a.data,retryAfterMs:t}:void 0},Ae=(a,e=Math.random)=>{const t=Math.min(we*2**Math.max(a-1,0),te);return Math.round(t*(.5+e()*.5))},Ie=a=>a instanceof I||F.has(a?.code??""),Oe=(a,e,t)=>{const s=ee(a);return s!==void 0&&s>0?Math.min(s,te):Ie(a)?Ae(e,t):void 0},Re=983040,Pe=a=>typeof TextEncoder>"u"?a.length:new TextEncoder().encode(a).length,Me="/_lunora/rpc",z="/_lunora/rpc-batch",He="/_lunora/ws",x=a=>a===void 0||a===""?"":`&bucket=${encodeURIComponent(a)}`,H=a=>{for(let e=a.length-1;e>=0;e-=1)a[e]?.()},V=Symbol("lunora.unmergeableDelta"),Fe=(a,e)=>{for(const t of e)t.op==="delete"?a.delete(t.key):t.value!==void 0&&a.set(t.key,t.value)},Le="lunora-ping",Ue=3e4,Ne=1e4,xe=250,De=5e3,Be=64,Ke=8,We="/_lunora/admin/shard-traffic",qe="/_lunora/admin/scheduled",Qe="/_lunora/admin/scheduled/status",$e="/_lunora/admin/scheduled/ws",Ge="/_lunora/admin/scheduled/cancel",J="/_lunora/admin/scheduled/dead",je="/_lunora/admin/scheduled/dead/retry",ze="/_lunora/admin/scheduled/dead/cancel",Ve="/_lunora/admin/workflows/instances",Je="/_lunora/admin/workflows/instance",Ye="/_lunora/admin/workflows/status",D="/_lunora/admin/storage",Xe="/_lunora/admin/storage/url",Ze="/_lunora/admin/storage/buckets",et="/_lunora/admin/functions",tt="/_lunora/admin/cron-jobs",st="/_lunora/admin/cron-jobs/run",rt="/_lunora/admin/openapi",it="/_lunora/admin/openrpc",nt="/_lunora/admin/global/tables",at="/_lunora/admin/global/table",ot="/_lunora/admin/global/facet",ct="/_lunora/admin/vector/indexes",ht="/_lunora/admin/vector/query",dt="/_lunora/admin/logs/archive",ut="/_lunora/admin/kv/namespaces",lt="/_lunora/admin/kv/keys",B="/_lunora/admin/kv/value",ft="/_lunora/admin/auth/users",mt="/_lunora/admin/auth/sessions",pt="/_lunora/admin/auth/users/create",yt="/_lunora/admin/auth/users/role",St="/_lunora/admin/auth/users/ban",bt="/_lunora/admin/auth/users/unban",Tt="/_lunora/admin/auth/users/password",vt="/_lunora/admin/auth/users/remove",gt="/_lunora/admin/auth/users/impersonate",kt="/_lunora/admin/auth/sessions/revoke",Ct="/_lunora/admin/auth/sessions/revoke-all",wt="/_lunora/admin/auth/capabilities",Et="/_lunora/admin/auth/users/update",_t="/_lunora/admin/auth/accounts",At="/_lunora/admin/auth/accounts/unlink",It="/_lunora/admin/auth/passkeys",Ot="/_lunora/admin/auth/passkeys/delete",Rt="/_lunora/admin/auth/two-factor/disable",Pt="/_lunora/admin/auth/organizations",Mt="/_lunora/admin/auth/organizations/members",Ht="/_lunora/admin/auth/organizations/invitations",Ft="/_lunora/admin/auth/organizations/members/remove",Lt="/_lunora/admin/auth/organizations/invitations/cancel",Ut="/_lunora/admin/auth/config",Nt="/_lunora/admin/auth/sign-up-invitations",xt="/_lunora/admin/auth/sign-up-invitations/create",Dt="/_lunora/admin/auth/sign-up-invitations/revoke",Bt="/_lunora/admin/auth/organizations/create",Kt="/_lunora/admin/auth/organizations/update",Wt="/_lunora/admin/auth/organizations/remove",qt="/_lunora/admin/auth/organizations/members/add",Qt="/_lunora/admin/auth/organizations/members/invite",$t="/_lunora/admin/auth/organizations/members/role",Gt="/_lunora/admin/auth/organizations/teams",jt="/_lunora/admin/auth/organizations/teams/create",zt="/_lunora/admin/auth/organizations/teams/update",Vt="/_lunora/admin/auth/organizations/teams/remove",Jt="/_lunora/admin/auth/organizations/teams/members",Yt="/_lunora/admin/auth/organizations/teams/members/add",Xt="/_lunora/admin/auth/organizations/teams/members/remove",Zt="/_lunora/admin/auth/organizations/roles",es="/_lunora/admin/auth/organizations/roles/create",ts="/_lunora/admin/auth/organizations/roles/update",ss="/_lunora/admin/auth/organizations/roles/remove",rs="/api/auth",is="/get-session",Y=a=>a.startsWith("https://")?`wss://${a.slice(8)}`:a.startsWith("http://")?`ws://${a.slice(7)}`:a,C=(a,e)=>`${a.endsWith("/")?a.slice(0,-1):a}${e}`,p=(a,e)=>{const t=new URLSearchParams;for(const[r,i]of Object.entries(e))i!==void 0&&i!==""&&t.set(r,String(i));const s=t.toString();return s===""?a:`${a}?${s}`},ns=[ce],l=a=>a??"",re=(a,e)=>{const t=a.error,s=typeof t?.code=="string"?t.code:void 0,r=typeof t?.message=="string"?t.message:void 0;return{code:s,messageText:(typeof a.message=="string"?a.message:void 0)??r??e}},as=a=>{const{code:e,messageText:t}=re(a,"stream error");return e===void 0?new Error(t):new m(e,t)},X=a=>{const{code:e,messageText:t}=re(a,"subscription error");return{message:t,...e===void 0?{}:{code:e}}};function K(a){if(a!==void 0)return e=>{a(e)}}const _=(a,e)=>{for(const t of a)try{t(e)}catch{}},os=new TextDecoder,cs=a=>{if(typeof a=="string")return a;if(a instanceof ArrayBuffer)return os.decode(a)},b=(a,e)=>{if(!a.socket||a.wsState!=="open")return!1;try{return a.socket.send(JSON.stringify(e)),!0}catch{return!1}},A=a=>{const e=new Error(a.message??"request failed");return e.code=a.code,a.data!==void 0&&(e.data=T(a.data)),a.hint!==void 0&&(e.hint=a.hint),a.docsUrl!==void 0&&(e.docsUrl=a.docsUrl),e},Z=(a,e)=>{const t=A(a),s=_e(t,e);return s!==void 0&&(t.data=s),t},g=(a,e)=>{try{return q(a)}catch(t){const s=t instanceof Error?t.message:String(t);throw new TypeError(`LunoraClient: cannot encode ${e} — ${s}`,t instanceof Error?{cause:t}:void 0)}},W=a=>"args"in a?{...a,args:T(a.args)}:a,hs=(a,e)=>{const t=Array.from({length:e});for(const s of a){if(typeof s.id!="number"||s.id<0||s.id>=e)continue;const r=s.body;t[s.id]=r&&"error"in r&&r.error?{error:A(r.error),ok:!1}:{ok:!0,value:T(r?.result)}}return t.map(s=>s??{error:new Error("batch call returned no result"),ok:!1})},ds=Promise.resolve();class ie{static MAX_POKE_BUFFERS=256;static createClientQuery(e,t){return{defaultValue:t,key:e}}url;wsUrl;clientQueryStore;wsToken;authBasePath;fetchImpl;WebSocketImpl;bookmark;reconnectOptions;connectTimeoutMs;heartbeatIntervalMs;offlineQueue;outbox;clientId;shardCursors=new Map;defaultShardKey;readyResolved=!1;readyResolve;readyPromise;clientWatermarks=new Map;outboxMutationCounter=0;onPersistenceError;persistence;persistenceVersion;outboxLeaderRelease;queryCache;hydratedQueryCache=new Map;pendingCacheWrites=new Map;cacheFlushTimer;subscriptions=new k;tabCoordinator;leaderStatus;leaderWasEverConnected=!1;connections=new Map;defaultConnectionContext;connectionContexts=new Map;connectionContextHolders=new Map;authToken=null;authSubject=void 0;subjectToken=null;queuedIdentities=new Map;queuedOfflineShardKeys=new Set;closed=!1;authTokenListeners=new E;statusListeners=new E;tokenExpiredListeners=new E;mutationSettledListeners=new E;pendingChangeListeners=new E;whisperHandlers=new Map;lastStatus="idle";nextSubId=0;nextStreamId=0;streams=new Map;adminSocketTeardowns=new Set;offlineFlushes=new Map;replayRetryState=new Map;replayRetryTimers=new Map;shapeSubscriptions=new Map;pokeBuffers=new Map;nextShapeId=0;constructor(e){this.url=e.url,this.wsUrl=e.wsUrl??C(Y(e.url),He),this.wsToken=e.wsToken;const t=e.authBasePath??rs;this.authBasePath=t.endsWith("/")?t.slice(0,-1):t,this.fetchImpl=e.fetch??(typeof fetch=="function"?fetch.bind(globalThis):void 0),this.WebSocketImpl=e.WebSocket??(typeof WebSocket=="function"?WebSocket:void 0),this.bookmark=e.bookmarkStorage??he(),this.reconnectOptions=e.reconnect,this.heartbeatIntervalMs=e.heartbeatIntervalMs??Ue,this.connectTimeoutMs=e.connectTimeoutMs??Ne,this.defaultConnectionContext=e.connectionContext,this.persistence=be(e.persistence,e.outbox===void 0),this.persistenceVersion=e.persistenceVersion,this.queryCache=Te(e.queryCache),this.onPersistenceError=e.offlineQueue?.onPersistenceError,this.clientQueryStore=new de,e.crossTabSync?(this.tabCoordinator=this.createTabCoordinator(),this.tabCoordinator.start()):this.tabCoordinator=void 0,e.hydrateOnStart&&this.queryCache?this.readyPromise=new Promise(s=>{this.readyResolve=s}):(this.readyResolved=!0,this.readyPromise=ds),this.offlineQueue=new pe(e.offlineQueue,{onEvict:(s,r)=>{this.emitItemSettled(s,"rejected",r)},onSizeChange:s=>{this.pendingChangeListeners.emit(s)},persistence:this.persistence,version:e.persistenceVersion}),this.outbox=e.outbox,this.clientId=e.clientId??`client-${$()}`,this.persistence&&queueMicrotask(()=>{this.hydrateAsOutboxLeader()}),this.queryCache&&queueMicrotask(()=>{(async()=>{try{await this.hydrateQueryCache()}catch{}finally{this.readyResolved=!0,this.readyResolve?.()}})().catch(()=>{})})}setAuthToken(e,t){const s=this.authToken!==e,r=this.identityFingerprint(),i=this.authSubject===void 0||this.subjectToken===this.authToken;this.authToken=e,t!==void 0?(this.authSubject=t,this.subjectToken=e):e===null&&(this.authSubject=void 0,this.subjectToken=null);const n=this.identityFingerprint();if(n!==r&&(!s&&i?(this.restampQueuedIdentity(r,n),this.restampWatermarks(r,n),this.restampConnectionIdentity(r,n)):this.rejectQueuedForIdentityChange(r),this.tabCoordinator)){const o=this.tabCoordinator.isLeader();this.tabCoordinator.stop(),this.tabCoordinator=this.createTabCoordinator(),this.tabCoordinator.start(),o&&this.tabCoordinator.promoteImmediately()}s&&this.authTokenListeners.emit(e),this.offlineQueue.size>0&&this.computeStatus()==="connected"&&this.flushAllOfflineQueues()}getAuthToken(){return this.authToken}currentIdentity(){return this.identityFingerprint()}replayIdentityVerdict(e){if(this.subjectAwaitingReconfirm())return"unknown";const t=this.identityFingerprint();return e===t||e!==void 0&&this.isSameCredentialUnderTokenHash(e)?"match":t===null?"unknown":"mismatch"}clientIdentifier(){return this.clientId}confirmedMutationWatermark(e){return this.clientWatermarks.get(this.identityFingerprint()??"")?.get(e??"")??0}async callMutator(e,t,s){const r=s?.clientSeq;if(r!==void 0&&(!Number.isInteger(r)||r<=0))throw new m("INTERNAL",`callMutator: clientSeq must be a positive integer, got ${String(r)}`);const i=s?.shardKey??"",n=this.identityFingerprint();let o;const c=await this.rpc(e,t,s?.shardKey,{captureBookmark:!0,clientId:this.clientId,clientSeq:r,onMutationAck:d=>{o=d}});if(o!==void 0&&o>(this.clientWatermarks.get(n??"")?.get(i)??0)){let d=this.clientWatermarks.get(n??"");d===void 0&&(j(this.clientWatermarks,Ke),d=new Map,this.clientWatermarks.set(n??"",d)),d.set(i,o)}return{applied:o===void 0||o===r,result:c}}onAuthTokenChange(e){return this.authTokenListeners.add(e)}async getCurrentUser(){if(this.closed||!this.fetchImpl)return null;const e={},t=this.authToken;this.authToken&&(e.authorization=`Bearer ${this.authToken}`);try{const s=await this.fetchImpl(C(this.url,`${this.authBasePath}${is}`),{credentials:"include",headers:e,method:"GET"});if(!s.ok)return null;const i=(await s.json())?.user??null;return this.adoptResolvedSubject(t,i),i}catch{return null}}setWsToken(e){if(this.wsToken!==e){this.wsToken=e;for(const t of this.connections.values())if(t.socket)try{t.socket.close()}catch{}}}setConnectionContext(e,t={}){this.assertLeaderOwnedSurface("setConnectionContext");const s=l(t.shardKey);e===void 0?this.connectionContexts.delete(s):this.connectionContexts.set(s,e),this.refreshConnectionContext(s)}acquireConnectionContext(e,t={}){if(this.followsAnotherTab())return()=>{};const s=l(t.shardKey),r={context:e},i=this.connectionContextHolders.get(s);i?i.push(r):this.connectionContextHolders.set(s,[r]),this.refreshConnectionContext(s);let n=!1;return()=>{if(n)return;n=!0;const o=this.connectionContextHolders.get(s);if(!o)return;const c=o.indexOf(r);c!==-1&&o.splice(c,1),o.length===0&&this.connectionContextHolders.delete(s),this.refreshConnectionContext(s)}}whisperSubscribe(e,t,s={}){this.assertLeaderOwnedSurface("whisperSubscribe");const r=l(s.shardKey);let i=this.whisperHandlers.get(r);i||(i=new Map,this.whisperHandlers.set(r,i));let n=i.get(e);const o=n===void 0;if(n||(n=new Set,i.set(e,n)),n.add(t),this.ensureSocket(s.shardKey),o){const c=this.getConnection(s.shardKey);c&&b(c,{topic:e,type:"whisper_subscribe"})}return()=>{const c=this.whisperHandlers.get(r),h=c?.get(e);if(!h?.delete(t)||h.size>0)return;c?.delete(e),c?.size===0&&this.whisperHandlers.delete(r);const d=this.getConnection(s.shardKey);d&&b(d,{topic:e,type:"whisper_unsubscribe"})}}whisper(e,t,s={}){this.assertLeaderOwnedSurface("whisper"),this.ensureSocket(s.shardKey);const r=this.getConnection(s.shardKey);r&&b(r,{data:g(t??null,`whisper data for topic '${e}'`),topic:e,type:"whisper"})}onTokenExpired(e){return this.tokenExpiredListeners.add(e)}connectionStatus(){return this.computeStatus()}onConnectionStatus(e){const t=this.statusListeners.add(e);return e(this.computeStatus()),t}pendingCount(){return this.offlineQueue.size}debug(){const e=[],t=this.clientWatermarks.get(this.identityFingerprint()??""),s=new Set([...this.connections.keys(),...t?.keys()??[]]);for(const i of s){const n=this.connections.get(i);e.push({confirmedMutationWatermark:t?.get(i)??0,hasSocket:n?.socket!==void 0,shardKey:i===""?void 0:i,wasEverConnected:n?.wasEverConnected??!1,wsState:n?.wsState??"idle"})}const r=this.subscriptions.all().map(i=>({acked:i.acked,functionPath:i.fn.__lunoraRef,id:i.id,kind:"query",lastMutationId:i.lastMutationId,pendingOptimisticLayers:i.optimisticLayers.length,serverCursor:i.serverCursor,shardKey:i.shardKey,subscriberCount:i.callbacks.size}));for(const i of this.shapeSubscriptions.values())r.push({acked:i.serverCursor!==void 0,functionPath:`shape:${i.name}`,id:i.id,kind:"shape",lastMutationId:i.lastMutationId,pendingOptimisticLayers:0,rowCount:i.rows.size,serverCursor:i.serverCursor,shardKey:i.shardKey,subscriberCount:i.callbacks.size});return{clientId:this.clientId,closed:this.closed,connectionStatus:this.computeStatus(),pendingWrites:this.offlineQueue.size,shards:e.toSorted((i,n)=>(i.shardKey??"").localeCompare(n.shardKey??"")),subscriptions:r.toSorted((i,n)=>i.functionPath.localeCompare(n.functionPath))}}onPendingChange(e){const t=this.pendingChangeListeners.add(e);return e(this.offlineQueue.size),t}onMutationSettled(e){return this.mutationSettledListeners.add(e)}getWebSocketImpl(){return this.WebSocketImpl}getClientQuery(e){return this.clientQueryStore.get(e)}setClientQuery(e,t){this.clientQueryStore.set(e,t)}subscribeClientQuery(e,t){return this.clientQueryStore.subscribe(e,t)}resetClientQuery(e){this.clientQueryStore.reset(e)}snapshotPrecondition(e,t,s){return ve(this,e,t,s)}whenReady(){return this.readyPromise}get isReady(){return this.readyResolved}peekHydratedQuery(e,t,s){if(!this.readyResolved)return;const r=Q(t),i=P(e,r,s),n=this.hydratedQueryCache.get(i);if(n!==void 0)return n.identity===this.identityFingerprint()?n.value:void 0}peekActiveQuerySnapshot(e,t,s){const r=k.key(e,t,s),i=this.subscriptions.get(r);return{present:i!==void 0,value:i?.lastValue}}async query(e,t,s={}){return this.assertOpen(),await this.rpc(e.__lunoraRef,t,s.shardKey,{attachBookmark:!0})}async batch(e){if(this.assertOpen(),!this.fetchImpl)throw new m("INTERNAL","LunoraClient: no `fetch` implementation available");if(e.length===0)return[];const t=await this.fetchImpl(C(this.url,z),{body:JSON.stringify({calls:e.map((i,n)=>({args:g(i.args??{},`args for batch call '${i.fn.__lunoraRef}'`),functionPath:i.fn.__lunoraRef,id:n,shardKey:i.shardKey}))}),headers:this.rpcRequestHeaders({attachBookmark:!0}),method:"POST"}),s=t.headers.get("x-d1-bookmark");s&&this.bookmark.set(s);let r;try{r=await t.json()}catch{throw new m("INTERNAL",`LunoraClient: batch response was not JSON (status ${t.status.toString()})`)}if(!t.ok||r.error&&!r.results)throw r.error?A(r.error):new m("INTERNAL",`LunoraClient: batch request failed (status ${t.status.toString()})`);for(const i of r.results??[]){const n=i.body?.commitCursor;typeof i.id=="number"&&typeof n=="number"&&this.recordShardCursor(e[i.id]?.shardKey,n)}return hs(r.results??[],e.length)}async mutation(e,t,s={}){this.assertOpen();const r=t,i=s.mutationId??$(),{confirms:n,rollbacks:o}=this.applyOptimisticUpdates(e.__lunoraRef,r,s.shardKey,s.optimistic);s.optimisticUpdate&&this.applyOptimisticUpdate(s.optimisticUpdate,t,s.shardKey,o,n);const c=this.offlineFlushes.get(l(s.shardKey));c!==void 0&&await c;const{hasSocket:h,wasEverConnected:d,wsState:u}=this.connectionGateState(s.shardKey),{queueBeforeFirstConnect:f}=this.offlineQueue,S=d||f,y=this.WebSocketImpl!==void 0&&S;if(u!=="open"&&!h&&y||u==="connecting"&&S)return this.enqueueOfflineMutation(e,r,s.shardKey,i,o,n,s.precondition);try{let w;const ne=await this.rpc(e.__lunoraRef,r,s.shardKey,{captureBookmark:!0,mutationId:i,onCommitCursor:L=>{w=L}});for(const L of n)L(w);return ne}catch(w){throw H(o),w}}async action(e,t,s={}){return this.assertOpen(),await this.rpc(e.__lunoraRef,t,s.shardKey,{attachBookmark:!0,captureBookmark:!0})}async importRows(e,t,s={}){this.assertOpen();const r=Math.max(1,Math.trunc(s.chunkSize??500)),i=s.toArgs??(h=>({rows:h})),n=t.length;let o=0,c=0;for(let h=0;h<n;h+=r){const d=t.slice(h,h+r),u=c;await this.mutation(e,i(d),{...s.importId===void 0?{}:{mutationId:`${s.importId}:${String(u)}`},shardKey:s.shardKey}),c+=1,o+=d.length,s.onProgress?.({done:o,total:n})}return{chunks:c,imported:o}}async shardTraffic(e){this.assertOpen();const t=await this.adminFetch(We,"POST",{table:e});return{failed:t.failed??0,ok:t.ok??0,shards:t.shards??[]}}async listScheduledJobs(){return this.assertOpen(),((await this.adminFetch(qe,"GET")).records??[]).map(t=>W(t))}async schedulerStatus(){this.assertOpen();const e=await this.adminFetch(Qe,"GET");return{backlog:e.backlog??0,inFlight:e.inFlight??0,pools:e.pools??[]}}async cancelScheduledJob(e){return this.assertOpen(),{cancelled:(await this.adminFetch(Ge,"POST",{id:e})).cancelled===!0}}async listDeadJobs(){return this.assertOpen(),(await ke(async t=>await this.adminFetch(t===void 0?J:`${J}?cursor=${encodeURIComponent(t)}`,"GET"))).map(t=>W(t))}async retryDeadJob(e){return this.assertOpen(),{retried:(await this.adminFetch(je,"POST",{id:e})).retried===!0}}async removeDeadJob(e){return this.assertOpen(),{removed:(await this.adminFetch(ze,"POST",{id:e})).removed===!0}}async listWorkflowInstances(e){this.assertOpen();const t=new URLSearchParams({name:e.name});e.status!==void 0&&t.set("status",e.status),e.page!==void 0&&t.set("page",String(e.page)),e.perPage!==void 0&&t.set("perPage",String(e.perPage));const s=await this.adminFetch(`${Ve}?${t.toString()}`,"GET");return{configured:s.configured,instances:s.instances??[],page:s.page??1,perPage:s.perPage??e.perPage??0,totalCount:s.totalCount}}async getWorkflowInstance(e){this.assertOpen();const t=new URLSearchParams({id:e.id,name:e.name}),s=await this.adminFetch(`${Je}?${t.toString()}`,"GET");return{createdOn:s.createdOn,endedOn:s.endedOn,error:s.error,id:s.id??e.id,output:s.output,params:s.params,startedOn:s.startedOn,status:s.status??"unknown",steps:s.steps??[]}}async setWorkflowInstanceStatus(e){return this.assertOpen(),{status:(await this.adminFetch(Ye,"POST",{action:e.action,id:e.id,name:e.name})).status??"unknown"}}subscribeScheduledJobs(e){if(this.assertOpen(),this.WebSocketImpl===void 0)return()=>{};const t=C(Y(this.url),$e),s=G(this.reconnectOptions),r={connectTimer:void 0,heartbeatTimer:void 0,lastFrameAt:0,socket:void 0};let i,n=!1;const o=()=>{n||this.closed||(i=setTimeout(d,s.next()))},c=f=>{if(n||this.WebSocketImpl===void 0)return;const S=f===void 0?t:`${t}?token=${encodeURIComponent(f)}`;this.openManagedSocket(r,S,this.connectTimeoutMs,{onClose:()=>{o()},onMessage:y=>{let v;try{v=JSON.parse(typeof y.data=="string"?y.data:"")}catch{return}v.type==="jobs"&&Array.isArray(v.records)&&(s.reset(),e(v.records.map(w=>W(w))))}})},h=async f=>{let S;try{S=await f()}catch{o();return}c(S)},d=()=>{if(n||this.WebSocketImpl===void 0)return;const{wsToken:f}=this;if(typeof f=="function"){h(f).catch(()=>{});return}c(f)};d();const u=()=>{n=!0,i!==void 0&&(clearTimeout(i),i=void 0),r.connectTimer!==void 0&&(clearTimeout(r.connectTimer),r.connectTimer=void 0),this.stopHeartbeat(r),r.socket?.close(),r.socket=void 0};return this.adminSocketTeardowns.add(u),()=>{this.adminSocketTeardowns.delete(u),u()}}async listFunctions(){return this.assertOpen(),(await this.adminFetch(et,"GET")).functions??[]}async getCronJobs(){return this.assertOpen(),(await this.adminFetch(tt,"GET")).jobs??[]}async runCronJob(e){this.assertOpen();const t=await this.adminFetch(st,"POST",{name:e});return{name:t.name??e,ran:t.ran===!0}}async fetchOpenApi(){return this.assertOpen(),await this.adminFetch(rt,"GET")}async fetchOpenRpc(){return this.assertOpen(),await this.adminFetch(it,"GET")}async listStorageObjects(e={}){this.assertOpen();const t=p(D,{bucket:e.bucket,cursor:e.cursor,limit:e.limit,prefix:e.prefix}),s=await this.adminFetch(t,"GET");return{cursor:s.cursor,objects:s.objects??[]}}async deleteStorageObject(e,t){this.assertOpen();const s=`${D}?key=${encodeURIComponent(e)}${x(t?.bucket)}`,r=await this.adminFetch(s,"DELETE");return{deleted:r.deleted===!0,key:r.key??e}}async listStorageBuckets(){return this.assertOpen(),(await this.adminFetch(Ze,"GET")).buckets??[]}async uploadStorageObject(e){this.assertOpen();const t=`${D}?key=${encodeURIComponent(e.key)}${x(e.bucket)}`,s=await this.adminFetch(t,"PUT",e.body,e.contentType);return{etag:s.etag,key:s.key??e.key}}async signedStorageUrl(e,t){this.assertOpen();const s=t?.expiresInSeconds,r=s===void 0?"":`&expiresIn=${encodeURIComponent(s.toString())}`,i=`${Xe}?key=${encodeURIComponent(e)}${r}${x(t?.bucket)}`,n=await this.adminFetch(i,"GET");if(typeof n.url!="string")throw new TypeError("LunoraClient: storage URL endpoint returned no `url`");return n.url}async listGlobalTables(){return this.assertOpen(),await this.adminFetch(nt,"GET")}async readGlobalTablePage(e){this.assertOpen();const t=new URLSearchParams({table:e.table});return e.limit!==void 0&&t.set("limit",String(e.limit)),e.offset!==void 0&&t.set("offset",String(e.offset)),e.filters!==void 0&&e.filters.length>0&&t.set("filters",JSON.stringify(q(e.filters))),T(await this.adminFetch(`${at}?${t.toString()}`,"GET"))}async facetGlobalColumn(e){this.assertOpen();const t=new URLSearchParams({column:e.column,table:e.table});return e.limit!==void 0&&t.set("limit",String(e.limit)),e.filters!==void 0&&e.filters.length>0&&t.set("filters",JSON.stringify(q(e.filters))),T(await this.adminFetch(`${ot}?${t.toString()}`,"GET"))}async listVectorIndexes(){return this.assertOpen(),(await this.adminFetch(ct,"GET")).indexes??[]}async queryVectorIndex(e){return this.assertOpen(),(await this.adminFetch(ht,"POST",e)).matches??[]}async queryLogArchive(e={}){this.assertOpen();const t=await this.adminFetch(dt,"POST",e);return{nextCursor:t.nextCursor,rows:t.rows??[]}}async listKvNamespaces(){return this.assertOpen(),(await this.adminFetch(ut,"GET")).namespaces??[]}async listKvKeys(e){this.assertOpen();const t=p(lt,{cursor:e.cursor,limit:e.limit,namespace:e.namespace,prefix:e.prefix});return await this.adminFetch(t,"GET")}async getKvValue(e){this.assertOpen();const t=p(B,{key:e.key,namespace:e.namespace});return await this.adminFetch(t,"GET")}async putKvValue(e){this.assertOpen(),await this.adminFetch(B,"PUT",e)}async deleteKvKey(e){this.assertOpen();const t=p(B,{key:e.key,namespace:e.namespace});await this.adminFetch(t,"DELETE")}async listAuthUsers(e={}){this.assertOpen();const t=p(ft,{filterField:e.filterField,filterValue:e.filterValue,limit:e.limit,offset:e.offset,search:e.search,searchField:e.searchField,sortBy:e.sortBy,sortDirection:e.sortDirection});return await this.adminFetch(t,"GET")}async createAuthUser(e){return await this.adminFetch(pt,"POST",e)}async setAuthUserRole(e){return await this.adminFetch(yt,"POST",e)}async banAuthUser(e){return await this.adminFetch(St,"POST",e)}async unbanAuthUser(e){return await this.adminFetch(bt,"POST",e)}async setAuthUserPassword(e){await this.adminFetch(Tt,"POST",e)}async removeAuthUser(e){await this.adminFetch(vt,"POST",e)}async impersonateAuthUser(e){return await this.adminFetch(gt,"POST",e)}async revokeAuthSession(e){await this.adminFetch(kt,"POST",e)}async revokeAuthUserSessions(e){await this.adminFetch(Ct,"POST",e)}async getAuthCapabilities(){return await this.adminFetch(wt,"GET")}async updateAuthUser(e){return await this.adminFetch(Et,"POST",e)}async listAuthAccounts(e){return await this.adminFetch(p(_t,{userId:e.userId}),"GET")}async unlinkAuthAccount(e){await this.adminFetch(At,"POST",e)}async listAuthPasskeys(e){return await this.adminFetch(p(It,{userId:e.userId}),"GET")}async deleteAuthPasskey(e){await this.adminFetch(Ot,"POST",e)}async disableAuthTwoFactor(e){await this.adminFetch(Rt,"POST",e)}async listAuthOrganizations(e={}){return await this.adminFetch(p(Pt,{limit:e.limit,offset:e.offset}),"GET")}async listAuthOrgMembers(e){const t=p(Mt,{limit:e.limit,offset:e.offset,organizationId:e.organizationId});return await this.adminFetch(t,"GET")}async listAuthOrgInvitations(e){const t=p(Ht,{limit:e.limit,offset:e.offset,organizationId:e.organizationId});return await this.adminFetch(t,"GET")}async listAuthSignUpInvitations(e={}){const t=p(Nt,{limit:e.limit,offset:e.offset});return await this.adminFetch(t,"GET")}async createAuthSignUpInvitation(e){return await this.adminFetch(xt,"POST",e)}async revokeAuthSignUpInvitation(e){await this.adminFetch(Dt,"POST",e)}async removeAuthOrgMember(e){await this.adminFetch(Ft,"POST",e)}async cancelAuthOrgInvitation(e){await this.adminFetch(Lt,"POST",e)}async getAuthConfig(){return await this.adminFetch(Ut,"GET")}async createAuthOrganization(e){return await this.adminFetch(Bt,"POST",e)}async updateAuthOrganization(e){return await this.adminFetch(Kt,"POST",e)}async deleteAuthOrganization(e){await this.adminFetch(Wt,"POST",e)}async addAuthOrgMember(e){return await this.adminFetch(qt,"POST",e)}async inviteAuthOrgMember(e){return await this.adminFetch(Qt,"POST",e)}async setAuthOrgMemberRole(e){return await this.adminFetch($t,"POST",e)}async listAuthOrgTeams(e){const t=p(Gt,{limit:e.limit,offset:e.offset,organizationId:e.organizationId});return await this.adminFetch(t,"GET")}async createAuthOrgTeam(e){return await this.adminFetch(jt,"POST",e)}async updateAuthOrgTeam(e){return await this.adminFetch(zt,"POST",e)}async removeAuthOrgTeam(e){await this.adminFetch(Vt,"POST",e)}async listAuthOrgTeamMembers(e){const t=p(Jt,{limit:e.limit,offset:e.offset,teamId:e.teamId});return await this.adminFetch(t,"GET")}async addAuthOrgTeamMember(e){return await this.adminFetch(Yt,"POST",e)}async removeAuthOrgTeamMember(e){await this.adminFetch(Xt,"POST",e)}async listAuthOrgRoles(e){const t=p(Zt,{limit:e.limit,offset:e.offset,organizationId:e.organizationId});return await this.adminFetch(t,"GET")}async createAuthOrgRole(e){return await this.adminFetch(es,"POST",e)}async updateAuthOrgRole(e){return await this.adminFetch(ts,"POST",e)}async deleteAuthOrgRole(e){await this.adminFetch(ss,"POST",e)}async listAuthSessions(e={}){this.assertOpen();const t=p(mt,{limit:e.limit,offset:e.offset,userId:e.userId});return await this.adminFetch(t,"GET")}subscribe(e,t,s,r={}){this.assertOpen();const i=t??{},n=k.key(e.__lunoraRef,i,r.shardKey);let o=this.subscriptions.get(n);const c=K(s),h=K(r.onError),d=K(r.onCheckpoint);if(!o){this.nextSubId+=1;const f=`sub_${this.nextSubId.toString()}`,S=Q(i),y=this.takeHydratedCache(e.__lunoraRef,S,r.shardKey);o={acked:!1,args:i,argsKey:S,callbacks:new Set,checkpointCallbacks:new Set,errorCallbacks:new Set,fn:e,id:f,lastValue:y?.value,optimisticLayers:[],serverBase:y?.value,serverCursor:y?.serverCursor,shardKey:r.shardKey,wireArgs:g(i,`args for '${e.__lunoraRef}'`),...y?.serverEpoch===void 0?{}:{serverEpoch:y.serverEpoch}},this.subscriptions.add(o)}if(o.callbacks.add(c),h&&o.errorCallbacks.add(h),d&&o.checkpointCallbacks.add(d),o.lastValue!==void 0)try{c(o.lastValue)}catch{}this.ensureSocket(r.shardKey),this.sendSubscribeIfOpen(o);const u=o;return()=>{u.callbacks.delete(c),h&&u.errorCallbacks.delete(h),d&&u.checkpointCallbacks.delete(d),u.callbacks.size===0&&(this.sendOrQueueUnsubscribe(u.shardKey,u.id,"unsubscribe"),this.subscriptions.remove(u))}}subscribeShape(e,t,s={}){if(this.assertOpen(),this.followsAnotherTab()){const{onError:n}=s;return n!==void 0&&queueMicrotask(()=>{n({code:"NOT_IMPLEMENTED",message:"LunoraClient: `subscribeShape` is unavailable on a cross-tab follower tab. The `crossTabSync` channel only carries data from the leader tab outward and shape pokes are not part of that broadcast set, so this subscription could never resolve. Turn off `crossTabSync`, or use a `list`-backed collection, which IS relayed."})}),()=>{}}this.nextShapeId+=1;const r=`shape_${this.nextShapeId.toString()}`,i={args:e.args,callbacks:new Set([t]),errorCallbacks:s.onError?new Set([s.onError]):new Set,id:r,name:e.name,onCheckpoint:s.onCheckpoint,rows:new Map,shardKey:s.shardKey,wireArgs:e.args===void 0?void 0:g(e.args,`shape args for '${e.name}'`)};return this.shapeSubscriptions.set(r,i),this.ensureSocket(s.shardKey),this.sendShapeSubscribeIfOpen(i),()=>{this.shapeSubscriptions.delete(r),this.sendOrQueueUnsubscribe(i.shardKey,r,"shape_unsubscribe")}}stream(e,t,s={}){if(this.assertOpen(),this.WebSocketImpl===void 0)throw new m("INTERNAL","LunoraClient: streams require a WebSocket implementation");this.nextStreamId+=1;const r=`stream_${this.nextStreamId.toString()}`,{shardKey:i}=s,n=t??{},{handle:o,iterable:c}=ge({maxBuffer:s.maxBuffer,onCancel:()=>{this.cancelStream(r,i)}});this.ensureSocket(i);const h=this.getConnection(i),d={id:r,query:{args:g(n,`stream args for '${e.__lunoraRef}'`),functionPath:e.__lunoraRef,shardKey:i},type:"stream"},u={durable:s.durable===!0,generation:void 0,handle:o,lastSeq:0,message:d,shardKey:i,started:!1};this.streams.set(r,u);const f=h?.wsState==="open"&&b(h,d);if(u.started=f,!f&&h===void 0)return this.streams.delete(r),o.fail(new m("STREAM_DISCONNECTED","stream unavailable: this tab is not the cross-tab WebSocket leader, so it holds no socket to stream over")),c;if(!f){for(h.pendingStreams=h.pendingStreams??[];h.pendingStreams.length>=Be;){const y=h.pendingStreams.shift()?.id,v=y?this.streams.get(y):void 0;v&&(v.handle.fail(new m("STREAM_QUEUE_OVERFLOW","stream-start frame evicted while socket was unreachable")),this.streams.delete(y))}h.pendingStreams.push(d)}return c}httpStream(e,t,s={}){if(this.closed)throw new m("CLIENT_CLOSED","LunoraClient is closed");if(!this.fetchImpl)throw new m("INTERNAL","LunoraClient: no `fetch` implementation available");const r={...this.authToken?{authorization:`Bearer ${this.authToken}`}:{},...s.headers};return le(e,t,{baseUrl:this.url,fetch:this.fetchImpl,headers:r,maxBuffer:s.maxBuffer,signal:s.signal})}close(){this.closed=!0,this.outboxLeaderRelease?.(),this.outboxLeaderRelease=void 0;for(const e of this.streams.values())e.handle.fail(new m("CLIENT_CLOSED","LunoraClient closed"));this.streams.clear();for(const e of this.connections.values())this.teardownConnection(e);for(const e of this.adminSocketTeardowns)e();this.adminSocketTeardowns.clear();for(const e of this.replayRetryTimers.values())clearTimeout(e);this.replayRetryTimers.clear(),this.replayRetryState.clear(),this.offlineQueue.clear(),this.queuedIdentities.clear(),this.cacheFlushTimer!==void 0&&(clearTimeout(this.cacheFlushTimer),this.cacheFlushTimer=void 0),this.pendingCacheWrites.size>0&&this.flushQueryCacheWrites().catch(()=>{}),this.authTokenListeners.clear(),this.statusListeners.clear(),this.tokenExpiredListeners.clear(),this.mutationSettledListeners.clear(),this.pendingChangeListeners.clear(),this.whisperHandlers.clear(),this.shapeSubscriptions.clear(),this.pokeBuffers.clear(),this.subscriptions.clear(),this.clientQueryStore.clear(),this.hydratedQueryCache.clear(),this.tabCoordinator?.stop(),this.tabCoordinator=void 0}assertOpen(){if(this.closed)throw new m("INTERNAL","LunoraClient is closed")}followsAnotherTab(){const e=this.tabCoordinator;if(e===void 0||e.isLeader())return!1;const t=e.leaderTabId;return t!==void 0&&t!==e.id}assertLeaderOwnedSurface(e){if(this.followsAnotherTab())throw new m("NOT_IMPLEMENTED",`LunoraClient: \`${e}\` is unavailable on a cross-tab follower tab. The \`crossTabSync\` channel only carries data from the leader tab outward, so this call could never reach the server. Turn off \`crossTabSync\`, or keep \`${e}\` on the leader tab.`)}clearConnectionTimers(e){clearTimeout(e.reconnectTimer),clearTimeout(e.connectTimer),clearTimeout(e.stableTimer),e.reconnectTimer=void 0,e.connectTimer=void 0,e.stableTimer=void 0}teardownConnection(e){const t=l(e.shardKey);for(const[s,r]of this.streams)l(r.shardKey)===t&&(r.handle.fail(new m("STREAM_DISCONNECTED","stream terminated: the connection carrying it was torn down")),this.streams.delete(s));if(e.pendingStreams=void 0,e.pendingUnsubscribes=[],this.clearConnectionTimers(e),this.stopHeartbeat(e),e.socket){try{e.socket.close()}catch{}e.socket=void 0}e.wsState="closed"}createTabCoordinator(){const e=`lunora-bridge::${this.url}::${this.identityFingerprint()??"anon"}`;return new ue({channelName:e,onBecomeLeader:()=>{for(const t of this.subscriptions.all())this.ensureSocket(t.shardKey),this.sendSubscribeIfOpen(t);for(const t of this.queuedOfflineShardKeys)this.ensureSocket(t);this.tabCoordinator?.broadcastConnectionStatus(this.computeStatus(),this.identityFingerprint())},onStopBeingLeader:()=>{for(const[t,s]of this.connections)this.teardownConnection(s),this.connections.delete(t);this.leaderStatus=void 0,this.leaderWasEverConnected=!1},onConnectionStatus:(t,s)=>{if(s!==void 0&&s!==this.identityFingerprint())return;const r=t==="connected"&&this.leaderStatus!=="connected";this.leaderStatus=t,t==="connected"&&(this.leaderWasEverConnected=!0),this.emitConnectionStatus(),r&&this.flushAllOfflineQueues()},onSubscriptionData:(t,s,r,i,n)=>{if(n!==void 0&&n!==this.identityFingerprint())return;const o=this.subscriptions.get(t);o&&(o.serverBase=s,r!==void 0&&(o.serverCursor=r,i!==void 0&&(o.serverEpoch=i),U(o,r)),O(o,R(s,o.optimisticLayers)))},onLeaderClaimAnswered:()=>{this.tabCoordinator?.isLeader()&&this.tabCoordinator.broadcastConnectionStatus(this.computeStatus(),this.identityFingerprint())},onSubscriptionError:(t,s,r)=>{if(r!==void 0&&r!==this.identityFingerprint())return;const i=this.subscriptions.get(t);i&&_(i.errorCallbacks,s)},onSubscriptionSettled:(t,s,r,i,n,o)=>{if(o!==void 0&&o!==this.identityFingerprint())return;const c=this.subscriptions.get(t);if(c){this.ackAndAdvanceCursor(c,s,r),i!==void 0&&n===this.clientId&&(c.lastMutationId=Math.max(c.lastMutationId??0,i));for(const h of c.checkpointCallbacks)h({checkpoint:c.serverCursor,mutationId:c.lastMutationId})}}})}async enqueueOfflineMutation(e,t,s,r,i,n,o){const c=this.identityFingerprint();if(this.outbox){this.outboxMutationCounter+=1;const h=this.outboxMutationCounter;try{await this.outbox.enqueue({args:t,clientId:this.clientId,functionPath:e.__lunoraRef,idempotencyKey:`${this.clientId}:${String(h)}`,identity:c,mutationId:h,shardKey:s})}catch(d){throw H(i),d instanceof Error?d:new Error(String(d))}for(const d of n)d(void 0);return}return new Promise((h,d)=>{const u={args:t,functionPath:e.__lunoraRef,liveAwaiter:!0,id:r,clientId:this.clientId,identity:c,precondition:o,onCommit:f=>{for(const S of n)S(f)},reject:f=>{this.queuedIdentities.delete(r),H(i),d(f instanceof Error?f:new Error(String(f)))},resolve:h,shardKey:s};this.offlineQueue.enqueue(u),this.queuedOfflineShardKeys.add(s),u.id!==void 0&&this.queuedIdentities.set(u.id,c)})}async hydratePersistedQueue(){try{const e=await this.offlineQueue.hydrate();for(const t of e)this.queuedOfflineShardKeys.add(t),this.ensureSocket(t)}catch{}}hydrateAsOutboxLeader(){const e=()=>{this.hydratePersistedQueue().catch(()=>{})},t=globalThis.navigator?.locks;if(!t){e();return}t.request(`lunora:outbox-leader:${this.url}`,()=>(this.closed||e(),new Promise(s=>{if(this.closed){s();return}this.outboxLeaderRelease=s}))).catch(e)}async hydrateQueryCache(){if(this.queryCache)try{const e=await this.queryCache.load(),t=new Map;for(const s of this.subscriptions.all())t.set(P(s.fn.__lunoraRef,s.argsKey,s.shardKey),s);for(const{key:s,...r}of e){if(ye(this.persistenceVersion,r.version)){this.queryCache.remove(s).catch(()=>{});continue}const i=t.get(s);if(i){this.seedSubscriptionFromCache(i,r);continue}this.hydratedQueryCache.set(s,r)}}catch{}}seedSubscriptionFromCache(e,t){e.serverBase!==void 0||e.lastValue!==void 0||t.identity!==this.identityFingerprint()||(e.serverBase=t.value,e.serverCursor=t.serverCursor,t.serverEpoch!==void 0&&(e.serverEpoch=t.serverEpoch),O(e,R(t.value,e.optimisticLayers)))}takeHydratedCache(e,t,s){const r=P(e,t,s),i=this.hydratedQueryCache.get(r);if(i!==void 0)return this.hydratedQueryCache.delete(r),i.identity===this.identityFingerprint()?i:void 0}persistQueryValue(e){const t=e.serverBase;if(!this.queryCache||t===void 0)return;const s=P(e.fn.__lunoraRef,e.argsKey,e.shardKey),r=this.getConnection(e.shardKey)?.identity;this.pendingCacheWrites.set(s,{identity:r===void 0?this.identityFingerprint():r,serverCursor:e.serverCursor,ts:Date.now(),value:t,...e.serverEpoch===void 0?{}:{serverEpoch:e.serverEpoch},...this.persistenceVersion===void 0?{}:{version:this.persistenceVersion}}),this.cacheFlushTimer??=setTimeout(()=>{this.flushQueryCacheWrites().catch(()=>{})},xe)}async flushQueryCacheWrites(){this.cacheFlushTimer=void 0;const{queryCache:e}=this;if(!e){this.pendingCacheWrites.clear();return}const t=[...this.pendingCacheWrites.entries()];this.pendingCacheWrites.clear(),await Promise.allSettled(t.map(async([s,r])=>e.put(s,r)))}computeStatus(){if(this.tabCoordinator&&!this.tabCoordinator.isLeader())return this.leaderStatus??"idle";const e=[...this.connections.values()];return e.length===0?"idle":e.some(t=>t.wsState==="open")?"connected":e.some(t=>t.wsState==="connecting")?"connecting":"offline"}emitConnectionStatus(){const e=this.computeStatus();e!==this.lastStatus&&(this.lastStatus=e,this.statusListeners.emit(e),this.tabCoordinator?.isLeader()&&this.tabCoordinator.broadcastConnectionStatus(e,this.identityFingerprint()))}emitItemSettled(e,t,s){this.mutationSettledListeners.emit({args:e.args,code:s===void 0?void 0:s.code,error:s,functionPath:e.functionPath,hadAwaiter:e.liveAwaiter??!1,id:e.id??"",shardKey:e.shardKey,status:t})}applyOptimisticUpdates(e,t,s,r){const i=[],n=[];if(!r)return{confirms:i,rollbacks:n};const o=k.key(e,t,s),c=this.subscriptions.get(o);if(c){const h=fe(c,r);h&&(i.push(h.confirm),n.push(h.rollback))}return{confirms:i,rollbacks:n}}applyOptimisticUpdate(e,t,s,r,i){const{confirms:n,rollbacks:o,store:c}=me(this.subscriptions,s);try{e(c,t)}catch{H(o);return}r.push(...o),i.push(...n)}getConnection(e){return this.connections.get(l(e))}sendOrQueueUnsubscribe(e,t,s){const r=this.getConnection(e);r&&!b(r,{id:t,type:s})&&r.pendingUnsubscribes.push({id:t,type:s})}connectionGateState(e){if(this.tabCoordinator&&!this.tabCoordinator.isLeader()){let s="idle";return this.leaderStatus==="connected"?s="open":this.leaderStatus==="connecting"&&(s="connecting"),{hasSocket:!1,wasEverConnected:this.leaderWasEverConnected,wsState:s}}const t=this.getConnection(e);return{hasSocket:t?.socket!==void 0,wasEverConnected:t?.wasEverConnected??!1,wsState:t?.wsState??"idle"}}getOrCreateConnection(e){const t=l(e);let s=this.connections.get(t);return s||(s={connectTimer:void 0,heartbeatTimer:void 0,lastFrameAt:0,pendingUnsubscribes:[],reconnect:G(this.reconnectOptions),reconnectTimer:void 0,shardKey:e,socket:void 0,stableTimer:void 0,wasEverConnected:!1,wsState:"idle"},this.connections.set(t,s)),s}wsUrlFor(e,t){const s=[];if(e!==void 0&&s.push(`shard=${encodeURIComponent(e)}`),t!==void 0&&s.push(`token=${encodeURIComponent(t)}`),s.length===0)return this.wsUrl;const r=this.wsUrl.includes("?")?"&":"?";return`${this.wsUrl}${r}${s.join("&")}`}rpcRequestHeaders(e,t){const s={"content-type":"application/json"},r=this.shardCursors.get(this.cursorKeyFor(t));if(r!==void 0&&(s["x-lunora-min-seq"]=r.toString()),this.authToken&&(s.authorization=`Bearer ${this.authToken}`),e.mutationId&&(s["x-lunora-mutation-id"]=e.mutationId),(e.clientId!==void 0||e.mutationId!==void 0)&&(s["x-lunora-client-id"]=e.clientId??this.clientId),e.clientSeq!==void 0&&(s["x-lunora-client-seq"]=e.clientSeq.toString()),e.attachBookmark){const i=this.bookmark.get();i&&(s["x-d1-bookmark"]=i)}return s}async rpc(e,t,s,r={}){if(!this.fetchImpl)throw new I("LunoraClient: no `fetch` implementation available");const i=this.rpcRequestHeaders(r,s),n=await this.fetchImpl(C(this.url,Me),{body:JSON.stringify({args:g(t,`args for '${e}'`),functionPath:e,shardKey:s}),headers:i,method:"POST"});if(r.captureBookmark){const c=n.headers.get("x-d1-bookmark");c&&this.bookmark.set(c)}let o;try{o=await n.json()}catch{throw M(n.status,n.statusText,n.headers.get("retry-after"))}if("error"in o)throw Z(o.error,n.headers.get("retry-after"));if(!n.ok)throw M(n.status,n.statusText,n.headers.get("retry-after"));return r.onMutationAck?.(o.lastMutationId),r.onCommitCursor?.(o.commitCursor),this.learnDefaultShardKey(n,s),this.recordShardCursor(s,o.commitCursor),T(o.result)}async adminFetch(e,t,s,r){if(!this.fetchImpl)throw new m("INTERNAL","LunoraClient: no `fetch` implementation available");const i={};this.authToken&&(i.authorization=`Bearer ${this.authToken}`);const n=s instanceof ArrayBuffer||s instanceof Blob;let o;s===void 0?o=void 0:n?(o=s,r!==void 0&&(i["content-type"]=r)):(o=JSON.stringify(s),i["content-type"]="application/json");const c=await this.fetchImpl(C(this.url,e),{body:o,headers:i,method:t});let h;try{h=await c.json()}catch{const d=c.statusText?` ${c.statusText}`:"";throw new m("INTERNAL",`LunoraClient: response was not JSON (status ${c.status.toString()}${d})`)}if(typeof h=="object"&&h!==null&&"error"in h){const d=h.error,u=new Error(d.message??"admin request failed");throw u.code=d.code,u}if(!c.ok){const d=c.statusText?` ${c.statusText}`:"";throw new m("INTERNAL",`LunoraClient: admin request failed (status ${c.status.toString()}${d})`)}return h}effectiveConnectionContext(e){const t=this.connectionContextHolders.get(e);return t&&t.length>0?t[t.length-1]?.context:this.connectionContexts.get(e)??this.defaultConnectionContext}refreshConnectionContext(e){const t=this.connections.get(e);t?.wsState==="open"&&this.sendConnectEnvelope(t)}sendConnectEnvelope(e){const t=this.effectiveConnectionContext(l(e.shardKey));b(e,{caps:ns,clientId:this.clientId,id:"connect",type:"connect",...t===void 0?{}:{context:t}})}resendShapeSubscriptions(e){for(const t of this.shapeSubscriptions.values())l(t.shardKey)===l(e)&&this.sendShapeSubscribeIfOpen(t)}ensureSocket(e){if(this.closed||this.WebSocketImpl===void 0||this.tabCoordinator&&!this.tabCoordinator.isLeader())return;const t=this.getOrCreateConnection(e);if(!(t.wsState==="open"||t.wsState==="connecting")){if(t.wsState="connecting",this.emitConnectionStatus(),typeof this.wsToken=="function"){this.openSocketWithProvidedToken(t,e,this.wsToken).catch(()=>{});return}this.openSocket(t,e,this.wsToken)}}async openSocketWithProvidedToken(e,t,s){let r;try{r=await s()}catch{this.handleDisconnect(e);return}this.closed||this.WebSocketImpl===void 0||e.wsState!=="connecting"||e.socket!==void 0||this.openSocket(e,t,r)}openManagedSocket(e,t,s,r){const{WebSocketImpl:i}=this;if(i===void 0)throw new m("INTERNAL","no WebSocket implementation available");const n=new i(t);e.socket=n;const o=()=>{this.stopHeartbeat(e),e.connectTimer!==void 0&&(clearTimeout(e.connectTimer),e.connectTimer=void 0),e.socket===n&&(e.socket=void 0)},c=h=>{o(),r.onClose(h)};s>0&&(e.connectTimer=setTimeout(()=>{if(e.connectTimer=void 0,e.socket===n){try{n.close()}catch{}c()}},s)),n.addEventListener("open",()=>{if(e.socket===n){e.connectTimer!==void 0&&(clearTimeout(e.connectTimer),e.connectTimer=void 0),e.lastFrameAt=Date.now();try{r.onOpen?.()}catch(h){console.error("[lunora] connection open handler threw",h)}this.startHeartbeat(e,c)}}),n.addEventListener("message",h=>{if(e.socket===n){e.lastFrameAt=Date.now();try{r.onMessage(h)}catch(d){console.error("[lunora] server frame handler threw",d)}}}),n.addEventListener("close",h=>{e.socket===n&&c(h)}),n.addEventListener("error",()=>{e.socket===n&&c()})}openSocket(e,t,s){this.WebSocketImpl!==void 0&&(e.identity=this.identityFingerprint(),this.openManagedSocket(e,this.wsUrlFor(t,s),this.connectTimeoutMs,{onClose:r=>{r?.code===4001&&this.notifyTokenExpired(),this.handleDisconnect(e)},onMessage:r=>{this.handleServerMessage(r.data,t)},onOpen:()=>{e.wsState="open",e.wasEverConnected=!0,clearTimeout(e.stableTimer),e.stableTimer=setTimeout(()=>{e.wsState==="open"&&e.reconnect.reset()},De),this.emitConnectionStatus(),this.sendConnectEnvelope(e),this.markShardPendingAck(t);for(const i of this.subscriptions.all())l(i.shardKey)===l(t)&&this.sendSubscribeIfOpen(i);if(this.resendShapeSubscriptions(t),e.pendingUnsubscribes.length>0){const i=e.pendingUnsubscribes;e.pendingUnsubscribes=[];for(const{id:n,type:o}of i)b(e,{id:n,type:o})}this.flushPendingStreams(e);const r=this.whisperHandlers.get(l(t));if(r)for(const i of r.keys())b(e,{topic:i,type:"whisper_subscribe"});this.flushOfflineQueue(t).catch(()=>{})}}))}flushPendingStreams(e){if(!e.pendingStreams||e.pendingStreams.length===0)return;const t=e.pendingStreams;e.pendingStreams=[];for(const s of t){const r=b(e,s)?this.streams.get(String(s.id)):void 0;r&&(r.started=!0)}}cancelStream(e,t){const s=this.getConnection(t),r=this.streams.get(e);s&&(s.pendingStreams=s.pendingStreams?.filter(i=>i.id!==e),!b(s,{id:e,type:"unsubscribe"})&&r?.durable===!0&&r.started&&s.pendingUnsubscribes.push({id:e,type:"unsubscribe"})),this.streams.delete(e)}handleDisconnect(e){if(this.closed||e.wsState==="idle"||e.wsState==="closed")return;this.stopHeartbeat(e),this.clearConnectionTimers(e),e.socket=void 0,e.wsState="idle",this.emitConnectionStatus(),this.markShardPendingAck(e.shardKey);const t=new Set((e.pendingStreams??[]).map(r=>r.id));for(const[r,i]of this.streams)if(!(l(i.shardKey)!==l(e.shardKey)||t.has(r))){if(i.durable){const n={...i.message,...i.generation===void 0?{}:{generation:i.generation},sinceChunk:i.lastSeq};i.message=n,e.pendingStreams=[...(e.pendingStreams??[]).filter(o=>o.id!==r),n];continue}i.handle.fail(new m("STREAM_DISCONNECTED","stream terminated: WebSocket disconnected")),this.streams.delete(r)}if(this.WebSocketImpl===void 0)return;const s=e.reconnect.next();e.reconnectTimer=setTimeout(()=>{e.reconnectTimer=void 0,this.ensureSocket(e.shardKey)},s)}startHeartbeat(e,t){this.stopHeartbeat(e),!(this.heartbeatIntervalMs<=0)&&(e.heartbeatTimer=setInterval(()=>{if(!e.socket)return;const{socket:s}=e;if(Date.now()-e.lastFrameAt>this.heartbeatIntervalMs*2.5){try{s.close()}catch{}t();return}try{s.send(Le)}catch{}},this.heartbeatIntervalMs))}stopHeartbeat(e){e.heartbeatTimer!==void 0&&(clearInterval(e.heartbeatTimer),e.heartbeatTimer=void 0)}markShardPendingAck(e){const t=l(e);for(const s of this.subscriptions.all())l(s.shardKey)===t&&(s.acked=!1)}sendSubscribeIfOpen(e){const t=this.getConnection(e.shardKey);if(t?.wsState!=="open"||e.acked)return;const s=e.fn.__lunoraTable??e.fn.__lunoraRef,r=e.serverCursor!==void 0&&e.serverBase!==void 0;b(t,{id:e.id,query:{args:e.wireArgs,functionPath:e.fn.__lunoraRef,table:s,...r?{sinceSeq:e.serverCursor}:{},...r&&e.serverEpoch!==void 0?{sinceEpoch:e.serverEpoch}:{}},type:"subscribe"})}sendShapeSubscribeIfOpen(e){const t=this.getConnection(e.shardKey);t?.wsState==="open"&&b(t,{id:e.id,shape:{name:e.name,...e.wireArgs===void 0?{}:{args:e.wireArgs}},type:"shape_subscribe",...e.serverCursor===void 0?{}:{sinceCheckpoint:e.serverCursor},...e.serverEpoch===void 0?{}:{sinceEpoch:e.serverEpoch}})}handleServerMessage(e,t){const s=cs(e);if(s===void 0)return;let r;try{r=JSON.parse(s)}catch{return}switch(r.type!=="error"&&this.getConnection(t)?.reconnect.reset(),r.type){case"ack":{const i=this.subscriptions.getById(r.id);i&&(i.acked=!0);return}case"chunk":{const{data:i,generation:n,id:o,seq:c}=r,h=this.streams.get(o);h&&typeof c=="number"&&(h.lastSeq=c,typeof n=="number"&&(h.generation=n),h.durable=!0),h?.handle.push(T(i));return}case"complete":{this.handleCompleteMessage(r.id);return}case"data":case"delta":{this.handleDataMessage(r);return}case"error":{this.handleErrorMessage(r);break}case"pokeEnd":{this.handlePokeEnd(r,t);break}case"pokePart":{this.handlePokePart(r,t);break}case"pokeStart":{this.handlePokeStart(r,t);break}case"resume":{this.handleResumeMessage(r);break}case"settled":{this.handleSettledMessage(r);break}case"whisper":{this.dispatchWhisper(r,t);break}}}handleErrorMessage(e){if(e.error?.code==="TOKEN_EXPIRED"){this.notifyTokenExpired();return}const{id:s}=e,r=s===void 0?void 0:this.streams.get(s);if(r&&s!==void 0){r.handle.fail(as(e)),this.streams.delete(s);return}const i=s===void 0?void 0:this.subscriptions.getById(s);if(i){const o=X(e),c=this.identityFingerprint(),h=k.keyOf(i);_(i.errorCallbacks,o),this.tabCoordinator?.isLeader()&&this.tabCoordinator.broadcastSubscriptionError(h,o,c);return}const n=s===void 0?void 0:this.shapeSubscriptions.get(s);n&&_(n.errorCallbacks,X(e))}pokeBufferKey(e,t){return`${l(e)}\0${t}`}handlePokeStart(e,t){j(this.pokeBuffers,ie.MAX_POKE_BUFFERS),this.pokeBuffers.set(this.pokeBufferKey(t,e.pokeId),{baseCheckpoint:e.baseCheckpoint,bases:new Map,epoch:e.epoch,lastMutationId:new Map,parts:new Map,resets:new Set})}handlePokePart(e,t){const s=this.pokeBuffers.get(this.pokeBufferKey(t,e.pokeId));if(!s)return;const r=s.parts.get(e.shapeId)??[];for(const n of e.rowsPatch)r.push(n.value===void 0?n:{...n,value:T(n.value)});s.parts.set(e.shapeId,r),e.lastMutationId!==void 0&&s.lastMutationId.set(e.shapeId,e.lastMutationId);const i=e.baseCheckpoint??s.baseCheckpoint;i!==void 0&&s.bases.set(e.shapeId,i),e.reset===!0&&s.resets.add(e.shapeId)}handlePokeEnd(e,t){const s=this.pokeBufferKey(t,e.pokeId),r=this.pokeBuffers.get(s);if(r){this.pokeBuffers.delete(s);for(const i of r.parts.keys()){const n=this.shapeSubscriptions.get(i);n&&this.applyPokePart(n,r,e)}}}applyPokePart(e,t,s){const r=t.parts.get(e.id)??[],i=t.resets.has(e.id),n=t.bases.get(e.id),o=t.epoch!==void 0&&e.serverEpoch!==void 0&&t.epoch!==e.serverEpoch,c=n!==void 0&&e.serverCursor!==void 0&&e.serverCursor!==n;if(!i&&(o||c)){e.rows.clear(),e.serverCursor=void 0,e.serverEpoch=void 0,this.emitShapeRows(e),this.sendShapeSubscribeIfOpen(e);return}i&&e.rows.clear(),Fe(e.rows,r),s.checkpoint!==void 0&&(e.serverCursor=s.checkpoint),s.epoch!==void 0&&(e.serverEpoch=s.epoch);const h=t.lastMutationId.get(e.id);h!==void 0&&(e.lastMutationId=h),this.emitShapeRows(e),e.onCheckpoint?.({checkpoint:e.serverCursor,mutationId:e.lastMutationId})}resnapshotSubscription(e){e.acked=!1,e.serverCursor=void 0,e.serverEpoch=void 0,console.warn("[lunora] could not merge a row delta into the cached result; re-subscribing for a full snapshot"),this.sendSubscribeIfOpen(e)}emitShapeRows(e){const t=[...e.rows.values()];for(const s of e.callbacks)try{s(t)}catch{}}handleDataMessage(e){const{id:t}=e,s=t?this.subscriptions.getById(t):void 0;if(!s)return;let r;try{r=this.resolveDataPayload(e,s)}catch(i){_(s.errorCallbacks,{code:"WIRE_DECODE_FAILED",message:`could not decode a server frame for this subscription — ${i instanceof Error?i.message:String(i)}`});return}if(r===V){this.resnapshotSubscription(s);return}if(s.serverBase=r,e.cursor!==void 0&&(s.serverCursor=e.cursor),e.epoch!==void 0&&(s.serverEpoch=e.epoch),e.lastMutationId!==void 0){s.lastMutationId=Math.max(s.lastMutationId??0,e.lastMutationId);for(const i of s.checkpointCallbacks)i({checkpoint:s.serverCursor,mutationId:s.lastMutationId,rowsFollow:!0})}if(this.persistQueryValue(s),U(s,s.serverCursor),O(s,R(r,s.optimisticLayers)),this.tabCoordinator?.isLeader()){const i=k.keyOf(s);this.tabCoordinator.broadcastSubscriptionData(i,r,s.serverCursor,s.serverEpoch,this.identityFingerprint())}}handleResumeMessage(e){const t=this.subscriptions.getById(e.id);t&&this.ackAndAdvanceCursor(t,e.cursor,e.epoch)}handleSettledMessage(e){const t=this.subscriptions.getById(e.id);if(t){this.ackAndAdvanceCursor(t,e.cursor,e.epoch),e.lastMutationId!==void 0&&(t.lastMutationId=Math.max(t.lastMutationId??0,e.lastMutationId));for(const s of t.checkpointCallbacks)s({checkpoint:t.serverCursor,mutationId:t.lastMutationId});if(this.tabCoordinator?.isLeader()){const s=k.keyOf(t);this.tabCoordinator.broadcastSubscriptionSettled(s,t.serverCursor,t.serverEpoch,t.lastMutationId,this.clientId,this.identityFingerprint())}}}ackAndAdvanceCursor(e,t,s){e.acked=!0,(t!==void 0&&t!==e.serverCursor||s!==void 0&&s!==e.serverEpoch)&&(t!==void 0&&(e.serverCursor=t),s!==void 0&&(e.serverEpoch=s),this.persistQueryValue(e),U(e,e.serverCursor)&&O(e,R(e.serverBase,e.optimisticLayers)))}resolveDataPayload(e,t){if("data"in e&&e.data!==void 0)return T(e.data);const s=T(e.delta);return ae(s)?t.serverBase===void 0?s:oe(t.serverBase,s)??V:s}dispatchWhisper(e,t){const s=this.whisperHandlers.get(l(t))?.get(e.topic);if(!s)return;const r=T(e.data);for(const i of s)try{i(r,e.from)}catch{}}notifyTokenExpired(){this.tokenExpiredListeners.emit()}handleCompleteMessage(e){const t=this.streams.get(e);if(t){t.handle.complete(),this.streams.delete(e);return}const s=this.subscriptions.getById(e);s&&(s.acked=!1,_(s.errorCallbacks,{code:"SUBSCRIPTION_CANCELLED",message:"subscription was cancelled by the server"}))}unpersist(e){e&&this.persistence?.remove(e).catch(t=>{Se(this.onPersistenceError,"remove",t,e)})}identityFingerprint(){if(this.authSubject!==void 0)return this.authSubject===null?null:`subj:${this.authSubject}`;const e=this.authToken;return e===null?null:this.hashToken(e)}hashToken(e){let t=2166136261,s=5381;for(let r=0;r<e.length;r+=1){const i=e.charCodeAt(r);t^=i,t=Math.imul(t,16777619),s=Math.imul(s,33)+i}return`${e.length.toString(36)}:${(t>>>0).toString(36)}:${(s>>>0).toString(36)}`}isSameCredentialUnderTokenHash(e){if(e===null||e.startsWith("subj:"))return!1;const t=this.authToken;return t===null?!1:this.hashToken(t)===e}adoptResolvedSubject(e,t){this.closed||t===null||this.authToken!==e||this.setAuthToken(e,t.id)}subjectAwaitingReconfirm(){return this.authSubject!==void 0&&this.authSubject!==null&&this.subjectToken!==this.authToken}stampOf(e){const t=e.id===void 0?void 0:this.queuedIdentities.get(e.id);return t===void 0?e.identity:t}rejectQueuedForIdentityChange(e){const t=this.offlineQueue.drain(),s=[];for(const r of t){if(this.replayIdentityVerdict(this.stampOf(r))!=="mismatch"){s.push(r);continue}this.queuedIdentities.delete(r.id??""),this.unpersist(r.id);const i=new Error("offline mutation discarded: auth identity changed before replay");i.code="OFFLINE_IDENTITY_CHANGED",r.reject(i),this.emitItemSettled(r,"rejected",i)}this.offlineQueue.requeue(s),e!==null&&this.clearQueryCacheForIdentityChange()}restampConnectionIdentity(e,t){for(const s of this.connections.values())s.identity===e&&(s.identity=t)}restampQueuedIdentity(e,t){for(const[s,r]of this.queuedIdentities)r===e&&this.queuedIdentities.set(s,t);this.offlineQueue.restampIdentity(e,t)}restampWatermarks(e,t){const s=e??"",r=this.clientWatermarks.get(s);if(r===void 0)return;this.clientWatermarks.delete(s);const i=t??"",n=this.clientWatermarks.get(i);if(n===void 0)this.clientWatermarks.set(i,r);else for(const[o,c]of r)n.set(o,c)}clearQueryCacheForIdentityChange(){this.cacheFlushTimer!==void 0&&(clearTimeout(this.cacheFlushTimer),this.cacheFlushTimer=void 0),this.pendingCacheWrites.clear(),this.hydratedQueryCache.clear(),this.queryCache?.clear().catch(()=>{})}flushAllOfflineQueues(){for(const e of this.queuedOfflineShardKeys)this.flushOfflineQueue(e).catch(()=>{})}async flushOfflineQueue(e){const t=l(e),s=this.offlineFlushes.get(t);if(s===void 0&&this.offlineQueue.size===0)return;const r=(async()=>{await(s??Promise.resolve());try{await this.drainOfflineQueue(e)}catch{}})();this.offlineFlushes.set(t,r),await r,this.offlineFlushes.get(t)===r&&this.offlineFlushes.delete(t)}async drainOfflineQueue(e){const t=this.offlineQueue.drainConflict();for(const h of t){this.unpersist(h.id),this.queuedIdentities.delete(h.id??"");const d=new Error("offline mutation skipped: precondition failed before replay");d.code="OFFLINE_PRECONDITION_FAILED",this.emitItemSettled(h,"rejected",d)}const s=l(e),r=this.offlineQueue.drain(h=>l(h.shardKey)===s);if(r.length===0)return;const i=[],n=[];for(const h of r){const d=this.replayGateVerdict(h);d==="send"?i.push(h):d==="hold"&&n.push(h)}if(this.offlineQueue.requeue(n),n.length>0&&this.subjectAwaitingReconfirm()&&this.getCurrentUser().catch(()=>{}),i.length===0)return;const o=this.encodableOrSettleTerminal(i);if(o.length===0)return;if(o.length===1){await this.replaySequential(o,e),this.scheduleRateLimitedRetry(e);return}const c=[];for(let h=0;h<o.length;h+=N){const d=o.slice(h,h+N),u=await this.replayBatched(d,e);if(c.push(...u.requeue),u.stop){c.push(...o.slice(h+N));break}}c.length>0&&this.offlineQueue.requeue(c),this.scheduleRateLimitedRetry(e)}noteReplayRetryDelay(e,t){const s=l(e),r=this.replayRetryState.get(s),i=(r?.attempts??0)+1,n=Oe(t,i);this.replayRetryState.set(s,{attempts:i,delayMs:n===void 0?r?.delayMs:Math.max(r?.delayMs??0,n)})}scheduleRateLimitedRetry(e){const t=l(e),s=this.replayRetryState.get(t),r=s?.delayMs;if(s===void 0||r===void 0||this.closed||this.offlineQueue.size===0){this.replayRetryState.delete(t);return}s.delayMs=void 0;const i=this.replayRetryTimers.get(t);i!==void 0&&clearTimeout(i),this.replayRetryTimers.set(t,setTimeout(()=>{this.replayRetryTimers.delete(t),this.flushOfflineQueue(e).catch(()=>{})},r))}encodableOrSettleTerminal(e){const t=[];for(const s of e)try{g(s.args,`args for '${s.functionPath}'`),t.push(s)}catch(r){this.settleReplayTerminal(s,r instanceof Error?r:new Error(String(r)))}return t}replayGateVerdict(e){const t=this.stampOf(e);if(t===void 0)return this.queuedIdentities.delete(e.id??""),"send";const s=this.replayIdentityVerdict(t);if(s==="unknown")return"hold";if(this.queuedIdentities.delete(e.id??""),s==="match")return"send";this.unpersist(e.id);const r=new Error("offline mutation skipped: auth identity changed before replay");return r.code="OFFLINE_IDENTITY_CHANGED",e.reject(r),this.emitItemSettled(e,"rejected",r),"reject"}settleReplaySuccess(e,t,s){this.unpersist(e.id),this.recordShardCursor(e.shardKey,s),e.onCommit?.(s),e.resolve(t),this.emitItemSettled(e,"committed")}cursorKeyFor(e){return e??this.defaultShardKey??""}learnDefaultShardKey(e,t){const s=e.headers.get("x-lunora-shard-key");if(s===null||t!==void 0||this.defaultShardKey===s)return;this.defaultShardKey=s;const r=this.shardCursors.get("");r!==void 0&&(this.shardCursors.set(s,Math.max(this.shardCursors.get(s)??0,r)),this.shardCursors.delete(""))}recordShardCursor(e,t){if(typeof t!="number")return;const s=this.cursorKeyFor(e);this.shardCursors.set(s,Math.max(this.shardCursors.get(s)??0,t))}settleReplayTerminal(e,t){this.unpersist(e.id),e.reject(t),this.emitItemSettled(e,"rejected",t)}async replaySequential(e,t){for(let s=0;s<e.length;s+=1){const r=e[s];if(r)try{let i;const n=await this.rpc(r.functionPath,r.args,r.shardKey,{captureBookmark:!0,clientId:r.clientId??this.clientId,mutationId:r.id,onCommitCursor:o=>{i=o}});this.settleReplaySuccess(r,n,i)}catch(i){if(!Ce(i)){this.settleReplayTerminal(r,i);continue}this.noteReplayRetryDelay(t,i),this.offlineQueue.requeue(e.slice(s));return}}}async replayBatched(e,t){if(!this.fetchImpl)return{requeue:e,stop:!0};const s=JSON.stringify({calls:e.map((c,h)=>({args:g(c.args,`args for '${c.functionPath}'`),functionPath:c.functionPath,id:h,clientId:c.clientId??this.clientId,mutationId:c.id,shardKey:c.shardKey}))});if(e.length>1&&Pe(s)>Re)return await this.replayBatchedHalves(e,t);let r;try{r=await this.fetchImpl(C(this.url,z),{body:s,headers:this.rpcRequestHeaders({attachBookmark:!0}),method:"POST"})}catch{return{requeue:e,stop:!0}}const i=r.headers.get("x-d1-bookmark");if(i&&this.bookmark.set(i),r.status===413&&e.length>1)return await this.replayBatchedHalves(e,t);let n;const o=r.headers.get("retry-after");try{n=await r.json()}catch{return this.settleWholeBatchError(e,M(r.status,r.statusText,o),t)}if(!n.results){const c=n.error===void 0?M(r.status,r.statusText,o):Z(n.error,o);return this.settleWholeBatchError(e,c,t)}return{requeue:this.settleReplayBatchSlots(e,n.results,t),stop:!1}}settleWholeBatchError(e,t,s){if(t instanceof I||t.code!==void 0&&F.has(t.code))return this.noteReplayRetryDelay(s,t),{requeue:e,stop:!0};for(const r of e)this.settleReplayTerminal(r,t);return{requeue:[],stop:!1}}async replayBatchedHalves(e,t){const s=Math.ceil(e.length/2),r=await this.replayBatched(e.slice(0,s),t);if(r.stop)return{requeue:[...r.requeue,...e.slice(s)],stop:!0};const i=await this.replayBatched(e.slice(s),t);return{requeue:[...r.requeue,...i.requeue],stop:i.stop}}settleReplayBatchSlots(e,t,s){const r=new Map;for(const n of t)typeof n.id=="number"&&n.body!==void 0&&r.set(n.id,n.body);const i=[];for(const[n,o]of e.entries()){const c=r.get(n);c===void 0?i.push(o):"error"in c?F.has(c.error.code)?(this.noteReplayRetryDelay(s,A(c.error)),i.push(o)):this.settleReplayTerminal(o,A(c.error)):this.settleReplaySuccess(o,T(c.result),c.commitCursor)}return i}}export{ie as LunoraClient};
|