lupislabs 1.0.0 → 1.0.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 (60) hide show
  1. package/README.md +221 -359
  2. package/dist/cost-utils.d.ts +5 -0
  3. package/dist/cost-utils.d.ts.map +1 -0
  4. package/dist/cost-utils.js +51 -0
  5. package/dist/cost-utils.js.map +1 -0
  6. package/dist/endpoints.d.ts +2 -0
  7. package/dist/endpoints.d.ts.map +1 -0
  8. package/dist/endpoints.js +2 -0
  9. package/dist/endpoints.js.map +1 -0
  10. package/dist/http-interceptor.d.ts +18 -8
  11. package/dist/http-interceptor.d.ts.map +1 -1
  12. package/dist/http-interceptor.js +164 -416
  13. package/dist/http-interceptor.js.map +1 -1
  14. package/dist/index.d.ts +33 -6
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +96 -8
  17. package/dist/index.js.map +1 -1
  18. package/dist/interceptors/axios-interceptor.d.ts +18 -0
  19. package/dist/interceptors/axios-interceptor.d.ts.map +1 -0
  20. package/dist/interceptors/axios-interceptor.js +115 -0
  21. package/dist/interceptors/axios-interceptor.js.map +1 -0
  22. package/dist/interceptors/fetch-interceptor.d.ts +18 -0
  23. package/dist/interceptors/fetch-interceptor.d.ts.map +1 -0
  24. package/dist/interceptors/fetch-interceptor.js +228 -0
  25. package/dist/interceptors/fetch-interceptor.js.map +1 -0
  26. package/dist/interceptors/got-interceptor.d.ts +18 -0
  27. package/dist/interceptors/got-interceptor.d.ts.map +1 -0
  28. package/dist/interceptors/got-interceptor.js +103 -0
  29. package/dist/interceptors/got-interceptor.js.map +1 -0
  30. package/dist/interceptors/node-http-interceptor.d.ts +21 -0
  31. package/dist/interceptors/node-http-interceptor.d.ts.map +1 -0
  32. package/dist/interceptors/node-http-interceptor.js +301 -0
  33. package/dist/interceptors/node-http-interceptor.js.map +1 -0
  34. package/dist/providers/anthropic-handler.d.ts +3 -0
  35. package/dist/providers/anthropic-handler.d.ts.map +1 -0
  36. package/dist/providers/anthropic-handler.js +50 -0
  37. package/dist/providers/anthropic-handler.js.map +1 -0
  38. package/dist/providers/openai-handler.d.ts +3 -0
  39. package/dist/providers/openai-handler.d.ts.map +1 -0
  40. package/dist/providers/openai-handler.js +46 -0
  41. package/dist/providers/openai-handler.js.map +1 -0
  42. package/dist/providers/provider-detector.d.ts +4 -0
  43. package/dist/providers/provider-detector.d.ts.map +1 -0
  44. package/dist/providers/provider-detector.js +27 -0
  45. package/dist/providers/provider-detector.js.map +1 -0
  46. package/dist/sensitive-data-filter.d.ts +20 -0
  47. package/dist/sensitive-data-filter.d.ts.map +1 -0
  48. package/dist/sensitive-data-filter.js +280 -0
  49. package/dist/sensitive-data-filter.js.map +1 -0
  50. package/dist/trace-collector.d.ts +40 -0
  51. package/dist/trace-collector.d.ts.map +1 -0
  52. package/dist/trace-collector.js +59 -0
  53. package/dist/trace-collector.js.map +1 -0
  54. package/dist/tracer.d.ts +30 -7
  55. package/dist/tracer.d.ts.map +1 -1
  56. package/dist/tracer.js +76 -70
  57. package/dist/tracer.js.map +1 -1
  58. package/dist/types.d.ts +82 -6
  59. package/dist/types.d.ts.map +1 -1
  60. package/package.json +3 -17
package/README.md CHANGED
@@ -1,476 +1,338 @@
1
- # Lupis JavaScript SDK
1
+ # Lupis Labs JavaScript SDK
2
2
 
3
- [![npm version](https://badge.fury.io/js/%40lupislabs%2Fjs-sdk.svg)](https://badge.fury.io/js/%40lupislabs%2Fjs-sdk)
4
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
3
+ JavaScript SDK for LupisLabs with OpenTelemetry tracing and custom event tracking.
5
4
 
6
- A pure OpenTelemetry-based SDK for tracing HTTP requests in JavaScript applications with automatic instrumentation.
7
-
8
- ## ✨ Features
9
-
10
- - 🔭 **OpenTelemetry Native** - Uses official OpenTelemetry auto-instrumentation
11
- - 🚀 **Zero Manual Patching** - Automatic HTTP/fetch interception
12
- - 📊 **OTLP Export** - Standard protocol for any observability backend
13
- - 💬 **Conversation Grouping** - Group related requests with chatId
14
- - 🎯 **Smart Provider Detection** - Automatically detects AI providers (OpenAI, Claude, etc.)
15
- - 📝 **Full Request/Response Capture** - Automatically captures request & response bodies, headers, and status (extends OpenTelemetry's capabilities)
16
- - 🔄 **No Conflicts** - Works alongside other OpenTelemetry instrumentation
17
- - ⚡ **Lightweight** - Clean, minimal codebase
18
-
19
- ## 📦 Installation
5
+ ## Installation
20
6
 
21
7
  ```bash
22
- npm install @lupislabs/js-sdk
8
+ npm install lupislabs
23
9
  ```
24
10
 
25
- ## 🚀 Quick Start
11
+ ### Development-only install
26
12
 
27
- ```javascript
28
- import LupisSDK from '@lupislabs/js-sdk';
29
-
30
- const sdk = new LupisSDK({
31
- projectId: 'your-project-id',
32
- otlpEndpoint: 'http://localhost:3010/v1/traces',
33
- });
13
+ If you only need Lupis for local debugging, install it as a dev dependency:
34
14
 
35
- await sdk.run(async () => {
36
- const response = await fetch('https://api.openai.com/v1/chat/completions', {
37
- method: 'POST',
38
- headers: {
39
- 'Authorization': `Bearer ${API_KEY}`,
40
- 'Content-Type': 'application/json',
41
- },
42
- body: JSON.stringify({
43
- model: 'gpt-4',
44
- messages: [{ role: 'user', content: 'Hello!' }],
45
- }),
46
- });
47
-
48
- return await response.json();
49
- }, { chatId: 'conversation-123' });
15
+ ```bash
16
+ npm install --save-dev lupislabs
50
17
  ```
51
18
 
52
- ## 📝 Request & Response Capture
19
+ When the SDK is not explicitly enabled it stays idle, so keeping it in `devDependencies` will not impact your production runtime.
53
20
 
54
- Unlike standard OpenTelemetry implementations that only capture metadata, Lupis SDK automatically captures full request and response bodies, headers, and status codes. This is achieved through a custom `ResponseCaptureProcessor` that extends OpenTelemetry's capabilities.
21
+ ## Features
55
22
 
56
- ### What Gets Captured
23
+ - 🔍 **Automatic HTTP Tracing**: Captures AI API calls automatically
24
+ - 💬 **Chat ID Support**: Group traces by conversation/chat ID
25
+ - 🎯 **TypeScript Support**: Full TypeScript definitions included
26
+ - 🔒 **Privacy-First**: Never collects request/response bodies, only analytics data
57
27
 
58
- **Request Data:**
28
+ ## Quick Start
59
29
 
60
- - Request body (JSON, text, etc.)
61
- - Request headers
62
- - HTTP method and URL
63
-
64
- **Response Data:**
30
+ ```javascript
31
+ import LupisSDK from 'lupislabs';
65
32
 
66
- - Response body (full content)
67
- - Response headers
68
- - HTTP status code
69
- - Response timing
33
+ const lupis = new LupisSDK({
34
+ projectId: 'your-project-id',
35
+ enabled: true, // Explicitly enable the SDK
36
+ });
70
37
 
71
- ### How It Works
38
+ await lupis.shutdown();
39
+ ```
72
40
 
73
- The SDK uses a custom span processor that:
41
+ ## Checking the active state
74
42
 
75
- 1. Intercepts the fetch API at the earliest point
76
- 2. Captures request data before the request is sent
77
- 3. Clones and reads the response body without affecting the original response
78
- 4. Attaches all data to the OpenTelemetry span as attributes
43
+ You can verify whether the SDK activated:
79
44
 
80
- ### Example
45
+ ```typescript
46
+ const lupis = new LupisSDK({ projectId: 'your-project-id' });
81
47
 
82
- ```javascript
83
- await sdk.run(async () => {
84
- const response = await fetch('https://api.openai.com/v1/chat/completions', {
85
- method: 'POST',
86
- headers: {
87
- 'Content-Type': 'application/json',
88
- 'Authorization': `Bearer ${API_KEY}`,
89
- },
90
- body: JSON.stringify({
91
- model: 'gpt-4',
92
- messages: [{ role: 'user', content: 'Hello!' }],
93
- }),
94
- });
95
-
96
- const data = await response.json();
97
- }, { chatId: 'my-conversation' });
48
+ if (!lupis.isEnabled()) {
49
+ console.log('Lupis SDK is currently disabled.');
50
+ }
98
51
  ```
99
52
 
100
- The span will automatically include:
101
-
102
- - `http.request.body` - The full request payload
103
- - `http.request.headers` - All request headers (as JSON string)
104
- - `http.response.body` - The complete response body
105
- - `http.response.headers` - All response headers (as JSON string)
106
- - `http.response.status` - HTTP status code (e.g., 200, 404, 500)
107
-
108
- See `examples/response-capture-example.js` for more detailed examples.
109
-
110
- ## 📖 Configuration
53
+ ## Configuration
111
54
 
112
55
  ```typescript
113
56
  interface LupisConfig {
114
- projectId: string; // Required: Your project identifier
115
- enabled?: boolean; // Default: true
116
- otlpEndpoint?: string; // Default: 'http://localhost:4318/v1/traces'
117
- serviceName?: string; // Default: 'lupis-sdk'
118
- serviceVersion?: string; // Default: '1.0.0'
57
+ projectId: string;
58
+ enabled?: boolean;
59
+ serviceName?: string;
60
+ serviceVersion?: string;
61
+ filterSensitiveData?: boolean;
62
+ sensitiveDataPatterns?: string[];
63
+ redactionMode?: 'mask' | 'remove' | 'hash';
119
64
  }
120
-
121
- const sdk = new LupisSDK(config);
122
65
  ```
123
66
 
124
- ## 🔭 OpenTelemetry Integration
125
-
126
- This SDK uses **pure OpenTelemetry** with automatic instrumentation:
67
+ - `projectId` (required): Your project identifier
68
+ - `enabled` (optional): Enable/disable tracking. When omitted, the SDK checks `LUPIS_SDK_ENABLED` first, then enables automatically when `NODE_ENV` is defined and not `'production'`. Without those hints it stays disabled (ideal for devDependency usage).
69
+ - `serviceName` (optional): Service name for traces (default: 'lupis-sdk')
70
+ - `serviceVersion` (optional): Service version (default: '1.0.0')
71
+ - `filterSensitiveData` (optional): Enable sensitive data filtering (default: true)
72
+ - `sensitiveDataPatterns` (optional): Custom regex patterns to filter (default: common API keys, tokens, etc.)
73
+ - `redactionMode` (optional): How to redact sensitive data: 'mask', 'remove', or 'hash' (default: 'mask')
127
74
 
128
- - **Browser**: `@opentelemetry/instrumentation-fetch` auto-instruments `fetch()`
129
- - **Node.js**: `@opentelemetry/instrumentation-http` auto-instruments `http` and `https`
75
+ All telemetry is sent to `http://127.0.0.1:9009` by default:
130
76
 
131
- ### Features
77
+ - Traces → `http://127.0.0.1:9009/api/traces`
132
78
 
133
- **Automatic span creation** for all HTTP requests
134
- ✅ **Semantic conventions** (http.method, http.url, http.status_code)
135
- ✅ **W3C Trace Context** propagation
136
- ✅ **OTLP export** to any backend (Jaeger, Tempo, Datadog, etc.)
137
- ✅ **Custom attributes** (projectId, chatId, provider)
79
+ ## Conversation Grouping
138
80
 
139
- ### Architecture
140
-
141
- ```
142
- HTTP Request (fetch/http)
143
-
144
- Custom Fetch Patch (captures request/response data)
145
-
146
- OpenTelemetry Auto-Instrumentation
147
- ├─ FetchInstrumentation (browser)
148
- └─ HttpInstrumentation (Node.js)
149
-
150
- Span Created with Attributes
151
-
152
- TracerProvider
153
- ├─ ChatIdSpanProcessor (adds chatId)
154
- ├─ ResponseCaptureProcessor (adds request/response bodies)
155
- └─ BatchSpanProcessor + OTLPExporter
156
-
157
- Observability Backend
158
- ```
159
-
160
- ## 📋 Usage Examples
161
-
162
- ### Basic HTTP Tracing
81
+ Group traces by conversation/thread using `chatId`:
163
82
 
164
83
  ```javascript
165
- await sdk.run(async () => {
166
- const response = await fetch('https://api.example.com/data');
167
- return await response.json();
168
- }, { chatId: 'my-conversation' });
169
- ```
84
+ // Set global chat ID for all subsequent traces
85
+ lupis.setChatId('conversation_123');
170
86
 
171
- ### Multiple Requests
87
+ // Or set per-operation chat ID
88
+ lupis.run(async () => {
89
+ // Your AI conversation code here
90
+ }, { chatId: 'conversation_123' });
172
91
 
173
- ```javascript
174
- await sdk.run(async () => {
175
- const user = await fetch('/api/user').then(r => r.json());
176
- const posts = await fetch('/api/posts').then(r => r.json());
177
- return { user, posts };
178
- }, { chatId: 'user-session-123' });
92
+ lupis.clearChatId();
179
93
  ```
180
94
 
181
- ### AI Provider Requests
182
-
183
- ```javascript
184
- // OpenAI
185
- await sdk.run(async () => {
186
- const response = await fetch('https://api.openai.com/v1/chat/completions', {
187
- method: 'POST',
188
- headers: { 'Authorization': `Bearer ${API_KEY}` },
189
- body: JSON.stringify({
190
- model: 'gpt-4',
191
- messages: [{ role: 'user', content: 'Hello!' }],
192
- }),
193
- });
194
- }, { chatId: 'openai-conversation' });
195
-
196
- // Claude
197
- await sdk.run(async () => {
198
- const response = await fetch('https://api.anthropic.com/v1/messages', {
199
- method: 'POST',
200
- headers: { 'x-api-key': API_KEY },
201
- body: JSON.stringify({
202
- model: 'claude-3-sonnet-20240229',
203
- messages: [{ role: 'user', content: 'Hello!' }],
204
- }),
205
- });
206
- }, { chatId: 'claude-conversation' });
207
- ```
95
+ ## Metadata Types
208
96
 
209
- ### Custom Spans
97
+ ### sessionId vs chatId
210
98
 
211
- ```javascript
212
- import { otel } from '@lupislabs/js-sdk';
213
-
214
- const span = sdk.createSpan('data-processing', {
215
- 'processing.type': 'batch',
216
- 'batch.size': 100,
217
- }, otel.SpanKind.INTERNAL);
218
-
219
- try {
220
- // Your processing logic
221
- span.end();
222
- } catch (error) {
223
- span.recordException(error);
224
- span.setStatus({
225
- code: otel.SpanStatusCode.ERROR,
226
- message: error.message
227
- });
228
- span.end();
229
- }
230
- ```
99
+ - **`sessionId`**: Browser/app session identifier that persists across conversations
100
+ - Used for analytics and user journey tracking
101
+ - Example: `'browser_session_abc123'`
102
+
103
+ - **`chatId`**: Individual conversation/thread identifier
104
+ - Used for grouping related traces within a conversation
105
+ - Changes for each new conversation
106
+ - Example: `'chat_thread_xyz789'`
231
107
 
232
- ### Using OpenTelemetry API Directly
108
+ ### Example Usage
233
109
 
234
110
  ```javascript
235
- const tracer = sdk.getTracer();
236
-
237
- const span = tracer.startSpan('custom-operation', {
238
- attributes: {
239
- 'operation.type': 'ai-inference',
240
- },
111
+ // Set user context (persists across conversations)
112
+ lupis.setMetadata({
113
+ userId: 'user_123',
114
+ organizationId: 'org_456',
115
+ sessionId: 'browser_session_abc123', // Same across conversations
241
116
  });
242
117
 
243
- // Your code
244
- span.end();
245
- ```
118
+ // Start a new conversation
119
+ lupis.setChatId('conversation_1');
246
120
 
247
- ## 🔌 Export to Observability Backends
121
+ await lupis.run(async () => {
122
+ // AI conversation code
123
+ }, { chatId: 'conversation_1' });
248
124
 
249
- ### Jaeger
125
+ // Start another conversation (same session, different chat)
126
+ lupis.setChatId('conversation_2');
250
127
 
251
- ```javascript
252
- const sdk = new LupisSDK({
253
- projectId: 'my-project',
254
- otlpEndpoint: 'http://localhost:4318/v1/traces',
255
- });
128
+ await lupis.run(async () => {
129
+ // Another AI conversation code
130
+ }, { chatId: 'conversation_2' });
256
131
  ```
257
132
 
258
- ### Grafana Tempo
133
+ ## OpenTelemetry Integration
134
+
135
+ The SDK automatically instruments HTTP requests and creates traces. Access the tracer:
259
136
 
260
137
  ```javascript
261
- const sdk = new LupisSDK({
262
- projectId: 'my-project',
263
- otlpEndpoint: 'https://tempo.example.com/v1/traces',
138
+ const tracer = lupis.getTracer();
139
+
140
+ const span = lupis.createSpan('custom-operation', {
141
+ 'custom.attribute': 'value',
264
142
  });
265
- ```
266
143
 
267
- ### Datadog
144
+ // Your code here
268
145
 
269
- ```javascript
270
- const sdk = new LupisSDK({
271
- projectId: 'my-project',
272
- otlpEndpoint: 'https://http-intake.logs.datadoghq.com/v1/traces',
273
- });
146
+ span.end();
274
147
  ```
275
148
 
276
- ### New Relic
149
+ ## Data Collection
277
150
 
278
- ```javascript
279
- const sdk = new LupisSDK({
280
- projectId: 'my-project',
281
- otlpEndpoint: 'https://otlp.nr-data.net/v1/traces',
282
- });
283
- ```
151
+ The SDK collects only analytics-focused data while protecting sensitive information:
284
152
 
285
- ## 💬 Conversation Grouping
153
+ ### **Collected Data**
286
154
 
287
- Group related requests with `chatId`:
155
+ - **HTTP Metadata**: URL, method, status code, duration, headers (filtered)
156
+ - **Token Usage**: Input/output/cache tokens from AI providers
157
+ - **Cost Analytics**: Calculated costs based on token usage and provider pricing
158
+ - **Model Information**: AI model used for requests
159
+ - **User Context**: User ID, organization ID, session ID, chat ID
160
+ - **Performance Metrics**: Response times, error rates, success/failure status
288
161
 
289
- ```javascript
290
- // All requests in this block will have the same chatId
291
- await sdk.run(async () => {
292
- await fetch('/api/chat', {
293
- method: 'POST',
294
- body: JSON.stringify({ message: 'Hello' })
295
- });
296
- await fetch('/api/chat', {
297
- method: 'POST',
298
- body: JSON.stringify({ message: 'How are you?' })
299
- });
300
- }, { chatId: 'conversation-123' });
301
-
302
- // Or set/clear chatId manually
303
- sdk.setChatId('conversation-123');
304
- // Make requests...
305
- sdk.clearChatId();
306
- ```
162
+ ### ❌ **Never Collected**
307
163
 
308
- ## 🏷️ Span Attributes
164
+ - **Request Bodies**: Full request payloads are never captured
165
+ - **Response Bodies**: Full response content is never captured
166
+ - **Sensitive Data**: API keys, tokens, passwords (filtered by default)
167
+ - **Personal Information**: PII is not collected by default
309
168
 
310
- All HTTP spans automatically include:
169
+ ### 🔒 **Privacy Protection**
311
170
 
312
- **Standard OpenTelemetry:**
171
+ - Sensitive data filtering enabled by default
172
+ - Request/response bodies skipped to reduce span size
173
+ - Focus on analytics and cost tracking only
174
+ - User-controlled data collection
313
175
 
314
- - `http.method` - HTTP method (GET, POST, etc.)
315
- - `http.url` - Full URL
316
- - `http.status_code` - Response status code
176
+ ## Sensitive Data Filtering
317
177
 
318
- **Custom Lupis Attributes:**
178
+ The SDK automatically filters sensitive data in production to protect API keys, tokens, and other sensitive information. This feature is **enabled by default** for security.
319
179
 
320
- - `lupis.project.id` - Your project ID
321
- - `lupis.chat.id` - Conversation ID (when set)
322
- - `http.provider` - Detected provider (openai, claude, cohere, huggingface, google)
180
+ ### Default Filtering
323
181
 
324
- **Request/Response Capture Attributes (Custom Extension):**
182
+ The SDK automatically filters these common sensitive patterns:
325
183
 
326
- - `http.request.body` - Full request body content
327
- - `http.request.headers` - Request headers as JSON string
328
- - `http.response.body` - Full response body content
329
- - `http.response.headers` - Response headers as JSON string
330
- - `http.response.status` - HTTP response status code
184
+ #### API Keys & Tokens
331
185
 
332
- ## 🔧 API Reference
186
+ - `sk-[a-zA-Z0-9]{20,}` - OpenAI API keys
187
+ - `pk_[a-zA-Z0-9]{20,}` - Paddle API keys
188
+ - `ak-[a-zA-Z0-9]{20,}` - Anthropic API keys
189
+ - `Bearer [a-zA-Z0-9._-]+` - Bearer tokens
190
+ - `x-api-key`, `authorization` - API key headers
333
191
 
334
- ### LupisSDK
192
+ #### Authentication
335
193
 
336
- ```typescript
337
- class LupisSDK {
338
- constructor(config: LupisConfig)
339
-
340
- async run<T>(fn: () => Promise<T> | T, options?: { chatId?: string }): Promise<T>
341
-
342
- setChatId(chatId: string): void
343
- clearChatId(): void
344
-
345
- getTracer(): Tracer
346
- createSpan(name: string, attributes?: Attributes, spanKind?: SpanKind): Span
347
-
348
- async shutdown(): Promise<void>
349
- }
350
- ```
194
+ - `password`, `passwd`, `pwd` - Password fields
195
+ - `token`, `access_token`, `refresh_token`, `session_token` - Various tokens
196
+ - `secret`, `private_key`, `api_secret` - Secret fields
351
197
 
352
- ### Methods
198
+ #### Personal Data
353
199
 
354
- #### `sdk.run(fn, options)`
200
+ - `ssn`, `social_security` - Social Security Numbers
201
+ - `credit_card`, `card_number` - Credit card numbers
202
+ - `cvv`, `cvc` - Security codes
355
203
 
356
- Execute a function with automatic HTTP tracing:
204
+ ### Redaction Modes
357
205
 
358
- ```typescript
359
- await sdk.run(async () => {
360
- // Your code
361
- }, { chatId: 'optional-chat-id' });
362
- ```
206
+ Choose how sensitive data is replaced:
363
207
 
364
- #### `sdk.setChatId(chatId)` / `sdk.clearChatId()`
208
+ #### Mask Mode (Default)
365
209
 
366
- Manually set/clear the chatId for subsequent requests:
210
+ ```javascript
211
+ const lupis = new LupisSDK({
212
+ projectId: 'your-project-id',
213
+ redactionMode: 'mask', // Default
214
+ });
367
215
 
368
- ```typescript
369
- sdk.setChatId('conversation-123');
370
- // All requests will have this chatId
371
- sdk.clearChatId();
216
+ // Examples:
217
+ // sk-1234567890abcdef1234567890abcdef12345678 → sk-1***5678
218
+ // Bearer sk-1234567890abcdef1234567890abcdef12345678 Bear***5678
219
+ // password: 'secret-password' → password: '***'
372
220
  ```
373
221
 
374
- #### `sdk.getTracer()`
222
+ #### Remove Mode
375
223
 
376
- Get the OpenTelemetry tracer for advanced usage:
224
+ ```javascript
225
+ const lupis = new LupisSDK({
226
+ projectId: 'your-project-id',
227
+ redactionMode: 'remove',
228
+ });
377
229
 
378
- ```typescript
379
- const tracer = sdk.getTracer();
380
- const span = tracer.startSpan('my-operation');
230
+ // Examples:
231
+ // sk-1234567890abcdef1234567890abcdef12345678 [REDACTED]
232
+ // password: 'secret-password' → password: [REDACTED]
381
233
  ```
382
234
 
383
- #### `sdk.createSpan(name, attributes, spanKind)`
235
+ #### Hash Mode
384
236
 
385
- Create a custom span:
237
+ ```javascript
238
+ const lupis = new LupisSDK({
239
+ projectId: 'your-project-id',
240
+ redactionMode: 'hash',
241
+ });
386
242
 
387
- ```typescript
388
- const span = sdk.createSpan('operation-name', {
389
- 'custom.attribute': 'value',
390
- }, SpanKind.INTERNAL);
243
+ // Examples:
244
+ // sk-1234567890abcdef1234567890abcdef12345678 [HASH:2dd0e9d5]
245
+ // password: 'secret-password' → password: [HASHED]
391
246
  ```
392
247
 
393
- #### `sdk.shutdown()`
248
+ ### Custom Patterns
394
249
 
395
- Gracefully shutdown and flush all spans:
250
+ Add your own sensitive data patterns:
396
251
 
397
- ```typescript
398
- await sdk.shutdown();
252
+ ```javascript
253
+ const lupis = new LupisSDK({
254
+ projectId: 'your-project-id',
255
+ filterSensitiveData: true,
256
+ sensitiveDataPatterns: [
257
+ 'sk-[a-zA-Z0-9]{20,}', // OpenAI API keys
258
+ 'Bearer [a-zA-Z0-9._-]+', // Bearer tokens
259
+ 'custom_secret', // Your custom field
260
+ 'my_api_key', // Your custom field
261
+ 'email', // Email addresses
262
+ ],
263
+ redactionMode: 'mask',
264
+ });
399
265
  ```
400
266
 
401
- ## 🎯 Provider Detection
267
+ ### What Gets Filtered
402
268
 
403
- The SDK automatically detects AI providers based on URL patterns:
269
+ The SDK filters sensitive data in:
404
270
 
405
- | Provider | URL Pattern | Attribute Value |
406
- |----------|-------------|-----------------|
407
- | OpenAI | `api.openai.com` | `openai` |
408
- | Anthropic (Claude) | `api.anthropic.com` | `claude` |
409
- | Cohere | `api.cohere.ai` | `cohere` |
410
- | HuggingFace | `api.huggingface.co` | `huggingface` |
411
- | Google AI | `generativelanguage.googleapis.com` | `google` |
412
- | Others | - | `unknown` |
271
+ - **Request Headers**: Authorization, API keys, tokens
272
+ - **Span Attributes**: All OpenTelemetry span attributes
413
273
 
414
- ## ⚙️ Best Practices
274
+ **Note**: Request and response bodies are never collected, so no filtering is needed for them.
415
275
 
416
- ### 1. Meaningful ChatIds
276
+ ### Disable Filtering (Development Only)
417
277
 
418
- ```javascript
419
- // Good: Descriptive and unique
420
- { chatId: 'user-login-flow-2024-03-15' }
421
- { chatId: 'document-analysis-task-456' }
422
-
423
- // Avoid: Generic or unclear
424
- { chatId: 'test' }
425
- { chatId: '1' }
426
- ```
427
-
428
- ### 2. Always Shutdown
278
+ ⚠️ **Warning**: Only disable filtering in development environments:
429
279
 
430
280
  ```javascript
431
- process.on('SIGTERM', async () => {
432
- await sdk.shutdown();
433
- process.exit(0);
281
+ const lupis = new LupisSDK({
282
+ projectId: 'your-project-id',
283
+ filterSensitiveData: false, // ⚠️ Sensitive data will be exposed!
434
284
  });
435
285
  ```
436
286
 
437
- ### 3. Error Handling
287
+ ### Production Security
288
+
289
+ - ✅ **Enabled by default** - No configuration needed
290
+ - ✅ **Comprehensive coverage** - Common sensitive patterns included
291
+ - ✅ **Configurable** - Add custom patterns as needed
292
+ - ✅ **Performance optimized** - Minimal impact when enabled
293
+ - ✅ **Debugging friendly** - Mask mode preserves partial data for debugging
294
+
295
+ ## Shutdown
296
+
297
+ Always call `shutdown()` to stop interception and flush pending traces:
438
298
 
439
299
  ```javascript
440
- await sdk.run(async () => {
441
- try {
442
- const response = await fetch('/api/data');
443
- if (!response.ok) {
444
- throw new Error(`HTTP error! status: ${response.status}`);
445
- }
446
- return await response.json();
447
- } catch (error) {
448
- console.error('Request failed:', error);
449
- throw error;
450
- }
451
- }, { chatId: 'error-handling-example' });
300
+ await lupis.shutdown();
452
301
  ```
453
302
 
454
- ## 📚 Documentation
303
+ ## Testing
304
+
305
+ The SDK includes comprehensive tests for sensitive data filtering:
455
306
 
456
- - [ARCHITECTURE.md](./ARCHITECTURE.md) - Detailed architecture
457
- - [OPENTELEMETRY.md](./OPENTELEMETRY.md) - OpenTelemetry integration guide
458
- - [examples/](./examples/) - Code examples
307
+ ```bash
308
+ # Run unit tests
309
+ npm run test:sensitive:unit
459
310
 
460
- ## 🤝 Contributing
311
+ # Run integration tests
312
+ npm run test:sensitive:detailed
313
+
314
+ # Run all tests
315
+ npm run test:all
316
+ ```
461
317
 
462
- Contributions are welcome! Please feel free to submit a Pull Request.
318
+ ### Test Coverage
463
319
 
464
- ## 📄 License
320
+ - **Unit Tests**: Filter utility with all redaction modes
321
+ - ✅ **Integration Tests**: SDK with HTTP interception
322
+ - ✅ **Custom Patterns**: User-defined sensitive data patterns
323
+ - ✅ **Disabled Filtering**: Development mode verification
324
+ - ✅ **Request/Response**: Headers, bodies, and span attributes
465
325
 
466
- This project is licensed under the MIT License.
326
+ ## Examples
467
327
 
468
- ## 🆘 Support
328
+ See the `examples/` directory for more usage examples:
469
329
 
470
- If you encounter any issues:
471
- 1. Check the [Issues](https://github.com/lupislabs/lupis/issues) page
472
- 2. Create a new issue with detailed information
330
+ - `event-tracking-example.js` - Custom event tracking
331
+ - `anthropic-example.js` - Anthropic API integration
332
+ - `openai-example.js` - OpenAI API integration
333
+ - `langchain-example.js` - LangChain integration
334
+ - `streaming-example.js` - Streaming responses
473
335
 
474
- ---
336
+ ## License
475
337
 
476
338
  **Made with ❤️ by the Lupis team**