@microverse.ts/runtime-wasm 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 QADRAX
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,2 @@
1
+ export declare const WASM_BOOTSTRAP_ORDER: readonly ["init", "execute"];
2
+ //# sourceMappingURL=WasmBootstrapOrder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WasmBootstrapOrder.d.ts","sourceRoot":"","sources":["../../../src/application/bootstrap/WasmBootstrapOrder.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB,8BAA+B,CAAC"}
@@ -0,0 +1,20 @@
1
+ export type WorkerHostToRuntimeMessage = {
2
+ readonly _tag: 'init';
3
+ readonly wasmEntrypoint: string;
4
+ } | {
5
+ readonly _tag: 'execute';
6
+ readonly requestId: string;
7
+ readonly script: string;
8
+ };
9
+ export type WorkerRuntimeToHostMessage = {
10
+ readonly _tag: 'ready';
11
+ } | {
12
+ readonly _tag: 'result';
13
+ readonly requestId: string;
14
+ readonly output: string;
15
+ } | {
16
+ readonly _tag: 'error';
17
+ readonly requestId: string;
18
+ readonly message: string;
19
+ };
20
+ //# sourceMappingURL=WorkerMicroverseMessages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorkerMicroverseMessages.d.ts","sourceRoot":"","sources":["../../../src/domain/worker/WorkerMicroverseMessages.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,0BAA0B,GAClC;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GAC1D;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtF,MAAM,MAAM,0BAA0B,GAClC;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAC1B;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAChF;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC"}
@@ -0,0 +1,7 @@
1
+ export type { WorkerHostToRuntimeMessage, WorkerRuntimeToHostMessage, } from './domain/worker/WorkerMicroverseMessages';
2
+ export { createWasmMicroverseRuntime, type WasmMicroverseRuntimeOptions, } from './infrastructure/runtime/createWasmMicroverseRuntime';
3
+ export { MICROVERSE_LUA_DEFAULT_INSTRUCTION_BUDGET, MICROVERSE_LUA_SLOT_VM_BOOTSTRAP, } from './infrastructure/runtime/microverseLuaSlotVmBootstrap';
4
+ export { MICROVERSE_LUA_DEFAULT_MAX_SCRIPT_CHARS } from './infrastructure/runtime/wasmoonExecutePolicy';
5
+ export { WasmoonRuntimeAdapter, type WasmoonRuntimeAdapterOptions } from './infrastructure/runtime/WasmoonRuntimeAdapter';
6
+ export { WorkerMicroverseHost } from './infrastructure/worker/WorkerMicroverseHost';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,0BAA0B,EAC1B,0BAA0B,GAC3B,MAAM,0CAA0C,CAAC;AAClD,OAAO,EACL,2BAA2B,EAC3B,KAAK,4BAA4B,GAClC,MAAM,sDAAsD,CAAC;AAC9D,OAAO,EACL,yCAAyC,EACzC,gCAAgC,GACjC,MAAM,uDAAuD,CAAC;AAC/D,OAAO,EAAE,uCAAuC,EAAE,MAAM,+CAA+C,CAAC;AACxG,OAAO,EAAE,qBAAqB,EAAE,KAAK,4BAA4B,EAAE,MAAM,gDAAgD,CAAC;AAC1H,OAAO,EAAE,oBAAoB,EAAE,MAAM,8CAA8C,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,420 @@
1
+ import { ConsoleLogger, createStubMicroverseRuntime } from "@microverse.ts/runtime-core";
2
+ import { err, ok } from "@microverse.ts/shared";
3
+ import { LuaFactory } from "wasmoon";
4
+ //#region src/infrastructure/runtime/microverseLuaSlotVmBootstrap.ts
5
+ /**
6
+ * Lua 5.4 bootstrap for **one Wasmoon VM, many slots**:
7
+ * - Slot `_ENV` uses a **safe global** table (no `debug`, `load`, `io`, `os`, …).
8
+ * - Slot registry and internals are **closure-local** (not on `_G`).
9
+ * - Bridge tables are **read-only** from Lua (`__newindex`); host re-injects via `mergeEnv` each run.
10
+ * - **No auto-await**: async bridges return a handle with `:await()`; optional 2nd-arg callback runs after the current chunk step.
11
+ * - Optional **instruction budget** per chunk via `debug.sethook` when available.
12
+ */
13
+ var MICROVERSE_LUA_DEFAULT_INSTRUCTION_BUDGET = 5e6;
14
+ var MICROVERSE_LUA_SLOT_VM_BOOTSTRAP = `
15
+ do
16
+ local REAL_G = _G
17
+ local envs = {}
18
+ local pending_async = {}
19
+
20
+ local function copy_functions(lib)
21
+ if type(lib) ~= "table" then return nil end
22
+ local out = {}
23
+ for k, v in pairs(lib) do
24
+ if type(v) == "function" then
25
+ out[k] = v
26
+ end
27
+ end
28
+ return out
29
+ end
30
+
31
+ local function copy_math()
32
+ local src = REAL_G.math
33
+ if type(src) ~= "table" then return {} end
34
+ local blocked = { random = true, randomseed = true }
35
+ local out = {}
36
+ for k, v in pairs(src) do
37
+ if type(v) == "function" and not blocked[k] then
38
+ out[k] = v
39
+ end
40
+ end
41
+ return out
42
+ end
43
+
44
+ local SAFE_G = {
45
+ assert = assert,
46
+ error = error,
47
+ getmetatable = getmetatable,
48
+ ipairs = ipairs,
49
+ next = next,
50
+ pairs = pairs,
51
+ pcall = pcall,
52
+ rawequal = rawequal,
53
+ rawget = rawget,
54
+ rawlen = rawlen,
55
+ rawset = rawset,
56
+ select = select,
57
+ setmetatable = setmetatable,
58
+ tonumber = tonumber,
59
+ tostring = tostring,
60
+ type = type,
61
+ xpcall = xpcall,
62
+ table = copy_functions(REAL_G.table),
63
+ string = copy_functions(REAL_G.string),
64
+ math = copy_math(),
65
+ _VERSION = REAL_G._VERSION,
66
+ }
67
+
68
+ local ENV_MT = { __index = SAFE_G }
69
+
70
+ local function ensure_env(slot_key)
71
+ local e = envs[slot_key]
72
+ if not e then
73
+ e = {}
74
+ setmetatable(e, ENV_MT)
75
+ envs[slot_key] = e
76
+ end
77
+ return e
78
+ end
79
+
80
+ local debug_lib = REAL_G.debug
81
+ local DEFAULT_BUDGET = ${MICROVERSE_LUA_DEFAULT_INSTRUCTION_BUDGET}
82
+ local HOOK_STEP = 10000
83
+
84
+ local function is_awaitable(r)
85
+ if type(r) == "userdata" or type(r) == "table" then
86
+ return type(r.await) == "function"
87
+ end
88
+ return false
89
+ end
90
+
91
+ function __microverse_lua_await_value(r)
92
+ if not is_awaitable(r) then
93
+ return r
94
+ end
95
+ local ok, out = pcall(function()
96
+ return r:await()
97
+ end)
98
+ if not ok then
99
+ error(out, 0)
100
+ end
101
+ return out
102
+ end
103
+
104
+ function __microverse_lua_wrap_async_result(r)
105
+ if not is_awaitable(r) then
106
+ return r
107
+ end
108
+ return setmetatable({}, {
109
+ __index = function(_, key)
110
+ if key == "await" then
111
+ return function()
112
+ return __microverse_lua_await_value(r)
113
+ end
114
+ end
115
+ return nil
116
+ end,
117
+ })
118
+ end
119
+
120
+ local function is_lua_callback(v)
121
+ return type(v) == "function"
122
+ end
123
+
124
+ local function schedule_on_complete(onComplete, r)
125
+ pending_async[#pending_async + 1] = { cb = onComplete, r = r }
126
+ end
127
+
128
+ local function flush_pending_async()
129
+ for i = 1, #pending_async do
130
+ local job = pending_async[i]
131
+ local out = __microverse_lua_await_value(job.r)
132
+ job.cb(out)
133
+ end
134
+ end
135
+
136
+ local function proxy_bridge(impl)
137
+ return setmetatable({}, {
138
+ __index = function(_, method)
139
+ local f = impl[method]
140
+ if type(f) ~= "function" then
141
+ return nil
142
+ end
143
+ return function(...)
144
+ local n = select("#", ...)
145
+ local onComplete = nil
146
+ local payload
147
+ if n >= 3 and is_lua_callback(select(3, ...)) then
148
+ onComplete = select(3, ...)
149
+ payload = select(2, ...)
150
+ elseif n >= 2 and is_lua_callback(select(2, ...)) then
151
+ onComplete = select(2, ...)
152
+ payload = select(1, ...)
153
+ elseif n >= 2 then
154
+ payload = select(2, ...)
155
+ elseif n >= 1 then
156
+ payload = select(1, ...)
157
+ end
158
+ local r
159
+ if onComplete ~= nil then
160
+ if payload ~= nil then
161
+ r = f(impl, payload)
162
+ else
163
+ r = f(impl)
164
+ end
165
+ schedule_on_complete(onComplete, r)
166
+ return nil
167
+ end
168
+ if payload ~= nil then
169
+ r = f(impl, payload)
170
+ elseif n == 0 then
171
+ r = f(impl)
172
+ else
173
+ r = f(impl, select(1, ...))
174
+ end
175
+ return __microverse_lua_wrap_async_result(r)
176
+ end
177
+ end,
178
+ __newindex = function(_, key)
179
+ error("microverse: bridge table is read-only (" .. tostring(key) .. ")", 2)
180
+ end,
181
+ })
182
+ end
183
+
184
+ function __microverse_lua_put_bridge_from_global(slot_key, field_name, global_tmp_key)
185
+ local e = ensure_env(slot_key)
186
+ local v = REAL_G[global_tmp_key]
187
+ REAL_G[global_tmp_key] = nil
188
+ if type(v) == "userdata" or type(v) == "table" then
189
+ v = proxy_bridge(v)
190
+ end
191
+ rawset(e, field_name, v)
192
+ end
193
+
194
+ function __microverse_lua_execute_in_slot(slot_key, source, instr_budget)
195
+ instr_budget = instr_budget or DEFAULT_BUDGET
196
+ pending_async = {}
197
+ local env = ensure_env(slot_key)
198
+ local f, load_err = load(source, "@" .. tostring(slot_key), "t", env)
199
+ if not f then
200
+ error(load_err or "load failed", 0)
201
+ end
202
+ local count = 0
203
+ if debug_lib and debug_lib.sethook then
204
+ debug_lib.sethook(function()
205
+ count = count + HOOK_STEP
206
+ if count > instr_budget then
207
+ debug_lib.sethook()
208
+ error("microverse: instruction limit exceeded", 0)
209
+ end
210
+ end, "", HOOK_STEP)
211
+ end
212
+ local ok, result = pcall(f)
213
+ if debug_lib and debug_lib.sethook then
214
+ debug_lib.sethook()
215
+ end
216
+ flush_pending_async()
217
+ if not ok then
218
+ error(result, 0)
219
+ end
220
+ return result
221
+ end
222
+
223
+ function __microverse_lua_destroy_slot(slot_key)
224
+ envs[slot_key] = nil
225
+ end
226
+ end
227
+ `.trim();
228
+ //#endregion
229
+ //#region src/infrastructure/runtime/luaLongString.ts
230
+ /** Builds a Lua long literal `[=*[ ... ]=*]` so `source` can contain `]`, newlines, etc. */
231
+ function toLuaLongStringLiteral(source) {
232
+ let eq = 0;
233
+ while (true) {
234
+ const close = `]${"=".repeat(eq)}]`;
235
+ if (!source.includes(close)) break;
236
+ eq += 1;
237
+ }
238
+ return `${`[${"=".repeat(eq)}[`}${source}${`]${"=".repeat(eq)}]`}`;
239
+ }
240
+ //#endregion
241
+ //#region src/infrastructure/runtime/wasmoonExecutePolicy.ts
242
+ var MICROVERSE_LUA_DEFAULT_MAX_SCRIPT_CHARS = 512e3;
243
+ var schedulerHost = () => globalThis;
244
+ var scheduleTimeout = (fn, ms) => {
245
+ const host = schedulerHost();
246
+ if (typeof host.setTimeout !== "function") throw new Error("microverse: setTimeout is not available in this runtime");
247
+ return host.setTimeout(fn, ms);
248
+ };
249
+ var cancelTimeout = (handle) => {
250
+ const host = schedulerHost();
251
+ if (typeof host.clearTimeout === "function") host.clearTimeout(handle);
252
+ };
253
+ var MicroverseTimeoutError = class extends Error {
254
+ constructor() {
255
+ super("microverse: execution timed out");
256
+ this.name = "MicroverseTimeoutError";
257
+ }
258
+ };
259
+ function resolveTimeoutMs(timeout) {
260
+ if (timeout === void 0 || timeout.kind === "none") return;
261
+ return timeout.milliseconds;
262
+ }
263
+ function assertScriptSize(script, maxChars) {
264
+ if (script.length > maxChars) throw new Error(`microverse: script exceeds max size (${script.length} > ${maxChars})`);
265
+ }
266
+ function assertNotCancelled(cancellation) {
267
+ if (cancellation.isCancelled()) throw new Error("microverse: execution cancelled");
268
+ }
269
+ /**
270
+ * Runs an async Lua invocation with optional wall-clock timeout.
271
+ * Note: synchronous infinite Lua still blocks the thread until the instruction hook fires;
272
+ * callers should combine with {@link MICROVERSE_LUA_DEFAULT_INSTRUCTION_BUDGET} in the bootstrap.
273
+ */
274
+ async function runWithWallClockTimeout(run, timeoutMs) {
275
+ if (timeoutMs === void 0) {
276
+ await run();
277
+ return "ok";
278
+ }
279
+ let timer;
280
+ try {
281
+ await Promise.race([run(), new Promise((_, reject) => {
282
+ timer = scheduleTimeout(() => reject(new MicroverseTimeoutError()), timeoutMs);
283
+ })]);
284
+ return "ok";
285
+ } catch (e) {
286
+ if (e instanceof MicroverseTimeoutError) return "timeout";
287
+ throw e;
288
+ } finally {
289
+ if (timer !== void 0) cancelTimeout(timer);
290
+ }
291
+ }
292
+ function mapExecuteError(e) {
293
+ if (e instanceof MicroverseTimeoutError) return { _tag: "Timeout" };
294
+ const message = e instanceof Error ? e.message : String(e);
295
+ if (message.includes("execution cancelled")) return { _tag: "Cancelled" };
296
+ if (message.includes("instruction limit exceeded") || message.includes("script exceeds max size")) return {
297
+ _tag: "AdapterError",
298
+ message
299
+ };
300
+ return {
301
+ _tag: "AdapterError",
302
+ message
303
+ };
304
+ }
305
+ //#endregion
306
+ //#region src/infrastructure/runtime/WasmoonRuntimeAdapter.ts
307
+ var WasmoonRuntimeAdapter = class {
308
+ options;
309
+ factory = new LuaFactory();
310
+ maxScriptChars;
311
+ defaultInstructionBudget;
312
+ engineInit;
313
+ constructor(options = {}) {
314
+ this.options = options;
315
+ this.maxScriptChars = options.maxScriptChars ?? 512e3;
316
+ this.defaultInstructionBudget = options.defaultInstructionBudget ?? 5e6;
317
+ }
318
+ getEngine = () => {
319
+ if (this.engineInit === void 0) this.engineInit = (async () => {
320
+ const lua = await this.factory.createEngine({ injectObjects: true });
321
+ await lua.doString(MICROVERSE_LUA_SLOT_VM_BOOTSTRAP);
322
+ return lua;
323
+ })();
324
+ return this.engineInit;
325
+ };
326
+ resetEngine = async () => {
327
+ const current = this.engineInit;
328
+ this.engineInit = void 0;
329
+ if (current === void 0) return;
330
+ const lua = await current.catch(() => void 0);
331
+ if (lua !== void 0) try {
332
+ await Promise.resolve(lua.global.close());
333
+ } catch {}
334
+ };
335
+ runLua = async (lua, chunk) => {
336
+ await lua.doString(chunk);
337
+ };
338
+ execute = async (ctx, input) => {
339
+ try {
340
+ assertNotCancelled(ctx.cancellation);
341
+ assertScriptSize(String(input.script), this.maxScriptChars);
342
+ } catch (e) {
343
+ return err(mapExecuteError(e));
344
+ }
345
+ const timeoutMs = resolveTimeoutMs(input.timeout);
346
+ const budget = this.defaultInstructionBudget;
347
+ const runOnce = async () => {
348
+ const lua = await this.getEngine();
349
+ const slotLit = toLuaLongStringLiteral(String(ctx.microverseId));
350
+ const merge = input.mergeEnv;
351
+ if (merge !== void 0 && Object.keys(merge).length > 0) for (const name of Object.keys(merge)) {
352
+ if (!Object.prototype.hasOwnProperty.call(merge, name)) continue;
353
+ const tmp = `__microverse_lua_one_${randomMicroverseToken()}`;
354
+ lua.global.set(tmp, merge[name]);
355
+ const putChunk = `__microverse_lua_put_bridge_from_global(${slotLit}, ${toLuaLongStringLiteral(name)}, ${toLuaLongStringLiteral(tmp)})`;
356
+ if (await runWithWallClockTimeout(() => this.runLua(lua, putChunk), timeoutMs) === "timeout") {
357
+ await this.resetEngine();
358
+ return err({ _tag: "Timeout" });
359
+ }
360
+ }
361
+ const execChunk = `__microverse_lua_execute_in_slot(${slotLit}, ${toLuaLongStringLiteral(String(input.script))}, ${budget})`;
362
+ if (await runWithWallClockTimeout(() => this.runLua(lua, execChunk), timeoutMs) === "timeout") {
363
+ await this.resetEngine();
364
+ return err({ _tag: "Timeout" });
365
+ }
366
+ return ok({ output: "lua_ok" });
367
+ };
368
+ try {
369
+ return await runOnce();
370
+ } catch (e) {
371
+ const mapped = mapExecuteError(e);
372
+ if (mapped._tag === "AdapterError" && mapped.message.includes("instruction limit exceeded")) await this.resetEngine();
373
+ return err(mapped);
374
+ }
375
+ };
376
+ disposeMicroverse = async (microverseId) => {
377
+ if (this.engineInit === void 0) return;
378
+ const lua = await this.engineInit.catch(() => void 0);
379
+ if (lua === void 0) return;
380
+ const slotLit = toLuaLongStringLiteral(String(microverseId));
381
+ try {
382
+ await lua.doString(`__microverse_lua_destroy_slot(${slotLit})`);
383
+ } catch {}
384
+ };
385
+ };
386
+ function randomMicroverseToken() {
387
+ const g = globalThis;
388
+ if (g.crypto?.randomUUID) return g.crypto.randomUUID();
389
+ return Math.random().toString(16).slice(2);
390
+ }
391
+ //#endregion
392
+ //#region src/infrastructure/runtime/createWasmMicroverseRuntime.ts
393
+ /**
394
+ * Wasmoon-backed {@link MicroverseRuntime} with hardened slot bootstrap (safe globals, instruction budget).
395
+ */
396
+ function createWasmMicroverseRuntime(options = {}) {
397
+ const { defaultTimeout, ...adapterOptions } = options;
398
+ return createStubMicroverseRuntime({
399
+ adapter: new WasmoonRuntimeAdapter(adapterOptions),
400
+ logger: new ConsoleLogger(),
401
+ defaultTimeout
402
+ });
403
+ }
404
+ //#endregion
405
+ //#region src/infrastructure/worker/WorkerMicroverseHost.ts
406
+ var WorkerMicroverseHost = class {
407
+ last = null;
408
+ post = (message) => {
409
+ this.last = { _tag: "ready" };
410
+ };
411
+ drain = () => {
412
+ const v = this.last;
413
+ this.last = null;
414
+ return v === null ? void 0 : v;
415
+ };
416
+ };
417
+ //#endregion
418
+ export { MICROVERSE_LUA_DEFAULT_INSTRUCTION_BUDGET, MICROVERSE_LUA_DEFAULT_MAX_SCRIPT_CHARS, MICROVERSE_LUA_SLOT_VM_BOOTSTRAP, WasmoonRuntimeAdapter, WorkerMicroverseHost, createWasmMicroverseRuntime };
419
+
420
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/infrastructure/runtime/microverseLuaSlotVmBootstrap.ts","../src/infrastructure/runtime/luaLongString.ts","../src/infrastructure/runtime/wasmoonExecutePolicy.ts","../src/infrastructure/runtime/WasmoonRuntimeAdapter.ts","../src/infrastructure/runtime/createWasmMicroverseRuntime.ts","../src/infrastructure/worker/WorkerMicroverseHost.ts"],"sourcesContent":["/**\n * Lua 5.4 bootstrap for **one Wasmoon VM, many slots**:\n * - Slot `_ENV` uses a **safe global** table (no `debug`, `load`, `io`, `os`, …).\n * - Slot registry and internals are **closure-local** (not on `_G`).\n * - Bridge tables are **read-only** from Lua (`__newindex`); host re-injects via `mergeEnv` each run.\n * - **No auto-await**: async bridges return a handle with `:await()`; optional 2nd-arg callback runs after the current chunk step.\n * - Optional **instruction budget** per chunk via `debug.sethook` when available.\n */\nexport const MICROVERSE_LUA_DEFAULT_INSTRUCTION_BUDGET = 5_000_000;\n\nexport const MICROVERSE_LUA_SLOT_VM_BOOTSTRAP = `\ndo\n local REAL_G = _G\n local envs = {}\n local pending_async = {}\n\n local function copy_functions(lib)\n if type(lib) ~= \"table\" then return nil end\n local out = {}\n for k, v in pairs(lib) do\n if type(v) == \"function\" then\n out[k] = v\n end\n end\n return out\n end\n\n local function copy_math()\n local src = REAL_G.math\n if type(src) ~= \"table\" then return {} end\n local blocked = { random = true, randomseed = true }\n local out = {}\n for k, v in pairs(src) do\n if type(v) == \"function\" and not blocked[k] then\n out[k] = v\n end\n end\n return out\n end\n\n local SAFE_G = {\n assert = assert,\n error = error,\n getmetatable = getmetatable,\n ipairs = ipairs,\n next = next,\n pairs = pairs,\n pcall = pcall,\n rawequal = rawequal,\n rawget = rawget,\n rawlen = rawlen,\n rawset = rawset,\n select = select,\n setmetatable = setmetatable,\n tonumber = tonumber,\n tostring = tostring,\n type = type,\n xpcall = xpcall,\n table = copy_functions(REAL_G.table),\n string = copy_functions(REAL_G.string),\n math = copy_math(),\n _VERSION = REAL_G._VERSION,\n }\n\n local ENV_MT = { __index = SAFE_G }\n\n local function ensure_env(slot_key)\n local e = envs[slot_key]\n if not e then\n e = {}\n setmetatable(e, ENV_MT)\n envs[slot_key] = e\n end\n return e\n end\n\n local debug_lib = REAL_G.debug\n local DEFAULT_BUDGET = ${MICROVERSE_LUA_DEFAULT_INSTRUCTION_BUDGET}\n local HOOK_STEP = 10000\n\n local function is_awaitable(r)\n if type(r) == \"userdata\" or type(r) == \"table\" then\n return type(r.await) == \"function\"\n end\n return false\n end\n\n function __microverse_lua_await_value(r)\n if not is_awaitable(r) then\n return r\n end\n local ok, out = pcall(function()\n return r:await()\n end)\n if not ok then\n error(out, 0)\n end\n return out\n end\n\n function __microverse_lua_wrap_async_result(r)\n if not is_awaitable(r) then\n return r\n end\n return setmetatable({}, {\n __index = function(_, key)\n if key == \"await\" then\n return function()\n return __microverse_lua_await_value(r)\n end\n end\n return nil\n end,\n })\n end\n\n local function is_lua_callback(v)\n return type(v) == \"function\"\n end\n\n local function schedule_on_complete(onComplete, r)\n pending_async[#pending_async + 1] = { cb = onComplete, r = r }\n end\n\n local function flush_pending_async()\n for i = 1, #pending_async do\n local job = pending_async[i]\n local out = __microverse_lua_await_value(job.r)\n job.cb(out)\n end\n end\n\n local function proxy_bridge(impl)\n return setmetatable({}, {\n __index = function(_, method)\n local f = impl[method]\n if type(f) ~= \"function\" then\n return nil\n end\n return function(...)\n local n = select(\"#\", ...)\n local onComplete = nil\n local payload\n if n >= 3 and is_lua_callback(select(3, ...)) then\n onComplete = select(3, ...)\n payload = select(2, ...)\n elseif n >= 2 and is_lua_callback(select(2, ...)) then\n onComplete = select(2, ...)\n payload = select(1, ...)\n elseif n >= 2 then\n payload = select(2, ...)\n elseif n >= 1 then\n payload = select(1, ...)\n end\n local r\n if onComplete ~= nil then\n if payload ~= nil then\n r = f(impl, payload)\n else\n r = f(impl)\n end\n schedule_on_complete(onComplete, r)\n return nil\n end\n if payload ~= nil then\n r = f(impl, payload)\n elseif n == 0 then\n r = f(impl)\n else\n r = f(impl, select(1, ...))\n end\n return __microverse_lua_wrap_async_result(r)\n end\n end,\n __newindex = function(_, key)\n error(\"microverse: bridge table is read-only (\" .. tostring(key) .. \")\", 2)\n end,\n })\n end\n\n function __microverse_lua_put_bridge_from_global(slot_key, field_name, global_tmp_key)\n local e = ensure_env(slot_key)\n local v = REAL_G[global_tmp_key]\n REAL_G[global_tmp_key] = nil\n if type(v) == \"userdata\" or type(v) == \"table\" then\n v = proxy_bridge(v)\n end\n rawset(e, field_name, v)\n end\n\n function __microverse_lua_execute_in_slot(slot_key, source, instr_budget)\n instr_budget = instr_budget or DEFAULT_BUDGET\n pending_async = {}\n local env = ensure_env(slot_key)\n local f, load_err = load(source, \"@\" .. tostring(slot_key), \"t\", env)\n if not f then\n error(load_err or \"load failed\", 0)\n end\n local count = 0\n if debug_lib and debug_lib.sethook then\n debug_lib.sethook(function()\n count = count + HOOK_STEP\n if count > instr_budget then\n debug_lib.sethook()\n error(\"microverse: instruction limit exceeded\", 0)\n end\n end, \"\", HOOK_STEP)\n end\n local ok, result = pcall(f)\n if debug_lib and debug_lib.sethook then\n debug_lib.sethook()\n end\n flush_pending_async()\n if not ok then\n error(result, 0)\n end\n return result\n end\n\n function __microverse_lua_destroy_slot(slot_key)\n envs[slot_key] = nil\n end\nend\n`.trim();\n","/** Builds a Lua long literal `[=*[ ... ]=*]` so `source` can contain `]`, newlines, etc. */\nexport function toLuaLongStringLiteral(source: string): string {\n let eq = 0;\n while (true) {\n const close = `]${'='.repeat(eq)}]`;\n if (!source.includes(close)) {\n break;\n }\n eq += 1;\n }\n const open = `[${'='.repeat(eq)}[`;\n const shut = `]${'='.repeat(eq)}]`;\n return `${open}${source}${shut}`;\n}\n","import type { CancellationToken, TimeoutPolicy } from '@microverse.ts/runtime-core';\n\nexport const MICROVERSE_LUA_DEFAULT_MAX_SCRIPT_CHARS = 512_000;\n\ntype SchedulerHost = {\n setTimeout(callback: () => void, ms: number): unknown;\n clearTimeout(handle: unknown): void;\n};\n\ntype TimerHandle = unknown;\n\n// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- globalThis lacks SchedulerHost in lib.dom\nconst schedulerHost = (): SchedulerHost => globalThis as unknown as SchedulerHost;\n\nconst scheduleTimeout = (fn: () => void, ms: number): TimerHandle => {\n const host = schedulerHost();\n if (typeof host.setTimeout !== 'function') {\n throw new Error('microverse: setTimeout is not available in this runtime');\n }\n return host.setTimeout(fn, ms);\n};\n\nconst cancelTimeout = (handle: TimerHandle): void => {\n const host = schedulerHost();\n if (typeof host.clearTimeout === 'function') {\n host.clearTimeout(handle);\n }\n};\n\nclass MicroverseTimeoutError extends Error {\n constructor() {\n super('microverse: execution timed out');\n this.name = 'MicroverseTimeoutError';\n }\n}\n\nexport function resolveTimeoutMs(timeout: TimeoutPolicy | undefined): number | undefined {\n if (timeout === undefined || timeout.kind === 'none') {\n return undefined;\n }\n return timeout.milliseconds;\n}\n\nexport function assertScriptSize(script: string, maxChars: number): void {\n if (script.length > maxChars) {\n throw new Error(`microverse: script exceeds max size (${script.length} > ${maxChars})`);\n }\n}\n\nexport function assertNotCancelled(cancellation: CancellationToken): void {\n if (cancellation.isCancelled()) {\n throw new Error('microverse: execution cancelled');\n }\n}\n\n/**\n * Runs an async Lua invocation with optional wall-clock timeout.\n * Note: synchronous infinite Lua still blocks the thread until the instruction hook fires;\n * callers should combine with {@link MICROVERSE_LUA_DEFAULT_INSTRUCTION_BUDGET} in the bootstrap.\n */\nexport async function runWithWallClockTimeout(\n run: () => Promise<void>,\n timeoutMs: number | undefined,\n): Promise<'ok' | 'timeout'> {\n if (timeoutMs === undefined) {\n await run();\n return 'ok';\n }\n // TimerHandle is intentionally opaque (`unknown`).\n // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents -- explicit optional slot\n let timer: TimerHandle | undefined;\n try {\n await Promise.race([\n run(),\n new Promise<never>((_, reject) => {\n timer = scheduleTimeout(() => reject(new MicroverseTimeoutError()), timeoutMs);\n }),\n ]);\n return 'ok';\n } catch (e) {\n if (e instanceof MicroverseTimeoutError) {\n return 'timeout';\n }\n throw e;\n } finally {\n if (timer !== undefined) {\n cancelTimeout(timer);\n }\n }\n}\n\nexport function mapExecuteError(e: unknown): { readonly _tag: 'Timeout' } | { readonly _tag: 'Cancelled' } | { readonly _tag: 'AdapterError'; readonly message: string } {\n if (e instanceof MicroverseTimeoutError) {\n return { _tag: 'Timeout' };\n }\n const message = e instanceof Error ? e.message : String(e);\n if (message.includes('execution cancelled')) {\n return { _tag: 'Cancelled' };\n }\n if (message.includes('instruction limit exceeded') || message.includes('script exceeds max size')) {\n return { _tag: 'AdapterError', message };\n }\n return { _tag: 'AdapterError', message };\n}\n","import { err, ok, type Result } from '@microverse.ts/shared';\nimport { LuaFactory } from 'wasmoon';\n\nimport type {\n ExecutionContext,\n ExecutionFailure,\n RuntimeAdapter,\n RunScriptInput,\n RunScriptResult,\n MicroverseId,\n} from '@microverse.ts/runtime-core';\n\nimport {\n MICROVERSE_LUA_DEFAULT_INSTRUCTION_BUDGET,\n MICROVERSE_LUA_SLOT_VM_BOOTSTRAP,\n} from './microverseLuaSlotVmBootstrap';\nimport { toLuaLongStringLiteral } from './luaLongString';\nimport {\n assertNotCancelled,\n assertScriptSize,\n MICROVERSE_LUA_DEFAULT_MAX_SCRIPT_CHARS,\n mapExecuteError,\n resolveTimeoutMs,\n runWithWallClockTimeout,\n} from './wasmoonExecutePolicy';\n\ntype WasmoonLuaEngine = Awaited<ReturnType<LuaFactory['createEngine']>>;\n\nexport type WasmoonRuntimeAdapterOptions = {\n /** Rejects {@link RunScriptInput.script} larger than this (default {@link MICROVERSE_LUA_DEFAULT_MAX_SCRIPT_CHARS}). */\n readonly maxScriptChars?: number | undefined;\n /** Passed to `__microverse_lua_execute_in_slot` when the third argument is omitted (default {@link MICROVERSE_LUA_DEFAULT_INSTRUCTION_BUDGET}). */\n readonly defaultInstructionBudget?: number | undefined;\n};\n\nexport class WasmoonRuntimeAdapter implements RuntimeAdapter {\n private readonly factory = new LuaFactory();\n\n private readonly maxScriptChars: number;\n\n private readonly defaultInstructionBudget: number;\n\n private engineInit: Promise<WasmoonLuaEngine> | undefined;\n\n constructor(private readonly options: WasmoonRuntimeAdapterOptions = {}) {\n this.maxScriptChars = options.maxScriptChars ?? MICROVERSE_LUA_DEFAULT_MAX_SCRIPT_CHARS;\n this.defaultInstructionBudget =\n options.defaultInstructionBudget ?? MICROVERSE_LUA_DEFAULT_INSTRUCTION_BUDGET;\n }\n\n private getEngine = (): Promise<WasmoonLuaEngine> => {\n if (this.engineInit === undefined) {\n this.engineInit = (async () => {\n const lua = await this.factory.createEngine({ injectObjects: true });\n await lua.doString(MICROVERSE_LUA_SLOT_VM_BOOTSTRAP);\n return lua;\n })();\n }\n return this.engineInit;\n };\n\n private resetEngine = async (): Promise<void> => {\n const current = this.engineInit;\n this.engineInit = undefined;\n if (current === undefined) {\n return;\n }\n const lua = await current.catch(() => undefined);\n if (lua !== undefined) {\n try {\n await Promise.resolve(lua.global.close());\n } catch {\n // ignore\n }\n }\n };\n\n private runLua = async (lua: WasmoonLuaEngine, chunk: string): Promise<void> => {\n await lua.doString(chunk);\n };\n\n readonly execute = async (\n ctx: ExecutionContext,\n input: RunScriptInput,\n ): Promise<Result<RunScriptResult, ExecutionFailure>> => {\n try {\n assertNotCancelled(ctx.cancellation);\n assertScriptSize(String(input.script), this.maxScriptChars);\n } catch (e) {\n return err(mapExecuteError(e));\n }\n\n const timeoutMs = resolveTimeoutMs(input.timeout);\n const budget = this.defaultInstructionBudget;\n\n const runOnce = async (): Promise<Result<RunScriptResult, ExecutionFailure>> => {\n const lua = await this.getEngine();\n const slotLit = toLuaLongStringLiteral(String(ctx.microverseId));\n const merge = input.mergeEnv;\n if (merge !== undefined && Object.keys(merge).length > 0) {\n for (const name of Object.keys(merge)) {\n if (!Object.prototype.hasOwnProperty.call(merge, name)) {\n continue;\n }\n const tmp = `__microverse_lua_one_${randomMicroverseToken()}`;\n lua.global.set(tmp, merge[name]);\n const nameLit = toLuaLongStringLiteral(name);\n const tmpLit = toLuaLongStringLiteral(tmp);\n const putChunk = `__microverse_lua_put_bridge_from_global(${slotLit}, ${nameLit}, ${tmpLit})`;\n const putOutcome = await runWithWallClockTimeout(() => this.runLua(lua, putChunk), timeoutMs);\n if (putOutcome === 'timeout') {\n await this.resetEngine();\n return err({ _tag: 'Timeout' });\n }\n }\n }\n const srcLit = toLuaLongStringLiteral(String(input.script));\n const execChunk = `__microverse_lua_execute_in_slot(${slotLit}, ${srcLit}, ${budget})`;\n const execOutcome = await runWithWallClockTimeout(() => this.runLua(lua, execChunk), timeoutMs);\n if (execOutcome === 'timeout') {\n await this.resetEngine();\n return err({ _tag: 'Timeout' });\n }\n return ok({ output: 'lua_ok' });\n };\n\n try {\n return await runOnce();\n } catch (e) {\n const mapped = mapExecuteError(e);\n if (mapped._tag === 'AdapterError' && mapped.message.includes('instruction limit exceeded')) {\n await this.resetEngine();\n }\n return err(mapped);\n }\n };\n\n readonly disposeMicroverse = async (microverseId: MicroverseId): Promise<void> => {\n if (this.engineInit === undefined) {\n return;\n }\n const lua = await this.engineInit.catch(() => undefined);\n if (lua === undefined) {\n return;\n }\n const slotLit = toLuaLongStringLiteral(String(microverseId));\n try {\n await lua.doString(`__microverse_lua_destroy_slot(${slotLit})`);\n } catch {\n // ignore\n }\n };\n}\n\nfunction randomMicroverseToken(): string {\n const g = globalThis as typeof globalThis & { crypto?: { randomUUID?: () => string } };\n if (g.crypto?.randomUUID) {\n return g.crypto.randomUUID();\n }\n return Math.random().toString(16).slice(2);\n}\n","import {\n ConsoleLogger,\n createStubMicroverseRuntime,\n type MicroverseRuntime,\n type TimeoutPolicy,\n} from '@microverse.ts/runtime-core';\n\nimport { WasmoonRuntimeAdapter, type WasmoonRuntimeAdapterOptions } from './WasmoonRuntimeAdapter';\n\nexport type WasmMicroverseRuntimeOptions = WasmoonRuntimeAdapterOptions & {\n /** Default timeout forwarded to each {@link MicroverseSlot.run} when the call omits `timeout`. */\n readonly defaultTimeout?: TimeoutPolicy | undefined;\n};\n\n/**\n * Wasmoon-backed {@link MicroverseRuntime} with hardened slot bootstrap (safe globals, instruction budget).\n */\nexport function createWasmMicroverseRuntime(options: WasmMicroverseRuntimeOptions = {}): MicroverseRuntime {\n const { defaultTimeout, ...adapterOptions } = options;\n return createStubMicroverseRuntime({\n adapter: new WasmoonRuntimeAdapter(adapterOptions),\n logger: new ConsoleLogger(),\n defaultTimeout,\n });\n}\n","import type {\n WorkerHostToRuntimeMessage,\n WorkerRuntimeToHostMessage,\n} from '../../domain/worker/WorkerMicroverseMessages';\n\nexport class WorkerMicroverseHost {\n private last: WorkerRuntimeToHostMessage | null = null;\n\n readonly post = (message: WorkerHostToRuntimeMessage): void => {\n void message;\n this.last = { _tag: 'ready' };\n };\n\n readonly drain = (): WorkerRuntimeToHostMessage | undefined => {\n const v = this.last;\n this.last = null;\n return v === null ? undefined : v;\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { Result } from '@microverse.ts/shared';
2
+ import { ExecutionContext, ExecutionFailure, RuntimeAdapter, RunScriptInput, RunScriptResult, MicroverseId } from '@microverse.ts/runtime-core';
3
+ export type WasmoonRuntimeAdapterOptions = {
4
+ /** Rejects {@link RunScriptInput.script} larger than this (default {@link MICROVERSE_LUA_DEFAULT_MAX_SCRIPT_CHARS}). */
5
+ readonly maxScriptChars?: number | undefined;
6
+ /** Passed to `__microverse_lua_execute_in_slot` when the third argument is omitted (default {@link MICROVERSE_LUA_DEFAULT_INSTRUCTION_BUDGET}). */
7
+ readonly defaultInstructionBudget?: number | undefined;
8
+ };
9
+ export declare class WasmoonRuntimeAdapter implements RuntimeAdapter {
10
+ private readonly options;
11
+ private readonly factory;
12
+ private readonly maxScriptChars;
13
+ private readonly defaultInstructionBudget;
14
+ private engineInit;
15
+ constructor(options?: WasmoonRuntimeAdapterOptions);
16
+ private getEngine;
17
+ private resetEngine;
18
+ private runLua;
19
+ readonly execute: (ctx: ExecutionContext, input: RunScriptInput) => Promise<Result<RunScriptResult, ExecutionFailure>>;
20
+ readonly disposeMicroverse: (microverseId: MicroverseId) => Promise<void>;
21
+ }
22
+ //# sourceMappingURL=WasmoonRuntimeAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WasmoonRuntimeAdapter.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/runtime/WasmoonRuntimeAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAG7D,OAAO,KAAK,EACV,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,eAAe,EACf,YAAY,EACb,MAAM,6BAA6B,CAAC;AAkBrC,MAAM,MAAM,4BAA4B,GAAG;IACzC,wHAAwH;IACxH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,mJAAmJ;IACnJ,QAAQ,CAAC,wBAAwB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxD,CAAC;AAEF,qBAAa,qBAAsB,YAAW,cAAc;IAS9C,OAAO,CAAC,QAAQ,CAAC,OAAO;IARpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAE5C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IAExC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAS;IAElD,OAAO,CAAC,UAAU,CAAwC;gBAE7B,OAAO,GAAE,4BAAiC;IAMvE,OAAO,CAAC,SAAS,CASf;IAEF,OAAO,CAAC,WAAW,CAcjB;IAEF,OAAO,CAAC,MAAM,CAEZ;IAEF,QAAQ,CAAC,OAAO,GACd,KAAK,gBAAgB,EACrB,OAAO,cAAc,KACpB,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,gBAAgB,CAAC,CAAC,CAmDnD;IAEF,QAAQ,CAAC,iBAAiB,GAAU,cAAc,YAAY,KAAG,OAAO,CAAC,IAAI,CAAC,CAc5E;CACH"}
@@ -0,0 +1,11 @@
1
+ import { MicroverseRuntime, TimeoutPolicy } from '@microverse.ts/runtime-core';
2
+ import { WasmoonRuntimeAdapterOptions } from './WasmoonRuntimeAdapter';
3
+ export type WasmMicroverseRuntimeOptions = WasmoonRuntimeAdapterOptions & {
4
+ /** Default timeout forwarded to each {@link MicroverseSlot.run} when the call omits `timeout`. */
5
+ readonly defaultTimeout?: TimeoutPolicy | undefined;
6
+ };
7
+ /**
8
+ * Wasmoon-backed {@link MicroverseRuntime} with hardened slot bootstrap (safe globals, instruction budget).
9
+ */
10
+ export declare function createWasmMicroverseRuntime(options?: WasmMicroverseRuntimeOptions): MicroverseRuntime;
11
+ //# sourceMappingURL=createWasmMicroverseRuntime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createWasmMicroverseRuntime.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/runtime/createWasmMicroverseRuntime.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EACnB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAyB,KAAK,4BAA4B,EAAE,MAAM,yBAAyB,CAAC;AAEnG,MAAM,MAAM,4BAA4B,GAAG,4BAA4B,GAAG;IACxE,kGAAkG;IAClG,QAAQ,CAAC,cAAc,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;CACrD,CAAC;AAEF;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,GAAE,4BAAiC,GAAG,iBAAiB,CAOzG"}
@@ -0,0 +1,3 @@
1
+ /** Builds a Lua long literal `[=*[ ... ]=*]` so `source` can contain `]`, newlines, etc. */
2
+ export declare function toLuaLongStringLiteral(source: string): string;
3
+ //# sourceMappingURL=luaLongString.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"luaLongString.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/runtime/luaLongString.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAY7D"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Lua 5.4 bootstrap for **one Wasmoon VM, many slots**:
3
+ * - Slot `_ENV` uses a **safe global** table (no `debug`, `load`, `io`, `os`, …).
4
+ * - Slot registry and internals are **closure-local** (not on `_G`).
5
+ * - Bridge tables are **read-only** from Lua (`__newindex`); host re-injects via `mergeEnv` each run.
6
+ * - **No auto-await**: async bridges return a handle with `:await()`; optional 2nd-arg callback runs after the current chunk step.
7
+ * - Optional **instruction budget** per chunk via `debug.sethook` when available.
8
+ */
9
+ export declare const MICROVERSE_LUA_DEFAULT_INSTRUCTION_BUDGET = 5000000;
10
+ export declare const MICROVERSE_LUA_SLOT_VM_BOOTSTRAP: string;
11
+ //# sourceMappingURL=microverseLuaSlotVmBootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"microverseLuaSlotVmBootstrap.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/runtime/microverseLuaSlotVmBootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,yCAAyC,UAAY,CAAC;AAEnE,eAAO,MAAM,gCAAgC,QAqNrC,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { CancellationToken, TimeoutPolicy } from '@microverse.ts/runtime-core';
2
+ export declare const MICROVERSE_LUA_DEFAULT_MAX_SCRIPT_CHARS = 512000;
3
+ export declare function resolveTimeoutMs(timeout: TimeoutPolicy | undefined): number | undefined;
4
+ export declare function assertScriptSize(script: string, maxChars: number): void;
5
+ export declare function assertNotCancelled(cancellation: CancellationToken): void;
6
+ /**
7
+ * Runs an async Lua invocation with optional wall-clock timeout.
8
+ * Note: synchronous infinite Lua still blocks the thread until the instruction hook fires;
9
+ * callers should combine with {@link MICROVERSE_LUA_DEFAULT_INSTRUCTION_BUDGET} in the bootstrap.
10
+ */
11
+ export declare function runWithWallClockTimeout(run: () => Promise<void>, timeoutMs: number | undefined): Promise<'ok' | 'timeout'>;
12
+ export declare function mapExecuteError(e: unknown): {
13
+ readonly _tag: 'Timeout';
14
+ } | {
15
+ readonly _tag: 'Cancelled';
16
+ } | {
17
+ readonly _tag: 'AdapterError';
18
+ readonly message: string;
19
+ };
20
+ //# sourceMappingURL=wasmoonExecutePolicy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wasmoonExecutePolicy.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/runtime/wasmoonExecutePolicy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAEpF,eAAO,MAAM,uCAAuC,SAAU,CAAC;AAkC/D,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAKvF;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAIvE;AAED,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,iBAAiB,GAAG,IAAI,CAIxE;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EACxB,SAAS,EAAE,MAAM,GAAG,SAAS,GAC5B,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CA0B3B;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAYvK"}
@@ -0,0 +1,7 @@
1
+ import { WorkerHostToRuntimeMessage, WorkerRuntimeToHostMessage } from '../../domain/worker/WorkerMicroverseMessages';
2
+ export declare class WorkerMicroverseHost {
3
+ private last;
4
+ readonly post: (message: WorkerHostToRuntimeMessage) => void;
5
+ readonly drain: () => WorkerRuntimeToHostMessage | undefined;
6
+ }
7
+ //# sourceMappingURL=WorkerMicroverseHost.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorkerMicroverseHost.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/worker/WorkerMicroverseHost.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,0BAA0B,EAC3B,MAAM,8CAA8C,CAAC;AAEtD,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,IAAI,CAA2C;IAEvD,QAAQ,CAAC,IAAI,GAAI,SAAS,0BAA0B,KAAG,IAAI,CAGzD;IAEF,QAAQ,CAAC,KAAK,QAAO,0BAA0B,GAAG,SAAS,CAIzD;CACH"}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@microverse.ts/runtime-wasm",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "license": "MIT",
6
+ "sideEffects": false,
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/QADRAX/Microverse.ts.git",
10
+ "directory": "packages/runtime-wasm"
11
+ },
12
+ "bugs": "https://github.com/QADRAX/Microverse.ts/issues",
13
+ "homepage": "https://github.com/QADRAX/Microverse.ts/tree/main/packages/runtime-wasm",
14
+ "publishConfig": {
15
+ "access": "public",
16
+ "provenance": true
17
+ },
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js"
22
+ }
23
+ },
24
+ "files": [
25
+ "dist"
26
+ ],
27
+ "dependencies": {
28
+ "wasmoon": "^1.15.0",
29
+ "@microverse.ts/runtime-core": "0.1.0",
30
+ "@microverse.ts/runtime-lua": "0.1.0",
31
+ "@microverse.ts/shared": "0.1.0"
32
+ },
33
+ "devDependencies": {
34
+ "typescript": "^5.8.3",
35
+ "vite": "^8.0.0",
36
+ "vite-plugin-dts": "^4.5.4",
37
+ "vitest": "^3.1.4"
38
+ },
39
+ "scripts": {
40
+ "build": "vite build",
41
+ "lint": "eslint .",
42
+ "test": "vitest run",
43
+ "typecheck": "tsc -p tsconfig.json --noEmit"
44
+ }
45
+ }