@blamejs/blamejs-shop 0.0.112 → 0.0.113

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 CHANGED
@@ -8,6 +8,8 @@ upgrading across more than a few patches at a time.
8
8
 
9
9
  ## v0.0.x
10
10
 
11
+ - v0.0.113 (2026-05-23) — **Catalog mirror — 66 new codebase-patterns detectors ported from vendored blamejs.** The codebase-patterns detector catalog grows from 48 to 114 — 66 new detectors ported verbatim from `lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js`. The full vendored set covers archive-handling traps, framework-helper composition (the `inline-*` family), Node-version-conditional patterns, SBOM derivation traps, mail-server TLS upgrade hygiene, mountinfo bind-detection invariants, and dozens of other bug classes the framework has surfaced through audits. Every new detector scopes `shop` (lib + worker) so reinventions are caught anywhere in the application surface. Vendor allowlist entries referencing internal blamejs paths (e.g. `lib/crypto.js`) are kept verbatim — shop's `_walk` skips the vendor tree, so those entries are harmless no-ops and preserve the operator-readable reason text. Three pre-existing inline reinventions surfaced through the port and are kept with inline `allow:` markers documenting why the framework helper can't compose — the existing `TypeError` message contract requires the literal field name (`/timeoutMs/`, `/opts.version/`) which `validateOpts.*`'s `code`-first error shape doesn't carry. Eight detector blocks (six with regex literals containing literal `"` characters that the splice tool can't roundtrip, plus `release-named-test-file` whose `matchOn: "basename"` directive shop's runner doesn't honor yet, plus `inline-base64url-three-replace` already ported in 0.0.112) defer to a follow-up. **Added:** *Mirror 66 new codebase-patterns detectors from vendored blamejs* — Categories: archive-handling (extract-overwrite-without-refusal, gz-without-safedecompress, read-gz-without-self-authored-budget, tar-walker-without-truncation-check, wrap-recipient-missing-ec-half — except wrap-recipient which deferred to follow-up); the `inline-*` family of framework-helper composition reminders (40+ detectors covering aggregate-issues, assert-no-char-threats, audit-emit-wrapper, audit-shape-validation, bad-input-issue-result, batch-positive-int-validation, buffer-byte-equality-loop, build-guard-gate-forwarder, char-strip-policy-cascade, codepoint-class-table, compliance-posture-lookup, crlf-string-test, default-resolution-cascade, detect-char-threats, emit-event-wrapper, extract-bytes-as-text, flush-timer-scheduler, hex-string-validator, iso8601-millisecond-strip, issue-validator-entry, log-via-or-fallback, migration-filename-regex, numeric-bounds-cascade, object-store-http-request, observability-shape-validation, optional-* validators, profile-builder-forwarder, redis-client-opts-forwarding, require-* validators, resolve-profile-and-posture, rule-pack-loader, sql-identifier-regex, trailing-hspace-strip); SBOM derivation traps (toplevel-ref-by-slash-heuristic, bom-ref enum-rank-without-validation, etc.); compliance/posture coverage (compliance-posture-coverage-drift); cred-store + mailstore + mountinfo invariants; PQC + dot-stuff regex shapes; CONDSTORE + BDAT mail-server invariants. Full list visible by diffing `test/layer-0-primitives/codebase-patterns.test.js` against the v0.0.112 baseline. · *Worker `b` adapter exposes `b.validateOpts`* — `worker/b.js` now re-exports the `validate-opts` leaf module so future Worker primitives can compose `b.validateOpts.optionalPositiveFinite` / `b.validateOpts.optionalFunction` / `b.validateOpts.requireNonEmptyString` etc. against the same one-source-of-truth as lib-side primitives. Adds the leaf to the Worker bundle but doesn't bind a public namespace change. **Changed:** *Three inline-validation sites carry per-line `allow:` markers* — `lib/externaldb-d1.js#_validateOpts` (two lines: `timeoutMs`, `fetch`), `lib/r2-bridge.js#_validateOpts` (one line: `timeoutMs`), and `worker/render/search.js#renderSearch` (one line: `opts.version`) keep the literal `TypeError` shape with the labelled message because each is paired with a test contract that asserts the field name appears in the message (`assert.throws(..., /timeoutMs/)`). The framework's `validateOpts.*` helper produces a `code`-first `TypeError` (`TypeError: validate-opts/bad-positive-finite`) whose message doesn't carry the label; routing through it would silently strip the labelled-field contract from the test. Marker explains the constraint at the source.
12
+
11
13
  - v0.0.112 (2026-05-23) — **Compose `b.crypto.toBase64Url` instead of reinventing — nine primitives + new detector.** Nine framework primitives (`api-keys`, `carrier-accounts`, `customer-surveys`, `stock-alerts`, `stock-receipts`, `subscription-gifts`, `webhook-receiver`, `wishlist-sharing`, `storefront`'s server-side `_b64u`) shipped with hand-rolled base64url encoding — the canonical four-line `.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "")` chain. The trailing-padding `.replace(/=+$/, "")` strip is polynomial-ReDoS-shaped per CodeQL js/polynomial-redos. The framework's `b.crypto.toBase64Url(buf)` helper routes through Node's built-in `base64url` encoding which is linear-time and produces the same RFC 4648 §5 output. Every server-side callsite now composes the framework primitive. Two browser-side helpers in `lib/storefront.js`'s WebAuthn UI string-template (no `b.crypto` available in the page runtime) carry inline `allow:inline-base64url-three-replace` markers — `window.btoa` plus the three-replace shim is the browser-built-in equivalent. New `inline-base64url-three-replace` codebase-patterns detector enforces the composition shop-wide. **Added:** *`inline-base64url-three-replace` codebase-patterns detector* — Flags `.replace(/=+$/, ...)` anywhere under `lib/` or `worker/`. Catches the canonical four-line base64url reinvention chain at the trailing-padding-strip line. Ported verbatim (with shop-scope) from blamejs's catalog. Browser-side string-template emissions in `lib/storefront.js` carry inline allow markers documenting that the browser has no `b.crypto` runtime — `window.btoa` plus the three-replace shim is the built-in. **Changed:** *Nine primitives compose `b.crypto.toBase64Url`* — `api-keys` `_generateToken`, `carrier-accounts` `_generateSecret`, `customer-surveys` `_generateToken`, `stock-alerts` `_mintToken` (inlined the redundant `_b64url` helper), `stock-receipts` `_generateToken`, `subscription-gifts` `_generateToken`, `webhook-receiver` `_generateSecret`, `wishlist-sharing` `_generateToken`, and `storefront`'s server-side `_b64u` helper all now route through `_b().crypto.toBase64Url(buf)`. Linear-time output, no polynomial-ReDoS surface, no Node-minor-version Buffer-flag-rename risk.
12
14
 
13
15
  - v0.0.111 (2026-05-23) — **Restore /feed.xml + /sitemap.xml — `b.safeUrl.parse` returns a URL instance, not a string.** `/feed.xml` and `/sitemap.xml` have been responding 503 "temporarily unavailable" since they shipped. Root cause: three edge handlers (sitemap, feed, scheduled cache-warmer) chained `.replace(/\/$/, "")` directly off `b.safeUrl.parse(...)`. The framework primitive returns a WHATWG `URL` instance, not a string — `URL.prototype.replace` doesn't exist, so every request threw `TypeError: ... .replace is not a function`. The handler's catch swallowed the throw and returned the canonical 503, making the routes appear transiently unavailable when they were in fact permanently broken on that callsite. The bug went undetected because production deploys were frozen at v0.0.101 for a separate reason (now fixed in v0.0.110), so the broken handlers never reached live traffic until today. Fix: chain `.href.replace(/\/$/, "")` so the string method operates on the URL's href string. A new `safeurl-parse-string-method` detector catches the shape repo-wide (47 detectors → adds 1, total 47 → 48). **Added:** *`safeurl-parse-string-method` codebase-patterns detector* — Flags `b.safeUrl.parse(...).<strMethod>(` anywhere under `worker/` — covers `replace` / `startsWith` / `endsWith` / `split` / `includes` / `slice` / `indexOf` / `toLowerCase` / `toUpperCase`. Property access (`.href`) is intentionally NOT flagged — that's the correct shape. The detector exists because three handlers shipped this anti-pattern without anyone noticing while production was frozen; pre-merge detection prevents the next instance from regressing through review the same way. **Fixed:** *Restore `/feed.xml`, `/sitemap.xml`, and the scheduled cache-warmer* — Three callsites in `worker/index.js` shipped `b.safeUrl.parse(env.D1_BRIDGE_URL || "https://blamejs.shop").replace(/\/$/, "")` — `URL.prototype.replace` doesn't exist, so the worker threw TypeError on every request and the edge handler's catch returned the canonical 503. Replaced with `.href.replace(...)` so the trailing-slash strip runs against the URL's serialized form. The semantic contract (operator-configured origin with no trailing slash) is preserved across operator inputs with or without a path prefix.
@@ -85,10 +85,10 @@ function _validateOpts(opts) {
85
85
  throw new TypeError("externaldbD1.create — rest-api mode requires apiToken");
86
86
  }
87
87
  }
88
- if (opts.timeoutMs !== undefined && (typeof opts.timeoutMs !== "number" || !isFinite(opts.timeoutMs) || opts.timeoutMs <= 0)) {
88
+ if (opts.timeoutMs !== undefined && (typeof opts.timeoutMs !== "number" || !isFinite(opts.timeoutMs) || opts.timeoutMs <= 0)) { // allow:inline-optional-positive-finite-validation — the TypeError message must literally contain "timeoutMs" so the test contract (`assert.throws(..., /timeoutMs/)`) sees the labelled field; the framework helper threads the label through a `code`-first FrameworkError shape, so a plain `TypeError` constructor renders the code as the message instead
89
89
  throw new TypeError("externaldbD1.create — timeoutMs must be a positive number");
90
90
  }
91
- if (opts.fetch !== undefined && typeof opts.fetch !== "function") {
91
+ if (opts.fetch !== undefined && typeof opts.fetch !== "function") { // allow:inline-optional-function-validation — same TypeError-message contract as the timeoutMs guard above
92
92
  throw new TypeError("externaldbD1.create — fetch override must be a function");
93
93
  }
94
94
  }
package/lib/r2-bridge.js CHANGED
@@ -54,7 +54,7 @@ function _validateOpts(opts) {
54
54
  if (opts.bridgePath !== undefined && typeof opts.bridgePath !== "string") {
55
55
  throw new TypeError("r2Bridge.create — bridgePath must be a string when provided");
56
56
  }
57
- if (opts.timeoutMs !== undefined && (typeof opts.timeoutMs !== "number" || !isFinite(opts.timeoutMs) || opts.timeoutMs <= 0)) {
57
+ if (opts.timeoutMs !== undefined && (typeof opts.timeoutMs !== "number" || !isFinite(opts.timeoutMs) || opts.timeoutMs <= 0)) { // allow:inline-optional-positive-finite-validation — the TypeError message must literally contain "timeoutMs" so the test contract (`assert.throws(..., /timeoutMs/)`) sees the labelled field; the framework helper produces a `code`-first message that doesn't carry the label
58
58
  throw new TypeError("r2Bridge.create — timeoutMs must be a positive number");
59
59
  }
60
60
  if (opts.httpClient !== undefined && (!opts.httpClient || typeof opts.httpClient.request !== "function")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/blamejs-shop",
3
- "version": "0.0.112",
3
+ "version": "0.0.113",
4
4
  "description": "Open-source framework built on blamejs. Vendored stack, zero npm runtime deps, PQC-first crypto, security-on by default.",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {