@blamejs/core 0.6.28 → 0.6.29

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.6.x
10
10
 
11
+ - **0.6.29** (2026-05-02) — CI cleanup. **shellcheck gate green**: `docker/init/generate-certs.sh`'s footer line counted output via `ls "$CERT_DIR" | wc -l` (SC2012 — fragile on filenames with newlines or quoting metacharacters); replaced with `find "$CERT_DIR" -maxdepth 1 -mindepth 1 | wc -l`. Same semantics, robust to any cert filename pki-init might end up writing. **shellcheck added to the documented pre-push gate list** in CONTRIBUTING.md alongside smoke / wiki e2e / eslint / api-snapshot / primitive-section validators — CI's `Lint summary` job has always run it, but the local-dev recipe didn't, so contributors hit it post-push instead of catching it locally. **eslint pin alignment**: `.github/PULL_REQUEST_TEMPLATE.md` and CONTRIBUTING.md still pinned `eslint@10` even though v0.6.16 swapped CI runners to `eslint@latest`; both bumped to `@latest` to match the forward-track posture of every other CI tool. No framework code changes; the script + doc updates never ship in the npm package (excluded by `files` array).
11
12
  - **0.6.28** (2026-05-02) — bug-finding pass: live integration test suite + every framework bug it caught. **`b.ssrfGuard.checkUrl` cloud-metadata hard-deny** — `allowInternal: true` no longer permits 169.254.169.254 (AWS / GCP / Azure metadata). Loopback / private / link-local / reserved stay allowInternal-overridable per existing semantics; cloud-metadata is unconditional because a blanket override would let any compromised request exfiltrate instance credentials. **`b.mtlsCa` issues server certs and dual-EKU certs** — `generateClientCert({ usage: "client" | "server" | "both", sans: [...] })`. `usage` controls EKU (`client` = clientAuth, `server` = serverAuth, `both` = both); `sans` accepts `DNS:` / `IP:` / bare-DNS entries; serverAuth without an explicit SAN auto-adds the CN. Operators wiring inbound mTLS reverse-proxy fronts no longer hit "unsuitable certificate purpose" on the handshake. **`b.mtlsCa` algorithm auto-detect** — the engine probes webcrypto + the vendored x509 library at first cert issuance and picks the highest-PQC option that round-trips: SLH-DSA-SHAKE-256f → SLH-DSA-SHAKE-128f → ML-DSA-87 → ML-DSA-65 → ECDSA-P384-SHA384 (current bridge — what the X.509 ecosystem accepts today). When the bridge condition lifts and the vendor refresh ships, the same `b.mtlsCa.create(...)` call self-upgrades; `b.mtlsCa.status().cert.label` and `.posture` surface the chosen algorithm. **`b.redisClient.create({ ca, servername })`** — managed-Redis / on-prem-cluster operators connecting over `rediss://` against a private CA can pin trust roots; `servername` auto-suppresses for IP literals so `rediss://127.0.0.1:6380` no longer trips node:tls's IP-as-SNI rule. **`b.network.dns.useDnsOverTls` / `useDnsOverHttps` accept `ca`** — same trust-pinning surface for self-signed / private-PKI DoT and DoH endpoints. **DoT TLS handshake errors** now route as DnsError on the lookup promise rather than leaking as `unhandledRejection` — the secureConnect / error event-listener race had let cert-verification failures escape the per-query Promise wrapping. **DoT socket lifecycle** — was unconditionally `sock.unref()`'d after construct, causing node to exit during in-flight lookups when no other I/O kept the loop alive; now ref'd while a query is in flight and unref'd when idle. **`b.ntpCheck.querySingle` honours IPv6 servers** — was hardcoded to `dgram.createSocket("udp4")`, so `::1` / `fd00::…` queries failed with EINVAL; now auto-detects family from the server string. **`b.logStream.shutdown` drains in-flight emit microtasks** before closing sink fds — fire-and-forget emits queued just before shutdown were silently dropped because `close()` ran ahead of the microtask. **`b.logStream` webhook-sink `close()` flushes BEFORE setting `closed = true`** — `_flush`'s while loop bailed on `!closed`, leaving any records buffered just before shutdown stranded. **Integration test suite** (`test/integration/`, runner at `scripts/test-integration.js`) — 13 live test files across `b.redisClient` plain + TLS, `b.queue` Redis backend lifecycle, `b.mail` SMTP + STARTTLS + multi-rcpt + dot-stuffing transparency, `b.mail.dkim` rsa-sha256 + ed25519-sha256 + bad-algorithm reject, `b.ntpCheck` v4 + v6 + bootCheck + bad-host + bad-port, `b.network.dns` plain + DoT + DoH with strict CA pinning + bad-servername + cache, `b.network.heartbeat` http + tcp + state-change callbacks, `b.objectStore` sigv4 PUT / GET / list / delete on plain HTTP + TLS variants, `b.cache` memory + Redis-backed cluster, `b.httpClient` direct + Squid forward proxy + TLS pin, `b.ssrfGuard` classify + checkUrl + cloud-metadata block, `b.logStream` local + webhook + deferred-syslog error path, `b.mtlsCa` CA bootstrap + clientAuth + serverAuth + dual-EKU live mTLS handshakes. Companion `docker-compose.test.yml` stands up redis (plain + TLS) / postgres / mysql / mongo / minio (HTTP + HTTPS variants) / rabbitmq (plain + TLS) / nats / syslog / ntp / mailpit / coredns (plain + DoT + DoH) / haproxy / caddy / mitmproxy / squid / pki-init (auto-generates Ed25519 CA + per-service leaf certs into a docker volume); host port bindings dual-stack on `127.0.0.1` AND `[::1]`. `scripts/check-services.js` does host-side TCP / TLS handshake / SNTPv4 / DNS-A / Redis-PING / SMTP-banner / HTTP probes across every endpoint; `scripts/test-integration.js` exports the test CA via `docker cp` and sets `NODE_EXTRA_CA_CERTS` per-test child process so the framework's TLS verification stays strict (no `rejectUnauthorized: false` bypass anywhere in the test surface). **Test architecture rule** — live tests go in `test/integration/`, NEVER in `test/layer-N-*/`: smoke must remain pure (no docker dependency, runs in CI / on a developer laptop / inside prepack-guard) and a "skip silently when service is down" branch in a layer-N test makes the gate's pass count misleading and masks bugs that only surface against a live backend. The `0.6.27` `queue-redis.test.js` was moved to `test/integration/queue-redis.test.js` to enforce this. Smoke and wiki e2e green; integration suite ships green against the docker-compose stack.
12
13
  - **0.6.27** (2026-05-02) — Redis backend for `b.queue` so multi-replica apps can share a single queue without each needing to be cluster leader. **Bespoke RESP2 client** (`lib/redis-client.js`) — zero npm runtime deps. TCP via `node:net` + TLS via `node:tls` (`rediss://` auto-detected), legacy single-arg AUTH + ACL `AUTH user pass`, `SELECT db`, pipelining, exponential-backoff reconnect, EVAL helper. **`b.queue` protocol "redis"** (`lib/queue-redis.js`) — full enqueue/lease/extendLease/complete/fail/sweepExpired/size/purge/dlqList/dlqRetry/dlqSize parity with the local backend. Atomicity comes from server-side Lua scripts so concurrent consumers can't double-lease and a sweep can't race a complete. Storage layout: per-job HASH (sealed payload + lastError via `cryptoField.sealRow("_blamejs_jobs", row)` — same crypto config as the local backend), per-queue ready ZSET scored by availableAt, per-queue inflight ZSET scored by leaseExpiresAt, per-queue dlq ZSET scored by finishedAt, plus a queues SET so sweepExpired walks every known queue without a global secondary index. Cron-repeat handled in `complete()` JS — re-enqueues the next firing as a fresh jobId with availableAt=next-cron-fire. **`b.queue.bootFromEnv({ env })`** — env-driven init mirroring `b.network.bootFromEnv` and `b.logStream.bootFromEnv`. Reads `BLAMEJS_QUEUE_PROTOCOL` (`local`|`redis`), `BLAMEJS_QUEUE_REDIS_URL`, `BLAMEJS_QUEUE_REDIS_PASSWORD`, `BLAMEJS_QUEUE_REDIS_USERNAME`, `BLAMEJS_QUEUE_REDIS_TLS`, `BLAMEJS_QUEUE_REDIS_KEY_PREFIX`. Operators flip from local to Redis without a code change; both wiki docker-compose configs declare the new env knobs. Removed `redis` from `DEFERRED_PROTOCOLS`. **Out of scope for v1** (deferred to follow-up patches with explicit re-open conditions): Redis Cluster (slot-routing), Sentinel (managed primary failover), priority ordering on the Redis backend (queue-local supports `priority` opt; Redis backend orders strictly by availableAt for v1), flow children with `dependsOn` cascade. **Wiki**: queue-cache page documents the Redis backend opts schema, bootFromEnv, and the layout. **Tests**: 24 RESP2 protocol parser unit tests (`test/layer-0-primitives/redis-client.test.js`) cover URL parsing, command encoding (binary-safe), every reply type (simple string / error / integer / bulk / nil bulk / nested array / pipelined / incomplete-mid-frame). Live Redis round-trip tests (`test/layer-0-primitives/queue-redis.test.js`) cover enqueue+lease, availableAt scheduling, visibility-timeout sweep, fail+retry path, DLQ list/retry/size, extendLease, purge, and concurrent-leaser no-double-lease — skip cleanly when `BLAMEJS_TEST_REDIS_URL` is not set so the smoke suite passes on dev boxes without a Redis container. Smoke 6780 OK.
13
14
  - **0.6.26** (2026-05-02) — `blamejs restore` and `blamejs audit verify-chain` subcommands wrap the existing `b.restore` and `b.audit.verifyChain` primitives so operators can drive them from runbooks without writing app code. **`blamejs restore`**: `list` (enumerate bundles in storage), `inspect` (manifest summary without touching live data), `apply` (live in-place restore with rollback preserved), `rollback` (revert to most-recent OR named restore point), `list-rollbacks` (enumerate preserved rollback points). Two ways to identify a bundle — `--bundle <dir>` matches the shape `blamejs backup extract` produces (parent dir is treated as storage root, basename as bundle id), or `--storage-root <root> --bundle-id <id>` for multi-bundle stores. `apply` honors `--max-pulled-bytes` / `--max-pulled-files` (defaults 4 GiB / 100K), `--rollback-root` (default `<data-dir>.rollbacks`), `--no-audit`, and `BLAMEJS_BACKUP_PASSPHRASE` env. **`blamejs audit verify-chain`**: walks the live audit chain end-to-end, reports tampering with `breakAt` / `breakRowId` / expected-vs-actual prevHash; honours `--max-rows` to bound long walks; default table is `audit_log`. **Wiki CLI snapshot test now validates subcommand pairs**, not just top commands. Walks every wiki + README invocation of the form `blamejs <cmd> <sub>` and verifies that <sub> exists in the perCommand[<cmd>].subcommands list parsed from `lib/cli.js`. Surfaced one real drift on first run: `examples/wiki/seeders/prod/pages/backup-restore.js` documented `blamejs audit verify-signing` after vault rotation, but no such subcommand existed (only `verify-bundle`); fixed by shipping the new `verify-chain` subcommand and updating the wiki to reference it. Two top-level command gaps surfaced and fixed: `blamejs restore` (now real) and `blamejs network status` (was prose-promised in `network-config.js`; reworded to point at `b.network.snapshot()` for /healthz / custom diagnostics routes since wiring a CLI command for it is operator-side work). README CLI table updated with `restore` row and the two new audit subcommands.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/core",
3
- "version": "0.6.28",
3
+ "version": "0.6.29",
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:c6865ad2-35d9-413c-85ae-ddb9b7595c07",
5
+ "serialNumber": "urn:uuid:438bf95a-273c-4fba-b130-bb7dddcdb3de",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-05-02T17:54:24.793Z",
8
+ "timestamp": "2026-05-02T18:04:26.378Z",
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.6.28",
22
+ "bom-ref": "@blamejs/core@0.6.29",
23
23
  "type": "library",
24
24
  "name": "blamejs",
25
- "version": "0.6.28",
25
+ "version": "0.6.29",
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.6.28",
29
+ "purl": "pkg:npm/%40blamejs/core@0.6.29",
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.6.28",
57
+ "ref": "@blamejs/core@0.6.29",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]