@blamejs/core 0.7.102 → 0.7.104
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/index.js +2 -0
- package/lib/audit.js +1 -0
- package/lib/dsr.js +953 -0
- package/lib/guard-mime.js +3 -2
- package/lib/middleware/headers.js +3 -2
- package/lib/middleware/index.js +8 -2
- package/lib/middleware/span-http-server.js +243 -0
- package/lib/middleware/trace-log-correlation.js +134 -0
- package/lib/middleware/trace-propagate.js +9 -0
- package/lib/observability-otlp-exporter.js +351 -0
- package/lib/observability-tracer.js +395 -0
- package/lib/observability.js +230 -6
- package/lib/safe-buffer.js +15 -0
- package/package.json +1 -1
- package/sbom.cyclonedx.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,10 @@ upgrading across more than a few patches at a time.
|
|
|
8
8
|
|
|
9
9
|
## v0.7.x
|
|
10
10
|
|
|
11
|
+
- **0.7.104** (2026-05-06) — `b.dsr` Data Subject Rights workflow primitive (~2000 LoC). End-to-end coordinator for GDPR Article 15-22 / CCPA / CPRA / LGPD / PIPEDA / UK-GDPR data-subject requests. **`b.dsr.create({ ticketStore, posture, identityResolver, sources, ... })`** returns a workflow instance with full ticket lifecycle: `submit(input)` resolves subject identity via the operator-supplied `identityResolver`, computes a posture-aware deadline (gdpr 30d / ccpa 45d / lgpd-br 15d / pipl-cn 15d / pipeda-ca 30d / appi-jp 30d / pdpa-sg 30d / uk-gdpr 30d), and persists a pending ticket. `process(ticketId, opts)` orchestrates per-source `query` (for access / portability / rectification) or `erase` (for erasure) callbacks; partial source failures land the ticket in `partially_completed` state with per-source error capture. `cancel` / `reject` (with required reason per GDPR) advance to terminal states. `expireOverdue()` sweep marks deadline-overdue tickets as `expired`. Seven request types: `access` / `erasure` / `portability` / `rectification` / `restriction` / `object` / `automated-decision`. **Verification ladder** (`minimal` / `secondary` / `strong`) per GDPR Art. 12(6) — minimum required level by request type with operator override; erasure / portability / rectification require `secondary` by default. **Receipt builder** (`buildReceipt(ticketId)`) — emits a canonical `blamejs.dsr.receipt/1` JSON envelope for completed/cancelled/rejected/expired tickets with optional operator-side `receiptSigner` hook for cryptographic attestation. **Portability bundle builder** (`buildPortabilityBundle(ticket)`) — `blamejs.dsr.portability/1` JSON shape with per-source data for access / portability requests. **Two ticket-store backends** ship: `memoryTicketStore()` for development / tests, `dbTicketStore({ db, table })` for production (auto-provisions a SQLite table with subject_email + status indexes, includes a `purgeExpired()` retention sweep). Audit emissions on every state transition (`dsr.ticket.submitted` / `in_progress` / `completed` / `partial` / `cancelled` / `rejected` / `expired` plus per-source `dsr.source.queried` / `erased` / `failed`). Test coverage: 38 cases across submit / process / cancel / reject / list / expire / portability / verification ladder / receipt / store backends.
|
|
12
|
+
|
|
13
|
+
- **0.7.103** (2026-05-06) — W3C distributed tracing suite. End-to-end OTel-shaped tracing without a vendored OTel SDK: tracestate + Baggage parsers, span builder, OTLP/JSON exporter, HTTP-server span middleware, log correlation. **`b.observability.traceContext.parseTracestate / buildTracestate`** — W3C Trace Context §3.3 vendor data: enforces vendor-key shape (lcase-alnum + `_-*/`, optional `<tenant>@<system>`), value charset (printable ASCII excluding `,` and `=`), 32-entry cap, 512-char total cap, dup-key-keep-first per §3.3.1.5. **`b.observability.baggage.parse / build`** — W3C Baggage spec parser + builder for operator-supplied context (tenantId, region, experimentId, etc.) propagated across service boundaries. RFC 7230 tchar key grammar, percent-encoded UTF-8 values, optional per-entry properties (`key=value;property=value`), 64-entry / 8192-char caps. **`b.observability.tracer.create({ service, resource, onEnd })`** — OTel-shaped span builder. `tracer.start(name, opts)` returns a span with `setAttribute` / `setAttributes` / `addEvent` / `recordException` / `setStatus` / `end` / `isRecording` / `toJSON`. OTLP/JSON-compatible output (Trace v1) with `traceId` / `spanId` / `parentSpanId` / `name` / `kind` / `startTimeUnixNano` / `endTimeUnixNano` / `attributes` / `events` / `status` / `resource` / `scope` / `droppedAttributesCount` / `droppedEventsCount`. Attribute caps (128 keys, 1024-char values), event cap (128) per OTLP defaults. `tracer.startChildOf(parent, name)` derives child spans sharing the trace context. **`b.observability.tracer.spanToTraceparent(span)`** — emits the canonical W3C `traceparent` for outbound propagation. **`b.observability.otlpExporter.create({ endpoint, ... })`** — buffered OTLP/HTTP JSON span exporter. Batches spans (default 200), flushes on size + interval (default 5s), retries 5xx + 408/429 with exponential backoff, drops oldest on queue overflow (default 4096). Custom `fetchImpl` opt for testing or non-default HTTP transports; `allowedProtocols` opt for cleartext dev collectors. **`b.middleware.tracePropagate`** extended to also read inbound `tracestate` and stamp `req.trace.tracestate` as the parsed entries array (or `[]` when missing); when `setResponseHeader: true`, echoes both `traceparent` and `tracestate` on the response. **`b.middleware.spanHttpServer({ tracer, ... })`** — auto-creates a root server span per HTTP request, populates OTel `SEMCONV.HTTP_*` / `URL_*` / `SERVER_*` / `CLIENT_*` attributes, attaches the span to `req.span`, ends on response close, fires `onEnd(span.toJSON())` for export. `ignorePaths` (string + RegExp) keeps healthz / static-asset routes out of span volume; `captureRequestHeaders` / `captureResponseHeaders` lift named headers into the span as `http.request.header.*` / `http.response.header.*` attributes. **`b.middleware.traceLogCorrelation({ logger })`** — wraps a `b.log` instance for the request lifetime so every `info()` / `warn()` / `error()` / etc. emission inside the handler auto-includes `trace_id` + `span_id` from the active context (via `req.trace` + `req.span`). Pass-through when no trace context present. Internal sweep: `safeBuffer.TRACE_ID_HEX_RE` / `SPAN_ID_HEX_RE` / `RFC7230_TCHAR_RE` extracted as shared regex constants; `guard-mime` / `middleware/headers` / `observability` consolidated against the new shared constants.
|
|
14
|
+
|
|
11
15
|
- **0.7.102** (2026-05-06) — `b.middleware.tracePropagate({ generateIfMissing, ... })` — middleware that consumes the inbound `traceparent` header per W3C Trace Context and stamps `req.trace = { traceId, parentId, sampled, hadUpstream }` for downstream handlers + propagation into outbound HTTP calls. `generateIfMissing: true` (default) synthesises a fresh trace when the inbound header is missing/malformed and stamps `hadUpstream: false`. `auditOnMissing: true` emits `system.trace.synthesised` audit events on every locally-originated trace. `setResponseHeader: true` echoes the resolved traceparent on the response (useful when the framework is the back-end of an L7 router that wants to log it). Composes with `b.observability.traceContext` (v0.7.101) for outbound propagation: downstream handlers read `req.trace.traceId` and pass it to `traceContext.build({ traceId: req.trace.traceId, parentId: traceContext.newParentId(), sampled: req.trace.sampled })` for the `traceparent` header on upstream calls.
|
|
12
16
|
|
|
13
17
|
- **0.7.101** (2026-05-06) — `b.observability.traceContext` — W3C Trace Context (https://www.w3.org/TR/trace-context-1/) parser + builder. **`traceContext.parse(headerValue)`** consumes a `traceparent` HTTP header value (`00-<32hex traceId>-<16hex parentId>-<2hex flags>`) and returns `{ version, traceId, parentId, flags, sampled }` or null on malformed input. Enforces the §3.2.2.3 / §3.2.2.4 all-zero-rejection rule (zero trace-id and zero parent-id are explicitly forbidden by spec). **`traceContext.build({ traceId, parentId, sampled })`** produces a v1 `traceparent` header value; throws on bad input shape. **`traceContext.newTraceId()` / `newParentId()`** generate fresh randomized 128-bit / 64-bit hex strings (with the all-zero retry path the spec requires). Operators wiring distributed tracing across services use these to propagate trace IDs across an outbound HTTP call without a vendored OTel SDK — pair with the SEMCONV constants from v0.7.95 to build OTel-aligned spans on top.
|
package/index.js
CHANGED
|
@@ -213,6 +213,7 @@ var dualControl = require("./lib/dual-control");
|
|
|
213
213
|
var retention = require("./lib/retention");
|
|
214
214
|
var network = require("./lib/network");
|
|
215
215
|
var cloudEvents = require("./lib/cloud-events");
|
|
216
|
+
var dsr = require("./lib/dsr");
|
|
216
217
|
var outbox = require("./lib/outbox");
|
|
217
218
|
|
|
218
219
|
module.exports = {
|
|
@@ -361,6 +362,7 @@ module.exports = {
|
|
|
361
362
|
retention: retention,
|
|
362
363
|
network: network,
|
|
363
364
|
cloudEvents: cloudEvents,
|
|
365
|
+
dsr: dsr,
|
|
364
366
|
outbox: outbox,
|
|
365
367
|
ntpCheck: ntpCheck,
|
|
366
368
|
version: constants.version,
|
package/lib/audit.js
CHANGED
|
@@ -210,6 +210,7 @@ var FRAMEWORK_NAMESPACES = [
|
|
|
210
210
|
// (role-switching, RLS-shaped events)
|
|
211
211
|
"dkim", // b.mail.dkim (DKIM-Signature generation events)
|
|
212
212
|
"dora", // b.dora (DORA Article 17: dora.incident.classified / reported / draftFinal)
|
|
213
|
+
"dsr", // b.dsr (Data Subject Rights workflow: dsr.ticket.* / dsr.source.*)
|
|
213
214
|
"dual", // b.dualControl (dual.grant.requested / approved / denied / consumed / expired / self_approval_denied)
|
|
214
215
|
"mail", // b.mail (b.mail-bounce uses "system.mail.*")
|
|
215
216
|
"network", // b.middleware.networkAllowlist (network.gate.denied)
|