@superblocksteam/telemetry 2.0.129 → 2.0.130-next.1

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.
Files changed (62) hide show
  1. package/README.md +27 -12
  2. package/dist/common/index.d.ts +0 -2
  3. package/dist/common/index.d.ts.map +1 -1
  4. package/dist/common/index.js +0 -2
  5. package/dist/common/index.js.map +1 -1
  6. package/dist/index.d.ts +1 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +2 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/npm-registry/emitter.d.ts +227 -0
  11. package/dist/npm-registry/emitter.d.ts.map +1 -0
  12. package/dist/npm-registry/emitter.js +402 -0
  13. package/dist/npm-registry/emitter.js.map +1 -0
  14. package/dist/npm-registry/index.d.ts +12 -0
  15. package/dist/npm-registry/index.d.ts.map +1 -0
  16. package/dist/npm-registry/index.js +28 -0
  17. package/dist/npm-registry/index.js.map +1 -0
  18. package/dist/{common/sanitize-npm-attributes.d.ts → npm-registry/sanitize.d.ts} +19 -1
  19. package/dist/npm-registry/sanitize.d.ts.map +1 -0
  20. package/dist/{common/sanitize-npm-attributes.js → npm-registry/sanitize.js} +50 -2
  21. package/dist/npm-registry/sanitize.js.map +1 -0
  22. package/dist/npm-registry/spans.d.ts +61 -0
  23. package/dist/npm-registry/spans.d.ts.map +1 -0
  24. package/dist/npm-registry/spans.js +91 -0
  25. package/dist/npm-registry/spans.js.map +1 -0
  26. package/dist-esm/common/index.d.ts +0 -2
  27. package/dist-esm/common/index.d.ts.map +1 -1
  28. package/dist-esm/common/index.js +0 -2
  29. package/dist-esm/common/index.js.map +1 -1
  30. package/dist-esm/index.d.ts +1 -0
  31. package/dist-esm/index.d.ts.map +1 -1
  32. package/dist-esm/index.js +2 -0
  33. package/dist-esm/index.js.map +1 -1
  34. package/dist-esm/npm-registry/emitter.d.ts +227 -0
  35. package/dist-esm/npm-registry/emitter.d.ts.map +1 -0
  36. package/dist-esm/npm-registry/emitter.js +392 -0
  37. package/dist-esm/npm-registry/emitter.js.map +1 -0
  38. package/dist-esm/npm-registry/index.d.ts +12 -0
  39. package/dist-esm/npm-registry/index.d.ts.map +1 -0
  40. package/dist-esm/npm-registry/index.js +12 -0
  41. package/dist-esm/npm-registry/index.js.map +1 -0
  42. package/dist-esm/{common/sanitize-npm-attributes.d.ts → npm-registry/sanitize.d.ts} +19 -1
  43. package/dist-esm/npm-registry/sanitize.d.ts.map +1 -0
  44. package/dist-esm/{common/sanitize-npm-attributes.js → npm-registry/sanitize.js} +49 -2
  45. package/dist-esm/npm-registry/sanitize.js.map +1 -0
  46. package/dist-esm/npm-registry/spans.d.ts +61 -0
  47. package/dist-esm/npm-registry/spans.d.ts.map +1 -0
  48. package/dist-esm/npm-registry/spans.js +86 -0
  49. package/dist-esm/npm-registry/spans.js.map +1 -0
  50. package/package.json +4 -4
  51. package/dist/common/npm-install-metrics.d.ts +0 -88
  52. package/dist/common/npm-install-metrics.d.ts.map +0 -1
  53. package/dist/common/npm-install-metrics.js +0 -140
  54. package/dist/common/npm-install-metrics.js.map +0 -1
  55. package/dist/common/sanitize-npm-attributes.d.ts.map +0 -1
  56. package/dist/common/sanitize-npm-attributes.js.map +0 -1
  57. package/dist-esm/common/npm-install-metrics.d.ts +0 -88
  58. package/dist-esm/common/npm-install-metrics.d.ts.map +0 -1
  59. package/dist-esm/common/npm-install-metrics.js +0 -135
  60. package/dist-esm/common/npm-install-metrics.js.map +0 -1
  61. package/dist-esm/common/sanitize-npm-attributes.d.ts.map +0 -1
  62. package/dist-esm/common/sanitize-npm-attributes.js.map +0 -1
@@ -0,0 +1,86 @@
1
+ /**
2
+ * NPM Registry Spans (APPS-4378)
3
+ *
4
+ * OTel-native `startActiveSpan` helpers for the four named npm-registry spans.
5
+ * Using the global tracer (`trace.getTracer`) means LLMObs interop is
6
+ * automatic: a span started inside an `@llmobs.decorate`'d context becomes a
7
+ * child of that task span (shared global tracer provider); outside any LLMObs
8
+ * context (server verify, CLI bootstrap) it is a root span.
9
+ *
10
+ * `org_id` rides on spans (per-trace context), never on a metric label. Raw
11
+ * registry hostnames are bucketed via {@link bucketNpmRegistryHost} before
12
+ * they reach a span attribute, matching the metric path — the one exception
13
+ * is the structured-log path, which keeps the raw host (see
14
+ * {@link auditNpmRegistryHost} in ./sanitize).
15
+ */
16
+ import { SpanStatusCode, trace, } from "@opentelemetry/api";
17
+ /** Instrumentation scope for every npm-registry span. */
18
+ const TRACER_NAME = "superblocks.npm-registry";
19
+ /** The four named spans (APPS-4378). */
20
+ export const NPM_REGISTRY_SPAN = {
21
+ VERIFY: "npm_registry.verify",
22
+ LOOKUP_PACKAGE: "npm_registry.lookup_package",
23
+ PREPARE_FOR_PRIVATE_REGISTRY: "npm_registry.prepare_for_private_registry",
24
+ SYNC_HOME_NPMRC: "npm_registry.sync_home_npmrc",
25
+ };
26
+ /**
27
+ * Canonical span-attribute keys, shared across the four spans so the
28
+ * dimension names never drift between call sites.
29
+ */
30
+ export const NPM_REGISTRY_SPAN_ATTR = {
31
+ ORG_ID: "org_id",
32
+ /** Bucketed (`public_npm | private | unknown`) — never the raw host. */
33
+ REGISTRY_HOST: "registry_host",
34
+ OUTCOME: "outcome",
35
+ DURATION_MS: "duration_ms",
36
+ /** Richer `NpmRegistryFetchResult.source` for drill-down. */
37
+ SOURCE: "source",
38
+ REGISTRY_CONFIGURED: "registry_configured",
39
+ /** Tri-valued: `true | false | "unknown"`. */
40
+ ALLOW_INSTALL_SCRIPTS: "allow_install_scripts",
41
+ PACKAGE_NAME_BUCKET: "package_name_bucket",
42
+ /** Span-attribute ONLY — raw byte counts are unbounded, never a metric label. */
43
+ PACKAGE_UNPACKED_SIZE_BYTES: "package_unpacked_size_bytes",
44
+ };
45
+ /**
46
+ * Start an active npm-registry span over the global tracer, run `fn`, and
47
+ * end the span in `finally`. On throw, the error is recorded
48
+ * (`span.recordException`) and the span status set to ERROR before the throw
49
+ * propagates. `fn` receives the span so it can attach final attributes
50
+ * (outcome / duration) once the operation resolves.
51
+ */
52
+ export async function withNpmRegistrySpan(spanName, initialAttributes, fn) {
53
+ const tracer = trace.getTracer(TRACER_NAME);
54
+ return tracer.startActiveSpan(spanName, async (span) => {
55
+ if (Object.keys(initialAttributes).length > 0) {
56
+ span.setAttributes(initialAttributes);
57
+ }
58
+ try {
59
+ return await fn(span);
60
+ }
61
+ catch (err) {
62
+ // `recordException` accepts Error | string; narrow rather than cast.
63
+ span.recordException(err instanceof Error ? err : String(err));
64
+ span.setStatus({ code: SpanStatusCode.ERROR });
65
+ throw err;
66
+ }
67
+ finally {
68
+ span.end();
69
+ }
70
+ });
71
+ }
72
+ /**
73
+ * Coerce a registry-reported `dist.unpackedSize` to a span-safe value: a
74
+ * finite, non-negative number, else `undefined`. A hostile or buggy registry
75
+ * cannot smuggle a non-numeric byte count onto the span through this guard.
76
+ *
77
+ * Callers MUST omit the attribute when this returns `undefined` rather than
78
+ * calling `setAttribute(key, undefined)` (some OTel exporters mishandle
79
+ * undefined values). The lookup call site guards with `if (size !== undefined)`.
80
+ */
81
+ export function npmPackageUnpackedSizeBytes(raw) {
82
+ return typeof raw === "number" && Number.isFinite(raw) && raw >= 0
83
+ ? raw
84
+ : undefined;
85
+ }
86
+ //# sourceMappingURL=spans.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spans.js","sourceRoot":"","sources":["../../src/npm-registry/spans.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAGL,cAAc,EACd,KAAK,GACN,MAAM,oBAAoB,CAAC;AAE5B,yDAAyD;AACzD,MAAM,WAAW,GAAG,0BAA0B,CAAC;AAE/C,wCAAwC;AACxC,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,MAAM,EAAE,qBAAqB;IAC7B,cAAc,EAAE,6BAA6B;IAC7C,4BAA4B,EAAE,2CAA2C;IACzE,eAAe,EAAE,8BAA8B;CACvC,CAAC;AAEX;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,MAAM,EAAE,QAAQ;IAChB,wEAAwE;IACxE,aAAa,EAAE,eAAe;IAC9B,OAAO,EAAE,SAAS;IAClB,WAAW,EAAE,aAAa;IAC1B,6DAA6D;IAC7D,MAAM,EAAE,QAAQ;IAChB,mBAAmB,EAAE,qBAAqB;IAC1C,8CAA8C;IAC9C,qBAAqB,EAAE,uBAAuB;IAC9C,mBAAmB,EAAE,qBAAqB;IAC1C,iFAAiF;IACjF,2BAA2B,EAAE,6BAA6B;CAClD,CAAC;AAEX;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,QAAgB,EAChB,iBAA6B,EAC7B,EAA8B;IAE9B,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAC5C,OAAO,MAAM,CAAC,eAAe,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACrD,IAAI,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9C,IAAI,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC;QACxC,CAAC;QACD,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,qEAAqE;YACrE,IAAI,CAAC,eAAe,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC/D,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,KAAK,EAAE,CAAC,CAAC;YAC/C,MAAM,GAAG,CAAC;QACZ,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,GAAG,EAAE,CAAC;QACb,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,2BAA2B,CAAC,GAAY;IACtD,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;QAChE,CAAC,CAAC,GAAG;QACL,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superblocksteam/telemetry",
3
- "version": "2.0.129",
3
+ "version": "2.0.130-next.1",
4
4
  "description": "Superblocks Telemetry - Canonical OTEL bootstrap with tier-aware policy enforcement",
5
5
  "license": "Superblocks Community Software License",
6
6
  "repository": {
@@ -72,17 +72,17 @@
72
72
  "chokidar-cli": "^3.0.0",
73
73
  "eslint": "^9.39.1",
74
74
  "eslint-config-prettier": "^10.1.8",
75
- "eslint-config-turbo": "^2.6.1",
75
+ "eslint-config-turbo": "^2.9.16",
76
76
  "globals": "^16.5.0",
77
77
  "pino": "^8.0.0",
78
78
  "premove": "^4.0.0",
79
79
  "typescript": "^6.0.3",
80
80
  "typescript-eslint": "^8.47.0",
81
81
  "vitest": "^2.0.0",
82
- "@superblocksteam/shared": "0.9590.9"
82
+ "@superblocksteam/shared": "0.9591.1"
83
83
  },
84
84
  "peerDependencies": {
85
- "@superblocksteam/shared": "0.9590.9"
85
+ "@superblocksteam/shared": "0.9591.1"
86
86
  },
87
87
  "engines": {
88
88
  "node": ">=24"
@@ -1,88 +0,0 @@
1
- /**
2
- * NPM Install Metrics (APPS-4189 / P6.2)
3
- *
4
- * Emits `superblocks.npm.install.*` metrics from every npm install path
5
- * Superblocks owns and returns the matching attribute set so the caller can
6
- * annotate its active llmobs span with the same dimensions. The metric and
7
- * span streams share a closed attribute set so dashboards and traces join
8
- * cleanly without dimension drift.
9
- *
10
- * Cardinality budget (documented contract — must not regress without a
11
- * migration plan; every dashboard and Datadog saved facet pins on these):
12
- *
13
- * - `registry_host` ≤ 3 (`public_npm` | `private` | `unknown`)
14
- * - `outcome` ≤ 6 (`NPM_OUTCOMES`)
15
- * - `runner` ≤ 4 (`NPM_INSTALL_RUNNERS`)
16
- *
17
- * Total dimension product is bounded at 3 × 6 × 4 = 72 series, well under
18
- * any per-metric ceiling. New runners or outcomes go through P6.1
19
- * (sanitization policy) so a future emitter cannot blow the budget by
20
- * accident.
21
- *
22
- * Every value flows through the P6.1 helpers in `./sanitize-npm-attributes`
23
- * before reaching an OTel instrument, so raw registry hostnames and tokens
24
- * cannot escape via this emitter — the same guarantee the audit-event
25
- * emitter (P6.3) relies on.
26
- */
27
- import { type NpmOutcome, type NpmRegistryBucket } from "./sanitize-npm-attributes.js";
28
- /**
29
- * Closed enum of npm install call sites that emit metrics. One value per
30
- * call site Superblocks owns. Names are stabilised here; renaming any
31
- * value breaks every saved dashboard and alert split on `runner`, so
32
- * additions/removals must come with a migration plan.
33
- *
34
- * - `install_all` — full install from package.json (no specific
35
- * packages). Covers both `AppShell.runNpmInstall`
36
- * and `AppShell.runPackageManagerInstall`; the
37
- * two are semantically the same operation routed
38
- * through different package managers.
39
- * - `install_specific` — `AppShell.installSpecificPackages` (named
40
- * packages via `npm add` / equivalent).
41
- * - `prefetch` — `installTemplateModules` (template
42
- * `node_modules` prefetch during AiService
43
- * construction).
44
- */
45
- export declare const NPM_INSTALL_RUNNERS: readonly ["install_all", "install_specific", "prefetch"];
46
- export type NpmInstallRunner = (typeof NPM_INSTALL_RUNNERS)[number];
47
- export interface NpmInstallMetricInput {
48
- /** Which install call site emitted this event. */
49
- runner: NpmInstallRunner;
50
- /**
51
- * Registry URL or bare hostname the install was attempting (`null` /
52
- * `undefined` is fine — bucketed to `unknown`). Always passed through
53
- * `bucketNpmRegistryHost` before emission, so raw hostnames cannot leak.
54
- */
55
- registryHost: string | null | undefined;
56
- /**
57
- * Outcome key. Free-form on input; coerced to the closed
58
- * `NPM_OUTCOMES` enum at the emit boundary (unknown strings → `other`).
59
- * Use the `NpmInstallBlocked.reason` value for failures and the literal
60
- * `"success"` on the happy path.
61
- */
62
- outcome: string | null | undefined;
63
- /** Elapsed wall-clock time in milliseconds; clamped at 0. */
64
- durationMs: number;
65
- }
66
- /**
67
- * Attribute set shaped for direct spread into
68
- * `llmobs.annotate({ tags: ... })`. Returned by `recordNpmInstall` so the
69
- * span on the active install call site carries the exact same values that
70
- * just went into the metric pipeline.
71
- */
72
- export interface NpmInstallSpanAttributes {
73
- "npm.registry_host": NpmRegistryBucket;
74
- "npm.outcome": NpmOutcome;
75
- }
76
- /**
77
- * Emit one observation of the install metric triple and return the matching
78
- * span-attribute pair. Idempotent w.r.t. the metric SDK; safe to call from
79
- * `finally` blocks where the same code path may also throw.
80
- */
81
- export declare function recordNpmInstall(input: NpmInstallMetricInput): NpmInstallSpanAttributes;
82
- /**
83
- * Test-only: clear cached instruments + last-seen gauge state. Required
84
- * when a test installs its own MeterProvider, so the next emit re-binds to
85
- * the test provider and prior runs' gauge entries don't bleed across.
86
- */
87
- export declare function _resetNpmInstallMetricsForTesting(): void;
88
- //# sourceMappingURL=npm-install-metrics.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"npm-install-metrics.d.ts","sourceRoot":"","sources":["../../src/common/npm-install-metrics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAIH,OAAO,EAGL,KAAK,UAAU,EACf,KAAK,iBAAiB,EACvB,MAAM,8BAA8B,CAAC;AAEtC;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,mBAAmB,0DAItB,CAAC;AACX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAuEpE,MAAM,WAAW,qBAAqB;IACpC,kDAAkD;IAClD,MAAM,EAAE,gBAAgB,CAAC;IACzB;;;;OAIG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACxC;;;;;OAKG;IACH,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACnC,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,wBAAwB;IACvC,mBAAmB,EAAE,iBAAiB,CAAC;IACvC,aAAa,EAAE,UAAU,CAAC;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,qBAAqB,GAC3B,wBAAwB,CAwB1B;AAED;;;;GAIG;AACH,wBAAgB,iCAAiC,IAAI,IAAI,CAIxD"}
@@ -1,140 +0,0 @@
1
- "use strict";
2
- /**
3
- * NPM Install Metrics (APPS-4189 / P6.2)
4
- *
5
- * Emits `superblocks.npm.install.*` metrics from every npm install path
6
- * Superblocks owns and returns the matching attribute set so the caller can
7
- * annotate its active llmobs span with the same dimensions. The metric and
8
- * span streams share a closed attribute set so dashboards and traces join
9
- * cleanly without dimension drift.
10
- *
11
- * Cardinality budget (documented contract — must not regress without a
12
- * migration plan; every dashboard and Datadog saved facet pins on these):
13
- *
14
- * - `registry_host` ≤ 3 (`public_npm` | `private` | `unknown`)
15
- * - `outcome` ≤ 6 (`NPM_OUTCOMES`)
16
- * - `runner` ≤ 4 (`NPM_INSTALL_RUNNERS`)
17
- *
18
- * Total dimension product is bounded at 3 × 6 × 4 = 72 series, well under
19
- * any per-metric ceiling. New runners or outcomes go through P6.1
20
- * (sanitization policy) so a future emitter cannot blow the budget by
21
- * accident.
22
- *
23
- * Every value flows through the P6.1 helpers in `./sanitize-npm-attributes`
24
- * before reaching an OTel instrument, so raw registry hostnames and tokens
25
- * cannot escape via this emitter — the same guarantee the audit-event
26
- * emitter (P6.3) relies on.
27
- */
28
- Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.NPM_INSTALL_RUNNERS = void 0;
30
- exports.recordNpmInstall = recordNpmInstall;
31
- exports._resetNpmInstallMetricsForTesting = _resetNpmInstallMetricsForTesting;
32
- const api_1 = require("@opentelemetry/api");
33
- const sanitize_npm_attributes_js_1 = require("./sanitize-npm-attributes.js");
34
- /**
35
- * Closed enum of npm install call sites that emit metrics. One value per
36
- * call site Superblocks owns. Names are stabilised here; renaming any
37
- * value breaks every saved dashboard and alert split on `runner`, so
38
- * additions/removals must come with a migration plan.
39
- *
40
- * - `install_all` — full install from package.json (no specific
41
- * packages). Covers both `AppShell.runNpmInstall`
42
- * and `AppShell.runPackageManagerInstall`; the
43
- * two are semantically the same operation routed
44
- * through different package managers.
45
- * - `install_specific` — `AppShell.installSpecificPackages` (named
46
- * packages via `npm add` / equivalent).
47
- * - `prefetch` — `installTemplateModules` (template
48
- * `node_modules` prefetch during AiService
49
- * construction).
50
- */
51
- exports.NPM_INSTALL_RUNNERS = [
52
- "install_all",
53
- "install_specific",
54
- "prefetch",
55
- ];
56
- const METER_NAME = "@superblocksteam/telemetry/npm-install";
57
- const METRIC_COUNT = "superblocks.npm.install.count";
58
- const METRIC_DURATION = "superblocks.npm.install.duration";
59
- const METRIC_STATUS = "superblocks.npm.install.status";
60
- /**
61
- * Last-seen status keyed by the attribute tuple. The observable gauge
62
- * callback reads this on every collection cycle. Entries are intentionally
63
- * kept until the process exits (or the test reset helper runs): the gauge
64
- * is "last-seen for dashboards" and a stale combo dropping out would lie
65
- * about the most recent outcome. The map is bounded by the cardinality
66
- * budget above (72 entries worst case).
67
- */
68
- const lastStatusByLabels = new Map();
69
- let cachedMeter;
70
- let cachedInstruments;
71
- /**
72
- * Lazy instrument factory. Re-creates instruments and re-registers the
73
- * gauge callback when the global MeterProvider changes (the typical case
74
- * is a test that calls `metrics.setGlobalMeterProvider` for isolation —
75
- * the previous Meter's instruments are no longer wired to the active
76
- * provider so calling `.add()` / `.record()` on them silently drops data).
77
- */
78
- function getInstruments() {
79
- const meter = api_1.metrics.getMeter(METER_NAME);
80
- if (meter === cachedMeter && cachedInstruments) {
81
- return cachedInstruments;
82
- }
83
- cachedMeter = meter;
84
- cachedInstruments = {
85
- counter: meter.createCounter(METRIC_COUNT, {
86
- description: "Count of npm install invocations from Superblocks-owned paths.",
87
- unit: "{install}",
88
- }),
89
- histogram: meter.createHistogram(METRIC_DURATION, {
90
- description: "Duration of npm install invocations.",
91
- unit: "ms",
92
- }),
93
- };
94
- const gauge = meter.createObservableGauge(METRIC_STATUS, {
95
- description: "Last-seen npm install status (1 = success, 0 = anything else) per runner+registry+outcome. For at-a-glance dashboards.",
96
- });
97
- gauge.addCallback((result) => {
98
- for (const { value, attrs } of lastStatusByLabels.values()) {
99
- result.observe(value, attrs);
100
- }
101
- });
102
- return cachedInstruments;
103
- }
104
- /**
105
- * Emit one observation of the install metric triple and return the matching
106
- * span-attribute pair. Idempotent w.r.t. the metric SDK; safe to call from
107
- * `finally` blocks where the same code path may also throw.
108
- */
109
- function recordNpmInstall(input) {
110
- const { counter, histogram } = getInstruments();
111
- const registry_host = (0, sanitize_npm_attributes_js_1.bucketNpmRegistryHost)(input.registryHost);
112
- const outcome = (0, sanitize_npm_attributes_js_1.normalizeNpmOutcome)(input.outcome);
113
- const attrs = {
114
- runner: input.runner,
115
- registry_host,
116
- outcome,
117
- };
118
- counter.add(1, attrs);
119
- histogram.record(Math.max(0, input.durationMs), attrs);
120
- const key = `${attrs.runner}|${attrs.registry_host}|${attrs.outcome}`;
121
- lastStatusByLabels.set(key, {
122
- value: outcome === "success" ? 1 : 0,
123
- attrs,
124
- });
125
- return {
126
- "npm.registry_host": registry_host,
127
- "npm.outcome": outcome,
128
- };
129
- }
130
- /**
131
- * Test-only: clear cached instruments + last-seen gauge state. Required
132
- * when a test installs its own MeterProvider, so the next emit re-binds to
133
- * the test provider and prior runs' gauge entries don't bleed across.
134
- */
135
- function _resetNpmInstallMetricsForTesting() {
136
- cachedMeter = undefined;
137
- cachedInstruments = undefined;
138
- lastStatusByLabels.clear();
139
- }
140
- //# sourceMappingURL=npm-install-metrics.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"npm-install-metrics.js","sourceRoot":"","sources":["../../src/common/npm-install-metrics.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"sanitize-npm-attributes.d.ts","sourceRoot":"","sources":["../../src/common/sanitize-npm-attributes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAIH,eAAO,MAAM,oBAAoB,+CAIvB,CAAC;AACX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAKtE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,iBAAiB,CAkBnB;AAeD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,MAAM,CAWR;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,wBAAwB,sDAK3B,CAAC;AACX,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7E,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,cAAc,EAAE,iBAAiB,GAChC,oBAAoB,CAetB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,yIAQf,CAAC;AACX,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAIvD,iEAAiE;AACjE,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,UAAU,CAGZ;AAED,MAAM,WAAW,kBAAkB;IACjC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,0EAA0E;AAC1E,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,iBAAiB,CAAC;IACjC,mBAAmB,EAAE,oBAAoB,CAAC;IAC1C,OAAO,EAAE,UAAU,CAAC;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,iBAAiB,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,UAAU,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,kBAAkB,GACxB,mBAAmB,CAUrB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,kBAAkB,GACxB,kBAAkB,CAMpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CA0BpE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"sanitize-npm-attributes.js","sourceRoot":"","sources":["../../src/common/sanitize-npm-attributes.ts"],"names":[],"mappings":"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"}
@@ -1,88 +0,0 @@
1
- /**
2
- * NPM Install Metrics (APPS-4189 / P6.2)
3
- *
4
- * Emits `superblocks.npm.install.*` metrics from every npm install path
5
- * Superblocks owns and returns the matching attribute set so the caller can
6
- * annotate its active llmobs span with the same dimensions. The metric and
7
- * span streams share a closed attribute set so dashboards and traces join
8
- * cleanly without dimension drift.
9
- *
10
- * Cardinality budget (documented contract — must not regress without a
11
- * migration plan; every dashboard and Datadog saved facet pins on these):
12
- *
13
- * - `registry_host` ≤ 3 (`public_npm` | `private` | `unknown`)
14
- * - `outcome` ≤ 6 (`NPM_OUTCOMES`)
15
- * - `runner` ≤ 4 (`NPM_INSTALL_RUNNERS`)
16
- *
17
- * Total dimension product is bounded at 3 × 6 × 4 = 72 series, well under
18
- * any per-metric ceiling. New runners or outcomes go through P6.1
19
- * (sanitization policy) so a future emitter cannot blow the budget by
20
- * accident.
21
- *
22
- * Every value flows through the P6.1 helpers in `./sanitize-npm-attributes`
23
- * before reaching an OTel instrument, so raw registry hostnames and tokens
24
- * cannot escape via this emitter — the same guarantee the audit-event
25
- * emitter (P6.3) relies on.
26
- */
27
- import { type NpmOutcome, type NpmRegistryBucket } from "./sanitize-npm-attributes.js";
28
- /**
29
- * Closed enum of npm install call sites that emit metrics. One value per
30
- * call site Superblocks owns. Names are stabilised here; renaming any
31
- * value breaks every saved dashboard and alert split on `runner`, so
32
- * additions/removals must come with a migration plan.
33
- *
34
- * - `install_all` — full install from package.json (no specific
35
- * packages). Covers both `AppShell.runNpmInstall`
36
- * and `AppShell.runPackageManagerInstall`; the
37
- * two are semantically the same operation routed
38
- * through different package managers.
39
- * - `install_specific` — `AppShell.installSpecificPackages` (named
40
- * packages via `npm add` / equivalent).
41
- * - `prefetch` — `installTemplateModules` (template
42
- * `node_modules` prefetch during AiService
43
- * construction).
44
- */
45
- export declare const NPM_INSTALL_RUNNERS: readonly ["install_all", "install_specific", "prefetch"];
46
- export type NpmInstallRunner = (typeof NPM_INSTALL_RUNNERS)[number];
47
- export interface NpmInstallMetricInput {
48
- /** Which install call site emitted this event. */
49
- runner: NpmInstallRunner;
50
- /**
51
- * Registry URL or bare hostname the install was attempting (`null` /
52
- * `undefined` is fine — bucketed to `unknown`). Always passed through
53
- * `bucketNpmRegistryHost` before emission, so raw hostnames cannot leak.
54
- */
55
- registryHost: string | null | undefined;
56
- /**
57
- * Outcome key. Free-form on input; coerced to the closed
58
- * `NPM_OUTCOMES` enum at the emit boundary (unknown strings → `other`).
59
- * Use the `NpmInstallBlocked.reason` value for failures and the literal
60
- * `"success"` on the happy path.
61
- */
62
- outcome: string | null | undefined;
63
- /** Elapsed wall-clock time in milliseconds; clamped at 0. */
64
- durationMs: number;
65
- }
66
- /**
67
- * Attribute set shaped for direct spread into
68
- * `llmobs.annotate({ tags: ... })`. Returned by `recordNpmInstall` so the
69
- * span on the active install call site carries the exact same values that
70
- * just went into the metric pipeline.
71
- */
72
- export interface NpmInstallSpanAttributes {
73
- "npm.registry_host": NpmRegistryBucket;
74
- "npm.outcome": NpmOutcome;
75
- }
76
- /**
77
- * Emit one observation of the install metric triple and return the matching
78
- * span-attribute pair. Idempotent w.r.t. the metric SDK; safe to call from
79
- * `finally` blocks where the same code path may also throw.
80
- */
81
- export declare function recordNpmInstall(input: NpmInstallMetricInput): NpmInstallSpanAttributes;
82
- /**
83
- * Test-only: clear cached instruments + last-seen gauge state. Required
84
- * when a test installs its own MeterProvider, so the next emit re-binds to
85
- * the test provider and prior runs' gauge entries don't bleed across.
86
- */
87
- export declare function _resetNpmInstallMetricsForTesting(): void;
88
- //# sourceMappingURL=npm-install-metrics.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"npm-install-metrics.d.ts","sourceRoot":"","sources":["../../src/common/npm-install-metrics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAIH,OAAO,EAGL,KAAK,UAAU,EACf,KAAK,iBAAiB,EACvB,MAAM,8BAA8B,CAAC;AAEtC;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,mBAAmB,0DAItB,CAAC;AACX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAuEpE,MAAM,WAAW,qBAAqB;IACpC,kDAAkD;IAClD,MAAM,EAAE,gBAAgB,CAAC;IACzB;;;;OAIG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACxC;;;;;OAKG;IACH,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACnC,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,wBAAwB;IACvC,mBAAmB,EAAE,iBAAiB,CAAC;IACvC,aAAa,EAAE,UAAU,CAAC;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,qBAAqB,GAC3B,wBAAwB,CAwB1B;AAED;;;;GAIG;AACH,wBAAgB,iCAAiC,IAAI,IAAI,CAIxD"}
@@ -1,135 +0,0 @@
1
- /**
2
- * NPM Install Metrics (APPS-4189 / P6.2)
3
- *
4
- * Emits `superblocks.npm.install.*` metrics from every npm install path
5
- * Superblocks owns and returns the matching attribute set so the caller can
6
- * annotate its active llmobs span with the same dimensions. The metric and
7
- * span streams share a closed attribute set so dashboards and traces join
8
- * cleanly without dimension drift.
9
- *
10
- * Cardinality budget (documented contract — must not regress without a
11
- * migration plan; every dashboard and Datadog saved facet pins on these):
12
- *
13
- * - `registry_host` ≤ 3 (`public_npm` | `private` | `unknown`)
14
- * - `outcome` ≤ 6 (`NPM_OUTCOMES`)
15
- * - `runner` ≤ 4 (`NPM_INSTALL_RUNNERS`)
16
- *
17
- * Total dimension product is bounded at 3 × 6 × 4 = 72 series, well under
18
- * any per-metric ceiling. New runners or outcomes go through P6.1
19
- * (sanitization policy) so a future emitter cannot blow the budget by
20
- * accident.
21
- *
22
- * Every value flows through the P6.1 helpers in `./sanitize-npm-attributes`
23
- * before reaching an OTel instrument, so raw registry hostnames and tokens
24
- * cannot escape via this emitter — the same guarantee the audit-event
25
- * emitter (P6.3) relies on.
26
- */
27
- import { metrics } from "@opentelemetry/api";
28
- import { bucketNpmRegistryHost, normalizeNpmOutcome, } from "./sanitize-npm-attributes.js";
29
- /**
30
- * Closed enum of npm install call sites that emit metrics. One value per
31
- * call site Superblocks owns. Names are stabilised here; renaming any
32
- * value breaks every saved dashboard and alert split on `runner`, so
33
- * additions/removals must come with a migration plan.
34
- *
35
- * - `install_all` — full install from package.json (no specific
36
- * packages). Covers both `AppShell.runNpmInstall`
37
- * and `AppShell.runPackageManagerInstall`; the
38
- * two are semantically the same operation routed
39
- * through different package managers.
40
- * - `install_specific` — `AppShell.installSpecificPackages` (named
41
- * packages via `npm add` / equivalent).
42
- * - `prefetch` — `installTemplateModules` (template
43
- * `node_modules` prefetch during AiService
44
- * construction).
45
- */
46
- export const NPM_INSTALL_RUNNERS = [
47
- "install_all",
48
- "install_specific",
49
- "prefetch",
50
- ];
51
- const METER_NAME = "@superblocksteam/telemetry/npm-install";
52
- const METRIC_COUNT = "superblocks.npm.install.count";
53
- const METRIC_DURATION = "superblocks.npm.install.duration";
54
- const METRIC_STATUS = "superblocks.npm.install.status";
55
- /**
56
- * Last-seen status keyed by the attribute tuple. The observable gauge
57
- * callback reads this on every collection cycle. Entries are intentionally
58
- * kept until the process exits (or the test reset helper runs): the gauge
59
- * is "last-seen for dashboards" and a stale combo dropping out would lie
60
- * about the most recent outcome. The map is bounded by the cardinality
61
- * budget above (72 entries worst case).
62
- */
63
- const lastStatusByLabels = new Map();
64
- let cachedMeter;
65
- let cachedInstruments;
66
- /**
67
- * Lazy instrument factory. Re-creates instruments and re-registers the
68
- * gauge callback when the global MeterProvider changes (the typical case
69
- * is a test that calls `metrics.setGlobalMeterProvider` for isolation —
70
- * the previous Meter's instruments are no longer wired to the active
71
- * provider so calling `.add()` / `.record()` on them silently drops data).
72
- */
73
- function getInstruments() {
74
- const meter = metrics.getMeter(METER_NAME);
75
- if (meter === cachedMeter && cachedInstruments) {
76
- return cachedInstruments;
77
- }
78
- cachedMeter = meter;
79
- cachedInstruments = {
80
- counter: meter.createCounter(METRIC_COUNT, {
81
- description: "Count of npm install invocations from Superblocks-owned paths.",
82
- unit: "{install}",
83
- }),
84
- histogram: meter.createHistogram(METRIC_DURATION, {
85
- description: "Duration of npm install invocations.",
86
- unit: "ms",
87
- }),
88
- };
89
- const gauge = meter.createObservableGauge(METRIC_STATUS, {
90
- description: "Last-seen npm install status (1 = success, 0 = anything else) per runner+registry+outcome. For at-a-glance dashboards.",
91
- });
92
- gauge.addCallback((result) => {
93
- for (const { value, attrs } of lastStatusByLabels.values()) {
94
- result.observe(value, attrs);
95
- }
96
- });
97
- return cachedInstruments;
98
- }
99
- /**
100
- * Emit one observation of the install metric triple and return the matching
101
- * span-attribute pair. Idempotent w.r.t. the metric SDK; safe to call from
102
- * `finally` blocks where the same code path may also throw.
103
- */
104
- export function recordNpmInstall(input) {
105
- const { counter, histogram } = getInstruments();
106
- const registry_host = bucketNpmRegistryHost(input.registryHost);
107
- const outcome = normalizeNpmOutcome(input.outcome);
108
- const attrs = {
109
- runner: input.runner,
110
- registry_host,
111
- outcome,
112
- };
113
- counter.add(1, attrs);
114
- histogram.record(Math.max(0, input.durationMs), attrs);
115
- const key = `${attrs.runner}|${attrs.registry_host}|${attrs.outcome}`;
116
- lastStatusByLabels.set(key, {
117
- value: outcome === "success" ? 1 : 0,
118
- attrs,
119
- });
120
- return {
121
- "npm.registry_host": registry_host,
122
- "npm.outcome": outcome,
123
- };
124
- }
125
- /**
126
- * Test-only: clear cached instruments + last-seen gauge state. Required
127
- * when a test installs its own MeterProvider, so the next emit re-binds to
128
- * the test provider and prior runs' gauge entries don't bleed across.
129
- */
130
- export function _resetNpmInstallMetricsForTesting() {
131
- cachedMeter = undefined;
132
- cachedInstruments = undefined;
133
- lastStatusByLabels.clear();
134
- }
135
- //# sourceMappingURL=npm-install-metrics.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"npm-install-metrics.js","sourceRoot":"","sources":["../../src/common/npm-install-metrics.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"sanitize-npm-attributes.d.ts","sourceRoot":"","sources":["../../src/common/sanitize-npm-attributes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAIH,eAAO,MAAM,oBAAoB,+CAIvB,CAAC;AACX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAKtE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,iBAAiB,CAkBnB;AAeD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,MAAM,CAWR;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,wBAAwB,sDAK3B,CAAC;AACX,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7E,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,cAAc,EAAE,iBAAiB,GAChC,oBAAoB,CAetB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,yIAQf,CAAC;AACX,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAIvD,iEAAiE;AACjE,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,UAAU,CAGZ;AAED,MAAM,WAAW,kBAAkB;IACjC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,0EAA0E;AAC1E,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,iBAAiB,CAAC;IACjC,mBAAmB,EAAE,oBAAoB,CAAC;IAC1C,OAAO,EAAE,UAAU,CAAC;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,iBAAiB,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,UAAU,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,kBAAkB,GACxB,mBAAmB,CAUrB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,kBAAkB,GACxB,kBAAkB,CAMpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CA0BpE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"sanitize-npm-attributes.js","sourceRoot":"","sources":["../../src/common/sanitize-npm-attributes.ts"],"names":[],"mappings":"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"}