@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
@@ -21,6 +21,60 @@ function rejects(label, fn, pattern) {
21
21
 
22
22
  function _sleep(ms) { return helpers.passiveObserve(ms, "ws-client: handshake/echo/close real-time observation"); }
23
23
 
24
+ // Every wsClient dialed in the test holds a client socket. A client that
25
+ // errors, times out, or schedules a reconnect never reaches a graceful
26
+ // close(), so its socket finalizes its async destroy past the forked worker's
27
+ // post-run grace window. Track every live client here so the drain can retire
28
+ // each one (cancel reconnect + destroy the socket) and then poll until the TCP
29
+ // handles release inside run().
30
+ var _liveClients = [];
31
+ function _trackedConnect(url, opts) {
32
+ var c = b.wsClient.connect(url, opts);
33
+ _liveClients.push(c);
34
+ return c;
35
+ }
36
+
37
+ // The in-process fixture servers keep their accepted upgrade sockets open (the
38
+ // flood / stub / hold-open scenarios never send FIN), so server.close() alone
39
+ // stops listening but leaves those sockets — and their TCPSocketWrap handles —
40
+ // alive. Track every server so the drain can force its live connections shut.
41
+ var _liveServers = [];
42
+ function _trackServer(server) {
43
+ _liveServers.push(server);
44
+ return server;
45
+ }
46
+
47
+ async function _drainTcpHandles() {
48
+ _liveClients.forEach(function (c) {
49
+ try { c.cancelReconnect(); } catch (_e) { /* best-effort */ }
50
+ try { c.close(); } catch (_e) { /* best-effort */ }
51
+ // Force the socket down NOW — close()'s graceful path defers the socket
52
+ // teardown behind a 1s timer, which would itself outlive run().
53
+ try { c._teardown(b.wsClient.CLOSE_NORMAL, "", false); } catch (_e) { /* best-effort */ }
54
+ });
55
+ _liveServers.forEach(function (s) {
56
+ // Destroy any accepted upgrade / hold-open sockets the server is keeping
57
+ // alive (these are detached from the HTTP server's connection tracking, so
58
+ // closeAllConnections can't see them), then stop listening.
59
+ if (Array.isArray(s._wsSockets)) {
60
+ s._wsSockets.forEach(function (sock) {
61
+ try { if (sock && !sock.destroyed) sock.destroy(); } catch (_e) { /* best-effort */ }
62
+ });
63
+ s._wsSockets = [];
64
+ }
65
+ try { if (typeof s.closeAllConnections === "function") s.closeAllConnections(); } catch (_e) { /* best-effort */ }
66
+ try { s.close(); } catch (_e) { /* best-effort */ }
67
+ });
68
+ _liveClients = [];
69
+ _liveServers = [];
70
+ if (typeof process.getActiveResourcesInfo !== "function") return;
71
+ await helpers.waitUntil(function () {
72
+ return process.getActiveResourcesInfo().filter(function (t) {
73
+ return t === "TCPSocketWrap" || t === "TCPServerWrap";
74
+ }).length === 0;
75
+ }, { timeoutMs: 5000, label: "ws-client: TCP handle drain after client teardown" });
76
+ }
77
+
24
78
  // Minimal in-process WebSocket server using lib/websocket primitives.
25
79
  function _makeServer(opts) {
26
80
  opts = opts || {};
@@ -28,7 +82,12 @@ function _makeServer(opts) {
28
82
  res.writeHead(404);
29
83
  res.end();
30
84
  });
85
+ // Upgrade hands socket ownership to this handler, so the HTTP server no
86
+ // longer tracks it — closeAllConnections() can't reach it. Record each one
87
+ // so the drain can destroy them directly.
88
+ server._wsSockets = [];
31
89
  server.on("upgrade", function (req, socket /*, head */) {
90
+ server._wsSockets.push(socket);
32
91
  var key = req.headers["sec-websocket-key"];
33
92
  if (!key) {
34
93
  socket.write("HTTP/1.1 400 Bad Request\r\n\r\n");
@@ -92,12 +151,20 @@ function _makeServer(opts) {
92
151
  });
93
152
  return new Promise(function (resolve) {
94
153
  server.listen(0, "127.0.0.1", function () {
95
- resolve(server);
154
+ resolve(_trackServer(server));
96
155
  });
97
156
  });
98
157
  }
99
158
 
100
159
  async function run() {
160
+ try {
161
+ await _runTests();
162
+ } finally {
163
+ await _drainTcpHandles();
164
+ }
165
+ }
166
+
167
+ async function _runTests() {
101
168
  // ---- shape ----
102
169
  check("b.wsClient is object", typeof b.wsClient === "object");
103
170
  check("b.wsClient.connect is fn", typeof b.wsClient.connect === "function");
@@ -141,7 +208,7 @@ async function run() {
141
208
  // ---- happy path: connect + send + echo ----
142
209
  var server = await _makeServer({});
143
210
  var port = server.address().port;
144
- var client = b.wsClient.connect("ws://127.0.0.1:" + port + "/", {
211
+ var client = _trackedConnect("ws://127.0.0.1:" + port + "/", {
145
212
  reconnect: false,
146
213
  audit: false,
147
214
  allowInternal: true,
@@ -189,7 +256,7 @@ async function run() {
189
256
  // ---- send before open ----
190
257
  var server2 = await _makeServer({});
191
258
  var port2 = server2.address().port;
192
- var c2 = b.wsClient.connect("ws://127.0.0.1:" + port2, { reconnect: false, audit: false, allowInternal: true });
259
+ var c2 = _trackedConnect("ws://127.0.0.1:" + port2, { reconnect: false, audit: false, allowInternal: true });
193
260
  rejects("send: not open yet",
194
261
  function () { c2.send("data"); }, /not open/);
195
262
  c2.close();
@@ -199,7 +266,7 @@ async function run() {
199
266
  // ---- bad accept hash ----
200
267
  var server3 = await _makeServer({ tamperKey: true });
201
268
  var port3 = server3.address().port;
202
- var c3 = b.wsClient.connect("ws://127.0.0.1:" + port3, {
269
+ var c3 = _trackedConnect("ws://127.0.0.1:" + port3, {
203
270
  reconnect: false, audit: false, allowInternal: true,
204
271
  });
205
272
  var c3Err = null;
@@ -211,7 +278,7 @@ async function run() {
211
278
  // ---- non-101 status ----
212
279
  var server4 = await _makeServer({ rejectStatus: 403 });
213
280
  var port4 = server4.address().port;
214
- var c4 = b.wsClient.connect("ws://127.0.0.1:" + port4, {
281
+ var c4 = _trackedConnect("ws://127.0.0.1:" + port4, {
215
282
  reconnect: false, audit: false, allowInternal: true,
216
283
  });
217
284
  var c4Err = null;
@@ -229,7 +296,7 @@ async function run() {
229
296
  // bad-status code is split by the carried status, not re-derived by the caller.
230
297
  var server4b = await _makeServer({ rejectStatus: 503 });
231
298
  var port4b = server4b.address().port;
232
- var c4b = b.wsClient.connect("ws://127.0.0.1:" + port4b, {
299
+ var c4b = _trackedConnect("ws://127.0.0.1:" + port4b, {
233
300
  reconnect: false, audit: false, allowInternal: true,
234
301
  });
235
302
  var c4bErr = null;
@@ -243,7 +310,7 @@ async function run() {
243
310
  // ---- subprotocol negotiation ----
244
311
  var server5 = await _makeServer({ subprotocol: "json-stream-v1" });
245
312
  var port5 = server5.address().port;
246
- var c5 = b.wsClient.connect("ws://127.0.0.1:" + port5, {
313
+ var c5 = _trackedConnect("ws://127.0.0.1:" + port5, {
247
314
  subprotocols: ["json-stream-v1", "msgpack-stream"],
248
315
  reconnect: false, audit: false, allowInternal: true,
249
316
  });
@@ -259,7 +326,7 @@ async function run() {
259
326
  // ---- subprotocol-not-in-offer rejected ----
260
327
  var server6 = await _makeServer({ subprotocol: "ghost-protocol" });
261
328
  var port6 = server6.address().port;
262
- var c6 = b.wsClient.connect("ws://127.0.0.1:" + port6, {
329
+ var c6 = _trackedConnect("ws://127.0.0.1:" + port6, {
263
330
  subprotocols: ["json-stream-v1"],
264
331
  reconnect: false, audit: false, allowInternal: true,
265
332
  });
@@ -274,7 +341,7 @@ async function run() {
274
341
  // is attempted (where the CRLF check fires).
275
342
  var server7a = await _makeServer({});
276
343
  var port7a = server7a.address().port;
277
- var c7a = b.wsClient.connect("ws://127.0.0.1:" + port7a, {
344
+ var c7a = _trackedConnect("ws://127.0.0.1:" + port7a, {
278
345
  headers: { "X-Evil": "value\r\nX-Other: injected" },
279
346
  reconnect: false, audit: false, allowInternal: true,
280
347
  });
@@ -287,7 +354,7 @@ async function run() {
287
354
  // ---- maxMessageBytes guard on send ----
288
355
  var server7 = await _makeServer({});
289
356
  var port7 = server7.address().port;
290
- var c7 = b.wsClient.connect("ws://127.0.0.1:" + port7, {
357
+ var c7 = _trackedConnect("ws://127.0.0.1:" + port7, {
291
358
  maxMessageBytes: 100,
292
359
  reconnect: false, audit: false, allowInternal: true,
293
360
  });
@@ -304,7 +371,7 @@ async function run() {
304
371
  // enforced on the running fragment total, not only at FIN (CWE-770).
305
372
  var serverFlood = await _makeServer({ floodFragments: { partBytes: 600, count: 4 } });
306
373
  var portFlood = serverFlood.address().port;
307
- var cFlood = b.wsClient.connect("ws://127.0.0.1:" + portFlood, {
374
+ var cFlood = _trackedConnect("ws://127.0.0.1:" + portFlood, {
308
375
  maxMessageBytes: 1024, // 600 + 600 = 1200 > 1024 before any FIN
309
376
  reconnect: false, audit: false, allowInternal: true,
310
377
  });
@@ -320,7 +387,7 @@ async function run() {
320
387
  // ---- url + readyState getters ----
321
388
  var server8 = await _makeServer({});
322
389
  var port8 = server8.address().port;
323
- var c8 = b.wsClient.connect("ws://127.0.0.1:" + port8 + "/foo", {
390
+ var c8 = _trackedConnect("ws://127.0.0.1:" + port8 + "/foo", {
324
391
  reconnect: false, audit: false, allowInternal: true,
325
392
  });
326
393
  // Poll for handshake completion rather than a fixed-budget sleep — the
@@ -335,10 +402,14 @@ async function run() {
335
402
 
336
403
  // ---- handshake timeout ----
337
404
  // Connect to a TCP server that accepts then never responds.
338
- var stubServer = net.createServer(function (sock) { /* accept and hold */ });
405
+ var stubServer = _trackServer(net.createServer(function (sock) {
406
+ // Accept and hold — record it so the drain destroys the held socket.
407
+ stubServer._wsSockets.push(sock);
408
+ }));
409
+ stubServer._wsSockets = [];
339
410
  await new Promise(function (r) { stubServer.listen(0, "127.0.0.1", r); });
340
411
  var stubPort = stubServer.address().port;
341
- var c9 = b.wsClient.connect("ws://127.0.0.1:" + stubPort, {
412
+ var c9 = _trackedConnect("ws://127.0.0.1:" + stubPort, {
342
413
  handshakeTimeoutMs: 200,
343
414
  reconnect: false, audit: false, allowInternal: true,
344
415
  });
@@ -350,7 +421,7 @@ async function run() {
350
421
 
351
422
  // ---- reconnect: connection refused → schedules reconnect ----
352
423
  // Use a port we know nobody listens on.
353
- var c10 = b.wsClient.connect("ws://127.0.0.1:1", {
424
+ var c10 = _trackedConnect("ws://127.0.0.1:1", {
354
425
  reconnect: { maxAttempts: 1, baseMs: 50, maxMs: 100 },
355
426
  handshakeTimeoutMs: 200,
356
427
  audit: false,
@@ -367,7 +438,7 @@ async function run() {
367
438
  // ---- permanent error: 4xx skips reconnect ----
368
439
  var server4xx = await _makeServer({ rejectStatus: 403 });
369
440
  var port4xx = server4xx.address().port;
370
- var c11 = b.wsClient.connect("ws://127.0.0.1:" + port4xx, {
441
+ var c11 = _trackedConnect("ws://127.0.0.1:" + port4xx, {
371
442
  reconnect: { maxAttempts: 5, baseMs: 50, maxMs: 100 },
372
443
  audit: false,
373
444
  allowInternal: true,
@@ -385,7 +456,7 @@ async function run() {
385
456
  // alwaysPermanent → _isPermanentError always true → willReconnect always false).
386
457
  var server5xx = await _makeServer({ rejectStatus: 503 });
387
458
  var port5xx = server5xx.address().port;
388
- var c12 = b.wsClient.connect("ws://127.0.0.1:" + port5xx, {
459
+ var c12 = _trackedConnect("ws://127.0.0.1:" + port5xx, {
389
460
  reconnect: { maxAttempts: 1, baseMs: 50, maxMs: 100 },
390
461
  audit: false,
391
462
  allowInternal: true,
@@ -401,7 +472,7 @@ async function run() {
401
472
  // ---- close() reason length cap (>123 bytes truncated) ----
402
473
  var serverCl = await _makeServer({});
403
474
  var portCl = serverCl.address().port;
404
- var cCl = b.wsClient.connect("ws://127.0.0.1:" + portCl, { reconnect: false, audit: false, allowInternal: true });
475
+ var cCl = _trackedConnect("ws://127.0.0.1:" + portCl, { reconnect: false, audit: false, allowInternal: true });
405
476
  await _sleep(200);
406
477
  // Should not throw — close() truncates internally.
407
478
  cCl.close(1000, "x".repeat(500));
@@ -420,7 +491,7 @@ async function run() {
420
491
  // Custom GUID accepted at config time. Wire round-trip is exercised in the
421
492
  // ws-client integration test; here we only confirm config-time validation
422
493
  // does not refuse a valid string.
423
- var cGuid = b.wsClient.connect("ws://127.0.0.1:1", {
494
+ var cGuid = _trackedConnect("ws://127.0.0.1:1", {
424
495
  handshakeGuid: "MY-CUSTOM-GUID-12345678",
425
496
  reconnect: false, audit: false, allowInternal: true,
426
497
  handshakeTimeoutMs: 100,
@@ -439,7 +510,7 @@ async function run() {
439
510
  function _onUnhandled(e) { sawUnhandled = e; }
440
511
  process.on("unhandledRejection", _onUnhandled);
441
512
  var ssrfErr = null;
442
- var cSwap = b.wsClient.connect("ws://127.0.0.1:1", {
513
+ var cSwap = _trackedConnect("ws://127.0.0.1:1", {
443
514
  urlFor: function () { return "ws://169.254.169.254:1/"; }, // cloud-metadata — hard-deny
444
515
  reconnect: false, audit: false, allowInternal: true, // allowInternal must NOT bypass metadata
445
516
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/blamejs-shop",
3
- "version": "0.4.101",
3
+ "version": "0.4.102",
4
4
  "description": "Open-source framework built on blamejs. Vendored stack, zero npm runtime deps, PQC-first crypto, security-on by default.",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {