@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/browser.umd.js CHANGED
@@ -293,8 +293,217 @@
293
293
  return { asyncSignal, isAsyncSignal };
294
294
  })();
295
295
 
296
+ const __lazyRegistryModule = (() => {
297
+ const descriptorTypes = new Set(["handler", "component", "asyncSignal", "partial", "route"]);
298
+ const defaultBaseUrl = "_async";
299
+
300
+ function defineRegistrySnapshot(snapshot = {}) {
301
+ if (!snapshot || typeof snapshot !== "object" || Array.isArray(snapshot)) {
302
+ throw new TypeError("defineRegistrySnapshot(snapshot) requires an object.");
303
+ }
304
+ return snapshot;
305
+ }
306
+
307
+ function createLazyRegistry(options = {}) {
308
+ const registryAssets = normalizeRegistryAssets(options.registryAssets ?? options.assets);
309
+ const importModule = options.importModule ?? ((url) => import(url));
310
+ const moduleCache = new Map();
311
+ const exportCache = new Map();
312
+
313
+ return {
314
+ registryAssets,
315
+
316
+ resolveUrl(type, id, descriptor) {
317
+ return resolveDescriptorUrl(type, id, descriptor, registryAssets);
318
+ },
319
+
320
+ async resolve(type, id, descriptor) {
321
+ if (!isLazyDescriptor(descriptor)) {
322
+ return descriptor;
323
+ }
324
+ const cacheKey = `${type}:${id}`;
325
+ if (exportCache.has(cacheKey)) {
326
+ return exportCache.get(cacheKey);
327
+ }
328
+
329
+ const resolved = resolveDescriptorUrl(type, id, descriptor, registryAssets);
330
+ let modulePromise = moduleCache.get(resolved.moduleUrl);
331
+ if (!modulePromise) {
332
+ modulePromise = Promise.resolve(importModule(resolved.moduleUrl));
333
+ moduleCache.set(resolved.moduleUrl, modulePromise);
334
+ }
335
+ const module = await modulePromise;
336
+ const value = resolveExport(module, resolved.exportNames, type, id);
337
+ exportCache.set(cacheKey, value);
338
+ return value;
339
+ },
340
+
341
+ inspect() {
342
+ return {
343
+ registryAssets,
344
+ modules: [...moduleCache.keys()],
345
+ exports: [...exportCache.keys()]
346
+ };
347
+ }
348
+ };
349
+ }
350
+
351
+ function normalizeRegistryAssets(options = {}) {
352
+ const baseUrl = normalizeBaseUrl(options.baseUrl ?? defaultBaseUrl);
353
+ const paths = {
354
+ component: "component",
355
+ handler: "handler",
356
+ asyncSignal: "asyncSignal",
357
+ partial: "partial",
358
+ route: "route",
359
+ ...(options.paths ?? {})
360
+ };
361
+
362
+ for (const [type, value] of Object.entries(paths)) {
363
+ if (!descriptorTypes.has(type)) {
364
+ continue;
365
+ }
366
+ if (typeof value !== "string" || value.length === 0) {
367
+ throw new TypeError(`Registry asset path for "${type}" must be a non-empty string.`);
368
+ }
369
+ }
370
+
371
+ return {
372
+ baseUrl,
373
+ paths
374
+ };
375
+ }
376
+
377
+ function isLazyDescriptor(value) {
378
+ return Boolean(
379
+ value &&
380
+ typeof value === "object" &&
381
+ !Array.isArray(value) &&
382
+ typeof value.url === "string"
383
+ );
384
+ }
385
+
386
+ function sameRegistryValue(left, right) {
387
+ if (left === right) {
388
+ return true;
389
+ }
390
+ if (isLazyDescriptor(left) && isLazyDescriptor(right)) {
391
+ return stableStringify(left) === stableStringify(right);
392
+ }
393
+ return false;
394
+ }
395
+
396
+ function publicRegistryValue(value, id) {
397
+ if (isLazyDescriptor(value)) {
398
+ return { ...value };
399
+ }
400
+ return { id };
401
+ }
402
+
403
+ function resolveDescriptorUrl(type, id, descriptor, registryAssets) {
404
+ if (!descriptorTypes.has(type)) {
405
+ throw new Error(`Registry type "${type}" does not support lazy descriptors.`);
406
+ }
407
+ if (!isLazyDescriptor(descriptor)) {
408
+ throw new TypeError(`Registry descriptor for "${type}:${id}" requires a url.`);
409
+ }
410
+
411
+ const { path, hash } = splitHash(descriptor.url);
412
+ const moduleUrl = resolveModuleUrl(type, path, registryAssets);
413
+ const exportNames = hash
414
+ ? [hash]
415
+ : inferredExportNames(id, path);
416
+
417
+ return {
418
+ moduleUrl,
419
+ exportNames,
420
+ url: hash ? `${moduleUrl}#${hash}` : moduleUrl
421
+ };
422
+ }
423
+
424
+ function resolveModuleUrl(type, path, registryAssets) {
425
+ if (isAbsoluteUrl(path) || path.startsWith("/") || path.startsWith("./") || path.startsWith("../")) {
426
+ return path;
427
+ }
428
+ const typePath = registryAssets.paths[type] ?? type;
429
+ return joinUrl(registryAssets.baseUrl, typePath, path);
430
+ }
431
+
432
+ function resolveExport(module, exportNames, type, id) {
433
+ for (const name of exportNames) {
434
+ if (name in module) {
435
+ return module[name];
436
+ }
437
+ }
438
+ throw new Error(`Lazy ${type} "${id}" did not export ${exportNames.map((name) => `"${name}"`).join(", ")}.`);
439
+ }
440
+
441
+ function inferredExportNames(id, path) {
442
+ const names = [];
443
+ const leaf = id.split(".").filter(Boolean).at(-1);
444
+ const basename = path
445
+ .split("/")
446
+ .filter(Boolean)
447
+ .at(-1)
448
+ ?.replace(/\.[^.]+$/, "");
449
+ for (const name of [leaf, basename, "default"]) {
450
+ if (name && !names.includes(name)) {
451
+ names.push(name);
452
+ }
453
+ }
454
+ return names;
455
+ }
456
+
457
+ function splitHash(url) {
458
+ const index = url.indexOf("#");
459
+ if (index === -1) {
460
+ return { path: url, hash: "" };
461
+ }
462
+ return {
463
+ path: url.slice(0, index),
464
+ hash: url.slice(index + 1)
465
+ };
466
+ }
467
+
468
+ function normalizeBaseUrl(baseUrl) {
469
+ if (typeof baseUrl !== "string" || baseUrl.length === 0) {
470
+ throw new TypeError("registryAssets.baseUrl must be a non-empty string.");
471
+ }
472
+ if (isAbsoluteUrl(baseUrl) || baseUrl.startsWith("/") || baseUrl.startsWith("./") || baseUrl.startsWith("../")) {
473
+ return stripTrailingSlash(baseUrl);
474
+ }
475
+ return `/${stripSlashes(baseUrl)}`;
476
+ }
477
+
478
+ function joinUrl(...parts) {
479
+ const [first, ...rest] = parts;
480
+ return [stripTrailingSlash(first), ...rest.map(stripSlashes)].filter(Boolean).join("/");
481
+ }
482
+
483
+ function stripSlashes(value) {
484
+ return String(value).replace(/^\/+|\/+$/g, "");
485
+ }
486
+
487
+ function stripTrailingSlash(value) {
488
+ return String(value).replace(/\/+$/g, "");
489
+ }
490
+
491
+ function isAbsoluteUrl(value) {
492
+ return /^[A-Za-z][A-Za-z\d+.-]*:/.test(value);
493
+ }
494
+
495
+ function stableStringify(value) {
496
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
497
+ return JSON.stringify(value);
498
+ }
499
+ return JSON.stringify(Object.keys(value).sort().map((key) => [key, value[key]]));
500
+ }
501
+ return { defineRegistrySnapshot, createLazyRegistry, normalizeRegistryAssets, isLazyDescriptor, sameRegistryValue, publicRegistryValue };
502
+ })();
503
+
296
504
  const __registryStoreModule = (() => {
297
- const declarationTypes = new Set(["signal", "handler", "server", "partial", "route", "component"]);
505
+ const { publicRegistryValue } = __lazyRegistryModule;
506
+ const declarationTypes = new Set(["signal", "handler", "server", "partial", "route", "component", "asyncSignal"]);
298
507
  const cacheTypes = new Set(["cache.browser", "cache.server"]);
299
508
  const cacheEntryTypes = new Set(["cache.browser.entries", "cache.server.entries"]);
300
509
  const allTypes = new Set([...declarationTypes, ...cacheTypes, ...cacheEntryTypes]);
@@ -381,11 +590,12 @@
381
590
  const snapshotTarget = snapshotOptions.target ?? target;
382
591
  return {
383
592
  signal: snapshotSignals(backing.signal),
384
- handler: snapshotDescriptors(backing.handler, "handler"),
385
- server: snapshotDescriptors(backing.server, "server"),
386
- partial: snapshotDescriptors(backing.partial, "partial"),
593
+ handler: snapshotDescriptors(backing.handler),
594
+ server: snapshotDescriptors(backing.server),
595
+ partial: snapshotDescriptors(backing.partial),
387
596
  route: snapshotPlain(backing.route),
388
- component: snapshotDescriptors(backing.component, "component"),
597
+ component: snapshotDescriptors(backing.component),
598
+ asyncSignal: snapshotDescriptors(backing.asyncSignal),
389
599
  cache: {
390
600
  browser: snapshotPlain(backing.cache.browser),
391
601
  server: snapshotPlain(backing.cache.server)
@@ -405,6 +615,7 @@
405
615
  partial: Object.fromEntries(backing.partial),
406
616
  route: Object.fromEntries(backing.route),
407
617
  component: Object.fromEntries(backing.component),
618
+ asyncSignal: Object.fromEntries(backing.asyncSignal),
408
619
  cache: {
409
620
  browser: Object.fromEntries(backing.cache.browser),
410
621
  server: Object.fromEntries(backing.cache.server)
@@ -464,6 +675,7 @@
464
675
  partial: new Map(),
465
676
  route: new Map(),
466
677
  component: new Map(),
678
+ asyncSignal: new Map(),
467
679
  cache: {
468
680
  browser: new Map(),
469
681
  server: new Map()
@@ -482,6 +694,7 @@
482
694
  registry.registerMany("partial", initial.partial);
483
695
  registry.registerMany("route", initial.route);
484
696
  registry.registerMany("component", initial.component);
697
+ registry.registerMany("asyncSignal", initial.asyncSignal);
485
698
  registry.registerMany("cache.browser", initial.cache?.browser);
486
699
  registry.registerMany("cache.server", initial.cache?.server);
487
700
 
@@ -509,7 +722,7 @@
509
722
 
510
723
  function publicValue(type, id, value, options) {
511
724
  if (type === "server" && options.target === "browser") {
512
- return { id, kind: "server" };
725
+ return publicRegistryValue(value, id);
513
726
  }
514
727
  if (cacheEntryTypes.has(type)) {
515
728
  return value?.value;
@@ -529,10 +742,10 @@
529
742
  return snapshot;
530
743
  }
531
744
 
532
- function snapshotDescriptors(map, kind) {
745
+ function snapshotDescriptors(map) {
533
746
  const snapshot = {};
534
- for (const id of map.keys()) {
535
- snapshot[id] = { id, kind };
747
+ for (const [id, value] of map) {
748
+ snapshot[id] = publicRegistryValue(value, id);
536
749
  }
537
750
  return snapshot;
538
751
  }
@@ -809,6 +1022,7 @@
809
1022
  const __signalsModule = (() => {
810
1023
  const { asyncSignal: createAsyncSignal, isAsyncSignal } = __asyncSignalModule;
811
1024
  const { attachRegistryInspection, createRegistryStore } = __registryStoreModule;
1025
+ const { createLazyRegistry, isLazyDescriptor } = __lazyRegistryModule;
812
1026
  const signalKind = Symbol.for("@async/framework.signal");
813
1027
  const computedKind = Symbol.for("@async/framework.computed");
814
1028
  const effectKind = Symbol.for("@async/framework.effect");
@@ -930,6 +1144,8 @@
930
1144
  const registryStore = options.registry ?? createRegistryStore();
931
1145
  const type = options.type ?? "signal";
932
1146
  const entries = registryStore._map(type);
1147
+ const asyncDescriptors = registryStore._map("asyncSignal");
1148
+ const lazyRegistry = options.lazyRegistry ?? createLazyRegistry(options);
933
1149
  const registryCleanups = new Map();
934
1150
  const runtimeContext = {};
935
1151
  const boundEntries = new Set();
@@ -970,6 +1186,7 @@
970
1186
 
971
1187
  ensure(id, initial) {
972
1188
  assertId(id);
1189
+ materializeAsyncSignal(id);
973
1190
  if (!entries.has(id)) {
974
1191
  registry.register(id, createSignal(initial));
975
1192
  }
@@ -977,18 +1194,18 @@
977
1194
  },
978
1195
 
979
1196
  has(id) {
980
- return entries.has(id);
1197
+ return entries.has(id) || asyncDescriptors.has(id);
981
1198
  },
982
1199
 
983
1200
  get(path) {
984
- const parsed = parsePath(path, entries);
1201
+ const parsed = parseRegistryPath(path);
985
1202
  track(parsed.path);
986
1203
  const entry = requireEntry(entries, parsed.id);
987
1204
  return readEntry(entry, parsed.parts);
988
1205
  },
989
1206
 
990
1207
  set(path, value) {
991
- const parsed = parsePath(path, entries);
1208
+ const parsed = parseRegistryPath(path);
992
1209
  const entry = requireEntry(entries, parsed.id);
993
1210
  if (parsed.parts.length === 0) {
994
1211
  return entry.set(value);
@@ -1007,6 +1224,7 @@
1007
1224
 
1008
1225
  ref(id) {
1009
1226
  assertId(id);
1227
+ materializeAsyncSignal(id);
1010
1228
  return createRef(registry, id);
1011
1229
  },
1012
1230
 
@@ -1014,7 +1232,7 @@
1014
1232
  if (typeof fn !== "function") {
1015
1233
  throw new TypeError("subscribe(path, fn) requires a function.");
1016
1234
  }
1017
- const parsed = parsePath(path, entries);
1235
+ const parsed = parseRegistryPath(path);
1018
1236
  const entry = requireEntry(entries, parsed.id);
1019
1237
  const subscriptionId = ++subscriptionCounter;
1020
1238
  return entry.subscribe(() => {
@@ -1120,6 +1338,7 @@
1120
1338
  },
1121
1339
 
1122
1340
  _entry(id) {
1341
+ materializeAsyncSignal(id);
1123
1342
  return requireEntry(entries, id);
1124
1343
  },
1125
1344
 
@@ -1159,6 +1378,42 @@
1159
1378
  }
1160
1379
  }
1161
1380
 
1381
+ function parseRegistryPath(path) {
1382
+ if (typeof path !== "string" || path.length === 0) {
1383
+ throw new TypeError("Signal path must be a non-empty string.");
1384
+ }
1385
+ const segments = path.split(".");
1386
+ for (let end = segments.length; end > 0; end -= 1) {
1387
+ const id = segments.slice(0, end).join(".");
1388
+ if (entries.has(id) || asyncDescriptors.has(id)) {
1389
+ materializeAsyncSignal(id);
1390
+ return { id, parts: segments.slice(end), path };
1391
+ }
1392
+ }
1393
+ const [id, ...parts] = segments;
1394
+ return { id, parts, path };
1395
+ }
1396
+
1397
+ function materializeAsyncSignal(id) {
1398
+ if (entries.has(id) || !asyncDescriptors.has(id)) {
1399
+ return;
1400
+ }
1401
+ const descriptor = asyncDescriptors.get(id);
1402
+ if (!isLazyDescriptor(descriptor) && typeof descriptor !== "function") {
1403
+ throw new TypeError(`Async signal "${id}" must be a function or lazy descriptor.`);
1404
+ }
1405
+ const loader = async function runLazyAsyncSignal(...args) {
1406
+ const resolved = await lazyRegistry.resolve("asyncSignal", id, descriptor);
1407
+ if (typeof resolved !== "function") {
1408
+ throw new TypeError(`Async signal "${id}" did not resolve to a function.`);
1409
+ }
1410
+ return resolved.apply(this, args);
1411
+ };
1412
+ const entry = createAsyncSignal(id, loader);
1413
+ entries.set(id, entry);
1414
+ bindEntry(id, entry);
1415
+ }
1416
+
1162
1417
  function scheduleCallback(fn, options = {}) {
1163
1418
  const scheduler = options.scheduler;
1164
1419
  if (!scheduler || options.phase === "sync") {
@@ -1524,6 +1779,7 @@
1524
1779
  const { attributeName } = __attributesModule;
1525
1780
  const { escapeHtml, rawHtml, renderTemplate } = __htmlModule;
1526
1781
  const { attachRegistryInspection, createRegistryStore } = __registryStoreModule;
1782
+ const { createLazyRegistry, isLazyDescriptor } = __lazyRegistryModule;
1527
1783
  const componentKind = Symbol.for("@async/framework.component");
1528
1784
  let componentCounter = 0;
1529
1785
 
@@ -1544,13 +1800,15 @@
1544
1800
  const registryStore = options.registry ?? createRegistryStore();
1545
1801
  const type = options.type ?? "component";
1546
1802
  const entries = registryStore._map(type);
1803
+ const lazyRegistry = options.lazyRegistry ?? createLazyRegistry(options);
1804
+ const lazyComponents = new Map();
1547
1805
 
1548
1806
  const registry = attachRegistryInspection({
1549
1807
  register(id, Component) {
1550
1808
  if (typeof id !== "string" || id.length === 0) {
1551
1809
  throw new TypeError("Component id must be a non-empty string.");
1552
1810
  }
1553
- if (!isComponent(Component) && typeof Component !== "function") {
1811
+ if (!isComponent(Component) && typeof Component !== "function" && !isLazyDescriptor(Component)) {
1554
1812
  throw new TypeError(`Component "${id}" must be a component function.`);
1555
1813
  }
1556
1814
  if (entries.has(id)) {
@@ -1571,6 +1829,7 @@
1571
1829
  if (typeof id !== "string" || id.length === 0) {
1572
1830
  throw new TypeError("Component id must be a non-empty string.");
1573
1831
  }
1832
+ lazyComponents.delete(id);
1574
1833
  return entries.delete(id);
1575
1834
  },
1576
1835
 
@@ -1578,7 +1837,20 @@
1578
1837
  if (typeof id !== "string" || id.length === 0) {
1579
1838
  throw new TypeError("Component id must be a non-empty string.");
1580
1839
  }
1581
- return entries.get(id);
1840
+ const Component = entries.get(id);
1841
+ if (!isLazyDescriptor(Component)) {
1842
+ return Component;
1843
+ }
1844
+ if (!lazyComponents.has(id)) {
1845
+ lazyComponents.set(id, async function LazyComponent(...args) {
1846
+ const resolved = await lazyRegistry.resolve(type, id, Component);
1847
+ if (typeof resolved !== "function") {
1848
+ throw new TypeError(`Component "${id}" did not resolve to a function.`);
1849
+ }
1850
+ return resolved.apply(this, args);
1851
+ });
1852
+ }
1853
+ return lazyComponents.get(id);
1582
1854
  },
1583
1855
 
1584
1856
  _adoptMany() {
@@ -2243,6 +2515,7 @@
2243
2515
  const __handlersModule = (() => {
2244
2516
  const { applyServerResult, defaultInput, resolveServerCommandArguments, unwrapServerResult } = __serverModule;
2245
2517
  const { attachRegistryInspection, createRegistryStore } = __registryStoreModule;
2518
+ const { createLazyRegistry, isLazyDescriptor } = __lazyRegistryModule;
2246
2519
  const builtInTokens = new Set(["prevent", "preventDefault", "stopPropagation", "stopImmediatePropagation"]);
2247
2520
  const builtInHandlers = {
2248
2521
  prevent: preventDefault,
@@ -2263,11 +2536,13 @@
2263
2536
  const registryStore = options.registry ?? createRegistryStore();
2264
2537
  const type = options.type ?? "handler";
2265
2538
  const handlers = registryStore._map(type);
2539
+ const lazyRegistry = options.lazyRegistry ?? createLazyRegistry(options);
2540
+ const lazyHandlers = new Map();
2266
2541
 
2267
2542
  const registry = attachRegistryInspection({
2268
2543
  register(id, fn) {
2269
2544
  assertId(id);
2270
- if (typeof fn !== "function") {
2545
+ if (typeof fn !== "function" && !isLazyDescriptor(fn)) {
2271
2546
  throw new TypeError(`Handler "${id}" must be a function.`);
2272
2547
  }
2273
2548
  if (handlers.has(id)) {
@@ -2286,12 +2561,26 @@
2286
2561
 
2287
2562
  unregister(id) {
2288
2563
  assertId(id);
2564
+ lazyHandlers.delete(id);
2289
2565
  return handlers.delete(id);
2290
2566
  },
2291
2567
 
2292
2568
  resolve(id) {
2293
2569
  assertId(id);
2294
- return handlers.get(id);
2570
+ const handler = handlers.get(id);
2571
+ if (!isLazyDescriptor(handler)) {
2572
+ return handler;
2573
+ }
2574
+ if (!lazyHandlers.has(id)) {
2575
+ lazyHandlers.set(id, async function runLazyHandler(...args) {
2576
+ const resolved = await lazyRegistry.resolve(type, id, handler);
2577
+ if (typeof resolved !== "function") {
2578
+ throw new TypeError(`Handler "${id}" did not resolve to a function.`);
2579
+ }
2580
+ return resolved.apply(this, args);
2581
+ });
2582
+ }
2583
+ return lazyHandlers.get(id);
2295
2584
  },
2296
2585
 
2297
2586
  async run(ref, context = {}) {
@@ -3081,7 +3370,7 @@
3081
3370
  if (renderingBoundaries.has(boundary)) {
3082
3371
  continue;
3083
3372
  }
3084
- const id = readAttribute(boundary, attributeConfig, "async", "boundary");
3373
+ const id = boundaryIdFor(boundary, attributeConfig);
3085
3374
  if (id == null) {
3086
3375
  continue;
3087
3376
  }
@@ -3398,19 +3687,26 @@
3398
3687
  function collectBoundaryTemplates(boundary, id, attributeConfig) {
3399
3688
  const templates = {};
3400
3689
  for (const template of [...boundary.children].filter((child) => child.tagName === "TEMPLATE")) {
3401
- if (readAttribute(template, attributeConfig, "async", "loading") === id) {
3690
+ if (templateMatchesState(template, "loading", id, boundary, attributeConfig)) {
3402
3691
  templates.loading = template;
3403
3692
  }
3404
- if (readAttribute(template, attributeConfig, "async", "ready") === id) {
3693
+ if (templateMatchesState(template, "ready", id, boundary, attributeConfig)) {
3405
3694
  templates.ready = template;
3406
3695
  }
3407
- if (readAttribute(template, attributeConfig, "async", "error") === id) {
3696
+ if (templateMatchesState(template, "error", id, boundary, attributeConfig)) {
3408
3697
  templates.error = template;
3409
3698
  }
3410
3699
  }
3411
3700
  return templates;
3412
3701
  }
3413
3702
 
3703
+ function templateMatchesState(template, state, id, boundary, attributeConfig) {
3704
+ if (readAttribute(template, attributeConfig, "async", state) === id) {
3705
+ return true;
3706
+ }
3707
+ return isAsyncSuspense(boundary) && template.hasAttribute?.(state);
3708
+ }
3709
+
3414
3710
  function chooseBoundaryTemplate(templates, status) {
3415
3711
  if (status === "ready") {
3416
3712
  return templates.ready ?? templates.loading ?? templates.error;
@@ -3458,13 +3754,24 @@
3458
3754
 
3459
3755
  function findBoundary(root, boundaryId, attributeConfig) {
3460
3756
  for (const element of elementsIn(root)) {
3461
- if (readAttribute(element, attributeConfig, "async", "boundary") === String(boundaryId)) {
3757
+ if (boundaryIdFor(element, attributeConfig) === String(boundaryId)) {
3462
3758
  return element;
3463
3759
  }
3464
3760
  }
3465
3761
  return null;
3466
3762
  }
3467
3763
 
3764
+ function boundaryIdFor(element, attributeConfig) {
3765
+ if (isAsyncSuspense(element) && element.hasAttribute?.("for")) {
3766
+ return element.getAttribute("for");
3767
+ }
3768
+ return readAttribute(element, attributeConfig, "async", "boundary");
3769
+ }
3770
+
3771
+ function isAsyncSuspense(element) {
3772
+ return element?.tagName === "ASYNC-SUSPENSE";
3773
+ }
3774
+
3468
3775
  function toFragment(value, documentRef) {
3469
3776
  if (value?.nodeType === 11) {
3470
3777
  return value;
@@ -3497,15 +3804,18 @@
3497
3804
  const __partialsModule = (() => {
3498
3805
  const { isTemplateResult, renderTemplate } = __htmlModule;
3499
3806
  const { attachRegistryInspection, createRegistryStore } = __registryStoreModule;
3807
+ const { createLazyRegistry, isLazyDescriptor } = __lazyRegistryModule;
3500
3808
  function createPartialRegistry(initialMap = {}, options = {}) {
3501
3809
  const registryStore = options.registry ?? createRegistryStore();
3502
3810
  const type = options.type ?? "partial";
3503
3811
  const entries = registryStore._map(type);
3812
+ const lazyRegistry = options.lazyRegistry ?? createLazyRegistry(options);
3813
+ const lazyPartials = new Map();
3504
3814
 
3505
3815
  const registry = attachRegistryInspection({
3506
3816
  register(id, fn) {
3507
3817
  assertId(id);
3508
- if (typeof fn !== "function") {
3818
+ if (typeof fn !== "function" && !isLazyDescriptor(fn)) {
3509
3819
  throw new TypeError(`Partial "${id}" must be a function.`);
3510
3820
  }
3511
3821
  if (entries.has(id)) {
@@ -3524,12 +3834,26 @@
3524
3834
 
3525
3835
  unregister(id) {
3526
3836
  assertId(id);
3837
+ lazyPartials.delete(id);
3527
3838
  return entries.delete(id);
3528
3839
  },
3529
3840
 
3530
3841
  resolve(id) {
3531
3842
  assertId(id);
3532
- return entries.get(id);
3843
+ const partial = entries.get(id);
3844
+ if (!isLazyDescriptor(partial)) {
3845
+ return partial;
3846
+ }
3847
+ if (!lazyPartials.has(id)) {
3848
+ lazyPartials.set(id, async function runLazyPartial(...args) {
3849
+ const resolved = await lazyRegistry.resolve(type, id, partial);
3850
+ if (typeof resolved !== "function") {
3851
+ throw new TypeError(`Partial "${id}" did not resolve to a function.`);
3852
+ }
3853
+ return resolved.apply(this, args);
3854
+ });
3855
+ }
3856
+ return lazyPartials.get(id);
3533
3857
  },
3534
3858
 
3535
3859
  async render(id, props = {}, context = {}) {
@@ -4199,7 +4523,8 @@
4199
4523
  const { createSignal, createSignalRegistry } = __signalsModule;
4200
4524
  const { createRegistryStore } = __registryStoreModule;
4201
4525
  const { attributeName, normalizeAttributeConfig } = __attributesModule;
4202
- const registryTypes = new Set(["signal", "handler", "server", "partial", "route", "component"]);
4526
+ const { createLazyRegistry, defineRegistrySnapshot, sameRegistryValue } = __lazyRegistryModule;
4527
+ const registryTypes = new Set(["signal", "handler", "server", "partial", "route", "component", "asyncSignal"]);
4203
4528
 
4204
4529
  function defineApp(initial, options = {}) {
4205
4530
  const registry = createRegistryStore(undefined, { target: "browser" });
@@ -4228,6 +4553,27 @@
4228
4553
  return runtime;
4229
4554
  },
4230
4555
 
4556
+ attachRoot(root) {
4557
+ return ensureRuntime(app).attachRoot(root);
4558
+ },
4559
+
4560
+ detachRoot(root) {
4561
+ return app.runtime?.detachRoot(root) ?? app;
4562
+ },
4563
+
4564
+ applySnapshot(snapshot, snapshotOptions = {}) {
4565
+ if (app.runtime) {
4566
+ app.runtime.applySnapshot(snapshot, snapshotOptions);
4567
+ return app;
4568
+ }
4569
+ appendSnapshotDeclarations(registry, snapshot, snapshotOptions);
4570
+ return app;
4571
+ },
4572
+
4573
+ inspectRoots() {
4574
+ return app.runtime?.inspectRoots() ?? { count: 0, roots: [] };
4575
+ },
4576
+
4231
4577
  _attach(runtime) {
4232
4578
  runtimes.add(runtime);
4233
4579
  return () => app._detach(runtime);
@@ -4253,23 +4599,32 @@
4253
4599
  });
4254
4600
  const ownsScheduler = !options.scheduler && !options.loader?.scheduler;
4255
4601
  const attributes = normalizeAttributeConfig(options.attributes);
4602
+ const lazyRegistry = options.lazyRegistry ?? createLazyRegistry({
4603
+ registryAssets: options.registryAssets,
4604
+ importModule: options.importModule
4605
+ });
4256
4606
  const registry = options.registry ?? app.registry.view({ target });
4257
- const signals = options.signals ?? createSignalRegistry(undefined, { registry, type: "signal" });
4258
- const handlers = options.handlers ?? createHandlerRegistry(undefined, { registry, type: "handler" });
4607
+ const signals = options.signals ?? createSignalRegistry(undefined, { registry, type: "signal", lazyRegistry });
4608
+ const handlers = options.handlers ?? createHandlerRegistry(undefined, { registry, type: "handler", lazyRegistry });
4259
4609
  const serverCache = createCacheRegistry(undefined, { registry, type: "cache.server" });
4260
4610
  const browserCache = createCacheRegistry(undefined, { registry, type: "cache.browser" });
4261
4611
  const serverFactory = options.serverFactory ?? createServerReferenceRegistry;
4262
4612
  const server = options.server ?? serverFactory(undefined, { registry, type: "server" });
4263
- const partials = options.partials ?? createPartialRegistry(undefined, { registry, type: "partial" });
4613
+ const partials = options.partials ?? createPartialRegistry(undefined, { registry, type: "partial", lazyRegistry });
4264
4614
  const routes = options.routes ?? createRouteRegistry(undefined, { registry, type: "route" });
4265
- const components = options.components ?? createComponentRegistry(undefined, { registry, type: "component" });
4615
+ const components = options.components ?? createComponentRegistry(undefined, { registry, type: "component", lazyRegistry });
4616
+ const hasStartupRoot = options.loader || Object.hasOwn(options, "root");
4617
+ const startupRoot = hasStartupRoot ? options.root : null;
4266
4618
  let loader = options.loader;
4267
4619
  let router = options.router;
4620
+ let routerStarted = false;
4268
4621
  let detach = () => {};
4269
4622
  let started = false;
4270
4623
  let destroyed = false;
4624
+ const rootLoaders = new Map();
4271
4625
 
4272
- applySnapshot(signals, browserCache, options.snapshot ?? (target === "browser" ? readSnapshot(options.root, { attributes }) : undefined));
4626
+ const snapshotRoot = startupRoot ?? globalThis.document;
4627
+ const initialSnapshot = options.snapshot ?? (target === "browser" ? readSnapshot(snapshotRoot, { attributes }) : undefined);
4273
4628
  attachServerCache(server, serverCache);
4274
4629
 
4275
4630
  const runtime = {
@@ -4298,54 +4653,112 @@
4298
4653
  started = true;
4299
4654
 
4300
4655
  if (target !== "server") {
4301
- loader = loader ?? Loader({
4302
- root: options.root,
4303
- signals,
4304
- handlers,
4305
- server,
4306
- cache: browserCache,
4307
- scheduler,
4308
- attributes
4309
- });
4310
- runtime.loader = loader;
4311
-
4312
4656
  configureServerContext({ cache: browserCache });
4313
4657
  signals._setContext?.({ server, loader, cache: browserCache, scheduler });
4314
4658
 
4315
- loader.start();
4659
+ if (loader) {
4660
+ registerRootLoader(loader.root, loader);
4661
+ loader.start();
4662
+ startRouterFor(loader.root);
4663
+ } else if (startupRoot != null) {
4664
+ runtime.attachRoot(startupRoot);
4665
+ }
4666
+ } else {
4667
+ configureServerContext({ cache: serverCache });
4668
+ signals._setContext?.({ server, cache: serverCache, scheduler });
4669
+ }
4670
+
4671
+ return runtime;
4672
+ },
4673
+
4674
+ use(typeOrModule, entries) {
4675
+ app.use(typeOrModule, entries);
4676
+ return runtime;
4677
+ },
4316
4678
 
4317
- if (router !== false && (router || shouldStartRouter(routes, options))) {
4318
- router = router ?? createRouter({
4319
- mode: options.mode ?? "ssr-spa",
4320
- root: options.root,
4321
- boundary: options.boundary ?? "route",
4322
- routes,
4323
- loader,
4679
+ attachRoot(root) {
4680
+ assertActive();
4681
+ if (target === "server") {
4682
+ throw new Error("Server runtimes cannot attach DOM roots.");
4683
+ }
4684
+ if (!root) {
4685
+ throw new TypeError("runtime.attachRoot(root) requires a root.");
4686
+ }
4687
+ if (rootLoaders.has(root)) {
4688
+ return runtime;
4689
+ }
4690
+
4691
+ const rootLoader = rootLoaders.size === 0 && loader
4692
+ ? loader
4693
+ : Loader({
4694
+ root,
4324
4695
  signals,
4325
4696
  handlers,
4326
4697
  server,
4327
4698
  cache: browserCache,
4328
- partials,
4329
4699
  scheduler,
4330
- fetch: options.fetch,
4331
- routeEndpoint: options.routeEndpoint,
4332
4700
  attributes
4333
4701
  });
4334
- runtime.router = router;
4335
- loader.router = router;
4336
- configureServerContext({ cache: browserCache, router });
4337
- router.start();
4702
+ registerRootLoader(root, rootLoader);
4703
+ rootLoader.start();
4704
+ configureServerContext({ cache: browserCache });
4705
+ signals._setContext?.({ server, loader: runtime.loader, cache: browserCache, scheduler });
4706
+ startRouterFor(root);
4707
+ return runtime;
4708
+ },
4709
+
4710
+ detachRoot(root) {
4711
+ assertActive();
4712
+ if (target === "server") {
4713
+ return runtime;
4714
+ }
4715
+ if (root == null) {
4716
+ for (const rootLoader of new Set(rootLoaders.values())) {
4717
+ rootLoader.destroy?.();
4718
+ }
4719
+ rootLoaders.clear();
4720
+ router?.destroy?.();
4721
+ router = undefined;
4722
+ routerStarted = false;
4723
+ loader = undefined;
4724
+ runtime.loader = undefined;
4725
+ runtime.router = undefined;
4726
+ return runtime;
4727
+ }
4728
+ const rootLoader = rootLoaders.get(root);
4729
+ if (!rootLoader) {
4730
+ return runtime;
4731
+ }
4732
+ rootLoader.destroy?.();
4733
+ rootLoaders.delete(root);
4734
+ if (loader === rootLoader) {
4735
+ router?.destroy?.();
4736
+ router = undefined;
4737
+ routerStarted = false;
4738
+ const next = rootLoaders.values().next().value;
4739
+ loader = next;
4740
+ runtime.loader = next;
4741
+ runtime.router = undefined;
4742
+ if (next) {
4743
+ startRouterFor(next.root);
4338
4744
  }
4339
- } else {
4340
- configureServerContext({ cache: serverCache });
4341
- signals._setContext?.({ server, cache: serverCache, scheduler });
4342
4745
  }
4343
-
4344
4746
  return runtime;
4345
4747
  },
4346
4748
 
4347
- use(typeOrModule, entries) {
4348
- app.use(typeOrModule, entries);
4749
+ inspectRoots() {
4750
+ return {
4751
+ count: rootLoaders.size,
4752
+ roots: [...rootLoaders].map(([root, rootLoader]) => ({
4753
+ root,
4754
+ loader: rootLoader,
4755
+ primary: rootLoader === loader
4756
+ }))
4757
+ };
4758
+ },
4759
+
4760
+ applySnapshot(snapshot, snapshotOptions = {}) {
4761
+ applySnapshotToRuntime(runtime, snapshot, snapshotOptions);
4349
4762
  return runtime;
4350
4763
  },
4351
4764
 
@@ -4407,7 +4820,14 @@
4407
4820
  destroyed = true;
4408
4821
  detach();
4409
4822
  router?.destroy?.();
4410
- loader?.destroy?.();
4823
+ const destroyedLoaders = new Set(rootLoaders.values());
4824
+ for (const rootLoader of destroyedLoaders) {
4825
+ rootLoader.destroy?.();
4826
+ }
4827
+ rootLoaders.clear();
4828
+ if (loader && !destroyedLoaders.has(loader)) {
4829
+ loader?.destroy?.();
4830
+ }
4411
4831
  signals.destroy?.();
4412
4832
  if (ownsScheduler) {
4413
4833
  scheduler.destroy();
@@ -4421,10 +4841,49 @@
4421
4841
 
4422
4842
  server.cache = serverCache;
4423
4843
  runtime.server.cache = serverCache;
4844
+ runtime.applySnapshot(initialSnapshot, { strict: options.strictSnapshots ?? true });
4424
4845
  detach = app._attach(runtime);
4425
4846
 
4426
4847
  return runtime;
4427
4848
 
4849
+ function registerRootLoader(root, rootLoader) {
4850
+ rootLoaders.set(root, rootLoader);
4851
+ if (!loader) {
4852
+ loader = rootLoader;
4853
+ runtime.loader = rootLoader;
4854
+ }
4855
+ rootLoader.server = server;
4856
+ rootLoader.cache = browserCache;
4857
+ rootLoader.scheduler = scheduler;
4858
+ }
4859
+
4860
+ function startRouterFor(root) {
4861
+ if (router === false || routerStarted || !(router || shouldStartRouter(routes, options)) || !runtime.loader) {
4862
+ return;
4863
+ }
4864
+ router = router ?? createRouter({
4865
+ mode: options.mode ?? "ssr-spa",
4866
+ root,
4867
+ boundary: options.boundary ?? "route",
4868
+ routes,
4869
+ loader: runtime.loader,
4870
+ signals,
4871
+ handlers,
4872
+ server,
4873
+ cache: browserCache,
4874
+ partials,
4875
+ scheduler,
4876
+ fetch: options.fetch,
4877
+ routeEndpoint: options.routeEndpoint,
4878
+ attributes
4879
+ });
4880
+ runtime.router = router;
4881
+ runtime.loader.router = router;
4882
+ configureServerContext({ cache: browserCache, router });
4883
+ router.start();
4884
+ routerStarted = true;
4885
+ }
4886
+
4428
4887
  function configureServerContext(extra = {}) {
4429
4888
  const cache = isLocalServerRegistry(server) ? serverCache : extra.cache;
4430
4889
  server._setContext?.({
@@ -4467,6 +4926,7 @@
4467
4926
  return {};
4468
4927
  }
4469
4928
 
4929
+ const merged = {};
4470
4930
  for (const searchRoot of new Set([rootNode, documentRef])) {
4471
4931
  if (!searchRoot?.querySelectorAll) {
4472
4932
  continue;
@@ -4477,17 +4937,19 @@
4477
4937
  }
4478
4938
  const source = script.textContent?.trim() ?? "";
4479
4939
  if (!source) {
4480
- return {};
4940
+ continue;
4481
4941
  }
4942
+ let parsed;
4482
4943
  try {
4483
- return JSON.parse(source);
4944
+ parsed = JSON.parse(source);
4484
4945
  } catch (cause) {
4485
4946
  throw new Error(`Could not parse Async snapshot: ${cause instanceof Error ? cause.message : String(cause)}`);
4486
4947
  }
4948
+ mergeSnapshot(merged, parsed, { strict: true });
4487
4949
  }
4488
4950
  }
4489
4951
 
4490
- return {};
4952
+ return merged;
4491
4953
  }
4492
4954
 
4493
4955
  function applyUseToRuntime(runtime, normalized) {
@@ -4497,10 +4959,22 @@
4497
4959
  applyRegistryUse(runtime.partials, runtime.registry, normalized.partial);
4498
4960
  applyRegistryUse(runtime.routes, runtime.registry, normalized.route);
4499
4961
  applyRegistryUse(runtime.components, runtime.registry, normalized.component);
4962
+ applyRegistryStoreUse(runtime.registry, "asyncSignal", normalized.asyncSignal);
4500
4963
  applyRegistryUse(runtime.browser.cache, runtime.registry, normalized.cache.browser);
4501
4964
  applyRegistryUse(runtime.server.cache, runtime.registry, normalized.cache.server);
4502
4965
  }
4503
4966
 
4967
+ function applyRegistryStoreUse(registry, type, entries) {
4968
+ if (!entries || Object.keys(entries).length === 0) {
4969
+ return;
4970
+ }
4971
+ for (const [id, value] of Object.entries(entries)) {
4972
+ if (!registry.has(type, id)) {
4973
+ registry.register(type, id, value);
4974
+ }
4975
+ }
4976
+ }
4977
+
4504
4978
  function applyRegistryUse(registry, runtimeRegistry, entries) {
4505
4979
  if (!entries || Object.keys(entries).length === 0) {
4506
4980
  return;
@@ -4520,6 +4994,7 @@
4520
4994
  partial: {},
4521
4995
  route: {},
4522
4996
  component: {},
4997
+ asyncSignal: {},
4523
4998
  cache: {
4524
4999
  browser: {},
4525
5000
  server: {}
@@ -4575,11 +5050,128 @@
4575
5050
  return Boolean(value && typeof value.use === "function" && typeof value.snapshot === "function" && value.registry);
4576
5051
  }
4577
5052
 
4578
- function applySnapshot(signals, browserCache, snapshot = {}) {
4579
- for (const [path, value] of Object.entries(snapshot.signals ?? {})) {
4580
- setOrRegisterSignal(signals, path, value);
5053
+ function ensureRuntime(app) {
5054
+ if (!app.runtime) {
5055
+ app.start();
5056
+ }
5057
+ return app.runtime;
5058
+ }
5059
+
5060
+ function applySnapshotToRuntime(runtime, snapshot = {}, options = {}) {
5061
+ const normalized = normalizeSnapshot(snapshot);
5062
+ for (const [path, value] of Object.entries(normalized.signal)) {
5063
+ setOrRegisterSignal(runtime.signals, path, value);
5064
+ }
5065
+ runtime.browser.cache.restore(normalized.cache.browser);
5066
+ mergeRegistryEntries(runtime, "handler", normalized.handler, runtime.handlers, options);
5067
+ mergeRegistryEntries(runtime, "server", normalized.server, runtime.server, options);
5068
+ mergeRegistryEntries(runtime, "partial", normalized.partial, runtime.partials, options);
5069
+ mergeRegistryEntries(runtime, "route", normalized.route, runtime.routes, options);
5070
+ mergeRegistryEntries(runtime, "component", normalized.component, runtime.components, options);
5071
+ mergeRegistryEntries(runtime, "asyncSignal", normalized.asyncSignal, null, options);
5072
+ return runtime;
5073
+ }
5074
+
5075
+ function appendSnapshotDeclarations(registry, snapshot = {}, options = {}) {
5076
+ const normalized = normalizeSnapshot(snapshot);
5077
+ for (const [id, value] of Object.entries(normalized.signal)) {
5078
+ registerSnapshotEntry(registry, "signal", id, createSignal(value), options);
5079
+ }
5080
+ for (const type of ["handler", "server", "partial", "route", "component", "asyncSignal"]) {
5081
+ for (const [id, value] of Object.entries(normalized[type])) {
5082
+ registerSnapshotEntry(registry, type, id, value, options);
5083
+ }
5084
+ }
5085
+ }
5086
+
5087
+ function mergeRegistryEntries(runtime, type, entries, concreteRegistry, options = {}) {
5088
+ if (!entries || Object.keys(entries).length === 0) {
5089
+ return;
5090
+ }
5091
+ for (const [id, value] of Object.entries(entries)) {
5092
+ registerSnapshotEntry(runtime.registry, type, id, value, options);
5093
+ }
5094
+ concreteRegistry?._adoptMany?.(entries);
5095
+ }
5096
+
5097
+ function registerSnapshotEntry(registry, type, id, value, options = {}) {
5098
+ const strict = options.strict ?? true;
5099
+ const map = registry._map(type);
5100
+ if (map.has(id)) {
5101
+ if (sameRegistryValue(map.get(id), value) || sameSnapshotValue(map.get(id), value)) {
5102
+ return;
5103
+ }
5104
+ if (strict) {
5105
+ throw new Error(`${type} "${id}" is already registered with a different value.`);
5106
+ }
5107
+ return;
5108
+ }
5109
+ registry.set(type, id, value);
5110
+ }
5111
+
5112
+ function normalizeSnapshot(snapshot = {}) {
5113
+ const normalized = {
5114
+ signal: {
5115
+ ...(snapshot.signals ?? {}),
5116
+ ...(snapshot.signal ?? {})
5117
+ },
5118
+ handler: { ...(snapshot.handler ?? {}) },
5119
+ server: { ...(snapshot.server ?? {}) },
5120
+ partial: { ...(snapshot.partial ?? {}) },
5121
+ route: { ...(snapshot.route ?? {}) },
5122
+ component: { ...(snapshot.component ?? {}) },
5123
+ asyncSignal: { ...(snapshot.asyncSignal ?? {}) },
5124
+ cache: {
5125
+ browser: {
5126
+ ...(snapshot.entries?.browser ?? {}),
5127
+ ...(snapshot.cache?.browser ?? {})
5128
+ }
5129
+ }
5130
+ };
5131
+ return normalized;
5132
+ }
5133
+
5134
+ function mergeSnapshot(target, source, options = {}) {
5135
+ const normalized = normalizeSnapshot(defineRegistrySnapshot(source));
5136
+ target.signal = {
5137
+ ...(target.signal ?? target.signals ?? {}),
5138
+ ...normalized.signal
5139
+ };
5140
+ target.signals = target.signal;
5141
+ target.cache = {
5142
+ ...(target.cache ?? {}),
5143
+ browser: {
5144
+ ...(target.cache?.browser ?? {}),
5145
+ ...normalized.cache.browser
5146
+ }
5147
+ };
5148
+ for (const type of ["handler", "server", "partial", "route", "component", "asyncSignal"]) {
5149
+ target[type] = target[type] ?? {};
5150
+ for (const [id, value] of Object.entries(normalized[type])) {
5151
+ if (Object.hasOwn(target[type], id)) {
5152
+ if (sameRegistryValue(target[type][id], value) || sameSnapshotValue(target[type][id], value)) {
5153
+ continue;
5154
+ }
5155
+ if (options.strict ?? true) {
5156
+ throw new Error(`${type} "${id}" is already declared with a different value.`);
5157
+ }
5158
+ continue;
5159
+ }
5160
+ target[type][id] = value;
5161
+ }
5162
+ }
5163
+ return target;
5164
+ }
5165
+
5166
+ function sameSnapshotValue(left, right) {
5167
+ if (left === right) {
5168
+ return true;
5169
+ }
5170
+ try {
5171
+ return JSON.stringify(left) === JSON.stringify(right);
5172
+ } catch {
5173
+ return false;
4581
5174
  }
4582
- browserCache.restore(snapshot.cache?.browser);
4583
5175
  }
4584
5176
 
4585
5177
  function setOrRegisterSignal(signals, path, value) {
@@ -5064,6 +5656,72 @@
5064
5656
  return { delay };
5065
5657
  })();
5066
5658
 
5659
+ const __elementsModule = (() => {
5660
+ const { Async } = __appModule;
5661
+ function defineAsyncContainerElement(options = {}) {
5662
+ const tagName = options.tagName ?? "async-container";
5663
+ const registry = options.customElements ?? globalThis.customElements;
5664
+ if (!registry) {
5665
+ throw new Error("defineAsyncContainerElement(...) requires customElements.");
5666
+ }
5667
+ const existing = registry.get(tagName);
5668
+ if (existing) {
5669
+ return existing;
5670
+ }
5671
+ const app = options.app ?? options.Async ?? Async;
5672
+ const HTMLElementBase = options.HTMLElement ?? options.window?.HTMLElement ?? globalThis.HTMLElement;
5673
+ if (!HTMLElementBase) {
5674
+ throw new Error("defineAsyncContainerElement(...) requires HTMLElement.");
5675
+ }
5676
+
5677
+ class AsyncContainerElement extends HTMLElementBase {
5678
+ connectedCallback() {
5679
+ if (this.__asyncAttached) {
5680
+ return;
5681
+ }
5682
+ const runtime = app.runtime ?? app.start?.();
5683
+ runtime?.attachRoot?.(this);
5684
+ this.__asyncRuntime = runtime;
5685
+ this.__asyncAttached = true;
5686
+ }
5687
+
5688
+ disconnectedCallback() {
5689
+ if (!this.__asyncAttached) {
5690
+ return;
5691
+ }
5692
+ this.__asyncRuntime?.detachRoot?.(this);
5693
+ this.__asyncRuntime = undefined;
5694
+ this.__asyncAttached = false;
5695
+ }
5696
+ }
5697
+
5698
+ registry.define(tagName, AsyncContainerElement);
5699
+ return AsyncContainerElement;
5700
+ }
5701
+
5702
+ function defineAsyncSuspenseElement(options = {}) {
5703
+ const tagName = options.tagName ?? "async-suspense";
5704
+ const registry = options.customElements ?? globalThis.customElements;
5705
+ if (!registry) {
5706
+ throw new Error("defineAsyncSuspenseElement(...) requires customElements.");
5707
+ }
5708
+ const existing = registry.get(tagName);
5709
+ if (existing) {
5710
+ return existing;
5711
+ }
5712
+ const HTMLElementBase = options.HTMLElement ?? options.window?.HTMLElement ?? globalThis.HTMLElement;
5713
+ if (!HTMLElementBase) {
5714
+ throw new Error("defineAsyncSuspenseElement(...) requires HTMLElement.");
5715
+ }
5716
+
5717
+ class AsyncSuspenseElement extends HTMLElementBase {}
5718
+
5719
+ registry.define(tagName, AsyncSuspenseElement);
5720
+ return AsyncSuspenseElement;
5721
+ }
5722
+ return { defineAsyncContainerElement, defineAsyncSuspenseElement };
5723
+ })();
5724
+
5067
5725
  const { asyncSignal: asyncSignal } = __asyncSignalModule;
5068
5726
  const { Async: Async } = __appModule;
5069
5727
  const { createApp: createApp } = __appModule;
@@ -5078,8 +5736,12 @@
5078
5736
  const { createComponentRegistry: createComponentRegistry } = __componentModule;
5079
5737
  const { defineComponent: defineComponent } = __componentModule;
5080
5738
  const { delay: delay } = __delayModule;
5739
+ const { defineAsyncContainerElement: defineAsyncContainerElement } = __elementsModule;
5740
+ const { defineAsyncSuspenseElement: defineAsyncSuspenseElement } = __elementsModule;
5081
5741
  const { createHandlerRegistry: createHandlerRegistry } = __handlersModule;
5082
5742
  const { html: html } = __htmlModule;
5743
+ const { createLazyRegistry: createLazyRegistry } = __lazyRegistryModule;
5744
+ const { defineRegistrySnapshot: defineRegistrySnapshot } = __lazyRegistryModule;
5083
5745
  const { Loader: Loader } = __loaderModule;
5084
5746
  const { AsyncLoader: AsyncLoader } = __loaderModule;
5085
5747
  const { createPartialRegistry: createPartialRegistry } = __partialsModule;
@@ -5098,7 +5760,7 @@
5098
5760
  const { createSignalRegistry: createSignalRegistry } = __signalsModule;
5099
5761
  const { effect: effect } = __signalsModule;
5100
5762
  const { signal: signal } = __signalsModule;
5101
- const api = { 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 };
5763
+ const api = { 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 };
5102
5764
  assertNoUmdNamespaceConflicts(api, Async);
5103
5765
  Object.assign(Async, api);
5104
5766
  Async.Async = Async;