@blamejs/blamejs-shop 0.3.42 → 0.3.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/CHANGELOG.md +4 -0
- package/lib/admin.js +641 -1
- package/lib/asset-manifest.json +1 -1
- package/lib/order-ratings.js +36 -0
- package/lib/storefront.js +253 -0
- package/lib/vendor/MANIFEST.json +2 -2
- package/lib/vendor/blamejs/CHANGELOG.md +2 -0
- package/lib/vendor/blamejs/api-snapshot.json +6 -2
- package/lib/vendor/blamejs/lib/app.js +8 -0
- package/lib/vendor/blamejs/lib/mail.js +1 -0
- package/lib/vendor/blamejs/lib/network-dns.js +1 -0
- package/lib/vendor/blamejs/lib/network-nts.js +4 -0
- package/lib/vendor/blamejs/lib/ntp-check.js +8 -0
- package/lib/vendor/blamejs/lib/redis-client.js +8 -0
- package/lib/vendor/blamejs/lib/validate-opts.js +23 -0
- package/lib/vendor/blamejs/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.14.16.json +45 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +29 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/validate-opts-port.test.js +70 -0
- package/package.json +1 -1
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../scripts/release-notes-schema.json",
|
|
3
|
+
"version": "0.14.16",
|
|
4
|
+
"date": "2026-05-31",
|
|
5
|
+
"headline": "Connection entry-point ports are validated at config time",
|
|
6
|
+
"summary": "Six connection entry points previously read opts.port with a bare `|| <default>` fallback, silently coercing a string, negative, NaN, or out-of-range port instead of catching the operator's typo. A new b.validateOpts.optionalPort enforces the RFC 6335 §6 wire-valid range and is wired into b.mail.smtpTransport, b.ntpCheck.querySingle, b.networkDns.useDnsOverTls, b.networkNts (KE handshake / query / facade), b.redisClient.create, and createApp().listen — each now throws at construction with a clear message naming the bad value. The app.listen / createApp bind site opts into allowZero so port 0 (the legitimate ephemeral-bind sentinel) still works; the five outbound-connect sites require [1,65535].",
|
|
7
|
+
"sections": [
|
|
8
|
+
{
|
|
9
|
+
"heading": "Added",
|
|
10
|
+
"items": [
|
|
11
|
+
{
|
|
12
|
+
"title": "`b.validateOpts.optionalPort`",
|
|
13
|
+
"body": "A config-time port validator: `optionalPort(value, label, errorClass, code, opts?)` returns an omitted (`undefined` / `null`) port unchanged, and otherwise requires an integer in the RFC 6335 §6 wire-valid range [1,65535] — rejecting a string, negative, NaN, Infinity, fractional, or out-of-range value. Pass `{ allowZero: true }` for a listen-bind site where port 0 is the OS ephemeral-bind sentinel. The thrown message reports the offending shape (so `Infinity` / `\"443\"` stay visible), and routes a caller-supplied typed framework error (or a plain Error when none is given), matching the existing `optionalPositiveFinite` family."
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"heading": "Changed",
|
|
19
|
+
"items": [
|
|
20
|
+
{
|
|
21
|
+
"title": "Connection entry points reject a malformed port at construction",
|
|
22
|
+
"body": "`b.mail.smtpTransport`, `b.ntpCheck.querySingle`, `b.networkDns.useDnsOverTls`, `b.networkNts.performKeHandshake` / `query` / `querySingle`, `b.redisClient.create`, and `createApp().listen` (plus the `createApp` constructor's default port) now validate `opts.port` and throw synchronously on a non-integer / out-of-range value rather than coercing it through `||` to a default. This is a behavior change for a caller that was passing a non-canonical port (e.g. the string `\"587\"` or a NaN) and relying on the silent fallback — pass an integer in [1,65535] instead (or `0` for an ephemeral `createApp().listen` bind). `b.ntpCheck` gains a typed `NtpCheckError` for this (it had no error class before)."
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"heading": "Detectors",
|
|
28
|
+
"items": [
|
|
29
|
+
{
|
|
30
|
+
"title": "Connection entry points must compose the port validator",
|
|
31
|
+
"body": "A new check flags a lib connection entry point that reads `opts.port` / `opts.kePort` / `opts.ntpPort` with a `|| <default>` fallback without composing `b.validateOpts.optionalPort` (or the equivalent `numericBounds.isPositiveFiniteInt` + 65535 cap), so an unvalidated port read can't slip back in."
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"heading": "Migration",
|
|
37
|
+
"items": [
|
|
38
|
+
{
|
|
39
|
+
"title": "Pass an integer port to connection primitives",
|
|
40
|
+
"body": "If you were passing a non-integer or out-of-range `opts.port` to a mail / NTP / NTS / DNS-over-TLS / Redis transport or to `createApp().listen` and relying on the silent `|| default` fallback, that now throws at construction. Pass an integer in [1,65535]; for an ephemeral `createApp().listen` bind, pass `0` (still accepted)."
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
@@ -2743,6 +2743,33 @@ async function testNoDuplicateCodeBlocks() {
|
|
|
2743
2743
|
],
|
|
2744
2744
|
reason: "v0.12.42 — validateOpts-then-guard prelude shared by three builder-style functions: cert.create mints a certificate, mail-send-deliver.deliver sends a message, vc.present builds + signs a Verifiable Presentation. The common shingle is the `validateOpts(allowedKeys) + required-field / non-empty-array guards + typed-error throw` idiom; the bodies diverge entirely (X.509 minting / SMTP delivery / VC-JOSE-COSE presentation envelope). Same validate-then-guard family as the v0.12.29 / v0.12.33 / v0.12.40 clusters.",
|
|
2745
2745
|
},
|
|
2746
|
+
{
|
|
2747
|
+
mode: "family-subset",
|
|
2748
|
+
files: [
|
|
2749
|
+
"lib/api-key.js:_validateIssueOpts",
|
|
2750
|
+
"lib/http-client-cache.js:create",
|
|
2751
|
+
"lib/network-dns.js:useDnsOverTls",
|
|
2752
|
+
],
|
|
2753
|
+
reason: "v0.14.15 — validateOpts config-validation prelude (validateOpts(allowedKeys) + requireNonEmptyString + the new optionalPort port-range guard + typed-error throw). api-key._validateIssueOpts validates an API-key issue spec; http-client-cache.create validates a cache config; network-dns.useDnsOverTls validates a DoT endpoint. Wiring validateOpts.optionalPort into the DoT site tipped its preamble past the 50-token shingle threshold against two unrelated config-time primitives. Bodies diverge entirely; the shared primitive IS validateOpts (already extracted) — coupling these specs would couple three unrelated standards on a syntactic accident. Verified coincidental (absent on clean main; the 3 functions are unrelated). Same validate-then-guard family as the v0.12.29 / v0.12.42 clusters.",
|
|
2754
|
+
},
|
|
2755
|
+
{
|
|
2756
|
+
mode: "family-subset",
|
|
2757
|
+
files: [
|
|
2758
|
+
"lib/agent-idempotency.js:_safeAudit",
|
|
2759
|
+
"lib/agent-orchestrator.js:_safeAudit",
|
|
2760
|
+
"lib/redis-client.js:_frameToValue",
|
|
2761
|
+
],
|
|
2762
|
+
reason: "v0.14.15 — coincidental boilerplate shingle surfaced when the validateOpts.optionalPort wiring was added to redis-client.create: the file's token stream shifted enough that a 50-token window in redis-client.js clusters with the identical _safeAudit audit-emit wrappers in agent-idempotency / agent-orchestrator (a try/catch around audit().safeEmit). _safeAudit drop-silently emits an audit event; redis-client._frameToValue parses a RESP wire frame — entirely unrelated behaviour sharing only a generic guard/try-catch idiom. Verified absent on clean main; no shared logic to extract.",
|
|
2763
|
+
},
|
|
2764
|
+
{
|
|
2765
|
+
mode: "family-subset",
|
|
2766
|
+
files: [
|
|
2767
|
+
"lib/compliance-sanctions-fetcher.js:create",
|
|
2768
|
+
"lib/network-nts.js:performKeHandshake",
|
|
2769
|
+
"lib/web-push-vapid.js:buildVapidAuthHeader",
|
|
2770
|
+
],
|
|
2771
|
+
reason: "v0.14.15 — validateOpts config-validation prelude again: network-nts.performKeHandshake gained the optionalPort port-range guard, tipping its preamble past the shingle threshold against compliance-sanctions-fetcher.create (sanctions-list fetch config) and web-push-vapid.buildVapidAuthHeader (VAPID JWT auth header build). Three unrelated specs (NTS-KE handshake / sanctions fetch / Web-Push VAPID) sharing only the validateOpts-then-guard idiom; the shared primitive is validateOpts. Verified coincidental (absent on clean main). Same family as the v0.12.29 / v0.12.42 clusters.",
|
|
2772
|
+
},
|
|
2746
2773
|
{
|
|
2747
2774
|
mode: "family-subset",
|
|
2748
2775
|
files: [
|
|
@@ -6523,6 +6550,8 @@ var KNOWN_ANTIPATTERNS = [
|
|
|
6523
6550
|
|
|
6524
6551
|
{ id: "consent-purposes-null-proto", primitive: "the recognized-purpose map (PURPOSES) must be a null-prototype object so an operator-supplied free-form purpose colliding with an Object.prototype member (toString / constructor / __proto__) resolves to undefined, not the prototype value", scanScope: "lib", regex: /var PURPOSES\s*=\s*Object\.freeze\(/, requires: /Object\.create\(null\)/, allowlist: [], reason: "v0.14.14 Codex P2 on PR #295 (CWE-1321) — recognizedPurpose(name) + grant() index PURPOSES[purpose] with an operator-controlled value; a plain-prototype map returns Object.prototype.toString (truthy) for purpose \"toString\", breaking the null-for-free-form contract and entering grant()'s recognized branch for a value listPurposes() never exposes. PURPOSES is now Object.freeze(Object.assign(Object.create(null), {...})) so every unrecognized key resolves to undefined. Detector requires the null-prototype declaration so the lookup can't silently revert to a plain object." },
|
|
6525
6552
|
|
|
6553
|
+
{ id: "connect-entry-point-port-must-compose-optionalPort", primitive: "a connection entry point reading opts.port / opts.kePort / opts.ntpPort with a `|| <default>` fallback must first validate it via validateOpts.optionalPort (or, where a permanent typed error is needed, the equivalent numericBounds.isPositiveFiniteInt(opts.port) + 65535 cap) — an unvalidated opts.port || N silently accepts a string / negative / NaN / out-of-range port", scanScope: "lib", regex: /\bopts\.(?:port|kePort|ntpPort)\s*\|\|/, requires: /validateOpts\.optionalPort\(|isPositiveFiniteInt\(opts\.port\)/, allowlist: [], reason: "v0.14.15 — the connection entry points (mail.smtpTransport, ntpCheck.querySingle, dns.useDnsOverTls, nts.performKeHandshake / querySingle / query, redis.create) read opts.port || <default>, silently coercing a string / negative / NaN / >65535 port; rule §5 says config-time entry points THROW so the operator catches the typo at boot. Each now composes validateOpts.optionalPort (RFC 6335 §6 [1,65535]; allowZero for the app.listen ephemeral bind) — or, where a MailError-permanent typed error is needed, the same numericBounds.isPositiveFiniteInt + 65535 rule inline. The requires-companion clears a file once it validates; a new entry point reading opts.port || N without composing the validator trips the gate." },
|
|
6554
|
+
|
|
6526
6555
|
{
|
|
6527
6556
|
// ROTATION-EPOCH ACCEPT (v0.14.x): a vault-key rotation (b.vault.rotate)
|
|
6528
6557
|
// re-keys the local dataDir, which changes the SHA3-512 fingerprint of
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// b.validateOpts.optionalPort — RFC 6335 §6 port-range validator — plus the
|
|
3
|
+
// representative connection entry-point wiring (ntpCheck.querySingle; the other
|
|
4
|
+
// five sites compose the identical guard).
|
|
5
|
+
|
|
6
|
+
var helpers = require("../helpers");
|
|
7
|
+
var b = helpers.b;
|
|
8
|
+
var check = helpers.check;
|
|
9
|
+
var redisClient = require("../../lib/redis-client");
|
|
10
|
+
|
|
11
|
+
function _thrCode(fn) { try { fn(); return null; } catch (e) { return e.code || e.message; } }
|
|
12
|
+
|
|
13
|
+
function run() {
|
|
14
|
+
var vo = b.validateOpts;
|
|
15
|
+
check("optionalPort is a function", typeof vo.optionalPort === "function");
|
|
16
|
+
|
|
17
|
+
// pass-through + valid ports
|
|
18
|
+
check("optionalPort(undefined) → undefined", vo.optionalPort(undefined) === undefined);
|
|
19
|
+
check("optionalPort(null) → null", vo.optionalPort(null) === null);
|
|
20
|
+
check("optionalPort(443) → 443", vo.optionalPort(443, "p") === 443);
|
|
21
|
+
check("optionalPort(1) accepted", vo.optionalPort(1, "p") === 1);
|
|
22
|
+
check("optionalPort(65535) accepted", vo.optionalPort(65535, "p") === 65535);
|
|
23
|
+
|
|
24
|
+
// 0 rejected by default, accepted with allowZero (ephemeral listen-bind)
|
|
25
|
+
check("optionalPort(0) throws by default", _thrCode(function () { vo.optionalPort(0, "p"); }) !== null);
|
|
26
|
+
check("optionalPort(0, allowZero) → 0", vo.optionalPort(0, "p", undefined, undefined, { allowZero: true }) === 0);
|
|
27
|
+
|
|
28
|
+
// out-of-range / non-integer / wrong-type all throw
|
|
29
|
+
[65536, -1, 0.5, "443", NaN, Infinity, "x", true, {}].forEach(function (bad, i) {
|
|
30
|
+
check("optionalPort rejects bad value #" + i + " (" + String(bad) + ")",
|
|
31
|
+
_thrCode(function () { vo.optionalPort(bad, "p"); }) !== null);
|
|
32
|
+
});
|
|
33
|
+
// 65536 is out of range even with allowZero
|
|
34
|
+
check("optionalPort(65536, allowZero) still throws",
|
|
35
|
+
_thrCode(function () { vo.optionalPort(65536, "p", undefined, undefined, { allowZero: true }); }) !== null);
|
|
36
|
+
|
|
37
|
+
// message carries numericBounds.shape() so Infinity / "443" stay visible
|
|
38
|
+
var msg = _thrCode(function () { vo.optionalPort(Infinity, "p"); });
|
|
39
|
+
check("optionalPort message shows the bad shape", typeof msg === "string" && /Infinity/.test(msg));
|
|
40
|
+
|
|
41
|
+
// typed-error class + code via a defineClass-built framework error
|
|
42
|
+
check("optionalPort routes a typed error class + code",
|
|
43
|
+
_thrCode(function () { vo.optionalPort(-1, "p", b.ntpCheck.NtpCheckError, "ntp/bad-port"); }) === "ntp/bad-port");
|
|
44
|
+
|
|
45
|
+
// plain Error when no errorClass is supplied
|
|
46
|
+
var plain = null;
|
|
47
|
+
try { vo.optionalPort(-1, "p"); } catch (e) { plain = e; }
|
|
48
|
+
check("optionalPort throws a plain Error with no errorClass", (plain instanceof Error) && !plain.code);
|
|
49
|
+
|
|
50
|
+
// representative entry-point wiring: ntpCheck.querySingle rejects a bad port
|
|
51
|
+
// synchronously (before the Promise) with a typed NtpCheckError.
|
|
52
|
+
check("b.ntpCheck.NtpCheckError is a constructor", typeof b.ntpCheck.NtpCheckError === "function");
|
|
53
|
+
check("ntpCheck.querySingle({port:-1}) throws ntp/bad-port",
|
|
54
|
+
_thrCode(function () { b.ntpCheck.querySingle("pool.ntp.org", { port: -1 }); }) === "ntp/bad-port");
|
|
55
|
+
check("ntpCheck.querySingle({port:70000}) throws ntp/bad-port",
|
|
56
|
+
_thrCode(function () { b.ntpCheck.querySingle("pool.ntp.org", { port: 70000 }); }) === "ntp/bad-port");
|
|
57
|
+
|
|
58
|
+
// A url-supplied connection port must be range-checked too — the opts.port
|
|
59
|
+
// guard alone misses a port resolved from the url, so redis://h:0 (parsed to
|
|
60
|
+
// port 0) would otherwise reach an outbound connect. create() is inert until
|
|
61
|
+
// .connect(), so a valid url throws nothing.
|
|
62
|
+
check("redis url-port 0 rejected at create (resolved-port guard)",
|
|
63
|
+
_thrCode(function () { redisClient.create({ url: "redis://localhost:0" }); }) !== null);
|
|
64
|
+
check("redis url-port out-of-range rejected at create",
|
|
65
|
+
_thrCode(function () { redisClient.create({ url: "redis://localhost:99999" }); }) !== null);
|
|
66
|
+
check("redis valid url-port accepted (no throw at create)",
|
|
67
|
+
_thrCode(function () { redisClient.create({ url: "redis://localhost:6379" }); }) === null);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = { run: run };
|
package/package.json
CHANGED