@async/framework 0.11.2 → 0.11.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.11.4 - 2026-06-18
4
+
5
+ - Restored snapshot signal keys as exact IDs so dotted plain, async, and
6
+ component-scoped signal IDs such as `product.load` survive SSR activation
7
+ without becoming nested properties under their first segment.
8
+ - Adopted async-signal descriptors before restoring matching snapshot state so
9
+ dotted async signals preserve `$value`, `$status`, and `$version` without an
10
+ immediate client refresh.
11
+ - Kept server-result signal patches on nested first-segment path semantics for
12
+ updates such as `product.title`.
13
+ - Bundle size from bundled TypeScript source: `browser.ts` 180,585 B raw /
14
+ 33,742 B gzip -> `browser.min.js` 76,946 B raw / 22,793 B gzip
15
+ (-103,639 B raw, -10,949 B gzip).
16
+
17
+ ## 0.11.3 - 2026-06-18
18
+
19
+ - Isolated runtime-owned signal, async-signal, scheduler, request, and cache
20
+ state so each `createApp(...)` call materializes fresh mutable state from
21
+ reusable app declarations.
22
+ - Preserved reusable app declarations across runtime destroy/recreate cycles,
23
+ late `app.use(...)` adoption, server render repetition, and peer async-signal
24
+ subscribers.
25
+ - Added direct runtime-isolation regression coverage and regenerated the
26
+ published browser/server artifacts.
27
+ - Bundle size from bundled TypeScript source: `browser.ts` 179,469 B raw /
28
+ 33,612 B gzip -> `browser.min.js` 76,458 B raw / 22,690 B gzip
29
+ (-103,011 B raw, -10,922 B gzip).
30
+
3
31
  ## 0.11.2 - 2026-06-18
4
32
 
5
33
  - Published the post-`0.11.1` feedback-regression hardening now on `main`,
package/README.md CHANGED
@@ -430,7 +430,9 @@ Singular registry keys are canonical: `signal`, `handler`, `server`,
430
430
  ### Registry Inspection
431
431
 
432
432
  `Async.registry` is the global inspection surface for registered app pieces.
433
- Every runtime and concrete registry also points at the same backing store:
433
+ Every runtime owns fresh mutable signal and cache state materialized from the
434
+ app declaration store. Concrete registries inside one runtime share that
435
+ runtime's registry view:
434
436
 
435
437
  ```js
436
438
  Async.registry.keys("signal");
package/browser.js CHANGED
@@ -185,6 +185,10 @@ const __asyncSignalModule = (() => {
185
185
  };
186
186
  },
187
187
 
188
+ _cloneSignalDeclaration() {
189
+ return asyncSignal(id, fn);
190
+ },
191
+
188
192
  _restore(snapshot = {}) {
189
193
  if (!isAsyncSignalSnapshot(snapshot)) {
190
194
  return state.set(snapshot);
@@ -956,7 +960,12 @@ const __cacheModule = (() => {
956
960
  return registryStore.entries(`${type}.entries`);
957
961
  },
958
962
 
959
- _adoptMany() {
963
+ _adoptMany(map = {}) {
964
+ for (const [id, definition] of Object.entries(map ?? {})) {
965
+ if (!definitions.has(id)) {
966
+ registryApi.register(id, definition);
967
+ }
968
+ }
960
969
  return registryApi;
961
970
  }
962
971
  }, registryStore, type);
@@ -1114,6 +1123,10 @@ const __signalsModule = (() => {
1114
1123
 
1115
1124
  snapshot() {
1116
1125
  return value;
1126
+ },
1127
+
1128
+ _cloneSignalDeclaration() {
1129
+ return createSignal(value);
1117
1130
  }
1118
1131
  };
1119
1132
 
@@ -1156,6 +1169,10 @@ const __signalsModule = (() => {
1156
1169
  return backing.snapshot();
1157
1170
  },
1158
1171
 
1172
+ _cloneSignalDeclaration() {
1173
+ return computed(fn);
1174
+ },
1175
+
1159
1176
  _bindRegistry(registry, id) {
1160
1177
  return registry.effect(() => {
1161
1178
  backing.set(fn.call({
@@ -1180,6 +1197,9 @@ const __signalsModule = (() => {
1180
1197
  [effectKind]: true,
1181
1198
  kind: "effect",
1182
1199
  fn,
1200
+ _cloneSignalDeclaration() {
1201
+ return effect(fn);
1202
+ },
1183
1203
  _bindRegistry(registry) {
1184
1204
  return registry.effect(fn);
1185
1205
  }
@@ -1388,6 +1408,24 @@ const __signalsModule = (() => {
1388
1408
  return requireEntry(entries, id);
1389
1409
  },
1390
1410
 
1411
+ _setPath(path, value) {
1412
+ const parsed = parseRootPath(path);
1413
+ if (!entries.has(parsed.id)) {
1414
+ if (asyncDescriptors.has(parsed.id)) {
1415
+ materializeAsyncSignal(parsed.id);
1416
+ } else {
1417
+ registry.register(parsed.id, createSignal(parsed.parts.length === 0 ? value : {}));
1418
+ }
1419
+ }
1420
+ const entry = requireEntry(entries, parsed.id);
1421
+ if (parsed.parts.length === 0) {
1422
+ return entry.set(value);
1423
+ }
1424
+ const nextValue = setPath(entry.value, parsed.parts, value);
1425
+ entry.set(nextValue);
1426
+ return value;
1427
+ },
1428
+
1391
1429
  _setContext(context = {}) {
1392
1430
  Object.assign(runtimeContext, context);
1393
1431
  return registry;
@@ -1398,10 +1436,14 @@ const __signalsModule = (() => {
1398
1436
  },
1399
1437
 
1400
1438
  _adoptMany(map = {}) {
1401
- for (const id of Object.keys(map ?? {})) {
1402
- if (entries.has(id)) {
1403
- bindEntry(id, entries.get(id));
1439
+ for (const [id, signalLike] of Object.entries(map ?? {})) {
1440
+ if (!entries.has(id)) {
1441
+ const entry = cloneSignalDeclaration(signalLike);
1442
+ entries.set(id, entry);
1443
+ bindEntry(id, entry);
1444
+ continue;
1404
1445
  }
1446
+ bindEntry(id, entries.get(id));
1405
1447
  }
1406
1448
  return registry;
1407
1449
  }
@@ -1440,6 +1482,14 @@ const __signalsModule = (() => {
1440
1482
  return { id, parts, path };
1441
1483
  }
1442
1484
 
1485
+ function parseRootPath(path) {
1486
+ if (typeof path !== "string" || path.length === 0) {
1487
+ throw new TypeError("Signal path must be a non-empty string.");
1488
+ }
1489
+ const [id, ...parts] = path.split(".");
1490
+ return { id, parts, path };
1491
+ }
1492
+
1443
1493
  function materializeAsyncSignal(id) {
1444
1494
  if (entries.has(id) || !asyncDescriptors.has(id)) {
1445
1495
  return;
@@ -1479,6 +1529,16 @@ const __signalsModule = (() => {
1479
1529
  return createSignal(signalLike);
1480
1530
  }
1481
1531
 
1532
+ function cloneSignalDeclaration(signalLike) {
1533
+ if (typeof signalLike?._cloneSignalDeclaration === "function") {
1534
+ return signalLike._cloneSignalDeclaration();
1535
+ }
1536
+ if (isSignalLike(signalLike)) {
1537
+ return createSignal(typeof signalLike.snapshot === "function" ? signalLike.snapshot() : signalLike.value);
1538
+ }
1539
+ return createSignal(signalLike);
1540
+ }
1541
+
1482
1542
  function isSignalLike(value) {
1483
1543
  return Boolean(value && typeof value === "object" && typeof value.subscribe === "function");
1484
1544
  }
@@ -1657,7 +1717,7 @@ const __signalsModule = (() => {
1657
1717
  frame.add(path);
1658
1718
  }
1659
1719
  }
1660
- return { createSignal, computed, effect, createSignalRegistry, isSignalRef, signal };
1720
+ return { createSignal, computed, effect, createSignalRegistry, cloneSignalDeclaration, isSignalRef, signal };
1661
1721
  })();
1662
1722
 
1663
1723
  const __htmlModule = (() => {
@@ -1899,7 +1959,12 @@ const __componentModule = (() => {
1899
1959
  return lazyComponents.get(id);
1900
1960
  },
1901
1961
 
1902
- _adoptMany() {
1962
+ _adoptMany(map = {}) {
1963
+ for (const [id, Component] of Object.entries(map ?? {})) {
1964
+ if (!entries.has(id)) {
1965
+ registry.register(id, Component);
1966
+ }
1967
+ }
1903
1968
  return registry;
1904
1969
  }
1905
1970
  }, registryStore, type);
@@ -2739,7 +2804,12 @@ const __handlersModule = (() => {
2739
2804
  return results;
2740
2805
  },
2741
2806
 
2742
- _adoptMany() {
2807
+ _adoptMany(map = {}) {
2808
+ for (const [id, fn] of Object.entries(map ?? {})) {
2809
+ if (!handlers.has(id)) {
2810
+ registry.register(id, fn);
2811
+ }
2812
+ }
2743
2813
  return registry;
2744
2814
  }
2745
2815
  }, registryStore, type);
@@ -4028,7 +4098,12 @@ const __partialsModule = (() => {
4028
4098
  return normalizePartialResult(result, partialContext);
4029
4099
  },
4030
4100
 
4031
- _adoptMany() {
4101
+ _adoptMany(map = {}) {
4102
+ for (const [id, fn] of Object.entries(map ?? {})) {
4103
+ if (!entries.has(id)) {
4104
+ registry.register(id, fn);
4105
+ }
4106
+ }
4032
4107
  return registry;
4033
4108
  }
4034
4109
  }, registryStore, type);
@@ -4180,7 +4255,11 @@ const __routerModule = (() => {
4180
4255
  },
4181
4256
 
4182
4257
  _adoptMany(map = {}) {
4183
- for (const pattern of Object.keys(map ?? {})) {
4258
+ for (const [pattern, definition] of Object.entries(map ?? {})) {
4259
+ if (!entries.has(pattern)) {
4260
+ registry.register(pattern, definition);
4261
+ continue;
4262
+ }
4184
4263
  adoptRoute(pattern, entries.get(pattern));
4185
4264
  }
4186
4265
  return registry;
@@ -4676,7 +4755,7 @@ const __appModule = (() => {
4676
4755
  const { createRouteRegistry, createRouter } = __routerModule;
4677
4756
  const { createScheduler } = __schedulerModule;
4678
4757
  const { createServerNamespace } = __serverModule;
4679
- const { createSignal, createSignalRegistry } = __signalsModule;
4758
+ const { cloneSignalDeclaration, createSignal, createSignalRegistry } = __signalsModule;
4680
4759
  const { createRegistryStore } = __registryStoreModule;
4681
4760
  const { attributeName, normalizeAttributeConfig } = __attributesModule;
4682
4761
  const { createLazyRegistry, defineRegistrySnapshot, sameRegistryValue } = __lazyRegistryModule;
@@ -4759,7 +4838,7 @@ const __appModule = (() => {
4759
4838
  registryAssets: options.registryAssets,
4760
4839
  importModule: options.importModule
4761
4840
  });
4762
- const registry = options.registry ?? app.registry.view({ target });
4841
+ const registry = options.registry ?? createRuntimeRegistry(app.registry, { target });
4763
4842
  const signals = options.signals ?? createSignalRegistry(undefined, { registry, type: "signal", lazyRegistry });
4764
4843
  const handlers = options.handlers ?? createHandlerRegistry(undefined, { registry, type: "handler", lazyRegistry });
4765
4844
  const serverCache = createCacheRegistry(undefined, { registry, type: "cache.server" });
@@ -4951,7 +5030,7 @@ const __appModule = (() => {
4951
5030
 
4952
5031
  if (result.signals) {
4953
5032
  for (const [path, value] of Object.entries(result.signals)) {
4954
- setOrRegisterSignal(signals, path, value);
5033
+ applySignalPatch(signals, path, value);
4955
5034
  }
4956
5035
  }
4957
5036
  if (result.cache?.browser) {
@@ -5140,6 +5219,22 @@ const __appModule = (() => {
5140
5219
  registry?.registerMany?.(entries);
5141
5220
  }
5142
5221
 
5222
+ function createRuntimeRegistry(appRegistry, { target } = {}) {
5223
+ const declarations = appRegistry.rawSnapshot();
5224
+ return createRegistryStore({
5225
+ ...declarations,
5226
+ signal: cloneSignalDeclarations(declarations.signal)
5227
+ }, { target });
5228
+ }
5229
+
5230
+ function cloneSignalDeclarations(signals = {}) {
5231
+ const cloned = {};
5232
+ for (const [id, signalLike] of Object.entries(signals ?? {})) {
5233
+ cloned[id] = cloneSignalDeclaration(signalLike);
5234
+ }
5235
+ return cloned;
5236
+ }
5237
+
5143
5238
  function emptyDeclarations() {
5144
5239
  return {
5145
5240
  signal: {},
@@ -5213,8 +5308,9 @@ const __appModule = (() => {
5213
5308
 
5214
5309
  function applySnapshotToRuntime(runtime, snapshot = {}, options = {}) {
5215
5310
  const normalized = normalizeSnapshot(snapshot);
5216
- for (const [path, value] of Object.entries(normalized.signal)) {
5217
- setOrRegisterSignal(runtime.signals, path, value);
5311
+ mergeRegistryEntries(runtime, "asyncSignal", normalized.asyncSignal, null, options);
5312
+ for (const [id, value] of Object.entries(normalized.signal)) {
5313
+ restoreSignalEntry(runtime.signals, id, value);
5218
5314
  }
5219
5315
  runtime.browser.cache.restore(normalized.cache.browser);
5220
5316
  mergeRegistryEntries(runtime, "handler", normalized.handler, runtime.handlers, options);
@@ -5222,7 +5318,6 @@ const __appModule = (() => {
5222
5318
  mergeRegistryEntries(runtime, "partial", normalized.partial, runtime.partials, options);
5223
5319
  mergeRegistryEntries(runtime, "route", normalized.route, runtime.routes, options);
5224
5320
  mergeRegistryEntries(runtime, "component", normalized.component, runtime.components, options);
5225
- mergeRegistryEntries(runtime, "asyncSignal", normalized.asyncSignal, null, options);
5226
5321
  return runtime;
5227
5322
  }
5228
5323
 
@@ -5328,16 +5423,26 @@ const __appModule = (() => {
5328
5423
  }
5329
5424
  }
5330
5425
 
5331
- function setOrRegisterSignal(signals, path, value) {
5332
- const id = String(path).split(".")[0];
5426
+ function restoreSignalEntry(signals, id, value) {
5333
5427
  if (signals.has?.(id)) {
5334
- if (path === id) {
5335
- const entry = signals._entry?.(id);
5336
- if (typeof entry?._restore === "function" && isAsyncSignalSnapshot(value)) {
5337
- entry._restore(value);
5338
- return;
5339
- }
5428
+ const entry = signals._entry?.(id);
5429
+ if (typeof entry?._restore === "function" && isAsyncSignalSnapshot(value)) {
5430
+ entry._restore(value);
5431
+ return;
5340
5432
  }
5433
+ signals.set(id, value);
5434
+ return;
5435
+ }
5436
+ signals.register(id, createSignal(value));
5437
+ }
5438
+
5439
+ function applySignalPatch(signals, path, value) {
5440
+ if (typeof signals._setPath === "function") {
5441
+ signals._setPath(path, value);
5442
+ return;
5443
+ }
5444
+ const id = String(path).split(".")[0];
5445
+ if (signals.has?.(id)) {
5341
5446
  signals.set(path, value);
5342
5447
  return;
5343
5448
  }