@microverse.ts/host-surface 0.2.0 → 0.3.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/README.md +45 -15
- package/dist/application/ports/ScriptReferenceResolverPort.d.ts +13 -0
- package/dist/application/ports/ScriptReferenceResolverPort.d.ts.map +1 -0
- package/dist/application/useCases/compileBridgeDeclarationsFromHostSurfaceSpec.d.ts +3 -3
- package/dist/application/useCases/compileBridgeDeclarationsFromHostSurfaceSpec.d.ts.map +1 -1
- package/dist/application/useCases/compileHostSurface.d.ts +4 -3
- package/dist/application/useCases/compileHostSurface.d.ts.map +1 -1
- package/dist/domain/componentSlotPrelude.d.ts +8 -0
- package/dist/domain/componentSlotPrelude.d.ts.map +1 -1
- package/dist/domain/componentTypeSpec.d.ts +12 -0
- package/dist/domain/componentTypeSpec.d.ts.map +1 -0
- package/dist/domain/hostSurfaceManifest.d.ts +3 -2
- package/dist/domain/hostSurfaceManifest.d.ts.map +1 -1
- package/dist/domain/hostSurfaceSpecTypes.d.ts +89 -0
- package/dist/domain/hostSurfaceSpecTypes.d.ts.map +1 -0
- package/dist/domain/hostSurfaceTypes.d.ts +11 -90
- package/dist/domain/hostSurfaceTypes.d.ts.map +1 -1
- package/dist/domain/safeObjectKey.d.ts +1 -1
- package/dist/domain/safeObjectKey.d.ts.map +1 -1
- package/dist/domain/scriptCatalogManifest.d.ts +14 -0
- package/dist/domain/scriptCatalogManifest.d.ts.map +1 -0
- package/dist/domain/scriptProfileSpec.d.ts +31 -0
- package/dist/domain/scriptProfileSpec.d.ts.map +1 -0
- package/dist/domain/surfaceCapabilities.d.ts +1 -1
- package/dist/domain/surfaceCapabilities.d.ts.map +1 -1
- package/dist/domain/surfaceMethodDef.d.ts +1 -1
- package/dist/domain/surfaceMethodDef.d.ts.map +1 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +616 -296
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/builders/bridgeMergeEnv.d.ts +5 -10
- package/dist/infrastructure/builders/bridgeMergeEnv.d.ts.map +1 -1
- package/dist/infrastructure/builders/filterBridgeDeclarations.d.ts +11 -0
- package/dist/infrastructure/builders/filterBridgeDeclarations.d.ts.map +1 -0
- package/dist/infrastructure/builders/surfaceBuilder.d.ts +7 -2
- package/dist/infrastructure/builders/surfaceBuilder.d.ts.map +1 -1
- package/dist/infrastructure/components/hostScriptSession.d.ts +20 -5
- package/dist/infrastructure/components/hostScriptSession.d.ts.map +1 -1
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -1,22 +1,404 @@
|
|
|
1
1
|
import { buildDeclarativeBridgeTable } from "@microverse.ts/runtime-bridge";
|
|
2
|
-
import { validateWithZodSchema } from "@microverse.ts/runtime-zod";
|
|
3
|
-
import { z } from "zod";
|
|
4
2
|
import { applyScriptPropertyChanges, assertValidScriptPropertyBag, cloneScriptPropertyBag, createMicroverseScript, createScriptInstanceContext, diffScriptProperties } from "@microverse.ts/runtime-core";
|
|
5
|
-
import {
|
|
3
|
+
import { createCapabilityId } from "@microverse.ts/runtime-capabilities";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { validateWithZodSchema } from "@microverse.ts/runtime-zod";
|
|
6
|
+
//#region src/domain/scriptContextSymbol.ts
|
|
7
|
+
var MICROVERSE_SCRIPT_CONTEXT = Symbol("microverse.scriptContext");
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region src/application/useCases/compileBridgeDeclarationsFromHostSurfaceSpec.ts
|
|
10
|
+
function isThenable(value) {
|
|
11
|
+
if (value === null || value === void 0) return false;
|
|
12
|
+
if (typeof value !== "object" && typeof value !== "function") return false;
|
|
13
|
+
return typeof value.then === "function";
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Builds declarative bridge declarations from a host surface spec, using the schema validation port for Lua ↔ host payloads.
|
|
17
|
+
*/
|
|
18
|
+
function createBridgeDeclarationsFromHostSurfaceSpec(schemaValidation, spec) {
|
|
19
|
+
const out = [];
|
|
20
|
+
for (const bridgeName of Object.keys(spec)) {
|
|
21
|
+
const methods = spec[bridgeName];
|
|
22
|
+
out.push({
|
|
23
|
+
name: bridgeName,
|
|
24
|
+
perEntity: true,
|
|
25
|
+
createApi: (host, slotKey) => {
|
|
26
|
+
const api = {};
|
|
27
|
+
for (const methodName of Object.keys(methods)) {
|
|
28
|
+
const entry = methods[methodName];
|
|
29
|
+
api[methodName] = (...args) => {
|
|
30
|
+
const payload = args.length >= 2 ? args[1] : args[0];
|
|
31
|
+
const parsedIn = schemaValidation.validateWithZodSchema(entry.input, payload);
|
|
32
|
+
if (parsedIn._tag === "err") throw new Error(parsedIn.error);
|
|
33
|
+
const script = host[MICROVERSE_SCRIPT_CONTEXT] ?? createScriptInstanceContext({
|
|
34
|
+
instanceId: String(slotKey),
|
|
35
|
+
scriptId: "unknown",
|
|
36
|
+
slotKey: String(slotKey)
|
|
37
|
+
});
|
|
38
|
+
const raw = entry.handler({
|
|
39
|
+
host,
|
|
40
|
+
slotKey: String(slotKey),
|
|
41
|
+
script
|
|
42
|
+
}, parsedIn.value);
|
|
43
|
+
if (isThenable(raw)) return raw.then((resolved) => {
|
|
44
|
+
const parsedOut = schemaValidation.validateWithZodSchema(entry.output, resolved);
|
|
45
|
+
if (parsedOut._tag === "err") throw new Error(parsedOut.error);
|
|
46
|
+
return parsedOut.value;
|
|
47
|
+
});
|
|
48
|
+
const parsedOut = schemaValidation.validateWithZodSchema(entry.output, raw);
|
|
49
|
+
if (parsedOut._tag === "err") throw new Error(parsedOut.error);
|
|
50
|
+
return parsedOut.value;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return Object.freeze(api);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/infrastructure/builders/filterBridgeDeclarations.ts
|
|
61
|
+
/**
|
|
62
|
+
* Keeps bridge declarations (and methods) whose capability is in the allow set.
|
|
63
|
+
*/
|
|
64
|
+
function filterBridgeDeclarationsByCapabilities(declarations, spec, capabilities) {
|
|
65
|
+
const allowed = new Set(capabilities.map((c) => String(c)));
|
|
66
|
+
const bridgeNames = /* @__PURE__ */ new Set();
|
|
67
|
+
for (const bridgeName of Object.keys(spec)) {
|
|
68
|
+
const methods = spec[bridgeName];
|
|
69
|
+
for (const methodName of Object.keys(methods)) {
|
|
70
|
+
const entry = methods[methodName];
|
|
71
|
+
if (allowed.has(String(entry.capability))) {
|
|
72
|
+
bridgeNames.add(bridgeName);
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return declarations.filter((d) => bridgeNames.has(d.name)).map((d) => ({
|
|
78
|
+
...d,
|
|
79
|
+
createApi: (host, slotKey) => {
|
|
80
|
+
const api = d.createApi(host, slotKey);
|
|
81
|
+
const methods = spec[d.name];
|
|
82
|
+
const filtered = {};
|
|
83
|
+
for (const methodName of Object.keys(api)) {
|
|
84
|
+
const entry = methods[methodName];
|
|
85
|
+
if (entry !== void 0 && allowed.has(String(entry.capability))) filtered[methodName] = api[methodName];
|
|
86
|
+
}
|
|
87
|
+
return Object.freeze(filtered);
|
|
88
|
+
}
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
function createFilteredBridgeDeclarations(schemaValidation, spec, capabilities) {
|
|
92
|
+
return filterBridgeDeclarationsByCapabilities(createBridgeDeclarationsFromHostSurfaceSpec(schemaValidation, spec), spec, capabilities);
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
6
95
|
//#region src/infrastructure/builders/bridgeMergeEnv.ts
|
|
7
96
|
/**
|
|
8
|
-
* Builds a frozen
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
97
|
+
* Builds a frozen bridge table for a component profile capability set.
|
|
98
|
+
*/
|
|
99
|
+
function buildBridgeMergeEnvForProfile(schemaValidation, host, slotKey, spec, capabilities) {
|
|
100
|
+
return buildDeclarativeBridgeTable(host, slotKey, [...createFilteredBridgeDeclarations(schemaValidation, spec, capabilities)]);
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/domain/safeObjectKey.ts
|
|
104
|
+
/** Keys that must not be used as dynamic property names on ordinary objects. */
|
|
105
|
+
var FORBIDDEN_OBJECT_KEYS = new Set([
|
|
106
|
+
"__proto__",
|
|
107
|
+
"constructor",
|
|
108
|
+
"prototype"
|
|
109
|
+
]);
|
|
110
|
+
/**
|
|
111
|
+
* Rejects bridge/method names that could trigger prototype pollution when used as object keys.
|
|
13
112
|
*/
|
|
14
|
-
function
|
|
15
|
-
|
|
113
|
+
function assertSafeObjectKey(kind, name) {
|
|
114
|
+
if (FORBIDDEN_OBJECT_KEYS.has(name)) throw new Error(`Invalid surface ${kind} name "${name}": reserved key`);
|
|
115
|
+
}
|
|
116
|
+
/** Record with no inherited prototype — safe for dynamic string keys at runtime. */
|
|
117
|
+
function createNullPrototypeRecord() {
|
|
118
|
+
return Object.create(null);
|
|
119
|
+
}
|
|
120
|
+
//#endregion
|
|
121
|
+
//#region src/domain/surfaceCapabilities.ts
|
|
122
|
+
/** Runtime list of capability ids declared on a compiled surface spec. */
|
|
123
|
+
function collectCapabilitiesFromHostSurfaceSpec(spec) {
|
|
124
|
+
const out = [];
|
|
125
|
+
const seen = /* @__PURE__ */ new Set();
|
|
126
|
+
for (const bridgeName of Object.keys(spec)) {
|
|
127
|
+
const methods = spec[bridgeName];
|
|
128
|
+
for (const methodName of Object.keys(methods)) {
|
|
129
|
+
const id = methods[methodName].capability;
|
|
130
|
+
const key = String(id);
|
|
131
|
+
if (!seen.has(key)) {
|
|
132
|
+
seen.add(key);
|
|
133
|
+
out.push(id);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return out;
|
|
138
|
+
}
|
|
139
|
+
/** Narrows `capabilities` to those declared on the surface (runtime check). */
|
|
140
|
+
function pickSurfaceCapabilities(surfaceCapabilities, ...capabilities) {
|
|
141
|
+
const allowed = new Set(surfaceCapabilities.map((c) => String(c)));
|
|
142
|
+
for (const id of capabilities) if (!allowed.has(String(id))) throw new Error(`capability not declared on host surface: ${String(id)} (surface has: ${[...allowed].join(", ")})`);
|
|
143
|
+
return capabilities;
|
|
144
|
+
}
|
|
145
|
+
z.object({});
|
|
146
|
+
var EMPTY_STATE = z.object({});
|
|
147
|
+
function scriptProfileComponentClassName(profileName) {
|
|
148
|
+
return `${profileName}Component`;
|
|
149
|
+
}
|
|
150
|
+
function scriptProfilePropsAlias(profileName) {
|
|
151
|
+
return `${profileName}Props`;
|
|
152
|
+
}
|
|
153
|
+
function scriptProfileStateAlias(profileName) {
|
|
154
|
+
return `${profileName}State`;
|
|
155
|
+
}
|
|
156
|
+
function scriptProfileBridgesClassName(profileName) {
|
|
157
|
+
return `${profileName}Bridges`;
|
|
158
|
+
}
|
|
159
|
+
/** Bridge table names whose methods include at least one capability from the profile. */
|
|
160
|
+
function bridgeNamesForCapabilities(spec, capabilities) {
|
|
161
|
+
const allowed = new Set(capabilities.map((c) => String(c)));
|
|
162
|
+
const names = [];
|
|
163
|
+
for (const bridgeName of Object.keys(spec)) {
|
|
164
|
+
const methods = spec[bridgeName];
|
|
165
|
+
for (const methodName of Object.keys(methods)) {
|
|
166
|
+
const entry = methods[methodName];
|
|
167
|
+
if (allowed.has(String(entry.capability))) {
|
|
168
|
+
names.push(bridgeName);
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return names.sort((a, b) => a.localeCompare(b));
|
|
174
|
+
}
|
|
175
|
+
function resolveScriptProfile(registry, name, spec) {
|
|
176
|
+
const def = registry[name];
|
|
177
|
+
if (def === void 0) throw new Error(`unknown script profile: ${name}`);
|
|
178
|
+
const capabilities = def.capabilities.map((c) => createCapabilityId(c));
|
|
179
|
+
let props = def.props;
|
|
180
|
+
let state = def.state ?? EMPTY_STATE;
|
|
181
|
+
const hooks = [...def.hooks ?? []];
|
|
182
|
+
let parentName = def.extends;
|
|
183
|
+
const visited = new Set([name]);
|
|
184
|
+
while (parentName !== void 0) {
|
|
185
|
+
if (visited.has(parentName)) throw new Error(`script profile inheritance cycle: ${name}`);
|
|
186
|
+
visited.add(parentName);
|
|
187
|
+
const parent = registry[parentName];
|
|
188
|
+
if (parent === void 0) throw new Error(`script profile "${name}" extends unknown profile "${parentName}"`);
|
|
189
|
+
const parentCaps = parent.capabilities.map((c) => createCapabilityId(c));
|
|
190
|
+
for (const cap of parentCaps) if (!capabilities.some((c) => String(c) === String(cap))) capabilities.push(cap);
|
|
191
|
+
props = parent.props.merge(props);
|
|
192
|
+
state = (parent.state ?? EMPTY_STATE).merge(state);
|
|
193
|
+
const parentHooks = parent.hooks ?? [];
|
|
194
|
+
for (const h of parentHooks) if (!hooks.includes(h)) hooks.push(h);
|
|
195
|
+
parentName = parent.extends;
|
|
196
|
+
}
|
|
197
|
+
hooks.sort((a, b) => a.localeCompare(b));
|
|
198
|
+
const bridgeNames = bridgeNamesForCapabilities(spec, capabilities);
|
|
199
|
+
return {
|
|
200
|
+
name,
|
|
201
|
+
extends: def.extends,
|
|
202
|
+
capabilities,
|
|
203
|
+
props,
|
|
204
|
+
state,
|
|
205
|
+
hooks,
|
|
206
|
+
bridgeNames,
|
|
207
|
+
references: def.references
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function buildResolvedScriptProfileRegistry(registry, spec) {
|
|
211
|
+
const out = {};
|
|
212
|
+
for (const name of Object.keys(registry)) out[name] = resolveScriptProfile(registry, name, spec);
|
|
213
|
+
return out;
|
|
214
|
+
}
|
|
215
|
+
function validateScriptProfileRegistry(registry, spec, componentHooks, opts) {
|
|
216
|
+
if ((opts?.requireAtLeastOne ?? false) && Object.keys(registry).length === 0) throw new Error("host surface: at least one script profile or .componentType() is required");
|
|
217
|
+
const surfaceCaps = new Set(collectCapabilitiesFromHostSurfaceSpec(spec).map((c) => String(c)));
|
|
218
|
+
const hookKinds = componentHooks !== void 0 ? new Set(Object.keys(componentHooks)) : /* @__PURE__ */ new Set();
|
|
219
|
+
for (const name of Object.keys(registry)) {
|
|
220
|
+
assertSafeObjectKey("componentType", name);
|
|
221
|
+
const def = registry[name];
|
|
222
|
+
if (def.extends !== void 0) assertSafeObjectKey("componentType", def.extends);
|
|
223
|
+
for (const cap of def.capabilities) {
|
|
224
|
+
const id = createCapabilityId(cap);
|
|
225
|
+
if (!surfaceCaps.has(String(id))) throw new Error(`script profile "${name}": capability not declared on surface: ${String(cap)}`);
|
|
226
|
+
}
|
|
227
|
+
for (const hook of def.hooks ?? []) if (!hookKinds.has(hook)) throw new Error(`script profile "${name}": hook "${hook}" not declared in .componentHooks()`);
|
|
228
|
+
if (def.extends !== void 0 && registry[def.extends] === void 0) throw new Error(`script profile "${name}" extends unknown profile "${def.extends}"`);
|
|
229
|
+
}
|
|
230
|
+
for (const name of Object.keys(registry)) resolveScriptProfile(registry, name, spec);
|
|
231
|
+
}
|
|
232
|
+
//#endregion
|
|
233
|
+
//#region src/domain/scriptCatalogManifest.ts
|
|
234
|
+
/** LuaCATS aliases per catalog scriptId → resolved component class (for `---@type` in `.lua` files). */
|
|
235
|
+
function buildScriptCatalogLuaDefManifest(entries) {
|
|
236
|
+
return {
|
|
237
|
+
schemaVersion: 1,
|
|
238
|
+
output: "generated/scriptCatalog.d.lua",
|
|
239
|
+
classes: [],
|
|
240
|
+
aliases: entries.filter((entry) => entry.localComponentClass !== true).slice().sort((a, b) => a.scriptId.localeCompare(b.scriptId)).map((entry) => {
|
|
241
|
+
const componentClass = scriptProfileComponentClassName(entry.profileId);
|
|
242
|
+
return {
|
|
243
|
+
name: scriptCatalogComponentAlias(entry.scriptId),
|
|
244
|
+
definition: componentClass
|
|
245
|
+
};
|
|
246
|
+
}),
|
|
247
|
+
globals: [],
|
|
248
|
+
luaHooks: []
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
function scriptCatalogComponentAlias(scriptId) {
|
|
252
|
+
return `${scriptId.replace(/[^A-Za-z0-9_]/g, "_")}ScriptComponent`;
|
|
253
|
+
}
|
|
254
|
+
//#endregion
|
|
255
|
+
//#region src/domain/componentSlotPrelude.ts
|
|
256
|
+
/** @see MICROVERSE_LUA_COMPONENT_SLOT_PRELUDE */
|
|
257
|
+
var MICROVERSE_LUA_COMPONENT_SLOT_PRELUDE = `
|
|
258
|
+
rawset(_ENV, "__microverse_component_rawProps", {})
|
|
259
|
+
rawset(_ENV, "__microverse_component_dirty", {})
|
|
260
|
+
|
|
261
|
+
local function rawProps()
|
|
262
|
+
return rawget(_ENV, "__microverse_component_rawProps")
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
local function dirty()
|
|
266
|
+
return rawget(_ENV, "__microverse_component_dirty")
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
local PropertiesMT = {
|
|
270
|
+
__index = function(t, k)
|
|
271
|
+
return rawget(t, "__raw")[k]
|
|
272
|
+
end,
|
|
273
|
+
__newindex = function(t, k, v)
|
|
274
|
+
rawget(t, "__raw")[k] = v
|
|
275
|
+
local d = dirty()
|
|
276
|
+
d[k] = v
|
|
277
|
+
end,
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
local ReferencesMT = {
|
|
281
|
+
__index = function(t, k)
|
|
282
|
+
local wrap = rawget(_ENV, "__microverse_reference_wrap")
|
|
283
|
+
local raw = rawget(t, "__raw")
|
|
284
|
+
local val = raw[k]
|
|
285
|
+
if type(wrap) == "function" then
|
|
286
|
+
return wrap(k, val)
|
|
287
|
+
end
|
|
288
|
+
return val
|
|
289
|
+
end,
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function __microverse_lua_build_component_impl(bridges)
|
|
293
|
+
local impl = { state = {}, bridges = type(bridges) == "table" and bridges or {} }
|
|
294
|
+
local proxy = { __raw = rawProps() }
|
|
295
|
+
setmetatable(proxy, PropertiesMT)
|
|
296
|
+
impl.properties = proxy
|
|
297
|
+
local refProxy = { __raw = rawProps() }
|
|
298
|
+
setmetatable(refProxy, ReferencesMT)
|
|
299
|
+
impl.references = refProxy
|
|
300
|
+
local base = rawget(_ENV, "__microverse_component_hook_base")
|
|
301
|
+
if type(base) == "table" then
|
|
302
|
+
setmetatable(impl, { __index = base })
|
|
303
|
+
end
|
|
304
|
+
rawset(_ENV, "__microverse_lua_ComponentImpl", impl)
|
|
305
|
+
return impl
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
rawset(_ENV, "__microverse_lua_build_component_impl", __microverse_lua_build_component_impl)
|
|
309
|
+
|
|
310
|
+
rawset(_ENV, "__microverse_lua_component_apply_incoming", function()
|
|
311
|
+
local incoming = rawget(_ENV, "__microverseIncomingProps")
|
|
312
|
+
if type(incoming) ~= "table" then
|
|
313
|
+
return
|
|
314
|
+
end
|
|
315
|
+
local rp = rawProps()
|
|
316
|
+
local impl = rawget(_ENV, "__microverse_lua_ComponentImpl")
|
|
317
|
+
if type(impl) ~= "table" or type(impl.properties) ~= "table" then
|
|
318
|
+
for k, v in pairs(incoming) do
|
|
319
|
+
rp[k] = v
|
|
320
|
+
end
|
|
321
|
+
return
|
|
322
|
+
end
|
|
323
|
+
for k, v in pairs(incoming) do
|
|
324
|
+
impl.properties[k] = v
|
|
325
|
+
end
|
|
326
|
+
end)
|
|
327
|
+
|
|
328
|
+
rawset(_ENV, "__microverse_lua_component_flush_to_sink", function()
|
|
329
|
+
local push = rawget(_ENV, "__microverseFlushPush")
|
|
330
|
+
local d = dirty()
|
|
331
|
+
for k, v in pairs(d) do
|
|
332
|
+
if type(push) == "function" then
|
|
333
|
+
push(k, v)
|
|
334
|
+
end
|
|
335
|
+
d[k] = nil
|
|
336
|
+
end
|
|
337
|
+
end)
|
|
338
|
+
`.trim();
|
|
339
|
+
/** Lua prelude that registers `TypeName:extend()` singletons for each component type. */
|
|
340
|
+
function profileBridgeSlotKey(typeName, bridgeName) {
|
|
341
|
+
return `__mv_${typeName}_${bridgeName}`;
|
|
16
342
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
343
|
+
function profileBridgeNamesMergeEnvKey(typeName) {
|
|
344
|
+
return `__microverse_profile_bridge_names_${typeName}`;
|
|
345
|
+
}
|
|
346
|
+
function buildComponentTypeBridgeNamesPreludeLua(componentTypes) {
|
|
347
|
+
const lines = [];
|
|
348
|
+
for (const typeName of Object.keys(componentTypes).sort((a, b) => a.localeCompare(b))) {
|
|
349
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(typeName)) throw new Error(`unsafe component type name for bridge names prelude: ${typeName}`);
|
|
350
|
+
const entries = componentTypes[typeName].bridgeNames.map((n) => JSON.stringify(n)).join(", ");
|
|
351
|
+
lines.push(`rawset(_ENV, ${JSON.stringify(profileBridgeNamesMergeEnvKey(typeName))}, { ${entries} })`);
|
|
352
|
+
}
|
|
353
|
+
return lines.join("\n");
|
|
354
|
+
}
|
|
355
|
+
function buildComponentTypeSingletonsPreludeLua(typeNames) {
|
|
356
|
+
const lines = [
|
|
357
|
+
"local function __microverse_collect_profile_bridges(typeName)",
|
|
358
|
+
" local names = rawget(_ENV, \"__microverse_profile_bridge_names_\" .. typeName)",
|
|
359
|
+
" local bridges = {}",
|
|
360
|
+
" if type(names) ~= \"table\" then",
|
|
361
|
+
" return bridges",
|
|
362
|
+
" end",
|
|
363
|
+
" for _, name in ipairs(names) do",
|
|
364
|
+
" if type(name) == \"string\" then",
|
|
365
|
+
" local b = rawget(_ENV, \"__mv_\" .. typeName .. \"_\" .. name)",
|
|
366
|
+
" if type(b) == \"table\" then",
|
|
367
|
+
" bridges[name] = b",
|
|
368
|
+
" end",
|
|
369
|
+
" end",
|
|
370
|
+
" end",
|
|
371
|
+
" return bridges",
|
|
372
|
+
"end",
|
|
373
|
+
"local function __microverse_make_type_extend(typeName)",
|
|
374
|
+
" return function(self)",
|
|
375
|
+
" local ext = rawget(_ENV, \"__microverse_lua_extend_component\")",
|
|
376
|
+
" if type(ext) == \"function\" then",
|
|
377
|
+
" ext(typeName)",
|
|
378
|
+
" end",
|
|
379
|
+
" local build = rawget(_ENV, \"__microverse_lua_build_component_impl\")",
|
|
380
|
+
" if type(build) ~= \"function\" then",
|
|
381
|
+
" error(\"component type extend: build impl missing\")",
|
|
382
|
+
" end",
|
|
383
|
+
" return build(__microverse_collect_profile_bridges(typeName))",
|
|
384
|
+
" end",
|
|
385
|
+
"end"
|
|
386
|
+
];
|
|
387
|
+
for (const name of typeNames) {
|
|
388
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) throw new Error(`unsafe component type name for Lua singleton: ${name}`);
|
|
389
|
+
lines.push(`rawset(_ENV, ${JSON.stringify(name)}, { extend = __microverse_make_type_extend(${JSON.stringify(name)}) })`);
|
|
390
|
+
}
|
|
391
|
+
return lines.join("\n");
|
|
392
|
+
}
|
|
393
|
+
/** Applies host-selected profile (same as `Type:extend()` without requiring Lua to call it). */
|
|
394
|
+
function buildApplyHostScriptProfileChunkLua(profileName) {
|
|
395
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(profileName)) throw new Error(`unsafe script profile name: ${profileName}`);
|
|
396
|
+
return [
|
|
397
|
+
`local T = ${profileName}`,
|
|
398
|
+
"if type(T) == \"table\" and type(T.extend) == \"function\" then",
|
|
399
|
+
" T:extend()",
|
|
400
|
+
"end"
|
|
401
|
+
].join("\n");
|
|
20
402
|
}
|
|
21
403
|
//#endregion
|
|
22
404
|
//#region src/infrastructure/adapters/zodSchemaValidationAdapter.ts
|
|
@@ -167,19 +549,7 @@ function asyncHandleClassName(bridgeName, methodName) {
|
|
|
167
549
|
function bridgeLuaClassName(bridgeTableName) {
|
|
168
550
|
return bridgeTableName.charAt(0).toUpperCase() + bridgeTableName.slice(1);
|
|
169
551
|
}
|
|
170
|
-
function
|
|
171
|
-
if (bridgeNames.length === 0) return;
|
|
172
|
-
classes.push({
|
|
173
|
-
name: "MicroverseBridges",
|
|
174
|
-
description: "Capability-scoped host bridges for this component (`self.bridges` after `component:extend()`).",
|
|
175
|
-
fields: bridgeNames.map((name) => ({
|
|
176
|
-
name,
|
|
177
|
-
luaType: bridgeLuaClassName(name)
|
|
178
|
-
})),
|
|
179
|
-
emitSingleton: false
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
function buildComponentEventManifestFields(kinds, componentHooks) {
|
|
552
|
+
function buildComponentEventManifestFields(kinds, componentClassName, componentHooks) {
|
|
183
553
|
const out = [];
|
|
184
554
|
for (const kind of kinds) {
|
|
185
555
|
if (!(componentHooks[kind] instanceof z.ZodObject)) throw new Error(`defineHostSurface componentHooks: "${kind}" must be a z.object(...)`);
|
|
@@ -188,7 +558,7 @@ function buildComponentEventManifestFields(kinds, componentHooks) {
|
|
|
188
558
|
out.push({
|
|
189
559
|
name: hookName,
|
|
190
560
|
description: `Host invokes when \`${kind}\` is emitted. Payload: \`${payloadName}\`.`,
|
|
191
|
-
luaType: `fun(self:
|
|
561
|
+
luaType: `fun(self: ${componentClassName}, evt: ${payloadName})`
|
|
192
562
|
});
|
|
193
563
|
}
|
|
194
564
|
return out;
|
|
@@ -210,60 +580,112 @@ function pushComponentEventPayloadClasses(kinds, componentHooks, classes) {
|
|
|
210
580
|
});
|
|
211
581
|
}
|
|
212
582
|
}
|
|
213
|
-
function
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
583
|
+
function pushBaseComponentClass(classes) {
|
|
584
|
+
classes.push({
|
|
585
|
+
name: "Component",
|
|
586
|
+
description: "Base component lifecycle (extended by typed component profiles).",
|
|
587
|
+
fields: [
|
|
588
|
+
{
|
|
589
|
+
name: "init",
|
|
590
|
+
luaType: "fun(self: Component)",
|
|
591
|
+
description: "Called once after mount and initial props are applied."
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
name: "onPropsChanged",
|
|
595
|
+
luaType: "fun(self: Component, key: string, newValue: any)",
|
|
596
|
+
description: "Called when the host patches a property key."
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
name: "onDestroy",
|
|
600
|
+
luaType: "fun(self: Component)",
|
|
601
|
+
description: "Called before the script instance slot is disposed."
|
|
602
|
+
}
|
|
603
|
+
],
|
|
604
|
+
emitSingleton: false
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
function pushProfileBridgesClass(typeName, bridgeNames, classes) {
|
|
608
|
+
if (bridgeNames.length === 0) return;
|
|
609
|
+
const bridgesName = scriptProfileBridgesClassName(typeName);
|
|
610
|
+
classes.push({
|
|
611
|
+
name: bridgesName,
|
|
612
|
+
description: `Host bridges for \`${typeName}\` components (\`self.bridges\` after \`${typeName}:extend()\`).`,
|
|
613
|
+
fields: bridgeNames.map((name) => ({
|
|
614
|
+
name,
|
|
615
|
+
luaType: bridgeLuaClassName(name)
|
|
616
|
+
})),
|
|
617
|
+
emitSingleton: false
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
function pushComponentTypeManifest(classes, aliases, typeName, profile, componentHooks) {
|
|
621
|
+
const propsAlias = scriptProfilePropsAlias(typeName);
|
|
622
|
+
const stateAlias = scriptProfileStateAlias(typeName);
|
|
623
|
+
aliases.set(propsAlias, zodToLuaTypeRef(profile.props));
|
|
624
|
+
aliases.set(stateAlias, zodToLuaTypeRef(profile.state));
|
|
625
|
+
pushProfileBridgesClass(typeName, profile.bridgeNames, classes);
|
|
626
|
+
const componentClass = scriptProfileComponentClassName(typeName);
|
|
627
|
+
const bridgesClass = profile.bridgeNames.length > 0 ? scriptProfileBridgesClassName(typeName) : "table";
|
|
628
|
+
const extendsClass = profile.extends !== void 0 ? scriptProfileComponentClassName(profile.extends) : "Component";
|
|
629
|
+
const fields = [
|
|
217
630
|
{
|
|
218
631
|
name: "properties",
|
|
219
|
-
luaType:
|
|
632
|
+
luaType: propsAlias,
|
|
220
633
|
description: "Host-synced props (proxy)."
|
|
221
634
|
},
|
|
222
635
|
{
|
|
223
636
|
name: "state",
|
|
224
|
-
luaType:
|
|
637
|
+
luaType: stateAlias,
|
|
225
638
|
description: "Lua-local state."
|
|
226
639
|
},
|
|
227
640
|
{
|
|
228
641
|
name: "bridges",
|
|
229
|
-
luaType:
|
|
230
|
-
description: "Host bridges allowed for this
|
|
642
|
+
luaType: bridgesClass,
|
|
643
|
+
description: "Host bridges allowed for this component type."
|
|
231
644
|
},
|
|
232
645
|
{
|
|
233
646
|
name: "init",
|
|
234
|
-
luaType:
|
|
647
|
+
luaType: `fun(self: ${componentClass})`,
|
|
235
648
|
description: "Called once after mount and initial props are applied."
|
|
236
649
|
},
|
|
237
650
|
{
|
|
238
651
|
name: "onPropsChanged",
|
|
239
|
-
luaType:
|
|
652
|
+
luaType: `fun(self: ${componentClass}, key: string, newValue: any)`,
|
|
240
653
|
description: "Called when the host patches a property key."
|
|
241
654
|
},
|
|
242
655
|
{
|
|
243
656
|
name: "onDestroy",
|
|
244
|
-
luaType:
|
|
657
|
+
luaType: `fun(self: ${componentClass})`,
|
|
245
658
|
description: "Called before the script instance slot is disposed."
|
|
246
659
|
}
|
|
247
660
|
];
|
|
248
|
-
if (componentHooks !== void 0)
|
|
661
|
+
if (componentHooks !== void 0 && profile.hooks.length > 0) fields.push(...buildComponentEventManifestFields(profile.hooks, componentClass, componentHooks));
|
|
249
662
|
classes.push({
|
|
250
|
-
name:
|
|
251
|
-
|
|
252
|
-
|
|
663
|
+
name: componentClass,
|
|
664
|
+
extendsClass,
|
|
665
|
+
description: `Component instance from \`local C = ${typeName}:extend()\`.`,
|
|
666
|
+
fields,
|
|
253
667
|
emitSingleton: false
|
|
254
668
|
});
|
|
255
669
|
classes.push({
|
|
256
|
-
name:
|
|
257
|
-
description:
|
|
670
|
+
name: typeName,
|
|
671
|
+
description: `Factory for \`${componentClass}\` in this slot.`,
|
|
258
672
|
methods: [{
|
|
259
673
|
name: "extend",
|
|
260
|
-
description: "
|
|
674
|
+
description: "Creates the active component with profile-scoped bridges.",
|
|
261
675
|
params: [],
|
|
262
|
-
returns:
|
|
263
|
-
}]
|
|
676
|
+
returns: componentClass
|
|
677
|
+
}],
|
|
678
|
+
emitSingleton: true
|
|
264
679
|
});
|
|
265
680
|
}
|
|
266
|
-
function
|
|
681
|
+
function pushComponentManifestClasses(classes, aliases, componentTypes, componentHooks) {
|
|
682
|
+
const eventKinds = componentHooks !== void 0 ? Object.keys(componentHooks).sort((a, b) => a.localeCompare(b)) : [];
|
|
683
|
+
if (componentHooks !== void 0) pushComponentEventPayloadClasses(eventKinds, componentHooks, classes);
|
|
684
|
+
pushBaseComponentClass(classes);
|
|
685
|
+
const typeNames = Object.keys(componentTypes).sort((a, b) => a.localeCompare(b));
|
|
686
|
+
for (const typeName of typeNames) pushComponentTypeManifest(classes, aliases, typeName, componentTypes[typeName], componentHooks);
|
|
687
|
+
}
|
|
688
|
+
function buildLuaDefManifestFromHostSurfaceSpec(spec, opts, componentHooks, componentTypes) {
|
|
267
689
|
const classes = [];
|
|
268
690
|
const bridgeNames = Object.keys(spec).sort((a, b) => a.localeCompare(b));
|
|
269
691
|
for (const bridgeName of bridgeNames) {
|
|
@@ -307,12 +729,11 @@ function buildLuaDefManifestFromHostSurfaceSpec(spec, opts, componentHooks) {
|
|
|
307
729
|
emitSingleton: false
|
|
308
730
|
});
|
|
309
731
|
}
|
|
310
|
-
pushMicroverseBridgesClass(bridgeNames, classes);
|
|
311
732
|
const fromLuaType = collectLuaTypeAliasesFromHostSpec(spec);
|
|
312
733
|
const fromOverrides = inferLuaTypeAliasesFromHostSpec(spec);
|
|
313
734
|
const merged = new Map([...fromLuaType.map((a) => [a.name, a.definition]), ...fromOverrides.map((a) => [a.name, a.definition])]);
|
|
314
735
|
if (opts.luaTypeAliases !== void 0) for (const [k, v] of Object.entries(opts.luaTypeAliases)) merged.set(k, v);
|
|
315
|
-
pushComponentManifestClasses(classes,
|
|
736
|
+
if (componentTypes !== void 0) pushComponentManifestClasses(classes, merged, componentTypes, componentHooks);
|
|
316
737
|
const aliases = merged.size === 0 ? void 0 : [...merged.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([name, definition]) => ({
|
|
317
738
|
name,
|
|
318
739
|
definition
|
|
@@ -452,110 +873,28 @@ function unwrapInputSchema(schema) {
|
|
|
452
873
|
return cur;
|
|
453
874
|
}
|
|
454
875
|
//#endregion
|
|
455
|
-
//#region src/domain/surfaceCapabilities.ts
|
|
456
|
-
/** Runtime list of capability ids declared on a compiled surface spec. */
|
|
457
|
-
function collectCapabilitiesFromHostSurfaceSpec(spec) {
|
|
458
|
-
const out = [];
|
|
459
|
-
const seen = /* @__PURE__ */ new Set();
|
|
460
|
-
for (const bridgeName of Object.keys(spec)) {
|
|
461
|
-
const methods = spec[bridgeName];
|
|
462
|
-
for (const methodName of Object.keys(methods)) {
|
|
463
|
-
const id = methods[methodName].capability;
|
|
464
|
-
const key = String(id);
|
|
465
|
-
if (!seen.has(key)) {
|
|
466
|
-
seen.add(key);
|
|
467
|
-
out.push(id);
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
return out;
|
|
472
|
-
}
|
|
473
|
-
/** Narrows `capabilities` to those declared on the surface (runtime check). */
|
|
474
|
-
function pickSurfaceCapabilities(surfaceCapabilities, ...capabilities) {
|
|
475
|
-
const allowed = new Set(surfaceCapabilities.map((c) => String(c)));
|
|
476
|
-
for (const id of capabilities) if (!allowed.has(String(id))) throw new Error(`capability not declared on host surface: ${String(id)} (surface has: ${[...allowed].join(", ")})`);
|
|
477
|
-
return capabilities;
|
|
478
|
-
}
|
|
479
|
-
//#endregion
|
|
480
|
-
//#region src/domain/capabilityRegistrySymbol.ts
|
|
481
|
-
/**
|
|
482
|
-
* Well-known symbol key used to attach a {@link CapabilityRegistryPort} on the host object
|
|
483
|
-
* while surface bridge methods run. Populated by {@link augmentHostWithCapabilityRegistry} or
|
|
484
|
-
* internally by {@link HostScriptSession}.
|
|
485
|
-
*/
|
|
486
|
-
var MICROVERSE_CAPABILITY_REGISTRY = Symbol.for("microverse:capabilityRegistry");
|
|
487
|
-
//#endregion
|
|
488
|
-
//#region src/domain/scriptContextSymbol.ts
|
|
489
|
-
var MICROVERSE_SCRIPT_CONTEXT = Symbol("microverse.scriptContext");
|
|
490
|
-
//#endregion
|
|
491
|
-
//#region src/application/useCases/compileBridgeDeclarationsFromHostSurfaceSpec.ts
|
|
492
|
-
function isThenable(value) {
|
|
493
|
-
if (value === null || value === void 0) return false;
|
|
494
|
-
if (typeof value !== "object" && typeof value !== "function") return false;
|
|
495
|
-
return typeof value.then === "function";
|
|
496
|
-
}
|
|
497
|
-
/**
|
|
498
|
-
* Builds declarative bridge declarations from a host surface spec, using the schema validation port for Lua ↔ host payloads.
|
|
499
|
-
*/
|
|
500
|
-
function createBridgeDeclarationsFromHostSurfaceSpec(schemaValidation, spec) {
|
|
501
|
-
const out = [];
|
|
502
|
-
for (const bridgeName of Object.keys(spec)) {
|
|
503
|
-
const methods = spec[bridgeName];
|
|
504
|
-
out.push({
|
|
505
|
-
name: bridgeName,
|
|
506
|
-
perEntity: true,
|
|
507
|
-
createApi: (host, slotKey) => {
|
|
508
|
-
const hostWithScript = host;
|
|
509
|
-
const api = {};
|
|
510
|
-
for (const methodName of Object.keys(methods)) {
|
|
511
|
-
const entry = methods[methodName];
|
|
512
|
-
api[methodName] = (...args) => {
|
|
513
|
-
const payload = args.length >= 2 ? args[1] : args[0];
|
|
514
|
-
const registry = hostWithScript[MICROVERSE_CAPABILITY_REGISTRY];
|
|
515
|
-
const capability = entry.capability;
|
|
516
|
-
if (!registry.isAllowed(capability)) throw new Error(`capability denied: ${String(capability)}`);
|
|
517
|
-
const parsedIn = schemaValidation.validateWithZodSchema(entry.input, payload);
|
|
518
|
-
if (parsedIn._tag === "err") throw new Error(parsedIn.error);
|
|
519
|
-
const script = hostWithScript[MICROVERSE_SCRIPT_CONTEXT] ?? createScriptInstanceContext({
|
|
520
|
-
instanceId: String(slotKey),
|
|
521
|
-
scriptId: "unknown",
|
|
522
|
-
slotKey: String(slotKey)
|
|
523
|
-
});
|
|
524
|
-
const raw = entry.handler({
|
|
525
|
-
host: hostWithScript,
|
|
526
|
-
slotKey: String(slotKey),
|
|
527
|
-
script
|
|
528
|
-
}, parsedIn.value);
|
|
529
|
-
if (isThenable(raw)) return raw.then((resolved) => {
|
|
530
|
-
const parsedOut = schemaValidation.validateWithZodSchema(entry.output, resolved);
|
|
531
|
-
if (parsedOut._tag === "err") throw new Error(parsedOut.error);
|
|
532
|
-
return parsedOut.value;
|
|
533
|
-
});
|
|
534
|
-
const parsedOut = schemaValidation.validateWithZodSchema(entry.output, raw);
|
|
535
|
-
if (parsedOut._tag === "err") throw new Error(parsedOut.error);
|
|
536
|
-
return parsedOut.value;
|
|
537
|
-
};
|
|
538
|
-
}
|
|
539
|
-
return Object.freeze(api);
|
|
540
|
-
}
|
|
541
|
-
});
|
|
542
|
-
}
|
|
543
|
-
return out;
|
|
544
|
-
}
|
|
545
|
-
//#endregion
|
|
546
876
|
//#region src/application/useCases/compileHostSurface.ts
|
|
547
|
-
function buildHostSurfaceCore(schemaValidation, spec, componentHooks) {
|
|
877
|
+
function buildHostSurfaceCore(schemaValidation, spec, componentTypeRegistry, componentHooks) {
|
|
878
|
+
validateScriptProfileRegistry(componentTypeRegistry, spec, componentHooks, { requireAtLeastOne: false });
|
|
879
|
+
const componentTypes = buildResolvedScriptProfileRegistry(componentTypeRegistry, spec);
|
|
548
880
|
const capabilities = collectCapabilitiesFromHostSurfaceSpec(spec);
|
|
549
881
|
return {
|
|
882
|
+
getHostSurfaceSpec: () => spec,
|
|
550
883
|
toBridgeDeclarations: () => createBridgeDeclarationsFromHostSurfaceSpec(schemaValidation, spec),
|
|
551
|
-
toLuaDefManifest: (opts) => buildLuaDefManifestFromHostSurfaceSpec(spec, opts, componentHooks),
|
|
884
|
+
toLuaDefManifest: (opts) => buildLuaDefManifestFromHostSurfaceSpec(spec, opts, componentHooks, componentTypes),
|
|
552
885
|
capabilities,
|
|
886
|
+
componentTypes,
|
|
887
|
+
getComponentType: (name) => {
|
|
888
|
+
const profile = componentTypes[name];
|
|
889
|
+
if (profile === void 0) throw new Error(`unknown component type: ${name}`);
|
|
890
|
+
return profile;
|
|
891
|
+
},
|
|
553
892
|
pickCapabilities: (...picked) => pickSurfaceCapabilities(capabilities, ...picked)
|
|
554
893
|
};
|
|
555
894
|
}
|
|
556
|
-
function compileHostSurface(ports, spec, componentHooks) {
|
|
895
|
+
function compileHostSurface(ports, spec, componentTypeRegistry, componentHooks) {
|
|
557
896
|
const [schemaValidation] = ports;
|
|
558
|
-
const core = buildHostSurfaceCore(schemaValidation, spec, componentHooks);
|
|
897
|
+
const core = buildHostSurfaceCore(schemaValidation, spec, componentTypeRegistry, componentHooks);
|
|
559
898
|
if (componentHooks === void 0) return core;
|
|
560
899
|
return {
|
|
561
900
|
...core,
|
|
@@ -565,8 +904,8 @@ function compileHostSurface(ports, spec, componentHooks) {
|
|
|
565
904
|
/**
|
|
566
905
|
* Same as {@link compileHostSurface}, but requires every bridge method to be typed with the same `THost`.
|
|
567
906
|
*/
|
|
568
|
-
function compileHostSurfaceFor(ports, spec, componentHooks) {
|
|
569
|
-
return componentHooks === void 0 ? compileHostSurface(ports, spec) : compileHostSurface(ports, spec, componentHooks);
|
|
907
|
+
function compileHostSurfaceFor(ports, spec, componentTypeRegistry, componentHooks) {
|
|
908
|
+
return componentHooks === void 0 ? compileHostSurface(ports, spec, componentTypeRegistry) : compileHostSurface(ports, spec, componentTypeRegistry, componentHooks);
|
|
570
909
|
}
|
|
571
910
|
//#endregion
|
|
572
911
|
//#region src/domain/inferMethodAsync.ts
|
|
@@ -593,33 +932,16 @@ function normalizeMethodDef(def) {
|
|
|
593
932
|
};
|
|
594
933
|
}
|
|
595
934
|
//#endregion
|
|
596
|
-
//#region src/domain/safeObjectKey.ts
|
|
597
|
-
/** Keys that must not be used as dynamic property names on ordinary objects. */
|
|
598
|
-
var FORBIDDEN_OBJECT_KEYS = new Set([
|
|
599
|
-
"__proto__",
|
|
600
|
-
"constructor",
|
|
601
|
-
"prototype"
|
|
602
|
-
]);
|
|
603
|
-
/**
|
|
604
|
-
* Rejects bridge/method names that could trigger prototype pollution when used as object keys.
|
|
605
|
-
*/
|
|
606
|
-
function assertSafeObjectKey(kind, name) {
|
|
607
|
-
if (FORBIDDEN_OBJECT_KEYS.has(name)) throw new Error(`Invalid surface ${kind} name "${name}": reserved key`);
|
|
608
|
-
}
|
|
609
|
-
/** Record with no inherited prototype — safe for dynamic string keys at runtime. */
|
|
610
|
-
function createNullPrototypeRecord() {
|
|
611
|
-
return Object.create(null);
|
|
612
|
-
}
|
|
613
|
-
//#endregion
|
|
614
935
|
//#region src/infrastructure/builders/surfaceBuilder.ts
|
|
615
936
|
/**
|
|
616
937
|
* Fluent builder for a host surface. Created via {@link defineHostSurfaceFor} / {@link defineHostSurface} factory overloads.
|
|
617
938
|
*/
|
|
618
939
|
var SurfaceBuilder = class SurfaceBuilder {
|
|
619
940
|
spec = createNullPrototypeRecord();
|
|
941
|
+
componentTypeRegistry = createNullPrototypeRecord();
|
|
620
942
|
componentHooksSpec;
|
|
621
943
|
ports;
|
|
622
|
-
constructor(ports, componentHooks, initialSpec) {
|
|
944
|
+
constructor(ports, componentHooks, initialSpec, initialComponentTypes) {
|
|
623
945
|
this.ports = ports;
|
|
624
946
|
this.componentHooksSpec = componentHooks;
|
|
625
947
|
if (initialSpec !== void 0) for (const bridgeName of Object.keys(initialSpec)) {
|
|
@@ -632,19 +954,27 @@ var SurfaceBuilder = class SurfaceBuilder {
|
|
|
632
954
|
}
|
|
633
955
|
this.spec[bridgeName] = bridge;
|
|
634
956
|
}
|
|
957
|
+
if (initialComponentTypes !== void 0) for (const name of Object.keys(initialComponentTypes)) this.componentTypeRegistry[name] = initialComponentTypes[name];
|
|
958
|
+
}
|
|
959
|
+
/** Declares a typed Lua component profile (props, state, capabilities, hooks). */
|
|
960
|
+
componentType(name, def) {
|
|
961
|
+
assertSafeObjectKey("componentType", name);
|
|
962
|
+
this.componentTypeRegistry[name] = def;
|
|
963
|
+
return this;
|
|
635
964
|
}
|
|
636
965
|
/** Opens a Lua bridge table (e.g. `orders`, `greet`). */
|
|
637
966
|
bridge(name) {
|
|
638
967
|
return new BridgeBuilder(this, name);
|
|
639
968
|
}
|
|
640
|
-
/** Attaches component domain-event Zod schemas (emitted into `.d.lua` as `on*` methods on
|
|
969
|
+
/** Attaches component domain-event Zod schemas (emitted into `.d.lua` as `on*` methods on component types). */
|
|
641
970
|
componentHooks(hooks) {
|
|
642
|
-
return new SurfaceBuilder(this.ports, hooks, this.spec);
|
|
971
|
+
return new SurfaceBuilder(this.ports, hooks, this.spec, this.componentTypeRegistry);
|
|
643
972
|
}
|
|
644
973
|
/** Compiles the accumulated spec into a {@link HostSurface}. */
|
|
645
974
|
build() {
|
|
646
975
|
const spec = this.spec;
|
|
647
|
-
|
|
976
|
+
const registry = this.componentTypeRegistry;
|
|
977
|
+
return compileHostSurfaceFor(this.ports, spec, registry, this.componentHooksSpec);
|
|
648
978
|
}
|
|
649
979
|
/** @internal */
|
|
650
980
|
addMethod(bridgeName, methodName, entry) {
|
|
@@ -720,99 +1050,6 @@ function defineHostSurfaceFor() {
|
|
|
720
1050
|
return createSurfaceBuilder();
|
|
721
1051
|
}
|
|
722
1052
|
//#endregion
|
|
723
|
-
//#region src/domain/componentSlotPrelude.ts
|
|
724
|
-
/** @see MICROVERSE_LUA_COMPONENT_SLOT_PRELUDE */
|
|
725
|
-
var MICROVERSE_LUA_COMPONENT_SLOT_PRELUDE = `
|
|
726
|
-
rawset(_ENV, "__microverse_component_rawProps", {})
|
|
727
|
-
rawset(_ENV, "__microverse_component_dirty", {})
|
|
728
|
-
|
|
729
|
-
local function rawProps()
|
|
730
|
-
return rawget(_ENV, "__microverse_component_rawProps")
|
|
731
|
-
end
|
|
732
|
-
|
|
733
|
-
local function dirty()
|
|
734
|
-
return rawget(_ENV, "__microverse_component_dirty")
|
|
735
|
-
end
|
|
736
|
-
|
|
737
|
-
local PropertiesMT = {
|
|
738
|
-
__index = function(t, k)
|
|
739
|
-
return rawget(t, "__raw")[k]
|
|
740
|
-
end,
|
|
741
|
-
__newindex = function(t, k, v)
|
|
742
|
-
rawget(t, "__raw")[k] = v
|
|
743
|
-
local d = dirty()
|
|
744
|
-
d[k] = v
|
|
745
|
-
end,
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
function __microverse_lua_attach_bridges(impl)
|
|
749
|
-
if type(impl) ~= "table" then
|
|
750
|
-
return
|
|
751
|
-
end
|
|
752
|
-
impl.bridges = impl.bridges or {}
|
|
753
|
-
local names = rawget(_ENV, "__microverse_bridge_names")
|
|
754
|
-
if type(names) ~= "table" then
|
|
755
|
-
return
|
|
756
|
-
end
|
|
757
|
-
for _, name in ipairs(names) do
|
|
758
|
-
if type(name) == "string" then
|
|
759
|
-
local g = rawget(_ENV, name)
|
|
760
|
-
if type(g) == "table" then
|
|
761
|
-
impl.bridges[name] = g
|
|
762
|
-
rawset(_ENV, name, nil)
|
|
763
|
-
end
|
|
764
|
-
end
|
|
765
|
-
end
|
|
766
|
-
end
|
|
767
|
-
|
|
768
|
-
rawset(_ENV, "__microverse_lua_attach_bridges", __microverse_lua_attach_bridges)
|
|
769
|
-
|
|
770
|
-
rawset(_ENV, "component", {
|
|
771
|
-
extend = function()
|
|
772
|
-
local impl = { state = {}, bridges = {} }
|
|
773
|
-
local proxy = { __raw = rawProps() }
|
|
774
|
-
setmetatable(proxy, PropertiesMT)
|
|
775
|
-
impl.properties = proxy
|
|
776
|
-
local base = rawget(_ENV, "__microverse_component_hook_base")
|
|
777
|
-
if type(base) == "table" then
|
|
778
|
-
setmetatable(impl, { __index = base })
|
|
779
|
-
end
|
|
780
|
-
__microverse_lua_attach_bridges(impl)
|
|
781
|
-
rawset(_ENV, "__microverse_lua_ComponentImpl", impl)
|
|
782
|
-
return impl
|
|
783
|
-
end,
|
|
784
|
-
})
|
|
785
|
-
|
|
786
|
-
rawset(_ENV, "__microverse_lua_component_apply_incoming", function()
|
|
787
|
-
local incoming = rawget(_ENV, "__microverseIncomingProps")
|
|
788
|
-
if type(incoming) ~= "table" then
|
|
789
|
-
return
|
|
790
|
-
end
|
|
791
|
-
local rp = rawProps()
|
|
792
|
-
local impl = rawget(_ENV, "__microverse_lua_ComponentImpl")
|
|
793
|
-
if type(impl) ~= "table" or type(impl.properties) ~= "table" then
|
|
794
|
-
for k, v in pairs(incoming) do
|
|
795
|
-
rp[k] = v
|
|
796
|
-
end
|
|
797
|
-
return
|
|
798
|
-
end
|
|
799
|
-
for k, v in pairs(incoming) do
|
|
800
|
-
impl.properties[k] = v
|
|
801
|
-
end
|
|
802
|
-
end)
|
|
803
|
-
|
|
804
|
-
rawset(_ENV, "__microverse_lua_component_flush_to_sink", function()
|
|
805
|
-
local push = rawget(_ENV, "__microverseFlushPush")
|
|
806
|
-
local d = dirty()
|
|
807
|
-
for k, v in pairs(d) do
|
|
808
|
-
if type(push) == "function" then
|
|
809
|
-
push(k, v)
|
|
810
|
-
end
|
|
811
|
-
d[k] = nil
|
|
812
|
-
end
|
|
813
|
-
end)
|
|
814
|
-
`.trim();
|
|
815
|
-
//#endregion
|
|
816
1053
|
//#region src/domain/scriptPropertyMergeEnv.ts
|
|
817
1054
|
function scriptPropertyBagToMergeEnv(bag) {
|
|
818
1055
|
const out = {};
|
|
@@ -857,34 +1094,27 @@ function plainToScriptPropertyValue(value) {
|
|
|
857
1094
|
}
|
|
858
1095
|
}
|
|
859
1096
|
//#endregion
|
|
860
|
-
//#region src/infrastructure/adapters/augmentHostWithCapabilityRegistry.ts
|
|
861
|
-
/**
|
|
862
|
-
* Returns a shallow copy of `host` with {@link MICROVERSE_CAPABILITY_REGISTRY} set to `registry`.
|
|
863
|
-
* Bridge handlers read the registry to enforce per-session capability allowlists.
|
|
864
|
-
*
|
|
865
|
-
* @param host - Your engine / service context passed into `buildDeclarativeBridgeTable`.
|
|
866
|
-
* @param registry - Typically an {@link InMemoryCapabilityRegistry} from `@microverse.ts/runtime-capabilities`.
|
|
867
|
-
*/
|
|
868
|
-
function augmentHostWithCapabilityRegistry(host, registry) {
|
|
869
|
-
return Object.assign(host, { [MICROVERSE_CAPABILITY_REGISTRY]: registry });
|
|
870
|
-
}
|
|
871
|
-
//#endregion
|
|
872
1097
|
//#region src/infrastructure/adapters/augmentHostWithScriptContext.ts
|
|
873
1098
|
function augmentHostWithScriptContext(host, script) {
|
|
874
1099
|
return Object.assign(host, { [MICROVERSE_SCRIPT_CONTEXT]: script });
|
|
875
1100
|
}
|
|
876
1101
|
//#endregion
|
|
877
1102
|
//#region src/infrastructure/components/hostScriptSession.ts
|
|
1103
|
+
var defaultSchemaValidation = createZodSchemaValidationPort();
|
|
878
1104
|
var HostScriptSession = class {
|
|
879
1105
|
opts;
|
|
880
1106
|
sandbox;
|
|
881
1107
|
hostProps = {};
|
|
882
|
-
|
|
1108
|
+
schemaValidation;
|
|
1109
|
+
activeComponentType;
|
|
1110
|
+
hostProfileApplied = false;
|
|
883
1111
|
context;
|
|
884
1112
|
constructor(opts) {
|
|
885
1113
|
this.opts = opts;
|
|
886
|
-
this.
|
|
1114
|
+
this.schemaValidation = opts.schemaValidation ?? defaultSchemaValidation;
|
|
887
1115
|
this.context = opts.script;
|
|
1116
|
+
if (opts.resolvedProfile !== void 0) this.activeComponentType = opts.resolvedProfile.name;
|
|
1117
|
+
else if (opts.profileId !== void 0) this.activeComponentType = opts.profileId;
|
|
888
1118
|
}
|
|
889
1119
|
openSession = async () => {
|
|
890
1120
|
this.sandbox = await this.opts.runtime.createMicroverse({ slotKey: this.opts.slotKey });
|
|
@@ -895,11 +1125,25 @@ var HostScriptSession = class {
|
|
|
895
1125
|
mergeEnv: this.mergeEnv(),
|
|
896
1126
|
timeout: this.opts.defaultTimeout
|
|
897
1127
|
});
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
1128
|
+
const activeProfile = this.tryGetActiveProfile();
|
|
1129
|
+
const singletonName = this.profileSingletonName();
|
|
1130
|
+
const typeNames = this.singletonTypeNames();
|
|
1131
|
+
if (typeNames.length > 0) {
|
|
1132
|
+
const bridgeRegistry = activeProfile !== void 0 ? { [activeProfile.name]: activeProfile } : this.opts.surface.componentTypes;
|
|
1133
|
+
await sb.run({
|
|
1134
|
+
script: createMicroverseScript([buildComponentTypeBridgeNamesPreludeLua(bridgeRegistry), buildComponentTypeSingletonsPreludeLua(typeNames)].join("\n")),
|
|
1135
|
+
mergeEnv: this.mergeEnv(),
|
|
1136
|
+
timeout: this.opts.defaultTimeout
|
|
1137
|
+
});
|
|
1138
|
+
if (singletonName !== void 0) {
|
|
1139
|
+
await sb.run({
|
|
1140
|
+
script: createMicroverseScript(buildApplyHostScriptProfileChunkLua(singletonName)),
|
|
1141
|
+
mergeEnv: this.mergeEnv(),
|
|
1142
|
+
timeout: this.opts.defaultTimeout
|
|
1143
|
+
});
|
|
1144
|
+
this.hostProfileApplied = true;
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
903
1147
|
const hooks = readComponentHooks(this.opts.surface);
|
|
904
1148
|
if (hooks !== void 0) {
|
|
905
1149
|
const prelude = buildComponentEventStubPreludeLua(hooks);
|
|
@@ -911,25 +1155,82 @@ var HostScriptSession = class {
|
|
|
911
1155
|
}
|
|
912
1156
|
}
|
|
913
1157
|
};
|
|
914
|
-
getCapabilityRegistry = () => this.registry;
|
|
915
1158
|
requireMicroverseSlot() {
|
|
916
1159
|
if (this.sandbox === void 0) throw new Error("HostScriptSession: openSession() was not called");
|
|
917
1160
|
return this.sandbox;
|
|
918
1161
|
}
|
|
919
1162
|
mergeEnv() {
|
|
920
|
-
|
|
1163
|
+
const host = augmentHostWithScriptContext(this.opts.host, this.opts.script);
|
|
1164
|
+
const spec = this.opts.surface.getHostSurfaceSpec();
|
|
1165
|
+
const env = { __microverse_lua_extend_component: (typeName) => {
|
|
1166
|
+
if (this.opts.resolvedProfile !== void 0 && typeName === this.profileSingletonName()) {
|
|
1167
|
+
this.activeComponentType = this.opts.resolvedProfile.name;
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
this.opts.surface.getComponentType(typeName);
|
|
1171
|
+
this.activeComponentType = typeName;
|
|
1172
|
+
} };
|
|
1173
|
+
const activeProfile = this.tryGetActiveProfile();
|
|
1174
|
+
const typeNames = activeProfile !== void 0 ? [activeProfile.name] : Object.keys(this.opts.surface.componentTypes);
|
|
1175
|
+
for (const typeName of typeNames) {
|
|
1176
|
+
const profile = activeProfile !== void 0 && typeName === activeProfile.name ? activeProfile : this.opts.surface.getComponentType(typeName);
|
|
1177
|
+
const bridgeTable = buildBridgeMergeEnvForProfile(this.schemaValidation, host, String(this.opts.slotKey), spec, profile.capabilities);
|
|
1178
|
+
for (const bridgeName of profile.bridgeNames) env[profileBridgeSlotKey(typeName, bridgeName)] = bridgeTable[bridgeName];
|
|
1179
|
+
}
|
|
1180
|
+
const profileForRefs = this.tryGetActiveProfile();
|
|
1181
|
+
if (profileForRefs?.references !== void 0 && this.opts.referenceResolver !== void 0) {
|
|
1182
|
+
const profile = profileForRefs;
|
|
1183
|
+
env.__microverse_reference_wrap = (field, raw) => this.wrapReference(field, raw, profile);
|
|
1184
|
+
}
|
|
1185
|
+
return env;
|
|
1186
|
+
}
|
|
1187
|
+
wrapReference(field, raw, profile) {
|
|
1188
|
+
const resolver = this.opts.referenceResolver;
|
|
1189
|
+
const refs = profile.references;
|
|
1190
|
+
if (resolver === void 0 || refs === void 0) return raw;
|
|
1191
|
+
const def = refs[field];
|
|
1192
|
+
if (def === void 0) return raw;
|
|
1193
|
+
const rawId = raw === null || raw === void 0 ? null : typeof raw === "string" ? raw : typeof raw === "number" || typeof raw === "boolean" ? String(raw) : null;
|
|
1194
|
+
return resolver.wrap({
|
|
1195
|
+
slotKey: String(this.opts.slotKey),
|
|
1196
|
+
field,
|
|
1197
|
+
raw: rawId,
|
|
1198
|
+
kind: def.kind,
|
|
1199
|
+
componentType: referenceComponentType(def)
|
|
1200
|
+
});
|
|
921
1201
|
}
|
|
922
1202
|
emitAudit(event) {
|
|
923
1203
|
this.opts.onScriptAudit?.(event);
|
|
924
1204
|
}
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
1205
|
+
getActiveProfileName() {
|
|
1206
|
+
return this.activeComponentType ?? this.opts.profileId;
|
|
1207
|
+
}
|
|
1208
|
+
profileSingletonName() {
|
|
1209
|
+
return this.opts.profileSingleton ?? this.opts.profileId ?? this.opts.resolvedProfile?.name;
|
|
1210
|
+
}
|
|
1211
|
+
singletonTypeNames() {
|
|
1212
|
+
const singleton = this.profileSingletonName();
|
|
1213
|
+
const fromSurface = Object.keys(this.opts.surface.componentTypes);
|
|
1214
|
+
const names = new Set(fromSurface);
|
|
1215
|
+
if (singleton !== void 0) names.add(singleton);
|
|
1216
|
+
return [...names].sort((a, b) => a.localeCompare(b));
|
|
1217
|
+
}
|
|
1218
|
+
tryGetActiveProfile() {
|
|
1219
|
+
if (this.opts.resolvedProfile !== void 0) return this.opts.resolvedProfile;
|
|
1220
|
+
const name = this.getActiveProfileName();
|
|
1221
|
+
if (name === void 0) return;
|
|
1222
|
+
try {
|
|
1223
|
+
return this.opts.surface.getComponentType(name);
|
|
1224
|
+
} catch {
|
|
1225
|
+
return;
|
|
930
1226
|
}
|
|
931
|
-
|
|
932
|
-
|
|
1227
|
+
}
|
|
1228
|
+
validatePropsBag(bag) {
|
|
1229
|
+
const profile = this.tryGetActiveProfile();
|
|
1230
|
+
if (profile === void 0) throw new Error("HostScriptSession: set profileId or resolvedProfile before props or host sync");
|
|
1231
|
+
const parsed = profile.props.parse(bag);
|
|
1232
|
+
assertValidScriptPropertyBag(parsed);
|
|
1233
|
+
return parsed;
|
|
933
1234
|
}
|
|
934
1235
|
getProps = () => ({ ...this.hostProps });
|
|
935
1236
|
setProps = async (bag) => {
|
|
@@ -1009,8 +1310,6 @@ var HostScriptSession = class {
|
|
|
1009
1310
|
const src = [
|
|
1010
1311
|
`local impl = rawget(_ENV, "__microverse_lua_ComponentImpl")`,
|
|
1011
1312
|
`if type(impl) == "table" then`,
|
|
1012
|
-
` local attach = rawget(_ENV, "__microverse_lua_attach_bridges")`,
|
|
1013
|
-
` if type(attach) == "function" then attach(impl) end`,
|
|
1014
1313
|
` local m = rawget(impl, ${JSON.stringify(hookName)})`,
|
|
1015
1314
|
` if type(m) == "function" then`,
|
|
1016
1315
|
argLiterals.length > 0 ? ` m(impl, ${argLiterals})` : ` m(impl)`,
|
|
@@ -1058,7 +1357,11 @@ var HostScriptSession = class {
|
|
|
1058
1357
|
for (const k of Object.keys(this.hostProps)) delete this.hostProps[k];
|
|
1059
1358
|
Object.assign(this.hostProps, cloned);
|
|
1060
1359
|
};
|
|
1360
|
+
getHostProfileApplied = () => this.hostProfileApplied;
|
|
1061
1361
|
};
|
|
1362
|
+
function referenceComponentType(def) {
|
|
1363
|
+
if (def.kind === "entityComponentRef" || def.kind === "entityComponentRefArray") return def.componentType;
|
|
1364
|
+
}
|
|
1062
1365
|
function assertSafeLuaGlobalName(name) {
|
|
1063
1366
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) throw new Error(`unsafe Lua global name: ${name}`);
|
|
1064
1367
|
}
|
|
@@ -1066,9 +1369,6 @@ function readComponentHooks(surface) {
|
|
|
1066
1369
|
if (!("componentHooks" in surface)) return;
|
|
1067
1370
|
return surface.componentHooks;
|
|
1068
1371
|
}
|
|
1069
|
-
function buildBridgeNamesPreludeLua(bridgeNames) {
|
|
1070
|
-
return `rawset(_ENV, "__microverse_bridge_names", { ${bridgeNames.map((n) => JSON.stringify(n)).join(", ")} })`;
|
|
1071
|
-
}
|
|
1072
1372
|
function buildComponentEventStubPreludeLua(hooks) {
|
|
1073
1373
|
return [
|
|
1074
1374
|
"local Base = {}",
|
|
@@ -1111,6 +1411,26 @@ function luaTableLiteralFromUnknownRecord(o) {
|
|
|
1111
1411
|
return `{ ${parts.join(", ")} }`;
|
|
1112
1412
|
}
|
|
1113
1413
|
//#endregion
|
|
1114
|
-
|
|
1414
|
+
//#region src/domain/capabilityRegistrySymbol.ts
|
|
1415
|
+
/**
|
|
1416
|
+
* Well-known symbol key used to attach a {@link CapabilityRegistryPort} on the host object
|
|
1417
|
+
* while surface bridge methods run. Populated by {@link augmentHostWithCapabilityRegistry} or
|
|
1418
|
+
* internally by {@link HostScriptSession}.
|
|
1419
|
+
*/
|
|
1420
|
+
var MICROVERSE_CAPABILITY_REGISTRY = Symbol.for("microverse:capabilityRegistry");
|
|
1421
|
+
//#endregion
|
|
1422
|
+
//#region src/infrastructure/adapters/augmentHostWithCapabilityRegistry.ts
|
|
1423
|
+
/**
|
|
1424
|
+
* Returns a shallow copy of `host` with {@link MICROVERSE_CAPABILITY_REGISTRY} set to `registry`.
|
|
1425
|
+
* Bridge handlers read the registry to enforce per-session capability allowlists.
|
|
1426
|
+
*
|
|
1427
|
+
* @param host - Your engine / service context passed into `buildDeclarativeBridgeTable`.
|
|
1428
|
+
* @param registry - Typically an {@link InMemoryCapabilityRegistry} from `@microverse.ts/runtime-capabilities`.
|
|
1429
|
+
*/
|
|
1430
|
+
function augmentHostWithCapabilityRegistry(host, registry) {
|
|
1431
|
+
return Object.assign(host, { [MICROVERSE_CAPABILITY_REGISTRY]: registry });
|
|
1432
|
+
}
|
|
1433
|
+
//#endregion
|
|
1434
|
+
export { BridgeBuilder, HostScriptSession, MICROVERSE_CAPABILITY_REGISTRY, MICROVERSE_LUA_COMPONENT_SLOT_PRELUDE, MICROVERSE_SCRIPT_CONTEXT, SurfaceBuilder, augmentHostWithCapabilityRegistry, augmentHostWithScriptContext, buildBridgeMergeEnvForProfile, buildComponentTypeSingletonsPreludeLua, buildResolvedScriptProfileRegistry, buildScriptCatalogLuaDefManifest, collectCapabilitiesFromHostSurfaceSpec, compileHostSurface, compileHostSurfaceFor, createBridgeDeclarationsFromHostSurfaceSpec, defineHostSurface, defineHostSurfaceFor, luaGlobalHookName, luaType, mergeEnvSinkToScriptPropertyBag, pickSurfaceCapabilities, resolveScriptProfile, scriptCatalogComponentAlias, scriptProfileBridgesClassName, scriptProfileComponentClassName, scriptProfilePropsAlias, scriptProfileStateAlias, scriptPropertyBagToMergeEnv, scriptPropertyValueToPlain, zodToLuaTypeRef };
|
|
1115
1435
|
|
|
1116
1436
|
//# sourceMappingURL=index.js.map
|