@provide-io/telemetry 0.2.2
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/README.md +247 -0
- package/dist/backpressure.d.ts +19 -0
- package/dist/backpressure.d.ts.map +1 -0
- package/dist/backpressure.js +51 -0
- package/dist/cardinality.d.ts +15 -0
- package/dist/cardinality.d.ts.map +1 -0
- package/dist/cardinality.js +69 -0
- package/dist/classification.d.ts +29 -0
- package/dist/classification.d.ts.map +1 -0
- package/dist/classification.js +58 -0
- package/dist/config.d.ts +156 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +350 -0
- package/dist/consent.d.ts +11 -0
- package/dist/consent.d.ts.map +1 -0
- package/dist/consent.js +50 -0
- package/dist/context.d.ts +60 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +127 -0
- package/dist/exceptions.d.ts +14 -0
- package/dist/exceptions.d.ts.map +1 -0
- package/dist/exceptions.js +21 -0
- package/dist/fingerprint.d.ts +5 -0
- package/dist/fingerprint.d.ts.map +1 -0
- package/dist/fingerprint.js +50 -0
- package/dist/hash.d.ts +8 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +102 -0
- package/dist/health.d.ts +54 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +102 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +59 -0
- package/dist/logger.d.ts +28 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +254 -0
- package/dist/metrics.d.ts +78 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +238 -0
- package/dist/otel-logs.d.ts +29 -0
- package/dist/otel-logs.d.ts.map +1 -0
- package/dist/otel-logs.js +127 -0
- package/dist/otel-noop.d.ts +13 -0
- package/dist/otel-noop.d.ts.map +1 -0
- package/dist/otel-noop.js +5 -0
- package/dist/otel.d.ts +20 -0
- package/dist/otel.d.ts.map +1 -0
- package/dist/otel.js +80 -0
- package/dist/pii.d.ts +43 -0
- package/dist/pii.d.ts.map +1 -0
- package/dist/pii.js +278 -0
- package/dist/pretty.d.ts +12 -0
- package/dist/pretty.d.ts.map +1 -0
- package/dist/pretty.js +85 -0
- package/dist/propagation.d.ts +52 -0
- package/dist/propagation.d.ts.map +1 -0
- package/dist/propagation.js +183 -0
- package/dist/react.d.ts +38 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +72 -0
- package/dist/receipts.d.ts +26 -0
- package/dist/receipts.d.ts.map +1 -0
- package/dist/receipts.js +69 -0
- package/dist/resilience.d.ts +26 -0
- package/dist/resilience.d.ts.map +1 -0
- package/dist/resilience.js +183 -0
- package/dist/runtime.d.ts +33 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +133 -0
- package/dist/sampling.d.ts +9 -0
- package/dist/sampling.d.ts.map +1 -0
- package/dist/sampling.js +53 -0
- package/dist/sanitize.d.ts +6 -0
- package/dist/sanitize.d.ts.map +1 -0
- package/dist/sanitize.js +7 -0
- package/dist/schema.d.ts +41 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +109 -0
- package/dist/shutdown.d.ts +2 -0
- package/dist/shutdown.d.ts.map +1 -0
- package/dist/shutdown.js +15 -0
- package/dist/slo.d.ts +25 -0
- package/dist/slo.d.ts.map +1 -0
- package/dist/slo.js +115 -0
- package/dist/testing.d.ts +10 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +51 -0
- package/dist/tracing.d.ts +51 -0
- package/dist/tracing.d.ts.map +1 -0
- package/dist/tracing.js +181 -0
- package/package.json +139 -0
- package/src/backpressure.ts +68 -0
- package/src/cardinality.ts +83 -0
- package/src/classification.ts +87 -0
- package/src/config.ts +589 -0
- package/src/consent.ts +61 -0
- package/src/context.ts +157 -0
- package/src/exceptions.ts +24 -0
- package/src/fingerprint.ts +53 -0
- package/src/hash.ts +118 -0
- package/src/health.ts +175 -0
- package/src/index.ts +183 -0
- package/src/logger.ts +287 -0
- package/src/metrics.ts +204 -0
- package/src/otel-logs.ts +161 -0
- package/src/otel-noop.ts +19 -0
- package/src/otel.ts +112 -0
- package/src/pii.ts +358 -0
- package/src/pretty.ts +93 -0
- package/src/propagation.ts +222 -0
- package/src/react.ts +98 -0
- package/src/receipts.ts +97 -0
- package/src/resilience.ts +220 -0
- package/src/runtime.ts +171 -0
- package/src/sampling.ts +68 -0
- package/src/sanitize.ts +8 -0
- package/src/schema.ts +135 -0
- package/src/shutdown.ts +18 -0
- package/src/slo.ts +156 -0
- package/src/testing.ts +56 -0
- package/src/tracing.ts +211 -0
package/dist/config.js
ADDED
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 provide.io llc. All rights reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* TelemetryConfig — mirrors Python provide.telemetry TelemetryConfig.
|
|
5
|
+
*
|
|
6
|
+
* Env vars (same names as Python package):
|
|
7
|
+
* PROVIDE_TELEMETRY_SERVICE_NAME, PROVIDE_TELEMETRY_ENV (fallback: PROVIDE_ENV),
|
|
8
|
+
* PROVIDE_TELEMETRY_VERSION (fallback: PROVIDE_VERSION),
|
|
9
|
+
* PROVIDE_LOG_LEVEL, PROVIDE_LOG_FORMAT, PROVIDE_TRACE_ENABLED,
|
|
10
|
+
* PROVIDE_TELEMETRY_STRICT_SCHEMA,
|
|
11
|
+
* OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS
|
|
12
|
+
*/
|
|
13
|
+
import { setSamplingPolicy } from './sampling';
|
|
14
|
+
import { setQueuePolicy } from './backpressure';
|
|
15
|
+
import { setExporterPolicy } from './resilience';
|
|
16
|
+
import { setSetupError } from './health';
|
|
17
|
+
import { ConfigurationError } from './exceptions';
|
|
18
|
+
const DEFAULTS = {
|
|
19
|
+
serviceName: 'provide-service',
|
|
20
|
+
environment: 'development',
|
|
21
|
+
version: 'unknown',
|
|
22
|
+
logLevel: 'info',
|
|
23
|
+
logFormat: 'json',
|
|
24
|
+
otelEnabled: false,
|
|
25
|
+
sanitizeFields: [],
|
|
26
|
+
captureToWindow: true,
|
|
27
|
+
consoleOutput: false,
|
|
28
|
+
strictSchema: false,
|
|
29
|
+
requiredLogKeys: [],
|
|
30
|
+
logIncludeTimestamp: true,
|
|
31
|
+
logIncludeCaller: true,
|
|
32
|
+
logSanitize: true,
|
|
33
|
+
logCodeAttributes: false,
|
|
34
|
+
logModuleLevels: {},
|
|
35
|
+
traceSampleRate: 1.0,
|
|
36
|
+
metricsEnabled: true,
|
|
37
|
+
samplingLogsRate: 1.0,
|
|
38
|
+
samplingTracesRate: 1.0,
|
|
39
|
+
samplingMetricsRate: 1.0,
|
|
40
|
+
backpressureLogsMaxsize: 0,
|
|
41
|
+
backpressureTracesMaxsize: 0,
|
|
42
|
+
backpressureMetricsMaxsize: 0,
|
|
43
|
+
exporterLogsRetries: 0,
|
|
44
|
+
exporterLogsBackoffMs: 0,
|
|
45
|
+
exporterLogsTimeoutMs: 10000,
|
|
46
|
+
exporterLogsFailOpen: true,
|
|
47
|
+
exporterTracesRetries: 0,
|
|
48
|
+
exporterTracesBackoffMs: 0,
|
|
49
|
+
exporterTracesTimeoutMs: 10000,
|
|
50
|
+
exporterTracesFailOpen: true,
|
|
51
|
+
exporterMetricsRetries: 0,
|
|
52
|
+
exporterMetricsBackoffMs: 0,
|
|
53
|
+
exporterMetricsTimeoutMs: 10000,
|
|
54
|
+
exporterMetricsFailOpen: true,
|
|
55
|
+
sloEnableRedMetrics: false,
|
|
56
|
+
sloEnableUseMetrics: false,
|
|
57
|
+
piiMaxDepth: 8,
|
|
58
|
+
securityMaxAttrValueLength: 1024,
|
|
59
|
+
securityMaxAttrCount: 64,
|
|
60
|
+
};
|
|
61
|
+
let _config = { ...DEFAULTS };
|
|
62
|
+
/** Read a string from Node process.env. Silently returns undefined in non-Node environments. */
|
|
63
|
+
// Stryker disable BlockStatement
|
|
64
|
+
function nodeEnv(key) {
|
|
65
|
+
try {
|
|
66
|
+
// process.env is not available in browser builds after tree-shaking,
|
|
67
|
+
// but some bundlers (esbuild, Vite) leave process.env.X inline replacements.
|
|
68
|
+
// Stryker disable next-line ConditionalExpression,StringLiteral: process is always defined in Node.js/test environments
|
|
69
|
+
return typeof process !== 'undefined' ? process.env[key] : undefined;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Stryker enable BlockStatement
|
|
76
|
+
/** Parse an env var as a number, falling back to `fallback` on missing or NaN. */
|
|
77
|
+
function envNumber(key, fallback) {
|
|
78
|
+
const raw = nodeEnv(key);
|
|
79
|
+
// Stryker disable next-line ConditionalExpression: undefined check — removing returns NaN path which NaN guard catches identically
|
|
80
|
+
if (raw === undefined)
|
|
81
|
+
return fallback;
|
|
82
|
+
const n = Number(raw);
|
|
83
|
+
return Number.isNaN(n) ? fallback : n;
|
|
84
|
+
}
|
|
85
|
+
function envBool(key, fallback) {
|
|
86
|
+
const raw = nodeEnv(key);
|
|
87
|
+
if (raw === undefined || raw.trim() === '')
|
|
88
|
+
return fallback;
|
|
89
|
+
switch (raw.trim().toLowerCase()) {
|
|
90
|
+
case '1':
|
|
91
|
+
case 'true':
|
|
92
|
+
case 'yes':
|
|
93
|
+
case 'on':
|
|
94
|
+
return true;
|
|
95
|
+
case '0':
|
|
96
|
+
case 'false':
|
|
97
|
+
case 'no':
|
|
98
|
+
case 'off':
|
|
99
|
+
return false;
|
|
100
|
+
default:
|
|
101
|
+
throw new ConfigurationError(`invalid boolean for ${key}: ${JSON.stringify(raw)} (expected one of: 1,true,yes,on,0,false,no,off)`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function envFloatInRange(key, fallback, min, max) {
|
|
105
|
+
const value = envNumber(key, fallback);
|
|
106
|
+
if (!Number.isFinite(value) || value < min || value > max) {
|
|
107
|
+
throw new ConfigurationError(`${key} must be in [${min}, ${max}], got ${String(value)}`);
|
|
108
|
+
}
|
|
109
|
+
return value;
|
|
110
|
+
}
|
|
111
|
+
function envNonNegativeInt(key, fallback) {
|
|
112
|
+
const value = envNumber(key, fallback);
|
|
113
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
114
|
+
throw new ConfigurationError(`${key} must be a non-negative integer, got ${String(value)}`);
|
|
115
|
+
}
|
|
116
|
+
return value;
|
|
117
|
+
}
|
|
118
|
+
function envNonNegativeMsFromSeconds(key, fallbackMs) {
|
|
119
|
+
const value = envSecondsToMs(key, fallbackMs);
|
|
120
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
121
|
+
throw new ConfigurationError(`${key} must be >= 0, got ${String(value)}`);
|
|
122
|
+
}
|
|
123
|
+
return value;
|
|
124
|
+
}
|
|
125
|
+
/** Parse an env var expressed in seconds and return milliseconds. */
|
|
126
|
+
function envSecondsToMs(key, fallbackMs) {
|
|
127
|
+
const raw = nodeEnv(key);
|
|
128
|
+
// Stryker disable next-line ConditionalExpression: same as envNumber — undefined falls through to NaN guard
|
|
129
|
+
if (raw === undefined)
|
|
130
|
+
return fallbackMs;
|
|
131
|
+
const n = Number(raw);
|
|
132
|
+
return Number.isNaN(n) ? fallbackMs : n * 1000;
|
|
133
|
+
}
|
|
134
|
+
/** Parse a module_levels string like "mod1=DEBUG,mod2=WARN" into a Record. */
|
|
135
|
+
function parseModuleLevels(raw) {
|
|
136
|
+
if (!raw)
|
|
137
|
+
return {};
|
|
138
|
+
const result = {};
|
|
139
|
+
for (const pair of raw.split(',')) {
|
|
140
|
+
/* Stryker disable MethodExpression,StringLiteral,ConditionalExpression: trim + includes('=') guard — removing produces malformed but non-crashing output */
|
|
141
|
+
const trimmed = pair.trim();
|
|
142
|
+
if (!trimmed.includes('='))
|
|
143
|
+
continue;
|
|
144
|
+
/* Stryker restore MethodExpression,StringLiteral,ConditionalExpression */
|
|
145
|
+
const [mod, level] = trimmed.split('=', 2).map((s) => s.trim());
|
|
146
|
+
if (mod && level)
|
|
147
|
+
result[mod] = level;
|
|
148
|
+
}
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Build a TelemetryConfig from environment variables.
|
|
153
|
+
* Uses the same env var names as the Python package.
|
|
154
|
+
* Explicit values passed to setupTelemetry() override env vars.
|
|
155
|
+
*/
|
|
156
|
+
export function configFromEnv() {
|
|
157
|
+
const otelHeader = nodeEnv('OTEL_EXPORTER_OTLP_HEADERS');
|
|
158
|
+
const parsedHeaders = otelHeader ? parseOtlpHeaders(otelHeader) : undefined;
|
|
159
|
+
return {
|
|
160
|
+
serviceName: nodeEnv('PROVIDE_TELEMETRY_SERVICE_NAME') ?? DEFAULTS.serviceName,
|
|
161
|
+
environment: nodeEnv('PROVIDE_TELEMETRY_ENV') ?? nodeEnv('PROVIDE_ENV') ?? DEFAULTS.environment,
|
|
162
|
+
version: nodeEnv('PROVIDE_TELEMETRY_VERSION') ?? nodeEnv('PROVIDE_VERSION') ?? DEFAULTS.version,
|
|
163
|
+
logLevel: nodeEnv('PROVIDE_LOG_LEVEL')?.toLowerCase() ?? DEFAULTS.logLevel,
|
|
164
|
+
logFormat: (() => {
|
|
165
|
+
const fmt = nodeEnv('PROVIDE_LOG_FORMAT');
|
|
166
|
+
// Stryker disable next-line ConditionalExpression: 'json' is DEFAULTS.logFormat so removing its check returns the same default value
|
|
167
|
+
return fmt === 'json' || fmt === 'pretty' ? fmt : DEFAULTS.logFormat;
|
|
168
|
+
})(),
|
|
169
|
+
otelEnabled: envBool('PROVIDE_TRACE_ENABLED', DEFAULTS.otelEnabled),
|
|
170
|
+
otlpEndpoint: nodeEnv('OTEL_EXPORTER_OTLP_ENDPOINT'),
|
|
171
|
+
otlpHeaders: parsedHeaders,
|
|
172
|
+
sanitizeFields: DEFAULTS.sanitizeFields,
|
|
173
|
+
captureToWindow: true,
|
|
174
|
+
consoleOutput: false,
|
|
175
|
+
strictSchema: envBool('PROVIDE_TELEMETRY_STRICT_SCHEMA', DEFAULTS.strictSchema),
|
|
176
|
+
requiredLogKeys: (() => {
|
|
177
|
+
const raw = nodeEnv('PROVIDE_TELEMETRY_REQUIRED_KEYS');
|
|
178
|
+
return raw
|
|
179
|
+
? raw
|
|
180
|
+
.split(',')
|
|
181
|
+
.map((s) => s.trim())
|
|
182
|
+
.filter(Boolean)
|
|
183
|
+
: [];
|
|
184
|
+
})(),
|
|
185
|
+
// Logging extras
|
|
186
|
+
logIncludeTimestamp: envBool('PROVIDE_LOG_INCLUDE_TIMESTAMP', DEFAULTS.logIncludeTimestamp),
|
|
187
|
+
logIncludeCaller: envBool('PROVIDE_LOG_INCLUDE_CALLER', DEFAULTS.logIncludeCaller),
|
|
188
|
+
logSanitize: envBool('PROVIDE_LOG_SANITIZE', DEFAULTS.logSanitize),
|
|
189
|
+
logCodeAttributes: envBool('PROVIDE_LOG_CODE_ATTRIBUTES', DEFAULTS.logCodeAttributes),
|
|
190
|
+
logModuleLevels: parseModuleLevels(nodeEnv('PROVIDE_LOG_MODULE_LEVELS')),
|
|
191
|
+
// Tracing
|
|
192
|
+
traceSampleRate: envFloatInRange('PROVIDE_TRACE_SAMPLE_RATE', DEFAULTS.traceSampleRate, 0, 1),
|
|
193
|
+
// Metrics
|
|
194
|
+
metricsEnabled: envBool('PROVIDE_METRICS_ENABLED', DEFAULTS.metricsEnabled),
|
|
195
|
+
// Per-signal sampling
|
|
196
|
+
samplingLogsRate: envFloatInRange('PROVIDE_SAMPLING_LOGS_RATE', DEFAULTS.samplingLogsRate, 0, 1),
|
|
197
|
+
samplingTracesRate: envFloatInRange('PROVIDE_SAMPLING_TRACES_RATE', DEFAULTS.samplingTracesRate, 0, 1),
|
|
198
|
+
samplingMetricsRate: envFloatInRange('PROVIDE_SAMPLING_METRICS_RATE', DEFAULTS.samplingMetricsRate, 0, 1),
|
|
199
|
+
// Per-signal backpressure
|
|
200
|
+
backpressureLogsMaxsize: envNonNegativeInt('PROVIDE_BACKPRESSURE_LOGS_MAXSIZE', DEFAULTS.backpressureLogsMaxsize),
|
|
201
|
+
backpressureTracesMaxsize: envNonNegativeInt('PROVIDE_BACKPRESSURE_TRACES_MAXSIZE', DEFAULTS.backpressureTracesMaxsize),
|
|
202
|
+
backpressureMetricsMaxsize: envNonNegativeInt('PROVIDE_BACKPRESSURE_METRICS_MAXSIZE', DEFAULTS.backpressureMetricsMaxsize),
|
|
203
|
+
// Per-signal exporter resilience
|
|
204
|
+
exporterLogsRetries: envNonNegativeInt('PROVIDE_EXPORTER_LOGS_RETRIES', DEFAULTS.exporterLogsRetries),
|
|
205
|
+
exporterLogsBackoffMs: envNonNegativeMsFromSeconds('PROVIDE_EXPORTER_LOGS_BACKOFF_SECONDS', DEFAULTS.exporterLogsBackoffMs),
|
|
206
|
+
exporterLogsTimeoutMs: envNonNegativeMsFromSeconds('PROVIDE_EXPORTER_LOGS_TIMEOUT_SECONDS', DEFAULTS.exporterLogsTimeoutMs),
|
|
207
|
+
exporterLogsFailOpen: envBool('PROVIDE_EXPORTER_LOGS_FAIL_OPEN', DEFAULTS.exporterLogsFailOpen),
|
|
208
|
+
exporterTracesRetries: envNonNegativeInt('PROVIDE_EXPORTER_TRACES_RETRIES', DEFAULTS.exporterTracesRetries),
|
|
209
|
+
exporterTracesBackoffMs: envNonNegativeMsFromSeconds('PROVIDE_EXPORTER_TRACES_BACKOFF_SECONDS', DEFAULTS.exporterTracesBackoffMs),
|
|
210
|
+
exporterTracesTimeoutMs: envNonNegativeMsFromSeconds('PROVIDE_EXPORTER_TRACES_TIMEOUT_SECONDS', DEFAULTS.exporterTracesTimeoutMs),
|
|
211
|
+
exporterTracesFailOpen: envBool('PROVIDE_EXPORTER_TRACES_FAIL_OPEN', DEFAULTS.exporterTracesFailOpen),
|
|
212
|
+
exporterMetricsRetries: envNonNegativeInt('PROVIDE_EXPORTER_METRICS_RETRIES', DEFAULTS.exporterMetricsRetries),
|
|
213
|
+
exporterMetricsBackoffMs: envNonNegativeMsFromSeconds('PROVIDE_EXPORTER_METRICS_BACKOFF_SECONDS', DEFAULTS.exporterMetricsBackoffMs),
|
|
214
|
+
exporterMetricsTimeoutMs: envNonNegativeMsFromSeconds('PROVIDE_EXPORTER_METRICS_TIMEOUT_SECONDS', DEFAULTS.exporterMetricsTimeoutMs),
|
|
215
|
+
exporterMetricsFailOpen: envBool('PROVIDE_EXPORTER_METRICS_FAIL_OPEN', DEFAULTS.exporterMetricsFailOpen),
|
|
216
|
+
// SLO
|
|
217
|
+
sloEnableRedMetrics: envBool('PROVIDE_SLO_ENABLE_RED_METRICS', DEFAULTS.sloEnableRedMetrics),
|
|
218
|
+
sloEnableUseMetrics: envBool('PROVIDE_SLO_ENABLE_USE_METRICS', DEFAULTS.sloEnableUseMetrics),
|
|
219
|
+
// PII
|
|
220
|
+
piiMaxDepth: envNonNegativeInt('PROVIDE_LOG_PII_MAX_DEPTH', DEFAULTS.piiMaxDepth),
|
|
221
|
+
// Security
|
|
222
|
+
securityMaxAttrValueLength: envNonNegativeInt('PROVIDE_SECURITY_MAX_ATTR_VALUE_LENGTH', DEFAULTS.securityMaxAttrValueLength),
|
|
223
|
+
securityMaxAttrCount: envNonNegativeInt('PROVIDE_SECURITY_MAX_ATTR_COUNT', DEFAULTS.securityMaxAttrCount),
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
/** Return the active TelemetryConfig. */
|
|
227
|
+
export function getConfig() {
|
|
228
|
+
return _config;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Apply parsed config fields to the runtime policy engines (sampling, backpressure, resilience).
|
|
232
|
+
* Mirrors Python provide.telemetry.runtime.apply_runtime_config.
|
|
233
|
+
*/
|
|
234
|
+
export function applyConfigPolicies(cfg) {
|
|
235
|
+
// Sampling
|
|
236
|
+
setSamplingPolicy('logs', { defaultRate: cfg.samplingLogsRate });
|
|
237
|
+
setSamplingPolicy('traces', { defaultRate: cfg.samplingTracesRate });
|
|
238
|
+
setSamplingPolicy('metrics', { defaultRate: cfg.samplingMetricsRate });
|
|
239
|
+
// Backpressure
|
|
240
|
+
setQueuePolicy({
|
|
241
|
+
maxLogs: cfg.backpressureLogsMaxsize,
|
|
242
|
+
maxTraces: cfg.backpressureTracesMaxsize,
|
|
243
|
+
maxMetrics: cfg.backpressureMetricsMaxsize,
|
|
244
|
+
});
|
|
245
|
+
// Exporter resilience (per-signal)
|
|
246
|
+
setExporterPolicy('logs', {
|
|
247
|
+
retries: cfg.exporterLogsRetries,
|
|
248
|
+
backoffMs: cfg.exporterLogsBackoffMs,
|
|
249
|
+
timeoutMs: cfg.exporterLogsTimeoutMs,
|
|
250
|
+
failOpen: cfg.exporterLogsFailOpen,
|
|
251
|
+
});
|
|
252
|
+
setExporterPolicy('traces', {
|
|
253
|
+
retries: cfg.exporterTracesRetries,
|
|
254
|
+
backoffMs: cfg.exporterTracesBackoffMs,
|
|
255
|
+
timeoutMs: cfg.exporterTracesTimeoutMs,
|
|
256
|
+
failOpen: cfg.exporterTracesFailOpen,
|
|
257
|
+
});
|
|
258
|
+
setExporterPolicy('metrics', {
|
|
259
|
+
retries: cfg.exporterMetricsRetries,
|
|
260
|
+
backoffMs: cfg.exporterMetricsBackoffMs,
|
|
261
|
+
timeoutMs: cfg.exporterMetricsTimeoutMs,
|
|
262
|
+
failOpen: cfg.exporterMetricsFailOpen,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Configure telemetry. Call once at app startup.
|
|
267
|
+
* Merges explicit values over the current config (which may include env-derived values).
|
|
268
|
+
*/
|
|
269
|
+
export function setupTelemetry(overrides) {
|
|
270
|
+
_config = { ...configFromEnv(), ...overrides };
|
|
271
|
+
try {
|
|
272
|
+
applyConfigPolicies(_config);
|
|
273
|
+
}
|
|
274
|
+
catch (err) {
|
|
275
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
276
|
+
setSetupError(message);
|
|
277
|
+
console.warn(`setupTelemetry: applyConfigPolicies failed: ${message}`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
/** Reset to defaults (used in tests). */
|
|
281
|
+
export function _resetConfig() {
|
|
282
|
+
_config = { ...DEFAULTS };
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Parse OTLP-style header string "key=value,key2=value2" into a Record.
|
|
286
|
+
* Keys and values are URL-decoded. Malformed pairs (no '=') and empty keys are skipped.
|
|
287
|
+
* Values may contain '=' characters (only the first '=' splits key from value).
|
|
288
|
+
*/
|
|
289
|
+
export function parseOtlpHeaders(raw) {
|
|
290
|
+
const result = {};
|
|
291
|
+
// Stryker disable next-line ConditionalExpression: early return is an optimization — empty string splits to [""], idx<1 skips the only pair, returns {} identically
|
|
292
|
+
if (!raw)
|
|
293
|
+
return result;
|
|
294
|
+
for (const pair of raw.split(',')) {
|
|
295
|
+
const idx = pair.indexOf('=');
|
|
296
|
+
if (idx < 1)
|
|
297
|
+
continue; // no '=' or empty key
|
|
298
|
+
const rawKey = pair.slice(0, idx).trim();
|
|
299
|
+
const rawVal = pair.slice(idx + 1).trim();
|
|
300
|
+
try {
|
|
301
|
+
const key = decodeURIComponent(rawKey);
|
|
302
|
+
// Stryker disable next-line ConditionalExpression: defensive guard — unreachable because idx<1 check and trim() already exclude empty keys
|
|
303
|
+
/* v8 ignore next: defensive — idx<1 and trim() already exclude observable empty keys */
|
|
304
|
+
if (!key)
|
|
305
|
+
continue;
|
|
306
|
+
const val = decodeURIComponent(rawVal);
|
|
307
|
+
result[key] = val;
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
// Skip pairs with invalid URL encoding
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return result;
|
|
315
|
+
}
|
|
316
|
+
/** Mask a single header value: show first 4 chars + **** if >= 8 chars, else ****. */
|
|
317
|
+
function maskHeaderValue(v) {
|
|
318
|
+
return v.length < 8 ? '****' : v.slice(0, 4) + '****';
|
|
319
|
+
}
|
|
320
|
+
/** Mask the password component of a URL's userinfo, if present. */
|
|
321
|
+
function maskEndpointUrl(raw) {
|
|
322
|
+
try {
|
|
323
|
+
const u = new URL(raw);
|
|
324
|
+
if (u.password) {
|
|
325
|
+
u.password = '****';
|
|
326
|
+
return u.toString();
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
/* not a valid URL — return as-is */
|
|
331
|
+
}
|
|
332
|
+
return raw;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Return a copy of the config with OTLP secrets masked.
|
|
336
|
+
* Safe to log or serialize — never leaks header values or endpoint credentials.
|
|
337
|
+
*/
|
|
338
|
+
export function redactConfig(config) {
|
|
339
|
+
const result = { ...config };
|
|
340
|
+
if (config.otlpHeaders && Object.keys(config.otlpHeaders).length > 0) {
|
|
341
|
+
result.otlpHeaders = Object.fromEntries(Object.entries(config.otlpHeaders).map(([k, v]) => [k, maskHeaderValue(v)]));
|
|
342
|
+
}
|
|
343
|
+
if (config.otlpEndpoint) {
|
|
344
|
+
result.otlpEndpoint = maskEndpointUrl(config.otlpEndpoint);
|
|
345
|
+
}
|
|
346
|
+
return result;
|
|
347
|
+
}
|
|
348
|
+
/** Package version — mirrors Python __version__. */
|
|
349
|
+
export const version = '0.2.0';
|
|
350
|
+
export const __version__ = version;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consent-aware telemetry collection — strippable governance module.
|
|
3
|
+
* When deleted, all signals pass through unchanged.
|
|
4
|
+
*/
|
|
5
|
+
export type ConsentLevel = 'FULL' | 'FUNCTIONAL' | 'MINIMAL' | 'NONE';
|
|
6
|
+
export declare function setConsentLevel(level: ConsentLevel): void;
|
|
7
|
+
export declare function getConsentLevel(): ConsentLevel;
|
|
8
|
+
export declare function shouldAllow(signal: string, logLevel?: string): boolean;
|
|
9
|
+
export declare function loadConsentFromEnv(): void;
|
|
10
|
+
export declare function resetConsentForTests(): void;
|
|
11
|
+
//# sourceMappingURL=consent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consent.d.ts","sourceRoot":"","sources":["../src/consent.ts"],"names":[],"mappings":"AAGA;;;GAGG;AAEH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,YAAY,GAAG,SAAS,GAAG,MAAM,CAAC;AActE,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAEzD;AAED,wBAAgB,eAAe,IAAI,YAAY,CAE9C;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAkBtE;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAMzC;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C"}
|
package/dist/consent.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 provide.io llc. All rights reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
const LOG_LEVEL_ORDER = {
|
|
4
|
+
TRACE: 0,
|
|
5
|
+
DEBUG: 1,
|
|
6
|
+
INFO: 2,
|
|
7
|
+
WARNING: 3,
|
|
8
|
+
WARN: 3,
|
|
9
|
+
ERROR: 4,
|
|
10
|
+
CRITICAL: 5,
|
|
11
|
+
};
|
|
12
|
+
let _consentLevel = 'FULL';
|
|
13
|
+
export function setConsentLevel(level) {
|
|
14
|
+
_consentLevel = level;
|
|
15
|
+
}
|
|
16
|
+
export function getConsentLevel() {
|
|
17
|
+
return _consentLevel;
|
|
18
|
+
}
|
|
19
|
+
export function shouldAllow(signal, logLevel) {
|
|
20
|
+
const level = _consentLevel;
|
|
21
|
+
if (level === 'FULL')
|
|
22
|
+
return true;
|
|
23
|
+
if (level === 'NONE')
|
|
24
|
+
return false;
|
|
25
|
+
if (level === 'FUNCTIONAL') {
|
|
26
|
+
if (signal === 'logs') {
|
|
27
|
+
const order = LOG_LEVEL_ORDER[(logLevel ?? '').toUpperCase()] ?? 0;
|
|
28
|
+
return order >= LOG_LEVEL_ORDER['WARNING'];
|
|
29
|
+
}
|
|
30
|
+
if (signal === 'context')
|
|
31
|
+
return false;
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
// MINIMAL
|
|
35
|
+
if (signal === 'logs') {
|
|
36
|
+
const order = LOG_LEVEL_ORDER[(logLevel ?? '').toUpperCase()] ?? 0;
|
|
37
|
+
return order >= LOG_LEVEL_ORDER['ERROR'];
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
export function loadConsentFromEnv() {
|
|
42
|
+
const raw = (process.env['PROVIDE_CONSENT_LEVEL'] ?? 'FULL').trim().toUpperCase();
|
|
43
|
+
const valid = ['FULL', 'FUNCTIONAL', 'MINIMAL', 'NONE'];
|
|
44
|
+
if (valid.includes(raw)) {
|
|
45
|
+
_consentLevel = raw;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export function resetConsentForTests() {
|
|
49
|
+
_consentLevel = 'FULL';
|
|
50
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module-level context binding — mirrors Python provide.telemetry bind_context/unbind_context.
|
|
3
|
+
*
|
|
4
|
+
* In browser environments, context is stored in a module-level object. All log calls
|
|
5
|
+
* in the same JS execution context share the same bindings.
|
|
6
|
+
*
|
|
7
|
+
* In Node.js environments, AsyncLocalStorage provides per-async-context isolation
|
|
8
|
+
* (useful for SSR / worker processes where multiple requests run concurrently).
|
|
9
|
+
* Use runWithContext() to scope bindings to a single request/operation.
|
|
10
|
+
*/
|
|
11
|
+
type Context = Record<string, unknown>;
|
|
12
|
+
type ALS = {
|
|
13
|
+
getStore(): Context | undefined;
|
|
14
|
+
run<T>(store: Context, fn: () => T): T;
|
|
15
|
+
enterWith(store: Context): void;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Bind key/value pairs into the current context.
|
|
19
|
+
* These fields are merged into every log record emitted after this call.
|
|
20
|
+
*/
|
|
21
|
+
export declare function bindContext(values: Context): void;
|
|
22
|
+
/**
|
|
23
|
+
* Remove specific keys from the current context.
|
|
24
|
+
*/
|
|
25
|
+
export declare function unbindContext(...keys: string[]): void;
|
|
26
|
+
/**
|
|
27
|
+
* Clear all context bindings.
|
|
28
|
+
*/
|
|
29
|
+
export declare function clearContext(): void;
|
|
30
|
+
/**
|
|
31
|
+
* Return a snapshot of the current context (no side effects).
|
|
32
|
+
*/
|
|
33
|
+
export declare function getContext(): Context;
|
|
34
|
+
/**
|
|
35
|
+
* Run fn with additional context values scoped to its execution.
|
|
36
|
+
* In Node.js, uses AsyncLocalStorage so the bindings are isolated per-request.
|
|
37
|
+
* In browser, temporarily binds then restores the previous state.
|
|
38
|
+
* Mirrors Python: contextvars copy_context().run(fn) pattern.
|
|
39
|
+
*/
|
|
40
|
+
export declare function runWithContext<T>(values: Context, fn: () => T): T;
|
|
41
|
+
/**
|
|
42
|
+
* Bind a session ID that propagates across all telemetry events.
|
|
43
|
+
*/
|
|
44
|
+
export declare function bindSessionContext(sessionId: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* Return the current session ID, or null if not set.
|
|
47
|
+
*/
|
|
48
|
+
export declare function getSessionId(): string | null;
|
|
49
|
+
/**
|
|
50
|
+
* Clear the session ID.
|
|
51
|
+
*/
|
|
52
|
+
export declare function clearSessionContext(): void;
|
|
53
|
+
/** Reset to empty context (used in tests). */
|
|
54
|
+
export declare function _resetContext(): void;
|
|
55
|
+
/** Disable AsyncLocalStorage for testing the module-level fallback path. */
|
|
56
|
+
export declare function _disableAsyncLocalStorageForTest(): ALS | null;
|
|
57
|
+
/** Re-enable AsyncLocalStorage after testing (pass value from _disable call). */
|
|
58
|
+
export declare function _restoreAsyncLocalStorageForTest(saved: ALS | null): void;
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AAEH,KAAK,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAGvC,KAAK,GAAG,GAAG;IACT,QAAQ,IAAI,OAAO,GAAG,SAAS,CAAC;IAChC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IACvC,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;CACjC,CAAC;AAoCF;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAGjD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAGrD;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,IAAI,CASnC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAYjE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE1D;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,GAAG,IAAI,CAG5C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED,8CAA8C;AAC9C,wBAAgB,aAAa,IAAI,IAAI,CAMpC;AAED,4EAA4E;AAC5E,wBAAgB,gCAAgC,IAAI,GAAG,GAAG,IAAI,CAI7D;AAED,iFAAiF;AACjF,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI,CAExE"}
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 provide.io llc. All rights reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// ── AsyncLocalStorage (Node.js / Cloudflare Workers) ──────────────────────────
|
|
4
|
+
let _asyncLocalStorage = null;
|
|
5
|
+
let _AlsConstructor = null;
|
|
6
|
+
try {
|
|
7
|
+
// Dynamic require so the import doesn't break browser bundles.
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
9
|
+
const als = require('node:async_hooks');
|
|
10
|
+
_AlsConstructor = als.AsyncLocalStorage;
|
|
11
|
+
_asyncLocalStorage = new _AlsConstructor();
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
// Not available — fall back to module-level context below.
|
|
15
|
+
}
|
|
16
|
+
// ── Fallback: module-level context (browser / single-thread) ──────────────────
|
|
17
|
+
let _moduleCtx = {};
|
|
18
|
+
function getStore() {
|
|
19
|
+
if (_asyncLocalStorage) {
|
|
20
|
+
return _asyncLocalStorage.getStore() ?? _moduleCtx;
|
|
21
|
+
}
|
|
22
|
+
return _moduleCtx;
|
|
23
|
+
}
|
|
24
|
+
function ensureStore() {
|
|
25
|
+
if (_asyncLocalStorage) {
|
|
26
|
+
const store = _asyncLocalStorage.getStore();
|
|
27
|
+
if (store)
|
|
28
|
+
return store;
|
|
29
|
+
const next = { ..._moduleCtx };
|
|
30
|
+
_asyncLocalStorage.enterWith(next);
|
|
31
|
+
return next;
|
|
32
|
+
}
|
|
33
|
+
return _moduleCtx;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Bind key/value pairs into the current context.
|
|
37
|
+
* These fields are merged into every log record emitted after this call.
|
|
38
|
+
*/
|
|
39
|
+
export function bindContext(values) {
|
|
40
|
+
const store = ensureStore();
|
|
41
|
+
Object.assign(store, values);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Remove specific keys from the current context.
|
|
45
|
+
*/
|
|
46
|
+
export function unbindContext(...keys) {
|
|
47
|
+
const store = ensureStore();
|
|
48
|
+
for (const k of keys)
|
|
49
|
+
delete store[k];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Clear all context bindings.
|
|
53
|
+
*/
|
|
54
|
+
export function clearContext() {
|
|
55
|
+
if (_asyncLocalStorage) {
|
|
56
|
+
const store = _asyncLocalStorage.getStore();
|
|
57
|
+
if (store) {
|
|
58
|
+
for (const k of Object.keys(store))
|
|
59
|
+
delete store[k];
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
_moduleCtx = {};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Return a snapshot of the current context (no side effects).
|
|
67
|
+
*/
|
|
68
|
+
export function getContext() {
|
|
69
|
+
return { ...getStore() };
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Run fn with additional context values scoped to its execution.
|
|
73
|
+
* In Node.js, uses AsyncLocalStorage so the bindings are isolated per-request.
|
|
74
|
+
* In browser, temporarily binds then restores the previous state.
|
|
75
|
+
* Mirrors Python: contextvars copy_context().run(fn) pattern.
|
|
76
|
+
*/
|
|
77
|
+
export function runWithContext(values, fn) {
|
|
78
|
+
if (_asyncLocalStorage) {
|
|
79
|
+
const inherited = { ...getStore(), ...values };
|
|
80
|
+
return _asyncLocalStorage.run(inherited, fn);
|
|
81
|
+
}
|
|
82
|
+
const prev = { ...getStore() };
|
|
83
|
+
bindContext(values);
|
|
84
|
+
try {
|
|
85
|
+
return fn();
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
_moduleCtx = prev;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Bind a session ID that propagates across all telemetry events.
|
|
93
|
+
*/
|
|
94
|
+
export function bindSessionContext(sessionId) {
|
|
95
|
+
bindContext({ session_id: sessionId });
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Return the current session ID, or null if not set.
|
|
99
|
+
*/
|
|
100
|
+
export function getSessionId() {
|
|
101
|
+
const sessionId = getStore()['session_id'];
|
|
102
|
+
return typeof sessionId === 'string' ? sessionId : null;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Clear the session ID.
|
|
106
|
+
*/
|
|
107
|
+
export function clearSessionContext() {
|
|
108
|
+
unbindContext('session_id');
|
|
109
|
+
}
|
|
110
|
+
/** Reset to empty context (used in tests). */
|
|
111
|
+
export function _resetContext() {
|
|
112
|
+
// Recreate ALS so no enterWith-seeded store leaks between tests.
|
|
113
|
+
// The null branch is only reachable in environments without node:async_hooks (e.g. browsers).
|
|
114
|
+
/* v8 ignore next */
|
|
115
|
+
_asyncLocalStorage = _AlsConstructor ? new _AlsConstructor() : null;
|
|
116
|
+
_moduleCtx = {};
|
|
117
|
+
}
|
|
118
|
+
/** Disable AsyncLocalStorage for testing the module-level fallback path. */
|
|
119
|
+
export function _disableAsyncLocalStorageForTest() {
|
|
120
|
+
const prev = _asyncLocalStorage;
|
|
121
|
+
_asyncLocalStorage = null;
|
|
122
|
+
return prev;
|
|
123
|
+
}
|
|
124
|
+
/** Re-enable AsyncLocalStorage after testing (pass value from _disable call). */
|
|
125
|
+
export function _restoreAsyncLocalStorageForTest(saved) {
|
|
126
|
+
_asyncLocalStorage = saved;
|
|
127
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exception hierarchy — mirrors Python provide.telemetry.exceptions.
|
|
3
|
+
*/
|
|
4
|
+
export declare class TelemetryError extends Error {
|
|
5
|
+
constructor(message?: string);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Raised when telemetry configuration is invalid.
|
|
9
|
+
* Also extends Error directly for maximum compatibility.
|
|
10
|
+
*/
|
|
11
|
+
export declare class ConfigurationError extends TelemetryError {
|
|
12
|
+
constructor(message?: string);
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=exceptions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exceptions.d.ts","sourceRoot":"","sources":["../src/exceptions.ts"],"names":[],"mappings":"AAGA;;GAEG;AAEH,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,CAAC,EAAE,MAAM;CAI7B;AAED;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,cAAc;gBACxC,OAAO,CAAC,EAAE,MAAM;CAI7B"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 provide.io llc. All rights reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* Exception hierarchy — mirrors Python provide.telemetry.exceptions.
|
|
5
|
+
*/
|
|
6
|
+
export class TelemetryError extends Error {
|
|
7
|
+
constructor(message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = 'TelemetryError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Raised when telemetry configuration is invalid.
|
|
14
|
+
* Also extends Error directly for maximum compatibility.
|
|
15
|
+
*/
|
|
16
|
+
export class ConfigurationError extends TelemetryError {
|
|
17
|
+
constructor(message) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = 'ConfigurationError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"AA6CA;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAIjF"}
|