@blamejs/core 0.13.43 → 0.13.45

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/lib/boot-gates.js CHANGED
@@ -66,7 +66,7 @@ var DEFAULT_EXIT_CODE = 1;
66
66
  async function run(gates, opts) {
67
67
  opts = opts || {};
68
68
  if (!Array.isArray(gates) || gates.length === 0) {
69
- throw new BootGatesError("bootgates/bad-input",
69
+ throw new BootGatesError("boot-gates/bad-input",
70
70
  "b.bootGates.run: gates must be a non-empty array");
71
71
  }
72
72
  var log = typeof opts.log === "function" ? opts.log : function (msg) {
@@ -82,7 +82,7 @@ async function run(gates, opts) {
82
82
  // throw rather than terminating the process — operators that wire
83
83
  // bootGates from their daemon main() pass `exit: process.exit.bind(process)`.
84
84
  var exit = typeof opts.exit === "function" ? opts.exit : function (code) {
85
- var e = new BootGatesError("bootgates/no-exit-wired",
85
+ var e = new BootGatesError("boot-gates/no-exit-wired",
86
86
  "b.bootGates.run: gate failed (exitCode=" + code + ") but no opts.exit handler was supplied; " +
87
87
  "operators wire opts.exit to process.exit.bind(process) in their daemon main()");
88
88
  e.exitCode = code;
@@ -96,26 +96,26 @@ async function run(gates, opts) {
96
96
  var gate = gates[i];
97
97
  if (!gate || typeof gate.name !== "string" || gate.name.length === 0 ||
98
98
  typeof gate.fn !== "function") {
99
- throw new BootGatesError("bootgates/bad-gate",
99
+ throw new BootGatesError("boot-gates/bad-gate",
100
100
  "b.bootGates.run: gates[" + i + "] must be { name: string, fn: function }");
101
101
  }
102
102
  var timeoutMs = gate.timeoutMs || DEFAULT_GATE_TIMEOUT_MS;
103
103
  if (typeof timeoutMs !== "number" || !isFinite(timeoutMs) || timeoutMs < 1) {
104
- throw new BootGatesError("bootgates/bad-timeout",
104
+ throw new BootGatesError("boot-gates/bad-timeout",
105
105
  "b.bootGates.run: gates[" + i + "].timeoutMs must be a positive finite number");
106
106
  }
107
107
  var gateT0 = Date.now();
108
108
  var failure = null;
109
109
  try {
110
110
  await safeAsync.withTimeout(Promise.resolve().then(gate.fn), timeoutMs,
111
- new BootGatesError("bootgates/timeout",
111
+ new BootGatesError("boot-gates/timeout",
112
112
  "b.bootGates.run: gate '" + gate.name + "' exceeded " + timeoutMs + "ms"));
113
113
  } catch (err) {
114
114
  failure = err;
115
115
  }
116
116
  if (overallTimeoutMs !== undefined &&
117
117
  Date.now() - t0 > overallTimeoutMs && failure === null) {
118
- failure = new BootGatesError("bootgates/overall-timeout",
118
+ failure = new BootGatesError("boot-gates/overall-timeout",
119
119
  "b.bootGates.run: overall budget " + overallTimeoutMs + "ms exceeded after gate '" +
120
120
  gate.name + "'");
121
121
  }
package/lib/budr.js CHANGED
@@ -78,31 +78,31 @@ var declarations = new Map();
78
78
  */
79
79
  function declare(opts) {
80
80
  if (!opts || typeof opts !== "object") {
81
- throw BudrError.factory("BAD_OPTS", "budr.declare: opts required");
81
+ throw BudrError.factory("budr/bad-opts", "budr.declare: opts required");
82
82
  }
83
83
  if (typeof opts.service !== "string" || opts.service.length === 0 ||
84
84
  opts.service.length > SERVICE_MAX || !SERVICE_RE.test(opts.service)) {
85
- throw BudrError.factory("BAD_SERVICE",
85
+ throw BudrError.factory("budr/bad-service",
86
86
  "budr.declare: service must match " + SERVICE_RE);
87
87
  }
88
88
  numericBounds.requirePositiveFiniteIntIfPresent(opts.rtoMs, "budr.declare: rtoMs", BudrError, "BAD_RTO");
89
89
  numericBounds.requirePositiveFiniteIntIfPresent(opts.rpoMs, "budr.declare: rpoMs", BudrError, "BAD_RPO");
90
90
  if (typeof opts.rtoMs !== "number" || typeof opts.rpoMs !== "number") {
91
- throw BudrError.factory("BAD_TARGETS",
91
+ throw BudrError.factory("budr/bad-targets",
92
92
  "budr.declare: rtoMs and rpoMs are required positive integer milliseconds");
93
93
  }
94
94
  if (opts.tier !== undefined && TIERS.indexOf(opts.tier) === -1) {
95
- throw BudrError.factory("BAD_TIER",
95
+ throw BudrError.factory("budr/bad-tier",
96
96
  "budr.declare: tier must be one of " + TIERS.join(", "));
97
97
  }
98
98
  if (opts.criticality !== undefined && CRITICALITIES.indexOf(opts.criticality) === -1) {
99
- throw BudrError.factory("BAD_CRITICALITY",
99
+ throw BudrError.factory("budr/bad-criticality",
100
100
  "budr.declare: criticality must be one of " + CRITICALITIES.join(", "));
101
101
  }
102
102
  validateOpts.optionalNonEmptyString(opts.owner,
103
103
  "budr.declare: owner", BudrError, "BAD_OWNER");
104
104
  if (opts.citations !== undefined && !Array.isArray(opts.citations)) {
105
- throw BudrError.factory("BAD_CITATIONS",
105
+ throw BudrError.factory("budr/bad-citations",
106
106
  "budr.declare: citations must be an array of strings");
107
107
  }
108
108
 
package/lib/cert.js CHANGED
@@ -22,9 +22,9 @@
22
22
  * - `b.acme.create` → ACME orders, JWS, ARI fetch
23
23
  * - `b.vault.seal` → sealed-disk persistence of certs + keys + account material
24
24
  * - `b.safeAsync.repeating` → renewal scheduler with drop-silent error path
25
- * - `b.network.tls.ocsp` → server-side stapling helpers
25
+ * - `b.network.tls.ocsp` → fetches + caches a validated OCSP response per cert for server-side stapling
26
26
  * - `b.audit` → cert.* lifecycle audit chain
27
- * - `b.compliance` → posture refusals (e.g. plaintext storage refused under HIPAA / PCI)
27
+ * - `b.compliance` → validates the declared posture names; storage-confidentiality postures hold because keys/certs are always sealed at rest
28
28
  *
29
29
  * Does NOT ship the challenge-solver implementations (HTTP-01 server,
30
30
  * DNS provider integrations, TLS-ALPN-01 socket). Those are operator-
@@ -60,6 +60,7 @@ var acme = lazyRequire(function () { return require("./acme"); });
60
60
  var vault = lazyRequire(function () { return require("./vault"); });
61
61
  var audit = lazyRequire(function () { return require("./audit"); });
62
62
  var networkTls = lazyRequire(function () { return require("./network-tls"); });
63
+ var compliance = lazyRequire(function () { return require("./compliance"); });
63
64
  var bCrypto = lazyRequire(function () { return require("./crypto"); });
64
65
 
65
66
  var CertError = defineClass("CertError");
@@ -222,7 +223,7 @@ function _createSealedDiskStorage(opts) {
222
223
  * refreshMs: number, // default 12h — OCSP-response cache lifetime
223
224
  * },
224
225
  * audit: boolean | object, // default true — emit cert.* lifecycle events via b.audit.safeEmit
225
- * compliance: Array<string>, // optional — posture refusals (e.g. ["hipaa"]); refuses plaintext storage etc.
226
+ * compliance: Array<string>, // optional — posture names (e.g. ["hipaa"]); validated against b.compliance.KNOWN_POSTURES (throws on an unknown name) + surfaced on getContext().compliance. Cert keys/certs are always sealed at rest, so storage-confidentiality postures hold by construction.
226
227
  *
227
228
  * @example
228
229
  * var mgr = b.cert.create({
@@ -383,13 +384,31 @@ function create(opts) {
383
384
 
384
385
  // ---- Audit + compliance ----
385
386
  var auditEnabled = opts.audit !== false;
386
- var compliance = Array.isArray(opts.compliance) ? opts.compliance.slice() : [];
387
+ var compliancePostures = Array.isArray(opts.compliance) ? opts.compliance.slice() : [];
388
+ // Validate posture names against the framework catalog so a typo is
389
+ // caught at create() rather than silently ignored. The cert manager
390
+ // satisfies the storage-confidentiality postures (HIPAA / PCI-DSS /
391
+ // GDPR …) by construction — keys + certs are always sealed at rest
392
+ // (storage.type is enforced to "sealed-disk"), so there is no plaintext-
393
+ // storage state for a posture to fail to. The postures are recorded +
394
+ // surfaced on the served context for an auditor.
395
+ if (compliancePostures.length > 0) {
396
+ var knownPostures = compliance().KNOWN_POSTURES;
397
+ compliancePostures.forEach(function (p) {
398
+ if (knownPostures.indexOf(p) === -1) {
399
+ throw new CertError("cert/unknown-compliance-posture",
400
+ "cert.create: opts.compliance posture '" + p + "' is not a known posture; " +
401
+ "see b.compliance.KNOWN_POSTURES");
402
+ }
403
+ });
404
+ }
387
405
 
388
406
  // ---- Internal state ----
389
407
  var emitter = new EventEmitter();
390
- var loadedContexts = Object.create(null); // name → { cert, key, ca, expiresAt, fingerprintSha256, sniNames }
408
+ var loadedContexts = Object.create(null); // name → { cert, key, ca, expiresAt, fingerprintSha256, sniNames, ocspResponse }
391
409
  var acmeClient = null;
392
410
  var scheduler = null;
411
+ var ocspTimer = null;
393
412
  var stopped = false;
394
413
 
395
414
  function _emitAudit(action, outcome, metadata) {
@@ -689,6 +708,39 @@ function create(opts) {
689
708
  }
690
709
  }
691
710
 
711
+ // Split a PEM chain into individual certificate blocks (leaf first).
712
+ function _splitPemChain(pem) {
713
+ return pem.match(/-----BEGIN CERTIFICATE-----[\s\S]+?-----END CERTIFICATE-----/g) || [];
714
+ }
715
+
716
+ // Fetch + cache a validated OCSP response for one managed cert, for
717
+ // server-side stapling. Fail-soft: a responder error, or no issuer in the
718
+ // served chain, leaves any prior staple in place and never throws — an
719
+ // absent staple degrades gracefully (clients fall back to their own
720
+ // revocation checking). The validated DER is exposed on
721
+ // getContext().ocspResponse for the operator's TLS server to staple via
722
+ // its 'OCSPRequest' handler.
723
+ async function _refreshOcspFor(name) {
724
+ var ctx = loadedContexts[name];
725
+ if (!ctx || !ocspStapling) return;
726
+ var chain = _splitPemChain(ctx.cert);
727
+ if (chain.length < 2) return; // no issuer in the served chain
728
+ try {
729
+ // allow:raw-outbound-http — b.network.tls.ocsp.fetch composes b.httpClient internally (SSRF guard + pinned DNS); not a raw outbound call
730
+ var rv = await networkTls().ocsp.fetch({ leafPem: chain[0], issuerPem: chain[1] });
731
+ ctx.ocspResponse = rv.ocspDer;
732
+ _emitAudit("cert.ocsp.refreshed", "success", { name: name });
733
+ } catch (e) {
734
+ _emitAudit("cert.ocsp.refresh-failed", "failure",
735
+ { name: name, error: (e && e.message) || String(e) });
736
+ }
737
+ }
738
+
739
+ async function _refreshAllOcsp() {
740
+ var keys = Object.keys(loadedContexts);
741
+ for (var i = 0; i < keys.length; i += 1) { await _refreshOcspFor(keys[i]); }
742
+ }
743
+
692
744
  async function start() {
693
745
  if (stopped) {
694
746
  throw new CertError("cert/already-stopped",
@@ -706,12 +758,21 @@ function create(opts) {
706
758
  await _renewCheckOne(certsByName[keys[ki]]);
707
759
  }
708
760
  }, renewIntervalMs, { name: "cert-renew" });
761
+ // 3. OCSP stapling. The initial fetch runs in the background so a slow
762
+ // responder never delays start(); the staple becomes available
763
+ // shortly after, and the timer refreshes on the configured cadence.
764
+ if (ocspStapling) {
765
+ _refreshAllOcsp().catch(function () { /* per-cert errors already audited */ });
766
+ ocspTimer = safeAsync.repeating(_refreshAllOcsp, ocspRefreshMs, { name: "cert-ocsp" });
767
+ }
709
768
  }
710
769
 
711
770
  async function stop() {
712
771
  stopped = true;
713
772
  if (scheduler && typeof scheduler.stop === "function") scheduler.stop();
714
773
  scheduler = null;
774
+ if (ocspTimer && typeof ocspTimer.stop === "function") ocspTimer.stop();
775
+ ocspTimer = null;
715
776
  }
716
777
 
717
778
  function getContext(name) {
@@ -729,6 +790,11 @@ function create(opts) {
729
790
  key: ctx.key,
730
791
  expiresAt: ctx.expiresAt,
731
792
  fingerprintSha256: ctx.fingerprintSha256,
793
+ // The cached, validated OCSP response (DER Buffer) when ocsp.stapling
794
+ // is on and a response has been fetched; null otherwise. Staple it
795
+ // from the TLS server's 'OCSPRequest' handler: cb(null, ocspResponse).
796
+ ocspResponse: ctx.ocspResponse || null,
797
+ compliance: compliancePostures.slice(),
732
798
  };
733
799
  }
734
800
 
@@ -798,10 +864,6 @@ function create(opts) {
798
864
  function off(event, handler) { emitter.off(event, handler); return this; }
799
865
  function once(event, handler) { emitter.once(event, handler); return this; }
800
866
 
801
- // Suppress unused-warnings for ocsp + compliance until those branches
802
- // wire up in v0.11.23+ follow-up.
803
- void ocspStapling; void ocspRefreshMs; void compliance; void networkTls;
804
-
805
867
  return {
806
868
  start: start,
807
869
  stop: stop,
@@ -48,7 +48,7 @@ var REQUIRED_FIELDS = ["provider", "system", "systemVersion", "contentId"];
48
48
 
49
49
  function _validateBuildOpts(opts) {
50
50
  if (!opts || typeof opts !== "object") {
51
- throw ContentCredentialsError.factory("BAD_OPTS",
51
+ throw ContentCredentialsError.factory("content-credentials/bad-opts",
52
52
  "contentCredentials.build: opts required");
53
53
  }
54
54
  for (var i = 0; i < REQUIRED_FIELDS.length; i += 1) {
@@ -57,32 +57,32 @@ function _validateBuildOpts(opts) {
57
57
  "contentCredentials.build: " + f, ContentCredentialsError, "MISSING_" + f.toUpperCase());
58
58
  }
59
59
  if (opts.provider.length > STR_LEN_MAX) {
60
- throw ContentCredentialsError.factory("BAD_PROVIDER",
60
+ throw ContentCredentialsError.factory("content-credentials/bad-provider",
61
61
  "provider exceeds " + STR_LEN_MAX + " chars");
62
62
  }
63
63
  if (opts.system.length > ID_LEN_MAX || !ID_RE.test(opts.system)) {
64
- throw ContentCredentialsError.factory("BAD_SYSTEM",
64
+ throw ContentCredentialsError.factory("content-credentials/bad-system",
65
65
  "system must match " + ID_RE);
66
66
  }
67
67
  if (opts.systemVersion.length > 64 || !SEMVER_RE.test(opts.systemVersion)) { // allow:raw-byte-literal — semver length cap, not bytes
68
- throw ContentCredentialsError.factory("BAD_VERSION",
68
+ throw ContentCredentialsError.factory("content-credentials/bad-version",
69
69
  "systemVersion must be semver");
70
70
  }
71
71
  if (opts.contentId.length > ID_LEN_MAX || !ID_RE.test(opts.contentId)) {
72
- throw ContentCredentialsError.factory("BAD_CONTENT_ID",
72
+ throw ContentCredentialsError.factory("content-credentials/bad-content-id",
73
73
  "contentId must match " + ID_RE);
74
74
  }
75
75
  if (opts.contentType !== undefined) {
76
76
  if (typeof opts.contentType !== "string" || opts.contentType.length === 0 ||
77
77
  opts.contentType.length > ID_LEN_MAX || !/^[a-zA-Z]+\/[A-Za-z0-9._+-]+$/.test(opts.contentType)) {
78
- throw ContentCredentialsError.factory("BAD_CONTENT_TYPE",
78
+ throw ContentCredentialsError.factory("content-credentials/bad-content-type",
79
79
  "contentType must be a valid IANA media type");
80
80
  }
81
81
  }
82
82
  if (opts.contentSha3 !== undefined) {
83
83
  if (typeof opts.contentSha3 !== "string" || opts.contentSha3.length !== SHA3_HEX_LEN ||
84
84
  !/^[a-f0-9]+$/i.test(opts.contentSha3)) {
85
- throw ContentCredentialsError.factory("BAD_CONTENT_HASH",
85
+ throw ContentCredentialsError.factory("content-credentials/bad-content-hash",
86
86
  "contentSha3 must be lowercase hex SHA3-512 (" + SHA3_HEX_LEN + " chars)");
87
87
  }
88
88
  }
@@ -229,7 +229,7 @@ function required(opts) {
229
229
  function sign(manifest, opts) {
230
230
  opts = opts || {};
231
231
  if (!manifest || typeof manifest !== "object") {
232
- throw ContentCredentialsError.factory("BAD_MANIFEST",
232
+ throw ContentCredentialsError.factory("content-credentials/bad-manifest",
233
233
  "contentCredentials.sign: manifest required");
234
234
  }
235
235
  validateOpts.requireNonEmptyString(opts.privateKeyPem,
@@ -368,7 +368,7 @@ function _cborUint(n) {
368
368
  if (n < 256) return Buffer.from([0x18, n]); // allow:raw-byte-literal — CBOR threshold
369
369
  if (n < 65536) return Buffer.from([0x19, (n >> 8) & 0xFF, n & 0xFF]); // allow:raw-byte-literal — CBOR threshold
370
370
  if (n < 4294967296) return Buffer.from([0x1A, (n >> 24) & 0xFF, (n >> 16) & 0xFF, (n >> 8) & 0xFF, n & 0xFF]); // allow:raw-byte-literal — CBOR threshold
371
- throw ContentCredentialsError.factory("CBOR_OVERFLOW", "cbor uint too large: " + n);
371
+ throw ContentCredentialsError.factory("content-credentials/cbor-overflow", "cbor uint too large: " + n);
372
372
  }
373
373
 
374
374
  function _cborNint(n) {
@@ -397,13 +397,13 @@ function _cborArrayHeader(n) {
397
397
  if (n < 24) return Buffer.from([0x80 | n]); // allow:raw-byte-literal — CBOR threshold
398
398
  if (n < 256) return Buffer.from([0x98, n]); // allow:raw-byte-literal — CBOR threshold
399
399
  if (n < 65536) return Buffer.from([0x99, (n >> 8) & 0xFF, n & 0xFF]); // allow:raw-byte-literal — CBOR threshold
400
- throw ContentCredentialsError.factory("CBOR_OVERFLOW", "cbor array too large: " + n);
400
+ throw ContentCredentialsError.factory("content-credentials/cbor-overflow", "cbor array too large: " + n);
401
401
  }
402
402
 
403
403
  function _cborMapHeader(n) {
404
404
  if (n < 24) return Buffer.from([0xA0 | n]); // allow:raw-byte-literal — CBOR threshold
405
405
  if (n < 256) return Buffer.from([0xB8, n]); // allow:raw-byte-literal — CBOR threshold
406
- throw ContentCredentialsError.factory("CBOR_OVERFLOW", "cbor map too large: " + n);
406
+ throw ContentCredentialsError.factory("content-credentials/cbor-overflow", "cbor map too large: " + n);
407
407
  }
408
408
 
409
409
  function _cborTag(tag) {
@@ -454,14 +454,14 @@ function _cborTag(tag) {
454
454
  function signCose(manifest, opts) {
455
455
  opts = opts || {};
456
456
  if (!manifest || typeof manifest !== "object") {
457
- throw ContentCredentialsError.factory("BAD_MANIFEST",
457
+ throw ContentCredentialsError.factory("content-credentials/bad-manifest",
458
458
  "contentCredentials.signCose: manifest required");
459
459
  }
460
460
  validateOpts.requireNonEmptyString(opts.privateKeyPem,
461
461
  "contentCredentials.signCose: privateKeyPem", ContentCredentialsError, "BAD_KEY");
462
462
  var algName = (opts.alg || "ml-dsa-87").toLowerCase();
463
463
  if (!(algName in COSE_ALGS)) {
464
- throw ContentCredentialsError.factory("BAD_ALG",
464
+ throw ContentCredentialsError.factory("content-credentials/bad-alg",
465
465
  "contentCredentials.signCose: alg '" + algName +
466
466
  "' not in COSE alg registry. Known: " + Object.keys(COSE_ALGS).join(", "));
467
467
  }
@@ -64,47 +64,47 @@ var POSTURES = {
64
64
 
65
65
  function _validateFlowOpts(opts, label, errorClass) {
66
66
  if (!opts || typeof opts !== "object") {
67
- throw errorClass.factory("BAD_OPTS",
67
+ throw errorClass.factory("dark-patterns/bad-opts",
68
68
  "darkPatterns.record" + label + ": opts required");
69
69
  }
70
70
  if (CHANNELS.indexOf(opts.channel) === -1) {
71
- throw errorClass.factory("BAD_CHANNEL",
71
+ throw errorClass.factory("dark-patterns/bad-channel",
72
72
  "darkPatterns: channel must be one of " + CHANNELS.join(","));
73
73
  }
74
74
  if (typeof opts.clickCount !== "number" || !isFinite(opts.clickCount) ||
75
75
  opts.clickCount < 1 || opts.clickCount > 50 ||
76
76
  Math.floor(opts.clickCount) !== opts.clickCount) {
77
- throw errorClass.factory("BAD_CLICKS",
77
+ throw errorClass.factory("dark-patterns/bad-clicks",
78
78
  "darkPatterns: clickCount must be integer 1..50");
79
79
  }
80
80
  if (!opts.cta || typeof opts.cta !== "object") {
81
- throw errorClass.factory("BAD_CTA",
81
+ throw errorClass.factory("dark-patterns/bad-cta",
82
82
  "darkPatterns: cta object required (text, fontWeight, contrastRatio)");
83
83
  }
84
84
  if (typeof opts.cta.text !== "string" || opts.cta.text.length === 0 ||
85
85
  opts.cta.text.length > STR_LEN_MAX) {
86
- throw errorClass.factory("BAD_CTA_TEXT",
86
+ throw errorClass.factory("dark-patterns/bad-cta-text",
87
87
  "darkPatterns: cta.text must be 1-256 char string");
88
88
  }
89
89
  if (typeof opts.cta.fontWeight !== "number" || opts.cta.fontWeight < 100 ||
90
90
  opts.cta.fontWeight > FONT_WEIGHT_MAX) {
91
- throw errorClass.factory("BAD_FONT_WEIGHT",
91
+ throw errorClass.factory("dark-patterns/bad-font-weight",
92
92
  "darkPatterns: cta.fontWeight must be 100..1000");
93
93
  }
94
94
  if (typeof opts.cta.contrastRatio !== "number" ||
95
95
  opts.cta.contrastRatio < 1 || opts.cta.contrastRatio > 21) {
96
- throw errorClass.factory("BAD_CONTRAST",
96
+ throw errorClass.factory("dark-patterns/bad-contrast",
97
97
  "darkPatterns: cta.contrastRatio must be 1..21");
98
98
  }
99
99
  if (typeof opts.confirmations !== "number" ||
100
100
  opts.confirmations < 0 || opts.confirmations > 10 ||
101
101
  Math.floor(opts.confirmations) !== opts.confirmations) {
102
- throw errorClass.factory("BAD_CONFIRMATIONS",
102
+ throw errorClass.factory("dark-patterns/bad-confirmations",
103
103
  "darkPatterns: confirmations must be integer 0..10");
104
104
  }
105
105
  if (typeof opts.resourceId !== "string" || opts.resourceId.length === 0 ||
106
106
  opts.resourceId.length > STR_LEN_MAX) {
107
- throw errorClass.factory("BAD_RESOURCE_ID",
107
+ throw errorClass.factory("dark-patterns/bad-resource-id",
108
108
  "darkPatterns: resourceId must be 1-256 char string");
109
109
  }
110
110
  }
@@ -252,21 +252,21 @@ function assertParity(signup, cancel, opts) {
252
252
  opts = opts || {};
253
253
  var errorClass = opts.errorClass || DarkPatternsError;
254
254
  if (!signup || signup.kind !== "signup") {
255
- throw errorClass.factory("BAD_SIGNUP_FLOW",
255
+ throw errorClass.factory("dark-patterns/bad-signup-flow",
256
256
  "darkPatterns.assertParity: signup must be a recorded signup flow");
257
257
  }
258
258
  if (!cancel || cancel.kind !== "cancel") {
259
- throw errorClass.factory("BAD_CANCEL_FLOW",
259
+ throw errorClass.factory("dark-patterns/bad-cancel-flow",
260
260
  "darkPatterns.assertParity: cancel must be a recorded cancel flow");
261
261
  }
262
262
  if (signup.resourceId !== cancel.resourceId) {
263
- throw errorClass.factory("RESOURCE_MISMATCH",
263
+ throw errorClass.factory("dark-patterns/resource-mismatch",
264
264
  "darkPatterns.assertParity: resourceId differs between flows");
265
265
  }
266
266
  var postureName = opts.posture || "ftc-2024";
267
267
  var posture = POSTURES[postureName];
268
268
  if (!posture) {
269
- throw errorClass.factory("BAD_POSTURE",
269
+ throw errorClass.factory("dark-patterns/bad-posture",
270
270
  "darkPatterns.assertParity: unknown posture " + postureName);
271
271
  }
272
272
 
@@ -427,11 +427,11 @@ function middleware(opts) {
427
427
  opts = opts || {};
428
428
  var errorClass = opts.errorClass || DarkPatternsError;
429
429
  if (typeof opts.lookupAttestation !== "function") {
430
- throw errorClass.factory("BAD_OPTS",
430
+ throw errorClass.factory("dark-patterns/bad-opts",
431
431
  "darkPatterns.middleware: lookupAttestation function required");
432
432
  }
433
433
  if (typeof opts.resourceIdFromReq !== "function") {
434
- throw errorClass.factory("BAD_OPTS",
434
+ throw errorClass.factory("dark-patterns/bad-opts",
435
435
  "darkPatterns.middleware: resourceIdFromReq function required");
436
436
  }
437
437