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.
Files changed (154) hide show
  1. package/package.json +1 -2
  2. package/src/attribute-redacting-processor.test.ts +0 -763
  3. package/src/attribute-redacting-processor.ts +0 -621
  4. package/src/attributes/attachers.ts +0 -161
  5. package/src/attributes/builders.ts +0 -529
  6. package/src/attributes/domains.ts +0 -42
  7. package/src/attributes/index.ts +0 -81
  8. package/src/attributes/registry.ts +0 -323
  9. package/src/attributes/types.ts +0 -211
  10. package/src/attributes/utils.ts +0 -64
  11. package/src/attributes/validators.ts +0 -266
  12. package/src/attributes.test.ts +0 -292
  13. package/src/auto.ts +0 -67
  14. package/src/autotel-logger.test.ts +0 -548
  15. package/src/autotel-logger.ts +0 -364
  16. package/src/baggage-span-processor.test.ts +0 -202
  17. package/src/baggage-span-processor.ts +0 -100
  18. package/src/business-baggage.test.ts +0 -500
  19. package/src/business-baggage.ts +0 -669
  20. package/src/circuit-breaker.test.ts +0 -341
  21. package/src/circuit-breaker.ts +0 -184
  22. package/src/config.test.ts +0 -94
  23. package/src/config.ts +0 -172
  24. package/src/correlated-events.test.ts +0 -151
  25. package/src/correlated-events.ts +0 -47
  26. package/src/correlation-id.test.ts +0 -163
  27. package/src/correlation-id.ts +0 -206
  28. package/src/db.test.ts +0 -252
  29. package/src/db.ts +0 -447
  30. package/src/decorators.test.ts +0 -153
  31. package/src/decorators.ts +0 -188
  32. package/src/define-event.test.ts +0 -41
  33. package/src/define-event.ts +0 -58
  34. package/src/devtools.ts +0 -60
  35. package/src/drain-pipeline.test.ts +0 -68
  36. package/src/drain-pipeline.ts +0 -199
  37. package/src/drain-toolkit.test.ts +0 -113
  38. package/src/drain-toolkit.ts +0 -129
  39. package/src/enricher-toolkit.test.ts +0 -67
  40. package/src/enricher-toolkit.ts +0 -79
  41. package/src/enrichers.test.ts +0 -150
  42. package/src/enrichers.ts +0 -145
  43. package/src/env-config.test.ts +0 -323
  44. package/src/env-config.ts +0 -309
  45. package/src/error-catalog.test.ts +0 -133
  46. package/src/error-catalog.ts +0 -262
  47. package/src/event-queue.test.ts +0 -864
  48. package/src/event-queue.ts +0 -699
  49. package/src/event-subscriber.ts +0 -262
  50. package/src/event-testing.ts +0 -197
  51. package/src/event.test.ts +0 -1104
  52. package/src/event.ts +0 -988
  53. package/src/events-config.ts +0 -235
  54. package/src/exporters.ts +0 -165
  55. package/src/filtering-span-processor.test.ts +0 -281
  56. package/src/filtering-span-processor.ts +0 -111
  57. package/src/flatten-attributes.test.ts +0 -76
  58. package/src/flatten-attributes.ts +0 -80
  59. package/src/functional.strict-types.typecheck.ts +0 -53
  60. package/src/functional.test.ts +0 -1464
  61. package/src/functional.ts +0 -2539
  62. package/src/functional.types.test.ts +0 -135
  63. package/src/hook.mjs +0 -15
  64. package/src/http.test.ts +0 -485
  65. package/src/http.ts +0 -424
  66. package/src/index.ts +0 -433
  67. package/src/init-auto-redactor.test.ts +0 -53
  68. package/src/init-redactor.test.ts +0 -8
  69. package/src/init.customization.test.ts +0 -665
  70. package/src/init.integrations.test.ts +0 -399
  71. package/src/init.openllmetry.test.ts +0 -194
  72. package/src/init.protocol.test.ts +0 -215
  73. package/src/init.ts +0 -2439
  74. package/src/instrumentation.test.ts +0 -108
  75. package/src/instrumentation.ts +0 -319
  76. package/src/logger.test.ts +0 -125
  77. package/src/logger.ts +0 -341
  78. package/src/messaging-adapters.test.ts +0 -595
  79. package/src/messaging-adapters.ts +0 -583
  80. package/src/messaging-testing.test.ts +0 -573
  81. package/src/messaging-testing.ts +0 -935
  82. package/src/messaging.test.ts +0 -1646
  83. package/src/messaging.ts +0 -2245
  84. package/src/metric-helpers.ts +0 -47
  85. package/src/metric-testing.ts +0 -197
  86. package/src/metric.ts +0 -446
  87. package/src/metrics.test.ts +0 -241
  88. package/src/node-require.ts +0 -123
  89. package/src/operation-context.ts +0 -93
  90. package/src/parse-error.test.ts +0 -73
  91. package/src/parse-error.ts +0 -112
  92. package/src/posthog-logs.test.ts +0 -115
  93. package/src/posthog-logs.ts +0 -77
  94. package/src/pretty-console-exporter.test.ts +0 -545
  95. package/src/pretty-console-exporter.ts +0 -413
  96. package/src/pretty-log-formatter.test.ts +0 -123
  97. package/src/pretty-log-formatter.ts +0 -210
  98. package/src/processors/canonical-log-line-processor.test.ts +0 -523
  99. package/src/processors/canonical-log-line-processor.ts +0 -396
  100. package/src/processors.ts +0 -152
  101. package/src/rate-limiter.test.ts +0 -199
  102. package/src/rate-limiter.ts +0 -98
  103. package/src/redact-values.test.ts +0 -90
  104. package/src/redact-values.ts +0 -34
  105. package/src/register.ts +0 -37
  106. package/src/request-logger.test.ts +0 -545
  107. package/src/request-logger.ts +0 -342
  108. package/src/sampling.test.ts +0 -1060
  109. package/src/sampling.ts +0 -737
  110. package/src/security-schema.test.ts +0 -45
  111. package/src/security-schema.ts +0 -107
  112. package/src/semantic-conventions.ts +0 -15
  113. package/src/semantic-helpers.test.ts +0 -226
  114. package/src/semantic-helpers.ts +0 -438
  115. package/src/shutdown.test.ts +0 -364
  116. package/src/shutdown.ts +0 -246
  117. package/src/span-name-normalizer.test.ts +0 -377
  118. package/src/span-name-normalizer.ts +0 -213
  119. package/src/stable-hash.ts +0 -27
  120. package/src/structured-error.test.ts +0 -191
  121. package/src/structured-error.ts +0 -157
  122. package/src/stub.integration.test.ts +0 -361
  123. package/src/tail-sampling-processor.test.ts +0 -230
  124. package/src/tail-sampling-processor.ts +0 -55
  125. package/src/test-span-collector.test.ts +0 -234
  126. package/src/test-span-collector.ts +0 -150
  127. package/src/testing.ts +0 -705
  128. package/src/trace-context.test.ts +0 -73
  129. package/src/trace-context.ts +0 -567
  130. package/src/trace-helpers.new.test.ts +0 -278
  131. package/src/trace-helpers.test.ts +0 -290
  132. package/src/trace-helpers.ts +0 -710
  133. package/src/trace-hybrid.test.ts +0 -42
  134. package/src/trace-hybrid.ts +0 -37
  135. package/src/tracer-provider.test.ts +0 -183
  136. package/src/tracer-provider.ts +0 -266
  137. package/src/track.test.ts +0 -154
  138. package/src/track.ts +0 -216
  139. package/src/validate.test.ts +0 -287
  140. package/src/validate.ts +0 -307
  141. package/src/validation-attributes.ts +0 -43
  142. package/src/validation.test.ts +0 -330
  143. package/src/validation.ts +0 -246
  144. package/src/variable-name-inference.test.ts +0 -178
  145. package/src/variable-name-inference.ts +0 -242
  146. package/src/webhook.test.ts +0 -649
  147. package/src/webhook.ts +0 -637
  148. package/src/workflow-distributed.test.ts +0 -786
  149. package/src/workflow-distributed.ts +0 -916
  150. package/src/workflow.async-safety.integration.test.ts +0 -345
  151. package/src/workflow.test.ts +0 -647
  152. package/src/workflow.ts +0 -810
  153. package/src/yaml-config.test.ts +0 -373
  154. package/src/yaml-config.ts +0 -351
@@ -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
- });
@@ -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
- });
@@ -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);