autotel 4.1.0 → 4.2.0
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/package.json +1 -2
- package/src/attribute-redacting-processor.test.ts +0 -763
- package/src/attribute-redacting-processor.ts +0 -621
- package/src/attributes/attachers.ts +0 -161
- package/src/attributes/builders.ts +0 -529
- package/src/attributes/domains.ts +0 -42
- package/src/attributes/index.ts +0 -81
- package/src/attributes/registry.ts +0 -323
- package/src/attributes/types.ts +0 -211
- package/src/attributes/utils.ts +0 -64
- package/src/attributes/validators.ts +0 -266
- package/src/attributes.test.ts +0 -292
- package/src/auto.ts +0 -67
- package/src/autotel-logger.test.ts +0 -548
- package/src/autotel-logger.ts +0 -364
- package/src/baggage-span-processor.test.ts +0 -202
- package/src/baggage-span-processor.ts +0 -100
- package/src/business-baggage.test.ts +0 -500
- package/src/business-baggage.ts +0 -669
- package/src/circuit-breaker.test.ts +0 -341
- package/src/circuit-breaker.ts +0 -184
- package/src/config.test.ts +0 -94
- package/src/config.ts +0 -172
- package/src/correlated-events.test.ts +0 -151
- package/src/correlated-events.ts +0 -47
- package/src/correlation-id.test.ts +0 -163
- package/src/correlation-id.ts +0 -206
- package/src/db.test.ts +0 -252
- package/src/db.ts +0 -447
- package/src/decorators.test.ts +0 -153
- package/src/decorators.ts +0 -188
- package/src/define-event.test.ts +0 -41
- package/src/define-event.ts +0 -58
- package/src/devtools.ts +0 -60
- package/src/drain-pipeline.test.ts +0 -68
- package/src/drain-pipeline.ts +0 -199
- package/src/drain-toolkit.test.ts +0 -113
- package/src/drain-toolkit.ts +0 -129
- package/src/enricher-toolkit.test.ts +0 -67
- package/src/enricher-toolkit.ts +0 -79
- package/src/enrichers.test.ts +0 -150
- package/src/enrichers.ts +0 -145
- package/src/env-config.test.ts +0 -323
- package/src/env-config.ts +0 -309
- package/src/error-catalog.test.ts +0 -133
- package/src/error-catalog.ts +0 -262
- package/src/event-queue.test.ts +0 -864
- package/src/event-queue.ts +0 -699
- package/src/event-subscriber.ts +0 -262
- package/src/event-testing.ts +0 -197
- package/src/event.test.ts +0 -1104
- package/src/event.ts +0 -988
- package/src/events-config.ts +0 -235
- package/src/exporters.ts +0 -165
- package/src/filtering-span-processor.test.ts +0 -281
- package/src/filtering-span-processor.ts +0 -111
- package/src/flatten-attributes.test.ts +0 -76
- package/src/flatten-attributes.ts +0 -80
- package/src/functional.strict-types.typecheck.ts +0 -53
- package/src/functional.test.ts +0 -1464
- package/src/functional.ts +0 -2539
- package/src/functional.types.test.ts +0 -135
- package/src/hook.mjs +0 -15
- package/src/http.test.ts +0 -485
- package/src/http.ts +0 -424
- package/src/index.ts +0 -433
- package/src/init-auto-redactor.test.ts +0 -53
- package/src/init-redactor.test.ts +0 -8
- package/src/init.customization.test.ts +0 -665
- package/src/init.integrations.test.ts +0 -399
- package/src/init.openllmetry.test.ts +0 -194
- package/src/init.protocol.test.ts +0 -215
- package/src/init.ts +0 -2439
- package/src/instrumentation.test.ts +0 -108
- package/src/instrumentation.ts +0 -319
- package/src/logger.test.ts +0 -125
- package/src/logger.ts +0 -341
- package/src/messaging-adapters.test.ts +0 -595
- package/src/messaging-adapters.ts +0 -583
- package/src/messaging-testing.test.ts +0 -573
- package/src/messaging-testing.ts +0 -935
- package/src/messaging.test.ts +0 -1646
- package/src/messaging.ts +0 -2245
- package/src/metric-helpers.ts +0 -47
- package/src/metric-testing.ts +0 -197
- package/src/metric.ts +0 -446
- package/src/metrics.test.ts +0 -241
- package/src/node-require.ts +0 -123
- package/src/operation-context.ts +0 -93
- package/src/parse-error.test.ts +0 -73
- package/src/parse-error.ts +0 -112
- package/src/posthog-logs.test.ts +0 -115
- package/src/posthog-logs.ts +0 -77
- package/src/pretty-console-exporter.test.ts +0 -545
- package/src/pretty-console-exporter.ts +0 -413
- package/src/pretty-log-formatter.test.ts +0 -123
- package/src/pretty-log-formatter.ts +0 -210
- package/src/processors/canonical-log-line-processor.test.ts +0 -523
- package/src/processors/canonical-log-line-processor.ts +0 -396
- package/src/processors.ts +0 -152
- package/src/rate-limiter.test.ts +0 -199
- package/src/rate-limiter.ts +0 -98
- package/src/redact-values.test.ts +0 -90
- package/src/redact-values.ts +0 -34
- package/src/register.ts +0 -37
- package/src/request-logger.test.ts +0 -545
- package/src/request-logger.ts +0 -342
- package/src/sampling.test.ts +0 -1060
- package/src/sampling.ts +0 -737
- package/src/security-schema.test.ts +0 -45
- package/src/security-schema.ts +0 -107
- package/src/semantic-conventions.ts +0 -15
- package/src/semantic-helpers.test.ts +0 -226
- package/src/semantic-helpers.ts +0 -438
- package/src/shutdown.test.ts +0 -364
- package/src/shutdown.ts +0 -246
- package/src/span-name-normalizer.test.ts +0 -377
- package/src/span-name-normalizer.ts +0 -213
- package/src/stable-hash.ts +0 -27
- package/src/structured-error.test.ts +0 -191
- package/src/structured-error.ts +0 -157
- package/src/stub.integration.test.ts +0 -361
- package/src/tail-sampling-processor.test.ts +0 -230
- package/src/tail-sampling-processor.ts +0 -55
- package/src/test-span-collector.test.ts +0 -234
- package/src/test-span-collector.ts +0 -150
- package/src/testing.ts +0 -705
- package/src/trace-context.test.ts +0 -73
- package/src/trace-context.ts +0 -567
- package/src/trace-helpers.new.test.ts +0 -278
- package/src/trace-helpers.test.ts +0 -290
- package/src/trace-helpers.ts +0 -710
- package/src/trace-hybrid.test.ts +0 -42
- package/src/trace-hybrid.ts +0 -37
- package/src/tracer-provider.test.ts +0 -183
- package/src/tracer-provider.ts +0 -266
- package/src/track.test.ts +0 -154
- package/src/track.ts +0 -216
- package/src/validate.test.ts +0 -287
- package/src/validate.ts +0 -307
- package/src/validation-attributes.ts +0 -43
- package/src/validation.test.ts +0 -330
- package/src/validation.ts +0 -246
- package/src/variable-name-inference.test.ts +0 -178
- package/src/variable-name-inference.ts +0 -242
- package/src/webhook.test.ts +0 -649
- package/src/webhook.ts +0 -637
- package/src/workflow-distributed.test.ts +0 -786
- package/src/workflow-distributed.ts +0 -916
- package/src/workflow.async-safety.integration.test.ts +0 -345
- package/src/workflow.test.ts +0 -647
- package/src/workflow.ts +0 -810
- package/src/yaml-config.test.ts +0 -373
- package/src/yaml-config.ts +0 -351
package/src/rate-limiter.test.ts
DELETED
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for token bucket rate limiter
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
6
|
-
import { TokenBucketRateLimiter } from './rate-limiter';
|
|
7
|
-
|
|
8
|
-
describe('TokenBucketRateLimiter', () => {
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
vi.useFakeTimers();
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
describe('tryConsume()', () => {
|
|
14
|
-
it('should allow events within rate limit', () => {
|
|
15
|
-
const limiter = new TokenBucketRateLimiter({
|
|
16
|
-
maxEventsPerSecond: 10,
|
|
17
|
-
burstCapacity: 20,
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
// Should allow first 20 events (burst capacity)
|
|
21
|
-
for (let i = 0; i < 20; i++) {
|
|
22
|
-
expect(limiter.tryConsume()).toBe(true);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// 21st event should be rejected
|
|
26
|
-
expect(limiter.tryConsume()).toBe(false);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('should refill tokens over time', () => {
|
|
30
|
-
const limiter = new TokenBucketRateLimiter({
|
|
31
|
-
maxEventsPerSecond: 10, // 10 events/sec = 1 event/100ms
|
|
32
|
-
burstCapacity: 10,
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
// Consume all tokens
|
|
36
|
-
for (let i = 0; i < 10; i++) {
|
|
37
|
-
expect(limiter.tryConsume()).toBe(true);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Should be rate limited
|
|
41
|
-
expect(limiter.tryConsume()).toBe(false);
|
|
42
|
-
|
|
43
|
-
// Advance time by 100ms (1 token should be added)
|
|
44
|
-
vi.advanceTimersByTime(100);
|
|
45
|
-
|
|
46
|
-
// Should allow 1 more event
|
|
47
|
-
expect(limiter.tryConsume()).toBe(true);
|
|
48
|
-
expect(limiter.tryConsume()).toBe(false);
|
|
49
|
-
|
|
50
|
-
// Advance time by 500ms (5 tokens should be added)
|
|
51
|
-
vi.advanceTimersByTime(500);
|
|
52
|
-
|
|
53
|
-
// Should allow 5 more events
|
|
54
|
-
for (let i = 0; i < 5; i++) {
|
|
55
|
-
expect(limiter.tryConsume()).toBe(true);
|
|
56
|
-
}
|
|
57
|
-
expect(limiter.tryConsume()).toBe(false);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('should not exceed max tokens', () => {
|
|
61
|
-
const limiter = new TokenBucketRateLimiter({
|
|
62
|
-
maxEventsPerSecond: 10,
|
|
63
|
-
burstCapacity: 20,
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
// Wait a long time
|
|
67
|
-
vi.advanceTimersByTime(10_000);
|
|
68
|
-
|
|
69
|
-
// Should only have 20 tokens (burstCapacity), not more
|
|
70
|
-
expect(limiter.getAvailableTokens()).toBe(20);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('should consume multiple tokens at once', () => {
|
|
74
|
-
const limiter = new TokenBucketRateLimiter({
|
|
75
|
-
maxEventsPerSecond: 100,
|
|
76
|
-
burstCapacity: 200,
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
// Consume 50 tokens at once
|
|
80
|
-
expect(limiter.tryConsume(50)).toBe(true);
|
|
81
|
-
expect(limiter.getAvailableTokens()).toBe(150);
|
|
82
|
-
|
|
83
|
-
// Consume another 150 tokens
|
|
84
|
-
expect(limiter.tryConsume(150)).toBe(true);
|
|
85
|
-
expect(limiter.getAvailableTokens()).toBe(0);
|
|
86
|
-
|
|
87
|
-
// Should reject request for 1 token
|
|
88
|
-
expect(limiter.tryConsume(1)).toBe(false);
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
describe('waitForToken()', () => {
|
|
93
|
-
it('should wait until token is available', async () => {
|
|
94
|
-
const limiter = new TokenBucketRateLimiter({
|
|
95
|
-
maxEventsPerSecond: 10, // 1 token every 100ms
|
|
96
|
-
burstCapacity: 1,
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
// Consume the only token
|
|
100
|
-
expect(limiter.tryConsume()).toBe(true);
|
|
101
|
-
expect(limiter.tryConsume()).toBe(false);
|
|
102
|
-
|
|
103
|
-
// Wait for next token
|
|
104
|
-
const promise = limiter.waitForToken();
|
|
105
|
-
|
|
106
|
-
// Advance time by 100ms
|
|
107
|
-
vi.advanceTimersByTime(100);
|
|
108
|
-
|
|
109
|
-
// Should resolve after 100ms
|
|
110
|
-
await promise;
|
|
111
|
-
|
|
112
|
-
// Token should be consumed
|
|
113
|
-
expect(limiter.tryConsume()).toBe(false);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('should calculate correct wait time for multiple tokens', async () => {
|
|
117
|
-
const limiter = new TokenBucketRateLimiter({
|
|
118
|
-
maxEventsPerSecond: 10, // 1 token every 100ms
|
|
119
|
-
burstCapacity: 10,
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
// Consume all tokens
|
|
123
|
-
expect(limiter.tryConsume(10)).toBe(true);
|
|
124
|
-
|
|
125
|
-
// Request 5 tokens (should wait 500ms)
|
|
126
|
-
const promise = limiter.waitForToken(5);
|
|
127
|
-
|
|
128
|
-
// Advance by 400ms (not enough)
|
|
129
|
-
vi.advanceTimersByTime(400);
|
|
130
|
-
|
|
131
|
-
// Promise should not resolve yet
|
|
132
|
-
let resolved = false;
|
|
133
|
-
promise.then(() => {
|
|
134
|
-
resolved = true;
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
await vi.runAllTimersAsync();
|
|
138
|
-
|
|
139
|
-
// Should be resolved now
|
|
140
|
-
expect(resolved).toBe(true);
|
|
141
|
-
});
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
describe('getAvailableTokens()', () => {
|
|
145
|
-
it('should return current token count', () => {
|
|
146
|
-
const limiter = new TokenBucketRateLimiter({
|
|
147
|
-
maxEventsPerSecond: 100,
|
|
148
|
-
burstCapacity: 200,
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
expect(limiter.getAvailableTokens()).toBe(200);
|
|
152
|
-
|
|
153
|
-
limiter.tryConsume(50);
|
|
154
|
-
expect(limiter.getAvailableTokens()).toBe(150);
|
|
155
|
-
|
|
156
|
-
// Advance time by 100ms (10 tokens added)
|
|
157
|
-
vi.advanceTimersByTime(100);
|
|
158
|
-
expect(limiter.getAvailableTokens()).toBe(160);
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
describe('reset()', () => {
|
|
163
|
-
it('should reset to full capacity', () => {
|
|
164
|
-
const limiter = new TokenBucketRateLimiter({
|
|
165
|
-
maxEventsPerSecond: 10,
|
|
166
|
-
burstCapacity: 20,
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
// Consume all tokens
|
|
170
|
-
limiter.tryConsume(20);
|
|
171
|
-
expect(limiter.getAvailableTokens()).toBe(0);
|
|
172
|
-
|
|
173
|
-
// Reset
|
|
174
|
-
limiter.reset();
|
|
175
|
-
expect(limiter.getAvailableTokens()).toBe(20);
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
describe('Burst capacity', () => {
|
|
180
|
-
it('should default to 2x rate if not specified', () => {
|
|
181
|
-
const limiter = new TokenBucketRateLimiter({
|
|
182
|
-
maxEventsPerSecond: 50,
|
|
183
|
-
// burstCapacity not specified
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
// Should have 100 tokens (2x rate)
|
|
187
|
-
expect(limiter.getAvailableTokens()).toBe(100);
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
it('should allow custom burst capacity', () => {
|
|
191
|
-
const limiter = new TokenBucketRateLimiter({
|
|
192
|
-
maxEventsPerSecond: 50,
|
|
193
|
-
burstCapacity: 500, // 10x rate
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
expect(limiter.getAvailableTokens()).toBe(500);
|
|
197
|
-
});
|
|
198
|
-
});
|
|
199
|
-
});
|
package/src/rate-limiter.ts
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Token bucket rate limiter for event subscribers
|
|
3
|
-
*
|
|
4
|
-
* Prevents overwhelming downstream events platforms with too many events.
|
|
5
|
-
* Uses token bucket algorithm for smooth rate limiting with burst capacity.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export interface RateLimiterConfig {
|
|
9
|
-
/** Maximum events per second (default: 100) */
|
|
10
|
-
maxEventsPerSecond: number;
|
|
11
|
-
/** Burst capacity - max events in a single burst (default: 2x rate) */
|
|
12
|
-
burstCapacity?: number;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Token bucket rate limiter
|
|
17
|
-
*
|
|
18
|
-
* Allows bursts up to burstCapacity, then smooths to maxEventsPerSecond.
|
|
19
|
-
* Thread-safe for async operations.
|
|
20
|
-
*/
|
|
21
|
-
export class TokenBucketRateLimiter {
|
|
22
|
-
private tokens: number;
|
|
23
|
-
private readonly maxTokens: number;
|
|
24
|
-
private readonly refillRate: number; // tokens per millisecond
|
|
25
|
-
private lastRefill: number;
|
|
26
|
-
|
|
27
|
-
constructor(config: RateLimiterConfig) {
|
|
28
|
-
this.maxTokens = config.burstCapacity || config.maxEventsPerSecond * 2;
|
|
29
|
-
this.tokens = this.maxTokens; // Start with full bucket
|
|
30
|
-
this.refillRate = config.maxEventsPerSecond / 1000; // Convert to per-ms
|
|
31
|
-
this.lastRefill = Date.now();
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Try to consume a token (allow an event)
|
|
36
|
-
* Returns true if allowed, false if rate limit exceeded
|
|
37
|
-
*/
|
|
38
|
-
tryConsume(count = 1): boolean {
|
|
39
|
-
this.refill();
|
|
40
|
-
|
|
41
|
-
if (this.tokens >= count) {
|
|
42
|
-
this.tokens -= count;
|
|
43
|
-
return true;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Wait until a token is available (async rate limiting)
|
|
51
|
-
* Returns a promise that resolves when the event can be processed
|
|
52
|
-
*/
|
|
53
|
-
async waitForToken(count = 1): Promise<void> {
|
|
54
|
-
this.refill();
|
|
55
|
-
|
|
56
|
-
if (this.tokens >= count) {
|
|
57
|
-
this.tokens -= count;
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Calculate wait time until we have enough tokens
|
|
62
|
-
const tokensNeeded = count - this.tokens;
|
|
63
|
-
const waitMs = Math.ceil(tokensNeeded / this.refillRate);
|
|
64
|
-
|
|
65
|
-
await new Promise((resolve) => setTimeout(resolve, waitMs));
|
|
66
|
-
|
|
67
|
-
// After waiting, try again (recursive)
|
|
68
|
-
return this.waitForToken(count);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Refill tokens based on elapsed time
|
|
73
|
-
*/
|
|
74
|
-
private refill(): void {
|
|
75
|
-
const now = Date.now();
|
|
76
|
-
const elapsed = now - this.lastRefill;
|
|
77
|
-
const tokensToAdd = elapsed * this.refillRate;
|
|
78
|
-
|
|
79
|
-
this.tokens = Math.min(this.maxTokens, this.tokens + tokensToAdd);
|
|
80
|
-
this.lastRefill = now;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Get current available tokens (for testing/debugging)
|
|
85
|
-
*/
|
|
86
|
-
getAvailableTokens(): number {
|
|
87
|
-
this.refill();
|
|
88
|
-
return Math.floor(this.tokens);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Reset the rate limiter (for testing)
|
|
93
|
-
*/
|
|
94
|
-
reset(): void {
|
|
95
|
-
this.tokens = this.maxTokens;
|
|
96
|
-
this.lastRefill = Date.now();
|
|
97
|
-
}
|
|
98
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
-
import { createStringRedactor } from './redact-values';
|
|
3
|
-
import type { StringRedactor } from './redact-values';
|
|
4
|
-
|
|
5
|
-
describe('createStringRedactor', () => {
|
|
6
|
-
describe('default preset', () => {
|
|
7
|
-
let redact: StringRedactor;
|
|
8
|
-
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
redact = createStringRedactor('default');
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it('smart-masks emails', () => {
|
|
14
|
-
expect(redact('Contact user@example.com for info')).toBe(
|
|
15
|
-
'Contact u***@***.com for info',
|
|
16
|
-
);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('smart-masks international phone numbers (country code + last 2 digits)', () => {
|
|
20
|
-
expect(redact('Call +33 1 23 45 67 89 now')).toBe('Call +33******89 now');
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('smart-masks phone numbers with parens (last 2 digits)', () => {
|
|
24
|
-
expect(redact('Call (415) 555-1234 now')).toBe('Call ********34 now');
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('smart-masks common US phone formats', () => {
|
|
28
|
-
expect(redact('Call 555-123-4567 now')).toBe('Call ********67 now');
|
|
29
|
-
expect(redact('Call 5551234567 now')).toBe('Call ********67 now');
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('does not mistake bare digit runs for phone numbers', () => {
|
|
33
|
-
// UUIDs, order ids etc. should pass through untouched.
|
|
34
|
-
expect(redact('Order: 12345678 ok')).toBe('Order: 12345678 ok');
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('smart-masks credit card numbers (last four digits preserved)', () => {
|
|
38
|
-
expect(redact('Card: 4111-1111-1111-1111')).toBe('Card: ****1111');
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('returns input unchanged when no patterns match', () => {
|
|
42
|
-
expect(redact('hello world')).toBe('hello world');
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
describe('strict preset', () => {
|
|
47
|
-
let redact: StringRedactor;
|
|
48
|
-
|
|
49
|
-
beforeEach(() => {
|
|
50
|
-
redact = createStringRedactor('strict');
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('smart-masks JWTs', () => {
|
|
54
|
-
const jwt =
|
|
55
|
-
'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.abc123_-def';
|
|
56
|
-
expect(redact(`Token: ${jwt}`)).toBe('Token: eyJ***.***');
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('smart-masks bearer tokens', () => {
|
|
60
|
-
expect(redact('Authorization: Bearer abc123.xyz')).toBe(
|
|
61
|
-
'Authorization: Bearer ***',
|
|
62
|
-
);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
describe('custom config', () => {
|
|
67
|
-
it('accepts custom config with custom patterns', () => {
|
|
68
|
-
const redact = createStringRedactor({
|
|
69
|
-
valuePatterns: [{ name: 'customId', pattern: /CUST-\d{8}/g }],
|
|
70
|
-
replacement: '***',
|
|
71
|
-
});
|
|
72
|
-
expect(redact('Customer CUST-12345678 logged in')).toBe(
|
|
73
|
-
'Customer *** logged in',
|
|
74
|
-
);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('uses custom replacement string', () => {
|
|
78
|
-
const redact = createStringRedactor({
|
|
79
|
-
valuePatterns: [
|
|
80
|
-
{
|
|
81
|
-
name: 'email',
|
|
82
|
-
pattern: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/gi,
|
|
83
|
-
},
|
|
84
|
-
],
|
|
85
|
-
replacement: '<HIDDEN>',
|
|
86
|
-
});
|
|
87
|
-
expect(redact('Email: test@example.com')).toBe('Email: <HIDDEN>');
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
});
|
package/src/redact-values.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/** Standalone string redaction for use outside the span processor pipeline. */
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
REDACTOR_PRESETS,
|
|
5
|
-
type AttributeRedactorConfig,
|
|
6
|
-
type AttributeRedactorPreset,
|
|
7
|
-
type ValuePatternConfig,
|
|
8
|
-
} from './attribute-redacting-processor';
|
|
9
|
-
|
|
10
|
-
export type StringRedactor = (value: string) => string;
|
|
11
|
-
export function createStringRedactor(
|
|
12
|
-
config: AttributeRedactorConfig | AttributeRedactorPreset,
|
|
13
|
-
): StringRedactor {
|
|
14
|
-
const resolved =
|
|
15
|
-
typeof config === 'string' ? REDACTOR_PRESETS[config] : config;
|
|
16
|
-
const valuePatterns: ValuePatternConfig[] = resolved.valuePatterns ?? [];
|
|
17
|
-
const defaultReplacement = resolved.replacement ?? '[REDACTED]';
|
|
18
|
-
|
|
19
|
-
return (value: string): string => {
|
|
20
|
-
let result = value;
|
|
21
|
-
for (const { pattern, replacement, mask } of valuePatterns) {
|
|
22
|
-
pattern.lastIndex = 0;
|
|
23
|
-
// Smart masks (e.g. email → a***@***.com) take precedence over the
|
|
24
|
-
// static replacement so callers see the same output as the
|
|
25
|
-
// span-attribute redactor does.
|
|
26
|
-
if (mask) {
|
|
27
|
-
result = result.replaceAll(pattern, (match) => mask(match));
|
|
28
|
-
} else {
|
|
29
|
-
result = result.replaceAll(pattern, replacement ?? defaultReplacement);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
}
|
package/src/register.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ESM instrumentation registration for Node.js 18.19+
|
|
3
|
-
*
|
|
4
|
-
* This module registers the OpenTelemetry ESM loader hook using the modern
|
|
5
|
-
* node:module register() API. This eliminates the need for NODE_OPTIONS or
|
|
6
|
-
* --experimental-loader flags.
|
|
7
|
-
*
|
|
8
|
-
* Usage in instrumentation.mjs:
|
|
9
|
-
* ```typescript
|
|
10
|
-
* import 'autotel/register'; // MUST be first import!
|
|
11
|
-
* import { init } from 'autotel';
|
|
12
|
-
*
|
|
13
|
-
* init({
|
|
14
|
-
* service: 'my-app',
|
|
15
|
-
* instrumentations: [...], // or autoInstrumentations: ['express', 'http', 'pino']
|
|
16
|
-
* });
|
|
17
|
-
* ```
|
|
18
|
-
*
|
|
19
|
-
* Then run:
|
|
20
|
-
* ```bash
|
|
21
|
-
* node --import ./instrumentation.mjs src/index.js
|
|
22
|
-
* # or with tsx:
|
|
23
|
-
* tsx --import ./instrumentation.mjs src/index.ts
|
|
24
|
-
* ```
|
|
25
|
-
*
|
|
26
|
-
* No NODE_OPTIONS or --experimental-loader needed!
|
|
27
|
-
*
|
|
28
|
-
* @requires Node.js 18.19.0 or later
|
|
29
|
-
* @see https://github.com/open-telemetry/opentelemetry-js/blob/main/doc/esm-support.md
|
|
30
|
-
* @see https://nodejs.org/api/module.html#moduleregisterspecifier-parenturl-options
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
|
-
import { register } from 'node:module';
|
|
34
|
-
|
|
35
|
-
// Use the official OpenTelemetry instrumentation hook which wraps import-in-the-middle
|
|
36
|
-
// This ensures proper integration with OTel's instrumentation system
|
|
37
|
-
register('@opentelemetry/instrumentation/hook.mjs', import.meta.url);
|