@blamejs/core 0.7.95 → 0.7.96

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.7.x
10
10
 
11
+ - **0.7.96** (2026-05-06) — `b.observability.timed(name, fn, labels)` — convenience wrapper that measures wall-clock duration of a sync or async operation and emits a counter event carrying `duration_ms` in the labels alongside `outcome: "ok" | "fail"`. Returns the wrapped function's return value verbatim; rethrows on error after emitting the failure event with `error_type` capturing the thrown error's `.name`. Operators previously hand-rolled `var t0 = Date.now(); var r = await fn(); event(name, 1, { ...labels, duration_ms: Date.now() - t0, outcome: "ok" })` patterns at every call site — `timed` is the consolidated form. Composes with the existing `b.observability.SEMCONV` constants: `b.observability.timed("db.query", async () => db.query("SELECT ..."), { [SEMCONV.DB_OPERATION_NAME]: "select" })`. Operation name MUST be a stable string (not derived from input) to keep metric cardinality bounded; dynamic per-tenant labels go in the `labels` parameter.
12
+
11
13
  - **0.7.95** (2026-05-06) — `b.observability.SEMCONV` GenAI + cloud + container coverage. Twenty-eight new attribute names tracking OpenTelemetry semantic conventions for generative AI workloads, vector databases, cloud runtime context, and Kubernetes orchestration. **GenAI:** `GEN_AI_SYSTEM` / `GEN_AI_REQUEST_MODEL` / `GEN_AI_REQUEST_TEMPERATURE` / `GEN_AI_REQUEST_TOP_P` / `GEN_AI_REQUEST_TOP_K` / `GEN_AI_REQUEST_MAX_TOKENS` / `GEN_AI_REQUEST_STOP_SEQUENCES` / `GEN_AI_RESPONSE_MODEL` / `GEN_AI_RESPONSE_ID` / `GEN_AI_RESPONSE_FINISH_REASONS` / `GEN_AI_USAGE_INPUT_TOKENS` / `GEN_AI_USAGE_OUTPUT_TOKENS` / `GEN_AI_USAGE_TOTAL_TOKENS` / `GEN_AI_OPERATION_NAME` / `GEN_AI_TOOL_NAME` / `GEN_AI_TOOL_CALL_ID` / `GEN_AI_AGENT_ID` / `GEN_AI_AGENT_NAME` / `GEN_AI_AGENT_DESCRIPTION`. **Vector DB / RAG:** `DB_VECTOR_QUERY_TOP_K` / `DB_VECTOR_QUERY_DIMENSIONS` / `DB_VECTOR_QUERY_DISTANCE_METRIC`. **Cloud:** `CLOUD_PROVIDER` / `CLOUD_REGION` / `CLOUD_ACCOUNT_ID` / `CLOUD_RESOURCE_ID`. **Container / K8s:** `CONTAINER_ID` / `CONTAINER_IMAGE_NAME` / `CONTAINER_IMAGE_TAG` / `K8S_NAMESPACE_NAME` / `K8S_POD_NAME` / `K8S_DEPLOYMENT_NAME`. Operators wiring LLM client telemetry, vector-DB query traces, or Kubernetes-deployed services to an OTel collector reference these constants directly — string typos throw at access time instead of producing mis-named span attributes the OTel collector silently drops.
12
14
 
13
15
  - **0.7.94** (2026-05-06) — `b.compliance.REGIME_MAP` + `b.compliance.describe(<posture>)` — frozen lookup table mapping each posture name to its human-readable name + statutory citation + jurisdiction + domain. `b.compliance.describe("hipaa")` returns `{ name: "Health Insurance Portability and Accountability Act", citation: "Pub. L. 104-191; 45 CFR Parts 160, 162, 164", jurisdiction: "US", domain: "health" }`. Operators rendering the deployment posture in admin UI / audit logs reach for `REGIME_MAP[posture]` instead of hand-rolling a lookup table; values track the regulatory text and update with the framework rather than going stale in operator code. Covers all 19 postures shipped through v0.7.91 (hipaa / pci-dss / soc2 / sox + the v0.7.91 expansions: wmhmda / bipa / ccpa / gdpr / dora / nis2 / cra / ai-act / lgpd-br / pipl-cn / appi-jp / pdpa-sg / pipeda-ca / uk-gdpr). `domain` field categorizes the regime (privacy / health / payment / cybersecurity / financial-reporting / etc.) so operators can render compliance dashboards grouped by domain instead of alphabetical posture.
@@ -143,6 +143,57 @@ function safeEvent(name, value, labels) {
143
143
  catch (_e) { /* hot-path observability sink — drops silent on internal throws */ }
144
144
  }
145
145
 
146
+ // timed — convenience wrapper that measures wall-clock duration of a
147
+ // sync or async operation and emits a counter event with
148
+ // duration_ms in the labels. Returns the wrapped function's return
149
+ // value verbatim; rethrows on error after emitting the failure event
150
+ // with outcome: "fail".
151
+ //
152
+ // var rows = await b.observability.timed("db.query", async function () {
153
+ // return await db.query("SELECT * FROM users");
154
+ // }, { [SEMCONV.DB_OPERATION_NAME]: "select" });
155
+ //
156
+ // On success: emits `<name>` with { ...labels, outcome: "ok",
157
+ // duration_ms }. On throw: emits with outcome: "fail".
158
+ //
159
+ // The operation name MUST be a stable string (not derived from input)
160
+ // to keep the metric cardinality bounded; operators dynamically
161
+ // scope-naming via prefix should use the labels parameter instead.
162
+ function timed(name, fn, labels) {
163
+ if (typeof name !== "string" || name.length === 0) {
164
+ throw new TypeError("observability.timed: name must be a non-empty string");
165
+ }
166
+ if (typeof fn !== "function") {
167
+ throw new TypeError("observability.timed: fn must be a function");
168
+ }
169
+ var start = Date.now();
170
+ function _emit(outcome, extra) {
171
+ var allLabels = Object.assign({}, labels || {}, {
172
+ outcome: outcome,
173
+ duration_ms: Date.now() - start,
174
+ }, extra || {});
175
+ try { event(name, 1, allLabels); }
176
+ catch (_e) { /* drop-silent — observability sink */ }
177
+ }
178
+ var ret;
179
+ try { ret = fn(); }
180
+ catch (e) {
181
+ _emit("fail", { error_type: (e && e.name) || "Error" });
182
+ throw e;
183
+ }
184
+ if (ret && typeof ret.then === "function") {
185
+ return ret.then(
186
+ function (v) { _emit("ok"); return v; },
187
+ function (e) {
188
+ _emit("fail", { error_type: (e && e.name) || "Error" });
189
+ throw e;
190
+ }
191
+ );
192
+ }
193
+ _emit("ok");
194
+ return ret;
195
+ }
196
+
146
197
  // OpenTelemetry semantic-convention attribute names — the operator-
147
198
  // facing canonical vocabulary the framework's b.observability /
148
199
  // b.tracing / b.metrics emitters use when building span / metric
@@ -265,6 +316,7 @@ module.exports = {
265
316
  tap: tap,
266
317
  event: event,
267
318
  safeEvent: safeEvent,
319
+ timed: timed,
268
320
  setTap: setTap,
269
321
  SEMCONV: SEMCONV,
270
322
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/core",
3
- "version": "0.7.95",
3
+ "version": "0.7.96",
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:3787e423-1b20-4099-9ab6-2794f46a4b23",
5
+ "serialNumber": "urn:uuid:f930dea4-02bf-424a-81d9-af05bce63d00",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-05-06T08:34:31.373Z",
8
+ "timestamp": "2026-05-06T08:44:44.540Z",
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.95",
22
+ "bom-ref": "@blamejs/core@0.7.96",
23
23
  "type": "library",
24
24
  "name": "blamejs",
25
- "version": "0.7.95",
25
+ "version": "0.7.96",
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.95",
29
+ "purl": "pkg:npm/%40blamejs/core@0.7.96",
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.95",
57
+ "ref": "@blamejs/core@0.7.96",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]