@forgeax/engine-host 0.1.27
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/LICENSE +202 -0
- package/README.md +32 -0
- package/dist/__tests__/host.test.d.ts +2 -0
- package/dist/__tests__/host.test.d.ts.map +1 -0
- package/dist/backend.d.ts +46 -0
- package/dist/backend.d.ts.map +1 -0
- package/dist/backend.mjs +797 -0
- package/dist/backend.mjs.map +1 -0
- package/dist/frontend.d.ts +50 -0
- package/dist/frontend.d.ts.map +1 -0
- package/dist/frontend.mjs +715 -0
- package/dist/frontend.mjs.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +1473 -0
- package/dist/index.mjs.map +1 -0
- package/dist/protocol.d.ts +153 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.mjs +351 -0
- package/dist/protocol.mjs.map +1 -0
- package/dist/transport.d.ts +64 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.mjs +575 -0
- package/dist/transport.mjs.map +1 -0
- package/package.json +88 -0
- package/src/__tests__/host.test.ts +510 -0
- package/src/backend.ts +342 -0
- package/src/frontend.ts +508 -0
- package/src/index.ts +54 -0
- package/src/protocol.ts +586 -0
- package/src/transport.ts +717 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
// src/protocol.ts
|
|
2
|
+
var HOST_ASSEMBLY_SCHEMA_VERSION = 1;
|
|
3
|
+
var HostAssemblyError = class extends Error {
|
|
4
|
+
code;
|
|
5
|
+
expected;
|
|
6
|
+
hint;
|
|
7
|
+
detail;
|
|
8
|
+
constructor(code, expected, hint, detail) {
|
|
9
|
+
super(`${code}: ${expected}`);
|
|
10
|
+
this.name = "HostAssemblyError";
|
|
11
|
+
this.code = code;
|
|
12
|
+
this.expected = expected;
|
|
13
|
+
this.hint = hint;
|
|
14
|
+
this.detail = detail;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
function assertHostModuleCatalogIdentity(module, record) {
|
|
18
|
+
if (record.version !== void 0 && record.version !== module.version) {
|
|
19
|
+
throw new HostAssemblyError(
|
|
20
|
+
"host-assembly-module-version-mismatch",
|
|
21
|
+
`module ${module.name} to load catalog version ${module.version}`,
|
|
22
|
+
"Regenerate the static Catalog from the same backend package revision.",
|
|
23
|
+
{ name: module.name, actual: record.version, expected: module.version }
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
if (record.digest !== void 0 && module.digest !== void 0 && record.digest !== module.digest) {
|
|
27
|
+
throw new HostAssemblyError(
|
|
28
|
+
"host-assembly-module-version-mismatch",
|
|
29
|
+
`module ${module.name} to load catalog digest ${module.digest ?? "none"}`,
|
|
30
|
+
"Regenerate the static Catalog from the same backend package bytes.",
|
|
31
|
+
{ name: module.name, actual: record.digest, expected: module.digest ?? "none" }
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
const versionMatches = record.version !== void 0 && record.version === module.version;
|
|
35
|
+
const digestMatches = module.digest !== void 0 && record.digest !== void 0 && record.digest === module.digest;
|
|
36
|
+
const staticWithoutIdentity = module.version === "static" && module.digest === void 0 && record.version === void 0 && record.digest === void 0;
|
|
37
|
+
if (!versionMatches && !digestMatches && !staticWithoutIdentity) {
|
|
38
|
+
throw new HostAssemblyError(
|
|
39
|
+
"host-assembly-module-version-mismatch",
|
|
40
|
+
`module ${module.name} to have a matching catalog code identity for ${module.version}`,
|
|
41
|
+
"Add the generated module version or digest to the static Catalog.",
|
|
42
|
+
{
|
|
43
|
+
name: module.name,
|
|
44
|
+
actual: record.version ?? record.digest ?? "unknown",
|
|
45
|
+
expected: module.version
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function canonicalHostJson(value) {
|
|
51
|
+
if (value === void 0) return "undefined";
|
|
52
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
53
|
+
if (Array.isArray(value)) return `[${value.map(canonicalHostJson).join(",")}]`;
|
|
54
|
+
return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${canonicalHostJson(item)}`).join(",")}}`;
|
|
55
|
+
}
|
|
56
|
+
function hostRevision(value) {
|
|
57
|
+
let hash = 2166136261;
|
|
58
|
+
for (const char of canonicalHostJson(value)) {
|
|
59
|
+
hash ^= char.codePointAt(0) ?? 0;
|
|
60
|
+
hash = Math.imul(hash, 16777619);
|
|
61
|
+
}
|
|
62
|
+
return `fnv1a:${(hash >>> 0).toString(16).padStart(8, "0")}`;
|
|
63
|
+
}
|
|
64
|
+
function cloneEntry(entry) {
|
|
65
|
+
const config = entry.group ? entry.config?.map(cloneEntry) : entry.config;
|
|
66
|
+
return {
|
|
67
|
+
id: entry.id,
|
|
68
|
+
name: entry.name,
|
|
69
|
+
...config === void 0 ? {} : { config },
|
|
70
|
+
...entry.group === void 0 ? {} : { group: entry.group },
|
|
71
|
+
...entry.disabled === void 0 ? {} : { disabled: entry.disabled },
|
|
72
|
+
...entry.inject === void 0 ? {} : { inject: entry.inject },
|
|
73
|
+
...entry.realm === void 0 ? {} : { realm: entry.realm }
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function projectPairs(pairs) {
|
|
77
|
+
const entries = [];
|
|
78
|
+
const modules = [];
|
|
79
|
+
const projections = [];
|
|
80
|
+
for (const pair of pairs) {
|
|
81
|
+
if (pair.backend !== void 0 && pair.frontend !== void 0 && pair.backend.module.version !== pair.frontend.module.version) {
|
|
82
|
+
throw new HostAssemblyError(
|
|
83
|
+
"host-assembly-module-version-mismatch",
|
|
84
|
+
`paired module ${pair.id} to use one code version on both hosts`,
|
|
85
|
+
"Resolve backend and frontend package entries from the same locked package revision.",
|
|
86
|
+
{
|
|
87
|
+
name: pair.id,
|
|
88
|
+
actual: pair.backend.module.version,
|
|
89
|
+
expected: pair.frontend.module.version
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
if (pair.frontend === void 0) continue;
|
|
94
|
+
entries.push(pair.frontend.entry);
|
|
95
|
+
modules.push(pair.frontend.module);
|
|
96
|
+
projections.push({
|
|
97
|
+
id: pair.id,
|
|
98
|
+
entryId: pair.frontend.entry.id,
|
|
99
|
+
module: pair.frontend.module
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return { entries, modules, projections };
|
|
103
|
+
}
|
|
104
|
+
function assemblyPairsFromInput(input) {
|
|
105
|
+
if (input.pairs !== void 0) {
|
|
106
|
+
const projected = projectPairs(input.pairs);
|
|
107
|
+
return {
|
|
108
|
+
entries: input.entries ?? projected.entries,
|
|
109
|
+
modules: input.modules ?? projected.modules,
|
|
110
|
+
pairs: projected.projections
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
const entries = input.entries ?? [];
|
|
114
|
+
const modules = [...input.modules ?? []];
|
|
115
|
+
for (const [index, entry] of entries.entries()) {
|
|
116
|
+
if (modules[index] !== void 0 || modules.some((module) => module.name === entry.name))
|
|
117
|
+
continue;
|
|
118
|
+
modules.push({
|
|
119
|
+
name: entry.name,
|
|
120
|
+
realm: entry.realm ?? "engine",
|
|
121
|
+
version: "unknown"
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
entries,
|
|
126
|
+
modules,
|
|
127
|
+
pairs: entries.map((entry, index) => ({
|
|
128
|
+
id: entry.id,
|
|
129
|
+
entryId: entry.id,
|
|
130
|
+
module: modules[index]?.name === entry.name ? modules[index] : modules.find((module) => module.name === entry.name) ?? {
|
|
131
|
+
name: entry.name,
|
|
132
|
+
realm: entry.realm ?? "engine",
|
|
133
|
+
version: "unknown"
|
|
134
|
+
}
|
|
135
|
+
}))
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function createHostAssembly(input) {
|
|
139
|
+
const projected = assemblyPairsFromInput(input);
|
|
140
|
+
const entries = projected.entries.map(cloneEntry);
|
|
141
|
+
const modules = projected.modules.map((module) => ({ ...module }));
|
|
142
|
+
const pairs = projected.pairs.map((pair) => ({ ...pair, module: { ...pair.module } }));
|
|
143
|
+
const identity = {
|
|
144
|
+
schemaVersion: HOST_ASSEMBLY_SCHEMA_VERSION,
|
|
145
|
+
entries,
|
|
146
|
+
modules,
|
|
147
|
+
pairs,
|
|
148
|
+
...input.config === void 0 ? {} : { config: input.config }
|
|
149
|
+
};
|
|
150
|
+
return {
|
|
151
|
+
...identity,
|
|
152
|
+
revision: hostRevision(identity)
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function validateEntry(entry, path) {
|
|
156
|
+
if (entry === null || typeof entry !== "object") return `${path} must be an Entry object`;
|
|
157
|
+
if (typeof entry.id !== "string" || entry.id.length === 0) return `${path}.id must be non-empty`;
|
|
158
|
+
if (typeof entry.name !== "string" || entry.name.length === 0)
|
|
159
|
+
return `${path}.name must be non-empty`;
|
|
160
|
+
if (entry.group === true) {
|
|
161
|
+
if (!Array.isArray(entry.config)) return `${path}.config must be an Entry array for a Group`;
|
|
162
|
+
for (const [index, child] of entry.config.entries()) {
|
|
163
|
+
const reason = validateEntry(child, `${path}.config[${index}]`);
|
|
164
|
+
if (reason !== void 0) return reason;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return void 0;
|
|
168
|
+
}
|
|
169
|
+
function validateHostAssembly(assembly) {
|
|
170
|
+
if (assembly === null || typeof assembly !== "object") {
|
|
171
|
+
return {
|
|
172
|
+
ok: false,
|
|
173
|
+
error: new HostAssemblyError(
|
|
174
|
+
"host-assembly-invalid",
|
|
175
|
+
"assembly to be an object",
|
|
176
|
+
"Regenerate the frontend assembly from the active backend authority.",
|
|
177
|
+
{ reason: "assembly is not an object" }
|
|
178
|
+
)
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
if (assembly.schemaVersion !== HOST_ASSEMBLY_SCHEMA_VERSION) {
|
|
182
|
+
return {
|
|
183
|
+
ok: false,
|
|
184
|
+
error: new HostAssemblyError(
|
|
185
|
+
"host-assembly-invalid",
|
|
186
|
+
`assembly schema ${HOST_ASSEMBLY_SCHEMA_VERSION}`,
|
|
187
|
+
"Regenerate the frontend assembly with the matching Engine host package.",
|
|
188
|
+
{ reason: `unsupported schema ${String(assembly.schemaVersion)}` }
|
|
189
|
+
)
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
if (!Array.isArray(assembly.entries) || !Array.isArray(assembly.modules)) {
|
|
193
|
+
return {
|
|
194
|
+
ok: false,
|
|
195
|
+
error: new HostAssemblyError(
|
|
196
|
+
"host-assembly-invalid",
|
|
197
|
+
"assembly entries and modules to be arrays",
|
|
198
|
+
"Regenerate the frontend assembly from the active backend authority.",
|
|
199
|
+
{ reason: "entries or modules is not an array" }
|
|
200
|
+
)
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
if (!Array.isArray(assembly.pairs)) {
|
|
204
|
+
return {
|
|
205
|
+
ok: false,
|
|
206
|
+
error: new HostAssemblyError(
|
|
207
|
+
"host-assembly-invalid",
|
|
208
|
+
"assembly pairs to be an array",
|
|
209
|
+
"Regenerate the assembly from the backend host using the matching host package.",
|
|
210
|
+
{ reason: "pairs is not an array" }
|
|
211
|
+
)
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
const seen = /* @__PURE__ */ new Set();
|
|
215
|
+
for (const [index, entry] of assembly.entries.entries()) {
|
|
216
|
+
const reason = validateEntry(entry, `entries[${index}]`);
|
|
217
|
+
if (reason !== void 0) {
|
|
218
|
+
return {
|
|
219
|
+
ok: false,
|
|
220
|
+
error: new HostAssemblyError(
|
|
221
|
+
"host-assembly-invalid",
|
|
222
|
+
"all assembly entries to be valid native EntryOptions",
|
|
223
|
+
"Repair the backend Entry projection before publishing it to a browser.",
|
|
224
|
+
{ reason }
|
|
225
|
+
)
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
if (seen.has(entry.id)) {
|
|
229
|
+
return {
|
|
230
|
+
ok: false,
|
|
231
|
+
error: new HostAssemblyError(
|
|
232
|
+
"host-assembly-invalid",
|
|
233
|
+
"assembly Entry ids to be unique",
|
|
234
|
+
"Give repeated plugin instances independent stable ids.",
|
|
235
|
+
{ reason: `duplicate Entry id ${entry.id}` }
|
|
236
|
+
)
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
seen.add(entry.id);
|
|
240
|
+
}
|
|
241
|
+
const seenModules = /* @__PURE__ */ new Map();
|
|
242
|
+
for (const [index, module] of assembly.modules.entries()) {
|
|
243
|
+
if (module === null || typeof module !== "object" || typeof module.name !== "string" || typeof module.realm !== "string" || typeof module.version !== "string" || module.name.length === 0 || module.version.length === 0 || module.url !== void 0 && typeof module.url !== "string" || module.digest !== void 0 && (typeof module.digest !== "string" || module.digest.length === 0)) {
|
|
244
|
+
return {
|
|
245
|
+
ok: false,
|
|
246
|
+
error: new HostAssemblyError(
|
|
247
|
+
"host-assembly-invalid",
|
|
248
|
+
"module names and versions to be non-empty",
|
|
249
|
+
"Regenerate the module projection from the resolved package metadata.",
|
|
250
|
+
{ reason: `invalid module at index ${index}` }
|
|
251
|
+
)
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
const previousModule = seenModules.get(module.name);
|
|
255
|
+
if (previousModule !== void 0 && (previousModule.realm !== module.realm || previousModule.version !== module.version || previousModule.url !== module.url || previousModule.digest !== module.digest)) {
|
|
256
|
+
return {
|
|
257
|
+
ok: false,
|
|
258
|
+
error: new HostAssemblyError(
|
|
259
|
+
"host-assembly-invalid",
|
|
260
|
+
"assembly module identity to be consistent for repeated Entries",
|
|
261
|
+
"Reuse one resolved module identity when a package has multiple Entry instances.",
|
|
262
|
+
{ reason: `module ${module.name} has conflicting identities` }
|
|
263
|
+
)
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
seenModules.set(module.name, module);
|
|
267
|
+
}
|
|
268
|
+
const seenPairIds = /* @__PURE__ */ new Set();
|
|
269
|
+
for (const [index, pair] of assembly.pairs.entries()) {
|
|
270
|
+
const pairModule = pair?.module;
|
|
271
|
+
if (pair === null || typeof pair !== "object" || typeof pair.id !== "string" || pair.id.length === 0 || typeof pair.entryId !== "string" || pair.entryId.length === 0 || pairModule === null || pairModule === void 0 || typeof pairModule !== "object" || typeof pairModule.name !== "string" || typeof pairModule.realm !== "string" || typeof pairModule.version !== "string" || pairModule.name.length === 0 || pairModule.version.length === 0 || pairModule.url !== void 0 && typeof pairModule.url !== "string" || pairModule.digest !== void 0 && (typeof pairModule.digest !== "string" || pairModule.digest.length === 0)) {
|
|
272
|
+
return {
|
|
273
|
+
ok: false,
|
|
274
|
+
error: new HostAssemblyError(
|
|
275
|
+
"host-assembly-invalid",
|
|
276
|
+
"assembly pair identities and modules to be valid",
|
|
277
|
+
"Regenerate paired frontend entries from the backend package manifest.",
|
|
278
|
+
{ reason: `invalid pair at index ${index}` }
|
|
279
|
+
)
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
if (seenPairIds.has(pair.id)) {
|
|
283
|
+
return {
|
|
284
|
+
ok: false,
|
|
285
|
+
error: new HostAssemblyError(
|
|
286
|
+
"host-assembly-invalid",
|
|
287
|
+
"assembly pair ids to be unique",
|
|
288
|
+
"Give each paired package instance an independent stable id.",
|
|
289
|
+
{ reason: `duplicate pair ${pair.id}` }
|
|
290
|
+
)
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
seenPairIds.add(pair.id);
|
|
294
|
+
if (!assembly.entries.some((entry) => entry.id === pair.entryId)) {
|
|
295
|
+
return {
|
|
296
|
+
ok: false,
|
|
297
|
+
error: new HostAssemblyError(
|
|
298
|
+
"host-assembly-invalid",
|
|
299
|
+
`pair ${pair.id} to reference an assembly Entry`,
|
|
300
|
+
"Keep paired identity and frontend Entry projection under one backend authority.",
|
|
301
|
+
{ reason: `missing frontend Entry ${pair.entryId}` }
|
|
302
|
+
)
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
const module = assembly.modules.find(
|
|
306
|
+
(candidate) => candidate.name === pairModule.name && candidate.realm === pairModule.realm && candidate.version === pairModule.version && candidate.url === pairModule.url && candidate.digest === pairModule.digest
|
|
307
|
+
);
|
|
308
|
+
if (module === void 0) {
|
|
309
|
+
return {
|
|
310
|
+
ok: false,
|
|
311
|
+
error: new HostAssemblyError(
|
|
312
|
+
"host-assembly-invalid",
|
|
313
|
+
`pair ${pair.id} to reference a resolved frontend module`,
|
|
314
|
+
"Keep module/code identity in the backend-derived assembly projection.",
|
|
315
|
+
{ reason: `missing frontend module ${pairModule.name}` }
|
|
316
|
+
)
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
const expected = hostRevision({
|
|
321
|
+
schemaVersion: assembly.schemaVersion,
|
|
322
|
+
entries: assembly.entries,
|
|
323
|
+
modules: assembly.modules,
|
|
324
|
+
pairs: assembly.pairs,
|
|
325
|
+
...assembly.config === void 0 ? {} : { config: assembly.config }
|
|
326
|
+
});
|
|
327
|
+
if (expected !== assembly.revision) {
|
|
328
|
+
return {
|
|
329
|
+
ok: false,
|
|
330
|
+
error: new HostAssemblyError(
|
|
331
|
+
"host-assembly-revision-mismatch",
|
|
332
|
+
"assembly revision to match its entries and modules",
|
|
333
|
+
"Discard the stale response and request the current backend assembly again.",
|
|
334
|
+
{ actual: assembly.revision, expected }
|
|
335
|
+
)
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
return { ok: true, value: assembly };
|
|
339
|
+
}
|
|
340
|
+
function modulesFromCatalog(catalog, realm, version = "static") {
|
|
341
|
+
return [...catalog.entries()].filter(([, record]) => record.realm === realm).map(([name, record]) => ({
|
|
342
|
+
name,
|
|
343
|
+
realm,
|
|
344
|
+
version: record.version ?? version,
|
|
345
|
+
...record.digest === void 0 ? {} : { digest: record.digest }
|
|
346
|
+
}));
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export { HOST_ASSEMBLY_SCHEMA_VERSION, HostAssemblyError, assertHostModuleCatalogIdentity, canonicalHostJson, createHostAssembly, hostRevision, modulesFromCatalog, validateHostAssembly };
|
|
350
|
+
//# sourceMappingURL=protocol.mjs.map
|
|
351
|
+
//# sourceMappingURL=protocol.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/protocol.ts"],"names":[],"mappings":"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","file":"protocol.mjs","sourcesContent":["import type { EntryOptions } from '@deepseek-ai/cordis-plugin-loader';\nimport type {\n GamePluginEntry,\n PluginCatalog,\n PluginCatalogRecord,\n PluginRealm,\n} from '@forgeax/engine-plugin/loader';\n\ndeclare module '@forgeax/engine-plugin' {\n interface EngineContextServices {\n hostAssembly:\n | import('./backend.js').BackendAssemblyAuthority\n | import('./frontend.js').FrontendAssemblyState;\n hostTransport:\n | import('./transport.js').HostTransportServer\n | import('./transport.js').HostTransportClient;\n }\n}\n\n/** Wire version for the backend-derived browser assembly. */\nexport const HOST_ASSEMBLY_SCHEMA_VERSION = 1 as const;\n\nexport type HostAssemblySchemaVersion = typeof HOST_ASSEMBLY_SCHEMA_VERSION;\n\nexport interface HostModuleDescriptor {\n /** The exact module name used by a Cordis Entry. */\n readonly name: string;\n /** Physical ForgeaX realm expected by the CatalogLoader. */\n readonly realm: PluginRealm;\n /** Code identity. The backend and browser must agree on this value. */\n readonly version: string;\n /** Optional content identity for a static or generated catalog. */\n readonly digest?: string;\n /** URL used by a live browser host. Static builds omit it and use a Catalog. */\n readonly url?: string;\n}\n\n/** One package's explicitly paired backend/frontend Entry projections. */\nexport interface HostPluginPair {\n readonly id: string;\n readonly backend?: HostPluginEndpoint;\n readonly frontend?: HostPluginEndpoint;\n}\n\nexport interface HostPluginEndpoint {\n readonly entry: GamePluginEntry;\n readonly module: HostModuleDescriptor;\n}\n\n/** Safe identity projection; backend Entry configuration never crosses the wire. */\nexport interface HostAssemblyPair {\n readonly id: string;\n readonly entryId: string;\n readonly module: HostModuleDescriptor;\n}\n\n/**\n * A serializable projection of the entries that a frontend may activate.\n * `EntryOptions` is intentionally retained so nested Groups and repeated Entry\n * instances keep native Loader identity and reconciliation semantics.\n */\nexport interface HostAssembly {\n readonly schemaVersion: HostAssemblySchemaVersion;\n /** Digest of entries, modules and explicitly projected configuration. */\n readonly revision: string;\n readonly entries: readonly GamePluginEntry[];\n readonly modules: readonly HostModuleDescriptor[];\n readonly pairs: readonly HostAssemblyPair[];\n /** Safe, frontend-visible configuration only. */\n readonly config?: unknown;\n}\n\nexport interface HostAssemblyInput {\n /** Backend Entries are local authority and are never serialized. */\n readonly backendEntries?: readonly GamePluginEntry[];\n readonly entries?: readonly GamePluginEntry[];\n readonly modules?: readonly HostModuleDescriptor[];\n readonly pairs?: readonly HostPluginPair[];\n readonly config?: unknown;\n}\n\nexport interface HostActivationEntry {\n readonly entryId: string;\n readonly fiberState: string;\n readonly failure?: HostErrorSummary;\n}\n\nexport interface HostErrorSummary {\n readonly code: string;\n readonly expected: string;\n readonly hint: string;\n readonly detail: Readonly<Record<string, unknown>>;\n}\n\nexport interface HostActivationReport {\n readonly state: 'created' | 'loading' | 'active' | 'failed' | 'disposed';\n readonly revision: string;\n readonly entries?: readonly HostActivationEntry[];\n readonly error?: HostErrorSummary;\n}\n\nexport interface HostAssemblyErrorDetailByCode {\n 'host-assembly-invalid': { readonly reason: string };\n 'host-assembly-revision-mismatch': { readonly actual: string; readonly expected: string };\n 'host-assembly-module-missing': { readonly name: string };\n 'host-assembly-module-version-mismatch': {\n readonly name: string;\n readonly actual: string;\n readonly expected: string;\n };\n 'host-assembly-reload-required': {\n readonly module: string;\n readonly actual: string;\n readonly expected: string;\n };\n 'host-assembly-service-unavailable': { readonly service: string };\n 'host-assembly-stale-request': { readonly service: string; readonly generation: number };\n 'host-assembly-request-aborted': { readonly service: string };\n 'host-transport-failure': { readonly service: string; readonly reason: string };\n 'host-assembly-not-ready': {\n readonly entryId: string;\n readonly fiberState: string;\n readonly failure?: HostErrorSummary;\n };\n}\n\nexport type HostAssemblyErrorCode = keyof HostAssemblyErrorDetailByCode;\n\nexport class HostAssemblyError<\n C extends HostAssemblyErrorCode = HostAssemblyErrorCode,\n> extends Error {\n readonly code: C;\n readonly expected: string;\n readonly hint: string;\n readonly detail: HostAssemblyErrorDetailByCode[C];\n\n constructor(code: C, expected: string, hint: string, detail: HostAssemblyErrorDetailByCode[C]) {\n super(`${code}: ${expected}`);\n this.name = 'HostAssemblyError';\n this.code = code;\n this.expected = expected;\n this.hint = hint;\n this.detail = detail;\n }\n}\n\n/**\n * Prove that the code selected by a local Catalog is the code named by an\n * assembly descriptor. An optional digest is still checked whenever either\n * side supplies one; an unrelated digest must never stand in for a version.\n */\nexport function assertHostModuleCatalogIdentity(\n module: HostModuleDescriptor,\n record: PluginCatalogRecord,\n): void {\n if (record.version !== undefined && record.version !== module.version) {\n throw new HostAssemblyError(\n 'host-assembly-module-version-mismatch',\n `module ${module.name} to load catalog version ${module.version}`,\n 'Regenerate the static Catalog from the same backend package revision.',\n { name: module.name, actual: record.version, expected: module.version },\n );\n }\n if (\n record.digest !== undefined &&\n module.digest !== undefined &&\n record.digest !== module.digest\n ) {\n throw new HostAssemblyError(\n 'host-assembly-module-version-mismatch',\n `module ${module.name} to load catalog digest ${module.digest ?? 'none'}`,\n 'Regenerate the static Catalog from the same backend package bytes.',\n { name: module.name, actual: record.digest, expected: module.digest ?? 'none' },\n );\n }\n const versionMatches = record.version !== undefined && record.version === module.version;\n const digestMatches =\n module.digest !== undefined && record.digest !== undefined && record.digest === module.digest;\n const staticWithoutIdentity =\n module.version === 'static' &&\n module.digest === undefined &&\n record.version === undefined &&\n record.digest === undefined;\n if (!versionMatches && !digestMatches && !staticWithoutIdentity) {\n throw new HostAssemblyError(\n 'host-assembly-module-version-mismatch',\n `module ${module.name} to have a matching catalog code identity for ${module.version}`,\n 'Add the generated module version or digest to the static Catalog.',\n {\n name: module.name,\n actual: record.version ?? record.digest ?? 'unknown',\n expected: module.version,\n },\n );\n }\n}\n\nexport interface HostAssemblyResult {\n readonly ok: true;\n readonly value: HostAssembly;\n}\n\nexport interface HostAssemblyFailure {\n readonly ok: false;\n readonly error: HostAssemblyError;\n}\n\nexport type HostAssemblyValidation = HostAssemblyResult | HostAssemblyFailure;\n\n/** JSON-stable projection used for revision identity and diagnostics. */\nexport function canonicalHostJson(value: unknown): string {\n if (value === undefined) return 'undefined';\n if (value === null || typeof value !== 'object') return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(canonicalHostJson).join(',')}]`;\n return `{${Object.entries(value as Record<string, unknown>)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, item]) => `${JSON.stringify(key)}:${canonicalHostJson(item)}`)\n .join(',')}}`;\n}\n\n/** Small deterministic digest; it is an identity check, not a security hash. */\nexport function hostRevision(value: unknown): string {\n let hash = 2166136261;\n for (const char of canonicalHostJson(value)) {\n hash ^= char.codePointAt(0) ?? 0;\n hash = Math.imul(hash, 16777619);\n }\n return `fnv1a:${(hash >>> 0).toString(16).padStart(8, '0')}`;\n}\n\nfunction cloneEntry(entry: GamePluginEntry): GamePluginEntry {\n const config = entry.group\n ? (entry.config as readonly GamePluginEntry[] | undefined)?.map(cloneEntry)\n : entry.config;\n return {\n id: entry.id,\n name: entry.name,\n ...(config === undefined ? {} : { config }),\n ...(entry.group === undefined ? {} : { group: entry.group }),\n ...(entry.disabled === undefined ? {} : { disabled: entry.disabled }),\n ...(entry.inject === undefined ? {} : { inject: entry.inject }),\n ...(entry.realm === undefined ? {} : { realm: entry.realm }),\n };\n}\n\nfunction projectPairs(pairs: readonly HostPluginPair[]): {\n readonly entries: readonly GamePluginEntry[];\n readonly modules: readonly HostModuleDescriptor[];\n readonly projections: readonly HostAssemblyPair[];\n} {\n const entries: GamePluginEntry[] = [];\n const modules: HostModuleDescriptor[] = [];\n const projections: HostAssemblyPair[] = [];\n for (const pair of pairs) {\n if (\n pair.backend !== undefined &&\n pair.frontend !== undefined &&\n pair.backend.module.version !== pair.frontend.module.version\n ) {\n throw new HostAssemblyError(\n 'host-assembly-module-version-mismatch',\n `paired module ${pair.id} to use one code version on both hosts`,\n 'Resolve backend and frontend package entries from the same locked package revision.',\n {\n name: pair.id,\n actual: pair.backend.module.version,\n expected: pair.frontend.module.version,\n },\n );\n }\n if (pair.frontend === undefined) continue;\n entries.push(pair.frontend.entry);\n modules.push(pair.frontend.module);\n projections.push({\n id: pair.id,\n entryId: pair.frontend.entry.id,\n module: pair.frontend.module,\n });\n }\n return { entries, modules, projections };\n}\n\nfunction assemblyPairsFromInput(input: HostAssemblyInput): {\n readonly entries: readonly GamePluginEntry[];\n readonly modules: readonly HostModuleDescriptor[];\n readonly pairs: readonly HostAssemblyPair[];\n} {\n if (input.pairs !== undefined) {\n const projected = projectPairs(input.pairs);\n return {\n entries: input.entries ?? projected.entries,\n modules: input.modules ?? projected.modules,\n pairs: projected.projections,\n };\n }\n const entries = input.entries ?? [];\n const modules = [...(input.modules ?? [])];\n for (const [index, entry] of entries.entries()) {\n if (modules[index] !== undefined || modules.some((module) => module.name === entry.name))\n continue;\n modules.push({\n name: entry.name,\n realm: entry.realm ?? 'engine',\n version: 'unknown',\n });\n }\n return {\n entries,\n modules,\n pairs: entries.map((entry, index) => ({\n id: entry.id,\n entryId: entry.id,\n module:\n modules[index]?.name === entry.name\n ? modules[index]\n : (modules.find((module) => module.name === entry.name) ?? {\n name: entry.name,\n realm: entry.realm ?? 'engine',\n version: 'unknown',\n }),\n })),\n };\n}\n\n/** Build one disposable assembly projection from effective backend inputs. */\nexport function createHostAssembly(input: HostAssemblyInput): HostAssembly {\n const projected = assemblyPairsFromInput(input);\n const entries = projected.entries.map(cloneEntry);\n const modules = projected.modules.map((module) => ({ ...module }));\n const pairs = projected.pairs.map((pair) => ({ ...pair, module: { ...pair.module } }));\n const identity = {\n schemaVersion: HOST_ASSEMBLY_SCHEMA_VERSION,\n entries,\n modules,\n pairs,\n ...(input.config === undefined ? {} : { config: input.config }),\n };\n return {\n ...identity,\n revision: hostRevision(identity),\n };\n}\n\nfunction validateEntry(entry: EntryOptions, path: string): string | undefined {\n if (entry === null || typeof entry !== 'object') return `${path} must be an Entry object`;\n if (typeof entry.id !== 'string' || entry.id.length === 0) return `${path}.id must be non-empty`;\n if (typeof entry.name !== 'string' || entry.name.length === 0)\n return `${path}.name must be non-empty`;\n if (entry.group === true) {\n if (!Array.isArray(entry.config)) return `${path}.config must be an Entry array for a Group`;\n for (const [index, child] of entry.config.entries()) {\n const reason = validateEntry(child as EntryOptions, `${path}.config[${index}]`);\n if (reason !== undefined) return reason;\n }\n }\n return undefined;\n}\n\n/** Validate a received assembly before touching the native Loader. */\nexport function validateHostAssembly(assembly: HostAssembly): HostAssemblyValidation {\n if (assembly === null || typeof assembly !== 'object') {\n return {\n ok: false,\n error: new HostAssemblyError(\n 'host-assembly-invalid',\n 'assembly to be an object',\n 'Regenerate the frontend assembly from the active backend authority.',\n { reason: 'assembly is not an object' },\n ),\n };\n }\n if (assembly.schemaVersion !== HOST_ASSEMBLY_SCHEMA_VERSION) {\n return {\n ok: false,\n error: new HostAssemblyError(\n 'host-assembly-invalid',\n `assembly schema ${HOST_ASSEMBLY_SCHEMA_VERSION}`,\n 'Regenerate the frontend assembly with the matching Engine host package.',\n { reason: `unsupported schema ${String(assembly.schemaVersion)}` },\n ),\n };\n }\n if (!Array.isArray(assembly.entries) || !Array.isArray(assembly.modules)) {\n return {\n ok: false,\n error: new HostAssemblyError(\n 'host-assembly-invalid',\n 'assembly entries and modules to be arrays',\n 'Regenerate the frontend assembly from the active backend authority.',\n { reason: 'entries or modules is not an array' },\n ),\n };\n }\n if (!Array.isArray(assembly.pairs)) {\n return {\n ok: false,\n error: new HostAssemblyError(\n 'host-assembly-invalid',\n 'assembly pairs to be an array',\n 'Regenerate the assembly from the backend host using the matching host package.',\n { reason: 'pairs is not an array' },\n ),\n };\n }\n const seen = new Set<string>();\n for (const [index, entry] of assembly.entries.entries()) {\n const reason = validateEntry(entry, `entries[${index}]`);\n if (reason !== undefined) {\n return {\n ok: false,\n error: new HostAssemblyError(\n 'host-assembly-invalid',\n 'all assembly entries to be valid native EntryOptions',\n 'Repair the backend Entry projection before publishing it to a browser.',\n { reason },\n ),\n };\n }\n if (seen.has(entry.id)) {\n return {\n ok: false,\n error: new HostAssemblyError(\n 'host-assembly-invalid',\n 'assembly Entry ids to be unique',\n 'Give repeated plugin instances independent stable ids.',\n { reason: `duplicate Entry id ${entry.id}` },\n ),\n };\n }\n seen.add(entry.id);\n }\n const seenModules = new Map<string, HostModuleDescriptor>();\n for (const [index, module] of assembly.modules.entries()) {\n if (\n module === null ||\n typeof module !== 'object' ||\n typeof module.name !== 'string' ||\n typeof module.realm !== 'string' ||\n typeof module.version !== 'string' ||\n module.name.length === 0 ||\n module.version.length === 0 ||\n (module.url !== undefined && typeof module.url !== 'string') ||\n (module.digest !== undefined &&\n (typeof module.digest !== 'string' || module.digest.length === 0))\n ) {\n return {\n ok: false,\n error: new HostAssemblyError(\n 'host-assembly-invalid',\n 'module names and versions to be non-empty',\n 'Regenerate the module projection from the resolved package metadata.',\n { reason: `invalid module at index ${index}` },\n ),\n };\n }\n const previousModule = seenModules.get(module.name);\n if (\n previousModule !== undefined &&\n (previousModule.realm !== module.realm ||\n previousModule.version !== module.version ||\n previousModule.url !== module.url ||\n previousModule.digest !== module.digest)\n ) {\n return {\n ok: false,\n error: new HostAssemblyError(\n 'host-assembly-invalid',\n 'assembly module identity to be consistent for repeated Entries',\n 'Reuse one resolved module identity when a package has multiple Entry instances.',\n { reason: `module ${module.name} has conflicting identities` },\n ),\n };\n }\n seenModules.set(module.name, module);\n }\n const seenPairIds = new Set<string>();\n for (const [index, pair] of assembly.pairs.entries()) {\n const pairModule = pair?.module;\n if (\n pair === null ||\n typeof pair !== 'object' ||\n typeof pair.id !== 'string' ||\n pair.id.length === 0 ||\n typeof pair.entryId !== 'string' ||\n pair.entryId.length === 0 ||\n pairModule === null ||\n pairModule === undefined ||\n typeof pairModule !== 'object' ||\n typeof pairModule.name !== 'string' ||\n typeof pairModule.realm !== 'string' ||\n typeof pairModule.version !== 'string' ||\n pairModule.name.length === 0 ||\n pairModule.version.length === 0 ||\n (pairModule.url !== undefined && typeof pairModule.url !== 'string') ||\n (pairModule.digest !== undefined &&\n (typeof pairModule.digest !== 'string' || pairModule.digest.length === 0))\n ) {\n return {\n ok: false,\n error: new HostAssemblyError(\n 'host-assembly-invalid',\n 'assembly pair identities and modules to be valid',\n 'Regenerate paired frontend entries from the backend package manifest.',\n { reason: `invalid pair at index ${index}` },\n ),\n };\n }\n if (seenPairIds.has(pair.id)) {\n return {\n ok: false,\n error: new HostAssemblyError(\n 'host-assembly-invalid',\n 'assembly pair ids to be unique',\n 'Give each paired package instance an independent stable id.',\n { reason: `duplicate pair ${pair.id}` },\n ),\n };\n }\n seenPairIds.add(pair.id);\n if (!assembly.entries.some((entry) => entry.id === pair.entryId)) {\n return {\n ok: false,\n error: new HostAssemblyError(\n 'host-assembly-invalid',\n `pair ${pair.id} to reference an assembly Entry`,\n 'Keep paired identity and frontend Entry projection under one backend authority.',\n { reason: `missing frontend Entry ${pair.entryId}` },\n ),\n };\n }\n const module = assembly.modules.find(\n (candidate) =>\n candidate.name === pairModule.name &&\n candidate.realm === pairModule.realm &&\n candidate.version === pairModule.version &&\n candidate.url === pairModule.url &&\n candidate.digest === pairModule.digest,\n );\n if (module === undefined) {\n return {\n ok: false,\n error: new HostAssemblyError(\n 'host-assembly-invalid',\n `pair ${pair.id} to reference a resolved frontend module`,\n 'Keep module/code identity in the backend-derived assembly projection.',\n { reason: `missing frontend module ${pairModule.name}` },\n ),\n };\n }\n }\n const expected = hostRevision({\n schemaVersion: assembly.schemaVersion,\n entries: assembly.entries,\n modules: assembly.modules,\n pairs: assembly.pairs,\n ...(assembly.config === undefined ? {} : { config: assembly.config }),\n });\n if (expected !== assembly.revision) {\n return {\n ok: false,\n error: new HostAssemblyError(\n 'host-assembly-revision-mismatch',\n 'assembly revision to match its entries and modules',\n 'Discard the stale response and request the current backend assembly again.',\n { actual: assembly.revision, expected },\n ),\n };\n }\n return { ok: true, value: assembly };\n}\n\n/** Derive a static module descriptor set from an existing native Catalog. */\nexport function modulesFromCatalog(\n catalog: PluginCatalog,\n realm: PluginRealm,\n version = 'static',\n): HostModuleDescriptor[] {\n return [...catalog.entries()]\n .filter(([, record]) => record.realm === realm)\n .map(([name, record]) => ({\n name,\n realm,\n version: record.version ?? version,\n ...(record.digest === undefined ? {} : { digest: record.digest }),\n }));\n}\n"]}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { HostAssemblyError } from './protocol.js';
|
|
2
|
+
export declare const HOST_ASSEMBLY_SERVICE: "host/assembly.get";
|
|
3
|
+
export declare const HOST_ACTIVATION_REPORT_SERVICE: "host/assembly.report";
|
|
4
|
+
export declare const HOST_ASSEMBLY_CHANGED_TOPIC: "host/assembly.changed";
|
|
5
|
+
export interface HostRequestOptions {
|
|
6
|
+
readonly signal?: AbortSignal;
|
|
7
|
+
/** The service generation observed by the caller. */
|
|
8
|
+
readonly generation?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface HostServiceRequest<T = unknown> {
|
|
11
|
+
readonly service: string;
|
|
12
|
+
readonly payload: T;
|
|
13
|
+
readonly generation: number;
|
|
14
|
+
readonly signal: AbortSignal;
|
|
15
|
+
}
|
|
16
|
+
export type HostServiceHandler<TPayload = unknown, TResult = unknown> = (request: HostServiceRequest<TPayload>) => Promise<TResult> | TResult;
|
|
17
|
+
export interface HostServiceSnapshot {
|
|
18
|
+
readonly service: string;
|
|
19
|
+
readonly generation: number;
|
|
20
|
+
}
|
|
21
|
+
export interface HostTransportClient {
|
|
22
|
+
readonly connected: boolean;
|
|
23
|
+
readonly generation: number;
|
|
24
|
+
request<TPayload, TResult>(service: string, payload: TPayload, options?: HostRequestOptions): Promise<TResult>;
|
|
25
|
+
subscribe<T>(topic: string, listener: (payload: T) => void): () => void;
|
|
26
|
+
/** Observe a terminal connection loss without issuing another request. */
|
|
27
|
+
onDisconnect(listener: (error: HostAssemblyError) => void): () => void;
|
|
28
|
+
close(reason?: unknown): void;
|
|
29
|
+
}
|
|
30
|
+
export interface HostTransportServer {
|
|
31
|
+
readonly connectedClients: number;
|
|
32
|
+
register<TPayload, TResult>(service: string, handler: HostServiceHandler<TPayload, TResult>): () => void;
|
|
33
|
+
invalidate(service: string): void;
|
|
34
|
+
snapshot(service: string): HostServiceSnapshot | undefined;
|
|
35
|
+
publish<T>(topic: string, payload: T): void;
|
|
36
|
+
connect(): HostTransportClient;
|
|
37
|
+
close(reason?: unknown): void;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Create the small typed transport seam used by host plugins.
|
|
41
|
+
*
|
|
42
|
+
* This implementation is deliberately transport-neutral: the same request,
|
|
43
|
+
* subscription, cancellation, and generation semantics can be adapted to a
|
|
44
|
+
* WebSocket or MessagePort without moving business objects across the wire.
|
|
45
|
+
* It is also useful for deterministic host and lifecycle tests.
|
|
46
|
+
*/
|
|
47
|
+
export declare function createHostTransport(): HostTransportServer;
|
|
48
|
+
/** Minimal socket shape shared by browser WebSocket and Node `ws` instances. */
|
|
49
|
+
export interface HostSocketLike {
|
|
50
|
+
readonly readyState?: number;
|
|
51
|
+
send(data: string): void;
|
|
52
|
+
close(code?: number, reason?: string): void;
|
|
53
|
+
addEventListener?(type: string, listener: (...args: unknown[]) => void): void;
|
|
54
|
+
removeEventListener?(type: string, listener: (...args: unknown[]) => void): void;
|
|
55
|
+
on?(type: string, listener: (...args: unknown[]) => void): void;
|
|
56
|
+
off?(type: string, listener: (...args: unknown[]) => void): void;
|
|
57
|
+
}
|
|
58
|
+
/** Connect one browser WebSocket (or an already-open Node `ws`) to a host server. */
|
|
59
|
+
export declare function createHostWebSocketClient(socket: HostSocketLike): Promise<HostTransportClient>;
|
|
60
|
+
/** Open a browser-native WebSocket and install the typed host client. */
|
|
61
|
+
export declare function connectHostWebSocket(url: string): Promise<HostTransportClient>;
|
|
62
|
+
/** Attach one accepted process-side socket to an Engine host transport server. */
|
|
63
|
+
export declare function attachHostWebSocketServer(socket: HostSocketLike, server: HostTransportServer): () => void;
|
|
64
|
+
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
|