headlamp 0.1.22 → 0.1.24

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,579 @@
1
+ /* eslint-disable global-require */
2
+ /* eslint-disable @typescript-eslint/no-require-imports */
3
+ /* eslint-disable import/no-dynamic-require */
4
+
5
+ const { createRequire } = require('node:module');
6
+
7
+ const requireFromCwd = (id) => {
8
+ try {
9
+ return createRequire(`${process.cwd()}/`)(id);
10
+ } catch {
11
+ try {
12
+ return require(id);
13
+ } catch {
14
+ return undefined;
15
+ }
16
+ }
17
+ };
18
+
19
+ let NodeEnvironment = requireFromCwd('jest-environment-node');
20
+ if (NodeEnvironment && NodeEnvironment.TestEnvironment) {
21
+ NodeEnvironment = NodeEnvironment.TestEnvironment;
22
+ } else if (NodeEnvironment && NodeEnvironment.default) {
23
+ NodeEnvironment = NodeEnvironment.default;
24
+ }
25
+
26
+ module.exports = class BridgeEnv extends NodeEnvironment {
27
+ constructor(config, context) {
28
+ super(config, context);
29
+ this._cleanup = [];
30
+ try {
31
+ const { AsyncLocalStorage } = require('node:async_hooks');
32
+ this._als = new AsyncLocalStorage();
33
+ } catch {
34
+ this._als = {
35
+ getStore() {
36
+ return undefined;
37
+ },
38
+ enterWith() {},
39
+ };
40
+ }
41
+ try {
42
+ const fs = require('node:fs');
43
+ const dbgPath = process.env.JEST_BRIDGE_DEBUG_PATH;
44
+ this._dbg = (msg) => {
45
+ try {
46
+ if (process.env.JEST_BRIDGE_DEBUG && dbgPath) {
47
+ fs.appendFileSync(dbgPath, `${String(msg)}\\n`, 'utf8');
48
+ }
49
+ } catch {}
50
+ };
51
+ } catch {}
52
+ }
53
+
54
+ _ctx() {
55
+ try {
56
+ const s = this._als.getStore();
57
+ if (s) return s;
58
+ } catch {}
59
+ try {
60
+ const st =
61
+ this.global.expect && typeof this.global.expect.getState === 'function'
62
+ ? this.global.expect.getState()
63
+ : {};
64
+ return { testPath: st.testPath, currentTestName: st.currentTestName };
65
+ } catch {
66
+ return {};
67
+ }
68
+ }
69
+
70
+ async setup() {
71
+ await super.setup();
72
+
73
+ try {
74
+ Error.stackTraceLimit = Math.max(Error.stackTraceLimit || 10, 50);
75
+ } catch {}
76
+
77
+ const print = (payload) => {
78
+ try {
79
+ const stderr =
80
+ this.global && this.global.process && this.global.process.stderr
81
+ ? this.global.process.stderr
82
+ : process.stderr;
83
+ let line = '[JEST-BRIDGE-EVENT] ';
84
+ try {
85
+ line += JSON.stringify(payload);
86
+ } catch {
87
+ line += JSON.stringify({ type: String((payload && payload.type) || 'unknown') });
88
+ }
89
+ stderr.write(`${line}\\n`);
90
+ } catch {}
91
+ };
92
+ // Expose to class methods (e.g., handleTestEvent). Also keep a safe fallback.
93
+ try {
94
+ this._emitBridge = (p) => print(p);
95
+ } catch {}
96
+ const toErr = (x) => {
97
+ try {
98
+ return x instanceof Error ? x : new Error(String(x));
99
+ } catch {
100
+ return new Error('unknown');
101
+ }
102
+ };
103
+
104
+ const onRej = (reason) => {
105
+ const e = toErr(reason);
106
+ const c = this._ctx();
107
+ print({
108
+ type: 'unhandledRejection',
109
+ name: e.name,
110
+ message: e.message,
111
+ stack: e.stack,
112
+ code: e.code ?? undefined,
113
+ ...c,
114
+ });
115
+ };
116
+ const onExc = (error) => {
117
+ const e = toErr(error);
118
+ const c = this._ctx();
119
+ print({
120
+ type: 'uncaughtException',
121
+ name: e.name,
122
+ message: e.message,
123
+ stack: e.stack,
124
+ code: e.code ?? undefined,
125
+ ...c,
126
+ });
127
+ };
128
+
129
+ this.global.process.on('unhandledRejection', onRej);
130
+ this.global.process.on('uncaughtException', onExc);
131
+ this._cleanup.push(() => {
132
+ try {
133
+ const proc = this.global && this.global.process ? this.global.process : process;
134
+ const off =
135
+ typeof proc.off === 'function' ? proc.off.bind(proc) : proc.removeListener.bind(proc);
136
+ off('unhandledRejection', onRej);
137
+ off('uncaughtException', onExc);
138
+ } catch {}
139
+ });
140
+
141
+ // Signal environment readiness so we can confirm the custom env loaded
142
+ try {
143
+ const c = this._ctx();
144
+ print({ type: 'envReady', ...c });
145
+ } catch {}
146
+ try {
147
+ if (this._dbg) this._dbg('envReady');
148
+ } catch {}
149
+ // Capture console output during tests and emit a batch per test case
150
+ try {
151
+ const g = this.global;
152
+ const self = this;
153
+ const levels = ['log', 'info', 'warn', 'error'];
154
+ const originals = {};
155
+ const maxEntries = 200;
156
+ const toText = (args) => {
157
+ try {
158
+ return args.map((v) => (typeof v === 'string' ? v : JSON.stringify(v))).join(' ');
159
+ } catch {
160
+ return args.map(String).join(' ');
161
+ }
162
+ };
163
+ if (!g.__JEST_CONSOLE_BUFFER__) {
164
+ g.__JEST_CONSOLE_BUFFER__ = [];
165
+ }
166
+ for (const lvl of levels) {
167
+ try {
168
+ originals[lvl] =
169
+ g.console[lvl] && g.console[lvl].bind ? g.console[lvl].bind(g.console) : g.console[lvl];
170
+ g.console[lvl] = (...args) => {
171
+ try {
172
+ const buf = Array.isArray(g.__JEST_CONSOLE_BUFFER__)
173
+ ? g.__JEST_CONSOLE_BUFFER__
174
+ : (g.__JEST_CONSOLE_BUFFER__ = []);
175
+ const msg = toText(args);
176
+ buf.push({ type: lvl, message: msg, ts: Date.now() });
177
+ if (buf.length > maxEntries) buf.splice(0, buf.length - maxEntries);
178
+ try {
179
+ const c = self._ctx();
180
+ print({ type: 'console', level: lvl, message: msg, ...c });
181
+ } catch {}
182
+ try {
183
+ if (self._dbg) {
184
+ self._dbg(`console:${String(lvl)}:${String(msg).slice(0, 120)}`);
185
+ }
186
+ } catch {}
187
+ } catch {}
188
+ try {
189
+ return originals[lvl](...args);
190
+ } catch {
191
+ return undefined;
192
+ }
193
+ };
194
+ } catch {}
195
+ }
196
+ this._cleanup.push(() => {
197
+ try {
198
+ for (const lvl of levels) {
199
+ if (originals[lvl]) g.console[lvl] = originals[lvl];
200
+ }
201
+ } catch {}
202
+ });
203
+ } catch {}
204
+
205
+ try {
206
+ const http = require('node:http');
207
+
208
+ const PATCH_FLAG = Symbol.for('jestBridgePatched');
209
+ const ORIGINAL_KEY = Symbol.for('jestBridgeOriginalEmit');
210
+
211
+ const originalEmit =
212
+ http &&
213
+ http.Server &&
214
+ http.Server.prototype &&
215
+ typeof http.Server.prototype.emit === 'function'
216
+ ? http.Server.prototype.emit
217
+ : null;
218
+ if (originalEmit) {
219
+ // Skip if another worker has already patched it.
220
+ if (http.Server.prototype.emit[PATCH_FLAG]) {
221
+ try {
222
+ this.global.__JEST_BRIDGE_ENV_REF = this;
223
+ global.__JEST_BRIDGE_ENV_REF = this;
224
+ } catch {}
225
+ this._cleanup.push(() => {});
226
+ } else {
227
+ const MAX = 64 * 1024;
228
+ const asString = (x) => {
229
+ try {
230
+ if (typeof x === 'string') return x;
231
+ if (Buffer.isBuffer(x)) return x.toString('utf8');
232
+ return String(x);
233
+ } catch {
234
+ return '';
235
+ }
236
+ };
237
+
238
+ const patched = function (eventName, req, res) {
239
+ try {
240
+ if (
241
+ eventName === 'request' &&
242
+ req &&
243
+ res &&
244
+ typeof res.write === 'function' &&
245
+ typeof res.end === 'function'
246
+ ) {
247
+ const startAt = Date.now();
248
+ const safeHeader = (k) => {
249
+ try {
250
+ return req && req.headers ? String(req.headers[k.toLowerCase()] ?? '') : '';
251
+ } catch {
252
+ return '';
253
+ }
254
+ };
255
+ const reqIdHeader = safeHeader('x-request-id');
256
+ const chunks = [];
257
+ const write = res.write.bind(res);
258
+ const end = res.end.bind(res);
259
+ const method = req.method ? String(req.method) : undefined;
260
+ const url =
261
+ req.originalUrl || req.url ? String(req.originalUrl || req.url) : undefined;
262
+
263
+ res.write = function (chunk, enc, cb) {
264
+ try {
265
+ const s = asString(chunk);
266
+ if (s) chunks.push(s);
267
+ } catch {}
268
+ return write(chunk, enc, cb);
269
+ };
270
+ res.end = function (chunk, enc, cb) {
271
+ try {
272
+ const s = asString(chunk);
273
+ if (s) chunks.push(s);
274
+ } catch {}
275
+ try {
276
+ const preview = chunks.join('').slice(0, MAX);
277
+ const statusCode =
278
+ typeof res.statusCode === 'number' ? res.statusCode : undefined;
279
+ const ct =
280
+ (typeof res.getHeader === 'function' && res.getHeader('content-type')) ||
281
+ undefined;
282
+ const routePath =
283
+ (req && req.route && req.route.path) ||
284
+ (req && req.baseUrl && req.path ? req.baseUrl + req.path : undefined);
285
+ const jsonParsed = (() => {
286
+ try {
287
+ return JSON.parse(preview);
288
+ } catch {
289
+ return undefined;
290
+ }
291
+ })();
292
+ const requestId =
293
+ reqIdHeader ||
294
+ (jsonParsed && typeof jsonParsed === 'object'
295
+ ? jsonParsed.requestId || jsonParsed.reqId || ''
296
+ : '');
297
+ const ctx =
298
+ global.__JEST_BRIDGE_ENV_REF && global.__JEST_BRIDGE_ENV_REF._ctx
299
+ ? global.__JEST_BRIDGE_ENV_REF._ctx()
300
+ : {};
301
+ const payload = {
302
+ type: 'httpResponse',
303
+ timestampMs: Date.now(),
304
+ durationMs: Math.max(0, Date.now() - startAt),
305
+ method,
306
+ url,
307
+ statusCode,
308
+ route: routePath ? String(routePath) : undefined,
309
+ contentType: ct ? String(ct) : undefined,
310
+ headers: typeof res.getHeaders === 'function' ? res.getHeaders() : undefined,
311
+ requestId: requestId ? String(requestId) : undefined,
312
+ bodyPreview: preview,
313
+ json: jsonParsed,
314
+ testPath: ctx.testPath,
315
+ currentTestName: ctx.currentTestName,
316
+ };
317
+ try {
318
+ if (!global.__JEST_HTTP_EVENTS__) global.__JEST_HTTP_EVENTS__ = [];
319
+ const arr = global.__JEST_HTTP_EVENTS__;
320
+ arr.push({
321
+ timestampMs: payload.timestampMs,
322
+ durationMs: payload.durationMs,
323
+ method: payload.method,
324
+ url: payload.url,
325
+ route: payload.route,
326
+ statusCode: payload.statusCode,
327
+ contentType: payload.contentType,
328
+ requestId: payload.requestId,
329
+ json: payload.json,
330
+ bodyPreview: payload.bodyPreview,
331
+ });
332
+ if (arr.length > 25) arr.splice(0, arr.length - 25);
333
+ } catch {}
334
+ try {
335
+ print(payload);
336
+ } catch {}
337
+ } catch {}
338
+ return end(chunk, enc, cb);
339
+ };
340
+ try {
341
+ res.on('close', () => {
342
+ try {
343
+ const ended =
344
+ typeof res.writableEnded === 'boolean' ? res.writableEnded : false;
345
+ if (!ended) {
346
+ const routePath =
347
+ (req && req.route && req.route.path) ||
348
+ (req && req.baseUrl && req.path ? req.baseUrl + req.path : undefined);
349
+ const ctx =
350
+ global.__JEST_BRIDGE_ENV_REF && global.__JEST_BRIDGE_ENV_REF._ctx
351
+ ? global.__JEST_BRIDGE_ENV_REF._ctx()
352
+ : {};
353
+ const payload = {
354
+ type: 'httpAbort',
355
+ timestampMs: Date.now(),
356
+ durationMs: Math.max(0, Date.now() - startAt),
357
+ method,
358
+ url,
359
+ route: routePath ? String(routePath) : undefined,
360
+ testPath: ctx.testPath,
361
+ currentTestName: ctx.currentTestName,
362
+ };
363
+ try {
364
+ print(payload);
365
+ } catch {}
366
+ }
367
+ } catch {}
368
+ });
369
+ } catch {}
370
+ }
371
+ } catch {}
372
+ return originalEmit.apply(this, arguments);
373
+ };
374
+
375
+ try {
376
+ this.global.__JEST_BRIDGE_ENV_REF = this;
377
+ global.__JEST_BRIDGE_ENV_REF = this;
378
+ } catch {}
379
+
380
+ patched[PATCH_FLAG] = true;
381
+ patched[ORIGINAL_KEY] = originalEmit;
382
+ http.Server.prototype.emit = patched;
383
+
384
+ this._cleanup.push(() => {
385
+ try {
386
+ if (
387
+ http.Server &&
388
+ http.Server.prototype &&
389
+ typeof http.Server.prototype.emit === 'function'
390
+ ) {
391
+ const current = http.Server.prototype.emit;
392
+ if (current && current[PATCH_FLAG]) {
393
+ const orig = current[ORIGINAL_KEY] || originalEmit;
394
+ if (typeof orig === 'function') http.Server.prototype.emit = orig;
395
+ }
396
+ }
397
+ } catch {}
398
+ try {
399
+ delete this.global.__JEST_BRIDGE_ENV_REF;
400
+ } catch {}
401
+ });
402
+ }
403
+ }
404
+ } catch {}
405
+
406
+ // Wrap test functions to emit rich assertion events on failures
407
+ try {
408
+ const g = this.global;
409
+ const ctxFn = () => {
410
+ try {
411
+ const ref = g.__JEST_BRIDGE_ENV_REF;
412
+ return ref && typeof ref._ctx === 'function' ? ref._ctx() : {};
413
+ } catch {
414
+ return {};
415
+ }
416
+ };
417
+ const emitAssertion = (err) => {
418
+ try {
419
+ const e = toErr(err);
420
+ const mr = e && typeof e === 'object' && e.matcherResult ? e.matcherResult : undefined;
421
+ const messageText = (() => {
422
+ try {
423
+ return mr && typeof mr.message === 'function'
424
+ ? String(mr.message())
425
+ : e.message || '';
426
+ } catch {
427
+ return e.message || '';
428
+ }
429
+ })();
430
+ const expectedPreview = (() => {
431
+ try {
432
+ return mr && mr.expected !== undefined
433
+ ? JSON.stringify(mr.expected, null, 2)
434
+ : undefined;
435
+ } catch {
436
+ return undefined;
437
+ }
438
+ })();
439
+ const actualPreview = (() => {
440
+ try {
441
+ return mr && mr.received !== undefined
442
+ ? JSON.stringify(mr.received, null, 2)
443
+ : undefined;
444
+ } catch {
445
+ return undefined;
446
+ }
447
+ })();
448
+ const c = ctxFn();
449
+ print({
450
+ type: 'assertionFailure',
451
+ timestampMs: Date.now(),
452
+ matcher: mr && typeof mr.matcherName === 'string' ? mr.matcherName : undefined,
453
+ expectedPreview,
454
+ actualPreview,
455
+ expectedNumber: typeof (mr && mr.expected) === 'number' ? mr.expected : undefined,
456
+ receivedNumber: typeof (mr && mr.received) === 'number' ? mr.received : undefined,
457
+ message: messageText,
458
+ stack: e.stack,
459
+ ...c,
460
+ });
461
+ } catch {}
462
+ };
463
+ const wrap = (orig) => {
464
+ if (!orig || typeof orig !== 'function') return orig;
465
+ const wrapped = function (name, fn, timeout) {
466
+ if (typeof fn !== 'function') return orig.call(this, name, fn, timeout);
467
+ const run = function () {
468
+ try {
469
+ const res = fn.apply(this, arguments);
470
+ if (res && typeof res.then === 'function') {
471
+ return res.catch((err) => {
472
+ emitAssertion(err);
473
+ throw err;
474
+ });
475
+ }
476
+ return res;
477
+ } catch (err) {
478
+ emitAssertion(err);
479
+ throw err;
480
+ }
481
+ };
482
+ return orig.call(this, name, run, timeout);
483
+ };
484
+ try {
485
+ wrapped.only = orig.only && typeof orig.only === 'function' ? wrap(orig.only) : orig.only;
486
+ } catch {}
487
+ try {
488
+ wrapped.skip = orig.skip && typeof orig.skip === 'function' ? wrap(orig.skip) : orig.skip;
489
+ } catch {}
490
+ return wrapped;
491
+ };
492
+ try {
493
+ g.it = wrap(g.it);
494
+ } catch {}
495
+ try {
496
+ g.test = wrap(g.test);
497
+ } catch {}
498
+ } catch {}
499
+ }
500
+
501
+ async handleTestEvent(evt, state) {
502
+ if (evt && evt.name === 'test_start') {
503
+ const tn = evt.test && evt.test.name ? evt.test.name : undefined;
504
+ const store = {
505
+ testPath: state && state.testPath ? state.testPath : undefined,
506
+ currentTestName: tn,
507
+ };
508
+ try {
509
+ this._als && typeof this._als.enterWith === 'function' && this._als.enterWith(store);
510
+ } catch {}
511
+ try {
512
+ this._emitBridge &&
513
+ this._emitBridge({ type: 'testStart', testPath: store.testPath, currentTestName: tn });
514
+ } catch {}
515
+ } else if (evt && evt.name === 'test_done') {
516
+ try {
517
+ this._als && typeof this._als.enterWith === 'function' && this._als.enterWith({});
518
+ } catch {}
519
+
520
+ // Flush HTTP batch (global buffer)
521
+ try {
522
+ const events = Array.isArray(global.__JEST_HTTP_EVENTS__)
523
+ ? global.__JEST_HTTP_EVENTS__
524
+ : [];
525
+ if (events.length) {
526
+ const batch = events.slice(-10);
527
+ const payload = {
528
+ type: 'httpResponseBatch',
529
+ events: batch,
530
+ testPath: state && state.testPath ? state.testPath : undefined,
531
+ currentTestName: evt.test && evt.test.name ? evt.test.name : undefined,
532
+ };
533
+ try {
534
+ this._emitBridge && this._emitBridge(payload);
535
+ } catch {}
536
+ try {
537
+ global.__JEST_HTTP_EVENTS__ = [];
538
+ } catch {}
539
+ }
540
+ } catch {}
541
+
542
+ // Flush console batch (sandbox buffer)
543
+ try {
544
+ const buf = Array.isArray(this.global.__JEST_CONSOLE_BUFFER__)
545
+ ? this.global.__JEST_CONSOLE_BUFFER__
546
+ : [];
547
+ if (buf.length) {
548
+ const payload = {
549
+ type: 'consoleBatch',
550
+ entries: buf.slice(-200),
551
+ testPath: state && state.testPath ? state.testPath : undefined,
552
+ currentTestName: evt.test && evt.test.name ? evt.test.name : undefined,
553
+ };
554
+ try {
555
+ this._emitBridge && this._emitBridge(payload);
556
+ } catch {}
557
+ try {
558
+ this.global.__JEST_CONSOLE_BUFFER__ = [];
559
+ } catch {}
560
+ try {
561
+ this._dbg && this._dbg(`consoleBatch:${String(buf.length)}`);
562
+ } catch {}
563
+ }
564
+ } catch {}
565
+ }
566
+ }
567
+
568
+ async teardown() {
569
+ for (let i = this._cleanup.length - 1; i >= 0; i--) {
570
+ try {
571
+ this._cleanup[i]();
572
+ } catch {}
573
+ }
574
+ try {
575
+ delete global.__JEST_BRIDGE_ENV_REF;
576
+ } catch {}
577
+ await super.teardown();
578
+ }
579
+ };