@blamejs/core 0.8.43 → 0.8.50

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 (222) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/README.md +10 -10
  3. package/index.js +52 -0
  4. package/lib/a2a.js +159 -34
  5. package/lib/acme.js +762 -0
  6. package/lib/ai-pref.js +166 -43
  7. package/lib/api-key.js +108 -47
  8. package/lib/api-snapshot.js +157 -40
  9. package/lib/app-shutdown.js +113 -77
  10. package/lib/archive.js +337 -40
  11. package/lib/arg-parser.js +697 -0
  12. package/lib/asyncapi.js +99 -55
  13. package/lib/atomic-file.js +465 -104
  14. package/lib/audit-chain.js +123 -34
  15. package/lib/audit-daily-review.js +389 -0
  16. package/lib/audit-sign.js +302 -56
  17. package/lib/audit-tools.js +412 -63
  18. package/lib/audit.js +656 -35
  19. package/lib/auth/jwt-external.js +17 -0
  20. package/lib/auth/oauth.js +7 -0
  21. package/lib/auth-bot-challenge.js +505 -0
  22. package/lib/auth-header.js +92 -25
  23. package/lib/backup/bundle.js +26 -0
  24. package/lib/backup/index.js +512 -89
  25. package/lib/backup/manifest.js +168 -7
  26. package/lib/break-glass.js +415 -39
  27. package/lib/budr.js +103 -30
  28. package/lib/bundler.js +86 -66
  29. package/lib/cache.js +192 -72
  30. package/lib/chain-writer.js +65 -40
  31. package/lib/circuit-breaker.js +56 -33
  32. package/lib/cli-helpers.js +106 -75
  33. package/lib/cli.js +6 -30
  34. package/lib/cloud-events.js +99 -32
  35. package/lib/cluster-storage.js +162 -37
  36. package/lib/cluster.js +340 -49
  37. package/lib/codepoint-class.js +66 -0
  38. package/lib/compliance.js +424 -24
  39. package/lib/config-drift.js +111 -46
  40. package/lib/config.js +94 -40
  41. package/lib/consent.js +165 -18
  42. package/lib/constants.js +1 -0
  43. package/lib/content-credentials.js +153 -48
  44. package/lib/cookies.js +154 -62
  45. package/lib/credential-hash.js +133 -61
  46. package/lib/crypto-field.js +702 -18
  47. package/lib/crypto-hpke.js +256 -0
  48. package/lib/crypto.js +744 -22
  49. package/lib/csv.js +178 -35
  50. package/lib/daemon.js +456 -0
  51. package/lib/dark-patterns.js +186 -55
  52. package/lib/db-query.js +79 -2
  53. package/lib/db.js +1431 -60
  54. package/lib/ddl-change-control.js +523 -0
  55. package/lib/deprecate.js +195 -40
  56. package/lib/dev.js +82 -39
  57. package/lib/dora.js +67 -48
  58. package/lib/dr-runbook.js +368 -0
  59. package/lib/dsr.js +142 -11
  60. package/lib/dual-control.js +91 -56
  61. package/lib/events.js +120 -41
  62. package/lib/external-db-migrate.js +192 -2
  63. package/lib/external-db.js +795 -50
  64. package/lib/fapi2.js +122 -1
  65. package/lib/fda-21cfr11.js +395 -0
  66. package/lib/fdx.js +132 -2
  67. package/lib/file-type.js +87 -0
  68. package/lib/file-upload.js +93 -0
  69. package/lib/flag.js +82 -20
  70. package/lib/forms.js +132 -29
  71. package/lib/framework-error.js +169 -0
  72. package/lib/framework-schema.js +163 -35
  73. package/lib/gate-contract.js +849 -175
  74. package/lib/graphql-federation.js +68 -7
  75. package/lib/guard-all.js +172 -55
  76. package/lib/guard-archive.js +286 -124
  77. package/lib/guard-auth.js +194 -21
  78. package/lib/guard-cidr.js +190 -28
  79. package/lib/guard-csv.js +397 -51
  80. package/lib/guard-domain.js +213 -91
  81. package/lib/guard-email.js +236 -29
  82. package/lib/guard-filename.js +307 -75
  83. package/lib/guard-graphql.js +263 -30
  84. package/lib/guard-html.js +310 -116
  85. package/lib/guard-image.js +243 -30
  86. package/lib/guard-json.js +260 -54
  87. package/lib/guard-jsonpath.js +235 -23
  88. package/lib/guard-jwt.js +284 -30
  89. package/lib/guard-markdown.js +204 -22
  90. package/lib/guard-mime.js +190 -26
  91. package/lib/guard-oauth.js +277 -28
  92. package/lib/guard-pdf.js +251 -27
  93. package/lib/guard-regex.js +226 -18
  94. package/lib/guard-shell.js +229 -26
  95. package/lib/guard-svg.js +177 -10
  96. package/lib/guard-template.js +232 -21
  97. package/lib/guard-time.js +195 -29
  98. package/lib/guard-uuid.js +189 -30
  99. package/lib/guard-xml.js +259 -36
  100. package/lib/guard-yaml.js +241 -44
  101. package/lib/honeytoken.js +63 -27
  102. package/lib/html-balance.js +83 -0
  103. package/lib/http-client.js +486 -59
  104. package/lib/http-message-signature.js +582 -0
  105. package/lib/i18n.js +102 -49
  106. package/lib/iab-mspa.js +112 -32
  107. package/lib/iab-tcf.js +107 -2
  108. package/lib/inbox.js +90 -52
  109. package/lib/keychain.js +865 -0
  110. package/lib/legal-hold.js +374 -0
  111. package/lib/local-db-thin.js +320 -0
  112. package/lib/log-stream.js +281 -51
  113. package/lib/log.js +184 -86
  114. package/lib/mail-bounce.js +107 -62
  115. package/lib/mail.js +295 -58
  116. package/lib/mcp.js +108 -27
  117. package/lib/metrics.js +98 -89
  118. package/lib/middleware/age-gate.js +36 -0
  119. package/lib/middleware/ai-act-disclosure.js +37 -0
  120. package/lib/middleware/api-encrypt.js +45 -0
  121. package/lib/middleware/assetlinks.js +40 -0
  122. package/lib/middleware/asyncapi-serve.js +35 -0
  123. package/lib/middleware/attach-user.js +40 -0
  124. package/lib/middleware/bearer-auth.js +40 -0
  125. package/lib/middleware/body-parser.js +230 -0
  126. package/lib/middleware/bot-disclose.js +34 -0
  127. package/lib/middleware/bot-guard.js +39 -0
  128. package/lib/middleware/compression.js +37 -0
  129. package/lib/middleware/cookies.js +32 -0
  130. package/lib/middleware/cors.js +40 -0
  131. package/lib/middleware/csp-nonce.js +40 -0
  132. package/lib/middleware/csp-report.js +34 -0
  133. package/lib/middleware/csrf-protect.js +43 -0
  134. package/lib/middleware/daily-byte-quota.js +53 -85
  135. package/lib/middleware/db-role-for.js +40 -0
  136. package/lib/middleware/dpop.js +40 -0
  137. package/lib/middleware/error-handler.js +37 -14
  138. package/lib/middleware/fetch-metadata.js +39 -0
  139. package/lib/middleware/flag-context.js +34 -0
  140. package/lib/middleware/gpc.js +33 -0
  141. package/lib/middleware/headers.js +35 -0
  142. package/lib/middleware/health.js +46 -0
  143. package/lib/middleware/host-allowlist.js +30 -0
  144. package/lib/middleware/network-allowlist.js +38 -0
  145. package/lib/middleware/openapi-serve.js +34 -0
  146. package/lib/middleware/rate-limit.js +160 -18
  147. package/lib/middleware/request-id.js +36 -18
  148. package/lib/middleware/request-log.js +37 -0
  149. package/lib/middleware/require-aal.js +29 -0
  150. package/lib/middleware/require-auth.js +32 -0
  151. package/lib/middleware/require-bound-key.js +41 -0
  152. package/lib/middleware/require-content-type.js +32 -0
  153. package/lib/middleware/require-methods.js +27 -0
  154. package/lib/middleware/require-mtls.js +33 -0
  155. package/lib/middleware/require-step-up.js +37 -0
  156. package/lib/middleware/security-headers.js +44 -0
  157. package/lib/middleware/security-txt.js +38 -0
  158. package/lib/middleware/span-http-server.js +37 -0
  159. package/lib/middleware/sse.js +36 -0
  160. package/lib/middleware/trace-log-correlation.js +33 -0
  161. package/lib/middleware/trace-propagate.js +32 -0
  162. package/lib/middleware/tus-upload.js +90 -0
  163. package/lib/middleware/web-app-manifest.js +53 -0
  164. package/lib/mtls-ca.js +100 -70
  165. package/lib/network-byte-quota.js +308 -0
  166. package/lib/network-heartbeat.js +135 -0
  167. package/lib/network-tls.js +534 -4
  168. package/lib/network.js +103 -0
  169. package/lib/notify.js +114 -43
  170. package/lib/ntp-check.js +192 -51
  171. package/lib/observability.js +145 -47
  172. package/lib/openapi.js +90 -44
  173. package/lib/outbox.js +99 -1
  174. package/lib/pagination.js +168 -86
  175. package/lib/parsers/index.js +16 -5
  176. package/lib/permissions.js +93 -40
  177. package/lib/pqc-agent.js +84 -8
  178. package/lib/pqc-software.js +94 -60
  179. package/lib/process-spawn.js +95 -21
  180. package/lib/pubsub.js +96 -66
  181. package/lib/queue.js +375 -54
  182. package/lib/redact.js +793 -21
  183. package/lib/render.js +139 -47
  184. package/lib/request-helpers.js +485 -121
  185. package/lib/restore-bundle.js +142 -39
  186. package/lib/restore-rollback.js +136 -45
  187. package/lib/retention.js +178 -50
  188. package/lib/retry.js +116 -33
  189. package/lib/router.js +475 -23
  190. package/lib/safe-async.js +543 -94
  191. package/lib/safe-buffer.js +337 -41
  192. package/lib/safe-json.js +467 -62
  193. package/lib/safe-jsonpath.js +285 -0
  194. package/lib/safe-schema.js +631 -87
  195. package/lib/safe-sql.js +221 -59
  196. package/lib/safe-url.js +278 -46
  197. package/lib/sandbox-worker.js +135 -0
  198. package/lib/sandbox.js +358 -0
  199. package/lib/scheduler.js +135 -70
  200. package/lib/self-update.js +647 -0
  201. package/lib/session-device-binding.js +431 -0
  202. package/lib/session.js +259 -49
  203. package/lib/slug.js +138 -26
  204. package/lib/ssrf-guard.js +316 -56
  205. package/lib/storage.js +433 -70
  206. package/lib/subject.js +405 -23
  207. package/lib/template.js +148 -8
  208. package/lib/tenant-quota.js +545 -0
  209. package/lib/testing.js +440 -53
  210. package/lib/time.js +291 -23
  211. package/lib/tls-exporter.js +239 -0
  212. package/lib/tracing.js +90 -74
  213. package/lib/uuid.js +97 -22
  214. package/lib/vault/index.js +284 -22
  215. package/lib/vault/seal-pem-file.js +66 -0
  216. package/lib/watcher.js +368 -0
  217. package/lib/webhook.js +196 -63
  218. package/lib/websocket.js +393 -68
  219. package/lib/wiki-concepts.js +338 -0
  220. package/lib/worker-pool.js +464 -0
  221. package/package.json +3 -3
  222. package/sbom.cyclonedx.json +7 -7
@@ -1,83 +1,44 @@
1
1
  "use strict";
2
2
  /**
3
- * app-shutdown — graceful-shutdown orchestrator.
3
+ * @module b.appShutdown
4
+ * @nav Production
5
+ * @title App Shutdown
4
6
  *
5
- * SIGTERM is the contract between Kubernetes / systemd / docker stop
6
- * and the framework. Production rolling restarts depend on the
7
- * server draining cleanly: stop accepting new traffic, finish in-
8
- * flight requests, drain jobs, close DB, release the cluster lease.
9
- * Without orchestration each subsystem's shutdown races every other
10
- * subsystem's; the result is dropped requests, half-completed jobs,
11
- * stuck cluster leases that block the next pod from acquiring.
7
+ * @intro
8
+ * Graceful shutdown orchestrator drain in-flight requests, flush
9
+ * audit, close DB, release the cluster lease, then exit. Configurable
10
+ * timeouts and signal handlers wire SIGTERM / SIGINT (and any
11
+ * operator-supplied signals) into a single phase-ordered shutdown.
12
12
  *
13
- * This module ships a phase-ordered orchestrator. Each phase is
14
- * named, time-bounded, and best-effort a phase failure logs an
15
- * issue but doesn't block subsequent phases (we still want to close
16
- * the DB and release the lease even if jobs draining timed out).
13
+ * SIGTERM is the contract between Kubernetes / systemd / `docker
14
+ * stop` and the framework. Production rolling restarts depend on the
15
+ * server draining cleanly. Without orchestration each subsystem's
16
+ * shutdown races every other subsystem's the result is dropped
17
+ * requests, half-completed jobs, and stuck cluster leases that block
18
+ * the next pod from acquiring. The orchestrator runs phases in array
19
+ * order with per-phase budgets so a slow phase cannot starve later
20
+ * ones; a phase failure is logged but does not skip the remaining
21
+ * phases (the DB still closes even if jobs drain timed out).
17
22
  *
18
- * Standard phase order:
23
+ * `b.appShutdown.standardPhases(components)` builds the canonical
24
+ * ordering — mark-draining → scheduler → jobs → websockets →
25
+ * http-server → cluster → db → external-db — given a components map.
26
+ * Operators with custom topology call it directly and prepend or
27
+ * append their own phases. `b.appShutdown.pidLock(path)` is a single-
28
+ * instance file lock for daemons that must run exactly once on a
29
+ * host; it composes with the orchestrator via `addPhase` so the lock
30
+ * is released as part of graceful shutdown.
19
31
  *
20
- * 1. beforeStop operator hook (run before anything else)
21
- * 2. mark-draining health.markShuttingDown() so /readyz 503
22
- * and the LB starts draining the pod
23
- * 3. stop-accepting flip the orchestrator's `draining` flag
24
- * middleware (orchestrator.middleware())
25
- * refuses new requests with 503
26
- * 4. drain-in-flight wait for the in-flight counter to reach 0
27
- * (tracked via the same middleware) up to
28
- * phaseTimeoutMs
29
- * 5. afterDrain operator hook (run after in-flight drained)
30
- * 6. scheduler scheduler.stop() if registered
31
- * 7. jobs jobs.shutdown() / queue.shutdown() — let
32
- * current handlers finish, refuse new lease
33
- * 8. websockets router.closeWebSockets() if HTTP server
34
- * 9. http-server server.close() — waits for keepalive
35
- * connections to drain
36
- * 10. cluster cluster.shutdown() — release lease cleanly
37
- * so the next pod can acquire it without
38
- * waiting out the lease TTL
39
- * 11. db db.close() — flushes encrypted-at-rest
40
- * snapshot, closes SQLite handle
41
- * 12. external-db externalDb.shutdown() — drain pool
32
+ * Idempotency: `shutdown()` is idempotent. Calling it twice returns
33
+ * the same Promise. Signal handlers route through the same call so
34
+ * SIGTERM, SIGINT, an `uncaughtException` reaching the operator hook,
35
+ * and a manual `orchestrator.shutdown()` all converge on one
36
+ * orchestration. When `b.tracing` has an active registry every phase
37
+ * runs inside a span named `shutdown.<phase>` so per-phase durations
38
+ * surface in the operator's tracing exporter.
42
39
  *
43
- * Custom phases can be added via opts.phases; each entry is
44
- * { name, run: async fn, timeoutMs? }. The orchestrator runs them
45
- * in array order. The standard phase set above is added by
46
- * createApp via the components map; standalone callers build their
47
- * own.
48
- *
49
- * var orchestrator = b.appShutdown.create({
50
- * graceMs: 30000,
51
- * phases: [
52
- * { name: "beforeStop", run: async function () { ... } },
53
- * { name: "drain-in-flight", run: orchestrator.waitInFlight, timeoutMs: 10000 },
54
- * { name: "db", run: function () { db.close(); } },
55
- * ],
56
- * installSignalHandlers: true, // SIGTERM + SIGINT auto-call shutdown
57
- * });
58
- *
59
- * var result = await orchestrator.shutdown();
60
- * // → { ok, phases: [{ name, ms, ok, error? }, ...], totalMs, draining }
61
- *
62
- * // Mounted as middleware to refuse new requests during drain +
63
- * // track in-flight count.
64
- * router.use(orchestrator.middleware());
65
- *
66
- * orchestrator.draining(); // true once shutdown() has been called
67
- * orchestrator.inFlight(); // current in-flight count
68
- *
69
- * Idempotency: shutdown() is idempotent. Calling it twice returns
70
- * the same Promise. Signal handlers fire it via `installSignalHandlers`
71
- * so SIGTERM + SIGINT both route through the same orchestration.
72
- *
73
- * Per-phase timeouts: each phase has a budget. If a phase doesn't
74
- * complete within timeoutMs it's marked failed and the orchestrator
75
- * moves to the next phase. Default = remaining grace divided by
76
- * remaining phases (so a slow phase doesn't starve later ones).
77
- *
78
- * Tracing integration: when b.tracing has an active registry, each
79
- * phase runs inside a span named "shutdown.<phase>" so operators see
80
- * which phase took how long in their tracing exporter.
40
+ * @card
41
+ * Graceful shutdown orchestrator — drain in-flight requests, flush audit, close DB, release the cluster lease, then exit.
81
42
  */
82
43
 
83
44
  var safeAsync = require("./safe-async");
@@ -93,6 +54,41 @@ var log = boot("app-shutdown");
93
54
 
94
55
  var DEFAULT_GRACE_MS = C.TIME.seconds(30);
95
56
 
57
+ /**
58
+ * @primitive b.appShutdown.create
59
+ * @signature b.appShutdown.create(opts)
60
+ * @since 0.6.0
61
+ * @related b.appShutdown.standardPhases, b.appShutdown.pidLock
62
+ *
63
+ * Build a graceful-shutdown orchestrator. Returns an instance with
64
+ * `shutdown()` (idempotent — second call returns the same Promise),
65
+ * `middleware()` (refuses new requests with 503 + tracks in-flight
66
+ * count), `waitInFlight()`, `addPhase()`, `installSignals()`,
67
+ * `uninstallSignals()`, `draining()`, and `inFlight()`. Each phase has
68
+ * a per-phase budget; the default is remaining grace divided by
69
+ * remaining phases so a slow phase doesn't starve later ones. A phase
70
+ * failure is logged but does not skip the remaining phases.
71
+ *
72
+ * @opts
73
+ * graceMs: number, // total budget across all phases (default 30000)
74
+ * phases: array, // [{ name, run: async fn, timeoutMs? }]
75
+ * installSignalHandlers: boolean, // wire SIGTERM/SIGINT (default false)
76
+ * signals: array, // signal names (default ["SIGTERM","SIGINT"])
77
+ * onUncaught: function, // hook for uncaughtException / unhandledRejection
78
+ * installUncaught: boolean, // wire uncaughtException handler unconditionally
79
+ *
80
+ * @example
81
+ * var orchestrator = b.appShutdown.create({
82
+ * graceMs: 30000,
83
+ * phases: [
84
+ * { name: "before-stop", run: async function () { return "ok"; } },
85
+ * { name: "db", run: function () { return; }, timeoutMs: 5000 },
86
+ * ],
87
+ * });
88
+ * var result = await orchestrator.shutdown();
89
+ * result.ok; // → true
90
+ * result.phases.length; // → 2
91
+ */
96
92
  function create(opts) {
97
93
  opts = opts || {};
98
94
  nb.requirePositiveFiniteIntIfPresent(opts.graceMs,
@@ -331,10 +327,26 @@ function create(opts) {
331
327
  };
332
328
  }
333
329
 
334
- // Standard phase builder — given a components map, returns a phases
335
- // array suitable for create({ phases }). Used by createApp; operators
336
- // with custom topology call this directly to get the same ordering
337
- // then prepend / append their own phases.
330
+ /**
331
+ * @primitive b.appShutdown.standardPhases
332
+ * @signature b.appShutdown.standardPhases(components)
333
+ * @since 0.6.0
334
+ * @related b.appShutdown.create
335
+ *
336
+ * Build the canonical phases array for a components map. The order is
337
+ * mark-draining → scheduler → jobs (or queue) → websockets →
338
+ * http-server → cluster → db → external-db. Each entry carries a
339
+ * conservative `timeoutMs`. Operators wire the result into
340
+ * `b.appShutdown.create({ phases })`; with a non-standard topology they
341
+ * prepend or append their own entries to the returned array.
342
+ *
343
+ * @example
344
+ * var phases = b.appShutdown.standardPhases({
345
+ * db: { close: function () { return; } },
346
+ * });
347
+ * phases.length; // → 1
348
+ * phases[0].name; // → "db"
349
+ */
338
350
  function standardPhases(components) {
339
351
  components = components || {};
340
352
  var phases = [];
@@ -440,6 +452,30 @@ function standardPhases(components) {
440
452
  var nodeFs = require("fs");
441
453
  var nodePath = require("path");
442
454
 
455
+ /**
456
+ * @primitive b.appShutdown.pidLock
457
+ * @signature b.appShutdown.pidLock(lockPath)
458
+ * @since 0.6.0
459
+ * @related b.appShutdown.create
460
+ *
461
+ * Single-instance file lock for daemons that must run exactly once on
462
+ * a host. Returns `{ acquire, release, held, path }`. `acquire()`
463
+ * writes the current PID atomically (open with O_EXCL + write + fsync)
464
+ * and refuses to acquire if another live process already holds the
465
+ * lock; stale lock files (PID gone) are reaped automatically. On
466
+ * Windows the underlying advisory flock is unavailable, so the lock
467
+ * file's exclusive presence is the lock. Compose with the orchestrator
468
+ * by passing `release` as a phase via `addPhase`.
469
+ *
470
+ * @example
471
+ * var lock = b.appShutdown.pidLock("/tmp/blamejs-doc-example.pid");
472
+ * try {
473
+ * lock.acquire();
474
+ * lock.held(); // → true
475
+ * } finally {
476
+ * lock.release();
477
+ * }
478
+ */
443
479
  function pidLock(lockPath) {
444
480
  if (typeof lockPath !== "string" || lockPath.length === 0) {
445
481
  throw new AppShutdownError("app-shutdown/bad-pidlock-path",