@blamejs/core 0.7.91 → 0.7.93

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,10 @@ upgrading across more than a few patches at a time.
8
8
 
9
9
  ## v0.7.x
10
10
 
11
+ - **0.7.93** (2026-05-06) — Adjacent-regulation incident-reporting deadline reference exported on `b.dora`. **`b.dora.DEADLINES_NIS2`** — NIS2 (Directive (EU) 2022/2555) Art. 23 deadlines: 24h early warning, 72h initial notification, 1 month final report. **`b.dora.DEADLINES_CRA`** — CRA (Regulation (EU) 2024/2847) Art. 14 deadlines: 24h early warning, 72h initial notification, 14 days final report. **`b.dora.DEADLINES_HIPAA_BREACH`** — HIPAA Breach Notification Rule (45 CFR §164.404 / §164.408) deadlines: 60 days for affected individuals, 60 days for HHS Secretary, annual aggregate report by March 1 for sub-500-individual breaches. Operators handling NIS2 / CRA / HIPAA reporting reach for these constants instead of pinning literal hour counts in their workflow code; the values track the regulatory text and update with the framework rather than going stale in operator code. The b.dora factory itself continues to enforce DORA Article 19 deadlines unchanged — operators wiring NIS2 / CRA / HIPAA workflows compose against the deadline constants directly with their own scheduler / submission code.
12
+
13
+ - **0.7.92** (2026-05-06) — Retention floors + observability semconv expansion. **`b.retention.complianceFloor(<posture>, candidateMs)`** now recognizes `nis2` (3 years — NIS2 Art. 23 incident reporting), `cra` (5 years — CRA Art. 14 vulnerability handling logs), `lgpd-br` (5 years — Brazil fiscal record minimum + LGPD Art. 16), `appi-jp` (3 years — Japan APPI handler-of-record), `pdpa-sg` (1 year — PDPA breach notification audit trail), and `uk-gdpr` (6 years — UK ICO guidance + statutory limit alignment). `gdpr` continues to have no fixed minimum (Art. 5(1)(e) is "no longer than necessary" — operator-driven). **`b.observability.SEMCONV`** gains RPC attributes (`RPC_SYSTEM` / `RPC_SERVICE` / `RPC_METHOD` / `RPC_GRPC_STATUS_CODE`), additional messaging keys (`MESSAGING_CLIENT_ID` / `MESSAGING_MESSAGE_ID` / `MESSAGING_DESTINATION_PARTITION_ID` / `MESSAGING_BATCH_MESSAGE_COUNT`), network transport (`NETWORK_TRANSPORT` / `NETWORK_CONNECTION_TYPE`), process / runtime identification (`PROCESS_PID` / `PROCESS_RUNTIME_NAME` / `PROCESS_RUNTIME_VERSION`), service identification (`SERVICE_NAME` / `SERVICE_VERSION` / `SERVICE_INSTANCE_ID`), and telemetry SDK self-id (`TELEMETRY_SDK_NAME` / `TELEMETRY_SDK_LANGUAGE` / `TELEMETRY_SDK_VERSION`). Operators wiring the framework's tap into a gRPC-fronted OTel collector or an outbox-fed Kafka topic now reference the canonical attribute names directly without an aliasing table on their side.
14
+
11
15
  - **0.7.91** (2026-05-06) — Compliance-posture vocabulary expanded + OpenTelemetry semantic-convention attribute table. **`b.compliance.set(<posture>)`** now accepts thirteen new posture names: `wmhmda` (Washington My Health My Data Act), `bipa` (Illinois Biometric Information Privacy Act), `ccpa` (California Consumer Privacy Act), `nis2` (EU NIS2 Directive), `cra` (EU Cyber Resilience Act), `ai-act` (EU AI Act), `lgpd-br` (Brazil LGPD), `pipl-cn` (China PIPL), `appi-jp` (Japan APPI), `pdpa-sg` (Singapore PDPA), `pipeda-ca` (Canada PIPEDA), `uk-gdpr` (UK GDPR). Existing `hipaa` / `pci-dss` / `gdpr` / `soc2` / `dora` / `sox` continue to work. Postures map to per-primitive defaults via the existing compliancePosture opt on guards, retention, dora, etc. — operators set the deployment-wide posture once and primitives that key off it pick up the right defaults. **`b.observability.SEMCONV`** — frozen attribute-name table tracking the OpenTelemetry semantic-convention stable namespace (1.27+). HTTP server attributes (`http.request.method`, `http.response.status_code`, `http.route`, `server.address`, `client.address`), URL (`url.full`, `url.path`, `url.scheme`), database (`db.system`, `db.namespace`, `db.operation.name`, `db.query.text`), messaging (`messaging.system`, `messaging.destination.name`), auth (`user.id`, `session.id`), errors (`error.type`, `exception.type`, `exception.message`). Operators wiring the framework's tap into an OTel SDK reference these constants instead of hand-rolling the names — no aliasing table on the operator side, and string typos throw at access time instead of producing mis-named span attributes that the OTel collector silently drops.
12
16
 
13
17
  - **0.7.90** (2026-05-06) — `b.outbox` — transactional outbox primitive for at-least-once event publication without distributed transactions. **`b.outbox.create({ externalDb, table, publisher, ... })`** returns an outbox instance with three core operations: `enqueue(event, txn)` writes the outbox row inside the operator's transaction (using the `txClient` returned by `b.externalDb.transaction`), `start()` spins a polling publisher worker that claims rows via `SELECT ... FOR UPDATE SKIP LOCKED` (Postgres) and dispatches to the operator-supplied async `publisher(event)` callback, `stop()` gracefully shuts the worker down. Failed publishes retry with exponential backoff (`retryBackoff: { initialMs, maxMs, factor }`); rows that exceed `maxAttempts` are marked `'dead'` for operator triage and an `system.outbox.deadletter` audit event fires. Schema is operator-managed: `outbox.declareSchema(externalDb)` runs an idempotent `CREATE TABLE IF NOT EXISTS ... (id, topic, payload, key, headers, enqueued_at, next_attempt_at, published_at, attempts, last_error, status)` + a partial index on `(next_attempt_at) WHERE status = 'pending'`. `pendingCount()` / `deadCount()` expose the queue depth + DLQ depth for operator dashboards. Observability events on every state transition (`outbox.enqueued` / `outbox.published` / `outbox.publish-failed` / `outbox.dead-letter`).
package/lib/dora.js CHANGED
@@ -96,6 +96,39 @@ var INITIAL_REPORT_DEADLINE_MS = C.TIME.hours(24);
96
96
  var INTERMEDIATE_REPORT_DEADLINE_MS = C.TIME.hours(72);
97
97
  var FINAL_REPORT_DEADLINE_MS = C.TIME.days(30);
98
98
 
99
+ // Adjacent-regulation incident-reporting deadlines — operators wiring
100
+ // NIS2 / CRA / HIPAA breach notification reach for these constants
101
+ // rather than the b.dora-specific deadlines. The b.dora factory only
102
+ // uses INITIAL/INTERMEDIATE/FINAL above; these are reference data so
103
+ // operators don't pin literal hour counts in their code.
104
+ //
105
+ // NIS2 (Directive (EU) 2022/2555) Art. 23:
106
+ // 24h early warning → 72h initial notification → 1 month final
107
+ // CRA (Regulation (EU) 2024/2847) Art. 14:
108
+ // 24h early warning → 72h initial notification → 14 days final
109
+ // HIPAA Breach Notification Rule (45 CFR §164.404 / §164.408):
110
+ // 60 days to notify affected individuals
111
+ // 60 days to notify HHS Secretary (or "without unreasonable delay" if
112
+ // 500+ individuals — operator-driven, no hard deadline below 60 days)
113
+ // Annual report by Mar 1 for breaches of <500 individuals
114
+ var DEADLINES_NIS2 = Object.freeze({
115
+ earlyWarningMs: C.TIME.hours(24),
116
+ initialReportMs: C.TIME.hours(72),
117
+ finalReportMs: C.TIME.days(30),
118
+ });
119
+ var DEADLINES_CRA = Object.freeze({
120
+ earlyWarningMs: C.TIME.hours(24),
121
+ initialReportMs: C.TIME.hours(72),
122
+ finalReportMs: C.TIME.days(14),
123
+ });
124
+ var DEADLINES_HIPAA_BREACH = Object.freeze({
125
+ individualNoticeMs: C.TIME.days(60),
126
+ secretaryNoticeMs: C.TIME.days(60),
127
+ // Annual aggregate report due by March 1 of the year following any
128
+ // calendar year in which breaches affecting <500 individuals occurred.
129
+ annualAggregateMs: null,
130
+ });
131
+
99
132
  var VALID_DATA_AFFECTED = ["phi", "financial", "personal", "operational", "none"];
100
133
  var VALID_SEVERITY = ["critical", "high", "medium", "low"];
101
134
  var VALID_REPUTATIONAL = ["media", "internal", "none"];
@@ -343,5 +376,8 @@ module.exports = {
343
376
  INITIAL_REPORT_DEADLINE_MS: INITIAL_REPORT_DEADLINE_MS,
344
377
  INTERMEDIATE_REPORT_DEADLINE_MS: INTERMEDIATE_REPORT_DEADLINE_MS,
345
378
  FINAL_REPORT_DEADLINE_MS: FINAL_REPORT_DEADLINE_MS,
379
+ DEADLINES_NIS2: DEADLINES_NIS2,
380
+ DEADLINES_CRA: DEADLINES_CRA,
381
+ DEADLINES_HIPAA_BREACH: DEADLINES_HIPAA_BREACH,
346
382
  DoraError: DoraError,
347
383
  };
@@ -195,6 +195,31 @@ var SEMCONV = Object.freeze({
195
195
  EXCEPTION_TYPE: "exception.type",
196
196
  EXCEPTION_MESSAGE: "exception.message",
197
197
  EXCEPTION_STACKTRACE: "exception.stacktrace",
198
+ // RPC
199
+ RPC_SYSTEM: "rpc.system",
200
+ RPC_SERVICE: "rpc.service",
201
+ RPC_METHOD: "rpc.method",
202
+ RPC_GRPC_STATUS_CODE: "rpc.grpc.status_code",
203
+ // Messaging — additional client/server attrs
204
+ MESSAGING_CLIENT_ID: "messaging.client.id",
205
+ MESSAGING_MESSAGE_ID: "messaging.message.id",
206
+ MESSAGING_DESTINATION_PARTITION_ID: "messaging.destination.partition.id",
207
+ MESSAGING_BATCH_MESSAGE_COUNT: "messaging.batch.message_count",
208
+ // Network — transport / connection state
209
+ NETWORK_TRANSPORT: "network.transport",
210
+ NETWORK_CONNECTION_TYPE: "network.connection.type",
211
+ // Process / runtime
212
+ PROCESS_PID: "process.pid",
213
+ PROCESS_RUNTIME_NAME: "process.runtime.name",
214
+ PROCESS_RUNTIME_VERSION: "process.runtime.version",
215
+ // Service identification
216
+ SERVICE_NAME: "service.name",
217
+ SERVICE_VERSION: "service.version",
218
+ SERVICE_INSTANCE_ID: "service.instance.id",
219
+ // Telemetry SDK self-identification
220
+ TELEMETRY_SDK_NAME: "telemetry.sdk.name",
221
+ TELEMETRY_SDK_LANGUAGE: "telemetry.sdk.language",
222
+ TELEMETRY_SDK_VERSION: "telemetry.sdk.version",
198
223
  });
199
224
 
200
225
  module.exports = {
package/lib/retention.js CHANGED
@@ -445,11 +445,17 @@ function create(opts) {
445
445
  // SOC 2 (CC1–CC9) — 1 year typical; auditor-driven
446
446
  // DORA Art. 17 (incident logs) — 5 years
447
447
  var COMPLIANCE_RETENTION_FLOOR_MS = Object.freeze({
448
- "pci-dss": C.TIME.days(365), // 12 months
449
- "hipaa": C.TIME.days(365 * 6), // 6 years
450
- "sox": C.TIME.days(365 * 7), // 7 years
451
- "soc2": C.TIME.days(365), // 1 year
452
- "dora": C.TIME.days(365 * 5), // 5 years (Article 17 incident logs)
448
+ "pci-dss": C.TIME.days(365), // 12 months — PCI-DSS §10.7.1
449
+ "hipaa": C.TIME.days(365 * 6), // 6 years — 45 CFR §164.316(b)(2)(i)
450
+ "sox": C.TIME.days(365 * 7), // 7 years — Sarbanes-Oxley §802
451
+ "soc2": C.TIME.days(365), // 1 year — typical SOC 2 audit window
452
+ "dora": C.TIME.days(365 * 5), // 5 years — DORA Article 17 incident logs
453
+ "nis2": C.TIME.days(365 * 3), // 3 years — NIS2 Art. 23 incident reporting
454
+ "cra": C.TIME.days(365 * 5), // 5 years — CRA Art. 14 vulnerability handling logs
455
+ "lgpd-br": C.TIME.days(365 * 5), // 5 years — Brazil LGPD Art. 16 + fiscal-record minimum
456
+ "appi-jp": C.TIME.days(365 * 3), // 3 years — Japan APPI handler-of-record requirement
457
+ "pdpa-sg": C.TIME.days(365 * 1), // 1 year — PDPA breach-notification audit trail
458
+ "uk-gdpr": C.TIME.days(365 * 6), // 6 years — UK ICO guidance, statutory limit alignment
453
459
  });
454
460
 
455
461
  // Operator passes a posture name + a candidate ttlMs; returns the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/core",
3
- "version": "0.7.91",
3
+ "version": "0.7.93",
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:6f73b142-9c72-4abc-84d6-2ae27582baa7",
5
+ "serialNumber": "urn:uuid:1c2e15ca-bff7-43a5-ae92-d24199759193",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-05-06T07:57:14.212Z",
8
+ "timestamp": "2026-05-06T08:15:13.953Z",
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.7.91",
22
+ "bom-ref": "@blamejs/core@0.7.93",
23
23
  "type": "library",
24
24
  "name": "blamejs",
25
- "version": "0.7.91",
25
+ "version": "0.7.93",
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.7.91",
29
+ "purl": "pkg:npm/%40blamejs/core@0.7.93",
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.7.91",
57
+ "ref": "@blamejs/core@0.7.93",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]