@al8b/vm 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/dist/l8bvm.mjs ADDED
@@ -0,0 +1,270 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+
4
+ // src/l8bvm.ts
5
+ import { StorageService } from "@al8b/io";
6
+ import { Routine, Runner } from "@al8b/lootiscript";
7
+
8
+ // src/context.ts
9
+ import { Random } from "@al8b/lootiscript";
10
+ var _baseMeta = {
11
+ round: /* @__PURE__ */ __name((x) => Math.round(x), "round"),
12
+ floor: /* @__PURE__ */ __name((x) => Math.floor(x), "floor"),
13
+ ceil: /* @__PURE__ */ __name((x) => Math.ceil(x), "ceil"),
14
+ abs: /* @__PURE__ */ __name((x) => Math.abs(x), "abs"),
15
+ min: /* @__PURE__ */ __name((x, y) => Math.min(x, y), "min"),
16
+ max: /* @__PURE__ */ __name((x, y) => Math.max(x, y), "max"),
17
+ sqrt: /* @__PURE__ */ __name((x) => Math.sqrt(x), "sqrt"),
18
+ pow: /* @__PURE__ */ __name((x, y) => x ** y, "pow"),
19
+ sin: /* @__PURE__ */ __name((x) => Math.sin(x), "sin"),
20
+ cos: /* @__PURE__ */ __name((x) => Math.cos(x), "cos"),
21
+ tan: /* @__PURE__ */ __name((x) => Math.tan(x), "tan"),
22
+ asin: /* @__PURE__ */ __name((x) => Math.asin(x), "asin"),
23
+ acos: /* @__PURE__ */ __name((x) => Math.acos(x), "acos"),
24
+ atan: /* @__PURE__ */ __name((x) => Math.atan(x), "atan"),
25
+ atan2: /* @__PURE__ */ __name((y, x) => Math.atan2(y, x), "atan2"),
26
+ sind: /* @__PURE__ */ __name((x) => Math.sin(x / 180 * Math.PI), "sind"),
27
+ cosd: /* @__PURE__ */ __name((x) => Math.cos(x / 180 * Math.PI), "cosd"),
28
+ tand: /* @__PURE__ */ __name((x) => Math.tan(x / 180 * Math.PI), "tand"),
29
+ asind: /* @__PURE__ */ __name((x) => Math.asin(x) * 180 / Math.PI, "asind"),
30
+ acosd: /* @__PURE__ */ __name((x) => Math.acos(x) * 180 / Math.PI, "acosd"),
31
+ atand: /* @__PURE__ */ __name((x) => Math.atan(x) * 180 / Math.PI, "atand"),
32
+ atan2d: /* @__PURE__ */ __name((y, x) => Math.atan2(y, x) * 180 / Math.PI, "atan2d"),
33
+ log: /* @__PURE__ */ __name((x) => Math.log(x), "log"),
34
+ exp: /* @__PURE__ */ __name((x) => Math.exp(x), "exp"),
35
+ random: new Random(0),
36
+ PI: Math.PI,
37
+ true: 1,
38
+ false: 0
39
+ };
40
+ var _defaultPrint = /* @__PURE__ */ __name((text) => console.log(text), "_defaultPrint");
41
+ function createVMContext(meta, global) {
42
+ const fullMeta = {
43
+ ..._baseMeta,
44
+ print: meta.print ?? _defaultPrint,
45
+ ...meta
46
+ };
47
+ return {
48
+ meta: fullMeta,
49
+ global,
50
+ local: global,
51
+ object: global,
52
+ breakable: 0,
53
+ continuable: 0,
54
+ returnable: 0,
55
+ stack_size: 0,
56
+ timeout: Date.now() + 3e3,
57
+ warnings: {
58
+ using_undefined_variable: {},
59
+ assigning_field_to_undefined: {},
60
+ invoking_non_function: {},
61
+ assigning_api_variable: {},
62
+ assignment_as_condition: {}
63
+ }
64
+ };
65
+ }
66
+ __name(createVMContext, "createVMContext");
67
+
68
+ // src/extensions.ts
69
+ function setupArrayExtensions() {
70
+ if (!Array.prototype.insert) {
71
+ Array.prototype.insert = function(element) {
72
+ this.splice(0, 0, element);
73
+ return element;
74
+ };
75
+ }
76
+ if (!Array.prototype.insertAt) {
77
+ Array.prototype.insertAt = function(element, index) {
78
+ if (index >= 0 && index < this.length) {
79
+ this.splice(index, 0, element);
80
+ } else {
81
+ this.push(element);
82
+ }
83
+ return element;
84
+ };
85
+ }
86
+ if (!Array.prototype.remove) {
87
+ Array.prototype.remove = function(index) {
88
+ if (index >= 0 && index < this.length) {
89
+ return this.splice(index, 1)[0];
90
+ }
91
+ return 0;
92
+ };
93
+ }
94
+ if (!Array.prototype.removeElement) {
95
+ Array.prototype.removeElement = function(element) {
96
+ const index = this.indexOf(element);
97
+ if (index >= 0) {
98
+ return this.splice(index, 1)[0];
99
+ }
100
+ return 0;
101
+ };
102
+ }
103
+ if (!Array.prototype.contains) {
104
+ Array.prototype.contains = function(element) {
105
+ return this.indexOf(element) >= 0 ? 1 : 0;
106
+ };
107
+ }
108
+ if (!Array.prototype.sortList) {
109
+ Array.prototype.sortList = function(fn) {
110
+ if (fn) {
111
+ return this.sort(fn);
112
+ }
113
+ return this.sort();
114
+ };
115
+ }
116
+ }
117
+ __name(setupArrayExtensions, "setupArrayExtensions");
118
+
119
+ // src/l8bvm.ts
120
+ function extractErrorInfo(err, fallbackFile, fallbackType, runner) {
121
+ const errorMessage = typeof err === "object" && err !== null && "error" in err && typeof err.error === "string" ? err.error : err?.message ?? String(err);
122
+ let stackTrace = err?.stackTrace;
123
+ if (!stackTrace && runner?.main_thread?.processor?.generateStackTrace) {
124
+ stackTrace = runner.main_thread.processor.generateStackTrace();
125
+ }
126
+ return {
127
+ error: errorMessage,
128
+ type: err?.type ?? fallbackType,
129
+ line: err?.line,
130
+ column: err?.column,
131
+ file: err?.file ?? fallbackFile,
132
+ stack: err?.stack,
133
+ stackTrace
134
+ };
135
+ }
136
+ __name(extractErrorInfo, "extractErrorInfo");
137
+ var L8BVM = class {
138
+ static {
139
+ __name(this, "L8BVM");
140
+ }
141
+ context;
142
+ runner;
143
+ storage_service;
144
+ error_info = null;
145
+ constructor(meta = {}, global = {}, namespace = "/l8b", preserve_ls = false) {
146
+ this.context = createVMContext(meta, global);
147
+ this.storage_service = new StorageService(namespace, preserve_ls);
148
+ this.context.global.storage = this.storage_service.getInterface();
149
+ this.runner = new Runner(this);
150
+ this.runner.init();
151
+ setupArrayExtensions();
152
+ }
153
+ /**
154
+ * Run source code
155
+ *
156
+ * Compiles and executes a string of LootiScript code.
157
+ *
158
+ * @param {string} source - The source code to execute
159
+ * @param {number} [timeout=3000] - Execution time limit in ms
160
+ * @param {string} [filename=""] - Filename for error reporting
161
+ * @returns {any} The result of the last statement execution
162
+ * @throws {ErrorInfo} If compilation or execution fails
163
+ */
164
+ run(source, timeout = 3e3, filename = "") {
165
+ this.error_info = null;
166
+ this.context.timeout = Date.now() + timeout;
167
+ this.context.stack_size = 0;
168
+ try {
169
+ const result = this.runner.run(source, filename);
170
+ this.storage_service.check();
171
+ if (result !== null && result !== void 0) {
172
+ return this.runner.toString(result);
173
+ }
174
+ return null;
175
+ } catch (err) {
176
+ this.error_info = extractErrorInfo(err, filename, "runtime", this.runner);
177
+ throw err;
178
+ }
179
+ }
180
+ /**
181
+ * Call a global function
182
+ *
183
+ * Executes a specific function defined in the global scope.
184
+ * Useful for game loop hooks (update, draw) or event handlers.
185
+ *
186
+ * @param {string} name - Name of the function to call
187
+ * @param {any[]} [args=[]] - Arguments to pass to the function
188
+ * @param {number} [timeout=3000] - Execution time limit in ms
189
+ * @returns {any} The return value of the function
190
+ * @throws {ErrorInfo} If the function doesn't exist or execution fails
191
+ */
192
+ call(name, args = [], timeout = 3e3) {
193
+ this.error_info = null;
194
+ this.context.timeout = Date.now() + timeout;
195
+ this.context.stack_size = 0;
196
+ try {
197
+ const result = this.runner.call(name, ...args);
198
+ this.storage_service.check();
199
+ return result;
200
+ } catch (err) {
201
+ this.error_info = extractErrorInfo(err, name, "call", this.runner);
202
+ throw err;
203
+ }
204
+ }
205
+ /**
206
+ * Load a pre-compiled routine (for production builds)
207
+ *
208
+ * Loads bytecode directly into the VM, bypassing the compilation step.
209
+ * Used in production to improve startup time and obfuscate source.
210
+ *
211
+ * @param {any} routineData - Either a Routine instance or serialized JSON
212
+ * @param {string} [filename=""] - Name of the file for error reporting
213
+ * @throws {ErrorInfo} If loading fails
214
+ */
215
+ loadRoutine(routineData, filename = "") {
216
+ this.error_info = null;
217
+ try {
218
+ let routine;
219
+ if (routineData instanceof Routine) {
220
+ routine = routineData;
221
+ } else {
222
+ routine = new Routine(0).import(normalizeSerializedRoutine(routineData));
223
+ }
224
+ this.runner.main_thread.addCall(routine);
225
+ this.runner.tick();
226
+ } catch (err) {
227
+ this.error_info = extractErrorInfo(err, filename, "compile");
228
+ throw err;
229
+ }
230
+ }
231
+ /**
232
+ * Clear warnings
233
+ */
234
+ clearWarnings() {
235
+ this.context.warnings = {
236
+ using_undefined_variable: {},
237
+ assigning_field_to_undefined: {},
238
+ invoking_non_function: {},
239
+ assigning_api_variable: {},
240
+ assignment_as_condition: {}
241
+ };
242
+ }
243
+ /**
244
+ * Get warnings
245
+ */
246
+ getWarnings() {
247
+ return this.context.warnings || {};
248
+ }
249
+ /**
250
+ * Convert value to string (for printing)
251
+ */
252
+ toString(value) {
253
+ return this.runner.toString(value);
254
+ }
255
+ };
256
+ function normalizeSerializedRoutine(routineData) {
257
+ if (isCompiledModuleArtifact(routineData)) {
258
+ return routineData.routine;
259
+ }
260
+ return routineData;
261
+ }
262
+ __name(normalizeSerializedRoutine, "normalizeSerializedRoutine");
263
+ function isCompiledModuleArtifact(value) {
264
+ return typeof value === "object" && value !== null && "format" in value && value.format === "l8b-compiled-routine" && "routine" in value;
265
+ }
266
+ __name(isCompiledModuleArtifact, "isCompiledModuleArtifact");
267
+ export {
268
+ L8BVM
269
+ };
270
+ //# sourceMappingURL=l8bvm.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/l8bvm.ts","../src/context.ts","../src/extensions.ts"],"sourcesContent":["/**\n * L8BVM - Virtual Machine wrapper for lootiscript\n *\n * High-level interface for the LootiScript virtual machine.\n * Wraps the core Compiler, Processor, and Runner into a usable engine component.\n * Handles context creation, storage persistence, and error formatting.\n *\n * Responsibilities:\n * - Create and manage VM execution context\n * - Provide clean API for running code and calling functions\n * - Handle storage persistence\n * - Format and normalize runtime errors\n *\n * @module vm\n */\n\nimport type { CompiledModuleArtifact, SerializedRoutineData } from \"@al8b/framework-shared\";\nimport { StorageService } from \"@al8b/io\";\nimport { Routine, Runner } from \"@al8b/lootiscript\";\nimport { createVMContext } from \"./context\";\nimport { setupArrayExtensions } from \"./extensions\";\nimport type { ErrorInfo, GlobalAPI, MetaFunctions, VMContext } from \"./types\";\n\n/**\n * Extract normalized ErrorInfo from a caught exception.\n * Centralizes the error-parsing logic shared across run(), call(), and loadRoutine().\n */\nfunction extractErrorInfo(err: any, fallbackFile: string, fallbackType: string, runner?: Runner): ErrorInfo {\n\tconst errorMessage =\n\t\ttypeof err === \"object\" && err !== null && \"error\" in err && typeof err.error === \"string\"\n\t\t\t? err.error\n\t\t\t: err?.message ?? String(err);\n\n\tlet stackTrace = err?.stackTrace;\n\tif (!stackTrace && (runner as any)?.main_thread?.processor?.generateStackTrace) {\n\t\tstackTrace = (runner as any).main_thread.processor.generateStackTrace();\n\t}\n\n\treturn {\n\t\terror: errorMessage,\n\t\ttype: err?.type ?? fallbackType,\n\t\tline: err?.line,\n\t\tcolumn: err?.column,\n\t\tfile: err?.file ?? fallbackFile,\n\t\tstack: err?.stack,\n\t\tstackTrace,\n\t};\n}\n\nexport class L8BVM {\n\tpublic context: VMContext;\n\tpublic runner: Runner;\n\tpublic storage_service: StorageService;\n\tpublic error_info: ErrorInfo | null = null;\n\n\tconstructor(\n\t\tmeta: Partial<MetaFunctions> = {},\n\t\tglobal: Partial<GlobalAPI> = {},\n\t\tnamespace = \"/l8b\",\n\t\tpreserve_ls = false,\n\t) {\n\t\t// Initialize VM execution context with meta functions and global API\n\t\tthis.context = createVMContext(meta, global);\n\n\t\t// Initialize storage service for persistent data (localStorage/sessionStorage)\n\t\tthis.storage_service = new StorageService(namespace, preserve_ls);\n\n\t\t// Inject storage API into global scope for LootiScript access\n\t\tthis.context.global.storage = this.storage_service.getInterface();\n\n\t\t// Create Runner instance with reference to this VM for bidirectional communication\n\t\tthis.runner = new Runner(this as any);\n\n\t\t// Initialize Runner and create main execution thread\n\t\tthis.runner.init();\n\n\t\t// Add custom array methods to Array.prototype for LootiScript\n\t\tsetupArrayExtensions();\n\t}\n\n\t/**\n\t * Run source code\n\t *\n\t * Compiles and executes a string of LootiScript code.\n\t *\n\t * @param {string} source - The source code to execute\n\t * @param {number} [timeout=3000] - Execution time limit in ms\n\t * @param {string} [filename=\"\"] - Filename for error reporting\n\t * @returns {any} The result of the last statement execution\n\t * @throws {ErrorInfo} If compilation or execution fails\n\t */\n\trun(source: string, timeout = 3000, filename = \"\"): any {\n\t\tthis.error_info = null;\n\t\tthis.context.timeout = Date.now() + timeout;\n\t\tthis.context.stack_size = 0;\n\n\t\ttry {\n\t\t\tconst result = this.runner.run(source, filename);\n\t\t\tthis.storage_service.check();\n\n\t\t\tif (result !== null && result !== undefined) {\n\t\t\t\treturn this.runner.toString(result);\n\t\t\t}\n\t\t\treturn null;\n\t\t} catch (err: any) {\n\t\t\tthis.error_info = extractErrorInfo(err, filename, \"runtime\", this.runner);\n\t\t\tthrow err;\n\t\t}\n\t}\n\n\t/**\n\t * Call a global function\n\t *\n\t * Executes a specific function defined in the global scope.\n\t * Useful for game loop hooks (update, draw) or event handlers.\n\t *\n\t * @param {string} name - Name of the function to call\n\t * @param {any[]} [args=[]] - Arguments to pass to the function\n\t * @param {number} [timeout=3000] - Execution time limit in ms\n\t * @returns {any} The return value of the function\n\t * @throws {ErrorInfo} If the function doesn't exist or execution fails\n\t */\n\tcall(name: string, args: any[] = [], timeout = 3000): any {\n\t\tthis.error_info = null;\n\t\tthis.context.timeout = Date.now() + timeout;\n\t\tthis.context.stack_size = 0;\n\n\t\ttry {\n\t\t\tconst result = this.runner.call(name, ...args);\n\t\t\tthis.storage_service.check();\n\t\t\treturn result;\n\t\t} catch (err: any) {\n\t\t\tthis.error_info = extractErrorInfo(err, name, \"call\", this.runner);\n\t\t\tthrow err;\n\t\t}\n\t}\n\n\t/**\n\t * Load a pre-compiled routine (for production builds)\n\t *\n\t * Loads bytecode directly into the VM, bypassing the compilation step.\n\t * Used in production to improve startup time and obfuscate source.\n\t *\n\t * @param {any} routineData - Either a Routine instance or serialized JSON\n\t * @param {string} [filename=\"\"] - Name of the file for error reporting\n\t * @throws {ErrorInfo} If loading fails\n\t */\n\tloadRoutine(routineData: any, filename: string = \"\"): void {\n\t\tthis.error_info = null;\n\n\t\ttry {\n\t\t\tlet routine: Routine;\n\n\t\t\t// Handle both Routine instances and serialized routine data\n\t\t\t// Serialized data needs to be imported first\n\t\t\tif (routineData instanceof Routine) {\n\t\t\t\troutine = routineData;\n\t\t\t} else {\n\t\t\t\troutine = new Routine(0).import(normalizeSerializedRoutine(routineData));\n\t\t\t}\n\n\t\t\t// Add to main thread for execution\n\t\t\tthis.runner.main_thread.addCall(routine);\n\t\t\tthis.runner.tick();\n\t\t} catch (err: any) {\n\t\t\tthis.error_info = extractErrorInfo(err, filename, \"compile\");\n\t\t\tthrow err;\n\t\t}\n\t}\n\n\t/**\n\t * Clear warnings\n\t */\n\tclearWarnings(): void {\n\t\tthis.context.warnings = {\n\t\t\tusing_undefined_variable: {},\n\t\t\tassigning_field_to_undefined: {},\n\t\t\tinvoking_non_function: {},\n\t\t\tassigning_api_variable: {},\n\t\t\tassignment_as_condition: {},\n\t\t};\n\t}\n\n\t/**\n\t * Get warnings\n\t */\n\tgetWarnings(): Record<string, any> {\n\t\treturn this.context.warnings || {};\n\t}\n\n\t/**\n\t * Convert value to string (for printing)\n\t */\n\ttoString(value: any): string {\n\t\treturn this.runner.toString(value);\n\t}\n}\n\nfunction normalizeSerializedRoutine(routineData: CompiledModuleArtifact | SerializedRoutineData): SerializedRoutineData {\n\tif (isCompiledModuleArtifact(routineData)) {\n\t\treturn routineData.routine;\n\t}\n\n\treturn routineData;\n}\n\nfunction isCompiledModuleArtifact(value: unknown): value is CompiledModuleArtifact {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"format\" in value &&\n\t\t(value as { format?: unknown }).format === \"l8b-compiled-routine\" &&\n\t\t\"routine\" in value\n\t);\n}\n","/**\n * VM Context creation utilities\n */\n\nimport { Random } from \"@al8b/lootiscript\";\nimport type { GlobalAPI, MetaFunctions, VMContext } from \"./types\";\n\n// Shared math lambdas — allocated once, reused across all VM instances\nconst _baseMeta = {\n\tround: (x: number) => Math.round(x),\n\tfloor: (x: number) => Math.floor(x),\n\tceil: (x: number) => Math.ceil(x),\n\tabs: (x: number) => Math.abs(x),\n\tmin: (x: number, y: number) => Math.min(x, y),\n\tmax: (x: number, y: number) => Math.max(x, y),\n\tsqrt: (x: number) => Math.sqrt(x),\n\tpow: (x: number, y: number) => x ** y,\n\tsin: (x: number) => Math.sin(x),\n\tcos: (x: number) => Math.cos(x),\n\ttan: (x: number) => Math.tan(x),\n\tasin: (x: number) => Math.asin(x),\n\tacos: (x: number) => Math.acos(x),\n\tatan: (x: number) => Math.atan(x),\n\tatan2: (y: number, x: number) => Math.atan2(y, x),\n\tsind: (x: number) => Math.sin((x / 180) * Math.PI),\n\tcosd: (x: number) => Math.cos((x / 180) * Math.PI),\n\ttand: (x: number) => Math.tan((x / 180) * Math.PI),\n\tasind: (x: number) => (Math.asin(x) * 180) / Math.PI,\n\tacosd: (x: number) => (Math.acos(x) * 180) / Math.PI,\n\tatand: (x: number) => (Math.atan(x) * 180) / Math.PI,\n\tatan2d: (y: number, x: number) => (Math.atan2(y, x) * 180) / Math.PI,\n\tlog: (x: number) => Math.log(x),\n\texp: (x: number) => Math.exp(x),\n\trandom: new Random(0),\n\tPI: Math.PI,\n\ttrue: 1 as const,\n\tfalse: 0 as const,\n};\n\nconst _defaultPrint = (text: any) => console.log(text);\n\n/**\n * Create meta functions (built-in functions)\n */\nexport function createMetaFunctions(customPrint?: (text: any) => void): MetaFunctions {\n\treturn {\n\t\t..._baseMeta,\n\t\tprint: customPrint ?? _defaultPrint,\n\t};\n}\n\n/**\n * Create VM context\n */\nexport function createVMContext(meta: Partial<MetaFunctions>, global: Partial<GlobalAPI>): VMContext {\n\tconst fullMeta: MetaFunctions = {\n\t\t..._baseMeta,\n\t\tprint: meta.print ?? _defaultPrint,\n\t\t...meta,\n\t};\n\n\treturn {\n\t\tmeta: fullMeta as MetaFunctions,\n\t\tglobal: global as GlobalAPI,\n\t\tlocal: global,\n\t\tobject: global,\n\t\tbreakable: 0,\n\t\tcontinuable: 0,\n\t\treturnable: 0,\n\t\tstack_size: 0,\n\t\ttimeout: Date.now() + 3000,\n\t\twarnings: {\n\t\t\tusing_undefined_variable: {},\n\t\t\tassigning_field_to_undefined: {},\n\t\t\tinvoking_non_function: {},\n\t\t\tassigning_api_variable: {},\n\t\t\tassignment_as_condition: {},\n\t\t},\n\t};\n}\n","/**\n * Array extensions\n */\n\n/**\n * Setup array extensions\n */\nexport function setupArrayExtensions(): void {\n\t// Insert element at beginning of array (returns the inserted element)\n\tif (!Array.prototype.insert) {\n\t\tArray.prototype.insert = function (element: any) {\n\t\t\tthis.splice(0, 0, element);\n\t\t\treturn element;\n\t\t};\n\t}\n\n\t// Insert element at specific index (returns the inserted element)\n\tif (!Array.prototype.insertAt) {\n\t\tArray.prototype.insertAt = function (element: any, index: number) {\n\t\t\tif (index >= 0 && index < this.length) {\n\t\t\t\tthis.splice(index, 0, element);\n\t\t\t} else {\n\t\t\t\tthis.push(element);\n\t\t\t}\n\t\t\treturn element;\n\t\t};\n\t}\n\n\t// Remove element at index (returns removed element or 0 if out of bounds)\n\tif (!Array.prototype.remove) {\n\t\tArray.prototype.remove = function (index: number) {\n\t\t\tif (index >= 0 && index < this.length) {\n\t\t\t\treturn this.splice(index, 1)[0];\n\t\t\t}\n\t\t\treturn 0;\n\t\t};\n\t}\n\n\t// Remove first occurrence of element (returns removed element or 0 if not found)\n\tif (!Array.prototype.removeElement) {\n\t\tArray.prototype.removeElement = function (element: any) {\n\t\t\tconst index = this.indexOf(element);\n\t\t\tif (index >= 0) {\n\t\t\t\treturn this.splice(index, 1)[0];\n\t\t\t}\n\t\t\treturn 0;\n\t\t};\n\t}\n\n\t// Check if array contains element (returns 1 if found, 0 if not found)\n\tif (!Array.prototype.contains) {\n\t\tArray.prototype.contains = function (element: any) {\n\t\t\treturn this.indexOf(element) >= 0 ? 1 : 0;\n\t\t};\n\t}\n\n\t// Sort array with optional comparator function\n\tif (!Array.prototype.sortList) {\n\t\tArray.prototype.sortList = function (fn?: (a: any, b: any) => number) {\n\t\t\tif (fn) {\n\t\t\t\treturn this.sort(fn);\n\t\t\t}\n\t\t\treturn this.sort();\n\t\t};\n\t}\n}\n\n// TypeScript type declarations for Array prototype extensions\ndeclare global {\n\tinterface Array<T> {\n\t\tinsert(element: T): T;\n\t\tinsertAt(element: T, index: number): T;\n\t\tremove(index: number): T | 0;\n\t\tremoveElement(element: T): T | 0;\n\t\tcontains(element: T): 0 | 1;\n\t\tsortList(fn?: (a: T, b: T) => number): T[];\n\t}\n}\n"],"mappings":"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","names":["StorageService","Routine","Runner","Random","_baseMeta","round","x","Math","floor","ceil","abs","min","y","max","sqrt","pow","sin","cos","tan","asin","acos","atan","atan2","sind","PI","cosd","tand","asind","acosd","atand","atan2d","log","exp","random","Random","true","false","_defaultPrint","text","console","createVMContext","meta","global","fullMeta","_baseMeta","print","_defaultPrint","local","object","breakable","continuable","returnable","stack_size","timeout","Date","now","warnings","using_undefined_variable","assigning_field_to_undefined","invoking_non_function","assigning_api_variable","assignment_as_condition","setupArrayExtensions","Array","prototype","insert","element","splice","insertAt","index","length","push","remove","removeElement","indexOf","contains","sortList","fn","sort","extractErrorInfo","err","fallbackFile","fallbackType","runner","errorMessage","error","message","String","stackTrace","main_thread","processor","generateStackTrace","type","line","column","file","stack","L8BVM","context","storage_service","error_info","meta","global","namespace","preserve_ls","createVMContext","StorageService","storage","getInterface","Runner","init","setupArrayExtensions","run","source","timeout","filename","Date","now","stack_size","result","check","undefined","toString","call","name","args","loadRoutine","routineData","routine","Routine","import","normalizeSerializedRoutine","addCall","tick","clearWarnings","warnings","using_undefined_variable","assigning_field_to_undefined","invoking_non_function","assigning_api_variable","assignment_as_condition","getWarnings","value","isCompiledModuleArtifact","format"]}
@@ -0,0 +1,196 @@
1
+ /**
2
+ * VM related type definitions
3
+ */
4
+ /**
5
+ * Player API exposed to game code - controls player UX
6
+ */
7
+ interface PlayerAPI {
8
+ /** Pause the game loop */
9
+ pause: () => void;
10
+ /** Resume the game loop */
11
+ resume: () => void;
12
+ /** Send a custom message to the host application */
13
+ postMessage: (message: any) => void;
14
+ /** Set target update rate (FPS) */
15
+ setFps: (fps: number) => void;
16
+ /** Current FPS (read-only) */
17
+ readonly fps: number;
18
+ /** Target update rate in Hz (read/write) */
19
+ update_rate: number;
20
+ }
21
+ /**
22
+ * System API exposed to game code - system info and utilities
23
+ */
24
+ interface SystemAPI {
25
+ time: number;
26
+ fps: number;
27
+ cpu_load: number;
28
+ update_rate: number;
29
+ language: string;
30
+ inputs: {
31
+ keyboard: number;
32
+ mouse: number;
33
+ touch: number;
34
+ gamepad: number;
35
+ };
36
+ loading?: number;
37
+ prompt: (text: string, callback: (result: string) => void) => void;
38
+ say: (text: string) => void;
39
+ file: {
40
+ dropped: number;
41
+ };
42
+ javascript: any;
43
+ disable_autofullscreen?: number;
44
+ preemptive?: number;
45
+ threads?: any[];
46
+ }
47
+ /**
48
+ * Storage interface exposed to game code
49
+ */
50
+ interface StorageInterface {
51
+ set: (name: string, value: unknown) => void;
52
+ get: (name: string) => unknown;
53
+ }
54
+ /**
55
+ * Scene interface exposed to game code
56
+ */
57
+ interface SceneInterface {
58
+ register: (name: string, def: Record<string, unknown>) => void;
59
+ route: (path: string, sceneName: string) => void;
60
+ goto: (name: string, params?: Record<string, string>) => void;
61
+ current: () => string | null;
62
+ }
63
+ /**
64
+ * Router interface exposed to game code
65
+ */
66
+ interface RouterInterface {
67
+ navigate: (path: string) => void;
68
+ back: () => void;
69
+ readonly path: string;
70
+ }
71
+ /**
72
+ * Global API exposed to game code
73
+ *
74
+ * Core service fields (screen, audio, keyboard, etc.) use Record<string, any>
75
+ * because they are dynamically populated from different core packages with varying shapes.
76
+ * Helper interfaces above document the expected shape of stable APIs.
77
+ */
78
+ interface GlobalAPI {
79
+ screen: Record<string, any>;
80
+ audio: Record<string, any>;
81
+ keyboard: Record<string, any>;
82
+ mouse: Record<string, any>;
83
+ touch: Record<string, any>;
84
+ gamepad: Record<string, any>;
85
+ sprites: Record<string, any>;
86
+ maps: Record<string, any>;
87
+ sounds: Record<string, any>;
88
+ music: Record<string, any>;
89
+ assets: Record<string, any>;
90
+ storage: Record<string, any>;
91
+ scene: Record<string, any>;
92
+ route: Record<string, any>;
93
+ router: Record<string, any>;
94
+ player: Record<string, any>;
95
+ system: SystemAPI;
96
+ fonts?: Record<string, any>;
97
+ Sound?: any;
98
+ Image?: any;
99
+ Sprite?: any;
100
+ TileMap?: any;
101
+ Palette?: any;
102
+ Random?: any;
103
+ }
104
+ /**
105
+ * Meta functions (built-in functions)
106
+ */
107
+ interface MetaFunctions {
108
+ print: (text: any) => void;
109
+ round: (x: number) => number;
110
+ floor: (x: number) => number;
111
+ ceil: (x: number) => number;
112
+ abs: (x: number) => number;
113
+ min: (x: number, y: number) => number;
114
+ max: (x: number, y: number) => number;
115
+ sqrt: (x: number) => number;
116
+ pow: (x: number, y: number) => number;
117
+ sin: (x: number) => number;
118
+ cos: (x: number) => number;
119
+ tan: (x: number) => number;
120
+ asin: (x: number) => number;
121
+ acos: (x: number) => number;
122
+ atan: (x: number) => number;
123
+ atan2: (y: number, x: number) => number;
124
+ sind: (x: number) => number;
125
+ cosd: (x: number) => number;
126
+ tand: (x: number) => number;
127
+ asind: (x: number) => number;
128
+ acosd: (x: number) => number;
129
+ atand: (x: number) => number;
130
+ atan2d: (y: number, x: number) => number;
131
+ log: (x: number) => number;
132
+ exp: (x: number) => number;
133
+ random: any;
134
+ PI: number;
135
+ true: number;
136
+ false: number;
137
+ }
138
+ /**
139
+ * Warning info for a specific code location
140
+ */
141
+ interface WarningInfo {
142
+ file: string;
143
+ line: number;
144
+ column: number;
145
+ expression?: string;
146
+ identifier?: string;
147
+ reported?: boolean;
148
+ }
149
+ /**
150
+ * Accumulated warnings structure
151
+ */
152
+ interface VMWarnings {
153
+ using_undefined_variable: Record<string, WarningInfo>;
154
+ assigning_field_to_undefined: Record<string, WarningInfo>;
155
+ invoking_non_function: Record<string, WarningInfo>;
156
+ assigning_api_variable: Record<string, WarningInfo>;
157
+ assignment_as_condition: Record<string, WarningInfo>;
158
+ }
159
+ /**
160
+ * VM Context
161
+ */
162
+ interface VMContext {
163
+ meta: MetaFunctions;
164
+ global: GlobalAPI;
165
+ local: any;
166
+ object: any;
167
+ breakable: number;
168
+ continuable: number;
169
+ returnable: number;
170
+ stack_size: number;
171
+ timeout: number;
172
+ warnings: VMWarnings;
173
+ }
174
+ /**
175
+ * Call frame for stack trace
176
+ */
177
+ interface CallFrame {
178
+ functionName: string;
179
+ file: string;
180
+ line: number;
181
+ column: number;
182
+ }
183
+ /**
184
+ * Error information returned by VM
185
+ */
186
+ interface ErrorInfo {
187
+ error: string;
188
+ type?: string;
189
+ line?: number;
190
+ column?: number;
191
+ file?: string;
192
+ stack?: string;
193
+ stackTrace?: CallFrame[];
194
+ }
195
+
196
+ export type { CallFrame, ErrorInfo, GlobalAPI, MetaFunctions, PlayerAPI, RouterInterface, SceneInterface, StorageInterface, SystemAPI, VMContext, VMWarnings, WarningInfo };