@blamejs/core 0.8.42 → 0.8.49

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,73 +1,44 @@
1
1
  "use strict";
2
2
  /**
3
- * b.credentialHash — envelope-versioned credential hashing.
3
+ * @module b.credentialHash
4
+ * @nav Identity
5
+ * @title Credential Hash
4
6
  *
5
- * Stores a verifiable digest of a credential (API key secret, shared
6
- * bearer token, etc.) as a base64-encoded envelope:
7
+ * @intro
8
+ * Derive a deterministic, verifiable hash for credential lookup
9
+ * (API-key secret, shared bearer token, webhook signing key) without
10
+ * storing the credential itself. The default is an Argon2id-style
11
+ * fingerprint over a SHAKE256 MAC — same chassis the password
12
+ * primitive uses, but tuned for high-entropy machine-generated
13
+ * secrets where memory-hard work is unnecessary.
7
14
  *
8
- * byte 0: 0xC1 (CREDENTIAL_MAGIC)
9
- * byte 1: <algorithm ID>
10
- * bytes 2..N: algorithm-specific payload
15
+ * Rows persist a base64 envelope:
11
16
  *
12
- * The verify path dispatches on byte 1, so old credentials remain
13
- * verifiable regardless of what ACTIVE.CRED_HASH points at today.
14
- * When a new algorithm becomes the framework default, existing rows
15
- * surface via `needsRehash()` and the next successful verify rotates
16
- * them transparently — same pattern as `b.auth.password.needsRehash`.
17
+ * byte 0: 0xC1 (CREDENTIAL_MAGIC)
18
+ * byte 1: algorithm ID (0x01 SHAKE256 | 0x02 Argon2id)
19
+ * bytes 2-N: algorithm-specific payload
17
20
  *
18
- * var env = await b.credentialHash.hash(secretBytes);
19
- * // "wQEx..." (base64)
21
+ * `verify` dispatches on the algorithm byte so old rows remain
22
+ * verifiable regardless of what `ACTIVE.CRED_HASH` is today. When a
23
+ * new algorithm becomes the framework default, existing rows surface
24
+ * via `needsRehash()` and the next successful verify rotates them
25
+ * transparently — same pattern as `b.auth.password.needsRehash`.
20
26
  *
21
- * var ok = await b.credentialHash.verify(secretBytes, env);
22
- * // true / false
23
- *
24
- * var info = b.credentialHash.inspect(env);
25
- * // { algoId, algoName, payloadBytes }
26
- *
27
- * if (b.credentialHash.needsRehash(env)) {
28
- * await db.update({ credentialHash: await b.credentialHash.hash(secretBytes) });
29
- * }
30
- *
31
- * Active algorithm: SHAKE256 (0x01). Suitable for high-entropy random
32
- * secrets (≥ 128 bits) — fast verify (microseconds), brute-force
33
- * infeasible at the entropy level the framework generates. SHAKE256
34
- * is an XOF: the envelope payload length drives the digest size, so
35
- * a future operator can request a 96-byte (or 32-byte) digest without
36
- * a primitive change — the same algorithm ID covers all output sizes.
37
- * Operators with low-entropy or operator-supplied secrets should pin
38
- * Argon2id (0x02) per-registry: `hash(s, { algo: "argon2id" })`.
39
- *
40
- * Why SHAKE256 over SHA3-512 as the active:
41
- * - SHAKE256 is an extensible-output function (XOF). The envelope
42
- * payload's actual byte length tells the verify path how many
43
- * bytes to recompute. Changing digest size = no algo rotation.
44
- * - Same family as the framework KDF (`crypto.kdf`), so one
45
- * primitive does double duty.
46
- * - SHA-3 family fixed-size mode locks the byte count at 64 — the
47
- * moment we want a different size, we'd have to rotate algos.
48
- *
49
- * Why not Argon2id by default for api-key:
50
- * - Argon2id at framework defaults costs ~250ms per verify call.
51
- * For request-path verification that's a real latency hit.
52
- * SHAKE256 is microseconds.
53
- * - For ≥128-bit random secrets, the memory-hard property buys
54
- * nothing — brute force is infeasible regardless of hash.
55
- *
56
- * Why the envelope still matters with SHAKE256 as active:
57
- * - Algorithm agility — when SHA-3 family ever shows weakness, or
58
- * a stronger XOF lands, ACTIVE.CRED_HASH rotates with no need
59
- * to re-issue every credential. Old rows verify under their
60
- * stored algo byte; new rows use the active.
61
- * - Transparent rehash via needsRehash() drains old algos at the
62
- * pace of organic verify traffic.
27
+ * Active algorithm: SHAKE256 (0x01). Suitable for high-entropy random
28
+ * secrets (>= 128 bits) — verify is microseconds, brute force is
29
+ * infeasible at the entropy level the framework generates. SHAKE256
30
+ * is an XOF: the envelope payload length drives the digest size, so
31
+ * a future operator can request a 96-byte (or 32-byte) digest with no
32
+ * algorithm rotation. Operators with low-entropy or operator-supplied
33
+ * secrets pin Argon2id per-registry via `{ algo: "argon2id" }`.
63
34
  *
64
- * Validation policy:
35
+ * Validation tiers:
36
+ * - hash() opts and secret shape — throw at call site (config-time)
37
+ * - verify() malformed envelope or unknown algo ID — return false
38
+ * - inspect() malformed envelope — return null
65
39
  *
66
- * - hash() opts (algo, params) → throw at call site
67
- * - hash() secret type / length → throw at call site
68
- * - verify() envelope shape unparsable → return false (tolerant read)
69
- * - verify() unknown algo ID → return false (tolerant read)
70
- * - inspect() bad envelope → return null (tolerant read)
40
+ * @card
41
+ * Derive a deterministic, verifiable hash for credential lookup (API-key secret, shared bearer token, webhook signing key) without storing the credential itself.
71
42
  */
72
43
 
73
44
  var crypto = require("./crypto");
@@ -196,6 +167,37 @@ function _decodeEnvelope(env) {
196
167
 
197
168
  // ---- Public surface ----
198
169
 
170
+ /**
171
+ * @primitive b.credentialHash.hash
172
+ * @signature b.credentialHash.hash(secret, opts?)
173
+ * @since 0.2.28
174
+ * @status stable
175
+ * @compliance pci-dss, soc2, hipaa
176
+ * @related b.credentialHash.verify, b.credentialHash.needsRehash, b.auth.password.hash
177
+ *
178
+ * Hash a credential secret into a base64 envelope ready for storage in
179
+ * a `credentialHash` column. Default algorithm is SHAKE256 with a
180
+ * 128-byte output; pass `{ algo: "argon2id" }` for low-entropy or
181
+ * operator-supplied secrets. Throws on a non-string-or-Buffer secret,
182
+ * an unknown algorithm, a non-object `params`, or a SHAKE256 length
183
+ * below the 16-byte (128-bit) collision-space floor.
184
+ *
185
+ * @opts
186
+ * algo: "shake256" | "argon2id",
187
+ * params: {
188
+ * length: number, // SHAKE256 output bytes (default 128)
189
+ * ... // Argon2id m / t / p forwarded to b.auth.password
190
+ * },
191
+ *
192
+ * @example
193
+ * var token = b.crypto.generateToken(); // 32 random bytes, base64url
194
+ * var env = await b.credentialHash.hash(token);
195
+ * // → "wQE..." (base64 envelope)
196
+ *
197
+ * // Operator-supplied (low-entropy) secret pins Argon2id:
198
+ * var humanEnv = await b.credentialHash.hash("partner-shared-key", { algo: "argon2id" });
199
+ * // → "wQI..." (base64 envelope, algo byte 0x02)
200
+ */
199
201
  async function hash(secret, opts) {
200
202
  _validateSecret(secret);
201
203
  _validateOpts(opts);
@@ -228,6 +230,29 @@ async function hash(secret, opts) {
228
230
  "credential-hash/unsupported");
229
231
  }
230
232
 
233
+ /**
234
+ * @primitive b.credentialHash.verify
235
+ * @signature b.credentialHash.verify(secret, envelope)
236
+ * @since 0.2.28
237
+ * @status stable
238
+ * @compliance pci-dss, soc2, hipaa
239
+ * @related b.credentialHash.hash, b.credentialHash.needsRehash
240
+ *
241
+ * Constant-time check that `secret` matches the stored envelope.
242
+ * Tolerant read: malformed envelope / unknown algorithm / payload
243
+ * shorter than 16 bytes returns `false` without throwing, so callers
244
+ * write a single `if (!await verify(...))` branch without try/catch
245
+ * ceremony. Emits `credentialHash.verify` observability events with
246
+ * outcome + reason for SIEM dashboards.
247
+ *
248
+ * @example
249
+ * var ok = await b.credentialHash.verify(presented, row.credentialHash);
250
+ * if (!ok) {
251
+ * res.statusCode = 401;
252
+ * return res.end();
253
+ * }
254
+ * // → true / false
255
+ */
231
256
  async function verify(secret, envelope) {
232
257
  // Tolerant read: any malformed envelope → false. Lets operators write
233
258
  // if (!await ch.verify(s, row.hash)) return res.status(401);
@@ -285,6 +310,26 @@ async function verify(secret, envelope) {
285
310
  return false;
286
311
  }
287
312
 
313
+ /**
314
+ * @primitive b.credentialHash.inspect
315
+ * @signature b.credentialHash.inspect(envelope)
316
+ * @since 0.2.28
317
+ * @status stable
318
+ * @related b.credentialHash.needsRehash
319
+ *
320
+ * Decode the envelope's algorithm byte and payload length without
321
+ * verifying the secret. Returns `null` for any malformed envelope
322
+ * (missing magic byte, unknown algorithm, truncated). Used by
323
+ * operator dashboards to count rows-by-algorithm during a rotation
324
+ * window.
325
+ *
326
+ * @example
327
+ * var info = b.credentialHash.inspect(row.credentialHash);
328
+ * if (info && info.algoName === "shake256" && info.payloadBytes < 64) {
329
+ * console.warn("legacy SHAKE256 row, will be rotated on next verify");
330
+ * }
331
+ * // → { algoId: 0x01, algoName: "shake256", payloadBytes: 128 }
332
+ */
288
333
  function inspect(envelope) {
289
334
  var decoded = _decodeEnvelope(envelope);
290
335
  if (!decoded) return null;
@@ -295,6 +340,33 @@ function inspect(envelope) {
295
340
  };
296
341
  }
297
342
 
343
+ /**
344
+ * @primitive b.credentialHash.needsRehash
345
+ * @signature b.credentialHash.needsRehash(envelope, opts?)
346
+ * @since 0.2.28
347
+ * @status stable
348
+ * @related b.credentialHash.hash, b.credentialHash.verify, b.auth.password.needsRehash
349
+ *
350
+ * Returns `true` when the stored envelope was produced under an
351
+ * algorithm or parameter set that no longer matches the framework
352
+ * default. Operators wrap a successful `verify` with this and re-issue
353
+ * the credential transparently — same shape as `b.auth.password`.
354
+ * Argon2id rows defer the parameter-lag check to the password
355
+ * primitive's own `needsRehash` so the threshold lives in one place.
356
+ *
357
+ * @opts
358
+ * algo: "shake256" | "argon2id", // pin the comparison target
359
+ * params: object, // Argon2id m / t / p targets
360
+ *
361
+ * @example
362
+ * if (await b.credentialHash.verify(secret, row.credentialHash)) {
363
+ * if (b.credentialHash.needsRehash(row.credentialHash)) {
364
+ * var fresh = await b.credentialHash.hash(secret);
365
+ * db.from("apiKeys").where({ _id: row._id }).update({ credentialHash: fresh });
366
+ * }
367
+ * }
368
+ * // → true / false
369
+ */
298
370
  function needsRehash(envelope, opts) {
299
371
  var decoded = _decodeEnvelope(envelope);
300
372
  if (!decoded) return true; // unrecognized → migrate aggressively