@async/framework 0.10.2 → 0.11.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 +20 -0
- package/README.md +23 -7
- package/browser.d.ts +4 -7
- package/browser.js +17 -66
- package/browser.min.js +1 -1
- package/browser.ts +17 -66
- package/browser.umd.js +17 -66
- package/browser.umd.min.js +1 -1
- package/{server.d.ts → framework.d.ts} +4 -7
- package/framework.ts +5946 -0
- package/package.json +25 -17
- package/server.js +5945 -0
- package/examples/cache/index.html +0 -16
- package/examples/cache/main.js +0 -47
- package/examples/components/index.html +0 -11
- package/examples/components/main.js +0 -26
- package/examples/counter/index.html +0 -15
- package/examples/counter/main.js +0 -17
- package/examples/partials/index.html +0 -15
- package/examples/partials/main.js +0 -43
- package/examples/product/index.html +0 -32
- package/examples/product/main.js +0 -24
- package/examples/router/index.html +0 -18
- package/examples/router/main.js +0 -52
- package/examples/server-call/index.html +0 -21
- package/examples/server-call/main.js +0 -22
- package/examples/ssr/index.html +0 -12
- package/examples/ssr/main.js +0 -89
- package/examples/streaming/index.html +0 -16
- package/examples/streaming/main.js +0 -30
- package/src/app.js +0 -802
- package/src/async-signal.js +0 -277
- package/src/attributes.js +0 -52
- package/src/boundary-receiver.js +0 -302
- package/src/browser.js +0 -18
- package/src/cache.js +0 -193
- package/src/component.js +0 -373
- package/src/delay.js +0 -30
- package/src/elements.js +0 -63
- package/src/handlers.js +0 -219
- package/src/html.js +0 -158
- package/src/index.js +0 -20
- package/src/lazy-registry.js +0 -218
- package/src/loader.js +0 -772
- package/src/partials.js +0 -133
- package/src/registry-store.js +0 -267
- package/src/request-context.js +0 -40
- package/src/router.js +0 -617
- package/src/scheduler.js +0 -300
- package/src/server-entry.js +0 -20
- package/src/server-registry.js +0 -97
- package/src/server.js +0 -362
- package/src/signals.js +0 -592
package/src/app.js
DELETED
|
@@ -1,802 +0,0 @@
|
|
|
1
|
-
import { createCacheRegistry } from "./cache.js";
|
|
2
|
-
import { createComponentRegistry } from "./component.js";
|
|
3
|
-
import { createHandlerRegistry } from "./handlers.js";
|
|
4
|
-
import { Loader } from "./loader.js";
|
|
5
|
-
import { createPartialRegistry } from "./partials.js";
|
|
6
|
-
import { createRouteRegistry, createRouter } from "./router.js";
|
|
7
|
-
import { createScheduler } from "./scheduler.js";
|
|
8
|
-
import { createServerNamespace } from "./server.js";
|
|
9
|
-
import { createSignal, createSignalRegistry } from "./signals.js";
|
|
10
|
-
import { createRegistryStore } from "./registry-store.js";
|
|
11
|
-
import { attributeName, normalizeAttributeConfig } from "./attributes.js";
|
|
12
|
-
import { createLazyRegistry, defineRegistrySnapshot, sameRegistryValue } from "./lazy-registry.js";
|
|
13
|
-
|
|
14
|
-
const registryTypes = new Set(["signal", "handler", "server", "partial", "route", "component", "asyncSignal"]);
|
|
15
|
-
|
|
16
|
-
export function defineApp(initial, options = {}) {
|
|
17
|
-
const registry = createRegistryStore(undefined, { target: "browser" });
|
|
18
|
-
const runtimes = new Set();
|
|
19
|
-
const createRuntime = options.createRuntime ?? createApp;
|
|
20
|
-
|
|
21
|
-
const app = {
|
|
22
|
-
registry,
|
|
23
|
-
|
|
24
|
-
use(typeOrModule, entries) {
|
|
25
|
-
const normalized = normalizeUse(typeOrModule, entries);
|
|
26
|
-
appendDeclarations(registry, normalized);
|
|
27
|
-
for (const runtime of runtimes) {
|
|
28
|
-
runtime._applyUse(normalized);
|
|
29
|
-
}
|
|
30
|
-
return app;
|
|
31
|
-
},
|
|
32
|
-
|
|
33
|
-
snapshot() {
|
|
34
|
-
return registry.rawSnapshot();
|
|
35
|
-
},
|
|
36
|
-
|
|
37
|
-
start(options = {}) {
|
|
38
|
-
const runtime = createRuntime(app, options).start();
|
|
39
|
-
app.runtime = runtime;
|
|
40
|
-
return runtime;
|
|
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
|
-
|
|
64
|
-
_attach(runtime) {
|
|
65
|
-
runtimes.add(runtime);
|
|
66
|
-
return () => app._detach(runtime);
|
|
67
|
-
},
|
|
68
|
-
|
|
69
|
-
_detach(runtime) {
|
|
70
|
-
runtimes.delete(runtime);
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
if (initial) {
|
|
75
|
-
app.use(initial);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return app;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function createApp(appOrDefinition = Async, options = {}) {
|
|
82
|
-
const app = isAppHub(appOrDefinition) ? appOrDefinition : defineApp(appOrDefinition ?? {});
|
|
83
|
-
const target = options.target ?? "browser";
|
|
84
|
-
const scheduler = options.scheduler ?? options.loader?.scheduler ?? createScheduler({
|
|
85
|
-
strategy: target === "server" ? "manual" : "microtask"
|
|
86
|
-
});
|
|
87
|
-
const ownsScheduler = !options.scheduler && !options.loader?.scheduler;
|
|
88
|
-
const attributes = normalizeAttributeConfig(options.attributes);
|
|
89
|
-
const lazyRegistry = options.lazyRegistry ?? createLazyRegistry({
|
|
90
|
-
registryAssets: options.registryAssets,
|
|
91
|
-
importModule: options.importModule
|
|
92
|
-
});
|
|
93
|
-
const registry = options.registry ?? app.registry.view({ target });
|
|
94
|
-
const signals = options.signals ?? createSignalRegistry(undefined, { registry, type: "signal", lazyRegistry });
|
|
95
|
-
const handlers = options.handlers ?? createHandlerRegistry(undefined, { registry, type: "handler", lazyRegistry });
|
|
96
|
-
const serverCache = createCacheRegistry(undefined, { registry, type: "cache.server" });
|
|
97
|
-
const browserCache = createCacheRegistry(undefined, { registry, type: "cache.browser" });
|
|
98
|
-
const serverFactory = options.serverFactory ?? createServerReferenceRegistry;
|
|
99
|
-
const server = options.server ?? serverFactory(undefined, { registry, type: "server" });
|
|
100
|
-
const partials = options.partials ?? createPartialRegistry(undefined, { registry, type: "partial", lazyRegistry });
|
|
101
|
-
const routes = options.routes ?? createRouteRegistry(undefined, { registry, type: "route" });
|
|
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;
|
|
105
|
-
let loader = options.loader;
|
|
106
|
-
let router = options.router;
|
|
107
|
-
let routerStarted = false;
|
|
108
|
-
let detach = () => {};
|
|
109
|
-
let started = false;
|
|
110
|
-
let destroyed = false;
|
|
111
|
-
const rootLoaders = new Map();
|
|
112
|
-
|
|
113
|
-
const snapshotRoot = startupRoot ?? globalThis.document;
|
|
114
|
-
const initialSnapshot = options.snapshot ?? (target === "browser" ? readSnapshot(snapshotRoot, { attributes }) : undefined);
|
|
115
|
-
attachServerCache(server, serverCache);
|
|
116
|
-
|
|
117
|
-
const runtime = {
|
|
118
|
-
app,
|
|
119
|
-
registry,
|
|
120
|
-
target,
|
|
121
|
-
signals,
|
|
122
|
-
handlers,
|
|
123
|
-
server,
|
|
124
|
-
partials,
|
|
125
|
-
routes,
|
|
126
|
-
components,
|
|
127
|
-
browser: {
|
|
128
|
-
cache: browserCache
|
|
129
|
-
},
|
|
130
|
-
loader,
|
|
131
|
-
router,
|
|
132
|
-
scheduler,
|
|
133
|
-
attributes,
|
|
134
|
-
|
|
135
|
-
start() {
|
|
136
|
-
assertActive();
|
|
137
|
-
if (started) {
|
|
138
|
-
return runtime;
|
|
139
|
-
}
|
|
140
|
-
started = true;
|
|
141
|
-
|
|
142
|
-
if (target !== "server") {
|
|
143
|
-
configureServerContext({ cache: browserCache });
|
|
144
|
-
signals._setContext?.({ server, loader, cache: browserCache, scheduler });
|
|
145
|
-
|
|
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
|
-
}
|
|
177
|
-
|
|
178
|
-
const rootLoader = rootLoaders.size === 0 && loader
|
|
179
|
-
? loader
|
|
180
|
-
: Loader({
|
|
181
|
-
root,
|
|
182
|
-
signals,
|
|
183
|
-
handlers,
|
|
184
|
-
server,
|
|
185
|
-
cache: browserCache,
|
|
186
|
-
scheduler,
|
|
187
|
-
attributes
|
|
188
|
-
});
|
|
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);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
return runtime;
|
|
234
|
-
},
|
|
235
|
-
|
|
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);
|
|
249
|
-
return runtime;
|
|
250
|
-
},
|
|
251
|
-
|
|
252
|
-
async render(url) {
|
|
253
|
-
assertActive();
|
|
254
|
-
configureServerContext({ cache: serverCache });
|
|
255
|
-
signals._setContext?.({ server, cache: serverCache, scheduler });
|
|
256
|
-
const matched = routes.match(url);
|
|
257
|
-
if (!matched) {
|
|
258
|
-
await scheduler.flush();
|
|
259
|
-
return {
|
|
260
|
-
html: renderDocument("", { status: 404, signals, browserCache, boundary: options.boundary ?? "route", attributes }),
|
|
261
|
-
status: 404,
|
|
262
|
-
signals: signals.snapshot(),
|
|
263
|
-
cache: { browser: browserCache.snapshot() }
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
const partialId = matched.route.partial;
|
|
268
|
-
const result = partialId && partials.resolve(partialId)
|
|
269
|
-
? await partials.render(partialId, matched.params, {
|
|
270
|
-
params: matched.params,
|
|
271
|
-
route: matched.route,
|
|
272
|
-
signals,
|
|
273
|
-
handlers,
|
|
274
|
-
server,
|
|
275
|
-
cache: serverCache,
|
|
276
|
-
browserCache,
|
|
277
|
-
partials,
|
|
278
|
-
scheduler,
|
|
279
|
-
...currentRequestContext()
|
|
280
|
-
})
|
|
281
|
-
: { html: "" };
|
|
282
|
-
|
|
283
|
-
if (result.signals) {
|
|
284
|
-
for (const [path, value] of Object.entries(result.signals)) {
|
|
285
|
-
setOrRegisterSignal(signals, path, value);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
if (result.cache?.browser) {
|
|
289
|
-
browserCache.restore(result.cache.browser);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
await scheduler.flush();
|
|
293
|
-
|
|
294
|
-
const status = result.status ?? 200;
|
|
295
|
-
return {
|
|
296
|
-
html: renderDocument(result.html, { status, signals, browserCache, boundary: result.boundary ?? options.boundary ?? "route", attributes }),
|
|
297
|
-
status,
|
|
298
|
-
signals: signals.snapshot(),
|
|
299
|
-
cache: { browser: browserCache.snapshot() }
|
|
300
|
-
};
|
|
301
|
-
},
|
|
302
|
-
|
|
303
|
-
destroy() {
|
|
304
|
-
if (destroyed) {
|
|
305
|
-
return;
|
|
306
|
-
}
|
|
307
|
-
destroyed = true;
|
|
308
|
-
detach();
|
|
309
|
-
router?.destroy?.();
|
|
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
|
-
}
|
|
318
|
-
signals.destroy?.();
|
|
319
|
-
if (ownsScheduler) {
|
|
320
|
-
scheduler.destroy();
|
|
321
|
-
}
|
|
322
|
-
},
|
|
323
|
-
|
|
324
|
-
_applyUse(normalized) {
|
|
325
|
-
applyUseToRuntime(runtime, normalized);
|
|
326
|
-
}
|
|
327
|
-
};
|
|
328
|
-
|
|
329
|
-
server.cache = serverCache;
|
|
330
|
-
runtime.server.cache = serverCache;
|
|
331
|
-
runtime.applySnapshot(initialSnapshot, { strict: options.strictSnapshots ?? true });
|
|
332
|
-
detach = app._attach(runtime);
|
|
333
|
-
|
|
334
|
-
return runtime;
|
|
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
|
-
|
|
374
|
-
function configureServerContext(extra = {}) {
|
|
375
|
-
const cache = isLocalServerRegistry(server) ? serverCache : extra.cache;
|
|
376
|
-
server._setContext?.({
|
|
377
|
-
signals,
|
|
378
|
-
loader,
|
|
379
|
-
router,
|
|
380
|
-
cache,
|
|
381
|
-
scheduler,
|
|
382
|
-
requestContext: options.requestContext,
|
|
383
|
-
...currentRequestContext()
|
|
384
|
-
});
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
function currentRequestContext() {
|
|
388
|
-
const context = readRequestContextLike(options.requestContext);
|
|
389
|
-
return {
|
|
390
|
-
requestContext: context,
|
|
391
|
-
request: context.request ?? options.request,
|
|
392
|
-
headers: context.headers ?? options.headers,
|
|
393
|
-
cookies: context.cookies ?? options.cookies,
|
|
394
|
-
locals: context.locals ?? options.locals
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
function assertActive() {
|
|
399
|
-
if (destroyed) {
|
|
400
|
-
throw new Error("Async app runtime has been destroyed.");
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
export const Async = defineApp();
|
|
406
|
-
|
|
407
|
-
export function readSnapshot(root = globalThis.document, { attributes } = {}) {
|
|
408
|
-
const attributeConfig = normalizeAttributeConfig(attributes);
|
|
409
|
-
const snapshotAttr = attributeName(attributeConfig, "async", "snapshot");
|
|
410
|
-
const documentRef = root?.ownerDocument ?? root ?? globalThis.document;
|
|
411
|
-
const rootNode = root ?? documentRef;
|
|
412
|
-
if (!rootNode?.querySelectorAll && !documentRef?.querySelectorAll) {
|
|
413
|
-
return {};
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
const merged = {};
|
|
417
|
-
for (const searchRoot of new Set([rootNode, documentRef])) {
|
|
418
|
-
if (!searchRoot?.querySelectorAll) {
|
|
419
|
-
continue;
|
|
420
|
-
}
|
|
421
|
-
for (const script of searchRoot.querySelectorAll("script[type='application/json'], script")) {
|
|
422
|
-
if (!script.hasAttribute?.(snapshotAttr)) {
|
|
423
|
-
continue;
|
|
424
|
-
}
|
|
425
|
-
const source = script.textContent?.trim() ?? "";
|
|
426
|
-
if (!source) {
|
|
427
|
-
continue;
|
|
428
|
-
}
|
|
429
|
-
let parsed;
|
|
430
|
-
try {
|
|
431
|
-
parsed = JSON.parse(source);
|
|
432
|
-
} catch (cause) {
|
|
433
|
-
throw new Error(`Could not parse Async snapshot: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
434
|
-
}
|
|
435
|
-
mergeSnapshot(merged, parsed, { strict: true });
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
return merged;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
function applyUseToRuntime(runtime, normalized) {
|
|
443
|
-
applyRegistryUse(runtime.signals, runtime.registry, normalized.signal);
|
|
444
|
-
applyRegistryUse(runtime.handlers, runtime.registry, normalized.handler);
|
|
445
|
-
applyRegistryUse(runtime.server, runtime.registry, normalized.server);
|
|
446
|
-
applyRegistryUse(runtime.partials, runtime.registry, normalized.partial);
|
|
447
|
-
applyRegistryUse(runtime.routes, runtime.registry, normalized.route);
|
|
448
|
-
applyRegistryUse(runtime.components, runtime.registry, normalized.component);
|
|
449
|
-
applyRegistryStoreUse(runtime.registry, "asyncSignal", normalized.asyncSignal);
|
|
450
|
-
applyRegistryUse(runtime.browser.cache, runtime.registry, normalized.cache.browser);
|
|
451
|
-
applyRegistryUse(runtime.server.cache, runtime.registry, normalized.cache.server);
|
|
452
|
-
}
|
|
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
|
-
|
|
465
|
-
function applyRegistryUse(registry, runtimeRegistry, entries) {
|
|
466
|
-
if (!entries || Object.keys(entries).length === 0) {
|
|
467
|
-
return;
|
|
468
|
-
}
|
|
469
|
-
if (registry?.registry === runtimeRegistry) {
|
|
470
|
-
registry._adoptMany?.(entries);
|
|
471
|
-
return;
|
|
472
|
-
}
|
|
473
|
-
registry?.registerMany?.(entries);
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
function emptyDeclarations() {
|
|
477
|
-
return {
|
|
478
|
-
signal: {},
|
|
479
|
-
handler: {},
|
|
480
|
-
server: {},
|
|
481
|
-
partial: {},
|
|
482
|
-
route: {},
|
|
483
|
-
component: {},
|
|
484
|
-
asyncSignal: {},
|
|
485
|
-
cache: {
|
|
486
|
-
browser: {},
|
|
487
|
-
server: {}
|
|
488
|
-
}
|
|
489
|
-
};
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
function normalizeUse(typeOrModule, entries) {
|
|
493
|
-
const normalized = emptyDeclarations();
|
|
494
|
-
|
|
495
|
-
if (typeof typeOrModule === "string") {
|
|
496
|
-
if (!registryTypes.has(typeOrModule)) {
|
|
497
|
-
throw new Error(`Unknown Async registry type "${typeOrModule}".`);
|
|
498
|
-
}
|
|
499
|
-
normalized[typeOrModule] = normalizeEntries(typeOrModule, entries);
|
|
500
|
-
return normalized;
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
if (!typeOrModule || typeof typeOrModule !== "object") {
|
|
504
|
-
throw new TypeError("Async.use(...) requires a registry type or module object.");
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
for (const [type, value] of Object.entries(typeOrModule)) {
|
|
508
|
-
if (type === "cache") {
|
|
509
|
-
normalized.cache.browser = { ...(value?.browser ?? {}) };
|
|
510
|
-
normalized.cache.server = { ...(value?.server ?? {}) };
|
|
511
|
-
continue;
|
|
512
|
-
}
|
|
513
|
-
if (!registryTypes.has(type)) {
|
|
514
|
-
throw new Error(`Unknown Async registry type "${type}".`);
|
|
515
|
-
}
|
|
516
|
-
normalized[type] = normalizeEntries(type, value);
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
return normalized;
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
function appendDeclarations(target, source) {
|
|
523
|
-
for (const type of registryTypes) {
|
|
524
|
-
addEntries(target, type, source[type]);
|
|
525
|
-
}
|
|
526
|
-
addEntries(target, "cache.browser", source.cache.browser);
|
|
527
|
-
addEntries(target, "cache.server", source.cache.server);
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
function addEntries(registry, type, source) {
|
|
531
|
-
for (const [id, value] of Object.entries(source ?? {})) {
|
|
532
|
-
registry.register(type, id, value);
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
function isAppHub(value) {
|
|
537
|
-
return Boolean(value && typeof value.use === "function" && typeof value.snapshot === "function" && value.registry);
|
|
538
|
-
}
|
|
539
|
-
|
|
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;
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
function setOrRegisterSignal(signals, path, value) {
|
|
665
|
-
const id = String(path).split(".")[0];
|
|
666
|
-
if (signals.has?.(id)) {
|
|
667
|
-
signals.set(path, value);
|
|
668
|
-
return;
|
|
669
|
-
}
|
|
670
|
-
signals.register(id, createSignal(path === id ? value : {}));
|
|
671
|
-
if (path !== id) {
|
|
672
|
-
signals.set(path, value);
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
function attachServerCache(server, cache) {
|
|
677
|
-
try {
|
|
678
|
-
server.cache = cache;
|
|
679
|
-
} catch {
|
|
680
|
-
// Proxies that reject assignment can still receive cache through _setContext.
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
function createServerReferenceRegistry(initialMap = {}, options = {}) {
|
|
685
|
-
const registry = options.registry ?? createRegistryStore();
|
|
686
|
-
const type = options.type ?? "server";
|
|
687
|
-
const defaults = {};
|
|
688
|
-
|
|
689
|
-
const reference = {
|
|
690
|
-
registry,
|
|
691
|
-
|
|
692
|
-
register(id, value) {
|
|
693
|
-
registry.register(type, id, value);
|
|
694
|
-
return id;
|
|
695
|
-
},
|
|
696
|
-
|
|
697
|
-
registerMany(map) {
|
|
698
|
-
for (const [id, value] of Object.entries(map ?? {})) {
|
|
699
|
-
reference.register(id, value);
|
|
700
|
-
}
|
|
701
|
-
return reference;
|
|
702
|
-
},
|
|
703
|
-
|
|
704
|
-
unregister(id) {
|
|
705
|
-
return registry.unregister(type, id);
|
|
706
|
-
},
|
|
707
|
-
|
|
708
|
-
resolve() {
|
|
709
|
-
return undefined;
|
|
710
|
-
},
|
|
711
|
-
|
|
712
|
-
async run(id) {
|
|
713
|
-
throw new Error(`Server command "${id}" cannot run without a server proxy or server registry.`);
|
|
714
|
-
},
|
|
715
|
-
|
|
716
|
-
keys() {
|
|
717
|
-
return registry.keys(type);
|
|
718
|
-
},
|
|
719
|
-
|
|
720
|
-
entries() {
|
|
721
|
-
return registry.entries(type);
|
|
722
|
-
},
|
|
723
|
-
|
|
724
|
-
inspect() {
|
|
725
|
-
return registry.entries(type);
|
|
726
|
-
},
|
|
727
|
-
|
|
728
|
-
_setContext(context = {}) {
|
|
729
|
-
Object.assign(defaults, context);
|
|
730
|
-
return reference;
|
|
731
|
-
},
|
|
732
|
-
|
|
733
|
-
_adoptMany() {
|
|
734
|
-
return reference;
|
|
735
|
-
}
|
|
736
|
-
};
|
|
737
|
-
|
|
738
|
-
reference.registerMany(initialMap);
|
|
739
|
-
return createServerNamespace((id, args, context) => reference.run(id, args, context), reference, () => defaults);
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
function readRequestContextLike(store) {
|
|
743
|
-
if (!store) {
|
|
744
|
-
return {};
|
|
745
|
-
}
|
|
746
|
-
if (typeof store.get === "function") {
|
|
747
|
-
return store.get() ?? {};
|
|
748
|
-
}
|
|
749
|
-
if (typeof store.getStore === "function") {
|
|
750
|
-
return store.getStore() ?? {};
|
|
751
|
-
}
|
|
752
|
-
return {};
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
function normalizeEntries(type, entries = {}) {
|
|
756
|
-
if (type !== "signal") {
|
|
757
|
-
return { ...(entries ?? {}) };
|
|
758
|
-
}
|
|
759
|
-
const normalized = {};
|
|
760
|
-
for (const [id, value] of Object.entries(entries ?? {})) {
|
|
761
|
-
normalized[id] = normalizeSignalDeclaration(value);
|
|
762
|
-
}
|
|
763
|
-
return normalized;
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
function normalizeSignalDeclaration(value) {
|
|
767
|
-
if (value && typeof value === "object" && typeof value.subscribe === "function") {
|
|
768
|
-
return value;
|
|
769
|
-
}
|
|
770
|
-
return createSignal(value);
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
function isLocalServerRegistry(server) {
|
|
774
|
-
return typeof server?.registerMany === "function";
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
function shouldStartRouter(routes, options) {
|
|
778
|
-
return Boolean(options.routerOptions || options.mode || routes.entries().length > 0);
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
function renderDocument(routeHtml, { signals, browserCache, boundary, attributes }) {
|
|
782
|
-
const snapshot = {
|
|
783
|
-
signals: signals.snapshot(),
|
|
784
|
-
cache: {
|
|
785
|
-
browser: browserCache.snapshot()
|
|
786
|
-
}
|
|
787
|
-
};
|
|
788
|
-
const boundaryAttr = attributeName(attributes, "async", "boundary");
|
|
789
|
-
const snapshotAttr = attributeName(attributes, "async", "snapshot");
|
|
790
|
-
return `<section ${boundaryAttr}="${escapeAttribute(boundary)}">${routeHtml ?? ""}</section><script type="application/json" ${snapshotAttr}>${escapeScriptJson(snapshot)}</script>`;
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
function escapeAttribute(value) {
|
|
794
|
-
return String(value)
|
|
795
|
-
.replaceAll("&", "&")
|
|
796
|
-
.replaceAll('"', """)
|
|
797
|
-
.replaceAll("<", "<");
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
function escapeScriptJson(value) {
|
|
801
|
-
return JSON.stringify(value).replaceAll("<", "\\u003c");
|
|
802
|
-
}
|