@blamejs/core 0.8.68 → 0.8.69

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,7 @@ upgrading across more than a few patches at a time.
8
8
 
9
9
  ## v0.8.x
10
10
 
11
+ - v0.8.69 (2026-05-10) — test-side `waitUntil` helper + CLAUDE.md §11b convention. Every recurring "test passes alone, fails under SMOKE_PARALLEL=64 / macOS GitHub-Actions runner" flake we've fought across v0.8.55 (rate-limit-cluster), v0.8.60 (watcher), v0.8.63 / v0.8.65 / v0.8.68 (log-stream-otlp / sandbox) was the same root cause: a fixed-budget `setTimeout(r, N)` sleep too short for runner-contention reality. New `test/helpers/wait.js` ships `waitUntil(predicate, opts?)` (polls every `intervalMs` default 25ms up to `timeoutMs` default 5000ms, exits early when predicate truthy, throws labeled error on timeout) + `waitUntilEqual(getter, expected)` convenience wrapper. `test/helpers/index.js` re-exports both. Refactored `test/layer-0-primitives/log-stream-otlp.test.js`'s "collector saw retries" gate (the most-recently-flaked one) to use `waitUntil({ failCount >= 2, dropEvents.length === 1 })` instead of `_sleep(200)` — fast platforms exit in ~30ms, contended platforms get the full budget. CLAUDE.md §11b documents the convention: when you find yourself bumping a hand-tuned sleep to fix a CI flake, that's the smell — convert to `waitUntil`. Future flake fixes update one timeout ceiling instead of N inline budgets.
11
12
  - v0.8.68 (2026-05-10) — `b.watcher` polling backend for environments where `fs.watch` doesn't deliver events. Pre-v0.8.68 the watcher used `fs.watch(root, { recursive: true })` exclusively — works on real Linux/macOS/Windows kernels but silent on filesystems where the kernel→userspace event bridge doesn't exist: Docker Desktop bind-mounts on Windows / macOS hosts (gRPC-FUSE / VirtioFS doesn't propagate inotify events from the Linux container's mount through to the host fs the operator runs node on), NFS / SMB mounts, some FUSE filesystems. Add `mode: "fs" | "poll"` (default `"fs"`) — when `mode: "poll"`, the watcher walks the tree on a fixed interval and diffs against the previous snapshot. New file / mtime-change / size-change → `onChange` via the existing debounce + ignore + lstat dispatch; missing path → `onDelete`. `pollIntervalMs` (default 1s) sets cadence; `pollMaxFiles` (default 50000) caps the per-tick walk so a misconfigured root can't stall the event loop stat'ing 100k files every second — overflow refuses with `watcher/poll-overflow`. Symlinks skipped (matches fs.watch path). The initial walk happens synchronously in `create()` so the first event fires only on real post-start changes (not on pre-existing files). `_flushForTest()` runs one synchronous tick + drains pending debounces so polling tests don't have to sleep `pollIntervalMs`. Returned handle gains `.mode` for operator introspection. fs.watch-backend error messages now suggest `mode: "poll"` as the fallback. New Layer 0 polling tests cover create / modify / delete detection across nested directories + mode validation + pollMaxFiles overflow.
12
13
  - v0.8.67 (2026-05-10) — SAML XMLDSig Reference Transforms (`enveloped-signature` + per-Reference c14n) + full IdP-emitted SAML round-trip in the federation-auth integration test. Pre-v0.8.67 `b.auth.saml.sp.verifyResponse` only honored the SignedInfo's `CanonicalizationMethod`; it didn't process the `<ds:Transforms>` block on the Reference. Real-world IdP-signed responses (Keycloak, ADFS, Okta) attach `http://www.w3.org/2000/09/xmldsig#enveloped-signature` (strip the `<Signature>` child of the referenced element before c14n) and a per-Reference `xml-exc-c14n#` Transform — without them, the digest computed over the assertion-including-signature never matches the signed-then-signature-injected reality and verifyResponse rejected legitimate IdP responses. `_verifyXmldsig` now reads the Transforms list, applies enveloped-signature by filtering the parsed-tree's `<Signature>` element children before canonicalization, and honors the per-Reference c14n choice (with vs without comments). The single-match-by-ID invariant + signature-wrapping defense moves into the saml.js path directly so the modified subtree (signature stripped) is the one that gets canonicalized + digested. `test/integration/federation-auth.test.js` now drives Keycloak's HTML login form via cookie-jar curl-equivalent (no headless browser needed), captures the IdP-signed SAMLResponse, fetches the IdP signing certificate from `/protocol/saml/descriptor`, hands the response to `sp.verifyResponse(b64, { expectedInResponseTo })`, and asserts the extracted `nameId` / `issuer` / `audience` / `inResponseTo` match the realm's signed claims. Verified end-to-end: Keycloak alice user → SAML AuthnRequest → login form POST → signed Response → `sp.verifyResponse()` → `{ nameId: "alice", issuer: <realm>, audience: <SP entityID>, attributes: { Role: "default-roles-..." } }`. Unsupported Transform algorithms refuse loudly via `auth-saml/unsupported-transform`. No primitive surface change versus v0.8.66 (the Transforms processing is internal to `_verifyXmldsig`).
13
14
  - v0.8.66 (2026-05-10) — `b.session.updateData(token, data, opts?)`. Update the sealed `data` payload on a session WITHOUT rotating the sid. Pre-v0.8.66 the only path to mutate session data was `b.session.rotate(token, { data })` which forces an sid rotation — appropriate for security-boundary transitions (login, MFA, role escalation) but heavyweight for cart-state writes / preference flips / step-up-completion flags. Default semantics: full payload replace, `lastActivity` bumped (idle-timeout reset), reserved `__bj_fingerprint` binding preserved automatically so verify() still surfaces drift correctly. `opts.merge: true` does a one-level deep merge into the existing payload; `opts.touchLastActivity: false` skips the idle-timeout bump. Returns `false` for unknown / expired / pre-v0.8.61-raw-format tokens (no throw). Anonymous-session userIds work the same as named userIds. Leader-only. New Layer 0 tests: 13 checks covering replace / merge / null-clear / fingerprint preservation / unknown-token returns / array refusal.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/core",
3
- "version": "0.8.68",
3
+ "version": "0.8.69",
4
4
  "description": "The Node framework that owns its stack.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "blamejs contributors",
@@ -2,10 +2,10 @@
2
2
  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
3
3
  "bomFormat": "CycloneDX",
4
4
  "specVersion": "1.5",
5
- "serialNumber": "urn:uuid:474443de-ab7d-4d50-8f5f-a5c080068475",
5
+ "serialNumber": "urn:uuid:cf3aa594-6a94-4be5-9952-a87c315ec5eb",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-05-10T14:52:18.655Z",
8
+ "timestamp": "2026-05-10T15:19:22.438Z",
9
9
  "lifecycles": [
10
10
  {
11
11
  "phase": "build"
@@ -19,14 +19,14 @@
19
19
  }
20
20
  ],
21
21
  "component": {
22
- "bom-ref": "@blamejs/core@0.8.68",
22
+ "bom-ref": "@blamejs/core@0.8.69",
23
23
  "type": "library",
24
24
  "name": "blamejs",
25
- "version": "0.8.68",
25
+ "version": "0.8.69",
26
26
  "scope": "required",
27
27
  "author": "blamejs contributors",
28
28
  "description": "The Node framework that owns its stack.",
29
- "purl": "pkg:npm/%40blamejs/core@0.8.68",
29
+ "purl": "pkg:npm/%40blamejs/core@0.8.69",
30
30
  "properties": [],
31
31
  "externalReferences": [
32
32
  {
@@ -54,7 +54,7 @@
54
54
  "components": [],
55
55
  "dependencies": [
56
56
  {
57
- "ref": "@blamejs/core@0.8.68",
57
+ "ref": "@blamejs/core@0.8.69",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]