@lunora/svelte 0.0.0 → 1.0.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,374 @@
1
+ import { LunoraClient, User, ConnectionStatus, Preloaded, FunctionReference, ReturnOf, ArgsOf, MutationCallOptions, SubscriptionErrorCallback } from '@lunora/client';
2
+ export type { ArgsOf, ConnectionStatus, FunctionReference, LunoraClient, MutationCallOptions, Preloaded, ReturnOf } from '@lunora/client';
3
+ import { Readable } from 'svelte/store';
4
+ import { PaginationStatus } from '@lunora/client/pagination';
5
+ import { RateLimitStatus, RateLimitConfig } from '@lunora/ratelimit';
6
+ /**
7
+ * Publish a {@link LunoraClient} on the Svelte component context so that
8
+ * descendant components can read it with {@link getLunoraClient} (or implicitly,
9
+ * via the default-client lookups inside `query`/`mutation`/`hydratePreloaded`).
10
+ *
11
+ * Call this once, high in the tree (typically your root `+layout.svelte` or
12
+ * `App.svelte`), during component initialisation — `setContext` must run while
13
+ * the component is being constructed, exactly like React's provider mounts once.
14
+ * This is the Svelte analogue of mounting `LunoraProvider`.
15
+ */
16
+ declare const setLunoraClient: (client: LunoraClient) => LunoraClient;
17
+ /**
18
+ * Read the {@link LunoraClient} published by {@link setLunoraClient} from the
19
+ * nearest ancestor. Throws if no provider is mounted, mirroring `useLunora`'s
20
+ * "must be used inside a LunoraProvider" guard so the failure is loud and
21
+ * early rather than a confusing `undefined` deref later.
22
+ *
23
+ * Must be called during component initialisation (Svelte's `getContext`
24
+ * constraint); the live stores returned by `query`/`hydratePreloaded` resolve
25
+ * the client eagerly at call time for exactly this reason.
26
+ */
27
+ declare const getLunoraClient: () => LunoraClient;
28
+ interface AuthStore {
29
+ /** Set the auth token on the underlying `LunoraClient`. */
30
+ setToken: (token: string | null) => void;
31
+ /** Readable store of the auth token (`null` when signed out). */
32
+ token: Readable<string | null>;
33
+ /** Readable store of the resolved user (`null` when signed out or still loading). */
34
+ user: Readable<User | null>;
35
+ }
36
+ /**
37
+ * Create a pair of Svelte readable stores tracking the auth token and the
38
+ * resolved user identity. The stores are lazy: subscriptions open on the first
39
+ * reader and close when the last unsubscribes. Calling `setToken(jwt)` after
40
+ * sign-in refreshes both stores.
41
+ *
42
+ * Pass an explicit client to bypass the ambient context (useful in tests).
43
+ */
44
+ declare const auth: (explicitClient?: ReturnType<typeof getLunoraClient>) => AuthStore;
45
+ /** The shape held by a {@link connectionStatus} store: the latest aggregate live-socket status. */
46
+ type ConnectionStatusStore = Readable<ConnectionStatus>;
47
+ /**
48
+ * Expose the client's aggregate live-socket status as a Svelte readable store.
49
+ * Read it with the `$store` idiom (`{$status}`) and it stays current: the value
50
+ * transitions through `idle` → `connecting` → `connected` → `offline` as
51
+ * sockets open and drop — the Svelte equivalent of `@lunora/react`'s
52
+ * `useConnectionStatus`. Use it to drive a connection indicator.
53
+ *
54
+ * The status listener attaches inside `readable`'s start callback (on the first
55
+ * `$`-read / `.subscribe()`) and is released by the returned stop function when
56
+ * the last subscriber goes away, so a store that's never read attaches nothing.
57
+ *
58
+ * Pass `client` explicitly, or omit it to resolve the ambient client published
59
+ * by `setLunoraClient` (which must therefore be called during component init,
60
+ * before this runs).
61
+ */
62
+ declare const connectionStatus: (client?: LunoraClient) => ConnectionStatusStore;
63
+ /** A targeting context merged on top of the app's default (`defineFlags({ identify })`). */
64
+ type FlagContext = Record<string, unknown>;
65
+ /** The value kinds a flag resolves to — OpenFeature's boolean / number / string / structured (JSON) flags. */
66
+ type FlagValue = boolean | number | string | {
67
+ [key: string]: unknown;
68
+ } | unknown[] | null;
69
+ /**
70
+ * Open a single feature flag as a Svelte readable store, live over Lunora's
71
+ * WebSocket. Read it with the `$store` idiom (`{$darkMode}`).
72
+ *
73
+ * The store holds `defaultValue` until the first evaluation lands, then the
74
+ * server's resolved value — re-emitted whenever the provider re-evaluates (e.g. a
75
+ * flag is toggled in Cloudflare Flagship). The flag's kind is inferred from
76
+ * `defaultValue`'s runtime type, so `flag("dark", false)` reads a boolean and
77
+ * `flag("hero", "control")` a string. `context` supplies a per-call targeting
78
+ * context merged on top of the app's default `identify` targeting key.
79
+ *
80
+ * The subscription opens lazily on the first `$`-read and tears down when the
81
+ * last subscriber detaches. Pass `client` explicitly, or omit it to resolve the
82
+ * ambient client published by `setLunoraClient`. Evaluation never throws — a
83
+ * provider error resolves the default (the same fail-open contract as `ctx.flags`).
84
+ */
85
+ declare function flag<T extends FlagValue>(key: string, defaultValue: T, context?: FlagContext): Readable<T>;
86
+ declare function flag<T extends FlagValue>(client: LunoraClient, key: string, defaultValue: T, context?: FlagContext): Readable<T>;
87
+ /**
88
+ * Open several feature flags at once as a single Svelte readable store of the
89
+ * resolved record, live over Lunora's WebSocket.
90
+ *
91
+ * Pass a record of `key → defaultValue`; each flag's kind is inferred from its
92
+ * default, and the store holds the same-shaped record with resolved values (the
93
+ * defaults until each evaluation lands). A single `context` applies to every
94
+ * flag. This is the batched form of {@link flag} — one store, one subscription
95
+ * per key, torn down together when the last subscriber detaches.
96
+ *
97
+ * Pass `client` explicitly, or omit it to resolve the ambient client published
98
+ * by `setLunoraClient`.
99
+ */
100
+ declare function flags<T extends Record<string, FlagValue>>(flagDefaults: T, context?: FlagContext): Readable<T>;
101
+ declare function flags<T extends Record<string, FlagValue>>(client: LunoraClient, flagDefaults: T, context?: FlagContext): Readable<T>;
102
+ /**
103
+ * Hydrate a query store from a {@link Preloaded} token produced by
104
+ * `preloadQuery` during SSR, then keep it live — the reactive-loader handoff.
105
+ *
106
+ * The store is seeded **synchronously** with `preloaded.value`, so the very
107
+ * first read (`$store` during hydration) returns the server value with no
108
+ * loading flash and no hydration mismatch — there is no `undefined` window and
109
+ * no refetch. When the store gains its first subscriber on the client, a live
110
+ * WS subscription attaches and every subsequent delta re-emits, exactly like a
111
+ * plain `query` store. This is the Svelte equivalent of React's
112
+ * `usePreloadedQuery`.
113
+ *
114
+ * Pass `client` explicitly, or omit it to resolve the ambient client published
115
+ * by `setLunoraClient`.
116
+ *
117
+ * Note on SSR: `readable`'s start callback only runs when the store is actually
118
+ * subscribed (the browser), so on the server the store simply holds the seeded
119
+ * value and opens no socket. The token's `value` is the single source of truth
120
+ * for the first paint either way.
121
+ */
122
+ declare const hydratePreloaded: <T>(preloaded: Preloaded<T>, client?: LunoraClient) => Readable<T>;
123
+ /**
124
+ * The reactive handle returned by {@link mutation} — the Svelte counterpart to
125
+ * React's `useMutation`, re-expressed as stores you read with `$`. The surface
126
+ * is identical across the Lunora adapters (`@lunora/solid`, `/vue`):
127
+ * `data`/`error`/`pending` are readable stores and `mutate` is an awaitable.
128
+ */
129
+ interface MutationHandle<F extends FunctionReference> {
130
+ /** The latest invocation's resolved value, or `undefined` before the first success. */
131
+ data: Readable<ReturnOf<F> | undefined>;
132
+ /** The latest invocation's error, or `undefined`. */
133
+ error: Readable<Error | undefined>;
134
+ /**
135
+ * Run the mutation. Resolves with the server result and rejects on failure
136
+ * (errors propagate — there is no swallowing). Optimistic updates passed in
137
+ * `options` are applied and rolled back by the client against the live query
138
+ * subscriptions, exactly as in the React adapter.
139
+ */
140
+ mutate: (args: ArgsOf<F>, options?: MutationCallOptions<unknown, unknown, ArgsOf<F>>) => Promise<ReturnOf<F>>;
141
+ /**
142
+ * `true` while any invocation from this handle is in flight. Ref-counted, so
143
+ * overlapping calls compose and it only flips back to `false` once the last
144
+ * one settles. Read it with `$pending` in a component to disable a button.
145
+ */
146
+ pending: Readable<boolean>;
147
+ /** Clear `data`/`error` back to idle. */
148
+ reset: () => void;
149
+ }
150
+ /**
151
+ * Create an optimistic {@link MutationHandle} for a mutation reference. The
152
+ * Svelte counterpart to React's `useMutation`: returns
153
+ * `{ data, error, pending, mutate, reset }` of readable stores plus an awaitable
154
+ * `mutate`. The ref-counted pending + error-normalize orchestration is the
155
+ * shared `createMutationRunner` from `@lunora/client`; only the stores are
156
+ * adapter-specific.
157
+ *
158
+ * Pass `client` explicitly, or omit it to resolve the ambient client published
159
+ * by `setLunoraClient`.
160
+ */
161
+ declare function mutation<F extends FunctionReference>(function_: F): MutationHandle<F>;
162
+ declare function mutation<F extends FunctionReference>(client: LunoraClient, function_: F): MutationHandle<F>;
163
+ /** The args a paginated query exposes minus the framework-supplied page cursor. */
164
+ type PaginatedArgs<F extends FunctionReference> = Omit<ArgsOf<F>, "paginationOpts">;
165
+ /** The element type of the `page` array a paginated query returns. */
166
+ type PageItemOf<F extends FunctionReference> = ReturnOf<F> extends {
167
+ page: (infer T)[];
168
+ } ? T : unknown;
169
+ interface PaginatedQueryOptions {
170
+ /** Page size for the first page (and the default for `loadMore`). */
171
+ initialNumItems: number;
172
+ shardKey?: string;
173
+ }
174
+ interface PaginatedQueryHandle<T> {
175
+ /** `true` while the first page or a `loadMore` page is in flight. */
176
+ isLoading: Readable<boolean>;
177
+ /** Request the next page. A no-op unless `status === "CanLoadMore"`. */
178
+ loadMore: (numberItems: number) => void;
179
+ /** Flattened items across every loaded page, in order. */
180
+ results: Readable<T[]>;
181
+ status: Readable<PaginationStatus>;
182
+ }
183
+ interface InfiniteQueryOptions {
184
+ /** Page size for the first page (and the default for `fetchNextPage`). */
185
+ initialNumItems: number;
186
+ shardKey?: string;
187
+ }
188
+ interface InfiniteQueryHandle<T> {
189
+ /** Request the next page. A no-op unless `status === "CanLoadMore"`. */
190
+ fetchNextPage: (numberItems?: number) => void;
191
+ /** `true` when the loaded tail reports it can load another page. */
192
+ hasNextPage: Readable<boolean>;
193
+ /** `true` while a `fetchNextPage` page (beyond the first) is in flight. */
194
+ isFetchingNextPage: Readable<boolean>;
195
+ /** `true` while the first page is in flight. */
196
+ isLoading: Readable<boolean>;
197
+ /** One inner array per loaded page, in order; unresolved pages are omitted. */
198
+ pages: Readable<T[][]>;
199
+ status: Readable<PaginationStatus>;
200
+ }
201
+ /**
202
+ * Open a live paginated query as Svelte stores. The first page opens when
203
+ * called; call `loadMore(n)` to append the next page. Results are flattened
204
+ * across all loaded pages.
205
+ *
206
+ * Pass `client` explicitly, or omit it to resolve the ambient client from the
207
+ * Svelte context.
208
+ */
209
+ declare function paginatedQuery<F extends FunctionReference>(function_: F, args: "skip" | PaginatedArgs<F>, options: PaginatedQueryOptions): PaginatedQueryHandle<PageItemOf<F>>;
210
+ declare function paginatedQuery<F extends FunctionReference>(client: LunoraClient, function_: F, args: "skip" | PaginatedArgs<F>, options: PaginatedQueryOptions): PaginatedQueryHandle<PageItemOf<F>>;
211
+ /**
212
+ * Open a live paginated query as Svelte stores, keeping each page as its own
213
+ * inner array (TanStack-Query-style `fetchNextPage` / `hasNextPage` shape).
214
+ *
215
+ * Pass `client` explicitly, or omit it to resolve the ambient client from the
216
+ * Svelte context.
217
+ */
218
+ declare function infiniteQuery<F extends FunctionReference>(function_: F, args: "skip" | PaginatedArgs<F>, options: InfiniteQueryOptions): InfiniteQueryHandle<PageItemOf<F>>;
219
+ declare function infiniteQuery<F extends FunctionReference>(client: LunoraClient, function_: F, args: "skip" | PaginatedArgs<F>, options: InfiniteQueryOptions): InfiniteQueryHandle<PageItemOf<F>>;
220
+ /**
221
+ * `presence` — collaborative-awareness stores, the client half of the
222
+ * `@lunora/server` `definePresence` preset.
223
+ *
224
+ * Drives the heartbeat mutation (on call, interval, and tab re-focus) and
225
+ * subscribes to the live `listPresent` query for the given room.
226
+ *
227
+ * Pass `client` explicitly, or omit it to resolve the ambient client from the
228
+ * Svelte context.
229
+ */
230
+ /**
231
+ * A heartbeat mutation reference: takes `{ roomId, sessionId, data? }`.
232
+ */
233
+ type HeartbeatReference = FunctionReference<"mutation", {
234
+ data?: Record<string, unknown>;
235
+ roomId: string;
236
+ sessionId: string;
237
+ }>;
238
+ /**
239
+ * A listPresent query reference: takes `{ roomId }` and returns the array of
240
+ * present members.
241
+ */
242
+ type ListPresentReference = FunctionReference<"query", {
243
+ roomId: string;
244
+ }>;
245
+ interface PresenceOptions<H extends HeartbeatReference, L extends ListPresentReference> {
246
+ /** Awareness blob for the first heartbeat (selection, cursor, name, color…). */
247
+ data?: Record<string, unknown>;
248
+ /** The `api.*` reference for the presence heartbeat mutation. */
249
+ heartbeat: H;
250
+ /** Heartbeat cadence in ms. Defaults to 10s. */
251
+ intervalMs?: number;
252
+ /** The `api.*` reference for the presence listPresent query. */
253
+ listPresent: L;
254
+ /**
255
+ * Stable id for this presence row. Defaults to a fresh per-mount id.
256
+ * Pass a user/connection id to control deduping across tabs.
257
+ */
258
+ sessionId?: string;
259
+ /** Forwarded to the heartbeat mutation / listPresent subscription when sharding by room. */
260
+ shardKey?: string;
261
+ }
262
+ interface PresenceHandle<L extends ListPresentReference> {
263
+ /** The present members for the room. `undefined` until the first push. */
264
+ present: Readable<ReturnOf<L> | undefined>;
265
+ /** This handle's session id. */
266
+ sessionId: string;
267
+ /** Replace the awareness `data` sent with subsequent heartbeats, and heartbeat immediately. */
268
+ setData: (data: Record<string, unknown> | undefined) => void;
269
+ /** Stop all heartbeats, remove the visibility listener, and unsubscribe. Call in `onDestroy`. */
270
+ teardown: () => void;
271
+ }
272
+ /**
273
+ * Open a live presence handle.
274
+ *
275
+ * Pass `client` explicitly, or omit it to resolve the ambient client from the
276
+ * Svelte context (requires calling inside a component's `&lt;script>` block or
277
+ * inside a function called during component initialisation).
278
+ *
279
+ * Call `teardown()` when the component is destroyed to stop heartbeats and
280
+ * remove the visibility listener (`onDestroy(handle.teardown)`).
281
+ */
282
+ declare function presence<H extends HeartbeatReference, L extends ListPresentReference>(roomId: string, options: PresenceOptions<H, L>): PresenceHandle<L>;
283
+ declare function presence<H extends HeartbeatReference, L extends ListPresentReference>(client: LunoraClient, roomId: string, options: PresenceOptions<H, L>): PresenceHandle<L>;
284
+ /** Options accepted by {@link query}. */
285
+ interface QueryStoreOptions {
286
+ /** Called when the underlying subscription reports an error. */
287
+ onError?: SubscriptionErrorCallback;
288
+ /** Route to a specific shard when the target function is `.shardBy(...)`-partitioned. */
289
+ shardKey?: string;
290
+ }
291
+ /**
292
+ * The shape held by a {@link query} store: the latest server value (`undefined`
293
+ * until the first response lands, mirroring React's `useQuery`).
294
+ */
295
+ type QueryStore<F extends FunctionReference> = Readable<ReturnOf<F> | undefined>;
296
+ /**
297
+ * Open a live query as a Svelte readable store. Read it with the `$store`
298
+ * idiom in a component (`{$messages}`) and it stays current: a WS subscription
299
+ * attaches the moment the store gains its first subscriber and the value
300
+ * re-emits on every server delta — the Svelte equivalent of React's `useQuery`.
301
+ *
302
+ * The subscription is opened lazily (inside `readable`'s start callback, on the
303
+ * first `$`-read / `.subscribe()`) and torn down by the returned stop function
304
+ * when the last subscriber goes away — so a store that's never read opens no
305
+ * socket, and a component that unmounts releases its subscription. Sharing one
306
+ * store across several components shares a single underlying subscription
307
+ * (the `LunoraClient` de-dupes by `(fn, args, shardKey)`).
308
+ *
309
+ * Pass `client` explicitly, or omit it to resolve the ambient client published
310
+ * by `setLunoraClient` (which must therefore be called during component init,
311
+ * before this runs).
312
+ */
313
+ declare function query<F extends FunctionReference>(function_: F, args: ArgsOf<F>, options?: QueryStoreOptions): QueryStore<F>;
314
+ declare function query<F extends FunctionReference>(client: LunoraClient, function_: F, args: ArgsOf<F>, options?: QueryStoreOptions): QueryStore<F>;
315
+ interface RateLimitOptions {
316
+ /** Clock injection for tests. Defaults to `Date.now`. */
317
+ now?: () => number;
318
+ /**
319
+ * Re-evaluation cadence in milliseconds while throttled, so `retryAfter`
320
+ * ticks down and `disabled` flips back automatically. Defaults to `1000`.
321
+ */
322
+ tickMs?: number;
323
+ }
324
+ interface RateLimitHandle {
325
+ /** Would consuming `count` (default 1) succeed right now? Does not consume. */
326
+ check: (count?: number) => boolean;
327
+ /** Optimistically consume `count` (default 1) locally; mirrors the server algorithm. */
328
+ consume: (count?: number) => RateLimitStatus;
329
+ /** Readable store: `true` while a single unit cannot be consumed. */
330
+ disabled: Readable<boolean>;
331
+ /** Readable store: `true` while a single unit can be consumed. */
332
+ ok: Readable<boolean>;
333
+ /** Clear local accounting (e.g. after the server confirms a reset). */
334
+ reset: () => void;
335
+ /** Readable store: milliseconds until the next unit is available. `0` when `ok`. */
336
+ retryAfter: Readable<number>;
337
+ /** Stop the auto-tick interval. Call from `onDestroy` to prevent leaks. */
338
+ teardown: () => void;
339
+ }
340
+ /**
341
+ * Client-side mirror of a rate limit for instant UX — disable a button or show
342
+ * a countdown without a round-trip. It runs the same token-bucket / fixed-window
343
+ * math as `@lunora/ratelimit` on the server, so the prediction agrees with the
344
+ * authoritative check; the server remains the source of truth.
345
+ *
346
+ * `config` is read on every call; pass a stable reference (module constant).
347
+ *
348
+ * Call `teardown()` when the component is destroyed to stop the auto-tick
349
+ * interval (`onDestroy(handle.teardown)`).
350
+ */
351
+ declare const rateLimit: (config: RateLimitConfig, options?: RateLimitOptions) => RateLimitHandle;
352
+ interface SubscriptionStoreOptions {
353
+ onError?: (error: Error) => void;
354
+ shardKey?: string;
355
+ }
356
+ interface SubscriptionHandle<T> {
357
+ /** Svelte readable store of the latest server-pushed value (`undefined` until the first push). */
358
+ data: Readable<T | undefined>;
359
+ /** Svelte readable store of the latest subscription error (`undefined` when healthy). */
360
+ error: Readable<Error | undefined>;
361
+ }
362
+ /**
363
+ * Create a pair of Svelte readable stores that open a live subscription
364
+ * against the Lunora backend. `data` updates on every server push; `error`
365
+ * captures the last subscription error. Both stores are lazy: the subscription
366
+ * opens on the first subscriber to `data` and tears down when it stops.
367
+ *
368
+ * Passing `"skip"` as `args` keeps the stores connected but the subscription
369
+ * dormant (`data` stays `undefined`). Pass an explicit `client` as the first
370
+ * argument to bypass the ambient context (useful in tests).
371
+ */
372
+ declare function subscription<F extends FunctionReference>(function_: F, args: ArgsOf<F> | "skip", options?: SubscriptionStoreOptions): SubscriptionHandle<ReturnOf<F>>;
373
+ declare function subscription<F extends FunctionReference>(client: LunoraClient, function_: F, args: ArgsOf<F> | "skip", options?: SubscriptionStoreOptions): SubscriptionHandle<ReturnOf<F>>;
374
+ export { type AuthStore, type ConnectionStatusStore, type FlagContext, type FlagValue, type HeartbeatReference, type InfiniteQueryHandle, type InfiniteQueryOptions, type ListPresentReference, type MutationHandle, type PageItemOf, type PaginatedArgs, type PaginatedQueryHandle, type PaginatedQueryOptions, type PresenceHandle, type PresenceOptions, type QueryStore, type QueryStoreOptions, type RateLimitHandle, type RateLimitOptions, type SubscriptionHandle, type SubscriptionStoreOptions, auth, connectionStatus, flag, flags, getLunoraClient, hydratePreloaded, infiniteQuery, mutation, paginatedQuery, presence, query, rateLimit, setLunoraClient, subscription };
package/dist/index.mjs ADDED
@@ -0,0 +1,11 @@
1
+ export { auth } from './packem_shared/auth-DLPf_bK9.mjs';
2
+ export { connectionStatus } from './packem_shared/connectionStatus-CRsOMeYl.mjs';
3
+ export { getLunoraClient, setLunoraClient } from './packem_shared/getLunoraClient--bwSz7F6.mjs';
4
+ export { flag, flags } from './packem_shared/flag-19nEeKPT.mjs';
5
+ export { hydratePreloaded } from './packem_shared/hydratePreloaded-D5rUJdXy.mjs';
6
+ export { mutation } from './packem_shared/mutation-CnDkAaLH.mjs';
7
+ export { infiniteQuery, paginatedQuery } from './packem_shared/infiniteQuery-jPMQw8Vz.mjs';
8
+ export { presence } from './packem_shared/presence-BQWixJ2T.mjs';
9
+ export { query } from './packem_shared/query-D8Pct9Qe.mjs';
10
+ export { rateLimit } from './packem_shared/rateLimit-Cdw1kp8t.mjs';
11
+ export { subscription } from './packem_shared/subscription-twuBT_Wb.mjs';
@@ -0,0 +1,28 @@
1
+ import { getIdentityStore } from '@lunora/client/auth';
2
+ import { readable } from 'svelte/store';
3
+ import { getLunoraClient } from './getLunoraClient--bwSz7F6.mjs';
4
+
5
+ const auth = (explicitClient) => {
6
+ const client = explicitClient ?? getLunoraClient();
7
+ const store = getIdentityStore(client);
8
+ const token = readable(client.getAuthToken(), (set) => {
9
+ set(client.getAuthToken());
10
+ const unsub = client.onAuthTokenChange((next) => {
11
+ set(next);
12
+ });
13
+ return unsub;
14
+ });
15
+ const user = readable(store.getUser(), (set) => {
16
+ set(store.getUser());
17
+ const unsub = store.subscribe(() => {
18
+ set(store.getUser());
19
+ });
20
+ return unsub;
21
+ });
22
+ const setToken = (next) => {
23
+ client.setAuthToken(next);
24
+ };
25
+ return { setToken, token, user };
26
+ };
27
+
28
+ export { auth };
@@ -0,0 +1,14 @@
1
+ import { readable } from 'svelte/store';
2
+ import { getLunoraClient } from './getLunoraClient--bwSz7F6.mjs';
3
+
4
+ const connectionStatus = (client) => {
5
+ const resolved = client ?? getLunoraClient();
6
+ return readable(resolved.connectionStatus(), (set) => {
7
+ set(resolved.connectionStatus());
8
+ return resolved.onConnectionStatus((next) => {
9
+ set(next);
10
+ });
11
+ });
12
+ };
13
+
14
+ export { connectionStatus };
@@ -0,0 +1,56 @@
1
+ import { readable } from 'svelte/store';
2
+ import { getLunoraClient } from './getLunoraClient--bwSz7F6.mjs';
3
+
4
+ const FLAGS_EVAL_PATH = "__lunora_flags__:eval";
5
+ const flagKind = (value) => {
6
+ const kind = typeof value;
7
+ if (kind === "boolean" || kind === "number" || kind === "string") {
8
+ return kind;
9
+ }
10
+ return "object";
11
+ };
12
+ const flagsReference = { __lunoraRef: FLAGS_EVAL_PATH };
13
+ const isClient = (value) => typeof value === "object" && value !== null && typeof value.subscribe === "function";
14
+ const subscribeFlag = (client, key, defaultValue, context, set) => {
15
+ try {
16
+ return client.subscribe(flagsReference, { context, default: defaultValue, key, type: flagKind(defaultValue) }, (next) => {
17
+ set(next);
18
+ });
19
+ } catch {
20
+ return () => {
21
+ };
22
+ }
23
+ };
24
+ function flag(clientOrKey, keyOrDefault, defaultOrContext, maybeContext) {
25
+ const hasExplicitClient = isClient(clientOrKey);
26
+ const client = hasExplicitClient ? clientOrKey : getLunoraClient();
27
+ const key = hasExplicitClient ? keyOrDefault : clientOrKey;
28
+ const defaultValue = hasExplicitClient ? defaultOrContext : keyOrDefault;
29
+ const context = (hasExplicitClient ? maybeContext : defaultOrContext) ?? void 0;
30
+ return readable(defaultValue, (set) => subscribeFlag(client, key, defaultValue, context, set));
31
+ }
32
+ function flags(clientOrFlags, flagsOrContext, maybeContext) {
33
+ const hasExplicitClient = isClient(clientOrFlags);
34
+ const client = hasExplicitClient ? clientOrFlags : getLunoraClient();
35
+ const flagDefaults = hasExplicitClient ? flagsOrContext : clientOrFlags;
36
+ const context = (hasExplicitClient ? maybeContext : flagsOrContext) ?? void 0;
37
+ return readable(flagDefaults, (set) => {
38
+ let current = { ...flagDefaults };
39
+ const unsubscribes = [];
40
+ for (const [key, defaultValue] of Object.entries(flagDefaults)) {
41
+ unsubscribes.push(
42
+ subscribeFlag(client, key, defaultValue, context, (next) => {
43
+ current = { ...current, [key]: next };
44
+ set(current);
45
+ })
46
+ );
47
+ }
48
+ return () => {
49
+ for (const unsubscribe of unsubscribes) {
50
+ unsubscribe();
51
+ }
52
+ };
53
+ });
54
+ }
55
+
56
+ export { flag, flags };
@@ -0,0 +1,16 @@
1
+ import { setContext, getContext } from 'svelte';
2
+
3
+ const LUNORA_CONTEXT_KEY = /* @__PURE__ */ Symbol("lunora.client");
4
+ const setLunoraClient = (client) => {
5
+ setContext(LUNORA_CONTEXT_KEY, client);
6
+ return client;
7
+ };
8
+ const getLunoraClient = () => {
9
+ const client = getContext(LUNORA_CONTEXT_KEY);
10
+ if (!client) {
11
+ throw new Error("getLunoraClient(): no LunoraClient in context — call setLunoraClient(client) in an ancestor component first.");
12
+ }
13
+ return client;
14
+ };
15
+
16
+ export { getLunoraClient, setLunoraClient };
@@ -0,0 +1,21 @@
1
+ import { readable } from 'svelte/store';
2
+ import { getLunoraClient } from './getLunoraClient--bwSz7F6.mjs';
3
+
4
+ const hydratePreloaded = (preloaded, client) => {
5
+ const resolvedClient = client ?? getLunoraClient();
6
+ const { args, functionPath, shardKey, value } = preloaded;
7
+ const functionRef = { __lunoraRef: functionPath };
8
+ return readable(
9
+ value,
10
+ (set) => resolvedClient.subscribe(
11
+ functionRef,
12
+ args,
13
+ (next) => {
14
+ set(next);
15
+ },
16
+ { shardKey }
17
+ )
18
+ );
19
+ };
20
+
21
+ export { hydratePreloaded };