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