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