@blamejs/blamejs-shop 0.4.101 → 0.4.102

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 (55) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/vendor/MANIFEST.json +55 -51
  4. package/lib/vendor/blamejs/.gitignore +5 -0
  5. package/lib/vendor/blamejs/CHANGELOG.md +4 -0
  6. package/lib/vendor/blamejs/api-snapshot.json +2 -2
  7. package/lib/vendor/blamejs/lib/sandbox.js +23 -5
  8. package/lib/vendor/blamejs/package.json +1 -1
  9. package/lib/vendor/blamejs/release-notes/v0.15.25.json +18 -0
  10. package/lib/vendor/blamejs/release-notes/v0.15.26.json +18 -0
  11. package/lib/vendor/blamejs/test/layer-0-primitives/ai-adverse-decision.test.js +5 -2
  12. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-open-nofollow.test.js +7 -2
  13. package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-bucket-ops.test.js +30 -10
  14. package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-key-encoding.test.js +21 -0
  15. package/lib/vendor/blamejs/test/layer-0-primitives/bearer-auth.test.js +22 -17
  16. package/lib/vendor/blamejs/test/layer-0-primitives/body-parser-chunked-malformed.test.js +23 -18
  17. package/lib/vendor/blamejs/test/layer-0-primitives/breach-deadline.test.js +8 -3
  18. package/lib/vendor/blamejs/test/layer-0-primitives/ciba-authreqid-binding.test.js +22 -0
  19. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +50 -0
  20. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +13 -5
  21. package/lib/vendor/blamejs/test/layer-0-primitives/cra-report.test.js +5 -2
  22. package/lib/vendor/blamejs/test/layer-0-primitives/daily-byte-quota.test.js +20 -9
  23. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +8 -2
  24. package/lib/vendor/blamejs/test/layer-0-primitives/fido-mds3.test.js +34 -15
  25. package/lib/vendor/blamejs/test/layer-0-primitives/gcs-bucket-ops.test.js +30 -9
  26. package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +15 -3
  27. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache.test.js +41 -18
  28. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +33 -14
  29. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-throttle-transform.test.js +21 -2
  30. package/lib/vendor/blamejs/test/layer-0-primitives/incident-report.test.js +5 -2
  31. package/lib/vendor/blamejs/test/layer-0-primitives/log-stream-otlp.test.js +29 -8
  32. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-imap.test.js +42 -23
  33. package/lib/vendor/blamejs/test/layer-0-primitives/network-byte-quota.test.js +5 -2
  34. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns.test.js +20 -0
  35. package/lib/vendor/blamejs/test/layer-0-primitives/network-nts-handshake-byte-cap.test.js +20 -1
  36. package/lib/vendor/blamejs/test/layer-0-primitives/nis2-report.test.js +5 -2
  37. package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +22 -1
  38. package/lib/vendor/blamejs/test/layer-0-primitives/observability-tracing.test.js +8 -2
  39. package/lib/vendor/blamejs/test/layer-0-primitives/parser-verify-hardening.test.js +21 -16
  40. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +5 -2
  41. package/lib/vendor/blamejs/test/layer-0-primitives/queue-sqs.test.js +31 -11
  42. package/lib/vendor/blamejs/test/layer-0-primitives/request-id-async-context.test.js +21 -4
  43. package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +35 -0
  44. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +5 -2
  45. package/lib/vendor/blamejs/test/layer-0-primitives/self-update-poll-asset-digest.test.js +21 -2
  46. package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +29 -10
  47. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +51 -33
  48. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-multipart-sse.test.js +31 -13
  49. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +41 -21
  50. package/lib/vendor/blamejs/test/layer-0-primitives/testing-request.test.js +25 -0
  51. package/lib/vendor/blamejs/test/layer-0-primitives/tls-exporter.test.js +30 -6
  52. package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +22 -0
  53. package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool-recycle-race.test.js +10 -6
  54. package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +91 -20
  55. package/package.json +1 -1
@@ -676,24 +676,47 @@ async function test304MergesHeaders() {
676
676
  // ---- Run ----------------------------------------------------------------
677
677
 
678
678
  async function run() {
679
- testSurface();
680
- testCreateBadOpts();
681
- await testMissThenHit();
682
- await testNoStoreSkips();
683
- await testNoCacheRevalidatesEveryRead();
684
- await testPrivateRefusedInSharedCache();
685
- await testVarySplitsEntries();
686
- await testRevalidate304();
687
- await testStaleWhileRevalidate();
688
- await testStaleIfError();
689
- await testEvictionAtMaxBytes();
690
- await testEvictionAtMaxEntries();
691
- await testHeuristicFreshnessFromLastModified();
692
- await testPragmaNoCache();
693
- await testPostBypassesCache();
694
- await testInvalidateInspectClear();
695
- await testAuditAndObservabilityWired();
696
- await test304MergesHeaders();
679
+ try {
680
+ testSurface();
681
+ testCreateBadOpts();
682
+ await testMissThenHit();
683
+ await testNoStoreSkips();
684
+ await testNoCacheRevalidatesEveryRead();
685
+ await testPrivateRefusedInSharedCache();
686
+ await testVarySplitsEntries();
687
+ await testRevalidate304();
688
+ await testStaleWhileRevalidate();
689
+ await testStaleIfError();
690
+ await testEvictionAtMaxBytes();
691
+ await testEvictionAtMaxEntries();
692
+ await testHeuristicFreshnessFromLastModified();
693
+ await testPragmaNoCache();
694
+ await testPostBypassesCache();
695
+ await testInvalidateInspectClear();
696
+ await testAuditAndObservabilityWired();
697
+ await test304MergesHeaders();
698
+ } finally {
699
+ // Tear down the httpClient's keep-alive transport pool so the
700
+ // client-side sockets it cached don't outlive run() and keep the
701
+ // forked worker's event loop open (delays exit on a slow runner).
702
+ // agent.destroy() schedules the socket teardown asynchronously, so
703
+ // poll until the TCP handles have actually drained before returning.
704
+ await _drainTcpHandles();
705
+ }
706
+ }
707
+
708
+ // Destroy the httpClient transport pool and wait for every TCP handle
709
+ // (client sockets + any server-side sockets they kept open) to close.
710
+ // Polling drives real event-loop turns so the close completes inside
711
+ // run(), not in the worker's post-run grace window.
712
+ async function _drainTcpHandles() {
713
+ b.httpClient._resetForTest();
714
+ if (typeof process.getActiveResourcesInfo !== "function") return;
715
+ await helpers.waitUntil(function () {
716
+ return process.getActiveResourcesInfo().filter(function (t) {
717
+ return t === "TCPSocketWrap" || t === "TCPServerWrap";
718
+ }).length === 0;
719
+ }, { timeoutMs: 5000, label: "http-client-cache: TCP handle drain after _resetForTest" });
697
720
  }
698
721
 
699
722
  module.exports = { run: run };
@@ -465,21 +465,40 @@ async function testThrottleTransformValidation() {
465
465
  { url: "https://x.example/", uploadTransform: { not: "a stream" } });
466
466
  }
467
467
 
468
+ // Destroy the httpClient transport pool and wait for every TCP handle
469
+ // (client sockets the keep-alive agent cached, plus any server-side
470
+ // sockets they kept open) to close. Polling drives real event-loop
471
+ // turns so the asynchronous socket teardown completes inside run(),
472
+ // not in the forked worker's post-run grace window.
473
+ async function _drainTcpHandles() {
474
+ b.httpClient._resetForTest();
475
+ if (typeof process.getActiveResourcesInfo !== "function") return;
476
+ await helpers.waitUntil(function () {
477
+ return process.getActiveResourcesInfo().filter(function (t) {
478
+ return t === "TCPSocketWrap" || t === "TCPServerWrap";
479
+ }).length === 0;
480
+ }, { timeoutMs: 5000, label: "http-client-stream: TCP handle drain after _resetForTest" });
481
+ }
482
+
468
483
  async function run() {
469
- testSurface();
470
- await testBandwidthThrottle();
471
- await testDownloadTransformInterpose();
472
- await testThrottleTransformValidation();
473
- await testDownloadHappyPath();
474
- await testDownloadExpectedHashMatch();
475
- await testDownloadHashMismatch();
476
- await testDownloadHttpError();
477
- await testStreamErrorBodyPreserved();
478
- await testDownloadTempCreateIsExclusiveNoFollow();
479
- await testDownloadBadOpts();
480
- await testUploadHappyPath();
481
- await testUploadMissingFile();
482
- await testUploadBadOpts();
484
+ try {
485
+ testSurface();
486
+ await testBandwidthThrottle();
487
+ await testDownloadTransformInterpose();
488
+ await testThrottleTransformValidation();
489
+ await testDownloadHappyPath();
490
+ await testDownloadExpectedHashMatch();
491
+ await testDownloadHashMismatch();
492
+ await testDownloadHttpError();
493
+ await testStreamErrorBodyPreserved();
494
+ await testDownloadTempCreateIsExclusiveNoFollow();
495
+ await testDownloadBadOpts();
496
+ await testUploadHappyPath();
497
+ await testUploadMissingFile();
498
+ await testUploadBadOpts();
499
+ } finally {
500
+ await _drainTcpHandles();
501
+ }
483
502
  }
484
503
 
485
504
  module.exports = { run: run };
@@ -75,9 +75,28 @@ async function testUploadTransformSizeChangeNotTruncated() {
75
75
  });
76
76
  }
77
77
 
78
+ // Destroy the httpClient transport pool and wait for every TCP handle
79
+ // (the keep-alive agent's client sockets + any server-side sockets they
80
+ // kept open) to close. Polling drives real event-loop turns so the
81
+ // asynchronous teardown completes inside run(), not in the forked
82
+ // worker's post-run grace window.
83
+ async function _drainTcpHandles() {
84
+ b.httpClient._resetForTest();
85
+ if (typeof process.getActiveResourcesInfo !== "function") return;
86
+ await helpers.waitUntil(function () {
87
+ return process.getActiveResourcesInfo().filter(function (t) {
88
+ return t === "TCPSocketWrap" || t === "TCPServerWrap";
89
+ }).length === 0;
90
+ }, { timeoutMs: 5000, label: "http-client-throttle-transform: TCP handle drain after _resetForTest" });
91
+ }
92
+
78
93
  async function run() {
79
- await testDownloadTransformAppliesInBufferMode();
80
- await testUploadTransformSizeChangeNotTruncated();
94
+ try {
95
+ await testDownloadTransformAppliesInBufferMode();
96
+ await testUploadTransformSizeChangeNotTruncated();
97
+ } finally {
98
+ await _drainTcpHandles();
99
+ }
81
100
  }
82
101
 
83
102
  module.exports = { run: run };
@@ -3,7 +3,7 @@ var helpers = require("../helpers");
3
3
  var b = helpers.b;
4
4
  var check = helpers.check;
5
5
 
6
- (async function run() {
6
+ async function run() {
7
7
  var ir = b.incident.report.create({ audit: false });
8
8
  var rec = await ir.open({ regime: "gdpr", detectedAt: Date.now() });
9
9
  check("incident.open returns id", typeof rec.id === "string");
@@ -91,4 +91,7 @@ var check = helpers.check;
91
91
  clk2.stop();
92
92
 
93
93
  console.log("OK — incident.report tests");
94
- })().catch(function (e) { console.error(e); process.exit(1); });
94
+ }
95
+
96
+ module.exports = { run: run };
97
+ if (require.main === module) run().catch(function (e) { console.error(e); process.exit(1); });
@@ -9,6 +9,20 @@ var otlp = require("../../lib/log-stream-otlp");
9
9
  function _mockCollector(opts) {
10
10
  opts = opts || {};
11
11
  var received = [];
12
+ // Timers a responder schedules to delay/hang a response. Tracked so close()
13
+ // clears any still-pending one — an uncleared responder timer (e.g. the
14
+ // 5000ms hang in the overflow test) outlives the server and lingers as a
15
+ // referenced Timeout handle past run().
16
+ var pendingTimers = [];
17
+ function deferResponse(fn, ms) {
18
+ var t = setTimeout(function () {
19
+ var idx = pendingTimers.indexOf(t);
20
+ if (idx !== -1) pendingTimers.splice(idx, 1);
21
+ fn();
22
+ }, ms);
23
+ pendingTimers.push(t);
24
+ return t;
25
+ }
12
26
  var responder = opts.responder || function (_req, res) {
13
27
  res.statusCode = 200;
14
28
  res.setHeader("content-type", "application/json");
@@ -30,7 +44,7 @@ function _mockCollector(opts) {
30
44
  } catch (e) {
31
45
  received.push({ url: req.url, error: e.message });
32
46
  }
33
- responder(req, res);
47
+ responder(req, res, deferResponse);
34
48
  });
35
49
  });
36
50
  return new Promise(function (resolve) {
@@ -39,7 +53,10 @@ function _mockCollector(opts) {
39
53
  resolve({
40
54
  url: "http://127.0.0.1:" + port,
41
55
  received: received,
42
- close: function () { return new Promise(function (r) { server.close(r); }); },
56
+ close: function () {
57
+ while (pendingTimers.length > 0) clearTimeout(pendingTimers.pop());
58
+ return new Promise(function (r) { server.close(r); });
59
+ },
43
60
  });
44
61
  });
45
62
  });
@@ -202,11 +219,11 @@ async function run() {
202
219
 
203
220
  // ---- Buffer overflow drops oldest + emits onDrop ----
204
221
  var col4 = await _mockCollector({
205
- responder: function (_req, res) {
222
+ responder: function (_req, res, deferResponse) {
206
223
  // Hang the response so the in-flight batch never completes;
207
- // subsequent emits queue up, eventually overflowing.
208
- // (Test calls close() to release.)
209
- setTimeout(function () { res.statusCode = 200; res.end("{}"); }, 5000);
224
+ // subsequent emits queue up, eventually overflowing. The collector
225
+ // tracks this timer and clears it on close() so it doesn't linger.
226
+ deferResponse(function () { res.statusCode = 200; res.end("{}"); }, 5000);
210
227
  },
211
228
  });
212
229
  try {
@@ -229,8 +246,12 @@ async function run() {
229
246
  }, { timeoutMs: 5000, label: "log-stream-otlp: overflow drops fired" });
230
247
  var overflowDrops = dropEvents4.filter(function (d) { return d.reason === "overflow"; });
231
248
  check("overflow drops fired (oldest evicted)", overflowDrops.length > 0);
232
- // Don't await close — the hanging response keeps it alive
233
- sink4.close().catch(function () {});
249
+ // Close the collector first that clears the deferred-response timer and
250
+ // tears down the server, so the sink's in-flight POST stops hanging and its
251
+ // retry/backoff settles. Then await the sink's close so no retry-backoff
252
+ // timer lingers past run().
253
+ await col4.close();
254
+ await sink4.close().catch(function () {});
234
255
  } finally {
235
256
  await col4.close();
236
257
  }
@@ -696,30 +696,49 @@ async function testSelectQresyncImplicitlyEngagesCondstore() {
696
696
  } finally { await srv.close({ timeoutMs: 1000 }); } // allow:raw-time-literal — test-only short drain
697
697
  }
698
698
 
699
+ // Each test connects a raw client socket to a live IMAP TLS server and
700
+ // destroys both at the end; socket.destroy() and the server-side teardown
701
+ // finalize their handles asynchronously — past the forked worker's post-run
702
+ // grace window. Poll until every TCP handle has actually closed so the last
703
+ // test's client/server don't outlive run() and hold the event loop open on
704
+ // a slow runner.
705
+ async function _drainTcpHandles() {
706
+ if (typeof process.getActiveResourcesInfo !== "function") return;
707
+ await helpers.waitUntil(function () {
708
+ return process.getActiveResourcesInfo().filter(function (t) {
709
+ return t === "TCPSocketWrap" || t === "TCPServerWrap";
710
+ }).length === 0;
711
+ }, { timeoutMs: 5000, label: "mail-server-imap: TCP handle drain after run" });
712
+ }
713
+
699
714
  async function run() {
700
- testSurface();
701
- testRequiresTlsContext();
702
- testRequiresMailStore();
703
- testBadBoundsRefused();
704
- await testCapabilityAdvertisesCondstore();
705
- await testEnableCondstore();
706
- await testFetchChangedSinceParses();
707
- await testStoreUnchangedSinceConflict();
708
- await testFetchChangedSinceImpliesCondstore();
709
- await testStoreSilentEmitsModseqUnderCondstore();
710
- // v0.11.28 — NOTIFY / METADATA / CATENATE
711
- await testCapabilityAdvertisesNewExtensions();
712
- await testNotifyNoneAndSet();
713
- await testNotifyBackendMissing();
714
- await testGetSetMetadata();
715
- await testMetadataBackendMissing();
716
- await testCatenateBackendMissing();
717
- await testCatenatePartOrderingAndValidation();
718
- // v0.11.33 — QRESYNC (RFC 7162 §3.2)
719
- await testCapabilityAdvertisesQresync();
720
- await testEnableQresyncImpliesCondstore();
721
- await testSelectQresyncEmitsVanishedEarlier();
722
- await testSelectQresyncImplicitlyEngagesCondstore();
715
+ try {
716
+ testSurface();
717
+ testRequiresTlsContext();
718
+ testRequiresMailStore();
719
+ testBadBoundsRefused();
720
+ await testCapabilityAdvertisesCondstore();
721
+ await testEnableCondstore();
722
+ await testFetchChangedSinceParses();
723
+ await testStoreUnchangedSinceConflict();
724
+ await testFetchChangedSinceImpliesCondstore();
725
+ await testStoreSilentEmitsModseqUnderCondstore();
726
+ // v0.11.28 — NOTIFY / METADATA / CATENATE
727
+ await testCapabilityAdvertisesNewExtensions();
728
+ await testNotifyNoneAndSet();
729
+ await testNotifyBackendMissing();
730
+ await testGetSetMetadata();
731
+ await testMetadataBackendMissing();
732
+ await testCatenateBackendMissing();
733
+ await testCatenatePartOrderingAndValidation();
734
+ // v0.11.33 — QRESYNC (RFC 7162 §3.2)
735
+ await testCapabilityAdvertisesQresync();
736
+ await testEnableQresyncImpliesCondstore();
737
+ await testSelectQresyncEmitsVanishedEarlier();
738
+ await testSelectQresyncImplicitlyEngagesCondstore();
739
+ } finally {
740
+ await _drainTcpHandles();
741
+ }
723
742
  }
724
743
 
725
744
  module.exports = { run: run };
@@ -118,7 +118,7 @@ async function testRefusalEmitsAudit() {
118
118
  check("refusal emits network.byte_quota.exceeded", hit);
119
119
  }
120
120
 
121
- (async function run() {
121
+ async function run() {
122
122
  await testCheckBelowQuotaPasses();
123
123
  await testCheckOverQuotaRefuses();
124
124
  await testCheckIsPureNonMutating();
@@ -130,4 +130,7 @@ async function testRefusalEmitsAudit() {
130
130
  await testCheckRejectsBadKey();
131
131
  await testRefusalEmitsAudit();
132
132
  console.log("OK — network-byte-quota tests");
133
- })().catch(function (e) { console.error(e); process.exit(1); });
133
+ }
134
+
135
+ module.exports = { run: run };
136
+ if (require.main === module) run().catch(function (e) { console.error(e); process.exit(1); });
@@ -205,7 +205,27 @@ function _startTlsResponder(replyBytes, keyPem, certPem) {
205
205
  });
206
206
  }
207
207
 
208
+ // The DNS primitive's system-resolver TCP query (and DoT pool sockets)
209
+ // open client sockets; _resetForTest() destroys them, but socket.destroy()
210
+ // finalizes the underlying handle asynchronously — past the forked worker's
211
+ // post-run grace window. Reset, then poll until the TCP client handle has
212
+ // actually closed so it doesn't outlive run() and hold the event loop open.
213
+ async function _drainTcpHandles() {
214
+ _resetAll();
215
+ if (typeof process.getActiveResourcesInfo !== "function") return;
216
+ await helpers.waitUntil(function () {
217
+ return process.getActiveResourcesInfo().filter(function (t) {
218
+ return t === "TCPSocketWrap" || t === "TCPServerWrap";
219
+ }).length === 0;
220
+ }, { timeoutMs: 5000, label: "network-dns: TCP handle drain after _resetForTest" });
221
+ }
222
+
208
223
  async function run() {
224
+ try { await _runTests(); }
225
+ finally { await _drainTcpHandles(); }
226
+ }
227
+
228
+ async function _runTests() {
209
229
  _resetAll();
210
230
 
211
231
  // ============================================================
@@ -115,8 +115,27 @@ function testHandshakeByteCapFailsClosed() {
115
115
  });
116
116
  }
117
117
 
118
+ // The handshake test destroys its NTS-KE client socket on the byte-cap
119
+ // path and calls server.close(), but socket.destroy() / the server-side
120
+ // accepted-socket teardown finalize their handles asynchronously — past
121
+ // the forked worker's post-run grace window. Poll until every TCP handle
122
+ // has actually closed so neither outlives run() and holds the event loop
123
+ // open on a slow runner.
124
+ async function _drainTcpHandles() {
125
+ if (typeof process.getActiveResourcesInfo !== "function") return;
126
+ await helpers.waitUntil(function () {
127
+ return process.getActiveResourcesInfo().filter(function (t) {
128
+ return t === "TCPSocketWrap" || t === "TCPServerWrap";
129
+ }).length === 0;
130
+ }, { timeoutMs: 5000, label: "network-nts-handshake-byte-cap: TCP handle drain after handshake" });
131
+ }
132
+
118
133
  async function run() {
119
- await testHandshakeByteCapFailsClosed();
134
+ try {
135
+ await testHandshakeByteCapFailsClosed();
136
+ } finally {
137
+ await _drainTcpHandles();
138
+ }
120
139
  }
121
140
 
122
141
  module.exports = { run: run };
@@ -3,7 +3,7 @@ var helpers = require("../helpers");
3
3
  var b = helpers.b;
4
4
  var check = helpers.check;
5
5
 
6
- (async function run() {
6
+ async function run() {
7
7
  var n = b.nis2.report.create({
8
8
  audit: false,
9
9
  entityId: "acme-1", entityType: "essential", sectorAnnex: "I.6",
@@ -18,4 +18,7 @@ var check = helpers.check;
18
18
  check("nis2 refuses bad entityType", threwBadType);
19
19
 
20
20
  console.log("OK — nis2.report tests");
21
- })().catch(function (e) { console.error(e); process.exit(1); });
21
+ }
22
+
23
+ module.exports = { run: run };
24
+ if (require.main === module) run().catch(function (e) { console.error(e); process.exit(1); });
@@ -105,7 +105,7 @@ async function _pkceDowngradeCase(methods, expectRefusal, label) {
105
105
  } finally { server.close(); }
106
106
  }
107
107
 
108
- async function run() {
108
+ async function _runTests() {
109
109
  var oauth = b.auth.oauth.create({
110
110
  issuer: "https://idp.example",
111
111
  clientId: "rp-1",
@@ -460,6 +460,27 @@ async function run() {
460
460
  await _testBackchannelLogoutOversized();
461
461
  }
462
462
 
463
+ // b.auth.oauth discovery / PAR fetches go through the shared b.httpClient
464
+ // keep-alive agent, whose cached client sockets (and the mock servers they
465
+ // keep open) would otherwise outlive run() and hold the forked worker's
466
+ // event loop open. Tear the pool down and poll until the TCP handles have
467
+ // actually closed — agent.destroy() schedules the teardown asynchronously,
468
+ // so polling drives the event-loop turns needed to complete it inside run().
469
+ async function _drainTcpHandles() {
470
+ b.httpClient._resetForTest();
471
+ if (typeof process.getActiveResourcesInfo !== "function") return;
472
+ await helpers.waitUntil(function () {
473
+ return process.getActiveResourcesInfo().filter(function (t) {
474
+ return t === "TCPSocketWrap" || t === "TCPServerWrap";
475
+ }).length === 0;
476
+ }, { timeoutMs: 5000, label: "oauth-callback: TCP handle drain after _resetForTest" });
477
+ }
478
+
479
+ async function run() {
480
+ try { await _runTests(); }
481
+ finally { await _drainTcpHandles(); }
482
+ }
483
+
463
484
  // PAR carrying a signed request object: the form body MUST hold `request=`
464
485
  // + client auth ONLY, and the authorization parameters travel as request-
465
486
  // object claims, NOT as bare form params. The pushed JWT is verified
@@ -647,7 +647,7 @@ function testTracerToJSONIsImmutable() {
647
647
 
648
648
  // ---- Run all ----
649
649
 
650
- (async function run() {
650
+ async function run() {
651
651
  testTracestateParse();
652
652
  testTracestateBuild();
653
653
  testBaggageParse();
@@ -677,4 +677,10 @@ function testTracerToJSONIsImmutable() {
677
677
  testTracerToJSONIsImmutable();
678
678
  testTraceLogCorrelationRejectsAuditOpt();
679
679
  testTracerRejectsAuditOpt();
680
- })().catch(function (e) { console.error(e); process.exit(1); });
680
+ }
681
+
682
+ module.exports = { run: run };
683
+
684
+ if (require.main === module) {
685
+ run().catch(function (e) { console.error(e); process.exit(1); });
686
+ }
@@ -116,23 +116,28 @@ function testBodyParserRawWildcardMatchesRealType() {
116
116
  req.headers = { "content-type": "application/json", "content-length": "2" };
117
117
  req.socket = { remoteAddress: "127.0.0.1" };
118
118
  var res = _bodyRes();
119
- return new Promise(function (resolve) {
120
- var settled = false;
121
- bp(req, res, function () {
122
- if (settled) return; settled = true;
123
- check("bodyParser.raw() */* accepts application/json → next() runs", true);
124
- check("bodyParser.raw() exposes the raw body as a Buffer", Buffer.isBuffer(req.body));
125
- resolve();
119
+ // The parser settles by calling next() or by ending the response. Wrap in
120
+ // withTestTimeout so a parser that hangs becomes a hard "test timed out"
121
+ // reject (1500ms budget) instead of stalling the suite — its guard timer
122
+ // clears on settle, so no Timeout handle lingers past run().
123
+ return helpers.withTestTimeout("parser-verify: bodyParser.raw() settles", function () {
124
+ return new Promise(function (resolve) {
125
+ var settled = false;
126
+ bp(req, res, function () {
127
+ if (settled) return; settled = true;
128
+ check("bodyParser.raw() */* accepts application/json → next() runs", true);
129
+ check("bodyParser.raw() exposes the raw body as a Buffer", Buffer.isBuffer(req.body));
130
+ resolve();
131
+ });
132
+ res.on("finish", function () {
133
+ if (settled) return; settled = true;
134
+ check("bodyParser.raw() */* did NOT 415 a real Content-Type (status=" + res._endedStatus + ")",
135
+ res._endedStatus !== 415);
136
+ resolve();
137
+ });
138
+ setImmediate(function () { req.emit("data", Buffer.from("{}")); req.emit("end"); });
126
139
  });
127
- res.on("finish", function () {
128
- if (settled) return; settled = true;
129
- check("bodyParser.raw() */* did NOT 415 a real Content-Type (status=" + res._endedStatus + ")",
130
- res._endedStatus !== 415);
131
- resolve();
132
- });
133
- setImmediate(function () { req.emit("data", Buffer.from("{}")); req.emit("end"); });
134
- setTimeout(function () { if (!settled) { settled = true; check("bodyParser.raw() settled", false); resolve(); } }, 1500);
135
- });
140
+ }, { timeoutMs: 1500 }); // allow:raw-byte-literal — parser-settle budget ms
136
141
  }
137
142
 
138
143
  async function testPromiseToStreamWrapsPromise() {
@@ -281,7 +281,7 @@ async function testMultipartRepeatedFieldShapeUnchanged() {
281
281
  check("multipart: single field stays scalar", result.fields.title === "solo");
282
282
  }
283
283
 
284
- (async function run() {
284
+ async function run() {
285
285
  await testJsonParsesValidObject();
286
286
  await testJsonRefusesOverMaxBytes();
287
287
  await testJsonRefusesPrototypePollution();
@@ -296,4 +296,7 @@ async function testMultipartRepeatedFieldShapeUnchanged() {
296
296
  await testMultipartRefusesPoisonedFieldName();
297
297
  await testMultipartRepeatedFieldShapeUnchanged();
298
298
  console.log("OK — parsers-standalone tests");
299
- })().catch(function (e) { console.error(e); process.exit(1); });
299
+ }
300
+
301
+ module.exports = { run: run };
302
+ if (require.main === module) run().catch(function (e) { console.error(e); process.exit(1); });
@@ -324,18 +324,38 @@ async function testNumericConfigValidation() {
324
324
  shouldPass("accepts waitTimeSec=0 (short-poll sentinel)", { waitTimeSec: 0 });
325
325
  }
326
326
 
327
+ // sqs.create issues its signed requests through the shared b.httpClient
328
+ // keep-alive agent, whose cached client sockets (and the mock servers they
329
+ // keep open) would otherwise outlive run() and hold the forked worker's
330
+ // event loop open. Tear the pool down and poll until the TCP handles have
331
+ // actually closed — agent.destroy() schedules the teardown asynchronously,
332
+ // so polling drives the event-loop turns needed to complete it inside run().
333
+ async function _drainTcpHandles() {
334
+ b.httpClient._resetForTest();
335
+ if (typeof process.getActiveResourcesInfo !== "function") return;
336
+ await helpers.waitUntil(function () {
337
+ return process.getActiveResourcesInfo().filter(function (t) {
338
+ return t === "TCPSocketWrap" || t === "TCPServerWrap";
339
+ }).length === 0;
340
+ }, { timeoutMs: 5000, label: "queue-sqs: TCP handle drain after _resetForTest" });
341
+ }
342
+
327
343
  async function run() {
328
- await testFactoryValidation();
329
- await testNumericConfigValidation();
330
- await testEnqueueWireShape();
331
- await testDelaySecondsClampedAt900();
332
- await testLeaseRoundTrip();
333
- await testCompleteDeletes();
334
- await testExtendLease();
335
- await testFailMakesVisible();
336
- await testSizeAndPurge();
337
- await testCustomQueueUrlResolver();
338
- await testSessionTokenHeader();
344
+ try {
345
+ await testFactoryValidation();
346
+ await testNumericConfigValidation();
347
+ await testEnqueueWireShape();
348
+ await testDelaySecondsClampedAt900();
349
+ await testLeaseRoundTrip();
350
+ await testCompleteDeletes();
351
+ await testExtendLease();
352
+ await testFailMakesVisible();
353
+ await testSizeAndPurge();
354
+ await testCustomQueueUrlResolver();
355
+ await testSessionTokenHeader();
356
+ } finally {
357
+ await _drainTcpHandles();
358
+ }
339
359
  }
340
360
 
341
361
  module.exports = { run: run };
@@ -103,11 +103,28 @@ async function testConcurrentRequestsIsolated() {
103
103
  check("concurrent: every response header matches its request", hdrsMatch);
104
104
  }
105
105
 
106
+ // Each fixture http.Server is .close()'d, but the listening handle finalizes on
107
+ // a later event-loop turn — past the forked worker's post-run grace window.
108
+ // Poll process.getActiveResourcesInfo until no TCP handle remains; polling
109
+ // drives the real event-loop turns that complete the close inside run().
110
+ async function _drainTcpHandles() {
111
+ if (typeof process.getActiveResourcesInfo !== "function") return;
112
+ await helpers.waitUntil(function () {
113
+ return process.getActiveResourcesInfo().filter(function (t) {
114
+ return t === "TCPSocketWrap" || t === "TCPServerWrap";
115
+ }).length === 0;
116
+ }, { timeoutMs: 5000, label: "request-id-async-context: TCP handle drain" });
117
+ }
118
+
106
119
  async function run() {
107
- testSurface();
108
- await testAsyncContextBindsAls();
109
- await testDefaultModeDoesNotBindAls();
110
- await testConcurrentRequestsIsolated();
120
+ try {
121
+ testSurface();
122
+ await testAsyncContextBindsAls();
123
+ await testDefaultModeDoesNotBindAls();
124
+ await testConcurrentRequestsIsolated();
125
+ } finally {
126
+ await _drainTcpHandles();
127
+ }
111
128
  }
112
129
 
113
130
  module.exports = { run: run };