@lunora/svelte 1.0.0-alpha.32 → 1.0.0-alpha.34
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.mts +11 -4
- package/dist/index.d.ts +11 -4
- package/dist/index.mjs +4 -4
- package/dist/packem_shared/{infiniteQuery-BFsBpXnS.mjs → infiniteQuery-DlnFVv-f.mjs} +31 -17
- package/dist/packem_shared/{presence-UJKjdcKg.mjs → presence-BvChXqiB.mjs} +22 -5
- package/dist/packem_shared/{query-BsJHHnAK.mjs → query-B-Gu6KQw.mjs} +7 -1
- package/dist/packem_shared/{subscription-C121AbM_.mjs → subscription-COqqiMPX.mjs} +0 -3
- package/package.json +5 -5
package/dist/index.d.mts
CHANGED
|
@@ -307,8 +307,11 @@ interface PresenceHandle<L extends ListPresentReference> {
|
|
|
307
307
|
* Svelte context (requires calling inside a component's `<script>` block or
|
|
308
308
|
* inside a function called during component initialisation).
|
|
309
309
|
*
|
|
310
|
-
*
|
|
311
|
-
*
|
|
310
|
+
* Teardown (stop heartbeats, remove the visibility listener, release the
|
|
311
|
+
* connection context) is wired automatically to the component's `onDestroy`
|
|
312
|
+
* when called during component initialisation. Outside a component call
|
|
313
|
+
* `handle.teardown()` yourself. `teardown()` is idempotent, so an explicit
|
|
314
|
+
* `onDestroy(handle.teardown)` on top of the auto-wiring is safe.
|
|
312
315
|
*/
|
|
313
316
|
declare function presence<H extends HeartbeatReference, L extends ListPresentReference>(roomId: string, options: PresenceOptions<H, L>): PresenceHandle<L>;
|
|
314
317
|
declare function presence<H extends HeartbeatReference, L extends ListPresentReference>(client: LunoraClient, roomId: string, options: PresenceOptions<H, L>): PresenceHandle<L>;
|
|
@@ -337,12 +340,16 @@ type QueryStore<F extends FunctionReference> = Readable<ReturnOf<F> | undefined>
|
|
|
337
340
|
* store across several components shares a single underlying subscription
|
|
338
341
|
* (the `LunoraClient` de-dupes by `(fn, args, shardKey)`).
|
|
339
342
|
*
|
|
343
|
+
* Pass `"skip"` as `args` to keep the store connected but the subscription
|
|
344
|
+
* dormant (the value stays `undefined`, no socket opens) — useful for a query
|
|
345
|
+
* gated on auth or a route param, matching React/Vue/Solid's `useQuery`.
|
|
346
|
+
*
|
|
340
347
|
* Pass `client` explicitly, or omit it to resolve the ambient client published
|
|
341
348
|
* by `setLunoraClient` (which must therefore be called during component init,
|
|
342
349
|
* before this runs).
|
|
343
350
|
*/
|
|
344
|
-
declare function query<F extends FunctionReference>(function_: F, args: ArgsOf<F
|
|
345
|
-
declare function query<F extends FunctionReference>(client: LunoraClient, function_: F, args: ArgsOf<F
|
|
351
|
+
declare function query<F extends FunctionReference>(function_: F, args: ArgsOf<F> | "skip", options?: QueryStoreOptions): QueryStore<F>;
|
|
352
|
+
declare function query<F extends FunctionReference>(client: LunoraClient, function_: F, args: ArgsOf<F> | "skip", options?: QueryStoreOptions): QueryStore<F>;
|
|
346
353
|
interface RateLimitOptions {
|
|
347
354
|
/** Clock injection for tests. Defaults to `Date.now`. */
|
|
348
355
|
now?: () => number;
|
package/dist/index.d.ts
CHANGED
|
@@ -307,8 +307,11 @@ interface PresenceHandle<L extends ListPresentReference> {
|
|
|
307
307
|
* Svelte context (requires calling inside a component's `<script>` block or
|
|
308
308
|
* inside a function called during component initialisation).
|
|
309
309
|
*
|
|
310
|
-
*
|
|
311
|
-
*
|
|
310
|
+
* Teardown (stop heartbeats, remove the visibility listener, release the
|
|
311
|
+
* connection context) is wired automatically to the component's `onDestroy`
|
|
312
|
+
* when called during component initialisation. Outside a component call
|
|
313
|
+
* `handle.teardown()` yourself. `teardown()` is idempotent, so an explicit
|
|
314
|
+
* `onDestroy(handle.teardown)` on top of the auto-wiring is safe.
|
|
312
315
|
*/
|
|
313
316
|
declare function presence<H extends HeartbeatReference, L extends ListPresentReference>(roomId: string, options: PresenceOptions<H, L>): PresenceHandle<L>;
|
|
314
317
|
declare function presence<H extends HeartbeatReference, L extends ListPresentReference>(client: LunoraClient, roomId: string, options: PresenceOptions<H, L>): PresenceHandle<L>;
|
|
@@ -337,12 +340,16 @@ type QueryStore<F extends FunctionReference> = Readable<ReturnOf<F> | undefined>
|
|
|
337
340
|
* store across several components shares a single underlying subscription
|
|
338
341
|
* (the `LunoraClient` de-dupes by `(fn, args, shardKey)`).
|
|
339
342
|
*
|
|
343
|
+
* Pass `"skip"` as `args` to keep the store connected but the subscription
|
|
344
|
+
* dormant (the value stays `undefined`, no socket opens) — useful for a query
|
|
345
|
+
* gated on auth or a route param, matching React/Vue/Solid's `useQuery`.
|
|
346
|
+
*
|
|
340
347
|
* Pass `client` explicitly, or omit it to resolve the ambient client published
|
|
341
348
|
* by `setLunoraClient` (which must therefore be called during component init,
|
|
342
349
|
* before this runs).
|
|
343
350
|
*/
|
|
344
|
-
declare function query<F extends FunctionReference>(function_: F, args: ArgsOf<F
|
|
345
|
-
declare function query<F extends FunctionReference>(client: LunoraClient, function_: F, args: ArgsOf<F
|
|
351
|
+
declare function query<F extends FunctionReference>(function_: F, args: ArgsOf<F> | "skip", options?: QueryStoreOptions): QueryStore<F>;
|
|
352
|
+
declare function query<F extends FunctionReference>(client: LunoraClient, function_: F, args: ArgsOf<F> | "skip", options?: QueryStoreOptions): QueryStore<F>;
|
|
346
353
|
interface RateLimitOptions {
|
|
347
354
|
/** Clock injection for tests. Defaults to `Date.now`. */
|
|
348
355
|
now?: () => number;
|
package/dist/index.mjs
CHANGED
|
@@ -5,8 +5,8 @@ export { flag, flags } from './packem_shared/flag-CqMU07WH.mjs';
|
|
|
5
5
|
export { hydratePreloaded } from './packem_shared/hydratePreloaded-Djsf_C8Q.mjs';
|
|
6
6
|
export { mutation } from './packem_shared/mutation-BmkCZnTd.mjs';
|
|
7
7
|
export { mutator } from './packem_shared/mutator-B5LchgMS.mjs';
|
|
8
|
-
export { infiniteQuery, paginatedQuery } from './packem_shared/infiniteQuery-
|
|
9
|
-
export { presence } from './packem_shared/presence-
|
|
10
|
-
export { query } from './packem_shared/query-
|
|
8
|
+
export { infiniteQuery, paginatedQuery } from './packem_shared/infiniteQuery-DlnFVv-f.mjs';
|
|
9
|
+
export { presence } from './packem_shared/presence-BvChXqiB.mjs';
|
|
10
|
+
export { query } from './packem_shared/query-B-Gu6KQw.mjs';
|
|
11
11
|
export { rateLimit } from './packem_shared/rateLimit-Cdw1kp8t.mjs';
|
|
12
|
-
export { subscription } from './packem_shared/subscription-
|
|
12
|
+
export { subscription } from './packem_shared/subscription-COqqiMPX.mjs';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { initialPages, derivePaginationStatus, rebalance, applyLoadMore } from '@lunora/client/pagination';
|
|
2
|
-
import { derived, writable, readable } from 'svelte/store';
|
|
2
|
+
import { derived, writable, readable, get } from 'svelte/store';
|
|
3
3
|
import { getLunoraClient } from './getLunoraClient-Prczj1gU.mjs';
|
|
4
4
|
import { i as isFunctionReference } from './is-function-reference-ycLAcI79.mjs';
|
|
5
5
|
|
|
@@ -17,22 +17,37 @@ const createPaginatedEngine = (client, function_, baseArgs, options) => {
|
|
|
17
17
|
const resultsByKey = /* @__PURE__ */ new Map();
|
|
18
18
|
const activeSubs = /* @__PURE__ */ new Map();
|
|
19
19
|
const pendingPageKeys = /* @__PURE__ */ new Set();
|
|
20
|
-
let currentPages = initialPages(initialNumItems);
|
|
21
20
|
const currentBaseArgs = baseArgs;
|
|
22
|
-
pagesStore.subscribe((pages) => {
|
|
23
|
-
currentPages = pages;
|
|
24
|
-
});
|
|
25
21
|
const rebuildPageResults = () => {
|
|
26
22
|
if (currentBaseArgs === "skip") {
|
|
27
23
|
pageResultsInternal.set([]);
|
|
28
24
|
return;
|
|
29
25
|
}
|
|
30
|
-
const updated =
|
|
26
|
+
const updated = get(pagesStore).map((page) => {
|
|
31
27
|
const key = buildPageKey(function_["__lunoraRef"], buildPageArgs(page, currentBaseArgs));
|
|
32
28
|
return resultsByKey.get(key);
|
|
33
29
|
});
|
|
34
30
|
pageResultsInternal.set(updated);
|
|
35
31
|
};
|
|
32
|
+
const migrateResultsForRebalance = (oldPages, newPages) => {
|
|
33
|
+
if (currentBaseArgs === "skip") {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const keyOf = (page) => buildPageKey(function_["__lunoraRef"], buildPageArgs(page, currentBaseArgs));
|
|
37
|
+
for (const newPage of newPages) {
|
|
38
|
+
const newKey = keyOf(newPage);
|
|
39
|
+
if (resultsByKey.has(newKey)) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const donor = oldPages.find((op) => op.lower === newPage.lower);
|
|
43
|
+
if (donor) {
|
|
44
|
+
const carried = resultsByKey.get(keyOf(donor));
|
|
45
|
+
if (carried) {
|
|
46
|
+
resultsByKey.set(newKey, carried);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
36
51
|
const syncSubscriptions = () => {
|
|
37
52
|
if (currentBaseArgs === "skip") {
|
|
38
53
|
for (const unsub of activeSubs.values()) {
|
|
@@ -43,8 +58,9 @@ const createPaginatedEngine = (client, function_, baseArgs, options) => {
|
|
|
43
58
|
return;
|
|
44
59
|
}
|
|
45
60
|
const baseArgsRecord = currentBaseArgs;
|
|
61
|
+
const pages = get(pagesStore);
|
|
46
62
|
const wantedKeys = /* @__PURE__ */ new Set();
|
|
47
|
-
for (const page of
|
|
63
|
+
for (const page of pages) {
|
|
48
64
|
wantedKeys.add(buildPageKey(function_["__lunoraRef"], buildPageArgs(page, baseArgsRecord)));
|
|
49
65
|
}
|
|
50
66
|
for (const [key, unsub] of activeSubs) {
|
|
@@ -52,9 +68,10 @@ const createPaginatedEngine = (client, function_, baseArgs, options) => {
|
|
|
52
68
|
unsub();
|
|
53
69
|
activeSubs.delete(key);
|
|
54
70
|
pendingPageKeys.delete(key);
|
|
71
|
+
resultsByKey.delete(key);
|
|
55
72
|
}
|
|
56
73
|
}
|
|
57
|
-
for (const page of
|
|
74
|
+
for (const page of pages) {
|
|
58
75
|
const pageArgs = buildPageArgs(page, baseArgsRecord);
|
|
59
76
|
const key = buildPageKey(function_["__lunoraRef"], pageArgs);
|
|
60
77
|
if (activeSubs.has(key)) {
|
|
@@ -69,12 +86,10 @@ const createPaginatedEngine = (client, function_, baseArgs, options) => {
|
|
|
69
86
|
pendingPageKeys.delete(key);
|
|
70
87
|
rebuildPageResults();
|
|
71
88
|
if (pendingPageKeys.size === 0) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
updatedResults = results;
|
|
75
|
-
})();
|
|
76
|
-
const next = rebalance(currentPages, updatedResults);
|
|
89
|
+
const latestPages = get(pagesStore);
|
|
90
|
+
const next = rebalance(latestPages, get(pageResultsInternal));
|
|
77
91
|
if (next) {
|
|
92
|
+
migrateResultsForRebalance(latestPages, next);
|
|
78
93
|
pagesStore.set(next);
|
|
79
94
|
syncSubscriptions();
|
|
80
95
|
rebuildPageResults();
|
|
@@ -115,14 +130,12 @@ const createPaginatedEngine = (client, function_, baseArgs, options) => {
|
|
|
115
130
|
if (currentBaseArgs === "skip") {
|
|
116
131
|
return;
|
|
117
132
|
}
|
|
118
|
-
|
|
119
|
-
pageResultsInternal.subscribe((results) => {
|
|
120
|
-
currentResults = results;
|
|
121
|
-
})();
|
|
133
|
+
const currentResults = get(pageResultsInternal);
|
|
122
134
|
const { nextCursor, status: currentStatus } = derivePaginationStatus(false, currentResults);
|
|
123
135
|
if (currentStatus !== "CanLoadMore") {
|
|
124
136
|
return;
|
|
125
137
|
}
|
|
138
|
+
const currentPages = get(pagesStore);
|
|
126
139
|
const next = applyLoadMore(currentPages, nextCursor, numberItems);
|
|
127
140
|
if (!next) {
|
|
128
141
|
return;
|
|
@@ -136,6 +149,7 @@ const createPaginatedEngine = (client, function_, baseArgs, options) => {
|
|
|
136
149
|
const carried = resultsByKey.get(oldKey);
|
|
137
150
|
if (carried) {
|
|
138
151
|
resultsByKey.set(newKey, carried);
|
|
152
|
+
resultsByKey.delete(oldKey);
|
|
139
153
|
}
|
|
140
154
|
}
|
|
141
155
|
}
|
|
@@ -1,16 +1,24 @@
|
|
|
1
|
+
import { onDestroy } from 'svelte';
|
|
1
2
|
import { readable } from 'svelte/store';
|
|
2
3
|
import { getLunoraClient } from './getLunoraClient-Prczj1gU.mjs';
|
|
3
4
|
|
|
4
|
-
const
|
|
5
|
-
if (typeof crypto !== "undefined"
|
|
6
|
-
|
|
5
|
+
const randomSessionId = (prefix = "sess") => {
|
|
6
|
+
if (typeof crypto !== "undefined") {
|
|
7
|
+
if (typeof crypto.randomUUID === "function") {
|
|
8
|
+
return crypto.randomUUID();
|
|
9
|
+
}
|
|
10
|
+
if (typeof crypto.getRandomValues === "function") {
|
|
11
|
+
const bytes = crypto.getRandomValues(new Uint8Array(16));
|
|
12
|
+
return `${prefix}-${Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
|
|
13
|
+
}
|
|
7
14
|
}
|
|
8
|
-
return
|
|
15
|
+
return `${prefix}-${Date.now().toString(36)}`;
|
|
9
16
|
};
|
|
17
|
+
|
|
10
18
|
const DEFAULT_INTERVAL_MS = 1e4;
|
|
11
19
|
const createPresenceHandle = (client, roomId, options) => {
|
|
12
20
|
const { heartbeat, intervalMs = DEFAULT_INTERVAL_MS, listPresent, shardKey } = options;
|
|
13
|
-
const sessionId = options.sessionId ??
|
|
21
|
+
const sessionId = options.sessionId ?? randomSessionId();
|
|
14
22
|
let latestData = options.data;
|
|
15
23
|
const sendHeartbeat = () => {
|
|
16
24
|
const args = {
|
|
@@ -46,13 +54,22 @@ const createPresenceHandle = (client, roomId, options) => {
|
|
|
46
54
|
);
|
|
47
55
|
return unsubscribe;
|
|
48
56
|
});
|
|
57
|
+
let torndown = false;
|
|
49
58
|
const teardown = () => {
|
|
59
|
+
if (torndown) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
torndown = true;
|
|
50
63
|
clearInterval(intervalHandle);
|
|
51
64
|
if (typeof document !== "undefined") {
|
|
52
65
|
document.removeEventListener("visibilitychange", onVisible);
|
|
53
66
|
}
|
|
54
67
|
releaseConnectionContext();
|
|
55
68
|
};
|
|
69
|
+
try {
|
|
70
|
+
onDestroy(teardown);
|
|
71
|
+
} catch {
|
|
72
|
+
}
|
|
56
73
|
return { present, sessionId, setData, teardown };
|
|
57
74
|
};
|
|
58
75
|
function presence(clientOrRoomId, roomIdOrOptions, maybeOptions) {
|
|
@@ -25,7 +25,13 @@ function query(clientOrFunction, functionOrArguments, argumentsOrOptions, maybeO
|
|
|
25
25
|
onData: (value) => {
|
|
26
26
|
set(value);
|
|
27
27
|
},
|
|
28
|
-
onError: options.onError
|
|
28
|
+
onError: options.onError,
|
|
29
|
+
// `args === "skip"` short-circuits inside the shared helper and
|
|
30
|
+
// fires this reset — clear any prior value so a store that flips
|
|
31
|
+
// to `"skip"` does not retain stale data.
|
|
32
|
+
onReset: () => {
|
|
33
|
+
set(void 0);
|
|
34
|
+
}
|
|
29
35
|
},
|
|
30
36
|
{ shardKey: options.shardKey }
|
|
31
37
|
)
|
|
@@ -12,9 +12,6 @@ function subscription(clientOrFunction, functionOrArgs, argsOrOptions, maybeOpti
|
|
|
12
12
|
const { shardKey, onError } = options;
|
|
13
13
|
const errorStore = writable();
|
|
14
14
|
const data = readable(void 0, (set) => {
|
|
15
|
-
if (args === "skip") {
|
|
16
|
-
return () => void 0;
|
|
17
|
-
}
|
|
18
15
|
const unsubscribe = createQuerySubscription(
|
|
19
16
|
client,
|
|
20
17
|
functionRef,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/svelte",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.34",
|
|
4
4
|
"description": "Svelte adapter for Lunora — live stores, optimistic mutations, and reactive loaders",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -54,10 +54,10 @@
|
|
|
54
54
|
"access": "public"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@lunora/client": "1.0.0-alpha.
|
|
58
|
-
"@lunora/errors": "1.0.0-alpha.
|
|
59
|
-
"@lunora/ratelimit": "1.0.0-alpha.
|
|
60
|
-
"@lunora/runtime": "1.0.0-alpha.
|
|
57
|
+
"@lunora/client": "1.0.0-alpha.21",
|
|
58
|
+
"@lunora/errors": "1.0.0-alpha.4",
|
|
59
|
+
"@lunora/ratelimit": "1.0.0-alpha.7",
|
|
60
|
+
"@lunora/runtime": "1.0.0-alpha.24"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
63
|
"svelte": "^5.0.0"
|