@async/framework 0.8.0 → 0.10.0
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 +18 -0
- package/README.md +156 -0
- package/browser.d.ts +119 -18
- package/browser.js +1044 -71
- package/browser.min.js +1 -1
- package/browser.ts +1044 -71
- package/browser.umd.js +1044 -71
- package/browser.umd.min.js +1 -1
- package/package.json +1 -1
- package/server.d.ts +119 -18
- package/src/app.js +314 -46
- package/src/boundary-receiver.js +302 -0
- package/src/browser.js +3 -0
- package/src/component.js +19 -2
- package/src/elements.js +63 -0
- package/src/handlers.js +19 -2
- package/src/index.js +3 -0
- package/src/lazy-registry.js +204 -0
- package/src/loader.js +23 -5
- package/src/partials.js +19 -2
- package/src/registry-store.js +15 -9
- package/src/scheduler.js +4 -0
- package/src/signals.js +46 -4
package/src/app.js
CHANGED
|
@@ -9,8 +9,9 @@ import { createServerNamespace } from "./server.js";
|
|
|
9
9
|
import { createSignal, createSignalRegistry } from "./signals.js";
|
|
10
10
|
import { createRegistryStore } from "./registry-store.js";
|
|
11
11
|
import { attributeName, normalizeAttributeConfig } from "./attributes.js";
|
|
12
|
+
import { createLazyRegistry, defineRegistrySnapshot, sameRegistryValue } from "./lazy-registry.js";
|
|
12
13
|
|
|
13
|
-
const registryTypes = new Set(["signal", "handler", "server", "partial", "route", "component"]);
|
|
14
|
+
const registryTypes = new Set(["signal", "handler", "server", "partial", "route", "component", "asyncSignal"]);
|
|
14
15
|
|
|
15
16
|
export function defineApp(initial, options = {}) {
|
|
16
17
|
const registry = createRegistryStore(undefined, { target: "browser" });
|
|
@@ -39,6 +40,27 @@ export function defineApp(initial, options = {}) {
|
|
|
39
40
|
return runtime;
|
|
40
41
|
},
|
|
41
42
|
|
|
43
|
+
attachRoot(root) {
|
|
44
|
+
return ensureRuntime(app).attachRoot(root);
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
detachRoot(root) {
|
|
48
|
+
return app.runtime?.detachRoot(root) ?? app;
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
applySnapshot(snapshot, snapshotOptions = {}) {
|
|
52
|
+
if (app.runtime) {
|
|
53
|
+
app.runtime.applySnapshot(snapshot, snapshotOptions);
|
|
54
|
+
return app;
|
|
55
|
+
}
|
|
56
|
+
appendSnapshotDeclarations(registry, snapshot, snapshotOptions);
|
|
57
|
+
return app;
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
inspectRoots() {
|
|
61
|
+
return app.runtime?.inspectRoots() ?? { count: 0, roots: [] };
|
|
62
|
+
},
|
|
63
|
+
|
|
42
64
|
_attach(runtime) {
|
|
43
65
|
runtimes.add(runtime);
|
|
44
66
|
return () => app._detach(runtime);
|
|
@@ -64,23 +86,32 @@ export function createApp(appOrDefinition = Async, options = {}) {
|
|
|
64
86
|
});
|
|
65
87
|
const ownsScheduler = !options.scheduler && !options.loader?.scheduler;
|
|
66
88
|
const attributes = normalizeAttributeConfig(options.attributes);
|
|
89
|
+
const lazyRegistry = options.lazyRegistry ?? createLazyRegistry({
|
|
90
|
+
registryAssets: options.registryAssets,
|
|
91
|
+
importModule: options.importModule
|
|
92
|
+
});
|
|
67
93
|
const registry = options.registry ?? app.registry.view({ target });
|
|
68
|
-
const signals = options.signals ?? createSignalRegistry(undefined, { registry, type: "signal" });
|
|
69
|
-
const handlers = options.handlers ?? createHandlerRegistry(undefined, { registry, type: "handler" });
|
|
94
|
+
const signals = options.signals ?? createSignalRegistry(undefined, { registry, type: "signal", lazyRegistry });
|
|
95
|
+
const handlers = options.handlers ?? createHandlerRegistry(undefined, { registry, type: "handler", lazyRegistry });
|
|
70
96
|
const serverCache = createCacheRegistry(undefined, { registry, type: "cache.server" });
|
|
71
97
|
const browserCache = createCacheRegistry(undefined, { registry, type: "cache.browser" });
|
|
72
98
|
const serverFactory = options.serverFactory ?? createServerReferenceRegistry;
|
|
73
99
|
const server = options.server ?? serverFactory(undefined, { registry, type: "server" });
|
|
74
|
-
const partials = options.partials ?? createPartialRegistry(undefined, { registry, type: "partial" });
|
|
100
|
+
const partials = options.partials ?? createPartialRegistry(undefined, { registry, type: "partial", lazyRegistry });
|
|
75
101
|
const routes = options.routes ?? createRouteRegistry(undefined, { registry, type: "route" });
|
|
76
|
-
const components = options.components ?? createComponentRegistry(undefined, { registry, type: "component" });
|
|
102
|
+
const components = options.components ?? createComponentRegistry(undefined, { registry, type: "component", lazyRegistry });
|
|
103
|
+
const hasStartupRoot = options.loader || Object.hasOwn(options, "root");
|
|
104
|
+
const startupRoot = hasStartupRoot ? options.root : null;
|
|
77
105
|
let loader = options.loader;
|
|
78
106
|
let router = options.router;
|
|
107
|
+
let routerStarted = false;
|
|
79
108
|
let detach = () => {};
|
|
80
109
|
let started = false;
|
|
81
110
|
let destroyed = false;
|
|
111
|
+
const rootLoaders = new Map();
|
|
82
112
|
|
|
83
|
-
|
|
113
|
+
const snapshotRoot = startupRoot ?? globalThis.document;
|
|
114
|
+
const initialSnapshot = options.snapshot ?? (target === "browser" ? readSnapshot(snapshotRoot, { attributes }) : undefined);
|
|
84
115
|
attachServerCache(server, serverCache);
|
|
85
116
|
|
|
86
117
|
const runtime = {
|
|
@@ -109,54 +140,112 @@ export function createApp(appOrDefinition = Async, options = {}) {
|
|
|
109
140
|
started = true;
|
|
110
141
|
|
|
111
142
|
if (target !== "server") {
|
|
112
|
-
loader = loader ?? Loader({
|
|
113
|
-
root: options.root,
|
|
114
|
-
signals,
|
|
115
|
-
handlers,
|
|
116
|
-
server,
|
|
117
|
-
cache: browserCache,
|
|
118
|
-
scheduler,
|
|
119
|
-
attributes
|
|
120
|
-
});
|
|
121
|
-
runtime.loader = loader;
|
|
122
|
-
|
|
123
143
|
configureServerContext({ cache: browserCache });
|
|
124
144
|
signals._setContext?.({ server, loader, cache: browserCache, scheduler });
|
|
125
145
|
|
|
126
|
-
loader
|
|
146
|
+
if (loader) {
|
|
147
|
+
registerRootLoader(loader.root, loader);
|
|
148
|
+
loader.start();
|
|
149
|
+
startRouterFor(loader.root);
|
|
150
|
+
} else if (startupRoot != null) {
|
|
151
|
+
runtime.attachRoot(startupRoot);
|
|
152
|
+
}
|
|
153
|
+
} else {
|
|
154
|
+
configureServerContext({ cache: serverCache });
|
|
155
|
+
signals._setContext?.({ server, cache: serverCache, scheduler });
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return runtime;
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
use(typeOrModule, entries) {
|
|
162
|
+
app.use(typeOrModule, entries);
|
|
163
|
+
return runtime;
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
attachRoot(root) {
|
|
167
|
+
assertActive();
|
|
168
|
+
if (target === "server") {
|
|
169
|
+
throw new Error("Server runtimes cannot attach DOM roots.");
|
|
170
|
+
}
|
|
171
|
+
if (!root) {
|
|
172
|
+
throw new TypeError("runtime.attachRoot(root) requires a root.");
|
|
173
|
+
}
|
|
174
|
+
if (rootLoaders.has(root)) {
|
|
175
|
+
return runtime;
|
|
176
|
+
}
|
|
127
177
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
root
|
|
132
|
-
boundary: options.boundary ?? "route",
|
|
133
|
-
routes,
|
|
134
|
-
loader,
|
|
178
|
+
const rootLoader = rootLoaders.size === 0 && loader
|
|
179
|
+
? loader
|
|
180
|
+
: Loader({
|
|
181
|
+
root,
|
|
135
182
|
signals,
|
|
136
183
|
handlers,
|
|
137
184
|
server,
|
|
138
185
|
cache: browserCache,
|
|
139
|
-
partials,
|
|
140
186
|
scheduler,
|
|
141
|
-
fetch: options.fetch,
|
|
142
|
-
routeEndpoint: options.routeEndpoint,
|
|
143
187
|
attributes
|
|
144
188
|
});
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
189
|
+
registerRootLoader(root, rootLoader);
|
|
190
|
+
rootLoader.start();
|
|
191
|
+
configureServerContext({ cache: browserCache });
|
|
192
|
+
signals._setContext?.({ server, loader: runtime.loader, cache: browserCache, scheduler });
|
|
193
|
+
startRouterFor(root);
|
|
194
|
+
return runtime;
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
detachRoot(root) {
|
|
198
|
+
assertActive();
|
|
199
|
+
if (target === "server") {
|
|
200
|
+
return runtime;
|
|
201
|
+
}
|
|
202
|
+
if (root == null) {
|
|
203
|
+
for (const rootLoader of new Set(rootLoaders.values())) {
|
|
204
|
+
rootLoader.destroy?.();
|
|
205
|
+
}
|
|
206
|
+
rootLoaders.clear();
|
|
207
|
+
router?.destroy?.();
|
|
208
|
+
router = undefined;
|
|
209
|
+
routerStarted = false;
|
|
210
|
+
loader = undefined;
|
|
211
|
+
runtime.loader = undefined;
|
|
212
|
+
runtime.router = undefined;
|
|
213
|
+
return runtime;
|
|
214
|
+
}
|
|
215
|
+
const rootLoader = rootLoaders.get(root);
|
|
216
|
+
if (!rootLoader) {
|
|
217
|
+
return runtime;
|
|
218
|
+
}
|
|
219
|
+
rootLoader.destroy?.();
|
|
220
|
+
rootLoaders.delete(root);
|
|
221
|
+
if (loader === rootLoader) {
|
|
222
|
+
router?.destroy?.();
|
|
223
|
+
router = undefined;
|
|
224
|
+
routerStarted = false;
|
|
225
|
+
const next = rootLoaders.values().next().value;
|
|
226
|
+
loader = next;
|
|
227
|
+
runtime.loader = next;
|
|
228
|
+
runtime.router = undefined;
|
|
229
|
+
if (next) {
|
|
230
|
+
startRouterFor(next.root);
|
|
149
231
|
}
|
|
150
|
-
} else {
|
|
151
|
-
configureServerContext({ cache: serverCache });
|
|
152
|
-
signals._setContext?.({ server, cache: serverCache, scheduler });
|
|
153
232
|
}
|
|
154
|
-
|
|
155
233
|
return runtime;
|
|
156
234
|
},
|
|
157
235
|
|
|
158
|
-
|
|
159
|
-
|
|
236
|
+
inspectRoots() {
|
|
237
|
+
return {
|
|
238
|
+
count: rootLoaders.size,
|
|
239
|
+
roots: [...rootLoaders].map(([root, rootLoader]) => ({
|
|
240
|
+
root,
|
|
241
|
+
loader: rootLoader,
|
|
242
|
+
primary: rootLoader === loader
|
|
243
|
+
}))
|
|
244
|
+
};
|
|
245
|
+
},
|
|
246
|
+
|
|
247
|
+
applySnapshot(snapshot, snapshotOptions = {}) {
|
|
248
|
+
applySnapshotToRuntime(runtime, snapshot, snapshotOptions);
|
|
160
249
|
return runtime;
|
|
161
250
|
},
|
|
162
251
|
|
|
@@ -218,7 +307,14 @@ export function createApp(appOrDefinition = Async, options = {}) {
|
|
|
218
307
|
destroyed = true;
|
|
219
308
|
detach();
|
|
220
309
|
router?.destroy?.();
|
|
221
|
-
|
|
310
|
+
const destroyedLoaders = new Set(rootLoaders.values());
|
|
311
|
+
for (const rootLoader of destroyedLoaders) {
|
|
312
|
+
rootLoader.destroy?.();
|
|
313
|
+
}
|
|
314
|
+
rootLoaders.clear();
|
|
315
|
+
if (loader && !destroyedLoaders.has(loader)) {
|
|
316
|
+
loader?.destroy?.();
|
|
317
|
+
}
|
|
222
318
|
signals.destroy?.();
|
|
223
319
|
if (ownsScheduler) {
|
|
224
320
|
scheduler.destroy();
|
|
@@ -232,10 +328,49 @@ export function createApp(appOrDefinition = Async, options = {}) {
|
|
|
232
328
|
|
|
233
329
|
server.cache = serverCache;
|
|
234
330
|
runtime.server.cache = serverCache;
|
|
331
|
+
runtime.applySnapshot(initialSnapshot, { strict: options.strictSnapshots ?? true });
|
|
235
332
|
detach = app._attach(runtime);
|
|
236
333
|
|
|
237
334
|
return runtime;
|
|
238
335
|
|
|
336
|
+
function registerRootLoader(root, rootLoader) {
|
|
337
|
+
rootLoaders.set(root, rootLoader);
|
|
338
|
+
if (!loader) {
|
|
339
|
+
loader = rootLoader;
|
|
340
|
+
runtime.loader = rootLoader;
|
|
341
|
+
}
|
|
342
|
+
rootLoader.server = server;
|
|
343
|
+
rootLoader.cache = browserCache;
|
|
344
|
+
rootLoader.scheduler = scheduler;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function startRouterFor(root) {
|
|
348
|
+
if (router === false || routerStarted || !(router || shouldStartRouter(routes, options)) || !runtime.loader) {
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
router = router ?? createRouter({
|
|
352
|
+
mode: options.mode ?? "ssr-spa",
|
|
353
|
+
root,
|
|
354
|
+
boundary: options.boundary ?? "route",
|
|
355
|
+
routes,
|
|
356
|
+
loader: runtime.loader,
|
|
357
|
+
signals,
|
|
358
|
+
handlers,
|
|
359
|
+
server,
|
|
360
|
+
cache: browserCache,
|
|
361
|
+
partials,
|
|
362
|
+
scheduler,
|
|
363
|
+
fetch: options.fetch,
|
|
364
|
+
routeEndpoint: options.routeEndpoint,
|
|
365
|
+
attributes
|
|
366
|
+
});
|
|
367
|
+
runtime.router = router;
|
|
368
|
+
runtime.loader.router = router;
|
|
369
|
+
configureServerContext({ cache: browserCache, router });
|
|
370
|
+
router.start();
|
|
371
|
+
routerStarted = true;
|
|
372
|
+
}
|
|
373
|
+
|
|
239
374
|
function configureServerContext(extra = {}) {
|
|
240
375
|
const cache = isLocalServerRegistry(server) ? serverCache : extra.cache;
|
|
241
376
|
server._setContext?.({
|
|
@@ -278,6 +413,7 @@ export function readSnapshot(root = globalThis.document, { attributes } = {}) {
|
|
|
278
413
|
return {};
|
|
279
414
|
}
|
|
280
415
|
|
|
416
|
+
const merged = {};
|
|
281
417
|
for (const searchRoot of new Set([rootNode, documentRef])) {
|
|
282
418
|
if (!searchRoot?.querySelectorAll) {
|
|
283
419
|
continue;
|
|
@@ -288,17 +424,19 @@ export function readSnapshot(root = globalThis.document, { attributes } = {}) {
|
|
|
288
424
|
}
|
|
289
425
|
const source = script.textContent?.trim() ?? "";
|
|
290
426
|
if (!source) {
|
|
291
|
-
|
|
427
|
+
continue;
|
|
292
428
|
}
|
|
429
|
+
let parsed;
|
|
293
430
|
try {
|
|
294
|
-
|
|
431
|
+
parsed = JSON.parse(source);
|
|
295
432
|
} catch (cause) {
|
|
296
433
|
throw new Error(`Could not parse Async snapshot: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
297
434
|
}
|
|
435
|
+
mergeSnapshot(merged, parsed, { strict: true });
|
|
298
436
|
}
|
|
299
437
|
}
|
|
300
438
|
|
|
301
|
-
return
|
|
439
|
+
return merged;
|
|
302
440
|
}
|
|
303
441
|
|
|
304
442
|
function applyUseToRuntime(runtime, normalized) {
|
|
@@ -308,10 +446,22 @@ function applyUseToRuntime(runtime, normalized) {
|
|
|
308
446
|
applyRegistryUse(runtime.partials, runtime.registry, normalized.partial);
|
|
309
447
|
applyRegistryUse(runtime.routes, runtime.registry, normalized.route);
|
|
310
448
|
applyRegistryUse(runtime.components, runtime.registry, normalized.component);
|
|
449
|
+
applyRegistryStoreUse(runtime.registry, "asyncSignal", normalized.asyncSignal);
|
|
311
450
|
applyRegistryUse(runtime.browser.cache, runtime.registry, normalized.cache.browser);
|
|
312
451
|
applyRegistryUse(runtime.server.cache, runtime.registry, normalized.cache.server);
|
|
313
452
|
}
|
|
314
453
|
|
|
454
|
+
function applyRegistryStoreUse(registry, type, entries) {
|
|
455
|
+
if (!entries || Object.keys(entries).length === 0) {
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
for (const [id, value] of Object.entries(entries)) {
|
|
459
|
+
if (!registry.has(type, id)) {
|
|
460
|
+
registry.register(type, id, value);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
315
465
|
function applyRegistryUse(registry, runtimeRegistry, entries) {
|
|
316
466
|
if (!entries || Object.keys(entries).length === 0) {
|
|
317
467
|
return;
|
|
@@ -331,6 +481,7 @@ function emptyDeclarations() {
|
|
|
331
481
|
partial: {},
|
|
332
482
|
route: {},
|
|
333
483
|
component: {},
|
|
484
|
+
asyncSignal: {},
|
|
334
485
|
cache: {
|
|
335
486
|
browser: {},
|
|
336
487
|
server: {}
|
|
@@ -386,11 +537,128 @@ function isAppHub(value) {
|
|
|
386
537
|
return Boolean(value && typeof value.use === "function" && typeof value.snapshot === "function" && value.registry);
|
|
387
538
|
}
|
|
388
539
|
|
|
389
|
-
function
|
|
390
|
-
|
|
391
|
-
|
|
540
|
+
function ensureRuntime(app) {
|
|
541
|
+
if (!app.runtime) {
|
|
542
|
+
app.start();
|
|
543
|
+
}
|
|
544
|
+
return app.runtime;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
function applySnapshotToRuntime(runtime, snapshot = {}, options = {}) {
|
|
548
|
+
const normalized = normalizeSnapshot(snapshot);
|
|
549
|
+
for (const [path, value] of Object.entries(normalized.signal)) {
|
|
550
|
+
setOrRegisterSignal(runtime.signals, path, value);
|
|
551
|
+
}
|
|
552
|
+
runtime.browser.cache.restore(normalized.cache.browser);
|
|
553
|
+
mergeRegistryEntries(runtime, "handler", normalized.handler, runtime.handlers, options);
|
|
554
|
+
mergeRegistryEntries(runtime, "server", normalized.server, runtime.server, options);
|
|
555
|
+
mergeRegistryEntries(runtime, "partial", normalized.partial, runtime.partials, options);
|
|
556
|
+
mergeRegistryEntries(runtime, "route", normalized.route, runtime.routes, options);
|
|
557
|
+
mergeRegistryEntries(runtime, "component", normalized.component, runtime.components, options);
|
|
558
|
+
mergeRegistryEntries(runtime, "asyncSignal", normalized.asyncSignal, null, options);
|
|
559
|
+
return runtime;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
function appendSnapshotDeclarations(registry, snapshot = {}, options = {}) {
|
|
563
|
+
const normalized = normalizeSnapshot(snapshot);
|
|
564
|
+
for (const [id, value] of Object.entries(normalized.signal)) {
|
|
565
|
+
registerSnapshotEntry(registry, "signal", id, createSignal(value), options);
|
|
566
|
+
}
|
|
567
|
+
for (const type of ["handler", "server", "partial", "route", "component", "asyncSignal"]) {
|
|
568
|
+
for (const [id, value] of Object.entries(normalized[type])) {
|
|
569
|
+
registerSnapshotEntry(registry, type, id, value, options);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
function mergeRegistryEntries(runtime, type, entries, concreteRegistry, options = {}) {
|
|
575
|
+
if (!entries || Object.keys(entries).length === 0) {
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
for (const [id, value] of Object.entries(entries)) {
|
|
579
|
+
registerSnapshotEntry(runtime.registry, type, id, value, options);
|
|
580
|
+
}
|
|
581
|
+
concreteRegistry?._adoptMany?.(entries);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
function registerSnapshotEntry(registry, type, id, value, options = {}) {
|
|
585
|
+
const strict = options.strict ?? true;
|
|
586
|
+
const map = registry._map(type);
|
|
587
|
+
if (map.has(id)) {
|
|
588
|
+
if (sameRegistryValue(map.get(id), value) || sameSnapshotValue(map.get(id), value)) {
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
if (strict) {
|
|
592
|
+
throw new Error(`${type} "${id}" is already registered with a different value.`);
|
|
593
|
+
}
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
registry.set(type, id, value);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
function normalizeSnapshot(snapshot = {}) {
|
|
600
|
+
const normalized = {
|
|
601
|
+
signal: {
|
|
602
|
+
...(snapshot.signals ?? {}),
|
|
603
|
+
...(snapshot.signal ?? {})
|
|
604
|
+
},
|
|
605
|
+
handler: { ...(snapshot.handler ?? {}) },
|
|
606
|
+
server: { ...(snapshot.server ?? {}) },
|
|
607
|
+
partial: { ...(snapshot.partial ?? {}) },
|
|
608
|
+
route: { ...(snapshot.route ?? {}) },
|
|
609
|
+
component: { ...(snapshot.component ?? {}) },
|
|
610
|
+
asyncSignal: { ...(snapshot.asyncSignal ?? {}) },
|
|
611
|
+
cache: {
|
|
612
|
+
browser: {
|
|
613
|
+
...(snapshot.entries?.browser ?? {}),
|
|
614
|
+
...(snapshot.cache?.browser ?? {})
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
return normalized;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
function mergeSnapshot(target, source, options = {}) {
|
|
622
|
+
const normalized = normalizeSnapshot(defineRegistrySnapshot(source));
|
|
623
|
+
target.signal = {
|
|
624
|
+
...(target.signal ?? target.signals ?? {}),
|
|
625
|
+
...normalized.signal
|
|
626
|
+
};
|
|
627
|
+
target.signals = target.signal;
|
|
628
|
+
target.cache = {
|
|
629
|
+
...(target.cache ?? {}),
|
|
630
|
+
browser: {
|
|
631
|
+
...(target.cache?.browser ?? {}),
|
|
632
|
+
...normalized.cache.browser
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
for (const type of ["handler", "server", "partial", "route", "component", "asyncSignal"]) {
|
|
636
|
+
target[type] = target[type] ?? {};
|
|
637
|
+
for (const [id, value] of Object.entries(normalized[type])) {
|
|
638
|
+
if (Object.hasOwn(target[type], id)) {
|
|
639
|
+
if (sameRegistryValue(target[type][id], value) || sameSnapshotValue(target[type][id], value)) {
|
|
640
|
+
continue;
|
|
641
|
+
}
|
|
642
|
+
if (options.strict ?? true) {
|
|
643
|
+
throw new Error(`${type} "${id}" is already declared with a different value.`);
|
|
644
|
+
}
|
|
645
|
+
continue;
|
|
646
|
+
}
|
|
647
|
+
target[type][id] = value;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
return target;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
function sameSnapshotValue(left, right) {
|
|
654
|
+
if (left === right) {
|
|
655
|
+
return true;
|
|
656
|
+
}
|
|
657
|
+
try {
|
|
658
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
659
|
+
} catch {
|
|
660
|
+
return false;
|
|
392
661
|
}
|
|
393
|
-
browserCache.restore(snapshot.cache?.browser);
|
|
394
662
|
}
|
|
395
663
|
|
|
396
664
|
function setOrRegisterSignal(signals, path, value) {
|