@sveltejs/kit 2.60.1 → 2.61.1
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/package.json +8 -9
- package/src/core/postbuild/analyse.js +1 -3
- package/src/core/sync/create_manifest_data/conflict.js +72 -0
- package/src/core/sync/create_manifest_data/index.js +1 -65
- package/src/core/sync/write_non_ambient.js +2 -2
- package/src/core/sync/write_types/index.js +1 -1
- package/src/exports/public.d.ts +23 -30
- package/src/exports/vite/build/build_server.js +36 -13
- package/src/exports/vite/dev/index.js +4 -2
- package/src/exports/vite/index.js +18 -16
- package/src/runtime/app/server/index.js +1 -2
- package/src/runtime/app/server/remote/form.js +10 -0
- package/src/runtime/app/server/remote/query.js +100 -36
- package/src/runtime/client/client.js +13 -8
- package/src/runtime/client/remote-functions/cache.svelte.js +157 -0
- package/src/runtime/client/remote-functions/form.svelte.js +235 -196
- package/src/runtime/client/remote-functions/index.js +2 -2
- package/src/runtime/client/remote-functions/prerender.svelte.js +1 -2
- package/src/runtime/client/remote-functions/query/cache.js +4 -0
- package/src/runtime/client/remote-functions/query/index.js +48 -0
- package/src/runtime/client/remote-functions/query/instance.svelte.js +249 -0
- package/src/runtime/client/remote-functions/query/proxy.js +156 -0
- package/src/runtime/client/remote-functions/query-batch.svelte.js +1 -1
- package/src/runtime/client/remote-functions/query-live/cache.js +4 -0
- package/src/runtime/client/remote-functions/query-live/index.js +31 -0
- package/src/runtime/client/remote-functions/{query-live.svelte.js → query-live/instance.svelte.js} +61 -310
- package/src/runtime/client/remote-functions/query-live/iterator.js +91 -0
- package/src/runtime/client/remote-functions/query-live/proxy.js +144 -0
- package/src/runtime/client/remote-functions/shared.svelte.js +53 -6
- package/src/runtime/client/utils.js +1 -1
- package/src/runtime/form-utils.js +7 -16
- package/src/runtime/server/index.js +2 -3
- package/src/runtime/server/page/actions.js +2 -9
- package/src/runtime/server/page/csp.js +3 -4
- package/src/runtime/server/page/render.js +13 -14
- package/src/runtime/server/respond.js +60 -36
- package/src/runtime/server/utils.js +23 -3
- package/src/types/global-private.d.ts +5 -0
- package/src/types/internal.d.ts +29 -6
- package/src/utils/routing.js +3 -1
- package/src/utils/shared-iterator.js +213 -0
- package/src/version.js +1 -1
- package/types/index.d.ts +27 -31
- package/types/index.d.ts.map +1 -1
- package/src/runtime/client/remote-functions/query.svelte.js +0 -512
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { handle_error_and_jsonify } from '../../../server/utils.js';
|
|
15
15
|
import { HttpError, SvelteKitError } from '@sveltejs/kit/internal';
|
|
16
16
|
import { noop } from '../../../../utils/functions.js';
|
|
17
|
+
import { SharedIterator } from '../../../../utils/shared-iterator.js';
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Creates a remote query. When called from the browser, the function will be invoked on the server via a `fetch` call.
|
|
@@ -153,24 +154,6 @@ function live(validate_or_fn, maybe_fn) {
|
|
|
153
154
|
const run = (event, state, get_input) =>
|
|
154
155
|
run_remote_generator(event, state, false, get_input, fn, __.name);
|
|
155
156
|
|
|
156
|
-
/**
|
|
157
|
-
* @param {any} generator
|
|
158
|
-
* @returns {Promise<any>}
|
|
159
|
-
*/
|
|
160
|
-
const first_value = async (generator) => {
|
|
161
|
-
try {
|
|
162
|
-
const { value, done } = await generator.next();
|
|
163
|
-
|
|
164
|
-
if (done) {
|
|
165
|
-
throw new Error(`query.live '${__.name}' did not yield a value`);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return value;
|
|
169
|
-
} finally {
|
|
170
|
-
await generator.return(undefined);
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
|
|
174
157
|
/** @type {RemoteQueryLiveInternals} */
|
|
175
158
|
const __ = {
|
|
176
159
|
type: 'query_live',
|
|
@@ -181,8 +164,8 @@ function live(validate_or_fn, maybe_fn) {
|
|
|
181
164
|
bind(payload, validated_arg) {
|
|
182
165
|
const { event, state } = get_request_store();
|
|
183
166
|
|
|
184
|
-
return create_live_query_resource(__, payload, state, () =>
|
|
185
|
-
|
|
167
|
+
return create_live_query_resource(__, payload, state, event.request.signal, () =>
|
|
168
|
+
run(event, state, () => validated_arg)
|
|
186
169
|
);
|
|
187
170
|
}
|
|
188
171
|
};
|
|
@@ -198,8 +181,8 @@ function live(validate_or_fn, maybe_fn) {
|
|
|
198
181
|
const { event, state } = get_request_store();
|
|
199
182
|
const payload = stringify_remote_arg(arg, state.transport);
|
|
200
183
|
|
|
201
|
-
return create_live_query_resource(__, payload, state, () =>
|
|
202
|
-
|
|
184
|
+
return create_live_query_resource(__, payload, state, event.request.signal, () =>
|
|
185
|
+
run(event, state, () => validate(arg))
|
|
203
186
|
);
|
|
204
187
|
};
|
|
205
188
|
|
|
@@ -448,21 +431,17 @@ function create_query_resource(__, payload, state, fn) {
|
|
|
448
431
|
const value = is_immediate_refresh ? get_promise() : fn();
|
|
449
432
|
return update_refresh_value(refresh_context, value, is_immediate_refresh);
|
|
450
433
|
},
|
|
451
|
-
run() {
|
|
452
|
-
// potential TODO: if we want to be able to run queries at the top level of modules / outside of the request context, we could technically remove
|
|
453
|
-
// the requirement that `state` is defined, but that's kind of an annoying change to make, so we're going to wait on that until we have any sort of
|
|
454
|
-
// concrete use case.
|
|
455
|
-
if (!state.is_in_universal_load) {
|
|
456
|
-
throw new Error(
|
|
457
|
-
'On the server, .run() can only be called in universal `load` functions. Anywhere else, just await the query directly'
|
|
458
|
-
);
|
|
459
|
-
}
|
|
460
|
-
return get_response(__, payload, state, fn);
|
|
461
|
-
},
|
|
462
434
|
/** @param {any} value */
|
|
463
435
|
set(value) {
|
|
464
436
|
return update_refresh_value(get_refresh_context(__, 'set', payload), value);
|
|
465
437
|
},
|
|
438
|
+
// TODO 3.0 remove this
|
|
439
|
+
// @ts-expect-error This method no longer exists
|
|
440
|
+
run() {
|
|
441
|
+
throw new Error(
|
|
442
|
+
`\`myQuery().run()\` has been removed — please replace it with \`myQuery()\`. See https://github.com/sveltejs/kit/pull/15779 for more details`
|
|
443
|
+
);
|
|
444
|
+
},
|
|
466
445
|
/** @type {Promise<any>['then']} */
|
|
467
446
|
then(onfulfilled, onrejected) {
|
|
468
447
|
return get_promise().then(onfulfilled, onrejected);
|
|
@@ -480,13 +459,21 @@ function create_query_resource(__, payload, state, fn) {
|
|
|
480
459
|
* @param {RemoteQueryLiveInternals} __
|
|
481
460
|
* @param {string} payload — the stringified raw argument (i.e. the cache key the client will use)
|
|
482
461
|
* @param {RequestState} state
|
|
483
|
-
* @param {
|
|
462
|
+
* @param {AbortSignal} signal — the request signal; aborts in-flight iteration when the client disconnects
|
|
463
|
+
* @param {() => AsyncGenerator<any, void, void>} get_generator
|
|
484
464
|
* @returns {RemoteLiveQuery<any>}
|
|
485
465
|
*/
|
|
486
|
-
function create_live_query_resource(__, payload, state,
|
|
466
|
+
function create_live_query_resource(__, payload, state, signal, get_generator) {
|
|
487
467
|
/** @type {Promise<any> | null} */
|
|
488
468
|
let promise = null;
|
|
489
469
|
|
|
470
|
+
const get_first_value = async () => {
|
|
471
|
+
for await (const value of get_generator()) {
|
|
472
|
+
return value;
|
|
473
|
+
}
|
|
474
|
+
throw new Error(`query.live '${__.name}' did not yield a value`);
|
|
475
|
+
};
|
|
476
|
+
|
|
490
477
|
const get_promise = () => {
|
|
491
478
|
return (promise ??= get_response(__, payload, state, get_first_value));
|
|
492
479
|
};
|
|
@@ -540,19 +527,96 @@ function create_live_query_resource(__, payload, state, get_first_value) {
|
|
|
540
527
|
reconnects.set(create_remote_key(__.id, payload), get_promise());
|
|
541
528
|
return Promise.resolve();
|
|
542
529
|
},
|
|
530
|
+
/** @ts-expect-error This method no longer exists */
|
|
543
531
|
run() {
|
|
544
|
-
throw new Error(
|
|
532
|
+
throw new Error(
|
|
533
|
+
'`.run()` has been removed from live queries. Use `for await (const value of liveQuery())` instead.'
|
|
534
|
+
);
|
|
545
535
|
},
|
|
546
536
|
/** @type {Promise<any>['then']} */
|
|
547
537
|
then(onfulfilled, onrejected) {
|
|
548
538
|
return get_promise().then(onfulfilled, onrejected);
|
|
549
539
|
},
|
|
540
|
+
[Symbol.asyncIterator]() {
|
|
541
|
+
const key = create_remote_key(__.id, payload);
|
|
542
|
+
const cache = (state.remote.live_iterators ??= new Map());
|
|
543
|
+
let cached = cache.get(key);
|
|
544
|
+
if (!cached) {
|
|
545
|
+
cached = create_shared_live_iterator(signal, get_generator);
|
|
546
|
+
cache.set(key, cached);
|
|
547
|
+
}
|
|
548
|
+
return cached.subscribe();
|
|
549
|
+
},
|
|
550
550
|
get [Symbol.toStringTag]() {
|
|
551
551
|
return 'LiveQueryResource';
|
|
552
552
|
}
|
|
553
553
|
};
|
|
554
554
|
}
|
|
555
555
|
|
|
556
|
+
/**
|
|
557
|
+
* Wraps a lazily-created live-query generator so that multiple `for await`
|
|
558
|
+
* consumers within the same request share one underlying iteration. The first
|
|
559
|
+
* subscriber starts the generator; values are broadcast to all subscribers
|
|
560
|
+
* via a `SharedIterator`. When the last subscriber unsubscribes, the generator
|
|
561
|
+
* is closed via `generator.return(undefined)`.
|
|
562
|
+
*
|
|
563
|
+
* If `signal` aborts (typically because the client has disconnected), the
|
|
564
|
+
* pump is torn down and any in-flight `next()` calls on consumer iterators
|
|
565
|
+
* resolve with `{ done: true }`, so suspended `for await` loops unwind
|
|
566
|
+
* cleanly rather than leaking.
|
|
567
|
+
*
|
|
568
|
+
* @param {AbortSignal} signal
|
|
569
|
+
* @param {() => AsyncGenerator<any, void, void>} get_generator
|
|
570
|
+
*/
|
|
571
|
+
function create_shared_live_iterator(signal, get_generator) {
|
|
572
|
+
return new SharedIterator((instance) => {
|
|
573
|
+
// Don't bother starting the pump if the request has already been
|
|
574
|
+
// aborted between cache creation and first subscription.
|
|
575
|
+
if (signal.aborted) {
|
|
576
|
+
instance.done();
|
|
577
|
+
return noop;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
const generator = get_generator();
|
|
581
|
+
|
|
582
|
+
// Set to `true` when we deliberately close the generator (because every
|
|
583
|
+
// subscriber has unsubscribed, or the request was aborted). The pump's
|
|
584
|
+
// `generator.next()` will reject as a result; we use this flag to swallow that
|
|
585
|
+
// abort error rather than surfacing it through `instance.fail()`.
|
|
586
|
+
let aborted = false;
|
|
587
|
+
|
|
588
|
+
const close = () => {
|
|
589
|
+
aborted = true;
|
|
590
|
+
void generator.return().catch(noop);
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
// On request abort, tear down the pump and notify subscribers. `done()` is
|
|
594
|
+
// used (rather than `fail()`) because an aborted request is a normal
|
|
595
|
+
// termination — there's no error to surface to user code that's already
|
|
596
|
+
// been disconnected from the client.
|
|
597
|
+
signal.addEventListener('abort', () => (close(), instance.done()), { once: true });
|
|
598
|
+
|
|
599
|
+
void (async () => {
|
|
600
|
+
try {
|
|
601
|
+
while (true) {
|
|
602
|
+
const result = await generator.next();
|
|
603
|
+
if (result.done) {
|
|
604
|
+
instance.done();
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
instance.push(result.value);
|
|
608
|
+
}
|
|
609
|
+
} catch (error) {
|
|
610
|
+
if (!aborted) instance.fail(error);
|
|
611
|
+
} finally {
|
|
612
|
+
close();
|
|
613
|
+
}
|
|
614
|
+
})();
|
|
615
|
+
|
|
616
|
+
return close;
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
|
|
556
620
|
// Add batch as a property to the query function
|
|
557
621
|
Object.defineProperty(query, 'batch', { value: batch, enumerable: true });
|
|
558
622
|
Object.defineProperty(query, 'live', { value: live, enumerable: true });
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
/** @import {
|
|
2
|
-
/** @import {
|
|
1
|
+
/** @import { CacheEntry } from './remote-functions/cache.svelte.js' */
|
|
2
|
+
/** @import { Query } from './remote-functions/query/instance.svelte.js' */
|
|
3
|
+
/** @import { LiveQuery } from './remote-functions/query-live/instance.svelte.js' */
|
|
3
4
|
import { BROWSER, DEV } from 'esm-env';
|
|
4
5
|
import * as svelte from 'svelte';
|
|
5
6
|
import { HttpError, Redirect, SvelteKitError } from '@sveltejs/kit/internal';
|
|
@@ -302,13 +303,13 @@ const preload_tokens = new Set();
|
|
|
302
303
|
export let pending_invalidate;
|
|
303
304
|
|
|
304
305
|
/**
|
|
305
|
-
* @type {Map<string, Map<string,
|
|
306
|
+
* @type {Map<string, Map<string, CacheEntry<Query<any>>>>}
|
|
306
307
|
* A map of query id -> payload -> query internals for all active queries.
|
|
307
308
|
*/
|
|
308
309
|
export const query_map = new Map();
|
|
309
310
|
|
|
310
311
|
/**
|
|
311
|
-
* @type {Map<string, Map<string,
|
|
312
|
+
* @type {Map<string, Map<string, CacheEntry<LiveQuery<any>>>>}
|
|
312
313
|
* A map of id -> payload -> live query internals for all active queries.
|
|
313
314
|
*/
|
|
314
315
|
export const live_query_map = new Map();
|
|
@@ -658,7 +659,8 @@ async function _preload_code(url) {
|
|
|
658
659
|
* @param {boolean} hydrate
|
|
659
660
|
*/
|
|
660
661
|
async function initialize(result, target, hydrate) {
|
|
661
|
-
if (
|
|
662
|
+
if (__SVELTEKIT_DEV__ && result.state.error && document.querySelector('vite-error-overlay'))
|
|
663
|
+
return;
|
|
662
664
|
|
|
663
665
|
/** @type {import('@sveltejs/kit').NavigationEvent} */
|
|
664
666
|
const nav = {
|
|
@@ -672,8 +674,11 @@ async function initialize(result, target, hydrate) {
|
|
|
672
674
|
nav
|
|
673
675
|
};
|
|
674
676
|
|
|
675
|
-
|
|
676
|
-
if (
|
|
677
|
+
// Removes the style node we used to avoid FOUC during development
|
|
678
|
+
if (__SVELTEKIT_DEV__) {
|
|
679
|
+
const style = document.querySelector('style[data-sveltekit]');
|
|
680
|
+
if (style) style.remove();
|
|
681
|
+
}
|
|
677
682
|
|
|
678
683
|
update(/** @type {import('@sveltejs/kit').Page} */ (result.props.page));
|
|
679
684
|
|
|
@@ -2621,7 +2626,7 @@ function _start_router() {
|
|
|
2621
2626
|
});
|
|
2622
2627
|
|
|
2623
2628
|
// @ts-expect-error this isn't supported everywhere yet
|
|
2624
|
-
if (!navigator.connection?.saveData) {
|
|
2629
|
+
if (!navigator.connection?.saveData && !/2g/.test(navigator.connection?.effectiveType)) {
|
|
2625
2630
|
setup_preload();
|
|
2626
2631
|
}
|
|
2627
2632
|
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { tick } from 'svelte';
|
|
2
|
+
import { once } from '../../../utils/functions.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @template R
|
|
6
|
+
* @typedef {object} CacheEntry
|
|
7
|
+
* @property {number} proxy_count The number of live proxy instances referencing this
|
|
8
|
+
* entry. The entry is eligible for eviction when this hits zero.
|
|
9
|
+
* @property {R} resource The actual reactive resource (Query or LiveQuery).
|
|
10
|
+
* @property {() => void} cleanup Tears down the `$effect.root` that owns the resource.
|
|
11
|
+
* Run when the entry is evicted.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @template R
|
|
16
|
+
* @typedef {{ entry: CacheEntry<R>, id: string, payload: string }} ProxyFinalizerToken
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Cache controller bound to a specific cache map and resource teardown function. Owns the
|
|
21
|
+
* eviction scheduling and FinalizationRegistry for its cache.
|
|
22
|
+
*
|
|
23
|
+
* Methods are defined as arrow-function class fields so they can be destructured and
|
|
24
|
+
* re-exported without losing their `this` binding.
|
|
25
|
+
*
|
|
26
|
+
* @template R
|
|
27
|
+
*/
|
|
28
|
+
export class CacheController {
|
|
29
|
+
/** @type {Map<string, Map<string, CacheEntry<R>>>} */
|
|
30
|
+
#cache_map;
|
|
31
|
+
|
|
32
|
+
/** @type {((resource: R) => void) | undefined} */
|
|
33
|
+
#destroy_resource;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The held value points at the cache entry the proxy is contributing to. When the
|
|
37
|
+
* proxy is GC'd, we decrement that entry's `proxy_count` and schedule a deferred
|
|
38
|
+
* eviction check.
|
|
39
|
+
*
|
|
40
|
+
* @type {FinalizationRegistry<ProxyFinalizerToken<R>>}
|
|
41
|
+
*/
|
|
42
|
+
#proxy_finalizer = new FinalizationRegistry(({ entry, id, payload }) => {
|
|
43
|
+
this.deref(entry, id, payload);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @param {Map<string, Map<string, CacheEntry<R>>>} cache_map
|
|
48
|
+
* @param {(resource: R) => void} [destroy_resource] Optional teardown hook called on
|
|
49
|
+
* the resource itself before the cache entry's `$effect.root` cleanup runs. Used by
|
|
50
|
+
* live queries to detach event listeners and abort connections.
|
|
51
|
+
*/
|
|
52
|
+
constructor(cache_map, destroy_resource) {
|
|
53
|
+
this.#cache_map = cache_map;
|
|
54
|
+
this.#destroy_resource = destroy_resource;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Get-or-create the cache entry for `(id, payload)`. The resource is constructed
|
|
59
|
+
* inside an `$effect.root`, the cleanup of which is stored on the entry.
|
|
60
|
+
*
|
|
61
|
+
* @param {string} id
|
|
62
|
+
* @param {string} payload
|
|
63
|
+
* @param {() => R} create_resource
|
|
64
|
+
* @returns {CacheEntry<R>}
|
|
65
|
+
*/
|
|
66
|
+
ensure_entry = (id, payload, create_resource) => {
|
|
67
|
+
let entries = this.#cache_map.get(id);
|
|
68
|
+
|
|
69
|
+
if (!entries) {
|
|
70
|
+
entries = new Map();
|
|
71
|
+
this.#cache_map.set(id, entries);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let entry = entries.get(payload);
|
|
75
|
+
|
|
76
|
+
if (!entry) {
|
|
77
|
+
const c = /** @type {CacheEntry<R>} */ ({
|
|
78
|
+
proxy_count: 0,
|
|
79
|
+
resource: /** @type {R} */ (/** @type {unknown} */ (null)),
|
|
80
|
+
cleanup: /** @type {() => void} */ (/** @type {unknown} */ (null))
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
c.cleanup = $effect.root(() => {
|
|
84
|
+
c.resource = create_resource();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
entry = c;
|
|
88
|
+
entries.set(payload, entry);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return entry;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Register a reference to a resource cache entry using an anchor object with the FinalizationRegistry.
|
|
96
|
+
* When the anchor object is garbage collected, the held value's `entry.proxy_count` is decremented
|
|
97
|
+
* and a deferred eviction check is scheduled for `(id, payload)`.
|
|
98
|
+
*
|
|
99
|
+
* @param {object} anchor
|
|
100
|
+
* @param {CacheEntry<R>} entry
|
|
101
|
+
* @param {string} id
|
|
102
|
+
* @param {string} payload
|
|
103
|
+
*/
|
|
104
|
+
ref = (anchor, entry, id, payload) => {
|
|
105
|
+
entry.proxy_count++;
|
|
106
|
+
this.#proxy_finalizer.register(anchor, { entry, id, payload });
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Manually reference this cache entry. Danger: This entry will never be cleaned up unless the returned callback is called.
|
|
111
|
+
*
|
|
112
|
+
* @param {CacheEntry<R>} entry
|
|
113
|
+
* @param {string} id
|
|
114
|
+
* @param {string} payload
|
|
115
|
+
*/
|
|
116
|
+
manual_ref = (entry, id, payload) => {
|
|
117
|
+
entry.proxy_count++;
|
|
118
|
+
return once(() => this.deref(entry, id, payload));
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Dereference this cache entry. If the entry's `proxy_count` hits zero, schedule a deferred eviction check.
|
|
123
|
+
*
|
|
124
|
+
* @param {CacheEntry<R>} entry
|
|
125
|
+
* @param {string} id
|
|
126
|
+
* @param {string} payload
|
|
127
|
+
*/
|
|
128
|
+
deref = (entry, id, payload) => {
|
|
129
|
+
entry.proxy_count--;
|
|
130
|
+
void tick().then(() => {
|
|
131
|
+
const entry = this.#cache_map.get(id)?.get(payload);
|
|
132
|
+
if (!entry || entry.proxy_count > 0) return;
|
|
133
|
+
this.#evict(id, payload);
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Tear down the cache entry for `(id, payload)` if it exists. Runs the optional
|
|
139
|
+
* resource teardown and the entry's `$effect.root` cleanup, then removes the entry
|
|
140
|
+
* from the cache map.
|
|
141
|
+
*
|
|
142
|
+
* @param {string} id
|
|
143
|
+
* @param {string} payload
|
|
144
|
+
*/
|
|
145
|
+
#evict = (id, payload) => {
|
|
146
|
+
const entries = this.#cache_map.get(id);
|
|
147
|
+
const entry = entries?.get(payload);
|
|
148
|
+
if (!entry) return;
|
|
149
|
+
|
|
150
|
+
this.#destroy_resource?.(entry.resource);
|
|
151
|
+
entry.cleanup();
|
|
152
|
+
entries?.delete(payload);
|
|
153
|
+
if (entries && entries.size === 0) {
|
|
154
|
+
this.#cache_map.delete(id);
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|