@exodus/test-bundler 1.0.0-rc.1

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.
@@ -0,0 +1,49 @@
1
+ const colors = [
2
+ 'reset',
3
+ 'bold',
4
+ 'dim',
5
+ 'italic',
6
+ 'underline',
7
+ 'overline',
8
+ 'inverse',
9
+ 'hidden',
10
+ 'strikethrough',
11
+ 'black',
12
+ 'red',
13
+ 'green',
14
+ 'yellow',
15
+ 'blue',
16
+ 'magenta',
17
+ 'cyan',
18
+ 'white',
19
+ 'blackBright',
20
+ 'redBright',
21
+ 'greenBright',
22
+ 'yellowBright',
23
+ 'blueBright',
24
+ 'magentaBright',
25
+ 'cyanBright',
26
+ 'whiteBright',
27
+ 'gray',
28
+ 'grey',
29
+ 'bgBlack',
30
+ 'bgRed',
31
+ 'bgGreen',
32
+ 'bgYellow',
33
+ 'bgBlue',
34
+ 'bgMagenta',
35
+ 'bgCyan',
36
+ 'bgWhite',
37
+ 'bgBlackBright',
38
+ 'bgRedBright',
39
+ 'bgGreenBright',
40
+ 'bgYellowBright',
41
+ 'bgBlueBright',
42
+ 'bgMagentaBright',
43
+ 'bgCyanBright',
44
+ 'bgWhiteBright',
45
+ 'bgGray',
46
+ 'bgGrey',
47
+ ]
48
+
49
+ for (const key of colors) exports[key] = { open: '', close: '' }
@@ -0,0 +1 @@
1
+ module.exports = require('node:assert').strict
@@ -0,0 +1,10 @@
1
+ const keys = 'ChildProcess,exec,execFile,execFileSync,execSync,fork,spawn,spawnSync'.split(',')
2
+
3
+ const makeMethod = (key) => {
4
+ // Not an arrow as ChildProcess is a class and can be called with new
5
+ return function () {
6
+ throw new Error(`child_process.${key} unsupported in bundled mode`)
7
+ }
8
+ }
9
+
10
+ module.exports = Object.fromEntries(keys.map((key) => [key, makeMethod(key)]))
@@ -0,0 +1,27 @@
1
+ const EventEmitter = require('events')
2
+
3
+ const makeMethod = (key) => {
4
+ // Not an arrow as Worker is a class and can be called with new
5
+ return function () {
6
+ throw new Error(`cluster.${key} unsupported in bundled mode`)
7
+ }
8
+ }
9
+
10
+ const cluster = new EventEmitter()
11
+
12
+ Object.assign(cluster, {
13
+ isWorker: false,
14
+ isPrimary: true,
15
+ workers: {},
16
+ settings: {},
17
+ SCHED_NONE: 1,
18
+ SCHED_RR: 2,
19
+ schedulingPolicy: 2,
20
+ })
21
+
22
+ for (const key of ['Worker', 'setupPrimary', 'fork', 'disconnect']) cluster[key] = makeMethod(key)
23
+
24
+ cluster.isMaster = cluster.isPrimary
25
+ cluster.setupMaster = cluster.setupPrimary
26
+
27
+ module.exports = cluster
@@ -0,0 +1,5 @@
1
+ const cb = require('crypto-browserify')
2
+ const webcrypto = globalThis.crypto
3
+ const randomUUID = () => webcrypto.randomUUID()
4
+ const getRandomValues = (array) => webcrypto.getRandomValues(array)
5
+ module.exports = { ...cb, webcrypto, subtle: webcrypto?.subtle, randomUUID, getRandomValues }
@@ -0,0 +1,4 @@
1
+ // Should not be an arrow function as might be used as a constructor
2
+ module.exports = function () {
3
+ throw new Error('module unsupported in bundled mode')
4
+ }
@@ -0,0 +1 @@
1
+ throw new Error('module unsupported in bundled mode')
@@ -0,0 +1 @@
1
+ module.exports = require('node:fs').promises
package/modules/fs.cjs ADDED
@@ -0,0 +1,123 @@
1
+ const constants = require('constants-browserify')
2
+ const { resolve } = require('path')
3
+ const { F_OK, R_OK, W_OK, X_OK } = constants
4
+
5
+ // promises, sync, callbacks
6
+ const universalKeys = [
7
+ 'access',
8
+ 'appendFile',
9
+ 'chmod',
10
+ 'chown',
11
+ 'copyFile',
12
+ 'cp',
13
+ 'lchmod',
14
+ 'lchown',
15
+ 'link',
16
+ 'lstat',
17
+ 'lutimes',
18
+ 'mkdir',
19
+ 'mkdtemp',
20
+ 'open',
21
+ 'opendir',
22
+ 'readFile',
23
+ 'readdir',
24
+ 'readlink',
25
+ 'realpath',
26
+ 'rename',
27
+ 'rm',
28
+ 'rmdir',
29
+ 'stat',
30
+ 'statfs',
31
+ 'symlink',
32
+ 'truncate',
33
+ 'unlink',
34
+ 'utimes',
35
+ 'writeFile',
36
+ ]
37
+
38
+ // promises
39
+ const promisesKeys = [...universalKeys, 'watch']
40
+
41
+ // sync, callbacks
42
+ const baseKeys = [
43
+ ...universalKeys,
44
+ 'close',
45
+ 'exists',
46
+ 'fchmod',
47
+ 'fchown',
48
+ 'fdatasync',
49
+ 'fstat',
50
+ 'fsync',
51
+ 'ftruncate',
52
+ 'futimes',
53
+ 'read',
54
+ 'readv',
55
+ 'write',
56
+ 'writev',
57
+ ]
58
+
59
+ const mainKeys = [
60
+ ...baseKeys,
61
+ ...baseKeys.map((name) => `${name}Sync`),
62
+ 'createReadStream',
63
+ 'createWriteStream',
64
+ 'watch',
65
+ 'watchFile',
66
+ 'unwatchFile',
67
+ ]
68
+
69
+ const err = (key, file) => {
70
+ const info = file ? `\n (trying to access ${file})` : ''
71
+ throw new Error(`fs.${key} unsupported in bundled mode${info}`)
72
+ }
73
+
74
+ const stubs = Object.fromEntries(mainKeys.map((key) => [key, () => err(key)]))
75
+ const stubsPromises = Object.fromEntries(promisesKeys.map((key) => [key, async () => err(key)]))
76
+ const promises = { ...stubsPromises, constants }
77
+
78
+ const decode = (source, sourceEncoding, encoding) => {
79
+ if (encoding && sourceEncoding === encoding) return source
80
+ const data = Buffer.from(source, sourceEncoding)
81
+ return encoding === undefined ? data : data.toString(encoding)
82
+ }
83
+
84
+ const getOptions = (arg, options) => {
85
+ if (typeof arg !== 'string') throw new Error('first argument should be string')
86
+ const file = resolve(process.cwd(), arg)
87
+ if (typeof options === 'string') return { file, encoding: options, rest: {} }
88
+ if (options === undefined) return { file, rest: {} }
89
+ if (typeof options !== 'object') throw new Error('Unexpected options')
90
+ const { encoding: enc, ...rest } = options
91
+ if (enc !== undefined && typeof enc !== 'string') throw new Error('encoding should be a string')
92
+ return { file, encoding: enc, rest }
93
+ }
94
+
95
+ const fsFilesContents =
96
+ // eslint-disable-next-line no-undef
97
+ typeof EXODUS_TEST_FSFILES_CONTENTS === 'undefined' ? null : new Map(EXODUS_TEST_FSFILES_CONTENTS)
98
+ const readFileSync = (arg, options) => {
99
+ const { file, encoding, rest } = getOptions(arg, options)
100
+ if (Object.keys(rest).length > 0) throw new Error('Unsupported readFileSync options')
101
+ if (fsFilesContents?.has(file)) return decode(fsFilesContents.get(file), 'base64', encoding)
102
+ err('readFileSync', file)
103
+ }
104
+
105
+ // eslint-disable-next-line no-undef
106
+ const fsDir = typeof EXODUS_TEST_FSDIRS === 'undefined' ? null : new Map(EXODUS_TEST_FSDIRS)
107
+ const readdirSync = (arg, options) => {
108
+ const { file: dir, encoding, rest } = getOptions(arg, options)
109
+ if (Object.keys(rest).length > 0) throw new Error('Unsupported readdirSync options')
110
+ const enc = encoding === 'buffer' ? undefined : encoding || 'utf8'
111
+ if (fsDir?.has(dir)) return fsDir.get(dir).map((name) => decode(name, 'utf8', enc))
112
+ err('readdirSync', dir)
113
+ }
114
+
115
+ // eslint-disable-next-line no-undef
116
+ const fsFiles = typeof EXODUS_TEST_FSFILES === 'undefined' ? null : new Set(EXODUS_TEST_FSFILES)
117
+ const existsSync = (file) => {
118
+ if (fsFiles?.has(file) || fsFilesContents?.has(file) || fsDir?.has(file)) return true
119
+ err('existsSync', file)
120
+ }
121
+
122
+ const implemented = { existsSync, readFileSync, readdirSync }
123
+ module.exports = { ...stubs, ...implemented, promises, constants, F_OK, R_OK, W_OK, X_OK }
@@ -0,0 +1,341 @@
1
+ // We expect bundler to optimize out EXODUS_TEST_PLATFORM blocks
2
+ /* eslint-disable sonarjs/no-collapsible-if, unicorn/no-lonely-if */
3
+
4
+ if (!globalThis.global) globalThis.global = globalThis
5
+ if (!globalThis.Buffer) globalThis.Buffer = require('buffer').Buffer
6
+
7
+ const consoleKeys = ['log', 'error', 'warn', 'info', 'debug', 'trace']
8
+ const { print } = globalThis
9
+ if (process.env.EXODUS_TEST_PLATFORM === 'engine262') delete globalThis.console // prints [object Object] on everything
10
+ if (!globalThis.console) globalThis.console = Object.fromEntries(consoleKeys.map((k) => [k, print])) // eslint-disable-line no-undef
11
+ for (const k of consoleKeys) if (!console[k]) console[k] = console.log // SpiderMonkey has console but no console.error
12
+
13
+ // In browsers e.g. errors (and some other objects) are hard to unwrap via the API
14
+ // So we just stringify everything instead on the sender side
15
+ // In barebone, we don't want console.log({x:10}) to print "[Object object]"", we want "{ x: 10 }"
16
+ if (process.env.EXODUS_TEST_IS_BROWSER || process.env.EXODUS_TEST_IS_BAREBONE) {
17
+ const utilFormat = require('exodus-test:util-format')
18
+ if (print) globalThis.print = (...args) => print(utilFormat(...args))
19
+ for (const type of consoleKeys) {
20
+ if (!Object.hasOwn(console, type)) continue
21
+ const orig = console[type].bind(console)
22
+ console[type] = (...args) => orig(utilFormat(...args))
23
+ }
24
+ }
25
+
26
+ if (!console.time || !console.timeEnd) {
27
+ const start = new Map()
28
+ const now = globalThis.performance?.now ? performance.now.bind(performance) : Date.now.bind(Date) // d8 and jsc have performance.now()
29
+ const warn = (text) => console.error(`Warning: ${text}`)
30
+ console.time = (key = 'default') => {
31
+ if (start.has(key)) return warn(`Label '${key}' already exists for console.time()`) // Does not reset
32
+ start.set(key, now()) // Start late
33
+ }
34
+
35
+ console.timeEnd = (key = 'default') => {
36
+ const ms = now() // End early
37
+ if (!start.has(key)) return warn(`No such label '${key}' for console.timeEnd()`)
38
+ console.log(`${key}: ${ms - start.get(key)}ms`)
39
+ start.delete(key)
40
+ }
41
+ }
42
+
43
+ if (!globalThis.fetch) {
44
+ globalThis.fetch = () => {
45
+ throw new Error('Fetch not supported')
46
+ }
47
+ }
48
+
49
+ if (!globalThis.WebSocket) {
50
+ globalThis.WebSocket = () => {
51
+ throw new Error('WebSocket not supported')
52
+ }
53
+ }
54
+
55
+ if (!Array.prototype.at) {
56
+ const at = function (i) {
57
+ return this[i < 0 ? this.length + i : i]
58
+ }
59
+
60
+ // eslint-disable-next-line no-extend-native
61
+ Object.defineProperty(Array.prototype, 'at', { configurable: true, writable: true, value: at })
62
+ }
63
+
64
+ if (process.env.EXODUS_TEST_PLATFORM === 'hermes') {
65
+ // Fixed after 0.12, not present in 0.12
66
+ // Refs: https://github.com/facebook/hermes/commit/e8fa81328dd630e39975e6d16ac3e6f47f4cba06
67
+ if (!Promise.allSettled) {
68
+ const wrap = (element) =>
69
+ Promise.resolve(element).then(
70
+ (value) => ({ status: 'fulfilled', value }),
71
+ (reason) => ({ status: 'rejected', reason })
72
+ )
73
+ Promise.allSettled = (iterable) => Promise.all([...iterable].map((element) => wrap(element)))
74
+ }
75
+
76
+ // Refs: https://github.com/facebook/hermes/commit/e97db61b49bd0c065a3ce7da46f074bc39b80c6a
77
+ if (!Promise.any) {
78
+ const AggregateError =
79
+ globalThis.AggregateError ||
80
+ class AggregateError extends Error {
81
+ constructor(errors, message) {
82
+ super(message)
83
+ this.name = 'AggregateError'
84
+ this.errors = errors
85
+ }
86
+ }
87
+
88
+ const errmsg = 'All promises were rejected'
89
+ Promise.any = function (values) {
90
+ const promises = [...values]
91
+ const errors = []
92
+ if (promises.length === 0) return Promise.reject(new AggregateError(errors, errmsg))
93
+ let resolved = false
94
+ return new Promise((resolve, reject) => {
95
+ const oneResolve = (value) => {
96
+ if (resolved) return
97
+ resolved = true
98
+ errors.length = 0
99
+ resolve(value)
100
+ }
101
+
102
+ const oneReject = (error) => {
103
+ if (resolved) return
104
+ errors.push(error)
105
+ if (errors.length === promises.length) reject(new AggregateError(errors, errmsg))
106
+ }
107
+
108
+ promises.forEach((promise) => Promise.resolve(promise).then(oneResolve, oneReject))
109
+ })
110
+ }
111
+ }
112
+ }
113
+
114
+ if (process.env.EXODUS_TEST_PLATFORM === 'quickjs' && globalThis.os) {
115
+ const { setTimeout, setInterval, clearTimeout, clearInterval } = globalThis.os
116
+ Object.assign(globalThis, { setTimeout, setInterval, clearTimeout, clearInterval })
117
+ for (const key of ['os', 'std', 'bjson']) delete globalThis[key]
118
+ }
119
+
120
+ if (globalThis.describe) delete globalThis.describe
121
+
122
+ if (
123
+ process.env.EXODUS_TEST_PLATFORM === 'hermes' ||
124
+ (process.env.EXODUS_TEST_IS_BAREBONE && !globalThis.clearTimeout)
125
+ ) {
126
+ // Ok, we have broken timers, let's hack them around
127
+ const { setTimeout: setTimeoutOriginal, clearTimeout: clearTimeoutOriginal } = globalThis
128
+ const tickTimes = async (n) => {
129
+ if (process.env.EXODUS_TEST_PLATFORM === 'escargot') {
130
+ // escargot is _special_ (slow on await, unless we drain manually)
131
+ let promise = Promise.resolve()
132
+ for (let i = 0; i < n; i++) promise = promise.then(() => {})
133
+ globalThis.drainJobQueue()
134
+ await promise
135
+ } else {
136
+ const promise = Promise.resolve() // tickTimes(0) is equivalent to one Promise.resolve() as it's async
137
+ for (let i = 0; i < n; i++) await promise
138
+ }
139
+ }
140
+
141
+ // TODO: use interrupt timers on jsc
142
+
143
+ const tickPromiseInterval = process.env.EXODUS_TEST_PLATFORM === 'engine262' ? 5 : 50 // engine262 is slow
144
+ const schedule = setTimeoutOriginal || ((x) => tickTimes(tickPromiseInterval).then(() => x())) // e.g. SpiderMonkey doesn't even have setTimeout
145
+ const dateNow = Date.now.bind(Date)
146
+ const precision = clearTimeoutOriginal ? Infinity : 10 // have to tick this fast for clearTimeout to work
147
+ let current = 0
148
+ let loopTimeout
149
+ let publicId = 0
150
+ const timerMap = new Map()
151
+ let queue = []
152
+ const stopLoop = () => {
153
+ clearTimeoutOriginal?.(loopTimeout)
154
+ current++
155
+ }
156
+
157
+ const restartLoop = () => {
158
+ if (loopTimeout !== undefined) clearTimeoutOriginal?.(loopTimeout) // hermes clearTimeout doesn't follow spec on undefined
159
+ const at = queue[0].runAt
160
+ const id = ++current
161
+ const tick = () => {
162
+ if (id !== current) return
163
+ const remaining = at - dateNow()
164
+ if (remaining <= 0) return queueTick()
165
+ loopTimeout = schedule(tick, Math.min(precision, remaining))
166
+ }
167
+
168
+ loopTimeout = schedule(tick, Math.min(precision, at - dateNow()))
169
+ }
170
+
171
+ const queueSchedule = (entry) => {
172
+ if (!entry.publicId) entry.publicId = ++publicId // eslint-disable-line @exodus/mutable/no-param-reassign-prop-only
173
+ timerMap.set(entry.publicId, entry)
174
+
175
+ const before = queue.findIndex((x) => x.runAt > entry.runAt)
176
+ if (before === -1) {
177
+ queue.push(entry)
178
+ } else {
179
+ queue.splice(before, 0, entry)
180
+ }
181
+
182
+ if (entry === queue[0]) restartLoop()
183
+ return entry.publicId
184
+ }
185
+
186
+ const queueMicrotick = () => {
187
+ if (queue.length === 0 || !(queue[0].runAt <= dateNow())) return null
188
+ const next = queue.shift()
189
+ if (next.interval === undefined) {
190
+ timerMap.delete(next.publicId)
191
+ } else {
192
+ next.runAt += next.interval
193
+ queueSchedule(next)
194
+ }
195
+
196
+ next.callback(...next.args)
197
+ }
198
+
199
+ const queueTick = () => {
200
+ current++ // safeguard
201
+ while (queueMicrotick() !== null);
202
+ if (queue.length > 0) restartLoop()
203
+ }
204
+
205
+ globalThis.setTimeout = (callback, delay = 0, ...args) =>
206
+ queueSchedule({ callback, runAt: delay + dateNow(), args })
207
+
208
+ globalThis.setInterval = (callback, delay = 0, ...args) =>
209
+ queueSchedule({ callback, runAt: delay + dateNow(), interval: delay, args })
210
+
211
+ globalThis.clearTimeout = globalThis.clearInterval = (id) => {
212
+ const entry = timerMap.get(id)
213
+ if (!entry) return
214
+ timerMap.delete(id)
215
+ queue = queue.filter((x) => x !== entry)
216
+ if (queue.length === 0) stopLoop()
217
+ }
218
+ }
219
+
220
+ const { setTimeout } = globalThis // we need non-overriden by fake timers one
221
+
222
+ const isBarebone = process.env.EXODUS_TEST_IS_BAREBONE
223
+ if (typeof process === 'undefined') {
224
+ // Fixes process.exitCode handling
225
+
226
+ const process = {
227
+ __proto__: null,
228
+ _exitCode: 0,
229
+ set exitCode(value) {
230
+ process._exitCode = value
231
+ if (globalThis.process) globalThis.process.exitCode = value
232
+ if (globalThis.Deno) globalThis.Deno.exitCode = value
233
+ },
234
+ get exitCode() {
235
+ return process._exitCode
236
+ },
237
+ exit: (code = 0) => {
238
+ globalThis.Deno?.exit?.(code)
239
+ globalThis.process?.exit?.(code)
240
+ process.exitCode = code
241
+ process._maybeProcessExitCode()
242
+ },
243
+ _exitHook: null,
244
+ _maybeProcessExitCode: () => {
245
+ if (globalThis.Deno) return // has native exitCode support
246
+ if (process._exitHook) return process._exitHook(process._exitCode)
247
+ if (process._exitCode !== 0) {
248
+ setTimeout(() => {
249
+ if (isBarebone) print('EXODUS_TEST_FAILED_EXIT_CODE_1')
250
+ const err = new Error('Test failed')
251
+ err.stack = ''
252
+ throw err
253
+ }, 0)
254
+ }
255
+ },
256
+ cwd: () => {
257
+ // eslint-disable-next-line no-undef
258
+ if (typeof EXODUS_TEST_PROCESS_CWD === 'string') return EXODUS_TEST_PROCESS_CWD
259
+ throw new Error('Can not determine cwd, no process available')
260
+ },
261
+ }
262
+
263
+ globalThis.EXODUS_TEST_PROCESS = process
264
+ } else {
265
+ Object.assign(process, { argv: process.argv }) // apply values from defined bundled vars, if present
266
+ }
267
+
268
+ if (process.env.EXODUS_TEST_PLATFORM === 'hermes' || process.env.EXODUS_TEST_IS_BROWSER) {
269
+ const print = console.log.bind(console) // we don not want overrides
270
+ let logHeader = () => {
271
+ globalThis.EXODUS_TEST_PROCESS.exitCode = 1
272
+ print(`‼ FATAL Tests generated asynchronous activity after they ended.
273
+ This activity created errors and would have caused tests to fail, but instead triggered unhandledRejection events`)
274
+ logHeader = () => {}
275
+ setTimeout(() => globalThis.EXODUS_TEST_PROCESS._maybeProcessExitCode(), 0)
276
+ }
277
+
278
+ if (process.env.EXODUS_TEST_PLATFORM === 'hermes') {
279
+ const onUnhandled = (i, err) => {
280
+ logHeader()
281
+ print(`Uncaught error #${i}: ${err}`)
282
+ }
283
+
284
+ globalThis.HermesInternal?.enablePromiseRejectionTracker({ allRejections: true, onUnhandled })
285
+ } else if (process.env.EXODUS_TEST_IS_BROWSER) {
286
+ // Won't catch all errors, as we might still be running, but better than nothing
287
+ // We also don't print anything except the header, as browsers already print that
288
+ // Cancelling the default behavior is less robust as we want to treat this as error
289
+ globalThis.addEventListener('unhandledrejection', () => logHeader())
290
+ }
291
+ }
292
+
293
+ if (!globalThis.crypto?.getRandomValues && globalThis.EXODUS_TEST_CRYPTO_ENTROPY) {
294
+ const entropy = Buffer.from(globalThis.EXODUS_TEST_CRYPTO_ENTROPY, 'base64')
295
+ let pos = 0
296
+ if (!globalThis.crypto) globalThis.crypto = {}
297
+ const TypedArray = Object.getPrototypeOf(Uint8Array)
298
+ globalThis.crypto.getRandomValues = (typedArray) => {
299
+ if (!(typedArray instanceof TypedArray)) throw new Error('Argument should be a TypedArray')
300
+ const view = Buffer.from(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength)
301
+ if (pos + view.length <= entropy.length) {
302
+ pos += view.length
303
+ const copied = entropy.copy(view, 0, pos - view.length)
304
+ if (copied !== view.length) throw new Error('Unexpected')
305
+ return typedArray
306
+ }
307
+
308
+ throw new Error(`Not enough csprng entropy in this test bundle (ref: @exodus/test)`)
309
+ }
310
+ }
311
+
312
+ delete globalThis.EXODUS_TEST_CRYPTO_ENTROPY
313
+
314
+ if (globalThis.crypto?.getRandomValues && !globalThis.crypto?.randomUUID) {
315
+ const getRandomValues = globalThis.crypto.getRandomValues.bind(globalThis.crypto)
316
+ let entropy
317
+
318
+ const hex = (start, end) => entropy.slice(start, end).toString('hex')
319
+
320
+ globalThis.crypto.randomUUID = () => {
321
+ if (!entropy) entropy = Buffer.alloc(16)
322
+
323
+ getRandomValues(entropy)
324
+ entropy[6] = (entropy[6] & 0x0f) | 0x40 // version 4: 0100xxxx
325
+ entropy[8] = (entropy[8] & 0x3f) | 0x80 // variant 1: 10xxxxxx
326
+
327
+ // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
328
+ return `${hex(0, 4)}-${hex(4, 6)}-${hex(6, 8)}-${hex(8, 10)}-${hex(10, 16)}`
329
+ }
330
+ }
331
+
332
+ if (!globalThis.crypto.subtle) globalThis.crypto.subtle = {} // For getRandomValues detection
333
+
334
+ if (process.env.EXODUS_TEST_IS_BAREBONE) {
335
+ if (!globalThis.URLSearchParams) globalThis.URLSearchParams = require('@ungap/url-search-params')
336
+ if (!globalThis.TextEncoder || !globalThis.TextDecoder) {
337
+ const { TextEncoder, TextDecoder } = require('exodus-test:text-encoding-utf')
338
+ if (!globalThis.TextEncoder) globalThis.TextEncoder = TextEncoder
339
+ if (!globalThis.TextDecoder) global.TextDecoder = TextDecoder
340
+ }
341
+ }
@@ -0,0 +1,8 @@
1
+ // A slimmed-down version of globals.cjs specifically for Node.js bundle
2
+ Object.assign(process, { argv: process.argv })
3
+
4
+ if (!globalThis.crypto) {
5
+ // Old Node.js, we polyfill it as our bundler polyfills crypto module using webcrypto RNG
6
+ const r = require // prevent embed
7
+ globalThis.crypto = r('node:crypto').webcrypto
8
+ }