bruno-lifecycle-adapter 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/index.js ADDED
@@ -0,0 +1,668 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ BruFileScanner: () => BruFileScanner,
24
+ BrunoJsonReportParser: () => BrunoJsonReportParser,
25
+ BrunoLifecycleAdapter: () => BrunoLifecycleAdapter,
26
+ TypedEventBus: () => TypedEventBus
27
+ });
28
+ module.exports = __toCommonJS(index_exports);
29
+
30
+ // src/application/BrunoLifecycleAdapter.ts
31
+ var import_node_child_process = require("child_process");
32
+ var import_node_path2 = require("path");
33
+
34
+ // src/infrastructure/BrunoJsonReportParser.ts
35
+ var import_promises = require("fs/promises");
36
+
37
+ // src/shared/utils.ts
38
+ var import_node_crypto = require("crypto");
39
+ function generateRunId() {
40
+ return (0, import_node_crypto.randomUUID)();
41
+ }
42
+ function nowIso() {
43
+ return (/* @__PURE__ */ new Date()).toISOString();
44
+ }
45
+ function elapsedMs(startedAt) {
46
+ return Date.now() - new Date(startedAt).getTime();
47
+ }
48
+
49
+ // src/infrastructure/BrunoJsonReportParser.ts
50
+ var BrunoJsonReportParser = class {
51
+ async parse(reportPath) {
52
+ const raw = await this.readRaw(reportPath);
53
+ return this.mapToSummary(raw);
54
+ }
55
+ async readRaw(reportPath) {
56
+ let content;
57
+ try {
58
+ content = await (0, import_promises.readFile)(reportPath, "utf-8");
59
+ } catch (err) {
60
+ throw new Error(
61
+ `BrunoJsonReportParser: cannot read report at "${reportPath}": ${String(err)}`,
62
+ { cause: err }
63
+ );
64
+ }
65
+ let parsed;
66
+ try {
67
+ parsed = JSON.parse(content);
68
+ } catch (err) {
69
+ throw new Error(
70
+ `BrunoJsonReportParser: invalid JSON in report at "${reportPath}": ${String(err)}`,
71
+ { cause: err }
72
+ );
73
+ }
74
+ if (Array.isArray(parsed)) {
75
+ return parsed;
76
+ }
77
+ if (parsed !== null && typeof parsed === "object") {
78
+ const obj = parsed;
79
+ const results = Array.isArray(obj.results) ? obj.results : [];
80
+ const summary = obj.summary !== null && typeof obj.summary === "object" ? obj.summary : void 0;
81
+ const iteration = {
82
+ iterationIndex: typeof obj.iterationIndex === "number" ? obj.iterationIndex : 0,
83
+ results,
84
+ ...summary !== void 0 ? { summary } : {}
85
+ };
86
+ return [iteration];
87
+ }
88
+ return [];
89
+ }
90
+ mapToSummary(raw) {
91
+ const requests = raw.flatMap((iter) => (iter.results ?? []).map((r) => this.mapRequest(r)));
92
+ const summary = raw[0]?.summary ?? {};
93
+ const totalRequests = summary.totalRequests ?? requests.length;
94
+ const passedRequests = summary.passedRequests ?? requests.filter((r) => r.status === "finished").length;
95
+ const failedRequests = summary.failedRequests ?? requests.filter((r) => r.status === "failed").length;
96
+ const skippedRequests = summary.skippedRequests ?? requests.filter((r) => r.status === "skipped").length;
97
+ const allTests = requests.flatMap((r) => r.tests);
98
+ const totalTests = summary.totalTests ?? allTests.length;
99
+ const passedTests = summary.passedTests ?? allTests.filter((t) => t.status === "passed").length;
100
+ const failedTests = summary.failedTests ?? allTests.filter((t) => t.status === "failed").length;
101
+ const allAssertions = requests.flatMap((r) => r.assertions);
102
+ const totalAssertions = summary.totalAssertions ?? allAssertions.length;
103
+ const passedAssertions = summary.passedAssertions ?? allAssertions.filter((a) => a.passed).length;
104
+ const failedAssertions = summary.failedAssertions ?? allAssertions.filter((a) => !a.passed).length;
105
+ const now = nowIso();
106
+ return {
107
+ runId: "",
108
+ collectionPath: "",
109
+ startedAt: now,
110
+ finishedAt: now,
111
+ durationMs: 0,
112
+ exitCode: 0,
113
+ status: failedRequests > 0 ? "failed" : "finished",
114
+ totalRequests,
115
+ passedRequests,
116
+ failedRequests,
117
+ skippedRequests,
118
+ totalTests,
119
+ passedTests,
120
+ failedTests,
121
+ totalAssertions,
122
+ passedAssertions,
123
+ failedAssertions,
124
+ requests
125
+ };
126
+ }
127
+ mapRequest(raw) {
128
+ const tests = (raw.testResults ?? []).map((t) => this.mapTest(t));
129
+ const assertions = (raw.assertionResults ?? []).map((a) => this.mapAssertion(a));
130
+ const responseStatus = typeof raw.response?.status === "number" ? raw.response.status : void 0;
131
+ return {
132
+ requestName: raw.name ?? raw.test?.filename ?? "unknown",
133
+ requestFile: raw.test?.filename ?? "",
134
+ status: this.mapRequestStatus(raw.status),
135
+ ...responseStatus !== void 0 ? { responseStatus } : {},
136
+ ...raw.response?.responseTime !== void 0 ? { durationMs: raw.response.responseTime } : {},
137
+ ...raw.error ? { error: this.makeError(String(raw.error)) } : {},
138
+ tests,
139
+ assertions
140
+ };
141
+ }
142
+ mapTest(raw) {
143
+ return {
144
+ testName: raw.description ?? "unknown",
145
+ status: this.mapTestStatus(raw.status),
146
+ ...raw.error ? { error: this.makeError(String(raw.error)) } : {}
147
+ };
148
+ }
149
+ mapAssertion(raw) {
150
+ const passed = raw.status === "pass" || raw.status === "passed";
151
+ const assertion = raw.lhsExpr !== void 0 && raw.rhsExpr !== void 0 ? `${raw.lhsExpr} ${raw.rhsExpr}` : "unknown";
152
+ return {
153
+ assertion,
154
+ passed,
155
+ ...raw.error ? { error: this.makeError(String(raw.error)) } : {}
156
+ };
157
+ }
158
+ mapRequestStatus(status) {
159
+ switch (status?.toLowerCase()) {
160
+ case "pass":
161
+ case "passed":
162
+ case "success":
163
+ return "finished";
164
+ case "fail":
165
+ case "failed":
166
+ case "error":
167
+ return "failed";
168
+ case "skip":
169
+ case "skipped":
170
+ return "skipped";
171
+ default:
172
+ return "finished";
173
+ }
174
+ }
175
+ mapTestStatus(status) {
176
+ switch (status?.toLowerCase()) {
177
+ case "pass":
178
+ case "passed":
179
+ return "passed";
180
+ case "fail":
181
+ case "failed":
182
+ return "failed";
183
+ case "skip":
184
+ case "skipped":
185
+ return "skipped";
186
+ default:
187
+ return "failed";
188
+ }
189
+ }
190
+ makeError(message) {
191
+ return { message };
192
+ }
193
+ };
194
+
195
+ // src/infrastructure/BruFileScanner.ts
196
+ var import_promises2 = require("fs/promises");
197
+ var import_node_path = require("path");
198
+ var BruFileScanner = class {
199
+ /**
200
+ * Returns all HTTP request files found under `rootDir`.
201
+ *
202
+ * @param rootDir Absolute path to the collection root (the directory
203
+ * passed to `bru run`).
204
+ * @param recursive When `true`, descends into sub-directories. Mirrors
205
+ * the `-r` flag behaviour of `bru run`.
206
+ */
207
+ async scan(rootDir, recursive) {
208
+ const found = await this.collectBruFiles(rootDir, rootDir, recursive);
209
+ found.sort((a, b) => a.requestFile.localeCompare(b.requestFile));
210
+ return found;
211
+ }
212
+ // ---------------------------------------------------------------------------
213
+ // Private helpers
214
+ // ---------------------------------------------------------------------------
215
+ async collectBruFiles(rootDir, dir, recursive) {
216
+ let entries;
217
+ try {
218
+ entries = await (0, import_promises2.readdir)(dir, { withFileTypes: true });
219
+ } catch {
220
+ return [];
221
+ }
222
+ const results = [];
223
+ for (const entry of entries) {
224
+ const fullPath = (0, import_node_path.join)(dir, entry.name);
225
+ if (entry.isDirectory()) {
226
+ if (entry.name === "environments") continue;
227
+ if (recursive) {
228
+ const nested = await this.collectBruFiles(rootDir, fullPath, true);
229
+ results.push(...nested);
230
+ }
231
+ } else if (entry.isFile() && entry.name.endsWith(".bru")) {
232
+ const discovered = await this.parseRequestFile(rootDir, fullPath);
233
+ if (discovered !== null) {
234
+ results.push(discovered);
235
+ }
236
+ }
237
+ }
238
+ return results;
239
+ }
240
+ async parseRequestFile(rootDir, filePath) {
241
+ let content;
242
+ try {
243
+ content = await (0, import_promises2.readFile)(filePath, "utf-8");
244
+ } catch {
245
+ return null;
246
+ }
247
+ const meta = this.parseMetaBlock(content);
248
+ if (!meta.type || meta.type !== "http") {
249
+ return null;
250
+ }
251
+ const requestName = meta.name ?? this.nameFromPath(filePath);
252
+ const requestFile = (0, import_node_path.relative)(rootDir, filePath).replace(/\\/g, "/");
253
+ return { requestName, requestFile };
254
+ }
255
+ parseMetaBlock(content) {
256
+ const metaMatch = content.match(/meta\s*\{([^}]*)\}/s);
257
+ if (!metaMatch) return { name: void 0, type: void 0 };
258
+ const block = metaMatch[1];
259
+ const nameMatch = block.match(/\bname:\s*([^\n]+)/);
260
+ const typeMatch = block.match(/\btype:\s*([^\n]+)/);
261
+ return {
262
+ name: nameMatch?.[1]?.trim(),
263
+ type: typeMatch?.[1]?.trim()
264
+ };
265
+ }
266
+ nameFromPath(filePath) {
267
+ const parts = filePath.replace(/\\/g, "/").split("/");
268
+ return parts.at(-1)?.replace(/\.bru$/, "") ?? "unknown";
269
+ }
270
+ };
271
+
272
+ // src/infrastructure/TypedEventBus.ts
273
+ var TypedEventBus = class {
274
+ handlers = /* @__PURE__ */ new Map();
275
+ on(event, handler) {
276
+ this.getOrCreate(event).add(handler);
277
+ return () => this.off(event, handler);
278
+ }
279
+ once(event, handler) {
280
+ const wrapper = (payload) => {
281
+ this.off(event, wrapper);
282
+ handler(payload);
283
+ };
284
+ return this.on(event, wrapper);
285
+ }
286
+ off(event, handler) {
287
+ this.handlers.get(event)?.delete(handler);
288
+ }
289
+ emit(event, payload) {
290
+ const set = this.handlers.get(event);
291
+ if (!set) return;
292
+ for (const handler of set) {
293
+ handler(payload);
294
+ }
295
+ }
296
+ removeAllListeners(event) {
297
+ if (event !== void 0) {
298
+ this.handlers.delete(event);
299
+ } else {
300
+ this.handlers.clear();
301
+ }
302
+ }
303
+ getOrCreate(event) {
304
+ let set = this.handlers.get(event);
305
+ if (!set) {
306
+ set = /* @__PURE__ */ new Set();
307
+ this.handlers.set(event, set);
308
+ }
309
+ return set;
310
+ }
311
+ };
312
+
313
+ // src/application/BrunoLifecycleAdapter.ts
314
+ var BrunoLifecycleAdapter = class {
315
+ bus = new TypedEventBus();
316
+ parser;
317
+ scanner;
318
+ constructor(parser, scanner) {
319
+ this.parser = parser ?? new BrunoJsonReportParser();
320
+ this.scanner = scanner ?? new BruFileScanner();
321
+ }
322
+ on(event, handler) {
323
+ return this.bus.on(event, handler);
324
+ }
325
+ once(event, handler) {
326
+ return this.bus.once(event, handler);
327
+ }
328
+ off(event, handler) {
329
+ this.bus.off(event, handler);
330
+ }
331
+ async run(config) {
332
+ const runId = generateRunId();
333
+ const startedAt = nowIso();
334
+ this.emit("run:starting", {
335
+ event: "run:starting",
336
+ runId,
337
+ timestamp: startedAt,
338
+ reliability: "native",
339
+ cwd: config.cwd,
340
+ collectionPath: config.collectionPath
341
+ });
342
+ const resolvedCollection = (0, import_node_path2.resolve)(config.cwd, config.collectionPath);
343
+ const collectionRoot = resolvedCollection.endsWith(".bru") ? (0, import_node_path2.dirname)(resolvedCollection) : resolvedCollection;
344
+ const discoveryPromise = this.scanner.scan(collectionRoot, config.recursive ?? false).catch(() => []);
345
+ const args = this.buildArgs(config);
346
+ const bin = config.bruBin ?? "bru";
347
+ return new Promise((resolveRun, rejectRun) => {
348
+ let timedOut = false;
349
+ let timeoutHandle;
350
+ const child = (0, import_node_child_process.spawn)(bin, args, {
351
+ cwd: config.cwd,
352
+ stdio: ["ignore", "pipe", "pipe"],
353
+ shell: false
354
+ });
355
+ if (child.pid === void 0) {
356
+ const err = new Error(`Failed to spawn "${bin}". Is Bruno CLI installed?`);
357
+ const finishedAt = nowIso();
358
+ const durationMs = elapsedMs(startedAt);
359
+ const detail = { message: err.message };
360
+ const summary = this.buildEmptySummary({
361
+ runId,
362
+ collectionPath: config.collectionPath,
363
+ startedAt,
364
+ finishedAt,
365
+ durationMs,
366
+ exitCode: -1,
367
+ status: "failed",
368
+ error: detail
369
+ });
370
+ this.emit("run:failed", {
371
+ event: "run:failed",
372
+ runId,
373
+ timestamp: finishedAt,
374
+ reliability: "native",
375
+ exitCode: -1,
376
+ durationMs,
377
+ error: detail,
378
+ summary
379
+ });
380
+ rejectRun(err);
381
+ return;
382
+ }
383
+ this.emit("run:started", {
384
+ event: "run:started",
385
+ runId,
386
+ timestamp: nowIso(),
387
+ reliability: "native",
388
+ cwd: config.cwd,
389
+ collectionPath: config.collectionPath,
390
+ pid: child.pid
391
+ });
392
+ if (config.timeoutMs && config.timeoutMs > 0) {
393
+ timeoutHandle = setTimeout(() => {
394
+ timedOut = true;
395
+ child.kill("SIGTERM");
396
+ }, config.timeoutMs);
397
+ }
398
+ child.stdout.setEncoding("utf-8");
399
+ child.stderr.setEncoding("utf-8");
400
+ child.stdout.on("data", (chunk) => {
401
+ this.emit("stdout", {
402
+ event: "stdout",
403
+ runId,
404
+ timestamp: nowIso(),
405
+ reliability: "native",
406
+ chunk
407
+ });
408
+ });
409
+ child.stderr.on("data", (chunk) => {
410
+ this.emit("stderr", {
411
+ event: "stderr",
412
+ runId,
413
+ timestamp: nowIso(),
414
+ reliability: "native",
415
+ chunk
416
+ });
417
+ });
418
+ child.on("error", (err) => {
419
+ clearTimeout(timeoutHandle);
420
+ const detail = { message: err.message, stack: err.stack };
421
+ const finishedAt = nowIso();
422
+ const durationMs = elapsedMs(startedAt);
423
+ const summary = this.buildEmptySummary({
424
+ runId,
425
+ collectionPath: config.collectionPath,
426
+ startedAt,
427
+ finishedAt,
428
+ durationMs,
429
+ exitCode: -1,
430
+ status: "failed",
431
+ error: detail
432
+ });
433
+ this.emit("run:failed", {
434
+ event: "run:failed",
435
+ runId,
436
+ timestamp: finishedAt,
437
+ reliability: "native",
438
+ exitCode: -1,
439
+ durationMs,
440
+ error: detail,
441
+ summary
442
+ });
443
+ rejectRun(err);
444
+ });
445
+ child.on("close", (code) => {
446
+ clearTimeout(timeoutHandle);
447
+ void (async () => {
448
+ const exitCode = code ?? -1;
449
+ const finishedAt = nowIso();
450
+ const durationMs = elapsedMs(startedAt);
451
+ const runStatus = timedOut || exitCode !== 0 ? "failed" : "finished";
452
+ const discovered = await discoveryPromise;
453
+ for (const req of discovered) {
454
+ this.emit("request:discovered", {
455
+ event: "request:discovered",
456
+ runId,
457
+ timestamp: finishedAt,
458
+ reliability: "inferred",
459
+ requestName: req.requestName,
460
+ requestFile: req.requestFile
461
+ });
462
+ }
463
+ let summary;
464
+ let reportParsedSuccessfully = false;
465
+ if (config.reporterJsonPath) {
466
+ try {
467
+ summary = await this.parser.parse(config.reporterJsonPath);
468
+ reportParsedSuccessfully = true;
469
+ } catch {
470
+ summary = this.buildEmptySummary({
471
+ runId,
472
+ collectionPath: config.collectionPath,
473
+ startedAt,
474
+ finishedAt,
475
+ durationMs,
476
+ exitCode,
477
+ status: runStatus
478
+ });
479
+ }
480
+ } else {
481
+ summary = this.buildEmptySummary({
482
+ runId,
483
+ collectionPath: config.collectionPath,
484
+ startedAt,
485
+ finishedAt,
486
+ durationMs,
487
+ exitCode,
488
+ status: runStatus
489
+ });
490
+ }
491
+ const enriched = {
492
+ ...summary,
493
+ runId,
494
+ collectionPath: config.collectionPath,
495
+ startedAt,
496
+ finishedAt,
497
+ durationMs,
498
+ exitCode,
499
+ status: runStatus
500
+ };
501
+ this.emitReportEvents(enriched, runId, finishedAt);
502
+ if (config.reporterJsonPath && reportParsedSuccessfully) {
503
+ this.emit("report:json:ready", {
504
+ event: "report:json:ready",
505
+ runId,
506
+ timestamp: finishedAt,
507
+ reliability: "derived",
508
+ path: config.reporterJsonPath,
509
+ summary: enriched
510
+ });
511
+ }
512
+ if (runStatus === "finished") {
513
+ this.emit("run:finished", {
514
+ event: "run:finished",
515
+ runId,
516
+ timestamp: finishedAt,
517
+ reliability: "native",
518
+ exitCode,
519
+ durationMs,
520
+ summary: enriched
521
+ });
522
+ } else {
523
+ const error = timedOut ? { message: `Run timed out after ${config.timeoutMs ?? 0}ms` } : { message: `Run exited with code ${exitCode}` };
524
+ this.emit("run:failed", {
525
+ event: "run:failed",
526
+ runId,
527
+ timestamp: finishedAt,
528
+ reliability: "native",
529
+ exitCode,
530
+ durationMs,
531
+ error,
532
+ summary: enriched
533
+ });
534
+ }
535
+ resolveRun(enriched);
536
+ })().catch((err) => {
537
+ rejectRun(err instanceof Error ? err : new Error(String(err)));
538
+ });
539
+ });
540
+ });
541
+ }
542
+ emitReportEvents(summary, runId, timestamp) {
543
+ for (const req of summary.requests) {
544
+ const reqStarted = {
545
+ event: "request:started",
546
+ runId,
547
+ timestamp,
548
+ reliability: "derived",
549
+ requestName: req.requestName,
550
+ requestFile: req.requestFile
551
+ };
552
+ this.emit("request:started", reqStarted);
553
+ if (req.status === "skipped") {
554
+ const skipped = {
555
+ event: "request:skipped",
556
+ runId,
557
+ timestamp,
558
+ reliability: "derived",
559
+ requestName: req.requestName,
560
+ requestFile: req.requestFile
561
+ };
562
+ this.emit("request:skipped", skipped);
563
+ } else {
564
+ const finished = {
565
+ event: "request:finished",
566
+ runId,
567
+ timestamp,
568
+ reliability: "derived",
569
+ requestName: req.requestName,
570
+ requestFile: req.requestFile,
571
+ status: req.status,
572
+ ...req.responseStatus !== void 0 ? { responseStatus: req.responseStatus } : {},
573
+ ...req.durationMs !== void 0 ? { durationMs: req.durationMs } : {},
574
+ ...req.error !== void 0 ? { error: req.error } : {}
575
+ };
576
+ this.emit("request:finished", finished);
577
+ }
578
+ for (const test of req.tests) {
579
+ const testStarted = {
580
+ event: "test:started",
581
+ runId,
582
+ timestamp,
583
+ reliability: "derived",
584
+ requestName: req.requestName,
585
+ testName: test.testName
586
+ };
587
+ this.emit("test:started", testStarted);
588
+ const testFinished = {
589
+ event: "test:finished",
590
+ runId,
591
+ timestamp,
592
+ reliability: "derived",
593
+ requestName: req.requestName,
594
+ testName: test.testName,
595
+ status: test.status,
596
+ ...test.error !== void 0 ? { error: test.error } : {}
597
+ };
598
+ this.emit("test:finished", testFinished);
599
+ }
600
+ for (const a of req.assertions) {
601
+ const assertionResult = {
602
+ event: "assertion:result",
603
+ runId,
604
+ timestamp,
605
+ reliability: "derived",
606
+ requestName: req.requestName,
607
+ assertion: a.assertion,
608
+ passed: a.passed,
609
+ ...a.actual !== void 0 ? { actual: a.actual } : {},
610
+ ...a.expected !== void 0 ? { expected: a.expected } : {},
611
+ ...a.error !== void 0 ? { error: a.error } : {}
612
+ };
613
+ this.emit("assertion:result", assertionResult);
614
+ }
615
+ }
616
+ }
617
+ buildArgs(config) {
618
+ const args = ["run", config.collectionPath];
619
+ if (config.recursive) {
620
+ args.push("-r");
621
+ }
622
+ if (config.env) {
623
+ args.push("--env", config.env);
624
+ }
625
+ if (config.reporterJsonPath) {
626
+ args.push("--reporter-json", config.reporterJsonPath);
627
+ }
628
+ if (config.extraArgs) {
629
+ args.push(...config.extraArgs);
630
+ }
631
+ return args;
632
+ }
633
+ buildEmptySummary(opts) {
634
+ const requests = opts.requests ?? [];
635
+ return {
636
+ runId: opts.runId,
637
+ collectionPath: opts.collectionPath,
638
+ startedAt: opts.startedAt,
639
+ finishedAt: opts.finishedAt,
640
+ durationMs: opts.durationMs,
641
+ exitCode: opts.exitCode,
642
+ status: opts.status,
643
+ totalRequests: requests.length,
644
+ passedRequests: requests.filter((r) => r.status === "finished").length,
645
+ failedRequests: requests.filter((r) => r.status === "failed").length,
646
+ skippedRequests: requests.filter((r) => r.status === "skipped").length,
647
+ totalTests: 0,
648
+ passedTests: 0,
649
+ failedTests: 0,
650
+ totalAssertions: 0,
651
+ passedAssertions: 0,
652
+ failedAssertions: 0,
653
+ requests,
654
+ ...opts.error !== void 0 ? { error: opts.error } : {}
655
+ };
656
+ }
657
+ emit(event, payload) {
658
+ this.bus.emit(event, payload);
659
+ }
660
+ };
661
+ // Annotate the CommonJS export names for ESM import in node:
662
+ 0 && (module.exports = {
663
+ BruFileScanner,
664
+ BrunoJsonReportParser,
665
+ BrunoLifecycleAdapter,
666
+ TypedEventBus
667
+ });
668
+ //# sourceMappingURL=index.js.map