@async/framework 0.11.22 → 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.js CHANGED
@@ -2042,10 +2042,11 @@ const __componentModule = (() => {
2042
2042
  const { createLazyRegistry, isLazyDescriptor } = __lazyRegistryModule;
2043
2043
  const componentKind = Symbol.for("@async/framework.component");
2044
2044
  let componentCounter = 0;
2045
+ let defineComponentWarned = false;
2045
2046
 
2046
- function defineComponent(fn) {
2047
+ function component(fn) {
2047
2048
  if (typeof fn !== "function") {
2048
- throw new TypeError("defineComponent(fn) requires a function.");
2049
+ throw new TypeError("component(fn) requires a function.");
2049
2050
  }
2050
2051
  Object.defineProperty(fn, componentKind, {
2051
2052
  configurable: true,
@@ -2054,7 +2055,13 @@ const __componentModule = (() => {
2054
2055
  return fn;
2055
2056
  }
2056
2057
 
2057
- const component = defineComponent;
2058
+ function defineComponent(fn) {
2059
+ if (!defineComponentWarned) {
2060
+ defineComponentWarned = true;
2061
+ console.warn?.("defineComponent(...) is deprecated. Use component(...) instead.");
2062
+ }
2063
+ return component(fn);
2064
+ }
2058
2065
 
2059
2066
  function createComponentRegistry(initialMap = {}, options = {}) {
2060
2067
  const registryStore = options.registry ?? createRegistryStore();
@@ -2253,10 +2260,11 @@ const __componentModule = (() => {
2253
2260
  }
2254
2261
 
2255
2262
  function createComponentContext({ runtime, scope, cleanups, attachHooks, visibleHooks, intersectionHooks, destroyHooks, renderScopedTemplate }) {
2256
- const { signals, handlers, loader, server, router, cache, scheduler } = runtime;
2263
+ const { signals, handlers, loader, server, router, cache, components, scheduler } = runtime;
2257
2264
  const generatedHandlers = new WeakMap();
2258
2265
  let generatedHandlerCounter = 0;
2259
2266
  let generatedSignalCounter = 0;
2267
+ let generatedSlotCounter = 0;
2260
2268
  const context = {
2261
2269
  scope,
2262
2270
  signals,
@@ -2265,6 +2273,7 @@ const __componentModule = (() => {
2265
2273
  server,
2266
2274
  router,
2267
2275
  cache,
2276
+ components,
2268
2277
  scheduler,
2269
2278
 
2270
2279
  signal(name, initial) {
@@ -2344,6 +2353,38 @@ const __componentModule = (() => {
2344
2353
  return rawHtml(child.html);
2345
2354
  },
2346
2355
 
2356
+ slot(Child, propsOrFn = {}) {
2357
+ let target;
2358
+ let latestProps = {};
2359
+ const renderSlot = () => {
2360
+ if (!target) {
2361
+ return;
2362
+ }
2363
+ loader.mount(target, Child, latestProps);
2364
+ };
2365
+ const attach = registerScopedHandler(`slot.${++generatedSlotCounter}.attach`, function ({ element }) {
2366
+ target = element;
2367
+ renderSlot();
2368
+ return () => {
2369
+ target = undefined;
2370
+ };
2371
+ });
2372
+ const cleanup = signals.effect(() => {
2373
+ latestProps = typeof propsOrFn === "function" ? propsOrFn.call(context) : propsOrFn;
2374
+ renderSlot();
2375
+ }, {
2376
+ scheduler,
2377
+ phase: "effect",
2378
+ scope,
2379
+ key: `slot:${generatedSlotCounter}`
2380
+ });
2381
+ cleanups.push(cleanup);
2382
+ return {
2383
+ attach,
2384
+ render: renderSlot
2385
+ };
2386
+ },
2387
+
2347
2388
  suspense(signalRef, views) {
2348
2389
  const id = signalRef?.id;
2349
2390
  if (!id) {
@@ -2463,7 +2504,7 @@ const __componentModule = (() => {
2463
2504
  function componentName(Component) {
2464
2505
  return Component.displayName || Component.name || "anonymous";
2465
2506
  }
2466
- return { defineComponent, createComponentRegistry, isComponent, renderComponent, component };
2507
+ return { component, defineComponent, createComponentRegistry, isComponent, renderComponent };
2467
2508
  })();
2468
2509
 
2469
2510
  const __serverModule = (() => {
@@ -3520,7 +3561,7 @@ const __loaderModule = (() => {
3520
3561
  const { matchAttribute, normalizeAttributeConfig, readAttribute } = __attributesModule;
3521
3562
  const inlineBindingPrefix = "__async:inline:";
3522
3563
 
3523
- function Loader({ root, signals, handlers, server, router, cache, attributes, scheduler } = {}) {
3564
+ function Loader({ root, signals, handlers, server, router, cache, components, attributes, scheduler } = {}) {
3524
3565
  const documentRef = root?.ownerDocument ?? root ?? globalThis.document;
3525
3566
  const rootNode = root ?? documentRef;
3526
3567
  const signalRegistry = signals ?? createSignalRegistry();
@@ -3536,6 +3577,7 @@ const __loaderModule = (() => {
3536
3577
  const intersectionBindings = new WeakMap();
3537
3578
  const boundaryState = new WeakMap();
3538
3579
  const renderingBoundaries = new WeakSet();
3580
+ const componentBindings = new WeakSet();
3539
3581
  const inlineBindings = new Map();
3540
3582
  const scopedCleanups = new WeakMap();
3541
3583
  let inlineBindingCounter = 0;
@@ -3548,6 +3590,7 @@ const __loaderModule = (() => {
3548
3590
  server,
3549
3591
  router,
3550
3592
  cache,
3593
+ components,
3551
3594
  scheduler: schedulerInstance,
3552
3595
  attributes: attributeConfig,
3553
3596
 
@@ -3564,6 +3607,7 @@ const __loaderModule = (() => {
3564
3607
  bindClassAttributes(rootOrFragment);
3565
3608
  bindEventAttributes(rootOrFragment);
3566
3609
  bindBoundaries(rootOrFragment);
3610
+ bindComponentAttributes(rootOrFragment);
3567
3611
  runPseudoEvents(rootOrFragment);
3568
3612
  return api;
3569
3613
  },
@@ -3589,6 +3633,7 @@ const __loaderModule = (() => {
3589
3633
  server: api.server,
3590
3634
  router: api.router,
3591
3635
  cache: api.cache,
3636
+ components: api.components,
3592
3637
  scheduler: schedulerInstance,
3593
3638
  attributes: attributeConfig
3594
3639
  });
@@ -3883,6 +3928,32 @@ const __loaderModule = (() => {
3883
3928
  }
3884
3929
  }
3885
3930
 
3931
+ function bindComponentAttributes(scope) {
3932
+ for (const element of elementsIn(scope)) {
3933
+ const id = readAttribute(element, attributeConfig, "async", "component");
3934
+ if (id == null) {
3935
+ continue;
3936
+ }
3937
+ if (componentBindings.has(element)) {
3938
+ continue;
3939
+ }
3940
+ if (!components?.resolve) {
3941
+ throw new Error(`Component "${id}" cannot be mounted because no component registry is available.`);
3942
+ }
3943
+ const Component = components.resolve(id);
3944
+ if (!Component) {
3945
+ throw new Error(`Component "${id}" was not found.`);
3946
+ }
3947
+ componentBindings.add(element);
3948
+ try {
3949
+ api.mount(element, Component);
3950
+ } catch (error) {
3951
+ componentBindings.delete(element);
3952
+ throw error;
3953
+ }
3954
+ }
3955
+ }
3956
+
3886
3957
  function renderBoundary(boundary) {
3887
3958
  const state = boundaryState.get(boundary);
3888
3959
  if (!state) {
@@ -5262,9 +5333,12 @@ const __appModule = (() => {
5262
5333
  const registry = createRegistryStore(undefined, { target: "browser" });
5263
5334
  const runtimes = new Set();
5264
5335
  const createRuntime = options.createRuntime ?? createApp;
5336
+ const loaderFacade = createLoaderFacade();
5337
+ let currentRuntime;
5265
5338
 
5266
5339
  const app = {
5267
5340
  registry,
5341
+ loader: loaderFacade,
5268
5342
 
5269
5343
  use(typeOrModule, entries) {
5270
5344
  const normalized = normalizeUse(typeOrModule, entries);
@@ -5281,7 +5355,7 @@ const __appModule = (() => {
5281
5355
 
5282
5356
  start(options = {}) {
5283
5357
  const runtime = createRuntime(app, options).start();
5284
- app.runtime = runtime;
5358
+ setCurrentRuntime(runtime);
5285
5359
  return runtime;
5286
5360
  },
5287
5361
 
@@ -5290,12 +5364,12 @@ const __appModule = (() => {
5290
5364
  },
5291
5365
 
5292
5366
  detachRoot(root) {
5293
- return app.runtime?.detachRoot(root) ?? app;
5367
+ return currentRuntime?.detachRoot(root) ?? app;
5294
5368
  },
5295
5369
 
5296
5370
  applySnapshot(snapshot, snapshotOptions = {}) {
5297
- if (app.runtime) {
5298
- app.runtime.applySnapshot(snapshot, snapshotOptions);
5371
+ if (currentRuntime) {
5372
+ currentRuntime.applySnapshot(snapshot, snapshotOptions);
5299
5373
  return app;
5300
5374
  }
5301
5375
  appendSnapshotDeclarations(registry, snapshot, snapshotOptions);
@@ -5303,7 +5377,11 @@ const __appModule = (() => {
5303
5377
  },
5304
5378
 
5305
5379
  inspectRoots() {
5306
- return app.runtime?.inspectRoots() ?? { count: 0, roots: [] };
5380
+ return currentRuntime?.inspectRoots() ?? { count: 0, roots: [] };
5381
+ },
5382
+
5383
+ inspectRuntime() {
5384
+ return inspectRuntimeState(currentRuntime, loaderFacade);
5307
5385
  },
5308
5386
 
5309
5387
  _attach(runtime) {
@@ -5313,14 +5391,36 @@ const __appModule = (() => {
5313
5391
 
5314
5392
  _detach(runtime) {
5315
5393
  runtimes.delete(runtime);
5394
+ if (currentRuntime === runtime) {
5395
+ currentRuntime = latestRuntime(runtimes);
5396
+ }
5316
5397
  }
5317
5398
  };
5318
5399
 
5400
+ Object.defineProperties(app, {
5401
+ _runtime: {
5402
+ get() {
5403
+ return currentRuntime;
5404
+ }
5405
+ },
5406
+ _setRuntime: {
5407
+ value(runtime) {
5408
+ setCurrentRuntime(runtime);
5409
+ }
5410
+ }
5411
+ });
5412
+
5319
5413
  if (initial) {
5320
5414
  app.use(initial);
5321
5415
  }
5322
5416
 
5323
5417
  return app;
5418
+
5419
+ function setCurrentRuntime(runtime) {
5420
+ if (runtime) {
5421
+ currentRuntime = runtime;
5422
+ }
5423
+ }
5324
5424
  }
5325
5425
 
5326
5426
  function createApp(appOrDefinition = Async, options = {}) {
@@ -5383,6 +5483,7 @@ const __appModule = (() => {
5383
5483
  return runtime;
5384
5484
  }
5385
5485
  started = true;
5486
+ app._setRuntime?.(runtime);
5386
5487
 
5387
5488
  if (target !== "server") {
5388
5489
  configureServerContext({ cache: browserCache });
@@ -5392,6 +5493,7 @@ const __appModule = (() => {
5392
5493
  registerRootLoader(loader.root, loader);
5393
5494
  loader.start();
5394
5495
  startRouterFor(loader.root);
5496
+ app.loader._setCurrent(runtime.loader);
5395
5497
  } else if (startupRoot != null) {
5396
5498
  runtime.attachRoot(startupRoot);
5397
5499
  }
@@ -5428,6 +5530,7 @@ const __appModule = (() => {
5428
5530
  handlers,
5429
5531
  server,
5430
5532
  cache: browserCache,
5533
+ components,
5431
5534
  scheduler,
5432
5535
  attributes
5433
5536
  });
@@ -5436,6 +5539,7 @@ const __appModule = (() => {
5436
5539
  configureServerContext({ cache: browserCache });
5437
5540
  signals._setContext?.({ server, loader: runtime.loader, cache: browserCache, scheduler });
5438
5541
  startRouterFor(root);
5542
+ app.loader._setCurrent(runtime.loader);
5439
5543
  return runtime;
5440
5544
  },
5441
5545
 
@@ -5445,6 +5549,7 @@ const __appModule = (() => {
5445
5549
  return runtime;
5446
5550
  }
5447
5551
  if (root == null) {
5552
+ const detachedLoaders = [...new Set(rootLoaders.values())];
5448
5553
  for (const rootLoader of new Set(rootLoaders.values())) {
5449
5554
  rootLoader.destroy?.();
5450
5555
  }
@@ -5455,6 +5560,7 @@ const __appModule = (() => {
5455
5560
  loader = undefined;
5456
5561
  runtime.loader = undefined;
5457
5562
  runtime.router = undefined;
5563
+ app.loader._clearCurrent(detachedLoaders);
5458
5564
  return runtime;
5459
5565
  }
5460
5566
  const rootLoader = rootLoaders.get(root);
@@ -5473,6 +5579,9 @@ const __appModule = (() => {
5473
5579
  runtime.router = undefined;
5474
5580
  if (next) {
5475
5581
  startRouterFor(next.root);
5582
+ app.loader._setCurrent(next);
5583
+ } else {
5584
+ app.loader._clearCurrent(rootLoader);
5476
5585
  }
5477
5586
  }
5478
5587
  return runtime;
@@ -5560,6 +5669,8 @@ const __appModule = (() => {
5560
5669
  if (loader && !destroyedLoaders.has(loader)) {
5561
5670
  loader?.destroy?.();
5562
5671
  }
5672
+ app.loader._clearCurrent([...destroyedLoaders, loader]);
5673
+ app.loader._rejectPending(new Error("Async loader queue was cleared because the runtime was destroyed."));
5563
5674
  signals.destroy?.();
5564
5675
  if (ownsScheduler) {
5565
5676
  scheduler.destroy();
@@ -5571,6 +5682,22 @@ const __appModule = (() => {
5571
5682
  }
5572
5683
  };
5573
5684
 
5685
+ Object.defineProperties(runtime, {
5686
+ _inspect: {
5687
+ value() {
5688
+ return {
5689
+ active: !destroyed,
5690
+ started,
5691
+ destroyed,
5692
+ target,
5693
+ roots: runtime.inspectRoots(),
5694
+ loader: app.loader.inspect(),
5695
+ router: Boolean(runtime.router)
5696
+ };
5697
+ }
5698
+ }
5699
+ });
5700
+
5574
5701
  server.cache = serverCache;
5575
5702
  runtime.server.cache = serverCache;
5576
5703
  runtime.applySnapshot(initialSnapshot, { strict: options.strictSnapshots ?? true });
@@ -5647,6 +5774,107 @@ const __appModule = (() => {
5647
5774
 
5648
5775
  const Async = defineApp();
5649
5776
 
5777
+ function createLoaderFacade() {
5778
+ let current;
5779
+ const pending = [];
5780
+ const readyWaiters = [];
5781
+
5782
+ const facade = {
5783
+ get current() {
5784
+ return current;
5785
+ },
5786
+
5787
+ ready() {
5788
+ if (current) {
5789
+ return Promise.resolve(current);
5790
+ }
5791
+ return new Promise((resolve, reject) => {
5792
+ readyWaiters.push({ resolve, reject });
5793
+ });
5794
+ },
5795
+
5796
+ scan(rootOrFragment) {
5797
+ return enqueue("scan", [rootOrFragment]);
5798
+ },
5799
+
5800
+ swap(boundaryId, fragmentOrTemplate) {
5801
+ return enqueue("swap", [boundaryId, fragmentOrTemplate]);
5802
+ },
5803
+
5804
+ mount(target, Component, props) {
5805
+ return enqueue("mount", [target, Component, props]);
5806
+ },
5807
+
5808
+ inspect() {
5809
+ return {
5810
+ ready: Boolean(current),
5811
+ pending: pending.length,
5812
+ root: current?.root
5813
+ };
5814
+ }
5815
+ };
5816
+
5817
+ Object.defineProperties(facade, {
5818
+ _setCurrent: {
5819
+ value(loader) {
5820
+ if (!loader) {
5821
+ return;
5822
+ }
5823
+ current = loader;
5824
+ while (readyWaiters.length > 0) {
5825
+ readyWaiters.shift().resolve(loader);
5826
+ }
5827
+ flushPending(loader);
5828
+ }
5829
+ },
5830
+ _clearCurrent: {
5831
+ value(loaderOrLoaders) {
5832
+ if (loaderOrLoaders === undefined) {
5833
+ current = undefined;
5834
+ return;
5835
+ }
5836
+ const loaders = Array.isArray(loaderOrLoaders) ? loaderOrLoaders : [loaderOrLoaders];
5837
+ if (loaders.includes(current)) {
5838
+ current = undefined;
5839
+ }
5840
+ }
5841
+ },
5842
+ _rejectPending: {
5843
+ value(error) {
5844
+ while (pending.length > 0) {
5845
+ pending.shift().reject(error);
5846
+ }
5847
+ while (readyWaiters.length > 0) {
5848
+ readyWaiters.shift().reject(error);
5849
+ }
5850
+ }
5851
+ }
5852
+ });
5853
+
5854
+ return facade;
5855
+
5856
+ function enqueue(method, args) {
5857
+ if (current) {
5858
+ return invoke(current, method, args);
5859
+ }
5860
+ return new Promise((resolve, reject) => {
5861
+ pending.push({ method, args, resolve, reject });
5862
+ });
5863
+ }
5864
+
5865
+ function flushPending(loader) {
5866
+ while (pending.length > 0) {
5867
+ const operation = pending.shift();
5868
+ invoke(loader, operation.method, operation.args)
5869
+ .then(operation.resolve, operation.reject);
5870
+ }
5871
+ }
5872
+
5873
+ async function invoke(loader, method, args) {
5874
+ return loader[method](...args);
5875
+ }
5876
+ }
5877
+
5650
5878
  function readSnapshot(root = globalThis.document, { attributes } = {}) {
5651
5879
  const attributeConfig = normalizeAttributeConfig(attributes);
5652
5880
  const snapshotAttr = attributeName(attributeConfig, "async", "snapshot");
@@ -5797,10 +6025,33 @@ const __appModule = (() => {
5797
6025
  }
5798
6026
 
5799
6027
  function ensureRuntime(app) {
5800
- if (!app.runtime) {
6028
+ if (!app._runtime) {
5801
6029
  app.start();
5802
6030
  }
5803
- return app.runtime;
6031
+ return app._runtime;
6032
+ }
6033
+
6034
+ function latestRuntime(runtimes) {
6035
+ let latest;
6036
+ for (const runtime of runtimes) {
6037
+ latest = runtime;
6038
+ }
6039
+ return latest;
6040
+ }
6041
+
6042
+ function inspectRuntimeState(runtime, loaderFacade) {
6043
+ if (runtime?._inspect) {
6044
+ return runtime._inspect();
6045
+ }
6046
+ return {
6047
+ active: Boolean(runtime),
6048
+ started: Boolean(runtime),
6049
+ destroyed: false,
6050
+ target: runtime?.target,
6051
+ roots: runtime?.inspectRoots?.() ?? { count: 0, roots: [] },
6052
+ loader: loaderFacade.inspect(),
6053
+ router: Boolean(runtime?.router)
6054
+ };
5804
6055
  }
5805
6056
 
5806
6057
  function applySnapshotToRuntime(runtime, snapshot = {}, options = {}) {
@@ -6581,7 +6832,7 @@ const __boundaryReceiverModule = (() => {
6581
6832
  if (options.receiver && typeof options.receiver.apply === "function") {
6582
6833
  return options.receiver;
6583
6834
  }
6584
- const runtime = options.runtime ?? globalThis.Async?.runtime;
6835
+ const runtime = options.runtime ?? globalThis.Async?._runtime;
6585
6836
  const loader = options.loader ?? runtime?.loader;
6586
6837
  if (!loader) {
6587
6838
  throw new TypeError("AsyncStream requires receiver, loader, or runtime.loader.");
@@ -7178,7 +7429,7 @@ const __elementsModule = (() => {
7178
7429
  if (this.__asyncAttached) {
7179
7430
  return;
7180
7431
  }
7181
- const runtime = app.runtime ?? app.start?.();
7432
+ const runtime = app._runtime ?? app.start?.();
7182
7433
  runtime?.attachRoot?.(this);
7183
7434
  this.__asyncRuntime = runtime;
7184
7435
  this.__asyncAttached = true;