@squiz/render-runtime-lib 1.2.1-alpha.100

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.
Files changed (56) hide show
  1. package/README.md +11 -0
  2. package/lib/component-runner/component-runner.spec.d.ts +1 -0
  3. package/lib/component-runner/index.d.ts +22 -0
  4. package/lib/component-runner/worker/WorkerPool.d.ts +50 -0
  5. package/lib/component-runner/worker/getRuntimeModules.d.ts +1 -0
  6. package/lib/component-runner/worker/worker-root.d.ts +1 -0
  7. package/lib/index.d.ts +25 -0
  8. package/lib/index.js +112791 -0
  9. package/lib/index.js.map +7 -0
  10. package/lib/migrations/20220704054051_initial.sql +19 -0
  11. package/lib/migrations/20220718172237_adding_component_sets.sql +23 -0
  12. package/lib/migrations/20220728113941_add_env_vars_field.sql +1 -0
  13. package/lib/migrations/20220817113300_removing_null_props_from_jsonb.sql +41 -0
  14. package/lib/render-runtime-lib.spec.d.ts +1 -0
  15. package/lib/test/helpers/fixtures.d.ts +20 -0
  16. package/lib/test/helpers/stack.d.ts +6 -0
  17. package/lib/test/index.d.ts +2 -0
  18. package/lib/utils/convertFunctionStaticFilesToFqdn.d.ts +1 -0
  19. package/lib/utils/convertFunctionStaticFilesToFqdn.spec.d.ts +1 -0
  20. package/lib/utils/getFunctionDefinitionFromManifest.d.ts +2 -0
  21. package/lib/utils/getManifestPath.d.ts +1 -0
  22. package/lib/utils/getManifestPath.spec.d.ts +1 -0
  23. package/lib/utils/getPreviewFilePath.d.ts +1 -0
  24. package/lib/utils/getPreviewFilePath.spec.d.ts +1 -0
  25. package/lib/utils/isInProductionMode.d.ts +1 -0
  26. package/lib/utils/isInProductionMode.spec.d.ts +1 -0
  27. package/lib/utils/resolvePreviewOutput.d.ts +2 -0
  28. package/lib/utils/resolvePreviewOutput.spec.d.ts +1 -0
  29. package/lib/webserver/app.d.ts +4 -0
  30. package/lib/webserver/controllers/core.d.ts +3 -0
  31. package/lib/webserver/controllers/core.spec.d.ts +1 -0
  32. package/lib/webserver/controllers/definition.d.ts +3 -0
  33. package/lib/webserver/controllers/definition.spec.d.ts +1 -0
  34. package/lib/webserver/controllers/index.d.ts +4 -0
  35. package/lib/webserver/controllers/render.d.ts +3 -0
  36. package/lib/webserver/controllers/render.spec.d.ts +1 -0
  37. package/lib/webserver/controllers/static.d.ts +3 -0
  38. package/lib/webserver/controllers/static.spec.d.ts +1 -0
  39. package/lib/webserver/controllers/test/definition-route-tests.d.ts +1 -0
  40. package/lib/webserver/controllers/test/render-route-tests.d.ts +1 -0
  41. package/lib/webserver/controllers/test/static-route-tests.d.ts +1 -0
  42. package/lib/webserver/index.d.ts +22 -0
  43. package/lib/worker/bridge.js +1010 -0
  44. package/lib/worker/compiler.js +87 -0
  45. package/lib/worker/events.js +977 -0
  46. package/lib/worker/nodevm.js +503 -0
  47. package/lib/worker/resolver-compat.js +342 -0
  48. package/lib/worker/resolver.js +882 -0
  49. package/lib/worker/script.js +388 -0
  50. package/lib/worker/setup-node-sandbox.js +469 -0
  51. package/lib/worker/setup-sandbox.js +456 -0
  52. package/lib/worker/transformer.js +180 -0
  53. package/lib/worker/vm.js +539 -0
  54. package/lib/worker/worker-root.js +41743 -0
  55. package/lib/worker/worker-root.js.map +7 -0
  56. package/package.json +60 -0
@@ -0,0 +1,503 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * This callback will be called to resolve a module if it couldn't be found.
5
+ *
6
+ * @callback resolveCallback
7
+ * @param {string} moduleName - Name of the module used to resolve.
8
+ * @param {string} dirname - Name of the current directory.
9
+ * @return {(string|undefined)} The file or directory to use to load the requested module.
10
+ */
11
+
12
+ /**
13
+ * This callback will be called to require a module instead of node's require.
14
+ *
15
+ * @callback customRequire
16
+ * @param {string} moduleName - Name of the module requested.
17
+ * @return {*} The required module object.
18
+ */
19
+
20
+ const fs = require('fs');
21
+ const pa = require('path');
22
+ const {
23
+ Script
24
+ } = require('vm');
25
+ const {
26
+ VMError
27
+ } = require('./bridge');
28
+ const {
29
+ VMScript,
30
+ MODULE_PREFIX,
31
+ STRICT_MODULE_PREFIX,
32
+ MODULE_SUFFIX
33
+ } = require('./script');
34
+ const {
35
+ transformer
36
+ } = require('./transformer');
37
+ const {
38
+ VM
39
+ } = require('./vm');
40
+ const {
41
+ resolverFromOptions
42
+ } = require('./resolver-compat');
43
+
44
+ const objectDefineProperty = Object.defineProperty;
45
+ const objectDefineProperties = Object.defineProperties;
46
+
47
+ /**
48
+ * Host objects
49
+ *
50
+ * @private
51
+ */
52
+ const HOST = Object.freeze({
53
+ __proto__: null,
54
+ version: parseInt(process.versions.node.split('.')[0]),
55
+ process,
56
+ console,
57
+ setTimeout,
58
+ setInterval,
59
+ setImmediate,
60
+ clearTimeout,
61
+ clearInterval,
62
+ clearImmediate
63
+ });
64
+
65
+ /**
66
+ * Compile a script.
67
+ *
68
+ * @private
69
+ * @param {string} filename - Filename of the script.
70
+ * @param {string} script - Script.
71
+ * @return {vm.Script} The compiled script.
72
+ */
73
+ function compileScript(filename, script) {
74
+ return new Script(script, {
75
+ __proto__: null,
76
+ filename,
77
+ displayErrors: false
78
+ });
79
+ }
80
+
81
+ let cacheSandboxScript = null;
82
+ let cacheMakeNestingScript = null;
83
+
84
+ const NESTING_OVERRIDE = Object.freeze({
85
+ __proto__: null,
86
+ vm2: vm2NestingLoader
87
+ });
88
+
89
+ /**
90
+ * Event caused by a <code>console.debug</code> call if <code>options.console="redirect"</code> is specified.
91
+ *
92
+ * @public
93
+ * @event NodeVM."console.debug"
94
+ * @type {...*}
95
+ */
96
+
97
+ /**
98
+ * Event caused by a <code>console.log</code> call if <code>options.console="redirect"</code> is specified.
99
+ *
100
+ * @public
101
+ * @event NodeVM."console.log"
102
+ * @type {...*}
103
+ */
104
+
105
+ /**
106
+ * Event caused by a <code>console.info</code> call if <code>options.console="redirect"</code> is specified.
107
+ *
108
+ * @public
109
+ * @event NodeVM."console.info"
110
+ * @type {...*}
111
+ */
112
+
113
+ /**
114
+ * Event caused by a <code>console.warn</code> call if <code>options.console="redirect"</code> is specified.
115
+ *
116
+ * @public
117
+ * @event NodeVM."console.warn"
118
+ * @type {...*}
119
+ */
120
+
121
+ /**
122
+ * Event caused by a <code>console.error</code> call if <code>options.console="redirect"</code> is specified.
123
+ *
124
+ * @public
125
+ * @event NodeVM."console.error"
126
+ * @type {...*}
127
+ */
128
+
129
+ /**
130
+ * Event caused by a <code>console.dir</code> call if <code>options.console="redirect"</code> is specified.
131
+ *
132
+ * @public
133
+ * @event NodeVM."console.dir"
134
+ * @type {...*}
135
+ */
136
+
137
+ /**
138
+ * Event caused by a <code>console.trace</code> call if <code>options.console="redirect"</code> is specified.
139
+ *
140
+ * @public
141
+ * @event NodeVM."console.trace"
142
+ * @type {...*}
143
+ */
144
+
145
+ /**
146
+ * Class NodeVM.
147
+ *
148
+ * @public
149
+ * @extends {VM}
150
+ * @extends {EventEmitter}
151
+ */
152
+ class NodeVM extends VM {
153
+
154
+ /**
155
+ * Create a new NodeVM instance.<br>
156
+ *
157
+ * Unlike VM, NodeVM lets you use require same way like in regular node.<br>
158
+ *
159
+ * However, it does not use the timeout.
160
+ *
161
+ * @public
162
+ * @param {Object} [options] - VM options.
163
+ * @param {Object} [options.sandbox] - Objects that will be copied into the global object of the sandbox.
164
+ * @param {(string|compileCallback)} [options.compiler="javascript"] - The compiler to use.
165
+ * @param {boolean} [options.eval=true] - Allow the dynamic evaluation of code via eval(code) or Function(code)().<br>
166
+ * Only available for node v10+.
167
+ * @param {boolean} [options.wasm=true] - Allow to run wasm code.<br>
168
+ * Only available for node v10+.
169
+ * @param {("inherit"|"redirect"|"off")} [options.console="inherit"] - Sets the behavior of the console in the sandbox.
170
+ * <code>inherit</code> to enable console, <code>redirect</code> to redirect to events, <code>off</code> to disable console.
171
+ * @param {Object|boolean} [options.require=false] - Allow require inside the sandbox.
172
+ * @param {(boolean|string[]|Object)} [options.require.external=false] - <b>WARNING: When allowing require the option <code>options.require.root</code>
173
+ * should be set to restrict the script from requiring any module. Values can be true, an array of allowed external modules or an object.
174
+ * @param {(string[])} [options.require.external.modules] - Array of allowed external modules. Also supports wildcards, so specifying ['@scope/*-ver-??],
175
+ * for instance, will allow using all modules having a name of the form @scope/something-ver-aa, @scope/other-ver-11, etc.
176
+ * @param {boolean} [options.require.external.transitive=false] - Boolean which indicates if transitive dependencies of external modules are allowed.
177
+ * @param {string[]} [options.require.builtin=[]] - Array of allowed built-in modules, accepts ["*"] for all.
178
+ * @param {(string|string[])} [options.require.root] - Restricted path(s) where local modules can be required. If omitted every path is allowed.
179
+ * @param {Object} [options.require.mock] - Collection of mock modules (both external or built-in).
180
+ * @param {("host"|"sandbox")} [options.require.context="host"] - <code>host</code> to require modules in host and proxy them to sandbox.
181
+ * <code>sandbox</code> to load, compile and require modules in sandbox.
182
+ * Builtin modules except <code>events</code> always required in host and proxied to sandbox.
183
+ * @param {string[]} [options.require.import] - Array of modules to be loaded into NodeVM on start.
184
+ * @param {resolveCallback} [options.require.resolve] - An additional lookup function in case a module wasn't
185
+ * found in one of the traditional node lookup paths.
186
+ * @param {customRequire} [options.require.customRequire=require] - Custom require to require host and built-in modules.
187
+ * @param {boolean} [options.nesting=false] -
188
+ * <b>WARNING: Allowing this is a security risk as scripts can create a NodeVM which can require any host module.</b>
189
+ * Allow nesting of VMs.
190
+ * @param {("commonjs"|"none")} [options.wrapper="commonjs"] - <code>commonjs</code> to wrap script into CommonJS wrapper,
191
+ * <code>none</code> to retrieve value returned by the script.
192
+ * @param {string[]} [options.sourceExtensions=["js"]] - Array of file extensions to treat as source code.
193
+ * @param {string[]} [options.argv=[]] - Array of arguments passed to <code>process.argv</code>.
194
+ * This object will not be copied and the script can change this object.
195
+ * @param {Object} [options.env={}] - Environment map passed to <code>process.env</code>.
196
+ * This object will not be copied and the script can change this object.
197
+ * @param {boolean} [options.strict=false] - If modules should be loaded in strict mode.
198
+ * @throws {VMError} If the compiler is unknown.
199
+ */
200
+ constructor(options = {}) {
201
+ const {
202
+ compiler,
203
+ eval: allowEval,
204
+ wasm,
205
+ console: consoleType = 'inherit',
206
+ require: requireOpts = false,
207
+ nesting = false,
208
+ wrapper = 'commonjs',
209
+ sourceExtensions = ['js'],
210
+ argv,
211
+ env,
212
+ strict = false,
213
+ sandbox
214
+ } = options;
215
+
216
+ // Throw this early
217
+ if (sandbox && 'object' !== typeof sandbox) {
218
+ throw new VMError('Sandbox must be an object.');
219
+ }
220
+
221
+ super({__proto__: null, compiler: compiler, eval: allowEval, wasm});
222
+
223
+ // This is only here for backwards compatibility.
224
+ objectDefineProperty(this, 'options', {__proto__: null, value: {
225
+ console: consoleType,
226
+ require: requireOpts,
227
+ nesting,
228
+ wrapper,
229
+ sourceExtensions,
230
+ strict
231
+ }});
232
+
233
+ const resolver = resolverFromOptions(this, requireOpts, nesting && NESTING_OVERRIDE, this._compiler);
234
+
235
+ objectDefineProperty(this, '_resolver', {__proto__: null, value: resolver});
236
+
237
+ if (!cacheSandboxScript) {
238
+ cacheSandboxScript = compileScript(`${__dirname}/setup-node-sandbox.js`,
239
+ `(function (host, data) { ${fs.readFileSync(`${__dirname}/setup-node-sandbox.js`, 'utf8')}\n})`);
240
+ }
241
+
242
+ const closure = this._runScript(cacheSandboxScript);
243
+
244
+ const extensions = {
245
+ __proto__: null
246
+ };
247
+
248
+ const loadJS = (mod, filename) => resolver.loadJS(this, mod, filename);
249
+
250
+ for (let i = 0; i < sourceExtensions.length; i++) {
251
+ extensions['.' + sourceExtensions[i]] = loadJS;
252
+ }
253
+
254
+ if (!extensions['.json']) extensions['.json'] = (mod, filename) => resolver.loadJSON(this, mod, filename);
255
+ if (!extensions['.node']) extensions['.node'] = (mod, filename) => resolver.loadNode(this, mod, filename);
256
+
257
+
258
+ this.readonly(HOST);
259
+ this.readonly(resolver);
260
+ this.readonly(this);
261
+
262
+ const {
263
+ Module,
264
+ jsonParse,
265
+ createRequireForModule,
266
+ requireImpl
267
+ } = closure(HOST, {
268
+ __proto__: null,
269
+ argv,
270
+ env,
271
+ console: consoleType,
272
+ vm: this,
273
+ resolver,
274
+ extensions
275
+ });
276
+
277
+ objectDefineProperties(this, {
278
+ __proto__: null,
279
+ _Module: {__proto__: null, value: Module},
280
+ _jsonParse: {__proto__: null, value: jsonParse},
281
+ _createRequireForModule: {__proto__: null, value: createRequireForModule},
282
+ _requireImpl: {__proto__: null, value: requireImpl},
283
+ _cacheRequireModule: {__proto__: null, value: null, writable: true}
284
+ });
285
+
286
+
287
+ resolver.init(this);
288
+
289
+ // prepare global sandbox
290
+ if (sandbox) {
291
+ this.setGlobals(sandbox);
292
+ }
293
+
294
+ if (requireOpts && requireOpts.import) {
295
+ if (Array.isArray(requireOpts.import)) {
296
+ for (let i = 0, l = requireOpts.import.length; i < l; i++) {
297
+ this.require(requireOpts.import[i]);
298
+ }
299
+ } else {
300
+ this.require(requireOpts.import);
301
+ }
302
+ }
303
+ }
304
+
305
+ /**
306
+ * @ignore
307
+ * @deprecated Just call the method yourself like <code>method(args);</code>
308
+ * @param {function} method - Function to invoke.
309
+ * @param {...*} args - Arguments to pass to the function.
310
+ * @return {*} Return value of the function.
311
+ * @todo Can we remove this function? It even had a bug that would use args as this parameter.
312
+ * @throws {*} Rethrows anything the method throws.
313
+ * @throws {VMError} If method is not a function.
314
+ * @throws {Error} If method is a class.
315
+ */
316
+ call(method, ...args) {
317
+ if ('function' === typeof method) {
318
+ return method(...args);
319
+ } else {
320
+ throw new VMError('Unrecognized method type.');
321
+ }
322
+ }
323
+
324
+ /**
325
+ * Require a module in VM and return it's exports.
326
+ *
327
+ * @public
328
+ * @param {string} module - Module name.
329
+ * @return {*} Exported module.
330
+ * @throws {*} If the module couldn't be found or loading it threw an error.
331
+ */
332
+ require(module) {
333
+ const path = this._resolver.pathResolve('.');
334
+ let mod = this._cacheRequireModule;
335
+ if (!mod || mod.path !== path) {
336
+ const filename = this._resolver.pathConcat(path, '/vm.js');
337
+ mod = new (this._Module)(filename, path);
338
+ this._resolver.registerModule(mod, filename, path, null, false);
339
+ this._cacheRequireModule = mod;
340
+ }
341
+ return this._requireImpl(mod, module, true);
342
+ }
343
+
344
+ /**
345
+ * Run the code in NodeVM.
346
+ *
347
+ * First time you run this method, code is executed same way like in node's regular `require` - it's executed with
348
+ * `module`, `require`, `exports`, `__dirname`, `__filename` variables and expect result in `module.exports'.
349
+ *
350
+ * @param {(string|VMScript)} code - Code to run.
351
+ * @param {(string|Object)} [options] - Options map or filename.
352
+ * @param {string} [options.filename="vm.js"] - Filename that shows up in any stack traces produced from this script.<br>
353
+ * This is only used if code is a String.
354
+ * @param {boolean} [options.strict] - If modules should be loaded in strict mode. Defaults to NodeVM options.
355
+ * @param {("commonjs"|"none")} [options.wrapper] - <code>commonjs</code> to wrap script into CommonJS wrapper,
356
+ * <code>none</code> to retrieve value returned by the script. Defaults to NodeVM options.
357
+ * @return {*} Result of executed code.
358
+ * @throws {SyntaxError} If there is a syntax error in the script.
359
+ * @throws {*} If the script execution terminated with an exception it is propagated.
360
+ * @fires NodeVM."console.debug"
361
+ * @fires NodeVM."console.log"
362
+ * @fires NodeVM."console.info"
363
+ * @fires NodeVM."console.warn"
364
+ * @fires NodeVM."console.error"
365
+ * @fires NodeVM."console.dir"
366
+ * @fires NodeVM."console.trace"
367
+ */
368
+ run(code, options) {
369
+ let script;
370
+ let filename;
371
+
372
+ if (typeof options === 'object') {
373
+ filename = options.filename;
374
+ } else {
375
+ filename = options;
376
+ options = {__proto__: null};
377
+ }
378
+
379
+ const {
380
+ strict = this.options.strict,
381
+ wrapper = this.options.wrapper,
382
+ module: customModule,
383
+ require: customRequire,
384
+ dirname: customDirname = null
385
+ } = options;
386
+
387
+ let sandboxModule = customModule;
388
+ let dirname = customDirname;
389
+
390
+ if (code instanceof VMScript) {
391
+ script = strict ? code._compileNodeVMStrict() : code._compileNodeVM();
392
+ if (!sandboxModule) {
393
+ const resolvedFilename = this._resolver.pathResolve(code.filename);
394
+ dirname = this._resolver.pathDirname(resolvedFilename);
395
+ sandboxModule = new (this._Module)(resolvedFilename, dirname);
396
+ this._resolver.registerModule(sandboxModule, resolvedFilename, dirname, null, false);
397
+ }
398
+ } else {
399
+ const unresolvedFilename = filename || 'vm.js';
400
+ if (!sandboxModule) {
401
+ if (filename) {
402
+ const resolvedFilename = this._resolver.pathResolve(filename);
403
+ dirname = this._resolver.pathDirname(resolvedFilename);
404
+ sandboxModule = new (this._Module)(resolvedFilename, dirname);
405
+ this._resolver.registerModule(sandboxModule, resolvedFilename, dirname, null, false);
406
+ } else {
407
+ sandboxModule = new (this._Module)(null, null);
408
+ sandboxModule.id = unresolvedFilename;
409
+ }
410
+ }
411
+ const prefix = strict ? STRICT_MODULE_PREFIX : MODULE_PREFIX;
412
+ let scriptCode = this._compiler(code, unresolvedFilename);
413
+ scriptCode = transformer(null, scriptCode, false, false, unresolvedFilename).code;
414
+ script = new Script(prefix + scriptCode + MODULE_SUFFIX, {
415
+ __proto__: null,
416
+ filename: unresolvedFilename,
417
+ displayErrors: false
418
+ });
419
+ }
420
+
421
+ const closure = this._runScript(script);
422
+
423
+ const usedRequire = customRequire || this._createRequireForModule(sandboxModule);
424
+
425
+ const ret = Reflect.apply(closure, this.sandbox, [sandboxModule.exports, usedRequire, sandboxModule, filename, dirname]);
426
+ return wrapper === 'commonjs' ? sandboxModule.exports : ret;
427
+ }
428
+
429
+ /**
430
+ * Create NodeVM and run code inside it.
431
+ *
432
+ * @public
433
+ * @static
434
+ * @param {string} script - Code to execute.
435
+ * @param {string} [filename] - File name (used in stack traces only).
436
+ * @param {Object} [options] - VM options.
437
+ * @param {string} [options.filename] - File name (used in stack traces only). Used if <code>filename</code> is omitted.
438
+ * @return {*} Result of executed code.
439
+ * @see {@link NodeVM} for the options.
440
+ * @throws {SyntaxError} If there is a syntax error in the script.
441
+ * @throws {*} If the script execution terminated with an exception it is propagated.
442
+ */
443
+ static code(script, filename, options) {
444
+ let unresolvedFilename;
445
+ if (filename != null) {
446
+ if ('object' === typeof filename) {
447
+ options = filename;
448
+ unresolvedFilename = options.filename;
449
+ } else if ('string' === typeof filename) {
450
+ unresolvedFilename = filename;
451
+ } else {
452
+ throw new VMError('Invalid arguments.');
453
+ }
454
+ } else if ('object' === typeof options) {
455
+ unresolvedFilename = options.filename;
456
+ }
457
+
458
+ if (arguments.length > 3) {
459
+ throw new VMError('Invalid number of arguments.');
460
+ }
461
+
462
+ const resolvedFilename = typeof unresolvedFilename === 'string' ? pa.resolve(unresolvedFilename) : undefined;
463
+
464
+ return new NodeVM(options).run(script, resolvedFilename);
465
+ }
466
+
467
+ /**
468
+ * Create NodeVM and run script from file inside it.
469
+ *
470
+ * @public
471
+ * @static
472
+ * @param {string} filename - Filename of file to load and execute in a NodeVM.
473
+ * @param {Object} [options] - NodeVM options.
474
+ * @return {*} Result of executed code.
475
+ * @see {@link NodeVM} for the options.
476
+ * @throws {Error} If filename is not a valid filename.
477
+ * @throws {SyntaxError} If there is a syntax error in the script.
478
+ * @throws {*} If the script execution terminated with an exception it is propagated.
479
+ */
480
+ static file(filename, options) {
481
+ const resolvedFilename = pa.resolve(filename);
482
+
483
+ if (!fs.existsSync(resolvedFilename)) {
484
+ throw new VMError(`Script '${filename}' not found.`);
485
+ }
486
+
487
+ if (fs.statSync(resolvedFilename).isDirectory()) {
488
+ throw new VMError('Script must be file, got directory.');
489
+ }
490
+
491
+ return new NodeVM(options).run(fs.readFileSync(resolvedFilename, 'utf8'), resolvedFilename);
492
+ }
493
+ }
494
+
495
+ function vm2NestingLoader(resolver, vm, id) {
496
+ if (!cacheMakeNestingScript) {
497
+ cacheMakeNestingScript = compileScript('nesting.js', '(vm, nodevm) => ({VM: vm, NodeVM: nodevm})');
498
+ }
499
+ const makeNesting = vm._runScript(cacheMakeNestingScript);
500
+ return makeNesting(vm.readonly(VM), vm.readonly(NodeVM));
501
+ }
502
+
503
+ exports.NodeVM = NodeVM;