@blamejs/core 0.6.12 → 0.6.13
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/CHANGELOG.md +1 -0
- package/lib/api-key.js +2 -3
- package/lib/cache.js +3 -7
- package/lib/notify.js +2 -3
- package/lib/numeric-checks.js +40 -0
- package/lib/queue.js +5 -5
- package/lib/restore.js +5 -3
- package/lib/retry.js +3 -6
- package/lib/slug.js +2 -3
- package/lib/testing.js +3 -7
- package/lib/webhook.js +3 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,7 @@ upgrading across more than a few patches at a time.
|
|
|
8
8
|
|
|
9
9
|
## v0.6.x
|
|
10
10
|
|
|
11
|
+
- **0.6.13** (2026-05-02) — wiki primitive-section docs catch up to the v0.6.12 surface (`safeUrl.parse` allowUserinfo, `session.touch` extendBy ceiling, `queue.consume` rateLimit validation, `mail.transports.console` redactBcc, `logStream` webhook-sink onDrop, `backup.create` requireFlush, `restore.create` maxPulledBytes / maxPulledFiles); restore default cap stated as `C.BYTES.gib(4)` instead of a raw byte literal; numeric-check predicates (`isPositiveInt`, `isFiniteNonNegative`, `isPositiveFinite`) consolidated into `lib/numeric-checks.js` — were duplicated across api-key, cache, notify, queue, restore, retry, slug, testing, webhook; api-snapshot.json refreshed
|
|
11
12
|
- **0.6.12** (2026-05-02) — `b.safeUrl.parse` now rejects URLs with `user:pass@` userinfo by default (opt in per-call via `allowUserinfo: true`); `b.session.touch({ extendBy })` enforces the same `MAX_TTL_MS` ceiling as `create` / `rotate`; `b.queue.consume({ rateLimit })` rejects negative / zero / `NaN` / `Infinity` / fractional `max`; `b.middleware.requireAuth` no longer treats request `Content-Type: application/json` as a JSON-preference signal (only `Accept` and `X-Requested-With` count); `b.backup.create({ requireFlush: true })` opt-in fails the backup if pre-flush fails instead of producing a stale snapshot; `b.restore.create({ maxPulledBytes, maxPulledFiles })` preflight bounds bundle footprint before and after pull (defaults 4 GiB / 100K files); `b.mail.transports.console({ redactBcc: true })` opt-in prints recipient count instead of addresses; `b.logStream.transports.webhook({ onDrop })` callback fires on overflow + retry-exhausted batch drops. Wiki: admin login wired through `b.auth.lockout` (exponential-backoff after bad-cred attempts) and cookie `Secure` flag now routes through `b.requestHelpers.requestProtocol` with `WIKI_TRUST_PROXY` opt-in instead of trusting raw `x-forwarded-proto`. Wiki README documents the trust model for editable page bodies and the sanitization pattern operators should adopt before expanding the editor surface.
|
|
12
13
|
- **0.6.11** (2026-05-01) — wiki example-execution validator: fixture init no longer reaches across module realms (unblocks the npm-publish workflow's wiki-e2e gate, which `npm install --install-links` copies the framework into the wiki's node_modules — two distinct singletons before this fix)
|
|
13
14
|
- **0.6.10** (2026-05-01) — README / SECURITY / CONTRIBUTING / wiki: removed stale version stamps and an inaccurate vendored-dep list; SECURITY now points at `lib/vendor/MANIFEST.json` for the authoritative vendor list; supported-versions table no longer pins to a specific minor; wiki archive example names the digest variable correctly (was `sha256`, output is SHA3-512 hex)
|
package/lib/api-key.js
CHANGED
|
@@ -63,6 +63,7 @@ var cryptoField = require("./crypto-field");
|
|
|
63
63
|
var requestHelpers = require("./request-helpers");
|
|
64
64
|
var validateOpts = require("./validate-opts");
|
|
65
65
|
var C = require("./constants");
|
|
66
|
+
var numericChecks = require("./numeric-checks");
|
|
66
67
|
var { ApiKeyError } = require("./framework-error");
|
|
67
68
|
|
|
68
69
|
var observability = lazyRequire(function () { return require("./observability"); });
|
|
@@ -129,9 +130,7 @@ var DEFAULTS = Object.freeze({
|
|
|
129
130
|
|
|
130
131
|
// ---- Config-time validation helpers (throw on bad input) ----
|
|
131
132
|
|
|
132
|
-
|
|
133
|
-
return typeof n === "number" && isFinite(n) && n >= 1 && Math.floor(n) === n;
|
|
134
|
-
}
|
|
133
|
+
var _isPositiveInt = numericChecks.isPositiveInt;
|
|
135
134
|
|
|
136
135
|
function _validateIdentifier(name, value) {
|
|
137
136
|
if (typeof value !== "string" || value.length === 0) {
|
package/lib/cache.js
CHANGED
|
@@ -93,6 +93,7 @@
|
|
|
93
93
|
var clusterStorage = require("./cluster-storage");
|
|
94
94
|
var C = require("./constants");
|
|
95
95
|
var lazyRequire = require("./lazy-require");
|
|
96
|
+
var numericChecks = require("./numeric-checks");
|
|
96
97
|
var requestHelpers = require("./request-helpers");
|
|
97
98
|
var safeAsync = require("./safe-async");
|
|
98
99
|
var validateOpts = require("./validate-opts");
|
|
@@ -116,13 +117,8 @@ var DEFAULTS = Object.freeze({
|
|
|
116
117
|
|
|
117
118
|
// ---- Config-time validation helpers (throw on bad input) ----
|
|
118
119
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function _isPositiveInt(n) {
|
|
124
|
-
return typeof n === "number" && isFinite(n) && n >= 1 && Math.floor(n) === n;
|
|
125
|
-
}
|
|
120
|
+
var _isFiniteNonNegative = numericChecks.isFiniteNonNegative;
|
|
121
|
+
var _isPositiveInt = numericChecks.isPositiveInt;
|
|
126
122
|
|
|
127
123
|
// ttlMs accepts: any non-negative finite number OR Infinity. NaN, negative,
|
|
128
124
|
// or non-number is rejected.
|
package/lib/notify.js
CHANGED
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
|
|
50
50
|
var lazyRequire = require("./lazy-require");
|
|
51
51
|
var bootLog = require("./log");
|
|
52
|
+
var numericChecks = require("./numeric-checks");
|
|
52
53
|
var requestHelpers = require("./request-helpers");
|
|
53
54
|
var safeAsync = require("./safe-async");
|
|
54
55
|
var safeUrl = require("./safe-url");
|
|
@@ -76,9 +77,7 @@ var DEFAULTS = Object.freeze({
|
|
|
76
77
|
|
|
77
78
|
// ---- Call-site validation (throw on bad input) ----
|
|
78
79
|
|
|
79
|
-
|
|
80
|
-
return typeof n === "number" && isFinite(n) && n >= 0;
|
|
81
|
-
}
|
|
80
|
+
var _isFiniteNonNegative = numericChecks.isFiniteNonNegative;
|
|
82
81
|
|
|
83
82
|
function _validateTransport(name, t) {
|
|
84
83
|
if (!t || typeof t !== "object") {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* numeric-checks — predicate helpers for opts / arg validation.
|
|
4
|
+
*
|
|
5
|
+
* Existed previously as private `_isPositiveInt` / `_isFiniteNonNegative`
|
|
6
|
+
* / `_isNonNegFinite` copies inside api-key, cache, notify, retry, slug,
|
|
7
|
+
* testing, webhook, and (new in v0.6.12) inline checks in queue and
|
|
8
|
+
* restore. Same shape, different file — that's the repeat-means-primitive
|
|
9
|
+
* rule. Everything routes through here now so adding (e.g.) NaN-or-
|
|
10
|
+
* Infinity-string handling is a one-file change.
|
|
11
|
+
*
|
|
12
|
+
* Predicates only — callers throw with their own framework-error class.
|
|
13
|
+
*
|
|
14
|
+
* isPositiveInt(n) n is a finite integer >= 1
|
|
15
|
+
* isFiniteNonNegative(n) n is a finite number >= 0
|
|
16
|
+
* isPositiveFinite(n) n is a finite number > 0
|
|
17
|
+
*
|
|
18
|
+
* All return false for non-numbers, NaN, Infinity, -Infinity, null,
|
|
19
|
+
* undefined, strings, etc. — operators get one consistent gate against
|
|
20
|
+
* the silent-NaN-cap class of bug regardless of which primitive they're
|
|
21
|
+
* configuring.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
function isPositiveInt(n) {
|
|
25
|
+
return typeof n === "number" && isFinite(n) && n >= 1 && Math.floor(n) === n;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function isFiniteNonNegative(n) {
|
|
29
|
+
return typeof n === "number" && isFinite(n) && n >= 0;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function isPositiveFinite(n) {
|
|
33
|
+
return typeof n === "number" && isFinite(n) && n > 0;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = {
|
|
37
|
+
isPositiveInt: isPositiveInt,
|
|
38
|
+
isFiniteNonNegative: isFiniteNonNegative,
|
|
39
|
+
isPositiveFinite: isPositiveFinite,
|
|
40
|
+
};
|
package/lib/queue.js
CHANGED
|
@@ -34,6 +34,7 @@ var C = require("./constants");
|
|
|
34
34
|
var clusterStorage = require("./cluster-storage");
|
|
35
35
|
var crypto = require("./crypto");
|
|
36
36
|
var lazyRequire = require("./lazy-require");
|
|
37
|
+
var numericChecks = require("./numeric-checks");
|
|
37
38
|
var observability = require("./observability");
|
|
38
39
|
var protocolDispatcher = require("./protocol-dispatcher");
|
|
39
40
|
var localProto = require("./queue-local");
|
|
@@ -190,11 +191,10 @@ function consume(queueName, handler, opts) {
|
|
|
190
191
|
if (opts.rateLimit) {
|
|
191
192
|
var rlMax = opts.rateLimit.max;
|
|
192
193
|
var rlPer = opts.rateLimit.perSeconds;
|
|
193
|
-
//
|
|
194
|
-
//
|
|
195
|
-
// perma-
|
|
196
|
-
if (
|
|
197
|
-
typeof rlPer !== "number" || !isFinite(rlPer) || rlPer <= 0) {
|
|
194
|
+
// NaN, Infinity, 0, negatives, fractional max all produce undefined
|
|
195
|
+
// throttling math (NaN deque comparisons, perma-locked queues,
|
|
196
|
+
// perma-open windows). Reject at config time.
|
|
197
|
+
if (!numericChecks.isPositiveInt(rlMax) || !numericChecks.isPositiveFinite(rlPer)) {
|
|
198
198
|
throw _err("BAD_RATE_LIMIT",
|
|
199
199
|
"consume({ rateLimit }): expected { max: positive integer, perSeconds: positive finite number }, got " +
|
|
200
200
|
JSON.stringify(opts.rateLimit), true);
|
package/lib/restore.js
CHANGED
|
@@ -54,7 +54,9 @@
|
|
|
54
54
|
var fs = require("fs");
|
|
55
55
|
var os = require("os");
|
|
56
56
|
var path = require("path");
|
|
57
|
+
var C = require("./constants");
|
|
57
58
|
var crypto = require("./crypto");
|
|
59
|
+
var numericChecks = require("./numeric-checks");
|
|
58
60
|
var restoreBundle = require("./restore-bundle");
|
|
59
61
|
var restoreRollback = require("./restore-rollback");
|
|
60
62
|
var lazyRequire = require("./lazy-require");
|
|
@@ -113,9 +115,9 @@ function create(opts) {
|
|
|
113
115
|
// (defense-in-depth in case the backend lied). Default 4 GiB / 100K
|
|
114
116
|
// files keeps the small-bundle path uncapped while bounding the
|
|
115
117
|
// pathological case.
|
|
116
|
-
var maxPulledBytes =
|
|
117
|
-
? opts.maxPulledBytes : 4
|
|
118
|
-
var maxPulledFiles =
|
|
118
|
+
var maxPulledBytes = numericChecks.isPositiveFinite(opts.maxPulledBytes)
|
|
119
|
+
? opts.maxPulledBytes : C.BYTES.gib(4);
|
|
120
|
+
var maxPulledFiles = numericChecks.isPositiveInt(opts.maxPulledFiles)
|
|
119
121
|
? opts.maxPulledFiles : 100000;
|
|
120
122
|
|
|
121
123
|
function _walkPullDirFootprint(dir) {
|
package/lib/retry.js
CHANGED
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
|
|
35
35
|
var C = require("./constants");
|
|
36
36
|
var lazyRequire = require("./lazy-require");
|
|
37
|
+
var numericChecks = require("./numeric-checks");
|
|
37
38
|
// safe-async re-exports withRetry + CircuitBreaker from this module, so a
|
|
38
39
|
// direct top-level require would create a cycle. Lazy-require defers the
|
|
39
40
|
// resolution until the first sleep() call, by which point both modules
|
|
@@ -82,12 +83,8 @@ var DEFAULT_BREAKER = Object.freeze({
|
|
|
82
83
|
|
|
83
84
|
// ---- Call-site validation helpers (throw on bad input) ----
|
|
84
85
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
function _isNonNegFinite(n) {
|
|
89
|
-
return typeof n === "number" && isFinite(n) && n >= 0;
|
|
90
|
-
}
|
|
86
|
+
var _isPositiveInt = numericChecks.isPositiveInt;
|
|
87
|
+
var _isNonNegFinite = numericChecks.isFiniteNonNegative;
|
|
91
88
|
function _isAbortSignal(s) {
|
|
92
89
|
// Duck-typed: AbortSignal exposes .aborted (bool) and .addEventListener (fn)
|
|
93
90
|
return s != null && typeof s === "object" &&
|
package/lib/slug.js
CHANGED
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
* - HTML-tag stripping (sanitize textually before slugging).
|
|
35
35
|
*/
|
|
36
36
|
|
|
37
|
+
var numericChecks = require("./numeric-checks");
|
|
37
38
|
var { SlugError } = require("./framework-error");
|
|
38
39
|
var _err = SlugError.factory;
|
|
39
40
|
|
|
@@ -63,9 +64,7 @@ var _RESERVED = Object.freeze([
|
|
|
63
64
|
|
|
64
65
|
// ---- Call-site validation helpers (throw on bad input) ----
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
return typeof n === "number" && isFinite(n) && n >= 1 && Math.floor(n) === n;
|
|
68
|
-
}
|
|
67
|
+
var _isPositiveInt = numericChecks.isPositiveInt;
|
|
69
68
|
|
|
70
69
|
function _validateOpts(name, opts) {
|
|
71
70
|
if (typeof opts.separator !== "string" || opts.separator.length !== 1) {
|
package/lib/testing.js
CHANGED
|
@@ -65,6 +65,7 @@ var os = require("node:os");
|
|
|
65
65
|
var nodePath = require("node:path");
|
|
66
66
|
var EventEmitter = require("node:events").EventEmitter;
|
|
67
67
|
var lazyRequire = require("./lazy-require");
|
|
68
|
+
var numericChecks = require("./numeric-checks");
|
|
68
69
|
var safeAsync = require("./safe-async");
|
|
69
70
|
var { TestingError } = require("./framework-error");
|
|
70
71
|
|
|
@@ -84,13 +85,8 @@ var DEFAULTS = Object.freeze({
|
|
|
84
85
|
|
|
85
86
|
// ---- Call-site validation helpers (throw on bad input) ----
|
|
86
87
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function _isFiniteNonNegative(n) {
|
|
92
|
-
return typeof n === "number" && isFinite(n) && n >= 0;
|
|
93
|
-
}
|
|
88
|
+
var _isPositiveInt = numericChecks.isPositiveInt;
|
|
89
|
+
var _isFiniteNonNegative = numericChecks.isFiniteNonNegative;
|
|
94
90
|
|
|
95
91
|
// ---- HTTP mocks (standalone — no framework primitive overlap) ----
|
|
96
92
|
// These mimic Node's `http` module's request/response shapes. They're
|
package/lib/webhook.js
CHANGED
|
@@ -72,6 +72,7 @@ var safeUrl = require("./safe-url");
|
|
|
72
72
|
var retry = require("./retry");
|
|
73
73
|
var C = require("./constants");
|
|
74
74
|
var lazyRequire = require("./lazy-require");
|
|
75
|
+
var numericChecks = require("./numeric-checks");
|
|
75
76
|
var requestHelpers = require("./request-helpers");
|
|
76
77
|
var { WebhookError } = require("./framework-error");
|
|
77
78
|
|
|
@@ -113,12 +114,8 @@ var DEFAULTS = Object.freeze({
|
|
|
113
114
|
|
|
114
115
|
// ---- Call-site validation helpers (throw on bad input) ----
|
|
115
116
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
function _isNonNegFinite(n) {
|
|
120
|
-
return typeof n === "number" && isFinite(n) && n >= 0;
|
|
121
|
-
}
|
|
117
|
+
var _isPositiveInt = numericChecks.isPositiveInt;
|
|
118
|
+
var _isNonNegFinite = numericChecks.isFiniteNonNegative;
|
|
122
119
|
function _hasOwn(obj, k) { return Object.prototype.hasOwnProperty.call(obj, k); }
|
|
123
120
|
function _objectKeys(obj) { return Object.keys(obj); }
|
|
124
121
|
|