@async/framework 0.5.0 → 0.7.0
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/CHANGELOG.md +32 -0
- package/README.md +64 -9
- package/examples/cache/index.html +1 -1
- package/examples/components/index.html +1 -1
- package/examples/components/main.js +2 -2
- package/examples/counter/index.html +1 -1
- package/examples/partials/index.html +1 -1
- package/examples/product/index.html +1 -1
- package/examples/product/main.js +2 -2
- package/examples/router/index.html +1 -1
- package/examples/server-call/index.html +1 -1
- package/examples/ssr/index.html +1 -1
- package/examples/streaming/index.html +1 -1
- package/framework.d.ts +572 -0
- package/framework.js +216 -29
- package/framework.min.js +3820 -0
- package/framework.ts +4321 -0
- package/framework.umd.js +4342 -0
- package/framework.umd.min.js +3843 -0
- package/package.json +34 -5
- package/src/app.js +35 -3
- package/src/cache.js +27 -3
- package/src/component.js +1 -1
- package/src/index.js +2 -2
- package/src/loader.js +4 -2
- package/src/router.js +100 -16
- package/src/server.js +44 -1
package/framework.js
CHANGED
|
@@ -536,6 +536,7 @@ const __cacheModule = (() => {
|
|
|
536
536
|
const registryStore = registry ?? createRegistryStore();
|
|
537
537
|
const definitions = registryStore._map(type);
|
|
538
538
|
const entries = registryStore._map(`${type}.entries`);
|
|
539
|
+
const pending = new Map();
|
|
539
540
|
|
|
540
541
|
const registryApi = attachRegistryInspection({
|
|
541
542
|
register(id, definition = defineCache()) {
|
|
@@ -597,19 +598,37 @@ const __cacheModule = (() => {
|
|
|
597
598
|
if (cached !== undefined) {
|
|
598
599
|
return cached;
|
|
599
600
|
}
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
601
|
+
if (pending.has(key)) {
|
|
602
|
+
return pending.get(key);
|
|
603
|
+
}
|
|
604
|
+
let promise;
|
|
605
|
+
promise = Promise.resolve()
|
|
606
|
+
.then(fn)
|
|
607
|
+
.then((value) => {
|
|
608
|
+
if (pending.get(key) === promise) {
|
|
609
|
+
registryApi.set(key, value, options);
|
|
610
|
+
}
|
|
611
|
+
return value;
|
|
612
|
+
})
|
|
613
|
+
.finally(() => {
|
|
614
|
+
if (pending.get(key) === promise) {
|
|
615
|
+
pending.delete(key);
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
pending.set(key, promise);
|
|
619
|
+
return promise;
|
|
603
620
|
},
|
|
604
621
|
|
|
605
622
|
delete(key) {
|
|
606
623
|
assertKey(key);
|
|
624
|
+
pending.delete(key);
|
|
607
625
|
return entries.delete(key);
|
|
608
626
|
},
|
|
609
627
|
|
|
610
628
|
clear(prefix) {
|
|
611
629
|
if (prefix === undefined) {
|
|
612
630
|
entries.clear();
|
|
631
|
+
pending.clear();
|
|
613
632
|
return registryApi;
|
|
614
633
|
}
|
|
615
634
|
for (const key of [...entries.keys()]) {
|
|
@@ -617,6 +636,11 @@ const __cacheModule = (() => {
|
|
|
617
636
|
entries.delete(key);
|
|
618
637
|
}
|
|
619
638
|
}
|
|
639
|
+
for (const key of [...pending.keys()]) {
|
|
640
|
+
if (key.startsWith(prefix)) {
|
|
641
|
+
pending.delete(key);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
620
644
|
return registryApi;
|
|
621
645
|
},
|
|
622
646
|
|
|
@@ -1516,7 +1540,7 @@ const __componentModule = (() => {
|
|
|
1516
1540
|
bind(value) {
|
|
1517
1541
|
const id = runtime.loader?._registerBinding?.(value);
|
|
1518
1542
|
if (!id) {
|
|
1519
|
-
throw new Error("Inline template bindings require
|
|
1543
|
+
throw new Error("Inline template bindings require a Loader.");
|
|
1520
1544
|
}
|
|
1521
1545
|
bindingIds.push(id);
|
|
1522
1546
|
return id;
|
|
@@ -1752,6 +1776,8 @@ const __componentModule = (() => {
|
|
|
1752
1776
|
const __serverModule = (() => {
|
|
1753
1777
|
const { attachRegistryInspection, createRegistryStore } = __registryStoreModule;
|
|
1754
1778
|
const serverEnvelopeKeys = new Set(["value", "signals", "boundary", "html", "redirect", "error"]);
|
|
1779
|
+
const appliedServerResult = Symbol.for("@async/framework.appliedServerResult");
|
|
1780
|
+
const appliedServerValues = new WeakSet();
|
|
1755
1781
|
|
|
1756
1782
|
function createServerRegistry(initialMap = {}, options = {}) {
|
|
1757
1783
|
const registryStore = options.registry ?? createRegistryStore();
|
|
@@ -1858,6 +1884,7 @@ const __serverModule = (() => {
|
|
|
1858
1884
|
input: context.input ?? defaultInput(runContext),
|
|
1859
1885
|
signals: context.signalValues ?? snapshotSignalPaths(context.signalPaths, runContext.signals)
|
|
1860
1886
|
};
|
|
1887
|
+
assertJsonTransportable(body);
|
|
1861
1888
|
|
|
1862
1889
|
const response = await fetchImpl(joinEndpoint(endpoint, id), {
|
|
1863
1890
|
method: "POST",
|
|
@@ -1875,7 +1902,7 @@ const __serverModule = (() => {
|
|
|
1875
1902
|
|
|
1876
1903
|
const result = await readServerResponse(response);
|
|
1877
1904
|
await applyServerResult(result, runContext);
|
|
1878
|
-
return unwrapServerResult(result);
|
|
1905
|
+
return markAppliedServerValue(unwrapServerResult(result));
|
|
1879
1906
|
}
|
|
1880
1907
|
|
|
1881
1908
|
return createServerNamespace(run, {
|
|
@@ -1910,6 +1937,9 @@ const __serverModule = (() => {
|
|
|
1910
1937
|
if (!isServerEnvelope(result)) {
|
|
1911
1938
|
return result;
|
|
1912
1939
|
}
|
|
1940
|
+
if (result[appliedServerResult] || appliedServerValues.has(result)) {
|
|
1941
|
+
return result;
|
|
1942
|
+
}
|
|
1913
1943
|
|
|
1914
1944
|
if (result.signals && context.signals) {
|
|
1915
1945
|
for (const [path, value] of Object.entries(result.signals)) {
|
|
@@ -1933,6 +1963,12 @@ const __serverModule = (() => {
|
|
|
1933
1963
|
throw toError(result.error);
|
|
1934
1964
|
}
|
|
1935
1965
|
|
|
1966
|
+
Object.defineProperty(result, appliedServerResult, {
|
|
1967
|
+
configurable: true,
|
|
1968
|
+
enumerable: false,
|
|
1969
|
+
value: true
|
|
1970
|
+
});
|
|
1971
|
+
|
|
1936
1972
|
return result;
|
|
1937
1973
|
}
|
|
1938
1974
|
|
|
@@ -1943,6 +1979,13 @@ const __serverModule = (() => {
|
|
|
1943
1979
|
return result;
|
|
1944
1980
|
}
|
|
1945
1981
|
|
|
1982
|
+
function markAppliedServerValue(value) {
|
|
1983
|
+
if (value && typeof value === "object") {
|
|
1984
|
+
appliedServerValues.add(value);
|
|
1985
|
+
}
|
|
1986
|
+
return value;
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1946
1989
|
function defaultInput(context = {}) {
|
|
1947
1990
|
const form = findForm(context);
|
|
1948
1991
|
if (form) {
|
|
@@ -2120,6 +2163,30 @@ const __serverModule = (() => {
|
|
|
2120
2163
|
return output;
|
|
2121
2164
|
}
|
|
2122
2165
|
|
|
2166
|
+
function assertJsonTransportable(value, seen = new Set()) {
|
|
2167
|
+
if (value == null || typeof value !== "object") {
|
|
2168
|
+
return;
|
|
2169
|
+
}
|
|
2170
|
+
if (seen.has(value)) {
|
|
2171
|
+
return;
|
|
2172
|
+
}
|
|
2173
|
+
seen.add(value);
|
|
2174
|
+
|
|
2175
|
+
const tag = Object.prototype.toString.call(value);
|
|
2176
|
+
if (tag === "[object File]" || tag === "[object Blob]" || tag === "[object FormData]") {
|
|
2177
|
+
throw new Error("Server proxy JSON transport does not support File, Blob, or FormData values yet.");
|
|
2178
|
+
}
|
|
2179
|
+
if (Array.isArray(value)) {
|
|
2180
|
+
for (const item of value) {
|
|
2181
|
+
assertJsonTransportable(item, seen);
|
|
2182
|
+
}
|
|
2183
|
+
return;
|
|
2184
|
+
}
|
|
2185
|
+
for (const item of Object.values(value)) {
|
|
2186
|
+
assertJsonTransportable(item, seen);
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
|
|
2123
2190
|
function joinEndpoint(endpoint, id) {
|
|
2124
2191
|
return `${String(endpoint).replace(/\/$/, "")}/${encodeURIComponent(id)}`;
|
|
2125
2192
|
}
|
|
@@ -2356,7 +2423,7 @@ const __loaderModule = (() => {
|
|
|
2356
2423
|
const { matchAttribute, normalizeAttributeConfig, readAttribute } = __attributesModule;
|
|
2357
2424
|
const inlineBindingPrefix = "__async:inline:";
|
|
2358
2425
|
|
|
2359
|
-
function
|
|
2426
|
+
function Loader({ root, signals, handlers, server, router, cache, attributes } = {}) {
|
|
2360
2427
|
const documentRef = root?.ownerDocument ?? root ?? globalThis.document;
|
|
2361
2428
|
const rootNode = root ?? documentRef;
|
|
2362
2429
|
const signalRegistry = signals ?? createSignalRegistry();
|
|
@@ -2798,7 +2865,7 @@ const __loaderModule = (() => {
|
|
|
2798
2865
|
|
|
2799
2866
|
function assertActive() {
|
|
2800
2867
|
if (destroyed) {
|
|
2801
|
-
throw new Error("
|
|
2868
|
+
throw new Error("Loader has been destroyed.");
|
|
2802
2869
|
}
|
|
2803
2870
|
}
|
|
2804
2871
|
|
|
@@ -2862,6 +2929,8 @@ const __loaderModule = (() => {
|
|
|
2862
2929
|
return api;
|
|
2863
2930
|
}
|
|
2864
2931
|
|
|
2932
|
+
const AsyncLoader = Loader;
|
|
2933
|
+
|
|
2865
2934
|
function normalizeClassTokens(value, tokens = new Set()) {
|
|
2866
2935
|
if (value == null || value === false) {
|
|
2867
2936
|
return tokens;
|
|
@@ -3062,7 +3131,7 @@ const __loaderModule = (() => {
|
|
|
3062
3131
|
})
|
|
3063
3132
|
);
|
|
3064
3133
|
}
|
|
3065
|
-
return { AsyncLoader };
|
|
3134
|
+
return { Loader, AsyncLoader };
|
|
3066
3135
|
})();
|
|
3067
3136
|
|
|
3068
3137
|
const __partialsModule = (() => {
|
|
@@ -3185,7 +3254,7 @@ const __partialsModule = (() => {
|
|
|
3185
3254
|
})();
|
|
3186
3255
|
|
|
3187
3256
|
const __routerModule = (() => {
|
|
3188
|
-
const {
|
|
3257
|
+
const { Loader } = __loaderModule;
|
|
3189
3258
|
const { createHandlerRegistry } = __handlersModule;
|
|
3190
3259
|
const { createSignalRegistry } = __signalsModule;
|
|
3191
3260
|
const { applyServerResult } = __serverModule;
|
|
@@ -3217,6 +3286,7 @@ const __routerModule = (() => {
|
|
|
3217
3286
|
const nextRoute = normalizeRoute(pattern, definition);
|
|
3218
3287
|
entries.set(pattern, nextRoute.definition);
|
|
3219
3288
|
routes.push(nextRoute);
|
|
3289
|
+
sortRoutes(routes);
|
|
3220
3290
|
return nextRoute;
|
|
3221
3291
|
},
|
|
3222
3292
|
|
|
@@ -3289,6 +3359,7 @@ const __routerModule = (() => {
|
|
|
3289
3359
|
const nextRoute = normalizeRoute(pattern, definition);
|
|
3290
3360
|
entries.set(pattern, nextRoute.definition);
|
|
3291
3361
|
routes.push(nextRoute);
|
|
3362
|
+
sortRoutes(routes);
|
|
3292
3363
|
}
|
|
3293
3364
|
}
|
|
3294
3365
|
|
|
@@ -3314,7 +3385,7 @@ const __routerModule = (() => {
|
|
|
3314
3385
|
const attributeConfig = normalizeAttributeConfig(attributes ?? loader?.attributes);
|
|
3315
3386
|
const loaderInstance =
|
|
3316
3387
|
loader ??
|
|
3317
|
-
|
|
3388
|
+
Loader({
|
|
3318
3389
|
root: rootNode,
|
|
3319
3390
|
signals: signalRegistry,
|
|
3320
3391
|
handlers: handlerRegistry,
|
|
@@ -3325,6 +3396,8 @@ const __routerModule = (() => {
|
|
|
3325
3396
|
const ownsLoader = !loader;
|
|
3326
3397
|
const cleanups = new Set();
|
|
3327
3398
|
let destroyed = false;
|
|
3399
|
+
let navigationVersion = 0;
|
|
3400
|
+
let activeNavigation;
|
|
3328
3401
|
|
|
3329
3402
|
const api = {
|
|
3330
3403
|
mode,
|
|
@@ -3364,7 +3437,7 @@ const __routerModule = (() => {
|
|
|
3364
3437
|
},
|
|
3365
3438
|
|
|
3366
3439
|
match(url) {
|
|
3367
|
-
return routes.match(url);
|
|
3440
|
+
return routes.match(resolveUrl(url));
|
|
3368
3441
|
},
|
|
3369
3442
|
|
|
3370
3443
|
prefetch(url) {
|
|
@@ -3389,7 +3462,7 @@ const __routerModule = (() => {
|
|
|
3389
3462
|
return null;
|
|
3390
3463
|
}
|
|
3391
3464
|
|
|
3392
|
-
const target =
|
|
3465
|
+
const target = resolveUrl(url);
|
|
3393
3466
|
if (mode === "ssr-spa") {
|
|
3394
3467
|
return fetchRoutePartial(target, options);
|
|
3395
3468
|
}
|
|
@@ -3401,6 +3474,7 @@ const __routerModule = (() => {
|
|
|
3401
3474
|
return;
|
|
3402
3475
|
}
|
|
3403
3476
|
destroyed = true;
|
|
3477
|
+
activeNavigation?.controller.abort(new Error("Router has been destroyed."));
|
|
3404
3478
|
for (const cleanup of cleanups) {
|
|
3405
3479
|
cleanup();
|
|
3406
3480
|
}
|
|
@@ -3440,24 +3514,37 @@ const __routerModule = (() => {
|
|
|
3440
3514
|
async function renderLocalRoutePartial(target, options = {}) {
|
|
3441
3515
|
const matched = api.match(target);
|
|
3442
3516
|
if (!matched) {
|
|
3517
|
+
beginNavigation(target, null);
|
|
3443
3518
|
setNoRouteError(target);
|
|
3444
3519
|
return null;
|
|
3445
3520
|
}
|
|
3446
3521
|
|
|
3522
|
+
const navigation = beginNavigation(target, matched);
|
|
3447
3523
|
setMatchedRouterState(target, matched, { pending: true, error: null });
|
|
3448
3524
|
|
|
3449
3525
|
try {
|
|
3450
3526
|
if (!matched.route?.partial || !partials?.resolve?.(matched.route.partial)) {
|
|
3451
3527
|
const error = new Error(`Route "${target.pathname}" does not have a registered partial.`);
|
|
3452
|
-
|
|
3528
|
+
if (isActiveNavigation(navigation)) {
|
|
3529
|
+
setRouterState({ pending: false, error });
|
|
3530
|
+
}
|
|
3453
3531
|
return null;
|
|
3454
3532
|
}
|
|
3455
3533
|
|
|
3456
|
-
const result = await partials.render(matched.route.partial, matched.params, contextFor(matched));
|
|
3457
|
-
|
|
3534
|
+
const result = await partials.render(matched.route.partial, matched.params, contextFor(matched, navigation));
|
|
3535
|
+
if (!isActiveNavigation(navigation)) {
|
|
3536
|
+
return null;
|
|
3537
|
+
}
|
|
3538
|
+
await applyNavigationResult(result, target, options, navigation);
|
|
3539
|
+
if (!isActiveNavigation(navigation)) {
|
|
3540
|
+
return null;
|
|
3541
|
+
}
|
|
3458
3542
|
setRouterState({ pending: false, error: null });
|
|
3459
3543
|
return result;
|
|
3460
3544
|
} catch (error) {
|
|
3545
|
+
if (!isActiveNavigation(navigation)) {
|
|
3546
|
+
return null;
|
|
3547
|
+
}
|
|
3461
3548
|
setRouterState({ pending: false, error });
|
|
3462
3549
|
throw error;
|
|
3463
3550
|
}
|
|
@@ -3465,26 +3552,43 @@ const __routerModule = (() => {
|
|
|
3465
3552
|
|
|
3466
3553
|
async function fetchRoutePartial(target, options = {}) {
|
|
3467
3554
|
const matched = api.match(target);
|
|
3555
|
+
const navigation = beginNavigation(target, matched);
|
|
3468
3556
|
setMatchedRouterState(target, matched, { pending: true, error: null });
|
|
3469
3557
|
|
|
3470
3558
|
try {
|
|
3471
|
-
const result = await fetchRoute(target.href);
|
|
3472
|
-
|
|
3559
|
+
const result = await fetchRoute(target.href, { signal: navigation.abort });
|
|
3560
|
+
if (!isActiveNavigation(navigation)) {
|
|
3561
|
+
return null;
|
|
3562
|
+
}
|
|
3563
|
+
await applyNavigationResult(result, target, options, navigation);
|
|
3564
|
+
if (!isActiveNavigation(navigation)) {
|
|
3565
|
+
return null;
|
|
3566
|
+
}
|
|
3473
3567
|
setRouterState({ pending: false, error: null });
|
|
3474
3568
|
return result;
|
|
3475
3569
|
} catch (error) {
|
|
3570
|
+
if (!isActiveNavigation(navigation)) {
|
|
3571
|
+
return null;
|
|
3572
|
+
}
|
|
3476
3573
|
setRouterState({ pending: false, error });
|
|
3477
3574
|
throw error;
|
|
3478
3575
|
}
|
|
3479
3576
|
}
|
|
3480
3577
|
|
|
3481
|
-
async function applyNavigationResult(result, target, options) {
|
|
3578
|
+
async function applyNavigationResult(result, target, options, navigation) {
|
|
3579
|
+
if (!isActiveNavigation(navigation)) {
|
|
3580
|
+
return;
|
|
3581
|
+
}
|
|
3482
3582
|
await applyServerResult(result, {
|
|
3483
3583
|
signals: signalRegistry,
|
|
3484
3584
|
loader: loaderInstance,
|
|
3485
3585
|
router: api,
|
|
3486
|
-
cache
|
|
3586
|
+
cache,
|
|
3587
|
+
abort: navigation?.abort
|
|
3487
3588
|
});
|
|
3589
|
+
if (!isActiveNavigation(navigation)) {
|
|
3590
|
+
return;
|
|
3591
|
+
}
|
|
3488
3592
|
if (result?.html != null && !result.boundary && !result.redirect) {
|
|
3489
3593
|
loaderInstance.swap(boundary, result.html);
|
|
3490
3594
|
}
|
|
@@ -3498,14 +3602,15 @@ const __routerModule = (() => {
|
|
|
3498
3602
|
documentRef.defaultView?.history?.pushState?.({}, "", target.href);
|
|
3499
3603
|
}
|
|
3500
3604
|
|
|
3501
|
-
async function fetchRoute(url, { prefetch = false } = {}) {
|
|
3605
|
+
async function fetchRoute(url, { prefetch = false, signal } = {}) {
|
|
3502
3606
|
if (typeof fetchImpl !== "function") {
|
|
3503
3607
|
throw new Error("Router navigation requires a partial registry or fetch.");
|
|
3504
3608
|
}
|
|
3505
3609
|
const response = await fetchImpl(`${routeEndpoint}?to=${encodeURIComponent(String(url))}`, {
|
|
3506
3610
|
headers: {
|
|
3507
3611
|
accept: "application/json, text/html"
|
|
3508
|
-
}
|
|
3612
|
+
},
|
|
3613
|
+
signal
|
|
3509
3614
|
});
|
|
3510
3615
|
if (!response.ok) {
|
|
3511
3616
|
throw new Error(`Route "${url}" failed with ${response.status}.`);
|
|
@@ -3520,7 +3625,7 @@ const __routerModule = (() => {
|
|
|
3520
3625
|
return { boundary, html: await response.text() };
|
|
3521
3626
|
}
|
|
3522
3627
|
|
|
3523
|
-
function contextFor(matched) {
|
|
3628
|
+
function contextFor(matched, navigation) {
|
|
3524
3629
|
return {
|
|
3525
3630
|
params: matched.params,
|
|
3526
3631
|
route: matched.route,
|
|
@@ -3530,8 +3635,26 @@ const __routerModule = (() => {
|
|
|
3530
3635
|
loader: loaderInstance,
|
|
3531
3636
|
server,
|
|
3532
3637
|
cache,
|
|
3533
|
-
abort:
|
|
3638
|
+
abort: navigation?.abort
|
|
3639
|
+
};
|
|
3640
|
+
}
|
|
3641
|
+
|
|
3642
|
+
function beginNavigation(target, matched) {
|
|
3643
|
+
activeNavigation?.controller.abort(new Error(`Router navigation superseded by ${target.pathname}${target.search}.`));
|
|
3644
|
+
const controller = new AbortController();
|
|
3645
|
+
const navigation = {
|
|
3646
|
+
id: ++navigationVersion,
|
|
3647
|
+
controller,
|
|
3648
|
+
abort: controller.signal,
|
|
3649
|
+
target,
|
|
3650
|
+
matched
|
|
3534
3651
|
};
|
|
3652
|
+
activeNavigation = navigation;
|
|
3653
|
+
return navigation;
|
|
3654
|
+
}
|
|
3655
|
+
|
|
3656
|
+
function isActiveNavigation(navigation) {
|
|
3657
|
+
return !destroyed && navigation && activeNavigation?.id === navigation.id && !navigation.abort.aborted;
|
|
3535
3658
|
}
|
|
3536
3659
|
|
|
3537
3660
|
function updateStateFromLocation() {
|
|
@@ -3568,7 +3691,14 @@ const __routerModule = (() => {
|
|
|
3568
3691
|
}
|
|
3569
3692
|
|
|
3570
3693
|
function currentUrl() {
|
|
3571
|
-
return
|
|
3694
|
+
return resolveUrl(documentRef.defaultView?.location?.href ?? "http://localhost/");
|
|
3695
|
+
}
|
|
3696
|
+
|
|
3697
|
+
function resolveUrl(url) {
|
|
3698
|
+
if (url instanceof URL) {
|
|
3699
|
+
return url;
|
|
3700
|
+
}
|
|
3701
|
+
return new URL(String(url), documentRef.defaultView?.location?.href ?? "http://localhost/");
|
|
3572
3702
|
}
|
|
3573
3703
|
|
|
3574
3704
|
function assertActive() {
|
|
@@ -3585,6 +3715,7 @@ const __routerModule = (() => {
|
|
|
3585
3715
|
pattern,
|
|
3586
3716
|
regex,
|
|
3587
3717
|
keys,
|
|
3718
|
+
score: routeScore(pattern),
|
|
3588
3719
|
definition: normalized
|
|
3589
3720
|
};
|
|
3590
3721
|
}
|
|
@@ -3653,6 +3784,28 @@ const __routerModule = (() => {
|
|
|
3653
3784
|
return String(value).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3654
3785
|
}
|
|
3655
3786
|
|
|
3787
|
+
function sortRoutes(routes) {
|
|
3788
|
+
routes.sort((left, right) => right.score - left.score || right.pattern.length - left.pattern.length);
|
|
3789
|
+
}
|
|
3790
|
+
|
|
3791
|
+
function routeScore(pattern) {
|
|
3792
|
+
if (pattern === "*") {
|
|
3793
|
+
return -1;
|
|
3794
|
+
}
|
|
3795
|
+
return pattern
|
|
3796
|
+
.split("/")
|
|
3797
|
+
.filter(Boolean)
|
|
3798
|
+
.reduce((score, segment) => {
|
|
3799
|
+
if (segment === "*") {
|
|
3800
|
+
return score;
|
|
3801
|
+
}
|
|
3802
|
+
if (segment.startsWith(":")) {
|
|
3803
|
+
return score + 2;
|
|
3804
|
+
}
|
|
3805
|
+
return score + 4;
|
|
3806
|
+
}, pattern === "/" ? 3 : 0);
|
|
3807
|
+
}
|
|
3808
|
+
|
|
3656
3809
|
function assertPattern(pattern) {
|
|
3657
3810
|
if (typeof pattern !== "string" || (pattern !== "*" && !pattern.startsWith("/"))) {
|
|
3658
3811
|
throw new TypeError("Route pattern must be a path string or \"*\".");
|
|
@@ -3665,7 +3818,7 @@ const __appModule = (() => {
|
|
|
3665
3818
|
const { createCacheRegistry } = __cacheModule;
|
|
3666
3819
|
const { createComponentRegistry } = __componentModule;
|
|
3667
3820
|
const { createHandlerRegistry } = __handlersModule;
|
|
3668
|
-
const {
|
|
3821
|
+
const { Loader } = __loaderModule;
|
|
3669
3822
|
const { createPartialRegistry } = __partialsModule;
|
|
3670
3823
|
const { createRouteRegistry, createRouter } = __routerModule;
|
|
3671
3824
|
const { createServerRegistry } = __serverModule;
|
|
@@ -3736,7 +3889,7 @@ const __appModule = (() => {
|
|
|
3736
3889
|
let started = false;
|
|
3737
3890
|
let destroyed = false;
|
|
3738
3891
|
|
|
3739
|
-
applySnapshot(signals, browserCache, options.snapshot);
|
|
3892
|
+
applySnapshot(signals, browserCache, options.snapshot ?? (target === "browser" ? readSnapshot(options.root, { attributes }) : undefined));
|
|
3740
3893
|
attachServerCache(server, serverCache);
|
|
3741
3894
|
|
|
3742
3895
|
const runtime = {
|
|
@@ -3764,7 +3917,7 @@ const __appModule = (() => {
|
|
|
3764
3917
|
started = true;
|
|
3765
3918
|
|
|
3766
3919
|
if (target !== "server") {
|
|
3767
|
-
loader = loader ??
|
|
3920
|
+
loader = loader ?? Loader({
|
|
3768
3921
|
root: options.root,
|
|
3769
3922
|
signals,
|
|
3770
3923
|
handlers,
|
|
@@ -3904,6 +4057,38 @@ const __appModule = (() => {
|
|
|
3904
4057
|
|
|
3905
4058
|
const Async = defineApp();
|
|
3906
4059
|
|
|
4060
|
+
function readSnapshot(root = globalThis.document, { attributes } = {}) {
|
|
4061
|
+
const attributeConfig = normalizeAttributeConfig(attributes);
|
|
4062
|
+
const snapshotAttr = attributeName(attributeConfig, "async", "snapshot");
|
|
4063
|
+
const documentRef = root?.ownerDocument ?? root ?? globalThis.document;
|
|
4064
|
+
const rootNode = root ?? documentRef;
|
|
4065
|
+
if (!rootNode?.querySelectorAll && !documentRef?.querySelectorAll) {
|
|
4066
|
+
return {};
|
|
4067
|
+
}
|
|
4068
|
+
|
|
4069
|
+
for (const searchRoot of new Set([rootNode, documentRef])) {
|
|
4070
|
+
if (!searchRoot?.querySelectorAll) {
|
|
4071
|
+
continue;
|
|
4072
|
+
}
|
|
4073
|
+
for (const script of searchRoot.querySelectorAll("script[type='application/json'], script")) {
|
|
4074
|
+
if (!script.hasAttribute?.(snapshotAttr)) {
|
|
4075
|
+
continue;
|
|
4076
|
+
}
|
|
4077
|
+
const source = script.textContent?.trim() ?? "";
|
|
4078
|
+
if (!source) {
|
|
4079
|
+
return {};
|
|
4080
|
+
}
|
|
4081
|
+
try {
|
|
4082
|
+
return JSON.parse(source);
|
|
4083
|
+
} catch (cause) {
|
|
4084
|
+
throw new Error(`Could not parse Async snapshot: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
4085
|
+
}
|
|
4086
|
+
}
|
|
4087
|
+
}
|
|
4088
|
+
|
|
4089
|
+
return {};
|
|
4090
|
+
}
|
|
4091
|
+
|
|
3907
4092
|
function applyUseToRuntime(runtime, normalized) {
|
|
3908
4093
|
applyRegistryUse(runtime.signals, runtime.registry, normalized.signal);
|
|
3909
4094
|
applyRegistryUse(runtime.handlers, runtime.registry, normalized.handler);
|
|
@@ -4064,7 +4249,7 @@ const __appModule = (() => {
|
|
|
4064
4249
|
function escapeScriptJson(value) {
|
|
4065
4250
|
return JSON.stringify(value).replaceAll("<", "\\u003c");
|
|
4066
4251
|
}
|
|
4067
|
-
return { defineApp, createApp, Async };
|
|
4252
|
+
return { defineApp, createApp, readSnapshot, Async };
|
|
4068
4253
|
})();
|
|
4069
4254
|
|
|
4070
4255
|
const __delayModule = (() => {
|
|
@@ -4105,6 +4290,7 @@ const { asyncSignal: asyncSignal } = __asyncSignalModule;
|
|
|
4105
4290
|
const { Async: Async } = __appModule;
|
|
4106
4291
|
const { createApp: createApp } = __appModule;
|
|
4107
4292
|
const { defineApp: defineApp } = __appModule;
|
|
4293
|
+
const { readSnapshot: readSnapshot } = __appModule;
|
|
4108
4294
|
const { attributeName: attributeName } = __attributesModule;
|
|
4109
4295
|
const { defineAttributeConfig: defineAttributeConfig } = __attributesModule;
|
|
4110
4296
|
const { createCacheRegistry: createCacheRegistry } = __cacheModule;
|
|
@@ -4115,6 +4301,7 @@ const { defineComponent: defineComponent } = __componentModule;
|
|
|
4115
4301
|
const { delay: delay } = __delayModule;
|
|
4116
4302
|
const { createHandlerRegistry: createHandlerRegistry } = __handlersModule;
|
|
4117
4303
|
const { html: html } = __htmlModule;
|
|
4304
|
+
const { Loader: Loader } = __loaderModule;
|
|
4118
4305
|
const { AsyncLoader: AsyncLoader } = __loaderModule;
|
|
4119
4306
|
const { createPartialRegistry: createPartialRegistry } = __partialsModule;
|
|
4120
4307
|
const { createRegistryStore: createRegistryStore } = __registryStoreModule;
|
|
@@ -4130,4 +4317,4 @@ const { createSignalRegistry: createSignalRegistry } = __signalsModule;
|
|
|
4130
4317
|
const { effect: effect } = __signalsModule;
|
|
4131
4318
|
const { signal: signal } = __signalsModule;
|
|
4132
4319
|
|
|
4133
|
-
export { asyncSignal, Async, createApp, defineApp, attributeName, defineAttributeConfig, createCacheRegistry, defineCache, component, createComponentRegistry, defineComponent, delay, createHandlerRegistry, html, AsyncLoader, createPartialRegistry, createRegistryStore, createRouteRegistry, createRouter, defineRoute, route, createServerProxy, createServerRegistry, computed, createSignal, createSignalRegistry, effect, signal };
|
|
4320
|
+
export { asyncSignal, Async, createApp, defineApp, readSnapshot, attributeName, defineAttributeConfig, createCacheRegistry, defineCache, component, createComponentRegistry, defineComponent, delay, createHandlerRegistry, html, Loader, AsyncLoader, createPartialRegistry, createRegistryStore, createRouteRegistry, createRouter, defineRoute, route, createServerProxy, createServerRegistry, computed, createSignal, createSignalRegistry, effect, signal };
|