@async/framework 0.9.0 → 0.10.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 +12 -0
- package/README.md +115 -0
- package/browser.d.ts +69 -18
- package/browser.js +733 -71
- package/browser.min.js +1 -1
- package/browser.ts +733 -71
- package/browser.umd.js +733 -71
- package/browser.umd.min.js +1 -1
- package/package.json +1 -1
- package/server.d.ts +69 -18
- package/src/app.js +314 -46
- package/src/browser.js +2 -0
- package/src/component.js +19 -2
- package/src/elements.js +63 -0
- package/src/handlers.js +19 -2
- package/src/index.js +2 -0
- package/src/lazy-registry.js +204 -0
- package/src/loader.js +23 -5
- package/src/partials.js +19 -2
- package/src/registry-store.js +15 -9
- package/src/signals.js +46 -4
package/browser.ts
CHANGED
|
@@ -283,8 +283,217 @@ const __asyncSignalModule = (() => {
|
|
|
283
283
|
return { asyncSignal, isAsyncSignal };
|
|
284
284
|
})();
|
|
285
285
|
|
|
286
|
+
const __lazyRegistryModule = (() => {
|
|
287
|
+
const descriptorTypes = new Set(["handler", "component", "asyncSignal", "partial", "route"]);
|
|
288
|
+
const defaultBaseUrl = "_async";
|
|
289
|
+
|
|
290
|
+
function defineRegistrySnapshot(snapshot = {}) {
|
|
291
|
+
if (!snapshot || typeof snapshot !== "object" || Array.isArray(snapshot)) {
|
|
292
|
+
throw new TypeError("defineRegistrySnapshot(snapshot) requires an object.");
|
|
293
|
+
}
|
|
294
|
+
return snapshot;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function createLazyRegistry(options = {}) {
|
|
298
|
+
const registryAssets = normalizeRegistryAssets(options.registryAssets ?? options.assets);
|
|
299
|
+
const importModule = options.importModule ?? ((url) => import(url));
|
|
300
|
+
const moduleCache = new Map();
|
|
301
|
+
const exportCache = new Map();
|
|
302
|
+
|
|
303
|
+
return {
|
|
304
|
+
registryAssets,
|
|
305
|
+
|
|
306
|
+
resolveUrl(type, id, descriptor) {
|
|
307
|
+
return resolveDescriptorUrl(type, id, descriptor, registryAssets);
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
async resolve(type, id, descriptor) {
|
|
311
|
+
if (!isLazyDescriptor(descriptor)) {
|
|
312
|
+
return descriptor;
|
|
313
|
+
}
|
|
314
|
+
const cacheKey = `${type}:${id}`;
|
|
315
|
+
if (exportCache.has(cacheKey)) {
|
|
316
|
+
return exportCache.get(cacheKey);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const resolved = resolveDescriptorUrl(type, id, descriptor, registryAssets);
|
|
320
|
+
let modulePromise = moduleCache.get(resolved.moduleUrl);
|
|
321
|
+
if (!modulePromise) {
|
|
322
|
+
modulePromise = Promise.resolve(importModule(resolved.moduleUrl));
|
|
323
|
+
moduleCache.set(resolved.moduleUrl, modulePromise);
|
|
324
|
+
}
|
|
325
|
+
const module = await modulePromise;
|
|
326
|
+
const value = resolveExport(module, resolved.exportNames, type, id);
|
|
327
|
+
exportCache.set(cacheKey, value);
|
|
328
|
+
return value;
|
|
329
|
+
},
|
|
330
|
+
|
|
331
|
+
inspect() {
|
|
332
|
+
return {
|
|
333
|
+
registryAssets,
|
|
334
|
+
modules: [...moduleCache.keys()],
|
|
335
|
+
exports: [...exportCache.keys()]
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function normalizeRegistryAssets(options = {}) {
|
|
342
|
+
const baseUrl = normalizeBaseUrl(options.baseUrl ?? defaultBaseUrl);
|
|
343
|
+
const paths = {
|
|
344
|
+
component: "component",
|
|
345
|
+
handler: "handler",
|
|
346
|
+
asyncSignal: "asyncSignal",
|
|
347
|
+
partial: "partial",
|
|
348
|
+
route: "route",
|
|
349
|
+
...(options.paths ?? {})
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
for (const [type, value] of Object.entries(paths)) {
|
|
353
|
+
if (!descriptorTypes.has(type)) {
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
357
|
+
throw new TypeError(`Registry asset path for "${type}" must be a non-empty string.`);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return {
|
|
362
|
+
baseUrl,
|
|
363
|
+
paths
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function isLazyDescriptor(value) {
|
|
368
|
+
return Boolean(
|
|
369
|
+
value &&
|
|
370
|
+
typeof value === "object" &&
|
|
371
|
+
!Array.isArray(value) &&
|
|
372
|
+
typeof value.url === "string"
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function sameRegistryValue(left, right) {
|
|
377
|
+
if (left === right) {
|
|
378
|
+
return true;
|
|
379
|
+
}
|
|
380
|
+
if (isLazyDescriptor(left) && isLazyDescriptor(right)) {
|
|
381
|
+
return stableStringify(left) === stableStringify(right);
|
|
382
|
+
}
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function publicRegistryValue(value, id) {
|
|
387
|
+
if (isLazyDescriptor(value)) {
|
|
388
|
+
return { ...value };
|
|
389
|
+
}
|
|
390
|
+
return { id };
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function resolveDescriptorUrl(type, id, descriptor, registryAssets) {
|
|
394
|
+
if (!descriptorTypes.has(type)) {
|
|
395
|
+
throw new Error(`Registry type "${type}" does not support lazy descriptors.`);
|
|
396
|
+
}
|
|
397
|
+
if (!isLazyDescriptor(descriptor)) {
|
|
398
|
+
throw new TypeError(`Registry descriptor for "${type}:${id}" requires a url.`);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const { path, hash } = splitHash(descriptor.url);
|
|
402
|
+
const moduleUrl = resolveModuleUrl(type, path, registryAssets);
|
|
403
|
+
const exportNames = hash
|
|
404
|
+
? [hash]
|
|
405
|
+
: inferredExportNames(id, path);
|
|
406
|
+
|
|
407
|
+
return {
|
|
408
|
+
moduleUrl,
|
|
409
|
+
exportNames,
|
|
410
|
+
url: hash ? `${moduleUrl}#${hash}` : moduleUrl
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function resolveModuleUrl(type, path, registryAssets) {
|
|
415
|
+
if (isAbsoluteUrl(path) || path.startsWith("/") || path.startsWith("./") || path.startsWith("../")) {
|
|
416
|
+
return path;
|
|
417
|
+
}
|
|
418
|
+
const typePath = registryAssets.paths[type] ?? type;
|
|
419
|
+
return joinUrl(registryAssets.baseUrl, typePath, path);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function resolveExport(module, exportNames, type, id) {
|
|
423
|
+
for (const name of exportNames) {
|
|
424
|
+
if (name in module) {
|
|
425
|
+
return module[name];
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
throw new Error(`Lazy ${type} "${id}" did not export ${exportNames.map((name) => `"${name}"`).join(", ")}.`);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function inferredExportNames(id, path) {
|
|
432
|
+
const names = [];
|
|
433
|
+
const leaf = id.split(".").filter(Boolean).at(-1);
|
|
434
|
+
const basename = path
|
|
435
|
+
.split("/")
|
|
436
|
+
.filter(Boolean)
|
|
437
|
+
.at(-1)
|
|
438
|
+
?.replace(/\.[^.]+$/, "");
|
|
439
|
+
for (const name of [leaf, basename, "default"]) {
|
|
440
|
+
if (name && !names.includes(name)) {
|
|
441
|
+
names.push(name);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return names;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function splitHash(url) {
|
|
448
|
+
const index = url.indexOf("#");
|
|
449
|
+
if (index === -1) {
|
|
450
|
+
return { path: url, hash: "" };
|
|
451
|
+
}
|
|
452
|
+
return {
|
|
453
|
+
path: url.slice(0, index),
|
|
454
|
+
hash: url.slice(index + 1)
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
function normalizeBaseUrl(baseUrl) {
|
|
459
|
+
if (typeof baseUrl !== "string" || baseUrl.length === 0) {
|
|
460
|
+
throw new TypeError("registryAssets.baseUrl must be a non-empty string.");
|
|
461
|
+
}
|
|
462
|
+
if (isAbsoluteUrl(baseUrl) || baseUrl.startsWith("/") || baseUrl.startsWith("./") || baseUrl.startsWith("../")) {
|
|
463
|
+
return stripTrailingSlash(baseUrl);
|
|
464
|
+
}
|
|
465
|
+
return `/${stripSlashes(baseUrl)}`;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function joinUrl(...parts) {
|
|
469
|
+
const [first, ...rest] = parts;
|
|
470
|
+
return [stripTrailingSlash(first), ...rest.map(stripSlashes)].filter(Boolean).join("/");
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
function stripSlashes(value) {
|
|
474
|
+
return String(value).replace(/^\/+|\/+$/g, "");
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function stripTrailingSlash(value) {
|
|
478
|
+
return String(value).replace(/\/+$/g, "");
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function isAbsoluteUrl(value) {
|
|
482
|
+
return /^[A-Za-z][A-Za-z\d+.-]*:/.test(value);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function stableStringify(value) {
|
|
486
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
487
|
+
return JSON.stringify(value);
|
|
488
|
+
}
|
|
489
|
+
return JSON.stringify(Object.keys(value).sort().map((key) => [key, value[key]]));
|
|
490
|
+
}
|
|
491
|
+
return { defineRegistrySnapshot, createLazyRegistry, normalizeRegistryAssets, isLazyDescriptor, sameRegistryValue, publicRegistryValue };
|
|
492
|
+
})();
|
|
493
|
+
|
|
286
494
|
const __registryStoreModule = (() => {
|
|
287
|
-
const
|
|
495
|
+
const { publicRegistryValue } = __lazyRegistryModule;
|
|
496
|
+
const declarationTypes = new Set(["signal", "handler", "server", "partial", "route", "component", "asyncSignal"]);
|
|
288
497
|
const cacheTypes = new Set(["cache.browser", "cache.server"]);
|
|
289
498
|
const cacheEntryTypes = new Set(["cache.browser.entries", "cache.server.entries"]);
|
|
290
499
|
const allTypes = new Set([...declarationTypes, ...cacheTypes, ...cacheEntryTypes]);
|
|
@@ -371,11 +580,12 @@ const __registryStoreModule = (() => {
|
|
|
371
580
|
const snapshotTarget = snapshotOptions.target ?? target;
|
|
372
581
|
return {
|
|
373
582
|
signal: snapshotSignals(backing.signal),
|
|
374
|
-
handler: snapshotDescriptors(backing.handler
|
|
375
|
-
server: snapshotDescriptors(backing.server
|
|
376
|
-
partial: snapshotDescriptors(backing.partial
|
|
583
|
+
handler: snapshotDescriptors(backing.handler),
|
|
584
|
+
server: snapshotDescriptors(backing.server),
|
|
585
|
+
partial: snapshotDescriptors(backing.partial),
|
|
377
586
|
route: snapshotPlain(backing.route),
|
|
378
|
-
component: snapshotDescriptors(backing.component
|
|
587
|
+
component: snapshotDescriptors(backing.component),
|
|
588
|
+
asyncSignal: snapshotDescriptors(backing.asyncSignal),
|
|
379
589
|
cache: {
|
|
380
590
|
browser: snapshotPlain(backing.cache.browser),
|
|
381
591
|
server: snapshotPlain(backing.cache.server)
|
|
@@ -395,6 +605,7 @@ const __registryStoreModule = (() => {
|
|
|
395
605
|
partial: Object.fromEntries(backing.partial),
|
|
396
606
|
route: Object.fromEntries(backing.route),
|
|
397
607
|
component: Object.fromEntries(backing.component),
|
|
608
|
+
asyncSignal: Object.fromEntries(backing.asyncSignal),
|
|
398
609
|
cache: {
|
|
399
610
|
browser: Object.fromEntries(backing.cache.browser),
|
|
400
611
|
server: Object.fromEntries(backing.cache.server)
|
|
@@ -454,6 +665,7 @@ const __registryStoreModule = (() => {
|
|
|
454
665
|
partial: new Map(),
|
|
455
666
|
route: new Map(),
|
|
456
667
|
component: new Map(),
|
|
668
|
+
asyncSignal: new Map(),
|
|
457
669
|
cache: {
|
|
458
670
|
browser: new Map(),
|
|
459
671
|
server: new Map()
|
|
@@ -472,6 +684,7 @@ const __registryStoreModule = (() => {
|
|
|
472
684
|
registry.registerMany("partial", initial.partial);
|
|
473
685
|
registry.registerMany("route", initial.route);
|
|
474
686
|
registry.registerMany("component", initial.component);
|
|
687
|
+
registry.registerMany("asyncSignal", initial.asyncSignal);
|
|
475
688
|
registry.registerMany("cache.browser", initial.cache?.browser);
|
|
476
689
|
registry.registerMany("cache.server", initial.cache?.server);
|
|
477
690
|
|
|
@@ -499,7 +712,7 @@ const __registryStoreModule = (() => {
|
|
|
499
712
|
|
|
500
713
|
function publicValue(type, id, value, options) {
|
|
501
714
|
if (type === "server" && options.target === "browser") {
|
|
502
|
-
return
|
|
715
|
+
return publicRegistryValue(value, id);
|
|
503
716
|
}
|
|
504
717
|
if (cacheEntryTypes.has(type)) {
|
|
505
718
|
return value?.value;
|
|
@@ -519,10 +732,10 @@ const __registryStoreModule = (() => {
|
|
|
519
732
|
return snapshot;
|
|
520
733
|
}
|
|
521
734
|
|
|
522
|
-
function snapshotDescriptors(map
|
|
735
|
+
function snapshotDescriptors(map) {
|
|
523
736
|
const snapshot = {};
|
|
524
|
-
for (const id of map
|
|
525
|
-
snapshot[id] =
|
|
737
|
+
for (const [id, value] of map) {
|
|
738
|
+
snapshot[id] = publicRegistryValue(value, id);
|
|
526
739
|
}
|
|
527
740
|
return snapshot;
|
|
528
741
|
}
|
|
@@ -799,6 +1012,7 @@ const __attributesModule = (() => {
|
|
|
799
1012
|
const __signalsModule = (() => {
|
|
800
1013
|
const { asyncSignal: createAsyncSignal, isAsyncSignal } = __asyncSignalModule;
|
|
801
1014
|
const { attachRegistryInspection, createRegistryStore } = __registryStoreModule;
|
|
1015
|
+
const { createLazyRegistry, isLazyDescriptor } = __lazyRegistryModule;
|
|
802
1016
|
const signalKind = Symbol.for("@async/framework.signal");
|
|
803
1017
|
const computedKind = Symbol.for("@async/framework.computed");
|
|
804
1018
|
const effectKind = Symbol.for("@async/framework.effect");
|
|
@@ -920,6 +1134,8 @@ const __signalsModule = (() => {
|
|
|
920
1134
|
const registryStore = options.registry ?? createRegistryStore();
|
|
921
1135
|
const type = options.type ?? "signal";
|
|
922
1136
|
const entries = registryStore._map(type);
|
|
1137
|
+
const asyncDescriptors = registryStore._map("asyncSignal");
|
|
1138
|
+
const lazyRegistry = options.lazyRegistry ?? createLazyRegistry(options);
|
|
923
1139
|
const registryCleanups = new Map();
|
|
924
1140
|
const runtimeContext = {};
|
|
925
1141
|
const boundEntries = new Set();
|
|
@@ -960,6 +1176,7 @@ const __signalsModule = (() => {
|
|
|
960
1176
|
|
|
961
1177
|
ensure(id, initial) {
|
|
962
1178
|
assertId(id);
|
|
1179
|
+
materializeAsyncSignal(id);
|
|
963
1180
|
if (!entries.has(id)) {
|
|
964
1181
|
registry.register(id, createSignal(initial));
|
|
965
1182
|
}
|
|
@@ -967,18 +1184,18 @@ const __signalsModule = (() => {
|
|
|
967
1184
|
},
|
|
968
1185
|
|
|
969
1186
|
has(id) {
|
|
970
|
-
return entries.has(id);
|
|
1187
|
+
return entries.has(id) || asyncDescriptors.has(id);
|
|
971
1188
|
},
|
|
972
1189
|
|
|
973
1190
|
get(path) {
|
|
974
|
-
const parsed =
|
|
1191
|
+
const parsed = parseRegistryPath(path);
|
|
975
1192
|
track(parsed.path);
|
|
976
1193
|
const entry = requireEntry(entries, parsed.id);
|
|
977
1194
|
return readEntry(entry, parsed.parts);
|
|
978
1195
|
},
|
|
979
1196
|
|
|
980
1197
|
set(path, value) {
|
|
981
|
-
const parsed =
|
|
1198
|
+
const parsed = parseRegistryPath(path);
|
|
982
1199
|
const entry = requireEntry(entries, parsed.id);
|
|
983
1200
|
if (parsed.parts.length === 0) {
|
|
984
1201
|
return entry.set(value);
|
|
@@ -997,6 +1214,7 @@ const __signalsModule = (() => {
|
|
|
997
1214
|
|
|
998
1215
|
ref(id) {
|
|
999
1216
|
assertId(id);
|
|
1217
|
+
materializeAsyncSignal(id);
|
|
1000
1218
|
return createRef(registry, id);
|
|
1001
1219
|
},
|
|
1002
1220
|
|
|
@@ -1004,7 +1222,7 @@ const __signalsModule = (() => {
|
|
|
1004
1222
|
if (typeof fn !== "function") {
|
|
1005
1223
|
throw new TypeError("subscribe(path, fn) requires a function.");
|
|
1006
1224
|
}
|
|
1007
|
-
const parsed =
|
|
1225
|
+
const parsed = parseRegistryPath(path);
|
|
1008
1226
|
const entry = requireEntry(entries, parsed.id);
|
|
1009
1227
|
const subscriptionId = ++subscriptionCounter;
|
|
1010
1228
|
return entry.subscribe(() => {
|
|
@@ -1110,6 +1328,7 @@ const __signalsModule = (() => {
|
|
|
1110
1328
|
},
|
|
1111
1329
|
|
|
1112
1330
|
_entry(id) {
|
|
1331
|
+
materializeAsyncSignal(id);
|
|
1113
1332
|
return requireEntry(entries, id);
|
|
1114
1333
|
},
|
|
1115
1334
|
|
|
@@ -1149,6 +1368,42 @@ const __signalsModule = (() => {
|
|
|
1149
1368
|
}
|
|
1150
1369
|
}
|
|
1151
1370
|
|
|
1371
|
+
function parseRegistryPath(path) {
|
|
1372
|
+
if (typeof path !== "string" || path.length === 0) {
|
|
1373
|
+
throw new TypeError("Signal path must be a non-empty string.");
|
|
1374
|
+
}
|
|
1375
|
+
const segments = path.split(".");
|
|
1376
|
+
for (let end = segments.length; end > 0; end -= 1) {
|
|
1377
|
+
const id = segments.slice(0, end).join(".");
|
|
1378
|
+
if (entries.has(id) || asyncDescriptors.has(id)) {
|
|
1379
|
+
materializeAsyncSignal(id);
|
|
1380
|
+
return { id, parts: segments.slice(end), path };
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
const [id, ...parts] = segments;
|
|
1384
|
+
return { id, parts, path };
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
function materializeAsyncSignal(id) {
|
|
1388
|
+
if (entries.has(id) || !asyncDescriptors.has(id)) {
|
|
1389
|
+
return;
|
|
1390
|
+
}
|
|
1391
|
+
const descriptor = asyncDescriptors.get(id);
|
|
1392
|
+
if (!isLazyDescriptor(descriptor) && typeof descriptor !== "function") {
|
|
1393
|
+
throw new TypeError(`Async signal "${id}" must be a function or lazy descriptor.`);
|
|
1394
|
+
}
|
|
1395
|
+
const loader = async function runLazyAsyncSignal(...args) {
|
|
1396
|
+
const resolved = await lazyRegistry.resolve("asyncSignal", id, descriptor);
|
|
1397
|
+
if (typeof resolved !== "function") {
|
|
1398
|
+
throw new TypeError(`Async signal "${id}" did not resolve to a function.`);
|
|
1399
|
+
}
|
|
1400
|
+
return resolved.apply(this, args);
|
|
1401
|
+
};
|
|
1402
|
+
const entry = createAsyncSignal(id, loader);
|
|
1403
|
+
entries.set(id, entry);
|
|
1404
|
+
bindEntry(id, entry);
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1152
1407
|
function scheduleCallback(fn, options = {}) {
|
|
1153
1408
|
const scheduler = options.scheduler;
|
|
1154
1409
|
if (!scheduler || options.phase === "sync") {
|
|
@@ -1514,6 +1769,7 @@ const __componentModule = (() => {
|
|
|
1514
1769
|
const { attributeName } = __attributesModule;
|
|
1515
1770
|
const { escapeHtml, rawHtml, renderTemplate } = __htmlModule;
|
|
1516
1771
|
const { attachRegistryInspection, createRegistryStore } = __registryStoreModule;
|
|
1772
|
+
const { createLazyRegistry, isLazyDescriptor } = __lazyRegistryModule;
|
|
1517
1773
|
const componentKind = Symbol.for("@async/framework.component");
|
|
1518
1774
|
let componentCounter = 0;
|
|
1519
1775
|
|
|
@@ -1534,13 +1790,15 @@ const __componentModule = (() => {
|
|
|
1534
1790
|
const registryStore = options.registry ?? createRegistryStore();
|
|
1535
1791
|
const type = options.type ?? "component";
|
|
1536
1792
|
const entries = registryStore._map(type);
|
|
1793
|
+
const lazyRegistry = options.lazyRegistry ?? createLazyRegistry(options);
|
|
1794
|
+
const lazyComponents = new Map();
|
|
1537
1795
|
|
|
1538
1796
|
const registry = attachRegistryInspection({
|
|
1539
1797
|
register(id, Component) {
|
|
1540
1798
|
if (typeof id !== "string" || id.length === 0) {
|
|
1541
1799
|
throw new TypeError("Component id must be a non-empty string.");
|
|
1542
1800
|
}
|
|
1543
|
-
if (!isComponent(Component) && typeof Component !== "function") {
|
|
1801
|
+
if (!isComponent(Component) && typeof Component !== "function" && !isLazyDescriptor(Component)) {
|
|
1544
1802
|
throw new TypeError(`Component "${id}" must be a component function.`);
|
|
1545
1803
|
}
|
|
1546
1804
|
if (entries.has(id)) {
|
|
@@ -1561,6 +1819,7 @@ const __componentModule = (() => {
|
|
|
1561
1819
|
if (typeof id !== "string" || id.length === 0) {
|
|
1562
1820
|
throw new TypeError("Component id must be a non-empty string.");
|
|
1563
1821
|
}
|
|
1822
|
+
lazyComponents.delete(id);
|
|
1564
1823
|
return entries.delete(id);
|
|
1565
1824
|
},
|
|
1566
1825
|
|
|
@@ -1568,7 +1827,20 @@ const __componentModule = (() => {
|
|
|
1568
1827
|
if (typeof id !== "string" || id.length === 0) {
|
|
1569
1828
|
throw new TypeError("Component id must be a non-empty string.");
|
|
1570
1829
|
}
|
|
1571
|
-
|
|
1830
|
+
const Component = entries.get(id);
|
|
1831
|
+
if (!isLazyDescriptor(Component)) {
|
|
1832
|
+
return Component;
|
|
1833
|
+
}
|
|
1834
|
+
if (!lazyComponents.has(id)) {
|
|
1835
|
+
lazyComponents.set(id, async function LazyComponent(...args) {
|
|
1836
|
+
const resolved = await lazyRegistry.resolve(type, id, Component);
|
|
1837
|
+
if (typeof resolved !== "function") {
|
|
1838
|
+
throw new TypeError(`Component "${id}" did not resolve to a function.`);
|
|
1839
|
+
}
|
|
1840
|
+
return resolved.apply(this, args);
|
|
1841
|
+
});
|
|
1842
|
+
}
|
|
1843
|
+
return lazyComponents.get(id);
|
|
1572
1844
|
},
|
|
1573
1845
|
|
|
1574
1846
|
_adoptMany() {
|
|
@@ -2233,6 +2505,7 @@ const __serverModule = (() => {
|
|
|
2233
2505
|
const __handlersModule = (() => {
|
|
2234
2506
|
const { applyServerResult, defaultInput, resolveServerCommandArguments, unwrapServerResult } = __serverModule;
|
|
2235
2507
|
const { attachRegistryInspection, createRegistryStore } = __registryStoreModule;
|
|
2508
|
+
const { createLazyRegistry, isLazyDescriptor } = __lazyRegistryModule;
|
|
2236
2509
|
const builtInTokens = new Set(["prevent", "preventDefault", "stopPropagation", "stopImmediatePropagation"]);
|
|
2237
2510
|
const builtInHandlers = {
|
|
2238
2511
|
prevent: preventDefault,
|
|
@@ -2253,11 +2526,13 @@ const __handlersModule = (() => {
|
|
|
2253
2526
|
const registryStore = options.registry ?? createRegistryStore();
|
|
2254
2527
|
const type = options.type ?? "handler";
|
|
2255
2528
|
const handlers = registryStore._map(type);
|
|
2529
|
+
const lazyRegistry = options.lazyRegistry ?? createLazyRegistry(options);
|
|
2530
|
+
const lazyHandlers = new Map();
|
|
2256
2531
|
|
|
2257
2532
|
const registry = attachRegistryInspection({
|
|
2258
2533
|
register(id, fn) {
|
|
2259
2534
|
assertId(id);
|
|
2260
|
-
if (typeof fn !== "function") {
|
|
2535
|
+
if (typeof fn !== "function" && !isLazyDescriptor(fn)) {
|
|
2261
2536
|
throw new TypeError(`Handler "${id}" must be a function.`);
|
|
2262
2537
|
}
|
|
2263
2538
|
if (handlers.has(id)) {
|
|
@@ -2276,12 +2551,26 @@ const __handlersModule = (() => {
|
|
|
2276
2551
|
|
|
2277
2552
|
unregister(id) {
|
|
2278
2553
|
assertId(id);
|
|
2554
|
+
lazyHandlers.delete(id);
|
|
2279
2555
|
return handlers.delete(id);
|
|
2280
2556
|
},
|
|
2281
2557
|
|
|
2282
2558
|
resolve(id) {
|
|
2283
2559
|
assertId(id);
|
|
2284
|
-
|
|
2560
|
+
const handler = handlers.get(id);
|
|
2561
|
+
if (!isLazyDescriptor(handler)) {
|
|
2562
|
+
return handler;
|
|
2563
|
+
}
|
|
2564
|
+
if (!lazyHandlers.has(id)) {
|
|
2565
|
+
lazyHandlers.set(id, async function runLazyHandler(...args) {
|
|
2566
|
+
const resolved = await lazyRegistry.resolve(type, id, handler);
|
|
2567
|
+
if (typeof resolved !== "function") {
|
|
2568
|
+
throw new TypeError(`Handler "${id}" did not resolve to a function.`);
|
|
2569
|
+
}
|
|
2570
|
+
return resolved.apply(this, args);
|
|
2571
|
+
});
|
|
2572
|
+
}
|
|
2573
|
+
return lazyHandlers.get(id);
|
|
2285
2574
|
},
|
|
2286
2575
|
|
|
2287
2576
|
async run(ref, context = {}) {
|
|
@@ -3071,7 +3360,7 @@ const __loaderModule = (() => {
|
|
|
3071
3360
|
if (renderingBoundaries.has(boundary)) {
|
|
3072
3361
|
continue;
|
|
3073
3362
|
}
|
|
3074
|
-
const id =
|
|
3363
|
+
const id = boundaryIdFor(boundary, attributeConfig);
|
|
3075
3364
|
if (id == null) {
|
|
3076
3365
|
continue;
|
|
3077
3366
|
}
|
|
@@ -3388,19 +3677,26 @@ const __loaderModule = (() => {
|
|
|
3388
3677
|
function collectBoundaryTemplates(boundary, id, attributeConfig) {
|
|
3389
3678
|
const templates = {};
|
|
3390
3679
|
for (const template of [...boundary.children].filter((child) => child.tagName === "TEMPLATE")) {
|
|
3391
|
-
if (
|
|
3680
|
+
if (templateMatchesState(template, "loading", id, boundary, attributeConfig)) {
|
|
3392
3681
|
templates.loading = template;
|
|
3393
3682
|
}
|
|
3394
|
-
if (
|
|
3683
|
+
if (templateMatchesState(template, "ready", id, boundary, attributeConfig)) {
|
|
3395
3684
|
templates.ready = template;
|
|
3396
3685
|
}
|
|
3397
|
-
if (
|
|
3686
|
+
if (templateMatchesState(template, "error", id, boundary, attributeConfig)) {
|
|
3398
3687
|
templates.error = template;
|
|
3399
3688
|
}
|
|
3400
3689
|
}
|
|
3401
3690
|
return templates;
|
|
3402
3691
|
}
|
|
3403
3692
|
|
|
3693
|
+
function templateMatchesState(template, state, id, boundary, attributeConfig) {
|
|
3694
|
+
if (readAttribute(template, attributeConfig, "async", state) === id) {
|
|
3695
|
+
return true;
|
|
3696
|
+
}
|
|
3697
|
+
return isAsyncSuspense(boundary) && template.hasAttribute?.(state);
|
|
3698
|
+
}
|
|
3699
|
+
|
|
3404
3700
|
function chooseBoundaryTemplate(templates, status) {
|
|
3405
3701
|
if (status === "ready") {
|
|
3406
3702
|
return templates.ready ?? templates.loading ?? templates.error;
|
|
@@ -3448,13 +3744,24 @@ const __loaderModule = (() => {
|
|
|
3448
3744
|
|
|
3449
3745
|
function findBoundary(root, boundaryId, attributeConfig) {
|
|
3450
3746
|
for (const element of elementsIn(root)) {
|
|
3451
|
-
if (
|
|
3747
|
+
if (boundaryIdFor(element, attributeConfig) === String(boundaryId)) {
|
|
3452
3748
|
return element;
|
|
3453
3749
|
}
|
|
3454
3750
|
}
|
|
3455
3751
|
return null;
|
|
3456
3752
|
}
|
|
3457
3753
|
|
|
3754
|
+
function boundaryIdFor(element, attributeConfig) {
|
|
3755
|
+
if (isAsyncSuspense(element) && element.hasAttribute?.("for")) {
|
|
3756
|
+
return element.getAttribute("for");
|
|
3757
|
+
}
|
|
3758
|
+
return readAttribute(element, attributeConfig, "async", "boundary");
|
|
3759
|
+
}
|
|
3760
|
+
|
|
3761
|
+
function isAsyncSuspense(element) {
|
|
3762
|
+
return element?.tagName === "ASYNC-SUSPENSE";
|
|
3763
|
+
}
|
|
3764
|
+
|
|
3458
3765
|
function toFragment(value, documentRef) {
|
|
3459
3766
|
if (value?.nodeType === 11) {
|
|
3460
3767
|
return value;
|
|
@@ -3487,15 +3794,18 @@ const __loaderModule = (() => {
|
|
|
3487
3794
|
const __partialsModule = (() => {
|
|
3488
3795
|
const { isTemplateResult, renderTemplate } = __htmlModule;
|
|
3489
3796
|
const { attachRegistryInspection, createRegistryStore } = __registryStoreModule;
|
|
3797
|
+
const { createLazyRegistry, isLazyDescriptor } = __lazyRegistryModule;
|
|
3490
3798
|
function createPartialRegistry(initialMap = {}, options = {}) {
|
|
3491
3799
|
const registryStore = options.registry ?? createRegistryStore();
|
|
3492
3800
|
const type = options.type ?? "partial";
|
|
3493
3801
|
const entries = registryStore._map(type);
|
|
3802
|
+
const lazyRegistry = options.lazyRegistry ?? createLazyRegistry(options);
|
|
3803
|
+
const lazyPartials = new Map();
|
|
3494
3804
|
|
|
3495
3805
|
const registry = attachRegistryInspection({
|
|
3496
3806
|
register(id, fn) {
|
|
3497
3807
|
assertId(id);
|
|
3498
|
-
if (typeof fn !== "function") {
|
|
3808
|
+
if (typeof fn !== "function" && !isLazyDescriptor(fn)) {
|
|
3499
3809
|
throw new TypeError(`Partial "${id}" must be a function.`);
|
|
3500
3810
|
}
|
|
3501
3811
|
if (entries.has(id)) {
|
|
@@ -3514,12 +3824,26 @@ const __partialsModule = (() => {
|
|
|
3514
3824
|
|
|
3515
3825
|
unregister(id) {
|
|
3516
3826
|
assertId(id);
|
|
3827
|
+
lazyPartials.delete(id);
|
|
3517
3828
|
return entries.delete(id);
|
|
3518
3829
|
},
|
|
3519
3830
|
|
|
3520
3831
|
resolve(id) {
|
|
3521
3832
|
assertId(id);
|
|
3522
|
-
|
|
3833
|
+
const partial = entries.get(id);
|
|
3834
|
+
if (!isLazyDescriptor(partial)) {
|
|
3835
|
+
return partial;
|
|
3836
|
+
}
|
|
3837
|
+
if (!lazyPartials.has(id)) {
|
|
3838
|
+
lazyPartials.set(id, async function runLazyPartial(...args) {
|
|
3839
|
+
const resolved = await lazyRegistry.resolve(type, id, partial);
|
|
3840
|
+
if (typeof resolved !== "function") {
|
|
3841
|
+
throw new TypeError(`Partial "${id}" did not resolve to a function.`);
|
|
3842
|
+
}
|
|
3843
|
+
return resolved.apply(this, args);
|
|
3844
|
+
});
|
|
3845
|
+
}
|
|
3846
|
+
return lazyPartials.get(id);
|
|
3523
3847
|
},
|
|
3524
3848
|
|
|
3525
3849
|
async render(id, props = {}, context = {}) {
|
|
@@ -4189,7 +4513,8 @@ const __appModule = (() => {
|
|
|
4189
4513
|
const { createSignal, createSignalRegistry } = __signalsModule;
|
|
4190
4514
|
const { createRegistryStore } = __registryStoreModule;
|
|
4191
4515
|
const { attributeName, normalizeAttributeConfig } = __attributesModule;
|
|
4192
|
-
const
|
|
4516
|
+
const { createLazyRegistry, defineRegistrySnapshot, sameRegistryValue } = __lazyRegistryModule;
|
|
4517
|
+
const registryTypes = new Set(["signal", "handler", "server", "partial", "route", "component", "asyncSignal"]);
|
|
4193
4518
|
|
|
4194
4519
|
function defineApp(initial, options = {}) {
|
|
4195
4520
|
const registry = createRegistryStore(undefined, { target: "browser" });
|
|
@@ -4218,6 +4543,27 @@ const __appModule = (() => {
|
|
|
4218
4543
|
return runtime;
|
|
4219
4544
|
},
|
|
4220
4545
|
|
|
4546
|
+
attachRoot(root) {
|
|
4547
|
+
return ensureRuntime(app).attachRoot(root);
|
|
4548
|
+
},
|
|
4549
|
+
|
|
4550
|
+
detachRoot(root) {
|
|
4551
|
+
return app.runtime?.detachRoot(root) ?? app;
|
|
4552
|
+
},
|
|
4553
|
+
|
|
4554
|
+
applySnapshot(snapshot, snapshotOptions = {}) {
|
|
4555
|
+
if (app.runtime) {
|
|
4556
|
+
app.runtime.applySnapshot(snapshot, snapshotOptions);
|
|
4557
|
+
return app;
|
|
4558
|
+
}
|
|
4559
|
+
appendSnapshotDeclarations(registry, snapshot, snapshotOptions);
|
|
4560
|
+
return app;
|
|
4561
|
+
},
|
|
4562
|
+
|
|
4563
|
+
inspectRoots() {
|
|
4564
|
+
return app.runtime?.inspectRoots() ?? { count: 0, roots: [] };
|
|
4565
|
+
},
|
|
4566
|
+
|
|
4221
4567
|
_attach(runtime) {
|
|
4222
4568
|
runtimes.add(runtime);
|
|
4223
4569
|
return () => app._detach(runtime);
|
|
@@ -4243,23 +4589,32 @@ const __appModule = (() => {
|
|
|
4243
4589
|
});
|
|
4244
4590
|
const ownsScheduler = !options.scheduler && !options.loader?.scheduler;
|
|
4245
4591
|
const attributes = normalizeAttributeConfig(options.attributes);
|
|
4592
|
+
const lazyRegistry = options.lazyRegistry ?? createLazyRegistry({
|
|
4593
|
+
registryAssets: options.registryAssets,
|
|
4594
|
+
importModule: options.importModule
|
|
4595
|
+
});
|
|
4246
4596
|
const registry = options.registry ?? app.registry.view({ target });
|
|
4247
|
-
const signals = options.signals ?? createSignalRegistry(undefined, { registry, type: "signal" });
|
|
4248
|
-
const handlers = options.handlers ?? createHandlerRegistry(undefined, { registry, type: "handler" });
|
|
4597
|
+
const signals = options.signals ?? createSignalRegistry(undefined, { registry, type: "signal", lazyRegistry });
|
|
4598
|
+
const handlers = options.handlers ?? createHandlerRegistry(undefined, { registry, type: "handler", lazyRegistry });
|
|
4249
4599
|
const serverCache = createCacheRegistry(undefined, { registry, type: "cache.server" });
|
|
4250
4600
|
const browserCache = createCacheRegistry(undefined, { registry, type: "cache.browser" });
|
|
4251
4601
|
const serverFactory = options.serverFactory ?? createServerReferenceRegistry;
|
|
4252
4602
|
const server = options.server ?? serverFactory(undefined, { registry, type: "server" });
|
|
4253
|
-
const partials = options.partials ?? createPartialRegistry(undefined, { registry, type: "partial" });
|
|
4603
|
+
const partials = options.partials ?? createPartialRegistry(undefined, { registry, type: "partial", lazyRegistry });
|
|
4254
4604
|
const routes = options.routes ?? createRouteRegistry(undefined, { registry, type: "route" });
|
|
4255
|
-
const components = options.components ?? createComponentRegistry(undefined, { registry, type: "component" });
|
|
4605
|
+
const components = options.components ?? createComponentRegistry(undefined, { registry, type: "component", lazyRegistry });
|
|
4606
|
+
const hasStartupRoot = options.loader || Object.hasOwn(options, "root");
|
|
4607
|
+
const startupRoot = hasStartupRoot ? options.root : null;
|
|
4256
4608
|
let loader = options.loader;
|
|
4257
4609
|
let router = options.router;
|
|
4610
|
+
let routerStarted = false;
|
|
4258
4611
|
let detach = () => {};
|
|
4259
4612
|
let started = false;
|
|
4260
4613
|
let destroyed = false;
|
|
4614
|
+
const rootLoaders = new Map();
|
|
4261
4615
|
|
|
4262
|
-
|
|
4616
|
+
const snapshotRoot = startupRoot ?? globalThis.document;
|
|
4617
|
+
const initialSnapshot = options.snapshot ?? (target === "browser" ? readSnapshot(snapshotRoot, { attributes }) : undefined);
|
|
4263
4618
|
attachServerCache(server, serverCache);
|
|
4264
4619
|
|
|
4265
4620
|
const runtime = {
|
|
@@ -4288,54 +4643,112 @@ const __appModule = (() => {
|
|
|
4288
4643
|
started = true;
|
|
4289
4644
|
|
|
4290
4645
|
if (target !== "server") {
|
|
4291
|
-
loader = loader ?? Loader({
|
|
4292
|
-
root: options.root,
|
|
4293
|
-
signals,
|
|
4294
|
-
handlers,
|
|
4295
|
-
server,
|
|
4296
|
-
cache: browserCache,
|
|
4297
|
-
scheduler,
|
|
4298
|
-
attributes
|
|
4299
|
-
});
|
|
4300
|
-
runtime.loader = loader;
|
|
4301
|
-
|
|
4302
4646
|
configureServerContext({ cache: browserCache });
|
|
4303
4647
|
signals._setContext?.({ server, loader, cache: browserCache, scheduler });
|
|
4304
4648
|
|
|
4305
|
-
loader
|
|
4649
|
+
if (loader) {
|
|
4650
|
+
registerRootLoader(loader.root, loader);
|
|
4651
|
+
loader.start();
|
|
4652
|
+
startRouterFor(loader.root);
|
|
4653
|
+
} else if (startupRoot != null) {
|
|
4654
|
+
runtime.attachRoot(startupRoot);
|
|
4655
|
+
}
|
|
4656
|
+
} else {
|
|
4657
|
+
configureServerContext({ cache: serverCache });
|
|
4658
|
+
signals._setContext?.({ server, cache: serverCache, scheduler });
|
|
4659
|
+
}
|
|
4660
|
+
|
|
4661
|
+
return runtime;
|
|
4662
|
+
},
|
|
4663
|
+
|
|
4664
|
+
use(typeOrModule, entries) {
|
|
4665
|
+
app.use(typeOrModule, entries);
|
|
4666
|
+
return runtime;
|
|
4667
|
+
},
|
|
4306
4668
|
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4669
|
+
attachRoot(root) {
|
|
4670
|
+
assertActive();
|
|
4671
|
+
if (target === "server") {
|
|
4672
|
+
throw new Error("Server runtimes cannot attach DOM roots.");
|
|
4673
|
+
}
|
|
4674
|
+
if (!root) {
|
|
4675
|
+
throw new TypeError("runtime.attachRoot(root) requires a root.");
|
|
4676
|
+
}
|
|
4677
|
+
if (rootLoaders.has(root)) {
|
|
4678
|
+
return runtime;
|
|
4679
|
+
}
|
|
4680
|
+
|
|
4681
|
+
const rootLoader = rootLoaders.size === 0 && loader
|
|
4682
|
+
? loader
|
|
4683
|
+
: Loader({
|
|
4684
|
+
root,
|
|
4314
4685
|
signals,
|
|
4315
4686
|
handlers,
|
|
4316
4687
|
server,
|
|
4317
4688
|
cache: browserCache,
|
|
4318
|
-
partials,
|
|
4319
4689
|
scheduler,
|
|
4320
|
-
fetch: options.fetch,
|
|
4321
|
-
routeEndpoint: options.routeEndpoint,
|
|
4322
4690
|
attributes
|
|
4323
4691
|
});
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4692
|
+
registerRootLoader(root, rootLoader);
|
|
4693
|
+
rootLoader.start();
|
|
4694
|
+
configureServerContext({ cache: browserCache });
|
|
4695
|
+
signals._setContext?.({ server, loader: runtime.loader, cache: browserCache, scheduler });
|
|
4696
|
+
startRouterFor(root);
|
|
4697
|
+
return runtime;
|
|
4698
|
+
},
|
|
4699
|
+
|
|
4700
|
+
detachRoot(root) {
|
|
4701
|
+
assertActive();
|
|
4702
|
+
if (target === "server") {
|
|
4703
|
+
return runtime;
|
|
4704
|
+
}
|
|
4705
|
+
if (root == null) {
|
|
4706
|
+
for (const rootLoader of new Set(rootLoaders.values())) {
|
|
4707
|
+
rootLoader.destroy?.();
|
|
4708
|
+
}
|
|
4709
|
+
rootLoaders.clear();
|
|
4710
|
+
router?.destroy?.();
|
|
4711
|
+
router = undefined;
|
|
4712
|
+
routerStarted = false;
|
|
4713
|
+
loader = undefined;
|
|
4714
|
+
runtime.loader = undefined;
|
|
4715
|
+
runtime.router = undefined;
|
|
4716
|
+
return runtime;
|
|
4717
|
+
}
|
|
4718
|
+
const rootLoader = rootLoaders.get(root);
|
|
4719
|
+
if (!rootLoader) {
|
|
4720
|
+
return runtime;
|
|
4721
|
+
}
|
|
4722
|
+
rootLoader.destroy?.();
|
|
4723
|
+
rootLoaders.delete(root);
|
|
4724
|
+
if (loader === rootLoader) {
|
|
4725
|
+
router?.destroy?.();
|
|
4726
|
+
router = undefined;
|
|
4727
|
+
routerStarted = false;
|
|
4728
|
+
const next = rootLoaders.values().next().value;
|
|
4729
|
+
loader = next;
|
|
4730
|
+
runtime.loader = next;
|
|
4731
|
+
runtime.router = undefined;
|
|
4732
|
+
if (next) {
|
|
4733
|
+
startRouterFor(next.root);
|
|
4328
4734
|
}
|
|
4329
|
-
} else {
|
|
4330
|
-
configureServerContext({ cache: serverCache });
|
|
4331
|
-
signals._setContext?.({ server, cache: serverCache, scheduler });
|
|
4332
4735
|
}
|
|
4333
|
-
|
|
4334
4736
|
return runtime;
|
|
4335
4737
|
},
|
|
4336
4738
|
|
|
4337
|
-
|
|
4338
|
-
|
|
4739
|
+
inspectRoots() {
|
|
4740
|
+
return {
|
|
4741
|
+
count: rootLoaders.size,
|
|
4742
|
+
roots: [...rootLoaders].map(([root, rootLoader]) => ({
|
|
4743
|
+
root,
|
|
4744
|
+
loader: rootLoader,
|
|
4745
|
+
primary: rootLoader === loader
|
|
4746
|
+
}))
|
|
4747
|
+
};
|
|
4748
|
+
},
|
|
4749
|
+
|
|
4750
|
+
applySnapshot(snapshot, snapshotOptions = {}) {
|
|
4751
|
+
applySnapshotToRuntime(runtime, snapshot, snapshotOptions);
|
|
4339
4752
|
return runtime;
|
|
4340
4753
|
},
|
|
4341
4754
|
|
|
@@ -4397,7 +4810,14 @@ const __appModule = (() => {
|
|
|
4397
4810
|
destroyed = true;
|
|
4398
4811
|
detach();
|
|
4399
4812
|
router?.destroy?.();
|
|
4400
|
-
|
|
4813
|
+
const destroyedLoaders = new Set(rootLoaders.values());
|
|
4814
|
+
for (const rootLoader of destroyedLoaders) {
|
|
4815
|
+
rootLoader.destroy?.();
|
|
4816
|
+
}
|
|
4817
|
+
rootLoaders.clear();
|
|
4818
|
+
if (loader && !destroyedLoaders.has(loader)) {
|
|
4819
|
+
loader?.destroy?.();
|
|
4820
|
+
}
|
|
4401
4821
|
signals.destroy?.();
|
|
4402
4822
|
if (ownsScheduler) {
|
|
4403
4823
|
scheduler.destroy();
|
|
@@ -4411,10 +4831,49 @@ const __appModule = (() => {
|
|
|
4411
4831
|
|
|
4412
4832
|
server.cache = serverCache;
|
|
4413
4833
|
runtime.server.cache = serverCache;
|
|
4834
|
+
runtime.applySnapshot(initialSnapshot, { strict: options.strictSnapshots ?? true });
|
|
4414
4835
|
detach = app._attach(runtime);
|
|
4415
4836
|
|
|
4416
4837
|
return runtime;
|
|
4417
4838
|
|
|
4839
|
+
function registerRootLoader(root, rootLoader) {
|
|
4840
|
+
rootLoaders.set(root, rootLoader);
|
|
4841
|
+
if (!loader) {
|
|
4842
|
+
loader = rootLoader;
|
|
4843
|
+
runtime.loader = rootLoader;
|
|
4844
|
+
}
|
|
4845
|
+
rootLoader.server = server;
|
|
4846
|
+
rootLoader.cache = browserCache;
|
|
4847
|
+
rootLoader.scheduler = scheduler;
|
|
4848
|
+
}
|
|
4849
|
+
|
|
4850
|
+
function startRouterFor(root) {
|
|
4851
|
+
if (router === false || routerStarted || !(router || shouldStartRouter(routes, options)) || !runtime.loader) {
|
|
4852
|
+
return;
|
|
4853
|
+
}
|
|
4854
|
+
router = router ?? createRouter({
|
|
4855
|
+
mode: options.mode ?? "ssr-spa",
|
|
4856
|
+
root,
|
|
4857
|
+
boundary: options.boundary ?? "route",
|
|
4858
|
+
routes,
|
|
4859
|
+
loader: runtime.loader,
|
|
4860
|
+
signals,
|
|
4861
|
+
handlers,
|
|
4862
|
+
server,
|
|
4863
|
+
cache: browserCache,
|
|
4864
|
+
partials,
|
|
4865
|
+
scheduler,
|
|
4866
|
+
fetch: options.fetch,
|
|
4867
|
+
routeEndpoint: options.routeEndpoint,
|
|
4868
|
+
attributes
|
|
4869
|
+
});
|
|
4870
|
+
runtime.router = router;
|
|
4871
|
+
runtime.loader.router = router;
|
|
4872
|
+
configureServerContext({ cache: browserCache, router });
|
|
4873
|
+
router.start();
|
|
4874
|
+
routerStarted = true;
|
|
4875
|
+
}
|
|
4876
|
+
|
|
4418
4877
|
function configureServerContext(extra = {}) {
|
|
4419
4878
|
const cache = isLocalServerRegistry(server) ? serverCache : extra.cache;
|
|
4420
4879
|
server._setContext?.({
|
|
@@ -4457,6 +4916,7 @@ const __appModule = (() => {
|
|
|
4457
4916
|
return {};
|
|
4458
4917
|
}
|
|
4459
4918
|
|
|
4919
|
+
const merged = {};
|
|
4460
4920
|
for (const searchRoot of new Set([rootNode, documentRef])) {
|
|
4461
4921
|
if (!searchRoot?.querySelectorAll) {
|
|
4462
4922
|
continue;
|
|
@@ -4467,17 +4927,19 @@ const __appModule = (() => {
|
|
|
4467
4927
|
}
|
|
4468
4928
|
const source = script.textContent?.trim() ?? "";
|
|
4469
4929
|
if (!source) {
|
|
4470
|
-
|
|
4930
|
+
continue;
|
|
4471
4931
|
}
|
|
4932
|
+
let parsed;
|
|
4472
4933
|
try {
|
|
4473
|
-
|
|
4934
|
+
parsed = JSON.parse(source);
|
|
4474
4935
|
} catch (cause) {
|
|
4475
4936
|
throw new Error(`Could not parse Async snapshot: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
4476
4937
|
}
|
|
4938
|
+
mergeSnapshot(merged, parsed, { strict: true });
|
|
4477
4939
|
}
|
|
4478
4940
|
}
|
|
4479
4941
|
|
|
4480
|
-
return
|
|
4942
|
+
return merged;
|
|
4481
4943
|
}
|
|
4482
4944
|
|
|
4483
4945
|
function applyUseToRuntime(runtime, normalized) {
|
|
@@ -4487,10 +4949,22 @@ const __appModule = (() => {
|
|
|
4487
4949
|
applyRegistryUse(runtime.partials, runtime.registry, normalized.partial);
|
|
4488
4950
|
applyRegistryUse(runtime.routes, runtime.registry, normalized.route);
|
|
4489
4951
|
applyRegistryUse(runtime.components, runtime.registry, normalized.component);
|
|
4952
|
+
applyRegistryStoreUse(runtime.registry, "asyncSignal", normalized.asyncSignal);
|
|
4490
4953
|
applyRegistryUse(runtime.browser.cache, runtime.registry, normalized.cache.browser);
|
|
4491
4954
|
applyRegistryUse(runtime.server.cache, runtime.registry, normalized.cache.server);
|
|
4492
4955
|
}
|
|
4493
4956
|
|
|
4957
|
+
function applyRegistryStoreUse(registry, type, entries) {
|
|
4958
|
+
if (!entries || Object.keys(entries).length === 0) {
|
|
4959
|
+
return;
|
|
4960
|
+
}
|
|
4961
|
+
for (const [id, value] of Object.entries(entries)) {
|
|
4962
|
+
if (!registry.has(type, id)) {
|
|
4963
|
+
registry.register(type, id, value);
|
|
4964
|
+
}
|
|
4965
|
+
}
|
|
4966
|
+
}
|
|
4967
|
+
|
|
4494
4968
|
function applyRegistryUse(registry, runtimeRegistry, entries) {
|
|
4495
4969
|
if (!entries || Object.keys(entries).length === 0) {
|
|
4496
4970
|
return;
|
|
@@ -4510,6 +4984,7 @@ const __appModule = (() => {
|
|
|
4510
4984
|
partial: {},
|
|
4511
4985
|
route: {},
|
|
4512
4986
|
component: {},
|
|
4987
|
+
asyncSignal: {},
|
|
4513
4988
|
cache: {
|
|
4514
4989
|
browser: {},
|
|
4515
4990
|
server: {}
|
|
@@ -4565,11 +5040,128 @@ const __appModule = (() => {
|
|
|
4565
5040
|
return Boolean(value && typeof value.use === "function" && typeof value.snapshot === "function" && value.registry);
|
|
4566
5041
|
}
|
|
4567
5042
|
|
|
4568
|
-
function
|
|
4569
|
-
|
|
4570
|
-
|
|
5043
|
+
function ensureRuntime(app) {
|
|
5044
|
+
if (!app.runtime) {
|
|
5045
|
+
app.start();
|
|
5046
|
+
}
|
|
5047
|
+
return app.runtime;
|
|
5048
|
+
}
|
|
5049
|
+
|
|
5050
|
+
function applySnapshotToRuntime(runtime, snapshot = {}, options = {}) {
|
|
5051
|
+
const normalized = normalizeSnapshot(snapshot);
|
|
5052
|
+
for (const [path, value] of Object.entries(normalized.signal)) {
|
|
5053
|
+
setOrRegisterSignal(runtime.signals, path, value);
|
|
5054
|
+
}
|
|
5055
|
+
runtime.browser.cache.restore(normalized.cache.browser);
|
|
5056
|
+
mergeRegistryEntries(runtime, "handler", normalized.handler, runtime.handlers, options);
|
|
5057
|
+
mergeRegistryEntries(runtime, "server", normalized.server, runtime.server, options);
|
|
5058
|
+
mergeRegistryEntries(runtime, "partial", normalized.partial, runtime.partials, options);
|
|
5059
|
+
mergeRegistryEntries(runtime, "route", normalized.route, runtime.routes, options);
|
|
5060
|
+
mergeRegistryEntries(runtime, "component", normalized.component, runtime.components, options);
|
|
5061
|
+
mergeRegistryEntries(runtime, "asyncSignal", normalized.asyncSignal, null, options);
|
|
5062
|
+
return runtime;
|
|
5063
|
+
}
|
|
5064
|
+
|
|
5065
|
+
function appendSnapshotDeclarations(registry, snapshot = {}, options = {}) {
|
|
5066
|
+
const normalized = normalizeSnapshot(snapshot);
|
|
5067
|
+
for (const [id, value] of Object.entries(normalized.signal)) {
|
|
5068
|
+
registerSnapshotEntry(registry, "signal", id, createSignal(value), options);
|
|
5069
|
+
}
|
|
5070
|
+
for (const type of ["handler", "server", "partial", "route", "component", "asyncSignal"]) {
|
|
5071
|
+
for (const [id, value] of Object.entries(normalized[type])) {
|
|
5072
|
+
registerSnapshotEntry(registry, type, id, value, options);
|
|
5073
|
+
}
|
|
5074
|
+
}
|
|
5075
|
+
}
|
|
5076
|
+
|
|
5077
|
+
function mergeRegistryEntries(runtime, type, entries, concreteRegistry, options = {}) {
|
|
5078
|
+
if (!entries || Object.keys(entries).length === 0) {
|
|
5079
|
+
return;
|
|
5080
|
+
}
|
|
5081
|
+
for (const [id, value] of Object.entries(entries)) {
|
|
5082
|
+
registerSnapshotEntry(runtime.registry, type, id, value, options);
|
|
5083
|
+
}
|
|
5084
|
+
concreteRegistry?._adoptMany?.(entries);
|
|
5085
|
+
}
|
|
5086
|
+
|
|
5087
|
+
function registerSnapshotEntry(registry, type, id, value, options = {}) {
|
|
5088
|
+
const strict = options.strict ?? true;
|
|
5089
|
+
const map = registry._map(type);
|
|
5090
|
+
if (map.has(id)) {
|
|
5091
|
+
if (sameRegistryValue(map.get(id), value) || sameSnapshotValue(map.get(id), value)) {
|
|
5092
|
+
return;
|
|
5093
|
+
}
|
|
5094
|
+
if (strict) {
|
|
5095
|
+
throw new Error(`${type} "${id}" is already registered with a different value.`);
|
|
5096
|
+
}
|
|
5097
|
+
return;
|
|
5098
|
+
}
|
|
5099
|
+
registry.set(type, id, value);
|
|
5100
|
+
}
|
|
5101
|
+
|
|
5102
|
+
function normalizeSnapshot(snapshot = {}) {
|
|
5103
|
+
const normalized = {
|
|
5104
|
+
signal: {
|
|
5105
|
+
...(snapshot.signals ?? {}),
|
|
5106
|
+
...(snapshot.signal ?? {})
|
|
5107
|
+
},
|
|
5108
|
+
handler: { ...(snapshot.handler ?? {}) },
|
|
5109
|
+
server: { ...(snapshot.server ?? {}) },
|
|
5110
|
+
partial: { ...(snapshot.partial ?? {}) },
|
|
5111
|
+
route: { ...(snapshot.route ?? {}) },
|
|
5112
|
+
component: { ...(snapshot.component ?? {}) },
|
|
5113
|
+
asyncSignal: { ...(snapshot.asyncSignal ?? {}) },
|
|
5114
|
+
cache: {
|
|
5115
|
+
browser: {
|
|
5116
|
+
...(snapshot.entries?.browser ?? {}),
|
|
5117
|
+
...(snapshot.cache?.browser ?? {})
|
|
5118
|
+
}
|
|
5119
|
+
}
|
|
5120
|
+
};
|
|
5121
|
+
return normalized;
|
|
5122
|
+
}
|
|
5123
|
+
|
|
5124
|
+
function mergeSnapshot(target, source, options = {}) {
|
|
5125
|
+
const normalized = normalizeSnapshot(defineRegistrySnapshot(source));
|
|
5126
|
+
target.signal = {
|
|
5127
|
+
...(target.signal ?? target.signals ?? {}),
|
|
5128
|
+
...normalized.signal
|
|
5129
|
+
};
|
|
5130
|
+
target.signals = target.signal;
|
|
5131
|
+
target.cache = {
|
|
5132
|
+
...(target.cache ?? {}),
|
|
5133
|
+
browser: {
|
|
5134
|
+
...(target.cache?.browser ?? {}),
|
|
5135
|
+
...normalized.cache.browser
|
|
5136
|
+
}
|
|
5137
|
+
};
|
|
5138
|
+
for (const type of ["handler", "server", "partial", "route", "component", "asyncSignal"]) {
|
|
5139
|
+
target[type] = target[type] ?? {};
|
|
5140
|
+
for (const [id, value] of Object.entries(normalized[type])) {
|
|
5141
|
+
if (Object.hasOwn(target[type], id)) {
|
|
5142
|
+
if (sameRegistryValue(target[type][id], value) || sameSnapshotValue(target[type][id], value)) {
|
|
5143
|
+
continue;
|
|
5144
|
+
}
|
|
5145
|
+
if (options.strict ?? true) {
|
|
5146
|
+
throw new Error(`${type} "${id}" is already declared with a different value.`);
|
|
5147
|
+
}
|
|
5148
|
+
continue;
|
|
5149
|
+
}
|
|
5150
|
+
target[type][id] = value;
|
|
5151
|
+
}
|
|
5152
|
+
}
|
|
5153
|
+
return target;
|
|
5154
|
+
}
|
|
5155
|
+
|
|
5156
|
+
function sameSnapshotValue(left, right) {
|
|
5157
|
+
if (left === right) {
|
|
5158
|
+
return true;
|
|
5159
|
+
}
|
|
5160
|
+
try {
|
|
5161
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
5162
|
+
} catch {
|
|
5163
|
+
return false;
|
|
4571
5164
|
}
|
|
4572
|
-
browserCache.restore(snapshot.cache?.browser);
|
|
4573
5165
|
}
|
|
4574
5166
|
|
|
4575
5167
|
function setOrRegisterSignal(signals, path, value) {
|
|
@@ -5054,6 +5646,72 @@ const __delayModule = (() => {
|
|
|
5054
5646
|
return { delay };
|
|
5055
5647
|
})();
|
|
5056
5648
|
|
|
5649
|
+
const __elementsModule = (() => {
|
|
5650
|
+
const { Async } = __appModule;
|
|
5651
|
+
function defineAsyncContainerElement(options = {}) {
|
|
5652
|
+
const tagName = options.tagName ?? "async-container";
|
|
5653
|
+
const registry = options.customElements ?? globalThis.customElements;
|
|
5654
|
+
if (!registry) {
|
|
5655
|
+
throw new Error("defineAsyncContainerElement(...) requires customElements.");
|
|
5656
|
+
}
|
|
5657
|
+
const existing = registry.get(tagName);
|
|
5658
|
+
if (existing) {
|
|
5659
|
+
return existing;
|
|
5660
|
+
}
|
|
5661
|
+
const app = options.app ?? options.Async ?? Async;
|
|
5662
|
+
const HTMLElementBase = options.HTMLElement ?? options.window?.HTMLElement ?? globalThis.HTMLElement;
|
|
5663
|
+
if (!HTMLElementBase) {
|
|
5664
|
+
throw new Error("defineAsyncContainerElement(...) requires HTMLElement.");
|
|
5665
|
+
}
|
|
5666
|
+
|
|
5667
|
+
class AsyncContainerElement extends HTMLElementBase {
|
|
5668
|
+
connectedCallback() {
|
|
5669
|
+
if (this.__asyncAttached) {
|
|
5670
|
+
return;
|
|
5671
|
+
}
|
|
5672
|
+
const runtime = app.runtime ?? app.start?.();
|
|
5673
|
+
runtime?.attachRoot?.(this);
|
|
5674
|
+
this.__asyncRuntime = runtime;
|
|
5675
|
+
this.__asyncAttached = true;
|
|
5676
|
+
}
|
|
5677
|
+
|
|
5678
|
+
disconnectedCallback() {
|
|
5679
|
+
if (!this.__asyncAttached) {
|
|
5680
|
+
return;
|
|
5681
|
+
}
|
|
5682
|
+
this.__asyncRuntime?.detachRoot?.(this);
|
|
5683
|
+
this.__asyncRuntime = undefined;
|
|
5684
|
+
this.__asyncAttached = false;
|
|
5685
|
+
}
|
|
5686
|
+
}
|
|
5687
|
+
|
|
5688
|
+
registry.define(tagName, AsyncContainerElement);
|
|
5689
|
+
return AsyncContainerElement;
|
|
5690
|
+
}
|
|
5691
|
+
|
|
5692
|
+
function defineAsyncSuspenseElement(options = {}) {
|
|
5693
|
+
const tagName = options.tagName ?? "async-suspense";
|
|
5694
|
+
const registry = options.customElements ?? globalThis.customElements;
|
|
5695
|
+
if (!registry) {
|
|
5696
|
+
throw new Error("defineAsyncSuspenseElement(...) requires customElements.");
|
|
5697
|
+
}
|
|
5698
|
+
const existing = registry.get(tagName);
|
|
5699
|
+
if (existing) {
|
|
5700
|
+
return existing;
|
|
5701
|
+
}
|
|
5702
|
+
const HTMLElementBase = options.HTMLElement ?? options.window?.HTMLElement ?? globalThis.HTMLElement;
|
|
5703
|
+
if (!HTMLElementBase) {
|
|
5704
|
+
throw new Error("defineAsyncSuspenseElement(...) requires HTMLElement.");
|
|
5705
|
+
}
|
|
5706
|
+
|
|
5707
|
+
class AsyncSuspenseElement extends HTMLElementBase {}
|
|
5708
|
+
|
|
5709
|
+
registry.define(tagName, AsyncSuspenseElement);
|
|
5710
|
+
return AsyncSuspenseElement;
|
|
5711
|
+
}
|
|
5712
|
+
return { defineAsyncContainerElement, defineAsyncSuspenseElement };
|
|
5713
|
+
})();
|
|
5714
|
+
|
|
5057
5715
|
const { asyncSignal: asyncSignal } = __asyncSignalModule;
|
|
5058
5716
|
const { Async: Async } = __appModule;
|
|
5059
5717
|
const { createApp: createApp } = __appModule;
|
|
@@ -5068,8 +5726,12 @@ const { component: component } = __componentModule;
|
|
|
5068
5726
|
const { createComponentRegistry: createComponentRegistry } = __componentModule;
|
|
5069
5727
|
const { defineComponent: defineComponent } = __componentModule;
|
|
5070
5728
|
const { delay: delay } = __delayModule;
|
|
5729
|
+
const { defineAsyncContainerElement: defineAsyncContainerElement } = __elementsModule;
|
|
5730
|
+
const { defineAsyncSuspenseElement: defineAsyncSuspenseElement } = __elementsModule;
|
|
5071
5731
|
const { createHandlerRegistry: createHandlerRegistry } = __handlersModule;
|
|
5072
5732
|
const { html: html } = __htmlModule;
|
|
5733
|
+
const { createLazyRegistry: createLazyRegistry } = __lazyRegistryModule;
|
|
5734
|
+
const { defineRegistrySnapshot: defineRegistrySnapshot } = __lazyRegistryModule;
|
|
5073
5735
|
const { Loader: Loader } = __loaderModule;
|
|
5074
5736
|
const { AsyncLoader: AsyncLoader } = __loaderModule;
|
|
5075
5737
|
const { createPartialRegistry: createPartialRegistry } = __partialsModule;
|
|
@@ -5089,4 +5751,4 @@ const { createSignalRegistry: createSignalRegistry } = __signalsModule;
|
|
|
5089
5751
|
const { effect: effect } = __signalsModule;
|
|
5090
5752
|
const { signal: signal } = __signalsModule;
|
|
5091
5753
|
|
|
5092
|
-
export { asyncSignal, Async, createApp, defineApp, readSnapshot, attributeName, defineAttributeConfig, createBoundaryReceiver, createCacheRegistry, defineCache, component, createComponentRegistry, defineComponent, delay, createHandlerRegistry, html, Loader, AsyncLoader, createPartialRegistry, createRegistryStore, createRouteRegistry, createRouter, defineRoute, route, createScheduler, applyServerResult, createServerProxy, resolveServerCommandArguments, unwrapServerResult, computed, createSignal, createSignalRegistry, effect, signal };
|
|
5754
|
+
export { asyncSignal, Async, createApp, defineApp, readSnapshot, attributeName, defineAttributeConfig, createBoundaryReceiver, createCacheRegistry, defineCache, component, createComponentRegistry, defineComponent, delay, defineAsyncContainerElement, defineAsyncSuspenseElement, createHandlerRegistry, html, createLazyRegistry, defineRegistrySnapshot, Loader, AsyncLoader, createPartialRegistry, createRegistryStore, createRouteRegistry, createRouter, defineRoute, route, createScheduler, applyServerResult, createServerProxy, resolveServerCommandArguments, unwrapServerResult, computed, createSignal, createSignalRegistry, effect, signal };
|