@spooky-sync/core 0.0.1-canary.160 → 0.0.1-canary.162

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/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { A as StorageHealthStatus, B as DatabaseEventSystem, C as RecordVersionDiff, D as Sp00kyQueryResult, E as Sp00kyConfig, F as TimingPhase, G as EventSystem, H as Logger$1, I as UpdateOptions, L as UpEvent, M as SyncHealth, N as SyncHealthConfig, O as Sp00kyQueryResultPromise, P as SyncHealthStatus, R as LocalStore, S as RecordVersionArray, T as RunOptions, U as SyncEventSystem, V as DatabaseEventTypes, W as EventDefinition, _ as QueryStatus, a as MutationCallback, b as QueryTimings, c as PersistenceClient, d as PreloadOptions, f as PreloadRefresh, g as QueryState, h as QueryHash, i as MATERIALIZATION_SAMPLE_WINDOW, j as StoreType, k as StorageHealth, l as PhaseStat, m as QueryConfigRecord, n as EventSubscriptionOptions, o as MutationEvent, p as QueryConfig, r as Level, s as MutationEventType, t as DebounceOptions, u as PinoTransmit, v as QueryStatusCallback, w as RegistrationTimings, x as QueryUpdateCallback, y as QueryTimeToLive, z as SealedQuery } from "./types.js";
1
+ import { A as Sp00kyQueryResultPromise, B as LocalStore, C as ReconnectConfig, D as RunOptions, E as RegistrationTimings, F as SyncHealthConfig, G as SyncEventSystem, H as DatabaseEventSystem, I as SyncHealthStatus, K as EventDefinition, L as TimingPhase, M as StorageHealthStatus, N as StoreType, O as Sp00kyConfig, P as SyncHealth, R as UpdateOptions, S as QueryUpdateCallback, T as RecordVersionDiff, U as DatabaseEventTypes, V as SealedQuery, W as Logger$1, _ as QueryState, a as MATERIALIZATION_SAMPLE_WINDOW, b as QueryTimeToLive, c as MutationEventType, d as PinoTransmit, f as PreloadOptions, g as QueryHash, h as QueryConfigRecord, i as Level, j as StorageHealth, k as Sp00kyQueryResult, l as PersistenceClient, m as QueryConfig, n as DebounceOptions, o as MutationCallback, p as PreloadRefresh, q as EventSystem, r as EventSubscriptionOptions, s as MutationEvent, t as ConnectionState, u as PhaseStat, v as QueryStatus, w as RecordVersionArray, x as QueryTimings, y as QueryStatusCallback, z as UpEvent } from "./types.js";
2
2
  import * as surrealdb0 from "surrealdb";
3
- import { Duration, RecordId, Surreal as Surreal$1, SurrealTransaction } from "surrealdb";
3
+ import { Duration, RecordId, Surreal as Surreal$1, SurrealEvents, SurrealTransaction } from "surrealdb";
4
4
  import { AccessDefinition, BackendNames, BackendRoutes, BucketNames, ColumnSchema, FinalQuery, GetTable, QueryBuilder, QueryOptions, QueryPlan, RoutePayload, SchemaStructure, TableModel, TableNames, TypeNameToTypeMap } from "@spooky-sync/query-builder";
5
5
  import { Logger } from "pino";
6
6
  import { LoroDoc } from "loro-crdt";
@@ -10,6 +10,13 @@ declare abstract class AbstractDatabaseService {
10
10
  protected client: Surreal$1;
11
11
  protected logger: Logger$1;
12
12
  protected events: DatabaseEventSystem;
13
+ /**
14
+ * Per-query deadline in ms; `0` disables. Only the remote service sets this
15
+ * (see `RemoteDatabaseService`) — a local query can be legitimately slow and
16
+ * has its own retry ladders, and there is no half-open-socket failure mode
17
+ * for an in-process engine.
18
+ */
19
+ protected queryTimeoutMs: number;
13
20
  protected abstract eventType: typeof DatabaseEventTypes.LocalQuery | typeof DatabaseEventTypes.RemoteQuery;
14
21
  constructor(client: Surreal$1, logger: Logger$1, events: DatabaseEventSystem);
15
22
  abstract connect(): Promise<void>;
@@ -19,6 +26,11 @@ declare abstract class AbstractDatabaseService {
19
26
  private queryQueue;
20
27
  /**
21
28
  * Execute a query with serialized execution to prevent WASM transaction issues.
29
+ *
30
+ * Serialization means every query waits on the previous one, so a call that
31
+ * never settles blocks the whole chain forever. {@link queryTimeoutMs} bounds
32
+ * each link: on expiry this promise rejects and the chain moves on, even
33
+ * though the underlying RPC is still parked in the SDK's pending map.
22
34
  */
23
35
  query<T extends unknown[]>(query: string, vars?: Record<string, unknown>): Promise<T>;
24
36
  execute<T>(query: SealedQuery<T>, vars?: Record<string, unknown>): Promise<T>;
@@ -26,18 +38,144 @@ declare abstract class AbstractDatabaseService {
26
38
  }
27
39
  //#endregion
28
40
  //#region src/services/database/remote.d.ts
41
+ /** Transport events the SDK publishes, mapped 1:1 to {@link ConnectionState}. */
42
+ type RemoteConnectionEvent = ConnectionState | 'error';
29
43
  declare class RemoteDatabaseService extends AbstractDatabaseService {
30
44
  private config;
31
45
  protected eventType: "DATABASE_REMOTE_QUERY";
46
+ private readonly reconnectConfig;
47
+ /**
48
+ * In-flight `connect()`, so concurrent callers (boot + supervisor revive +
49
+ * an `online` event landing at the same moment) share one attempt instead of
50
+ * racing two sockets. Cleared on settle, so a later call always reconnects.
51
+ */
52
+ private connecting;
32
53
  constructor(config: Sp00kyConfig<any>['database'], logger: Logger$1);
33
54
  getConfig(): Sp00kyConfig<any>['database'];
55
+ /** Resolved reconnect tunables; the supervisor reads its own knobs here. */
56
+ getReconnectConfig(): Required<ReconnectConfig>;
57
+ /** Current transport state as reported by the SDK. */
58
+ getStatus(): ConnectionState;
59
+ /**
60
+ * Observe transport events. Thin passthrough so callers (the supervisor,
61
+ * sync, CRDT) don't have to reach through `getClient()`.
62
+ */
63
+ subscribeConnection<K extends RemoteConnectionEvent>(event: K, cb: (...payload: SurrealEvents[K]) => void): () => void;
64
+ /**
65
+ * Tear the socket down on purpose. Used by the heartbeat watchdog when a
66
+ * socket stops answering but never closes: `close()` makes the SDK publish
67
+ * `disconnected`, which is what drives the supervisor's revive loop.
68
+ */
69
+ forceClose(): Promise<void>;
70
+ /**
71
+ * Open (or re-open) the remote connection.
72
+ *
73
+ * Safe to call repeatedly: concurrent calls share the in-flight attempt, and
74
+ * a call after a `disconnected` builds a fresh socket. `use()` and
75
+ * `authenticate()` are re-applied here for the cold path; the SDK also
76
+ * replays them itself on its own internal reconnects.
77
+ */
34
78
  connect(): Promise<void>;
79
+ private doConnect;
35
80
  signin(params: any): Promise<any>;
36
81
  signup(params: any): Promise<any>;
37
82
  authenticate(token: string): Promise<any>;
38
83
  invalidate(): Promise<void>;
39
84
  }
40
85
  //#endregion
86
+ //#region src/services/database/connection-supervisor.d.ts
87
+ /**
88
+ * Keeps the remote WebSocket alive for the whole life of the page.
89
+ *
90
+ * The SurrealDB SDK reconnects on its own after a socket `close`, but that
91
+ * covers only one of three ways the connection dies:
92
+ *
93
+ * 1. **Socket closes, SDK recovers.** Handled entirely by the SDK. This
94
+ * supervisor only observes it (to report `reconnecting` upward).
95
+ * 2. **Socket closes, SDK gives up.** With `attempts: -1` this shouldn't happen
96
+ * from exhaustion — but the SDK also terminates the engine permanently when
97
+ * its post-reconnect handshake throws (it re-runs `version()`, `use()`,
98
+ * `authenticate()` on every reconnect and closes the engine on any error).
99
+ * One transient hiccup there would otherwise kill the page's connection for
100
+ * good. The revive loop re-opens from scratch.
101
+ * 3. **Socket never closes at all.** A half-open connection: the peer is gone
102
+ * (NAT timeout, wifi switch, laptop sleep) but no FIN ever arrives, so
103
+ * `readyState` stays OPEN and the SDK's own 30s ping — fire-and-forget, no
104
+ * response deadline — never notices. Nothing ever fires a `close` event, so
105
+ * nothing ever triggers a reconnect. The heartbeat detects this and forces
106
+ * the teardown that case 2's loop then repairs.
107
+ *
108
+ * Plus wake triggers: coming back `online` or un-hiding the tab probes
109
+ * immediately rather than waiting out a backoff that was scheduled while the
110
+ * network was known-down.
111
+ */
112
+ declare class ConnectionSupervisor {
113
+ private readonly remote;
114
+ private readonly logger;
115
+ private readonly config;
116
+ private state;
117
+ private subscribers;
118
+ private started;
119
+ private disposed;
120
+ private heartbeatTimer;
121
+ private heartbeatInFlight;
122
+ private reviveTimer;
123
+ private reviveAttempts;
124
+ private reviving;
125
+ /**
126
+ * Set while the browser reports itself offline. Retrying a socket against a
127
+ * down interface only burns backoff, so the loop parks until `online` fires.
128
+ */
129
+ private suspended;
130
+ private teardown;
131
+ private static readonly REVIVE_BASE_MS;
132
+ constructor(remote: RemoteDatabaseService, logger: Logger$1, config?: Required<ReconnectConfig>);
133
+ /** Latest observed transport state. */
134
+ get connection(): ConnectionState;
135
+ /**
136
+ * Observe transport state. Fires immediately with the current value and again
137
+ * on every change. Returns an unsubscribe.
138
+ */
139
+ subscribe(cb: (state: ConnectionState) => void): () => void;
140
+ /**
141
+ * Begin supervising. Call once, after the initial {@link
142
+ * RemoteDatabaseService.connect}. Idempotent.
143
+ */
144
+ start(): void;
145
+ /** Stop all timers and listeners. Safe to call more than once. */
146
+ dispose(): void;
147
+ private setState;
148
+ private clearReviveTimer;
149
+ /**
150
+ * Queue the next `connect()` attempt on exponential backoff, capped at
151
+ * `superviseRetryDelayMaxMs`. Never gives up — the page is expected to
152
+ * outlive any outage.
153
+ */
154
+ private scheduleRevive;
155
+ private revive;
156
+ private stopHeartbeat;
157
+ private startHeartbeat;
158
+ /**
159
+ * Probe the server end-to-end. Deliberately goes through
160
+ * `remote.query` — the same serialized queue every other remote call uses —
161
+ * so a queue wedged behind a stuck RPC also fails the heartbeat instead of
162
+ * being invisible to it.
163
+ */
164
+ private beat;
165
+ /**
166
+ * A restored network or an un-hidden tab is the strongest available hint that
167
+ * a reconnect will now succeed, so probe immediately instead of waiting out a
168
+ * backoff scheduled under worse conditions.
169
+ */
170
+ private installWakeTriggers;
171
+ /**
172
+ * Reset the backoff and act on whichever problem is present: reconnect if the
173
+ * socket is gone, otherwise probe it (it may be half-open — which is exactly
174
+ * what a sleep/wake cycle produces).
175
+ */
176
+ private wake;
177
+ }
178
+ //#endregion
41
179
  //#region src/modules/sync/queue/queue-down.d.ts
42
180
  type RegisterEvent = {
43
181
  type: 'register';
@@ -488,7 +626,55 @@ declare class DataModule<S extends SchemaStructure> {
488
626
  * await so a concurrently-firing timer can't process it twice.
489
627
  */
490
628
  flushPendingStreamUpdate(queryHash: string): Promise<void>;
629
+ /**
630
+ * Materialize a query's result rows from the local store.
631
+ *
632
+ * A query's rows are its MEMBERSHIP — the id-set the server put in
633
+ * `_00_list_ref` (`remoteArray`) — not "every local body that matches the
634
+ * WHERE". Those two disagree, and the disagreement was the bug: when a row
635
+ * leaves a query's window but still exists upstream, `handleRemovedRecords`
636
+ * keeps its local body and never re-fetches it, so a predicate re-scan finds
637
+ * that stale body still matching and keeps rendering the row. Selecting the
638
+ * id-set directly is also the only correct thing for a windowed query, where
639
+ * re-applying `START m` against the shared local store skips the window's own
640
+ * rows entirely (sparse windowing) and returns nothing.
641
+ *
642
+ * The rendered set is:
643
+ *
644
+ * (membership ∪ (pendingWrites ∩ localArray)) − pendingDeletes
645
+ *
646
+ * The middle term keeps optimistic writes visible without re-admitting stale
647
+ * rows. Every local write is fed to the SSP (`cache.saveBatch` →
648
+ * `ingestMany`), so `localArray` answers "does this row match the predicate
649
+ * per LOCAL truth". A pending write that moves a row into the window is in
650
+ * `localArray` and shows; one that moves a row out is absent and does not; a
651
+ * stale body the server dropped has no pending write at all, so it stays out.
652
+ * `pendingDeletes` covers the reverse lag — the server still lists a row whose
653
+ * DELETE is sitting in our outbox.
654
+ *
655
+ * Falls back to the predicate scan only when membership has never been
656
+ * established (a query first run on this device), so an offline first paint
657
+ * still shows something.
658
+ */
491
659
  private materializeRecords;
660
+ /**
661
+ * The materialization itself, without the DevTools timing wrapper. Split out so
662
+ * cold-start seeding can use it before a `QueryState` exists.
663
+ */
664
+ private materializeFromConfig;
665
+ /**
666
+ * The authoritative membership list to render from, or `null` when membership
667
+ * has never been established and the caller must fall back to a scan.
668
+ *
669
+ * A windowed query has no usable fallback — re-running its `START m` locally
670
+ * returns the wrong rows — so it renders from whatever id-set is on hand
671
+ * (SSP's included) rather than degrading to a scan. That is the pre-existing
672
+ * behavior for windows and is preserved.
673
+ */
674
+ private resolveMembership;
675
+ /** Apply the pending-write union and pending-delete subtraction, and map to
676
+ * RecordIds for the engines' id-set path. */
677
+ private buildRenderIds;
492
678
  private processStreamUpdate;
493
679
  /**
494
680
  * Compute p55/p90/p99 from a rolling window of materialization samples.
@@ -585,6 +771,32 @@ declare class DataModule<S extends SchemaStructure> {
585
771
  } | null>;
586
772
  /** Stamp the preload freshness marker after a successful snapshot fetch. */
587
773
  writePreloadMarker(hash: string, rowCount: number): Promise<void>;
774
+ /**
775
+ * Read the durable membership row, or `null` if this query has never had
776
+ * authoritative membership on this device. Any read error is treated as
777
+ * "unknown" so a broken row degrades to the predicate scan rather than
778
+ * rendering an empty list.
779
+ */
780
+ getWindowMembership(key: string): Promise<RecordVersionArray | null>;
781
+ /** Persist the durable membership row. Best-effort: callers must not fail a
782
+ * sync round because the mirror write failed. */
783
+ writeWindowMembership(key: string, ids: RecordVersionArray): Promise<void>;
784
+ /**
785
+ * Record ids with a mutation still in the outbox, split by direction.
786
+ *
787
+ * Both halves feed {@link materializeRecords}: `writes` keeps optimistic
788
+ * creates/updates visible before the server has acknowledged them, and
789
+ * `deletes` suppresses rows the server still lists because our DELETE hasn't
790
+ * been processed yet. Reading `_00_pending_mutations` (rather than tracking
791
+ * ids in memory) is what makes both survive a reload.
792
+ *
793
+ * On failure returns empty sets: membership alone then decides, which can
794
+ * briefly hide an optimistic write but never resurrects a deleted row.
795
+ */
796
+ getPendingRecordIds(): Promise<{
797
+ writes: Set<string>;
798
+ deletes: Set<string>;
799
+ }>;
588
800
  /** True while ≥1 live subscriber is watching this query (refcount guard). */
589
801
  hasSubscribers(hash: string): boolean;
590
802
  /**
@@ -679,6 +891,18 @@ declare class DataModule<S extends SchemaStructure> {
679
891
  private createAndRegisterQuery;
680
892
  private createNewQuery;
681
893
  private calculateHash;
894
+ /**
895
+ * Session-independent counterpart of {@link calculateHash}: the key for a
896
+ * query's durable `_00_window` membership row.
897
+ *
898
+ * Deliberately the SAME inputs minus the `session::id()` salt, so the two keys
899
+ * can never drift apart. The salt is right for `_00_query` (two tabs must not
900
+ * fight over one row) and wrong for membership, which has to be recognizable
901
+ * after a reload — a reload mints a new session id, and offline the salt is
902
+ * `''`, so a salted key can never match what the previous session wrote.
903
+ */
904
+ private calculateMembershipKey;
905
+ private sha256;
682
906
  private startTTLHeartbeat;
683
907
  private replaceRecordInQueries;
684
908
  }
@@ -808,6 +1032,13 @@ interface Sp00kySyncOptions {
808
1032
  * up-queue for the session. Defaults to 30000; `0` disables the timeout.
809
1033
  */
810
1034
  pushTimeoutMs?: number;
1035
+ /**
1036
+ * Transport supervisor. Sync reads its state to report `connection` in
1037
+ * {@link SyncHealth} so a UI can show "reconnecting…" the instant the socket
1038
+ * drops, without waiting for the degrade threshold. Optional: omitted in
1039
+ * tests, where `connection` then reports `connected`.
1040
+ */
1041
+ connectionSupervisor?: ConnectionSupervisor;
811
1042
  }
812
1043
  /**
813
1044
  * The main synchronization engine for Sp00ky.
@@ -831,7 +1062,12 @@ declare class Sp00kySync<S extends SchemaStructure> {
831
1062
  * `SYNC_QUERY_UPDATED` and `SYNC_MUTATION_ROLLED_BACK`. */
832
1063
  get engineEvents(): SyncEventSystem;
833
1064
  private scheduler;
834
- private wasDisconnected;
1065
+ /**
1066
+ * Set by any event that means the socket we registered on is gone, so the
1067
+ * next `connected` knows it must re-subscribe rather than treat itself as the
1068
+ * initial connect. See {@link subscribeToReconnect}.
1069
+ */
1070
+ private needsResubscribe;
835
1071
  events: SyncEventSystem;
836
1072
  private currentUserId;
837
1073
  private tabRole;
@@ -866,6 +1102,17 @@ declare class Sp00kySync<S extends SchemaStructure> {
866
1102
  private selfHealAttempts;
867
1103
  private static readonly SELF_HEAL_BASE_MS;
868
1104
  private static readonly SELF_HEAL_MAX_MS;
1105
+ /**
1106
+ * Transport supervisor, when one was supplied. Sync only reads state from it;
1107
+ * it never drives reconnects itself.
1108
+ */
1109
+ private readonly connectionSupervisor?;
1110
+ /**
1111
+ * Mirror of the supervisor's state. Defaults to `connected` so a client
1112
+ * constructed without a supervisor (tests, embedders) reports the same health
1113
+ * shape it always has rather than a permanent false "disconnected".
1114
+ */
1115
+ private connectionState;
869
1116
  /** Current sync-health snapshot. */
870
1117
  get syncHealth(): SyncHealth;
871
1118
  /**
@@ -875,6 +1122,17 @@ declare class Sp00kySync<S extends SchemaStructure> {
875
1122
  */
876
1123
  subscribeToSyncHealth(cb: (health: SyncHealth) => void): () => void;
877
1124
  private emitSyncHealth;
1125
+ /**
1126
+ * Mirror the supervisor's transport state into {@link SyncHealth} and emit on
1127
+ * every change, so a UI can react to a dropped socket immediately instead of
1128
+ * waiting for `degradeAfterFailures` failed rounds. `status` is untouched:
1129
+ * a brief reconnect is not a degradation.
1130
+ *
1131
+ * No explicit unsubscribe: the supervisor is owned by the same client and
1132
+ * drops all subscribers in its own `dispose()`, which `Sp00kyClient.close()`
1133
+ * calls first.
1134
+ */
1135
+ private subscribeToConnectionState;
878
1136
  /**
879
1137
  * Fed by the scheduler once per drained sync round. Individual failures are
880
1138
  * absorbed by the queue's retry; only a run of `degradeAfterFailures`
@@ -999,6 +1257,16 @@ declare class Sp00kySync<S extends SchemaStructure> {
999
1257
  listRefTable(): string;
1000
1258
  private killRefLiveQuery;
1001
1259
  private restartRefLiveQuery;
1260
+ /**
1261
+ * Drop local LIVE bookkeeping without issuing a `KILL`.
1262
+ *
1263
+ * Called when the socket dies. The server-side subscription is scoped to that
1264
+ * WebSocket session and died with it, so there is nothing left to kill — and
1265
+ * by the time the reconnect handler runs, the client reports `connected`
1266
+ * again, which would otherwise send a `KILL` for a stale uuid on the *new*
1267
+ * session and hold up the restart queued behind it.
1268
+ */
1269
+ private invalidateRefLiveQuery;
1002
1270
  private subscribeToReconnect;
1003
1271
  private startRefLiveQueries;
1004
1272
  private handleRemoteListRefChange;
@@ -1247,9 +1515,30 @@ declare class CrdtManager {
1247
1515
  private fields;
1248
1516
  private liveByTable;
1249
1517
  private pendingLive;
1518
+ private staleTables;
1519
+ private connectionGeneration;
1520
+ private connectionUnsubscribes;
1250
1521
  private logger;
1251
1522
  private sessionId;
1252
1523
  constructor(schema: SchemaStructure, local: LocalStore, remote: RemoteDatabaseService, logger: Logger$1, debounceMs?: number);
1524
+ /**
1525
+ * Re-establish table LIVEs after a socket drop.
1526
+ *
1527
+ * A LIVE subscription lives and dies with its WebSocket session, and
1528
+ * `ensureTableSubscription` is memoized on `liveByTable` — so without this,
1529
+ * the first reconnect leaves CRDT realtime permanently dead: the map still
1530
+ * holds a uuid for a subscription the server has forgotten, so every later
1531
+ * `open()` short-circuits and no LIVE is ever re-issued.
1532
+ *
1533
+ * Both drop events matter: the SDK publishes `reconnecting` (not
1534
+ * `disconnected`) when it intends to recover on its own, and `disconnected`
1535
+ * only once it has given up.
1536
+ */
1537
+ private subscribeToReconnect;
1538
+ /** Stop observing transport events. Separate from {@link closeAll}, which also
1539
+ * runs on a bucket switch where the manager keeps being used. */
1540
+ dispose(): void;
1541
+ private hasOpenFieldFor;
1253
1542
  /** Set the session id that scopes this client's cursor entries. Must be
1254
1543
  * called before `open()` for cursors to be pushed under a stable key.
1255
1544
  * Passed in from `sp00ky.ts` at boot (it already fetches `session::id()`
@@ -1441,6 +1730,7 @@ declare class Sp00kyClient<S extends SchemaStructure> {
1441
1730
  private config;
1442
1731
  private local;
1443
1732
  private remote;
1733
+ private connectionSupervisor;
1444
1734
  private persistenceClient;
1445
1735
  private migrator;
1446
1736
  private cache;
@@ -1650,4 +1940,4 @@ declare function textToHtml(text: string): string;
1650
1940
  */
1651
1941
 
1652
1942
  //#endregion
1653
- export { AppReleaseHandle, AppReleaseModule, type AppReleaseOptions, type AppReleaseSnapshot, AuthEventSystem, AuthEventTypeMap, AuthEventTypes, AuthService, BucketHandle, CURSOR_COLORS, CrdtField, CrdtManager, DebounceOptions, EventSubscriptionOptions, FeatureFlagHandle, FeatureFlagModule, type FeatureFlagOptions, type FeatureFlagSnapshot, Level, MATERIALIZATION_SAMPLE_WINDOW, MutationCallback, MutationEvent, MutationEventType, PersistenceClient, PhaseStat, PinoTransmit, PreloadOptions, PreloadRefresh, QueryConfig, QueryConfigRecord, QueryHash, QueryState, QueryStatus, QueryStatusCallback, QueryTimeToLive, QueryTimings, QueryUpdateCallback, RecordVersionArray, RecordVersionDiff, RegistrationTimings, RunOptions, Sp00kyClient, Sp00kyConfig, Sp00kyQueryResult, Sp00kyQueryResultPromise, StorageHealth, StorageHealthStatus, StoreType, SyncHealth, SyncHealthConfig, SyncHealthStatus, TimingPhase, UpdateOptions, createAuthEventSystem, cursorColorFromName, fileToUint8Array, semverGt, textToHtml };
1943
+ export { AppReleaseHandle, AppReleaseModule, type AppReleaseOptions, type AppReleaseSnapshot, AuthEventSystem, AuthEventTypeMap, AuthEventTypes, AuthService, BucketHandle, CURSOR_COLORS, ConnectionState, CrdtField, CrdtManager, DebounceOptions, EventSubscriptionOptions, FeatureFlagHandle, FeatureFlagModule, type FeatureFlagOptions, type FeatureFlagSnapshot, Level, MATERIALIZATION_SAMPLE_WINDOW, MutationCallback, MutationEvent, MutationEventType, PersistenceClient, PhaseStat, PinoTransmit, PreloadOptions, PreloadRefresh, QueryConfig, QueryConfigRecord, QueryHash, QueryState, QueryStatus, QueryStatusCallback, QueryTimeToLive, QueryTimings, QueryUpdateCallback, ReconnectConfig, RecordVersionArray, RecordVersionDiff, RegistrationTimings, RunOptions, Sp00kyClient, Sp00kyConfig, Sp00kyQueryResult, Sp00kyQueryResultPromise, StorageHealth, StorageHealthStatus, StoreType, SyncHealth, SyncHealthConfig, SyncHealthStatus, TimingPhase, UpdateOptions, createAuthEventSystem, cursorColorFromName, fileToUint8Array, semverGt, textToHtml };