@async/framework 0.11.19 → 0.11.23

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
@@ -2053,10 +2053,11 @@
2053
2053
  const { createLazyRegistry, isLazyDescriptor } = __lazyRegistryModule;
2054
2054
  const componentKind = Symbol.for("@async/framework.component");
2055
2055
  let componentCounter = 0;
2056
+ let defineComponentWarned = false;
2056
2057
 
2057
- function defineComponent(fn) {
2058
+ function component(fn) {
2058
2059
  if (typeof fn !== "function") {
2059
- throw new TypeError("defineComponent(fn) requires a function.");
2060
+ throw new TypeError("component(fn) requires a function.");
2060
2061
  }
2061
2062
  Object.defineProperty(fn, componentKind, {
2062
2063
  configurable: true,
@@ -2065,7 +2066,13 @@
2065
2066
  return fn;
2066
2067
  }
2067
2068
 
2068
- const component = defineComponent;
2069
+ function defineComponent(fn) {
2070
+ if (!defineComponentWarned) {
2071
+ defineComponentWarned = true;
2072
+ console.warn?.("defineComponent(...) is deprecated. Use component(...) instead.");
2073
+ }
2074
+ return component(fn);
2075
+ }
2069
2076
 
2070
2077
  function createComponentRegistry(initialMap = {}, options = {}) {
2071
2078
  const registryStore = options.registry ?? createRegistryStore();
@@ -2264,10 +2271,11 @@
2264
2271
  }
2265
2272
 
2266
2273
  function createComponentContext({ runtime, scope, cleanups, attachHooks, visibleHooks, intersectionHooks, destroyHooks, renderScopedTemplate }) {
2267
- const { signals, handlers, loader, server, router, cache, scheduler } = runtime;
2274
+ const { signals, handlers, loader, server, router, cache, components, scheduler } = runtime;
2268
2275
  const generatedHandlers = new WeakMap();
2269
2276
  let generatedHandlerCounter = 0;
2270
2277
  let generatedSignalCounter = 0;
2278
+ let generatedSlotCounter = 0;
2271
2279
  const context = {
2272
2280
  scope,
2273
2281
  signals,
@@ -2276,6 +2284,7 @@
2276
2284
  server,
2277
2285
  router,
2278
2286
  cache,
2287
+ components,
2279
2288
  scheduler,
2280
2289
 
2281
2290
  signal(name, initial) {
@@ -2355,6 +2364,38 @@
2355
2364
  return rawHtml(child.html);
2356
2365
  },
2357
2366
 
2367
+ slot(Child, propsOrFn = {}) {
2368
+ let target;
2369
+ let latestProps = {};
2370
+ const renderSlot = () => {
2371
+ if (!target) {
2372
+ return;
2373
+ }
2374
+ loader.mount(target, Child, latestProps);
2375
+ };
2376
+ const attach = registerScopedHandler(`slot.${++generatedSlotCounter}.attach`, function ({ element }) {
2377
+ target = element;
2378
+ renderSlot();
2379
+ return () => {
2380
+ target = undefined;
2381
+ };
2382
+ });
2383
+ const cleanup = signals.effect(() => {
2384
+ latestProps = typeof propsOrFn === "function" ? propsOrFn.call(context) : propsOrFn;
2385
+ renderSlot();
2386
+ }, {
2387
+ scheduler,
2388
+ phase: "effect",
2389
+ scope,
2390
+ key: `slot:${generatedSlotCounter}`
2391
+ });
2392
+ cleanups.push(cleanup);
2393
+ return {
2394
+ attach,
2395
+ render: renderSlot
2396
+ };
2397
+ },
2398
+
2358
2399
  suspense(signalRef, views) {
2359
2400
  const id = signalRef?.id;
2360
2401
  if (!id) {
@@ -2474,7 +2515,7 @@
2474
2515
  function componentName(Component) {
2475
2516
  return Component.displayName || Component.name || "anonymous";
2476
2517
  }
2477
- return { defineComponent, createComponentRegistry, isComponent, renderComponent, component };
2518
+ return { component, defineComponent, createComponentRegistry, isComponent, renderComponent };
2478
2519
  })();
2479
2520
 
2480
2521
  const __serverModule = (() => {
@@ -3531,7 +3572,7 @@
3531
3572
  const { matchAttribute, normalizeAttributeConfig, readAttribute } = __attributesModule;
3532
3573
  const inlineBindingPrefix = "__async:inline:";
3533
3574
 
3534
- function Loader({ root, signals, handlers, server, router, cache, attributes, scheduler } = {}) {
3575
+ function Loader({ root, signals, handlers, server, router, cache, components, attributes, scheduler } = {}) {
3535
3576
  const documentRef = root?.ownerDocument ?? root ?? globalThis.document;
3536
3577
  const rootNode = root ?? documentRef;
3537
3578
  const signalRegistry = signals ?? createSignalRegistry();
@@ -3547,6 +3588,7 @@
3547
3588
  const intersectionBindings = new WeakMap();
3548
3589
  const boundaryState = new WeakMap();
3549
3590
  const renderingBoundaries = new WeakSet();
3591
+ const componentBindings = new WeakSet();
3550
3592
  const inlineBindings = new Map();
3551
3593
  const scopedCleanups = new WeakMap();
3552
3594
  let inlineBindingCounter = 0;
@@ -3559,6 +3601,7 @@
3559
3601
  server,
3560
3602
  router,
3561
3603
  cache,
3604
+ components,
3562
3605
  scheduler: schedulerInstance,
3563
3606
  attributes: attributeConfig,
3564
3607
 
@@ -3575,6 +3618,7 @@
3575
3618
  bindClassAttributes(rootOrFragment);
3576
3619
  bindEventAttributes(rootOrFragment);
3577
3620
  bindBoundaries(rootOrFragment);
3621
+ bindComponentAttributes(rootOrFragment);
3578
3622
  runPseudoEvents(rootOrFragment);
3579
3623
  return api;
3580
3624
  },
@@ -3600,6 +3644,7 @@
3600
3644
  server: api.server,
3601
3645
  router: api.router,
3602
3646
  cache: api.cache,
3647
+ components: api.components,
3603
3648
  scheduler: schedulerInstance,
3604
3649
  attributes: attributeConfig
3605
3650
  });
@@ -3894,6 +3939,32 @@
3894
3939
  }
3895
3940
  }
3896
3941
 
3942
+ function bindComponentAttributes(scope) {
3943
+ for (const element of elementsIn(scope)) {
3944
+ const id = readAttribute(element, attributeConfig, "async", "component");
3945
+ if (id == null) {
3946
+ continue;
3947
+ }
3948
+ if (componentBindings.has(element)) {
3949
+ continue;
3950
+ }
3951
+ if (!components?.resolve) {
3952
+ throw new Error(`Component "${id}" cannot be mounted because no component registry is available.`);
3953
+ }
3954
+ const Component = components.resolve(id);
3955
+ if (!Component) {
3956
+ throw new Error(`Component "${id}" was not found.`);
3957
+ }
3958
+ componentBindings.add(element);
3959
+ try {
3960
+ api.mount(element, Component);
3961
+ } catch (error) {
3962
+ componentBindings.delete(element);
3963
+ throw error;
3964
+ }
3965
+ }
3966
+ }
3967
+
3897
3968
  function renderBoundary(boundary) {
3898
3969
  const state = boundaryState.get(boundary);
3899
3970
  if (!state) {
@@ -5273,9 +5344,12 @@
5273
5344
  const registry = createRegistryStore(undefined, { target: "browser" });
5274
5345
  const runtimes = new Set();
5275
5346
  const createRuntime = options.createRuntime ?? createApp;
5347
+ const loaderFacade = createLoaderFacade();
5348
+ let currentRuntime;
5276
5349
 
5277
5350
  const app = {
5278
5351
  registry,
5352
+ loader: loaderFacade,
5279
5353
 
5280
5354
  use(typeOrModule, entries) {
5281
5355
  const normalized = normalizeUse(typeOrModule, entries);
@@ -5292,7 +5366,7 @@
5292
5366
 
5293
5367
  start(options = {}) {
5294
5368
  const runtime = createRuntime(app, options).start();
5295
- app.runtime = runtime;
5369
+ setCurrentRuntime(runtime);
5296
5370
  return runtime;
5297
5371
  },
5298
5372
 
@@ -5301,12 +5375,12 @@
5301
5375
  },
5302
5376
 
5303
5377
  detachRoot(root) {
5304
- return app.runtime?.detachRoot(root) ?? app;
5378
+ return currentRuntime?.detachRoot(root) ?? app;
5305
5379
  },
5306
5380
 
5307
5381
  applySnapshot(snapshot, snapshotOptions = {}) {
5308
- if (app.runtime) {
5309
- app.runtime.applySnapshot(snapshot, snapshotOptions);
5382
+ if (currentRuntime) {
5383
+ currentRuntime.applySnapshot(snapshot, snapshotOptions);
5310
5384
  return app;
5311
5385
  }
5312
5386
  appendSnapshotDeclarations(registry, snapshot, snapshotOptions);
@@ -5314,7 +5388,11 @@
5314
5388
  },
5315
5389
 
5316
5390
  inspectRoots() {
5317
- return app.runtime?.inspectRoots() ?? { count: 0, roots: [] };
5391
+ return currentRuntime?.inspectRoots() ?? { count: 0, roots: [] };
5392
+ },
5393
+
5394
+ inspectRuntime() {
5395
+ return inspectRuntimeState(currentRuntime, loaderFacade);
5318
5396
  },
5319
5397
 
5320
5398
  _attach(runtime) {
@@ -5324,14 +5402,36 @@
5324
5402
 
5325
5403
  _detach(runtime) {
5326
5404
  runtimes.delete(runtime);
5405
+ if (currentRuntime === runtime) {
5406
+ currentRuntime = latestRuntime(runtimes);
5407
+ }
5327
5408
  }
5328
5409
  };
5329
5410
 
5411
+ Object.defineProperties(app, {
5412
+ _runtime: {
5413
+ get() {
5414
+ return currentRuntime;
5415
+ }
5416
+ },
5417
+ _setRuntime: {
5418
+ value(runtime) {
5419
+ setCurrentRuntime(runtime);
5420
+ }
5421
+ }
5422
+ });
5423
+
5330
5424
  if (initial) {
5331
5425
  app.use(initial);
5332
5426
  }
5333
5427
 
5334
5428
  return app;
5429
+
5430
+ function setCurrentRuntime(runtime) {
5431
+ if (runtime) {
5432
+ currentRuntime = runtime;
5433
+ }
5434
+ }
5335
5435
  }
5336
5436
 
5337
5437
  function createApp(appOrDefinition = Async, options = {}) {
@@ -5394,6 +5494,7 @@
5394
5494
  return runtime;
5395
5495
  }
5396
5496
  started = true;
5497
+ app._setRuntime?.(runtime);
5397
5498
 
5398
5499
  if (target !== "server") {
5399
5500
  configureServerContext({ cache: browserCache });
@@ -5403,6 +5504,7 @@
5403
5504
  registerRootLoader(loader.root, loader);
5404
5505
  loader.start();
5405
5506
  startRouterFor(loader.root);
5507
+ app.loader._setCurrent(runtime.loader);
5406
5508
  } else if (startupRoot != null) {
5407
5509
  runtime.attachRoot(startupRoot);
5408
5510
  }
@@ -5439,6 +5541,7 @@
5439
5541
  handlers,
5440
5542
  server,
5441
5543
  cache: browserCache,
5544
+ components,
5442
5545
  scheduler,
5443
5546
  attributes
5444
5547
  });
@@ -5447,6 +5550,7 @@
5447
5550
  configureServerContext({ cache: browserCache });
5448
5551
  signals._setContext?.({ server, loader: runtime.loader, cache: browserCache, scheduler });
5449
5552
  startRouterFor(root);
5553
+ app.loader._setCurrent(runtime.loader);
5450
5554
  return runtime;
5451
5555
  },
5452
5556
 
@@ -5456,6 +5560,7 @@
5456
5560
  return runtime;
5457
5561
  }
5458
5562
  if (root == null) {
5563
+ const detachedLoaders = [...new Set(rootLoaders.values())];
5459
5564
  for (const rootLoader of new Set(rootLoaders.values())) {
5460
5565
  rootLoader.destroy?.();
5461
5566
  }
@@ -5466,6 +5571,7 @@
5466
5571
  loader = undefined;
5467
5572
  runtime.loader = undefined;
5468
5573
  runtime.router = undefined;
5574
+ app.loader._clearCurrent(detachedLoaders);
5469
5575
  return runtime;
5470
5576
  }
5471
5577
  const rootLoader = rootLoaders.get(root);
@@ -5484,6 +5590,9 @@
5484
5590
  runtime.router = undefined;
5485
5591
  if (next) {
5486
5592
  startRouterFor(next.root);
5593
+ app.loader._setCurrent(next);
5594
+ } else {
5595
+ app.loader._clearCurrent(rootLoader);
5487
5596
  }
5488
5597
  }
5489
5598
  return runtime;
@@ -5571,6 +5680,8 @@
5571
5680
  if (loader && !destroyedLoaders.has(loader)) {
5572
5681
  loader?.destroy?.();
5573
5682
  }
5683
+ app.loader._clearCurrent([...destroyedLoaders, loader]);
5684
+ app.loader._rejectPending(new Error("Async loader queue was cleared because the runtime was destroyed."));
5574
5685
  signals.destroy?.();
5575
5686
  if (ownsScheduler) {
5576
5687
  scheduler.destroy();
@@ -5582,6 +5693,22 @@
5582
5693
  }
5583
5694
  };
5584
5695
 
5696
+ Object.defineProperties(runtime, {
5697
+ _inspect: {
5698
+ value() {
5699
+ return {
5700
+ active: !destroyed,
5701
+ started,
5702
+ destroyed,
5703
+ target,
5704
+ roots: runtime.inspectRoots(),
5705
+ loader: app.loader.inspect(),
5706
+ router: Boolean(runtime.router)
5707
+ };
5708
+ }
5709
+ }
5710
+ });
5711
+
5585
5712
  server.cache = serverCache;
5586
5713
  runtime.server.cache = serverCache;
5587
5714
  runtime.applySnapshot(initialSnapshot, { strict: options.strictSnapshots ?? true });
@@ -5658,6 +5785,107 @@
5658
5785
 
5659
5786
  const Async = defineApp();
5660
5787
 
5788
+ function createLoaderFacade() {
5789
+ let current;
5790
+ const pending = [];
5791
+ const readyWaiters = [];
5792
+
5793
+ const facade = {
5794
+ get current() {
5795
+ return current;
5796
+ },
5797
+
5798
+ ready() {
5799
+ if (current) {
5800
+ return Promise.resolve(current);
5801
+ }
5802
+ return new Promise((resolve, reject) => {
5803
+ readyWaiters.push({ resolve, reject });
5804
+ });
5805
+ },
5806
+
5807
+ scan(rootOrFragment) {
5808
+ return enqueue("scan", [rootOrFragment]);
5809
+ },
5810
+
5811
+ swap(boundaryId, fragmentOrTemplate) {
5812
+ return enqueue("swap", [boundaryId, fragmentOrTemplate]);
5813
+ },
5814
+
5815
+ mount(target, Component, props) {
5816
+ return enqueue("mount", [target, Component, props]);
5817
+ },
5818
+
5819
+ inspect() {
5820
+ return {
5821
+ ready: Boolean(current),
5822
+ pending: pending.length,
5823
+ root: current?.root
5824
+ };
5825
+ }
5826
+ };
5827
+
5828
+ Object.defineProperties(facade, {
5829
+ _setCurrent: {
5830
+ value(loader) {
5831
+ if (!loader) {
5832
+ return;
5833
+ }
5834
+ current = loader;
5835
+ while (readyWaiters.length > 0) {
5836
+ readyWaiters.shift().resolve(loader);
5837
+ }
5838
+ flushPending(loader);
5839
+ }
5840
+ },
5841
+ _clearCurrent: {
5842
+ value(loaderOrLoaders) {
5843
+ if (loaderOrLoaders === undefined) {
5844
+ current = undefined;
5845
+ return;
5846
+ }
5847
+ const loaders = Array.isArray(loaderOrLoaders) ? loaderOrLoaders : [loaderOrLoaders];
5848
+ if (loaders.includes(current)) {
5849
+ current = undefined;
5850
+ }
5851
+ }
5852
+ },
5853
+ _rejectPending: {
5854
+ value(error) {
5855
+ while (pending.length > 0) {
5856
+ pending.shift().reject(error);
5857
+ }
5858
+ while (readyWaiters.length > 0) {
5859
+ readyWaiters.shift().reject(error);
5860
+ }
5861
+ }
5862
+ }
5863
+ });
5864
+
5865
+ return facade;
5866
+
5867
+ function enqueue(method, args) {
5868
+ if (current) {
5869
+ return invoke(current, method, args);
5870
+ }
5871
+ return new Promise((resolve, reject) => {
5872
+ pending.push({ method, args, resolve, reject });
5873
+ });
5874
+ }
5875
+
5876
+ function flushPending(loader) {
5877
+ while (pending.length > 0) {
5878
+ const operation = pending.shift();
5879
+ invoke(loader, operation.method, operation.args)
5880
+ .then(operation.resolve, operation.reject);
5881
+ }
5882
+ }
5883
+
5884
+ async function invoke(loader, method, args) {
5885
+ return loader[method](...args);
5886
+ }
5887
+ }
5888
+
5661
5889
  function readSnapshot(root = globalThis.document, { attributes } = {}) {
5662
5890
  const attributeConfig = normalizeAttributeConfig(attributes);
5663
5891
  const snapshotAttr = attributeName(attributeConfig, "async", "snapshot");
@@ -5808,10 +6036,33 @@
5808
6036
  }
5809
6037
 
5810
6038
  function ensureRuntime(app) {
5811
- if (!app.runtime) {
6039
+ if (!app._runtime) {
5812
6040
  app.start();
5813
6041
  }
5814
- return app.runtime;
6042
+ return app._runtime;
6043
+ }
6044
+
6045
+ function latestRuntime(runtimes) {
6046
+ let latest;
6047
+ for (const runtime of runtimes) {
6048
+ latest = runtime;
6049
+ }
6050
+ return latest;
6051
+ }
6052
+
6053
+ function inspectRuntimeState(runtime, loaderFacade) {
6054
+ if (runtime?._inspect) {
6055
+ return runtime._inspect();
6056
+ }
6057
+ return {
6058
+ active: Boolean(runtime),
6059
+ started: Boolean(runtime),
6060
+ destroyed: false,
6061
+ target: runtime?.target,
6062
+ roots: runtime?.inspectRoots?.() ?? { count: 0, roots: [] },
6063
+ loader: loaderFacade.inspect(),
6064
+ router: Boolean(runtime?.router)
6065
+ };
5815
6066
  }
5816
6067
 
5817
6068
  function applySnapshotToRuntime(runtime, snapshot = {}, options = {}) {
@@ -6592,7 +6843,7 @@
6592
6843
  if (options.receiver && typeof options.receiver.apply === "function") {
6593
6844
  return options.receiver;
6594
6845
  }
6595
- const runtime = options.runtime ?? globalThis.Async?.runtime;
6846
+ const runtime = options.runtime ?? globalThis.Async?._runtime;
6596
6847
  const loader = options.loader ?? runtime?.loader;
6597
6848
  if (!loader) {
6598
6849
  throw new TypeError("AsyncStream requires receiver, loader, or runtime.loader.");
@@ -7189,7 +7440,7 @@
7189
7440
  if (this.__asyncAttached) {
7190
7441
  return;
7191
7442
  }
7192
- const runtime = app.runtime ?? app.start?.();
7443
+ const runtime = app._runtime ?? app.start?.();
7193
7444
  runtime?.attachRoot?.(this);
7194
7445
  this.__asyncRuntime = runtime;
7195
7446
  this.__asyncAttached = true;