@casual-simulation/aux-runtime 3.2.17 → 3.2.18-alpha.8332065024

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.
@@ -14,14 +14,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
14
14
  step((generator = generator.apply(thisArg, _arguments || [])).next());
15
15
  });
16
16
  };
17
- import { hasValue, tagsOnBot, isFormula, isScript, isNumber, BOT_SPACE_TAG, botUpdated, isBot, ORIGINAL_OBJECT, DEFAULT_ENERGY, getBotSpace, ON_ACTION_ACTION_NAME, breakIntoIndividualEvents, ON_BOT_ADDED_ACTION_NAME, ON_ANY_BOTS_ADDED_ACTION_NAME, ON_ANY_BOTS_REMOVED_ACTION_NAME, ON_BOT_CHANGED_ACTION_NAME, ON_ANY_BOTS_CHANGED_ACTION_NAME, updatedBot, TAG_MASK_SPACE_PRIORITIES, CLEAR_CHANGES_SYMBOL, DNA_TAG_PREFIX, isRuntimeBot, createBot, ON_ERROR, action, isBotInDimension, asyncResult, registerBuiltinPortal, defineGlobalBot, isBotLink, parseBotLink, isBotDate, parseBotDate, formatBotDate, isTaggedString, parseTaggedString, parseNumber, isTaggedNumber, isBotVector, parseBotVector, formatBotVector, isBotRotation, parseBotRotation, formatBotRotation, parseTaggedNumber, REPLACE_BOT_SYMBOL, } from '@casual-simulation/aux-common/bots';
17
+ import { hasValue, tagsOnBot, isFormula, isScript, isNumber, BOT_SPACE_TAG, botUpdated, isBot, ORIGINAL_OBJECT, DEFAULT_ENERGY, getBotSpace, ON_ACTION_ACTION_NAME, breakIntoIndividualEvents, ON_BOT_ADDED_ACTION_NAME, ON_ANY_BOTS_ADDED_ACTION_NAME, ON_ANY_BOTS_REMOVED_ACTION_NAME, ON_BOT_CHANGED_ACTION_NAME, ON_ANY_BOTS_CHANGED_ACTION_NAME, updatedBot, TAG_MASK_SPACE_PRIORITIES, CLEAR_CHANGES_SYMBOL, DNA_TAG_PREFIX, isRuntimeBot, createBot, ON_ERROR, action, isBotInDimension, asyncResult, registerBuiltinPortal, defineGlobalBot, isBotLink, parseBotLink, isBotDate, parseBotDate, formatBotDate, isTaggedString, parseTaggedString, parseNumber, isTaggedNumber, isBotVector, parseBotVector, formatBotVector, isBotRotation, parseBotRotation, formatBotRotation, parseTaggedNumber, REPLACE_BOT_SYMBOL, isModule, calculateStringTagValue, ON_RESOLVE_MODULE, } from '@casual-simulation/aux-common/bots';
18
18
  import { Subject, Subscription } from 'rxjs';
19
- import { AuxCompiler, getInterpretableFunction, isInterpretableFunction, } from './AuxCompiler';
19
+ import { AuxCompiler, getInterpretableFunction, isInterpretableFunction, IMPORT_META_FACTORY, IMPORT_FACTORY, EXPORT_FACTORY, } from './AuxCompiler';
20
20
  import { addToContext, MemoryGlobalContext, removeFromContext, isInContext, } from './AuxGlobalContext';
21
21
  import { createDefaultLibrary, GET_RUNTIME, } from './AuxLibrary';
22
22
  import { createRuntimeBot, RealtimeEditMode, } from './RuntimeBot';
23
23
  import { RanOutOfEnergyError, } from './AuxResults';
24
- import { isPromise, isRuntimePromise, markAsRuntimePromise, } from './Utils';
24
+ import { isPromise, isRuntimePromise, isUrl, markAsRuntimePromise, } from './Utils';
25
25
  import { DefaultRealtimeEditModeProvider, } from './AuxRealtimeEditModeProvider';
26
26
  import { sortBy, forOwn, merge, union } from 'lodash';
27
27
  import { applyTagEdit, isTagEdit, } from '@casual-simulation/aux-common/bots';
@@ -29,7 +29,7 @@ import { updateRuntimeVersion, } from './RuntimeStateVersion';
29
29
  import { replaceMacros } from './Transpiler';
30
30
  import { DateTime } from 'luxon';
31
31
  import { Rotation, Vector2, Vector3 } from '@casual-simulation/aux-common/math';
32
- import { isGenerator, UNCOPIABLE, } from '@casual-simulation/js-interpreter/InterpreterUtils';
32
+ import { isGenerator, markAsUncopiableObject, UNCOPIABLE, } from '@casual-simulation/js-interpreter/InterpreterUtils';
33
33
  import { v4 as uuid } from 'uuid';
34
34
  import { importInterpreter as _dynamicImportInterpreter } from './AuxRuntimeDynamicImports';
35
35
  import { UNMAPPABLE } from '@casual-simulation/aux-common/bots/BotEvents';
@@ -85,6 +85,9 @@ export class AuxRuntime {
85
85
  get canTriggerBreakpoint() {
86
86
  return !!this._interpreter && this._interpreter.debugging;
87
87
  }
88
+ get systemMap() {
89
+ return this._systemMap;
90
+ }
88
91
  /**
89
92
  * Creates a new AuxRuntime using the given library factory.
90
93
  * @param libraryFactory
@@ -143,6 +146,15 @@ export class AuxRuntime {
143
146
  this._autoBatch = true;
144
147
  this._forceSyncScripts = false;
145
148
  this._currentDebugger = null;
149
+ /**
150
+ * The map of module IDs to their exports.
151
+ * Only used for global modules, which are modules that are not attached to a bot (e.g. source modules).
152
+ */
153
+ this._cachedGlobalModules = new Map();
154
+ /**
155
+ * The map of system IDs to their respective bot IDs.
156
+ */
157
+ this._systemMap = new Map();
146
158
  /**
147
159
  * The number of times that the runtime can call onError for an error from the same script.
148
160
  */
@@ -235,6 +247,278 @@ export class AuxRuntime {
235
247
  }
236
248
  }
237
249
  }
250
+ _importModule(module, meta, dependencyChain = [], allowCustomResolution = true) {
251
+ return __awaiter(this, void 0, void 0, function* () {
252
+ try {
253
+ let m;
254
+ let bot;
255
+ const allowResolution = meta.tag !== ON_RESOLVE_MODULE && allowCustomResolution;
256
+ if (typeof module !== 'string') {
257
+ m = module;
258
+ if (!m) {
259
+ throw new Error('Module not found: ' + module);
260
+ }
261
+ }
262
+ else {
263
+ const globalModule = this._cachedGlobalModules.get(module);
264
+ if (globalModule) {
265
+ return yield globalModule;
266
+ }
267
+ m = yield this.resolveModule(module, meta, allowResolution);
268
+ if (!m) {
269
+ throw new Error('Module not found: ' + module);
270
+ }
271
+ if (dependencyChain.length > 1) {
272
+ const index = dependencyChain.indexOf(m.id);
273
+ if (index >= 0) {
274
+ throw new Error(`Circular dependency detected: ${dependencyChain
275
+ .slice(index)
276
+ .join(' -> ')} -> ${m.id}`);
277
+ }
278
+ }
279
+ if ('botId' in m) {
280
+ bot = this._compiledState[m.botId];
281
+ if (bot) {
282
+ const exports = bot.exports[m.tag];
283
+ if (exports) {
284
+ return yield exports;
285
+ }
286
+ }
287
+ }
288
+ }
289
+ const promise = this._importModuleCore(m, [...dependencyChain, m.id], allowResolution);
290
+ if (bot) {
291
+ bot.exports[m.tag] = promise;
292
+ }
293
+ else {
294
+ this._cachedGlobalModules.set(m.id, promise);
295
+ }
296
+ return yield promise;
297
+ }
298
+ finally {
299
+ this._scheduleJobQueueCheck();
300
+ }
301
+ });
302
+ }
303
+ _importModuleCore(m, dependencyChain, allowCustomResolution) {
304
+ return __awaiter(this, void 0, void 0, function* () {
305
+ try {
306
+ const exports = {};
307
+ const importFunc = (id, meta) => this._importModule(id, meta, dependencyChain, allowCustomResolution);
308
+ const exportFunc = (valueOrSource, e, meta) => __awaiter(this, void 0, void 0, function* () {
309
+ const result = yield this._resolveExports(valueOrSource, e, meta, dependencyChain, allowCustomResolution);
310
+ this._scheduleJobQueueCheck();
311
+ Object.assign(exports, result);
312
+ });
313
+ if ('botId' in m) {
314
+ const bot = this._compiledState[m.botId];
315
+ const module = bot === null || bot === void 0 ? void 0 : bot.modules[m.tag];
316
+ if (module) {
317
+ yield module.moduleFunc(importFunc, exportFunc);
318
+ }
319
+ }
320
+ else if ('source' in m) {
321
+ const source = m.source;
322
+ const mod = this._compile(null, null, source, {});
323
+ if (mod.moduleFunc) {
324
+ yield mod.moduleFunc(importFunc, exportFunc);
325
+ }
326
+ }
327
+ else if ('exports' in m) {
328
+ Object.assign(exports, m.exports);
329
+ }
330
+ else if ('url' in m) {
331
+ return yield this.dynamicImport(m.url);
332
+ }
333
+ return exports;
334
+ }
335
+ finally {
336
+ this._scheduleJobQueueCheck();
337
+ }
338
+ });
339
+ }
340
+ _resolveExports(valueOrSource, exports, meta, dependencyChain, allowCustomResolution) {
341
+ return __awaiter(this, void 0, void 0, function* () {
342
+ if (typeof valueOrSource === 'string') {
343
+ const sourceModule = yield this._importModule(valueOrSource, meta, dependencyChain, allowCustomResolution);
344
+ if (exports) {
345
+ const result = {};
346
+ for (let val of exports) {
347
+ if (typeof val === 'string') {
348
+ result[val] = sourceModule[val];
349
+ }
350
+ else {
351
+ const [source, target] = val;
352
+ const key = target !== null && target !== void 0 ? target : source;
353
+ result[key] = sourceModule[source];
354
+ }
355
+ }
356
+ return result;
357
+ }
358
+ else {
359
+ return sourceModule;
360
+ }
361
+ }
362
+ else {
363
+ return valueOrSource;
364
+ }
365
+ });
366
+ }
367
+ /**
368
+ * Performs a dynamic import() of the given module.
369
+ * Uses the JS Engine's native import() functionality.
370
+ * @param module The module that should be imported.
371
+ * @returns Returns a promise that resolves with the module's exports.
372
+ */
373
+ dynamicImport(module) {
374
+ return __awaiter(this, void 0, void 0, function* () {
375
+ return yield import(/* @vite-ignore */ module);
376
+ });
377
+ }
378
+ /**
379
+ * Attempts to resolve the module with the given name.
380
+ * @param moduleName The name of the module to resolve.
381
+ * @param meta The metadata that should be used to resolve the module.
382
+ */
383
+ resolveModule(moduleName, meta, allowCustomResolution = true) {
384
+ return __awaiter(this, void 0, void 0, function* () {
385
+ if ((meta === null || meta === void 0 ? void 0 : meta.tag) === ON_RESOLVE_MODULE) {
386
+ allowCustomResolution = false;
387
+ }
388
+ if (moduleName === 'casualos') {
389
+ let exports = Object.assign({}, this._library.api);
390
+ const bot = (meta === null || meta === void 0 ? void 0 : meta.botId) ? this._compiledState[meta.botId] : null;
391
+ const ctx = {
392
+ bot,
393
+ tag: meta === null || meta === void 0 ? void 0 : meta.tag,
394
+ creator: bot
395
+ ? this._getRuntimeBot(bot.script.tags.creator)
396
+ : null,
397
+ config: null,
398
+ };
399
+ for (let key in this._library.tagSpecificApi) {
400
+ if (!this._library.tagSpecificApi.hasOwnProperty(key)) {
401
+ continue;
402
+ }
403
+ const result = this._library.tagSpecificApi[key](ctx);
404
+ exports[key] = result;
405
+ }
406
+ return {
407
+ id: 'casualos',
408
+ exports,
409
+ };
410
+ }
411
+ if (allowCustomResolution) {
412
+ const shoutResult = this.shout(ON_RESOLVE_MODULE, undefined, {
413
+ module: moduleName,
414
+ meta,
415
+ });
416
+ const actionResult = isRuntimePromise(shoutResult)
417
+ ? yield shoutResult
418
+ : shoutResult;
419
+ for (let scriptResult of actionResult.results) {
420
+ const result = yield scriptResult;
421
+ if (result) {
422
+ if (typeof result === 'object') {
423
+ if (typeof result.botId === 'string' &&
424
+ typeof result.tag === 'string') {
425
+ const bot = this._compiledState[result.botId];
426
+ const mod = bot === null || bot === void 0 ? void 0 : bot.modules[result.tag];
427
+ if (mod) {
428
+ return {
429
+ botId: result.botId,
430
+ id: moduleName,
431
+ tag: result.tag,
432
+ };
433
+ }
434
+ }
435
+ else if (typeof result.exports === 'object' &&
436
+ result.exports) {
437
+ return {
438
+ id: moduleName,
439
+ exports: result.exports,
440
+ };
441
+ }
442
+ }
443
+ else if (typeof result === 'string') {
444
+ if (isUrl(result)) {
445
+ return {
446
+ id: moduleName,
447
+ url: result,
448
+ };
449
+ }
450
+ else {
451
+ return {
452
+ id: moduleName,
453
+ source: result,
454
+ };
455
+ }
456
+ }
457
+ }
458
+ }
459
+ }
460
+ const isRelativeImport = moduleName.startsWith('.') || moduleName.startsWith(':');
461
+ if (isRelativeImport) {
462
+ if (!meta) {
463
+ throw new Error('Cannot resolve relative import without metadata');
464
+ }
465
+ const bot = this._compiledState[meta.botId];
466
+ if (!bot) {
467
+ throw new Error('Cannot resolve relative import without bot');
468
+ }
469
+ const system = calculateStringTagValue(null, bot, 'system', `🔗${bot.id}`);
470
+ const split = system.split('.');
471
+ for (let i = 0; i < moduleName.length; i++) {
472
+ if (moduleName[i] === ':') {
473
+ split.pop();
474
+ }
475
+ else if (moduleName[i] === '.') {
476
+ }
477
+ else {
478
+ moduleName =
479
+ split.join('.') + '.' + moduleName.substring(i);
480
+ break;
481
+ }
482
+ }
483
+ }
484
+ if (moduleName.startsWith('🔗')) {
485
+ const [id, tag] = moduleName.substring('🔗'.length).split('.');
486
+ const bot = this._compiledState[id];
487
+ if (bot && tag) {
488
+ return {
489
+ id: moduleName,
490
+ botId: bot.id,
491
+ tag: tag,
492
+ };
493
+ }
494
+ }
495
+ const lastIndex = moduleName.lastIndexOf('.');
496
+ if (lastIndex >= 0) {
497
+ const system = moduleName.substring(0, lastIndex);
498
+ const tag = moduleName.substring(lastIndex + 1);
499
+ const botIds = this._systemMap.get(system);
500
+ if (botIds) {
501
+ for (let id of botIds) {
502
+ const bot = this._compiledState[id];
503
+ if (bot && bot.modules[tag]) {
504
+ return {
505
+ botId: id,
506
+ id: moduleName,
507
+ tag: tag,
508
+ };
509
+ }
510
+ }
511
+ }
512
+ }
513
+ if (isUrl(moduleName)) {
514
+ return {
515
+ id: moduleName,
516
+ url: moduleName,
517
+ };
518
+ }
519
+ return null;
520
+ });
521
+ }
238
522
  getShoutTimers() {
239
523
  return {};
240
524
  }
@@ -1409,6 +1693,11 @@ export class AuxRuntime {
1409
1693
  const bot = this._compiledState[id];
1410
1694
  if (bot) {
1411
1695
  removeFromContext(this._globalContext, [bot.script]);
1696
+ const system = bot.values['system'];
1697
+ if (hasValue(system)) {
1698
+ const map = this._systemMap.get(system);
1699
+ map === null || map === void 0 ? void 0 : map.delete(bot.id);
1700
+ }
1412
1701
  for (let breakpoint of bot.breakpoints) {
1413
1702
  this._interpreter.removeBreakpointById(breakpoint.id);
1414
1703
  this._breakpoints.delete(breakpoint.id);
@@ -1808,6 +2097,8 @@ export class AuxRuntime {
1808
2097
  precalculated: true,
1809
2098
  tags: fromFactory ? bot.tags : Object.assign({}, bot.tags),
1810
2099
  listeners: {},
2100
+ modules: {},
2101
+ exports: {},
1811
2102
  values: {},
1812
2103
  script: null,
1813
2104
  originalTagEditValues: {},
@@ -2096,7 +2387,7 @@ export class AuxRuntime {
2096
2387
  this._compileTagValue(bot, tag, tagValue);
2097
2388
  }
2098
2389
  _compileTagValue(bot, tag, tagValue) {
2099
- let { value, listener } = this._compileValue(bot, tag, tagValue);
2390
+ let { value, listener, module } = this._compileValue(bot, tag, tagValue);
2100
2391
  if (listener) {
2101
2392
  bot.listeners[tag] = listener;
2102
2393
  this._globalContext.recordListenerPresense(bot.id, tag, true);
@@ -2105,7 +2396,40 @@ export class AuxRuntime {
2105
2396
  delete bot.listeners[tag];
2106
2397
  this._globalContext.recordListenerPresense(bot.id, tag, false);
2107
2398
  }
2399
+ if (module) {
2400
+ bot.modules[tag] = module;
2401
+ }
2402
+ else if (!!bot.modules[tag]) {
2403
+ delete bot.modules[tag];
2404
+ }
2405
+ if (bot.exports[tag]) {
2406
+ delete bot.exports[tag];
2407
+ }
2108
2408
  if (typeof value !== 'function') {
2409
+ if (tag === 'system') {
2410
+ const originalValue = bot.values[tag];
2411
+ if (originalValue !== value) {
2412
+ if (hasValue(originalValue)) {
2413
+ let originalSystemBots = this._systemMap.get(originalValue);
2414
+ if (originalSystemBots) {
2415
+ // originalSystemBots = new Set();
2416
+ // this._systemMap.set(originalValue ?? value, originalSystemBots);
2417
+ originalSystemBots.delete(bot.id);
2418
+ if (originalSystemBots.size <= 0) {
2419
+ this._systemMap.delete(originalValue);
2420
+ }
2421
+ }
2422
+ }
2423
+ if (hasValue(value)) {
2424
+ let systemBots = this._systemMap.get(value);
2425
+ if (!systemBots) {
2426
+ systemBots = new Set();
2427
+ this._systemMap.set(value, systemBots);
2428
+ }
2429
+ systemBots.add(bot.id);
2430
+ }
2431
+ }
2432
+ }
2109
2433
  if (hasValue(value)) {
2110
2434
  bot.values[tag] = value;
2111
2435
  }
@@ -2117,6 +2441,7 @@ export class AuxRuntime {
2117
2441
  }
2118
2442
  _compileValue(bot, tag, value) {
2119
2443
  let listener;
2444
+ let module;
2120
2445
  if (isFormula(value)) {
2121
2446
  const parsed = value.substring(DNA_TAG_PREFIX.length);
2122
2447
  const transformed = replaceMacros(parsed);
@@ -2135,6 +2460,17 @@ export class AuxRuntime {
2135
2460
  value = ex;
2136
2461
  }
2137
2462
  }
2463
+ else if (isModule(value)) {
2464
+ try {
2465
+ module = this._compile(bot, tag, value, {
2466
+ api: {},
2467
+ tagSpecificApi: {},
2468
+ });
2469
+ }
2470
+ catch (ex) {
2471
+ value = ex;
2472
+ }
2473
+ }
2138
2474
  else if (isTaggedString(value)) {
2139
2475
  value = parseTaggedString(value);
2140
2476
  }
@@ -2170,7 +2506,10 @@ export class AuxRuntime {
2170
2506
  value = result;
2171
2507
  }
2172
2508
  }
2173
- return { value, listener };
2509
+ if ((listener === null || listener === void 0 ? void 0 : listener.moduleFunc) && !module) {
2510
+ module = listener;
2511
+ }
2512
+ return { value, listener, module };
2174
2513
  }
2175
2514
  _compileTagMaskValue(bot, tag, space, value) {
2176
2515
  let changedValue = false;
@@ -2227,6 +2566,7 @@ export class AuxRuntime {
2227
2566
  }
2228
2567
  }
2229
2568
  _compile(bot, tag, script, options) {
2569
+ var _a, _b, _c, _d;
2230
2570
  script = replaceMacros(script);
2231
2571
  let functionName;
2232
2572
  let diagnosticFunctionName;
@@ -2237,13 +2577,25 @@ export class AuxRuntime {
2237
2577
  diagnosticFunctionName = tag;
2238
2578
  fileName = `${bot.id}.${diagnosticFunctionName}`;
2239
2579
  }
2240
- const constants = Object.assign(Object.assign({}, this._library.api), { tagName: tag, globalThis: this._globalObject });
2241
- const specifics = Object.assign({}, this._library.tagSpecificApi);
2580
+ const meta = markAsUncopiableObject({
2581
+ botId: bot === null || bot === void 0 ? void 0 : bot.id,
2582
+ tag: tag,
2583
+ });
2584
+ Object.defineProperty(meta, 'resolve', {
2585
+ enumerable: false,
2586
+ configurable: false,
2587
+ writable: false,
2588
+ value: (module) => __awaiter(this, void 0, void 0, function* () {
2589
+ return yield this.resolveModule(module, meta, true);
2590
+ }),
2591
+ });
2592
+ const constants = Object.assign(Object.assign({}, ((_a = options.api) !== null && _a !== void 0 ? _a : this._library.api)), { tagName: tag, globalThis: this._globalObject, [IMPORT_META_FACTORY]: meta });
2593
+ const specifics = Object.assign({}, ((_b = options.tagSpecificApi) !== null && _b !== void 0 ? _b : this._library.tagSpecificApi));
2242
2594
  if (this._interpreter) {
2243
2595
  delete constants.globalThis;
2244
2596
  // if (this.canTriggerBreakpoint) {
2245
- Object.assign(constants, this._interpretedApi);
2246
- Object.assign(specifics, this._interpretedTagSpecificApi);
2597
+ Object.assign(constants, (_c = options.api) !== null && _c !== void 0 ? _c : this._interpretedApi);
2598
+ Object.assign(specifics, (_d = options.tagSpecificApi) !== null && _d !== void 0 ? _d : this._interpretedTagSpecificApi);
2247
2599
  // }
2248
2600
  }
2249
2601
  const func = this._compiler.compile(script, {
@@ -2282,25 +2634,46 @@ export class AuxRuntime {
2282
2634
  throw data;
2283
2635
  },
2284
2636
  constants: constants,
2285
- variables: Object.assign(Object.assign({}, specifics), { this: (ctx) => (ctx.bot ? ctx.bot.script : null), thisBot: (ctx) => (ctx.bot ? ctx.bot.script : null), bot: (ctx) => (ctx.bot ? ctx.bot.script : null), tags: (ctx) => (ctx.bot ? ctx.bot.script.tags : null), raw: (ctx) => (ctx.bot ? ctx.bot.script.raw : null), masks: (ctx) => (ctx.bot ? ctx.bot.script.masks : null), creatorBot: (ctx) => ctx.creator, configBot: () => this.context.playerBot, links: (ctx) => (ctx.bot ? ctx.bot.script.links : null) }),
2286
- arguments: [['that', 'data']],
2637
+ variables: Object.assign(Object.assign({}, specifics), { this: (ctx) => (ctx.bot ? ctx.bot.script : null), thisBot: (ctx) => (ctx.bot ? ctx.bot.script : null), bot: (ctx) => (ctx.bot ? ctx.bot.script : null), tags: (ctx) => (ctx.bot ? ctx.bot.script.tags : null), raw: (ctx) => (ctx.bot ? ctx.bot.script.raw : null), masks: (ctx) => (ctx.bot ? ctx.bot.script.masks : null), creatorBot: (ctx) => ctx.creator, configBot: () => this.context.playerBot, links: (ctx) => (ctx.bot ? ctx.bot.script.links : null),
2638
+ // Default import function
2639
+ [`_${IMPORT_FACTORY}`]: () => (module, meta) => this._importModule(module, meta) }),
2640
+ arguments: [['that', 'data'], IMPORT_FACTORY, EXPORT_FACTORY],
2287
2641
  });
2288
2642
  if (hasValue(bot)) {
2289
2643
  this._functionMap.set(functionName, func);
2290
2644
  const botFunctionNames = this._getFunctionNamesForBot(bot.id);
2291
2645
  botFunctionNames.add(functionName);
2292
2646
  }
2647
+ if (func.metadata.isModule) {
2648
+ const moduleFunc = (imports, exports) => {
2649
+ const importFunc = (module) => {
2650
+ return imports(module, meta);
2651
+ };
2652
+ const exportFunc = (valueOrSource, exp) => exports(valueOrSource, exp, meta);
2653
+ return this._wrapWithCurrentPromise(() => {
2654
+ let result = func(null, importFunc, exportFunc);
2655
+ this._scheduleJobQueueCheck();
2656
+ return result;
2657
+ });
2658
+ };
2659
+ func.moduleFunc = moduleFunc;
2660
+ }
2661
+ else {
2662
+ func.moduleFunc = null;
2663
+ }
2293
2664
  return func;
2294
2665
  }
2295
2666
  _handleError(err, bot, tag) {
2296
2667
  if (err instanceof RanOutOfEnergyError) {
2297
2668
  throw err;
2298
2669
  }
2299
- let data = {
2670
+ // Script errors are uncopiable because otherwise the interpreter might try
2671
+ // and run into weird issues.
2672
+ let data = markAsUncopiableObject({
2300
2673
  error: err,
2301
2674
  bot: bot,
2302
2675
  tag: tag,
2303
- };
2676
+ });
2304
2677
  if (err instanceof Error) {
2305
2678
  try {
2306
2679
  const newStack = this._compiler.calculateOriginalStackTrace(this._functionMap, err);