@async/framework 0.2.2 → 0.4.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 +26 -0
- package/README.md +324 -48
- package/examples/cache/index.html +3 -3
- package/examples/components/main.js +10 -10
- package/examples/counter/index.html +2 -2
- package/examples/partials/index.html +2 -2
- package/examples/product/index.html +9 -9
- package/examples/router/index.html +2 -2
- package/examples/router/main.js +2 -2
- package/examples/server-call/index.html +2 -2
- package/examples/ssr/index.html +1 -1
- package/examples/ssr/main.js +2 -2
- package/examples/streaming/index.html +2 -2
- package/examples/streaming/main.js +2 -2
- package/framework.js +3912 -0
- package/package.json +14 -3
- package/src/app.js +73 -53
- package/src/attributes.js +52 -0
- package/src/cache.js +31 -16
- package/src/component.js +94 -19
- package/src/handlers.js +24 -5
- package/src/html.js +99 -6
- package/src/index.js +2 -0
- package/src/loader.js +291 -54
- package/src/partials.js +26 -11
- package/src/registry-store.js +257 -0
- package/src/router.js +42 -3
- package/src/server.js +12 -4
- package/src/signals.js +32 -10
package/src/partials.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { isTemplateResult, renderTemplate } from "./html.js";
|
|
2
|
+
import { attachRegistryInspection, createRegistryStore } from "./registry-store.js";
|
|
2
3
|
|
|
3
|
-
export function createPartialRegistry(initialMap = {}) {
|
|
4
|
-
const
|
|
4
|
+
export function createPartialRegistry(initialMap = {}, options = {}) {
|
|
5
|
+
const registryStore = options.registry ?? createRegistryStore();
|
|
6
|
+
const type = options.type ?? "partial";
|
|
7
|
+
const entries = registryStore._map(type);
|
|
5
8
|
|
|
6
|
-
const registry = {
|
|
9
|
+
const registry = attachRegistryInspection({
|
|
7
10
|
register(id, fn) {
|
|
8
11
|
assertId(id);
|
|
9
12
|
if (typeof fn !== "function") {
|
|
@@ -43,26 +46,30 @@ export function createPartialRegistry(initialMap = {}) {
|
|
|
43
46
|
partials: registry
|
|
44
47
|
};
|
|
45
48
|
const result = await fn.call(partialContext, props);
|
|
46
|
-
return normalizePartialResult(result);
|
|
49
|
+
return normalizePartialResult(result, partialContext);
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
_adoptMany() {
|
|
53
|
+
return registry;
|
|
47
54
|
}
|
|
48
|
-
};
|
|
55
|
+
}, registryStore, type);
|
|
49
56
|
|
|
50
57
|
registry.registerMany(initialMap);
|
|
51
58
|
return registry;
|
|
52
59
|
}
|
|
53
60
|
|
|
54
|
-
export function normalizePartialResult(result) {
|
|
61
|
+
export function normalizePartialResult(result, context = {}) {
|
|
55
62
|
if (isPartialEnvelope(result)) {
|
|
56
63
|
return {
|
|
57
64
|
...result,
|
|
58
|
-
html: Object.hasOwn(result, "html") ? renderPartialValue(result.html) : result.html
|
|
65
|
+
html: Object.hasOwn(result, "html") ? renderPartialValue(result.html, context) : result.html
|
|
59
66
|
};
|
|
60
67
|
}
|
|
61
68
|
|
|
62
|
-
return { html: renderPartialValue(result) };
|
|
69
|
+
return { html: renderPartialValue(result, context) };
|
|
63
70
|
}
|
|
64
71
|
|
|
65
|
-
function renderPartialValue(value) {
|
|
72
|
+
function renderPartialValue(value, context) {
|
|
66
73
|
if (value?.nodeType) {
|
|
67
74
|
return value;
|
|
68
75
|
}
|
|
@@ -70,9 +77,17 @@ function renderPartialValue(value) {
|
|
|
70
77
|
return value;
|
|
71
78
|
}
|
|
72
79
|
if (isTemplateResult(value)) {
|
|
73
|
-
return renderTemplate(value);
|
|
80
|
+
return renderTemplate(value, templateRenderOptions(context));
|
|
74
81
|
}
|
|
75
|
-
return renderTemplate(value);
|
|
82
|
+
return renderTemplate(value, templateRenderOptions(context));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function templateRenderOptions(context) {
|
|
86
|
+
return {
|
|
87
|
+
attributes: context.loader?.attributes,
|
|
88
|
+
signals: context.signals,
|
|
89
|
+
bind: context.loader?._registerBinding?.bind(context.loader)
|
|
90
|
+
};
|
|
76
91
|
}
|
|
77
92
|
|
|
78
93
|
function isPartialEnvelope(value) {
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
const declarationTypes = new Set(["signal", "handler", "server", "partial", "route", "component"]);
|
|
2
|
+
const cacheTypes = new Set(["cache.browser", "cache.server"]);
|
|
3
|
+
const cacheEntryTypes = new Set(["cache.browser.entries", "cache.server.entries"]);
|
|
4
|
+
const allTypes = new Set([...declarationTypes, ...cacheTypes, ...cacheEntryTypes]);
|
|
5
|
+
|
|
6
|
+
export function createRegistryStore(initial = {}, options = {}) {
|
|
7
|
+
const backing = options.backing ?? createBacking();
|
|
8
|
+
const target = options.target ?? "server";
|
|
9
|
+
|
|
10
|
+
const registry = {
|
|
11
|
+
target,
|
|
12
|
+
|
|
13
|
+
register(type, id, value) {
|
|
14
|
+
const map = registry._map(type);
|
|
15
|
+
assertId(type, id);
|
|
16
|
+
if (map.has(id)) {
|
|
17
|
+
throw new Error(`${type} "${id}" is already registered.`);
|
|
18
|
+
}
|
|
19
|
+
map.set(id, value);
|
|
20
|
+
return id;
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
registerMany(type, map = {}) {
|
|
24
|
+
for (const [id, value] of Object.entries(map ?? {})) {
|
|
25
|
+
registry.register(type, id, value);
|
|
26
|
+
}
|
|
27
|
+
return registry;
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
set(type, id, value) {
|
|
31
|
+
const map = registry._map(type);
|
|
32
|
+
assertId(type, id);
|
|
33
|
+
map.set(id, value);
|
|
34
|
+
return value;
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
delete(type, id) {
|
|
38
|
+
return registry._map(type).delete(id);
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
keys(type) {
|
|
42
|
+
if (isHiddenInBrowser(type, target)) {
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
return [...registry._map(type).keys()];
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
entries(type, entryOptions = {}) {
|
|
49
|
+
const normalized = normalizeType(type);
|
|
50
|
+
if (isHiddenInBrowser(normalized, entryOptions.target ?? target)) {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
return [...registry._map(normalized)].map(([id, value]) => [
|
|
54
|
+
id,
|
|
55
|
+
publicValue(normalized, id, value, { target, ...entryOptions })
|
|
56
|
+
]);
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
has(type, id) {
|
|
60
|
+
assertId(type, id);
|
|
61
|
+
if (isHiddenInBrowser(type, target)) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
return registry._map(type).has(id);
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
get(type, id, getOptions = {}) {
|
|
68
|
+
assertId(type, id);
|
|
69
|
+
const normalized = normalizeType(type);
|
|
70
|
+
if (isHiddenInBrowser(normalized, getOptions.target ?? target)) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
const value = registry._map(normalized).get(id);
|
|
74
|
+
if (value === undefined) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
return publicValue(normalized, id, value, { target, ...getOptions });
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
snapshot(snapshotOptions = {}) {
|
|
81
|
+
const snapshotTarget = snapshotOptions.target ?? target;
|
|
82
|
+
return {
|
|
83
|
+
signal: snapshotSignals(backing.signal),
|
|
84
|
+
handler: snapshotDescriptors(backing.handler, "handler"),
|
|
85
|
+
server: snapshotDescriptors(backing.server, "server"),
|
|
86
|
+
partial: snapshotDescriptors(backing.partial, "partial"),
|
|
87
|
+
route: snapshotPlain(backing.route),
|
|
88
|
+
component: snapshotDescriptors(backing.component, "component"),
|
|
89
|
+
cache: {
|
|
90
|
+
browser: snapshotPlain(backing.cache.browser),
|
|
91
|
+
server: snapshotPlain(backing.cache.server)
|
|
92
|
+
},
|
|
93
|
+
entries: {
|
|
94
|
+
browser: snapshotCacheEntries(backing.cacheEntries.browser),
|
|
95
|
+
server: snapshotTarget === "browser" ? {} : snapshotCacheEntries(backing.cacheEntries.server)
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
rawSnapshot() {
|
|
101
|
+
return {
|
|
102
|
+
signal: Object.fromEntries(backing.signal),
|
|
103
|
+
handler: Object.fromEntries(backing.handler),
|
|
104
|
+
server: Object.fromEntries(backing.server),
|
|
105
|
+
partial: Object.fromEntries(backing.partial),
|
|
106
|
+
route: Object.fromEntries(backing.route),
|
|
107
|
+
component: Object.fromEntries(backing.component),
|
|
108
|
+
cache: {
|
|
109
|
+
browser: Object.fromEntries(backing.cache.browser),
|
|
110
|
+
server: Object.fromEntries(backing.cache.server)
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
view(viewOptions = {}) {
|
|
116
|
+
return createRegistryStore(undefined, {
|
|
117
|
+
backing,
|
|
118
|
+
target: viewOptions.target ?? target
|
|
119
|
+
});
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
_map(type) {
|
|
123
|
+
const normalized = normalizeType(type);
|
|
124
|
+
if (declarationTypes.has(normalized)) {
|
|
125
|
+
return backing[normalized];
|
|
126
|
+
}
|
|
127
|
+
if (normalized === "cache.browser") {
|
|
128
|
+
return backing.cache.browser;
|
|
129
|
+
}
|
|
130
|
+
if (normalized === "cache.server") {
|
|
131
|
+
return backing.cache.server;
|
|
132
|
+
}
|
|
133
|
+
if (normalized === "cache.browser.entries") {
|
|
134
|
+
return backing.cacheEntries.browser;
|
|
135
|
+
}
|
|
136
|
+
if (normalized === "cache.server.entries") {
|
|
137
|
+
return backing.cacheEntries.server;
|
|
138
|
+
}
|
|
139
|
+
throw new Error(`Unknown Async registry type "${type}".`);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
applyInitial(registry, initial);
|
|
144
|
+
return registry;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function attachRegistryInspection(target, registry, type) {
|
|
148
|
+
Object.defineProperty(target, "registry", {
|
|
149
|
+
configurable: true,
|
|
150
|
+
enumerable: true,
|
|
151
|
+
value: registry
|
|
152
|
+
});
|
|
153
|
+
target.keys = () => registry.keys(type);
|
|
154
|
+
target.entries = () => registry.entries(type);
|
|
155
|
+
target.inspect = () => registry.entries(type);
|
|
156
|
+
return target;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function createBacking() {
|
|
160
|
+
return {
|
|
161
|
+
signal: new Map(),
|
|
162
|
+
handler: new Map(),
|
|
163
|
+
server: new Map(),
|
|
164
|
+
partial: new Map(),
|
|
165
|
+
route: new Map(),
|
|
166
|
+
component: new Map(),
|
|
167
|
+
cache: {
|
|
168
|
+
browser: new Map(),
|
|
169
|
+
server: new Map()
|
|
170
|
+
},
|
|
171
|
+
cacheEntries: {
|
|
172
|
+
browser: new Map(),
|
|
173
|
+
server: new Map()
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function applyInitial(registry, initial = {}) {
|
|
179
|
+
registry.registerMany("signal", initial.signal);
|
|
180
|
+
registry.registerMany("handler", initial.handler);
|
|
181
|
+
registry.registerMany("server", initial.server);
|
|
182
|
+
registry.registerMany("partial", initial.partial);
|
|
183
|
+
registry.registerMany("route", initial.route);
|
|
184
|
+
registry.registerMany("component", initial.component);
|
|
185
|
+
registry.registerMany("cache.browser", initial.cache?.browser);
|
|
186
|
+
registry.registerMany("cache.server", initial.cache?.server);
|
|
187
|
+
|
|
188
|
+
const entries = initial.entries ?? {};
|
|
189
|
+
for (const [key, value] of Object.entries(entries.browser ?? {})) {
|
|
190
|
+
registry.set("cache.browser.entries", key, cacheEntry(value));
|
|
191
|
+
}
|
|
192
|
+
for (const [key, value] of Object.entries(entries.server ?? {})) {
|
|
193
|
+
registry.set("cache.server.entries", key, cacheEntry(value));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function normalizeType(type) {
|
|
198
|
+
if (!allTypes.has(type)) {
|
|
199
|
+
throw new Error(`Unknown Async registry type "${type}".`);
|
|
200
|
+
}
|
|
201
|
+
return type;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function assertId(type, id) {
|
|
205
|
+
if (typeof id !== "string" || id.length === 0) {
|
|
206
|
+
throw new TypeError(`${type} id must be a non-empty string.`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function publicValue(type, id, value, options) {
|
|
211
|
+
if (type === "server" && options.target === "browser") {
|
|
212
|
+
return { id, kind: "server" };
|
|
213
|
+
}
|
|
214
|
+
if (cacheEntryTypes.has(type)) {
|
|
215
|
+
return value?.value;
|
|
216
|
+
}
|
|
217
|
+
return value;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function isHiddenInBrowser(type, target) {
|
|
221
|
+
return type === "cache.server.entries" && target === "browser";
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function snapshotSignals(map) {
|
|
225
|
+
const snapshot = {};
|
|
226
|
+
for (const [id, entry] of map) {
|
|
227
|
+
snapshot[id] = typeof entry?.snapshot === "function" ? entry.snapshot() : entry?.value ?? entry;
|
|
228
|
+
}
|
|
229
|
+
return snapshot;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function snapshotDescriptors(map, kind) {
|
|
233
|
+
const snapshot = {};
|
|
234
|
+
for (const id of map.keys()) {
|
|
235
|
+
snapshot[id] = { id, kind };
|
|
236
|
+
}
|
|
237
|
+
return snapshot;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function snapshotPlain(map) {
|
|
241
|
+
return Object.fromEntries(map);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function snapshotCacheEntries(map) {
|
|
245
|
+
const snapshot = {};
|
|
246
|
+
for (const [id, entry] of map) {
|
|
247
|
+
snapshot[id] = entry?.value;
|
|
248
|
+
}
|
|
249
|
+
return snapshot;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function cacheEntry(value) {
|
|
253
|
+
if (value && typeof value === "object" && Object.hasOwn(value, "value")) {
|
|
254
|
+
return value;
|
|
255
|
+
}
|
|
256
|
+
return { value };
|
|
257
|
+
}
|
package/src/router.js
CHANGED
|
@@ -2,6 +2,8 @@ import { AsyncLoader } from "./loader.js";
|
|
|
2
2
|
import { createHandlerRegistry } from "./handlers.js";
|
|
3
3
|
import { createSignalRegistry } from "./signals.js";
|
|
4
4
|
import { applyServerResult } from "./server.js";
|
|
5
|
+
import { createRegistryStore } from "./registry-store.js";
|
|
6
|
+
import { normalizeAttributeConfig } from "./attributes.js";
|
|
5
7
|
|
|
6
8
|
export function defineRoute(partial, options = {}) {
|
|
7
9
|
return {
|
|
@@ -12,16 +14,22 @@ export function defineRoute(partial, options = {}) {
|
|
|
12
14
|
|
|
13
15
|
export const route = defineRoute;
|
|
14
16
|
|
|
15
|
-
export function createRouteRegistry(initialMap = {}) {
|
|
17
|
+
export function createRouteRegistry(initialMap = {}, options = {}) {
|
|
18
|
+
const registryStore = options.registry ?? createRegistryStore();
|
|
19
|
+
const type = options.type ?? "route";
|
|
20
|
+
const entries = registryStore._map(type);
|
|
16
21
|
const routes = [];
|
|
17
22
|
|
|
18
23
|
const registry = {
|
|
24
|
+
registry: registryStore,
|
|
25
|
+
|
|
19
26
|
register(pattern, definition) {
|
|
20
27
|
assertPattern(pattern);
|
|
21
28
|
if (routes.some((candidate) => candidate.pattern === pattern)) {
|
|
22
29
|
throw new Error(`Route "${pattern}" is already registered.`);
|
|
23
30
|
}
|
|
24
31
|
const nextRoute = normalizeRoute(pattern, definition);
|
|
32
|
+
entries.set(pattern, nextRoute.definition);
|
|
25
33
|
routes.push(nextRoute);
|
|
26
34
|
return nextRoute;
|
|
27
35
|
},
|
|
@@ -55,11 +63,38 @@ export function createRouteRegistry(initialMap = {}) {
|
|
|
55
63
|
|
|
56
64
|
entries() {
|
|
57
65
|
return routes.map(({ pattern, definition }) => ({ pattern, route: definition }));
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
keys() {
|
|
69
|
+
return [...entries.keys()];
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
inspect() {
|
|
73
|
+
return registryStore.entries(type);
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
_adoptMany(map = {}) {
|
|
77
|
+
for (const pattern of Object.keys(map ?? {})) {
|
|
78
|
+
adoptRoute(pattern, entries.get(pattern));
|
|
79
|
+
}
|
|
80
|
+
return registry;
|
|
58
81
|
}
|
|
59
82
|
};
|
|
60
83
|
|
|
84
|
+
for (const [pattern, definition] of entries) {
|
|
85
|
+
adoptRoute(pattern, definition);
|
|
86
|
+
}
|
|
61
87
|
registry.registerMany(initialMap);
|
|
62
88
|
return registry;
|
|
89
|
+
|
|
90
|
+
function adoptRoute(pattern, definition) {
|
|
91
|
+
if (routes.some((candidate) => candidate.pattern === pattern)) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const nextRoute = normalizeRoute(pattern, definition);
|
|
95
|
+
entries.set(pattern, nextRoute.definition);
|
|
96
|
+
routes.push(nextRoute);
|
|
97
|
+
}
|
|
63
98
|
}
|
|
64
99
|
|
|
65
100
|
export function createRouter({
|
|
@@ -74,12 +109,14 @@ export function createRouter({
|
|
|
74
109
|
cache,
|
|
75
110
|
partials,
|
|
76
111
|
fetch: fetchImpl = globalThis.fetch?.bind(globalThis),
|
|
77
|
-
routeEndpoint = "/__async/route"
|
|
112
|
+
routeEndpoint = "/__async/route",
|
|
113
|
+
attributes
|
|
78
114
|
} = {}) {
|
|
79
115
|
const documentRef = root?.ownerDocument ?? root ?? globalThis.document;
|
|
80
116
|
const rootNode = root ?? documentRef;
|
|
81
117
|
const signalRegistry = signals ?? loader?.signals ?? createSignalRegistry();
|
|
82
118
|
const handlerRegistry = handlers ?? loader?.handlers ?? createHandlerRegistry();
|
|
119
|
+
const attributeConfig = normalizeAttributeConfig(attributes ?? loader?.attributes);
|
|
83
120
|
const loaderInstance =
|
|
84
121
|
loader ??
|
|
85
122
|
AsyncLoader({
|
|
@@ -87,7 +124,8 @@ export function createRouter({
|
|
|
87
124
|
signals: signalRegistry,
|
|
88
125
|
handlers: handlerRegistry,
|
|
89
126
|
server,
|
|
90
|
-
cache
|
|
127
|
+
cache,
|
|
128
|
+
attributes: attributeConfig
|
|
91
129
|
});
|
|
92
130
|
const ownsLoader = !loader;
|
|
93
131
|
const cleanups = new Set();
|
|
@@ -104,6 +142,7 @@ export function createRouter({
|
|
|
104
142
|
server,
|
|
105
143
|
cache,
|
|
106
144
|
partials,
|
|
145
|
+
attributes: attributeConfig,
|
|
107
146
|
|
|
108
147
|
start() {
|
|
109
148
|
assertActive();
|
package/src/server.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
import { attachRegistryInspection, createRegistryStore } from "./registry-store.js";
|
|
2
|
+
|
|
1
3
|
const serverEnvelopeKeys = new Set(["value", "signals", "boundary", "html", "redirect", "error"]);
|
|
2
4
|
|
|
3
|
-
export function createServerRegistry(initialMap = {}) {
|
|
4
|
-
const
|
|
5
|
+
export function createServerRegistry(initialMap = {}, options = {}) {
|
|
6
|
+
const registryStore = options.registry ?? createRegistryStore();
|
|
7
|
+
const type = options.type ?? "server";
|
|
8
|
+
const entries = registryStore._map(type);
|
|
5
9
|
const defaults = {};
|
|
6
10
|
|
|
7
|
-
const registry = {
|
|
11
|
+
const registry = attachRegistryInspection({
|
|
8
12
|
register(id, fn) {
|
|
9
13
|
assertServerId(id);
|
|
10
14
|
if (typeof fn !== "function") {
|
|
@@ -64,8 +68,12 @@ export function createServerRegistry(initialMap = {}) {
|
|
|
64
68
|
_setContext(context = {}) {
|
|
65
69
|
Object.assign(defaults, context);
|
|
66
70
|
return registry;
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
_adoptMany() {
|
|
74
|
+
return registry;
|
|
67
75
|
}
|
|
68
|
-
};
|
|
76
|
+
}, registryStore, type);
|
|
69
77
|
|
|
70
78
|
registry.registerMany(initialMap);
|
|
71
79
|
return createServerNamespace((id, args, context) => registry.run(id, args, context), registry);
|
package/src/signals.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { asyncSignal as createAsyncSignal, isAsyncSignal } from "./async-signal.js";
|
|
2
|
+
import { attachRegistryInspection, createRegistryStore } from "./registry-store.js";
|
|
2
3
|
|
|
3
4
|
const signalKind = Symbol.for("@async/framework.signal");
|
|
4
5
|
const computedKind = Symbol.for("@async/framework.computed");
|
|
@@ -116,12 +117,15 @@ export function effect(fn) {
|
|
|
116
117
|
};
|
|
117
118
|
}
|
|
118
119
|
|
|
119
|
-
export function createSignalRegistry(initialMap = {}) {
|
|
120
|
-
const
|
|
120
|
+
export function createSignalRegistry(initialMap = {}, options = {}) {
|
|
121
|
+
const registryStore = options.registry ?? createRegistryStore();
|
|
122
|
+
const type = options.type ?? "signal";
|
|
123
|
+
const entries = registryStore._map(type);
|
|
121
124
|
const registryCleanups = new Set();
|
|
122
125
|
const runtimeContext = {};
|
|
126
|
+
const boundEntries = new Set();
|
|
123
127
|
|
|
124
|
-
const registry = {
|
|
128
|
+
const registry = attachRegistryInspection({
|
|
125
129
|
register(id, signalLike) {
|
|
126
130
|
assertId(id);
|
|
127
131
|
if (entries.has(id)) {
|
|
@@ -129,12 +133,7 @@ export function createSignalRegistry(initialMap = {}) {
|
|
|
129
133
|
}
|
|
130
134
|
const entry = normalizeSignal(signalLike);
|
|
131
135
|
entries.set(id, entry);
|
|
132
|
-
|
|
133
|
-
const cleanup = entry._bindRegistry(registry, id);
|
|
134
|
-
if (typeof cleanup === "function") {
|
|
135
|
-
registryCleanups.add(cleanup);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
136
|
+
bindEntry(id, entry);
|
|
138
137
|
return registry.ref(id);
|
|
139
138
|
},
|
|
140
139
|
|
|
@@ -289,11 +288,34 @@ export function createSignalRegistry(initialMap = {}) {
|
|
|
289
288
|
|
|
290
289
|
_context() {
|
|
291
290
|
return runtimeContext;
|
|
291
|
+
},
|
|
292
|
+
|
|
293
|
+
_adoptMany(map = {}) {
|
|
294
|
+
for (const id of Object.keys(map ?? {})) {
|
|
295
|
+
if (entries.has(id)) {
|
|
296
|
+
bindEntry(id, entries.get(id));
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return registry;
|
|
292
300
|
}
|
|
293
|
-
};
|
|
301
|
+
}, registryStore, type);
|
|
294
302
|
|
|
303
|
+
for (const [id, entry] of entries) {
|
|
304
|
+
bindEntry(id, entry);
|
|
305
|
+
}
|
|
295
306
|
registry.registerMany(initialMap);
|
|
296
307
|
return registry;
|
|
308
|
+
|
|
309
|
+
function bindEntry(id, entry) {
|
|
310
|
+
if (boundEntries.has(id) || typeof entry?._bindRegistry !== "function") {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
boundEntries.add(id);
|
|
314
|
+
const cleanup = entry._bindRegistry(registry, id);
|
|
315
|
+
if (typeof cleanup === "function") {
|
|
316
|
+
registryCleanups.add(cleanup);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
297
319
|
}
|
|
298
320
|
|
|
299
321
|
function normalizeSignal(signalLike) {
|