@blamejs/core 0.13.43 → 0.13.44

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
 
@@ -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
 
@@ -59,7 +59,7 @@ var DAY_NAMES = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
59
59
 
60
60
  function _parseWindowSpec(spec) {
61
61
  if (typeof spec !== "string" || spec.length === 0) {
62
- throw new DdlChangeControlError("ddlChangeControl/bad-window",
62
+ throw new DdlChangeControlError("ddl-change-control/bad-window",
63
63
  "windowSpec must be a non-empty string");
64
64
  }
65
65
  var trimmed = spec.trim();
@@ -68,11 +68,11 @@ function _parseWindowSpec(spec) {
68
68
  }
69
69
  var parts = trimmed.split(/\s+/);
70
70
  if (parts.length !== 3) {
71
- throw new DdlChangeControlError("ddlChangeControl/bad-window",
71
+ throw new DdlChangeControlError("ddl-change-control/bad-window",
72
72
  "windowSpec must be 'always' or '<days> <HH:MM-HH:MM> UTC' - got " + JSON.stringify(spec));
73
73
  }
74
74
  if (parts[2].toUpperCase() !== "UTC") {
75
- throw new DdlChangeControlError("ddlChangeControl/bad-window",
75
+ throw new DdlChangeControlError("ddl-change-control/bad-window",
76
76
  "windowSpec timezone must be UTC - got " + parts[2]);
77
77
  }
78
78
  var days = new Set();
@@ -82,13 +82,13 @@ function _parseWindowSpec(spec) {
82
82
  if (dp.indexOf("-") !== -1) {
83
83
  var range = dp.split("-");
84
84
  if (range.length !== 2) {
85
- throw new DdlChangeControlError("ddlChangeControl/bad-window",
85
+ throw new DdlChangeControlError("ddl-change-control/bad-window",
86
86
  "windowSpec day-range must be 'A-B' - got " + dp);
87
87
  }
88
88
  var lo = DAY_NAMES.indexOf(range[0]);
89
89
  var hi = DAY_NAMES.indexOf(range[1]);
90
90
  if (lo === -1 || hi === -1) {
91
- throw new DdlChangeControlError("ddlChangeControl/bad-window",
91
+ throw new DdlChangeControlError("ddl-change-control/bad-window",
92
92
  "windowSpec unknown day in range " + dp);
93
93
  }
94
94
  if (lo <= hi) {
@@ -100,7 +100,7 @@ function _parseWindowSpec(spec) {
100
100
  } else {
101
101
  var idx = DAY_NAMES.indexOf(dp);
102
102
  if (idx === -1) {
103
- throw new DdlChangeControlError("ddlChangeControl/bad-window",
103
+ throw new DdlChangeControlError("ddl-change-control/bad-window",
104
104
  "windowSpec unknown day '" + dp + "'");
105
105
  }
106
106
  days.add(idx);
@@ -108,13 +108,13 @@ function _parseWindowSpec(spec) {
108
108
  }
109
109
  var hourParts = parts[1].split("-");
110
110
  if (hourParts.length !== 2) {
111
- throw new DdlChangeControlError("ddlChangeControl/bad-window",
111
+ throw new DdlChangeControlError("ddl-change-control/bad-window",
112
112
  "windowSpec hour-range must be 'HH:MM-HH:MM' - got " + parts[1]);
113
113
  }
114
114
  var startMin = _parseHHMM(hourParts[0]);
115
115
  var endMin = _parseHHMM(hourParts[1]);
116
116
  if (startMin >= endMin) {
117
- throw new DdlChangeControlError("ddlChangeControl/bad-window",
117
+ throw new DdlChangeControlError("ddl-change-control/bad-window",
118
118
  "windowSpec start must be < end - got " + parts[1]);
119
119
  }
120
120
  return { always: false, days: days, startMin: startMin, endMin: endMin };
@@ -123,13 +123,13 @@ function _parseWindowSpec(spec) {
123
123
  function _parseHHMM(s) {
124
124
  var m = /^(\d{2}):(\d{2})$/.exec(s);
125
125
  if (!m) {
126
- throw new DdlChangeControlError("ddlChangeControl/bad-window",
126
+ throw new DdlChangeControlError("ddl-change-control/bad-window",
127
127
  "windowSpec time must be HH:MM - got " + s);
128
128
  }
129
129
  var hh = parseInt(m[1], 10);
130
130
  var mm = parseInt(m[2], 10);
131
131
  if (hh < 0 || hh > 23 || mm < 0 || mm > 59) {
132
- throw new DdlChangeControlError("ddlChangeControl/bad-window",
132
+ throw new DdlChangeControlError("ddl-change-control/bad-window",
133
133
  "windowSpec time out of range - got " + s);
134
134
  }
135
135
  return hh * 60 + mm; // allow:raw-time-literal — converting HH:MM to minute-of-day, not "60 seconds"
@@ -212,28 +212,28 @@ function create(opts) {
212
212
  "verifyWith", "store", "now", "selfApproval",
213
213
  ], "ddlChangeControl.create");
214
214
  validateOpts.auditShape(opts.audit, "ddlChangeControl",
215
- DdlChangeControlError, "ddlChangeControl/bad-audit");
215
+ DdlChangeControlError, "ddl-change-control/bad-audit");
216
216
  validateOpts.optionalFunction(opts.signWith,
217
- "ddlChangeControl: signWith", DdlChangeControlError, "ddlChangeControl/bad-signer");
217
+ "ddlChangeControl: signWith", DdlChangeControlError, "ddl-change-control/bad-signer");
218
218
  validateOpts.optionalFunction(opts.verifyWith,
219
- "ddlChangeControl: verifyWith", DdlChangeControlError, "ddlChangeControl/bad-verifier");
219
+ "ddlChangeControl: verifyWith", DdlChangeControlError, "ddl-change-control/bad-verifier");
220
220
  validateOpts.optionalFunction(opts.now,
221
- "ddlChangeControl: now", DdlChangeControlError, "ddlChangeControl/bad-now");
221
+ "ddlChangeControl: now", DdlChangeControlError, "ddl-change-control/bad-now");
222
222
  validateOpts.optionalNonEmptyString(opts.posture,
223
- "ddlChangeControl: posture", DdlChangeControlError, "ddlChangeControl/bad-posture");
223
+ "ddlChangeControl: posture", DdlChangeControlError, "ddl-change-control/bad-posture");
224
224
 
225
225
  var approvers = 2;
226
226
  if (opts.approvers !== undefined) {
227
227
  if (typeof opts.approvers !== "number" || !isFinite(opts.approvers) ||
228
228
  opts.approvers < 1) {
229
- throw new DdlChangeControlError("ddlChangeControl/bad-approvers",
229
+ throw new DdlChangeControlError("ddl-change-control/bad-approvers",
230
230
  "approvers must be a positive integer");
231
231
  }
232
232
  approvers = Math.floor(opts.approvers);
233
233
  }
234
234
  var posture = opts.posture || null;
235
235
  if (posture && POSTURES_REQUIRING_CHANGE_CONTROL.indexOf(posture) !== -1 && approvers < 2) {
236
- throw new DdlChangeControlError("ddlChangeControl/insufficient-approvers",
236
+ throw new DdlChangeControlError("ddl-change-control/insufficient-approvers",
237
237
  "posture '" + posture + "' requires approvers >= 2 (SOX 404 / PCI-DSS 6.5)");
238
238
  }
239
239
 
@@ -267,11 +267,11 @@ function create(opts) {
267
267
  async function propose(sql, options) {
268
268
  options = options || {};
269
269
  if (typeof sql !== "string" || sql.length === 0) {
270
- throw new DdlChangeControlError("ddlChangeControl/bad-sql",
270
+ throw new DdlChangeControlError("ddl-change-control/bad-sql",
271
271
  "propose: sql must be a non-empty string");
272
272
  }
273
273
  if (typeof options.proposer !== "string" || options.proposer.length === 0) {
274
- throw new DdlChangeControlError("ddlChangeControl/missing-proposer",
274
+ throw new DdlChangeControlError("ddl-change-control/missing-proposer",
275
275
  "propose: opts.proposer is required (non-empty string)");
276
276
  }
277
277
  var changeId = generateToken(C.BYTES.bytes(16));
@@ -311,37 +311,37 @@ function create(opts) {
311
311
  async function approve(changeId, approver, options) {
312
312
  options = options || {};
313
313
  if (typeof changeId !== "string" || changeId.length === 0) {
314
- throw new DdlChangeControlError("ddlChangeControl/bad-id",
314
+ throw new DdlChangeControlError("ddl-change-control/bad-id",
315
315
  "approve: changeId must be a non-empty string");
316
316
  }
317
317
  if (typeof approver !== "string" || approver.length === 0) {
318
- throw new DdlChangeControlError("ddlChangeControl/missing-approver",
318
+ throw new DdlChangeControlError("ddl-change-control/missing-approver",
319
319
  "approve: approver must be a non-empty string");
320
320
  }
321
321
  var change = store.get(changeId);
322
322
  if (!change) {
323
- throw new DdlChangeControlError("ddlChangeControl/unknown-change",
323
+ throw new DdlChangeControlError("ddl-change-control/unknown-change",
324
324
  "approve: unknown changeId '" + changeId + "'");
325
325
  }
326
326
  if (change.state === STATE_REJECTED) {
327
- throw new DdlChangeControlError("ddlChangeControl/already-rejected",
327
+ throw new DdlChangeControlError("ddl-change-control/already-rejected",
328
328
  "approve: change '" + changeId + "' is already rejected");
329
329
  }
330
330
  if (change.state === STATE_APPLIED) {
331
- throw new DdlChangeControlError("ddlChangeControl/already-applied",
331
+ throw new DdlChangeControlError("ddl-change-control/already-applied",
332
332
  "approve: change '" + changeId + "' is already applied");
333
333
  }
334
334
  if (!selfApprovalAllowed && approver === change.proposer) {
335
335
  _emit("ddl.change.apply_refused", {
336
336
  changeId: changeId, reason: "self-approval-denied", actor: approver,
337
337
  }, "denied");
338
- throw new DdlChangeControlError("ddlChangeControl/self-approval-denied",
338
+ throw new DdlChangeControlError("ddl-change-control/self-approval-denied",
339
339
  "approve: proposer '" + approver + "' cannot approve their own change under posture '" +
340
340
  (posture || "default") + "'");
341
341
  }
342
342
  for (var i = 0; i < change.approvals.length; i++) {
343
343
  if (change.approvals[i].approver === approver) {
344
- throw new DdlChangeControlError("ddlChangeControl/duplicate-approval",
344
+ throw new DdlChangeControlError("ddl-change-control/duplicate-approval",
345
345
  "approve: '" + approver + "' has already approved this change");
346
346
  }
347
347
  }
@@ -373,20 +373,20 @@ function create(opts) {
373
373
 
374
374
  async function reject(changeId, reviewer, reason) {
375
375
  if (typeof changeId !== "string" || changeId.length === 0) {
376
- throw new DdlChangeControlError("ddlChangeControl/bad-id",
376
+ throw new DdlChangeControlError("ddl-change-control/bad-id",
377
377
  "reject: changeId must be a non-empty string");
378
378
  }
379
379
  if (typeof reviewer !== "string" || reviewer.length === 0) {
380
- throw new DdlChangeControlError("ddlChangeControl/missing-reviewer",
380
+ throw new DdlChangeControlError("ddl-change-control/missing-reviewer",
381
381
  "reject: reviewer must be a non-empty string");
382
382
  }
383
383
  var change = store.get(changeId);
384
384
  if (!change) {
385
- throw new DdlChangeControlError("ddlChangeControl/unknown-change",
385
+ throw new DdlChangeControlError("ddl-change-control/unknown-change",
386
386
  "reject: unknown changeId '" + changeId + "'");
387
387
  }
388
388
  if (change.state === STATE_APPLIED) {
389
- throw new DdlChangeControlError("ddlChangeControl/already-applied",
389
+ throw new DdlChangeControlError("ddl-change-control/already-applied",
390
390
  "reject: change '" + changeId + "' is already applied");
391
391
  }
392
392
  change.state = STATE_REJECTED;
@@ -422,20 +422,20 @@ function create(opts) {
422
422
 
423
423
  async function applyApproved(changeId, runner) {
424
424
  if (typeof runner !== "function") {
425
- throw new DdlChangeControlError("ddlChangeControl/bad-runner",
425
+ throw new DdlChangeControlError("ddl-change-control/bad-runner",
426
426
  "applyApproved: runner must be an async function (sql) => result");
427
427
  }
428
428
  var change = store.get(changeId);
429
429
  if (!change) {
430
- throw new DdlChangeControlError("ddlChangeControl/unknown-change",
430
+ throw new DdlChangeControlError("ddl-change-control/unknown-change",
431
431
  "applyApproved: unknown changeId '" + changeId + "'");
432
432
  }
433
433
  if (change.state === STATE_APPLIED) {
434
- throw new DdlChangeControlError("ddlChangeControl/already-applied",
434
+ throw new DdlChangeControlError("ddl-change-control/already-applied",
435
435
  "applyApproved: change '" + changeId + "' is already applied");
436
436
  }
437
437
  if (change.state === STATE_REJECTED) {
438
- throw new DdlChangeControlError("ddlChangeControl/already-rejected",
438
+ throw new DdlChangeControlError("ddl-change-control/already-rejected",
439
439
  "applyApproved: change '" + changeId + "' is rejected");
440
440
  }
441
441
  if (change.approvals.length < approvers) {
@@ -443,7 +443,7 @@ function create(opts) {
443
443
  changeId: changeId,
444
444
  reason: "insufficient-approvals: " + change.approvals.length + "/" + approvers,
445
445
  }, "denied");
446
- throw new DdlChangeControlError("ddlChangeControl/insufficient-approvals",
446
+ throw new DdlChangeControlError("ddl-change-control/insufficient-approvals",
447
447
  "applyApproved: change '" + changeId + "' has " + change.approvals.length +
448
448
  " approvals; threshold is " + approvers);
449
449
  }
@@ -451,7 +451,7 @@ function create(opts) {
451
451
  _emit("ddl.change.apply_refused", {
452
452
  changeId: changeId, reason: "window-closed",
453
453
  }, "denied");
454
- throw new DdlChangeControlError("ddlChangeControl/window-closed",
454
+ throw new DdlChangeControlError("ddl-change-control/window-closed",
455
455
  "applyApproved: change '" + changeId + "' refused - outside allowed window");
456
456
  }
457
457
  var currentHash = _hashSql(change.sql);
@@ -459,7 +459,7 @@ function create(opts) {
459
459
  _emit("ddl.change.apply_refused", {
460
460
  changeId: changeId, reason: "sql-tampered",
461
461
  }, "denied");
462
- throw new DdlChangeControlError("ddlChangeControl/sql-tampered",
462
+ throw new DdlChangeControlError("ddl-change-control/sql-tampered",
463
463
  "applyApproved: stored SQL no longer matches its hash - refusing to apply");
464
464
  }
465
465
  var startedAt = now();
package/lib/dr-runbook.js CHANGED
@@ -232,7 +232,7 @@ function _renderTest(posture) {
232
232
  * placeholder otherwise so the runbook never silently drops a
233
233
  * required section.
234
234
  *
235
- * Throws `DrRunbookError("drRunbook/unknown-posture")` when `posture`
235
+ * Throws `DrRunbookError("dr-runbook/unknown-posture")` when `posture`
236
236
  * is not in the supported list.
237
237
  *
238
238
  * @opts
@@ -272,22 +272,22 @@ async function emit(opts) {
272
272
  ], "drRunbook.emit");
273
273
 
274
274
  validateOpts.requireNonEmptyString(opts.outDir,
275
- "drRunbook.emit: outDir", DrRunbookError, "drRunbook/no-outdir");
275
+ "drRunbook.emit: outDir", DrRunbookError, "dr-runbook/no-outdir");
276
276
  validateOpts.requireNonEmptyString(opts.posture,
277
- "drRunbook.emit: posture", DrRunbookError, "drRunbook/no-posture");
277
+ "drRunbook.emit: posture", DrRunbookError, "dr-runbook/no-posture");
278
278
  if (!POSTURE_BLOCKS[opts.posture]) {
279
- throw new DrRunbookError("drRunbook/unknown-posture",
279
+ throw new DrRunbookError("dr-runbook/unknown-posture",
280
280
  "drRunbook.emit: posture '" + opts.posture + "' not in supported list (" +
281
281
  Object.keys(POSTURE_BLOCKS).join(", ") + ")");
282
282
  }
283
283
  if (opts.services !== undefined && !Array.isArray(opts.services)) {
284
- throw new DrRunbookError("drRunbook/bad-services",
284
+ throw new DrRunbookError("dr-runbook/bad-services",
285
285
  "drRunbook.emit: services must be an array of {name, rtoMs, rpoMs}");
286
286
  }
287
287
  validateOpts.optionalPositiveFinite(opts.rtoMs,
288
- "drRunbook.emit: rtoMs", DrRunbookError, "drRunbook/bad-rto");
288
+ "drRunbook.emit: rtoMs", DrRunbookError, "dr-runbook/bad-rto");
289
289
  validateOpts.optionalPositiveFinite(opts.rpoMs,
290
- "drRunbook.emit: rpoMs", DrRunbookError, "drRunbook/bad-rpo");
290
+ "drRunbook.emit: rpoMs", DrRunbookError, "dr-runbook/bad-rpo");
291
291
 
292
292
  var auditOn = opts.audit !== false;
293
293
  var postureBlock = POSTURE_BLOCKS[opts.posture];
package/lib/fapi2.js CHANGED
@@ -135,17 +135,17 @@ var SENDER_CONSTRAINTS = ["dpop", "mtls"];
135
135
  */
136
136
  function assertConformance(opts) {
137
137
  if (!opts || typeof opts !== "object") {
138
- throw Fapi2Error.factory("BAD_OPTS",
138
+ throw Fapi2Error.factory("fapi2/bad-opts",
139
139
  "fapi2.assertConformance: opts required");
140
140
  }
141
141
  if (SENDER_CONSTRAINTS.indexOf(opts.senderConstraint) === -1) {
142
- throw Fapi2Error.factory("BAD_SENDER_CONSTRAINT",
142
+ throw Fapi2Error.factory("fapi2/bad-sender-constraint",
143
143
  "fapi2.assertConformance: senderConstraint must be 'dpop' or 'mtls'");
144
144
  }
145
145
  var parRequired = opts.parRequired !== false;
146
146
  var pkceMethod = opts.pkceMethod || "S256";
147
147
  if (pkceMethod !== "S256") {
148
- throw Fapi2Error.factory("BAD_PKCE",
148
+ throw Fapi2Error.factory("fapi2/bad-pkce",
149
149
  "fapi2.assertConformance: PKCE method must be S256 (FAPI 2.0 §5.3.1.1) — got '" +
150
150
  pkceMethod + "'");
151
151
  }
@@ -224,17 +224,17 @@ function assertConformance(opts) {
224
224
  */
225
225
  function assertOAuthConfig(oauthOpts) {
226
226
  if (!oauthOpts || typeof oauthOpts !== "object") {
227
- throw Fapi2Error.factory("BAD_OAUTH_OPTS",
227
+ throw Fapi2Error.factory("fapi2/bad-oauth-opts",
228
228
  "fapi2.assertOAuthConfig: oauth opts required");
229
229
  }
230
230
  // PKCE — refuse pkce: false (b.auth.oauth.create already does this,
231
231
  // but check explicitly for FAPI clarity).
232
232
  if (oauthOpts.pkce === false) {
233
- throw Fapi2Error.factory("PKCE_DISABLED",
233
+ throw Fapi2Error.factory("fapi2/pkce-disabled",
234
234
  "fapi2.assertOAuthConfig: PKCE is disabled — FAPI 2.0 §5.3.1.1 mandates S256");
235
235
  }
236
236
  if (oauthOpts.pkceMethod && oauthOpts.pkceMethod !== "S256") {
237
- throw Fapi2Error.factory("PKCE_NOT_S256",
237
+ throw Fapi2Error.factory("fapi2/pkce-not-s256",
238
238
  "fapi2.assertOAuthConfig: PKCE method '" + oauthOpts.pkceMethod +
239
239
  "' is not S256 (FAPI 2.0 §5.3.1.1)");
240
240
  }
@@ -242,16 +242,16 @@ function assertOAuthConfig(oauthOpts) {
242
242
  var hasDpop = oauthOpts.dpop === true || oauthOpts.senderConstraint === "dpop";
243
243
  var hasMtls = oauthOpts.mtls === true || oauthOpts.senderConstraint === "mtls";
244
244
  if (!hasDpop && !hasMtls) {
245
- throw Fapi2Error.factory("NO_SENDER_CONSTRAINT",
245
+ throw Fapi2Error.factory("fapi2/no-sender-constraint",
246
246
  "fapi2.assertOAuthConfig: FAPI 2.0 §5.3.2.5 requires sender-constrained tokens via DPoP OR mTLS — neither declared");
247
247
  }
248
248
  if (hasDpop && hasMtls) {
249
- throw Fapi2Error.factory("BOTH_SENDER_CONSTRAINTS",
249
+ throw Fapi2Error.factory("fapi2/both-sender-constraints",
250
250
  "fapi2.assertOAuthConfig: declare exactly one of DPoP / mTLS — both creates over-binding ambiguity");
251
251
  }
252
252
  // PAR
253
253
  if (oauthOpts.par === false) {
254
- throw Fapi2Error.factory("PAR_DISABLED",
254
+ throw Fapi2Error.factory("fapi2/par-disabled",
255
255
  "fapi2.assertOAuthConfig: PAR is disabled — FAPI 2.0 §5.3.2.2 mandates Pushed Authorization Requests");
256
256
  }
257
257
  }