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.
- package/README.md +221 -359
- package/dist/cost-utils.d.ts +5 -0
- package/dist/cost-utils.d.ts.map +1 -0
- package/dist/cost-utils.js +51 -0
- package/dist/cost-utils.js.map +1 -0
- package/dist/endpoints.d.ts +2 -0
- package/dist/endpoints.d.ts.map +1 -0
- package/dist/endpoints.js +2 -0
- package/dist/endpoints.js.map +1 -0
- package/dist/http-interceptor.d.ts +18 -8
- package/dist/http-interceptor.d.ts.map +1 -1
- package/dist/http-interceptor.js +164 -416
- package/dist/http-interceptor.js.map +1 -1
- package/dist/index.d.ts +33 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +96 -8
- package/dist/index.js.map +1 -1
- package/dist/interceptors/axios-interceptor.d.ts +18 -0
- package/dist/interceptors/axios-interceptor.d.ts.map +1 -0
- package/dist/interceptors/axios-interceptor.js +115 -0
- package/dist/interceptors/axios-interceptor.js.map +1 -0
- package/dist/interceptors/fetch-interceptor.d.ts +18 -0
- package/dist/interceptors/fetch-interceptor.d.ts.map +1 -0
- package/dist/interceptors/fetch-interceptor.js +228 -0
- package/dist/interceptors/fetch-interceptor.js.map +1 -0
- package/dist/interceptors/got-interceptor.d.ts +18 -0
- package/dist/interceptors/got-interceptor.d.ts.map +1 -0
- package/dist/interceptors/got-interceptor.js +103 -0
- package/dist/interceptors/got-interceptor.js.map +1 -0
- package/dist/interceptors/node-http-interceptor.d.ts +21 -0
- package/dist/interceptors/node-http-interceptor.d.ts.map +1 -0
- package/dist/interceptors/node-http-interceptor.js +301 -0
- package/dist/interceptors/node-http-interceptor.js.map +1 -0
- package/dist/providers/anthropic-handler.d.ts +3 -0
- package/dist/providers/anthropic-handler.d.ts.map +1 -0
- package/dist/providers/anthropic-handler.js +50 -0
- package/dist/providers/anthropic-handler.js.map +1 -0
- package/dist/providers/openai-handler.d.ts +3 -0
- package/dist/providers/openai-handler.d.ts.map +1 -0
- package/dist/providers/openai-handler.js +46 -0
- package/dist/providers/openai-handler.js.map +1 -0
- package/dist/providers/provider-detector.d.ts +4 -0
- package/dist/providers/provider-detector.d.ts.map +1 -0
- package/dist/providers/provider-detector.js +27 -0
- package/dist/providers/provider-detector.js.map +1 -0
- package/dist/sensitive-data-filter.d.ts +20 -0
- package/dist/sensitive-data-filter.d.ts.map +1 -0
- package/dist/sensitive-data-filter.js +280 -0
- package/dist/sensitive-data-filter.js.map +1 -0
- package/dist/trace-collector.d.ts +40 -0
- package/dist/trace-collector.d.ts.map +1 -0
- package/dist/trace-collector.js +59 -0
- package/dist/trace-collector.js.map +1 -0
- package/dist/tracer.d.ts +30 -7
- package/dist/tracer.d.ts.map +1 -1
- package/dist/tracer.js +76 -70
- package/dist/tracer.js.map +1 -1
- package/dist/types.d.ts +82 -6
- package/dist/types.d.ts.map +1 -1
- 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
|
-
|
|
4
|
-
[](https://opensource.org/licenses/MIT)
|
|
3
|
+
JavaScript SDK for LupisLabs with OpenTelemetry tracing and custom event tracking.
|
|
5
4
|
|
|
6
|
-
|
|
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
|
|
8
|
+
npm install lupislabs
|
|
23
9
|
```
|
|
24
10
|
|
|
25
|
-
|
|
11
|
+
### Development-only install
|
|
26
12
|
|
|
27
|
-
|
|
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
|
-
|
|
36
|
-
|
|
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
|
-
|
|
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
|
-
|
|
21
|
+
## Features
|
|
55
22
|
|
|
56
|
-
|
|
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
|
-
|
|
28
|
+
## Quick Start
|
|
59
29
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
- HTTP method and URL
|
|
63
|
-
|
|
64
|
-
**Response Data:**
|
|
30
|
+
```javascript
|
|
31
|
+
import LupisSDK from 'lupislabs';
|
|
65
32
|
|
|
66
|
-
|
|
67
|
-
-
|
|
68
|
-
|
|
69
|
-
|
|
33
|
+
const lupis = new LupisSDK({
|
|
34
|
+
projectId: 'your-project-id',
|
|
35
|
+
enabled: true, // Explicitly enable the SDK
|
|
36
|
+
});
|
|
70
37
|
|
|
71
|
-
|
|
38
|
+
await lupis.shutdown();
|
|
39
|
+
```
|
|
72
40
|
|
|
73
|
-
|
|
41
|
+
## Checking the active state
|
|
74
42
|
|
|
75
|
-
|
|
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
|
-
|
|
45
|
+
```typescript
|
|
46
|
+
const lupis = new LupisSDK({ projectId: 'your-project-id' });
|
|
81
47
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
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;
|
|
115
|
-
enabled?: boolean;
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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
|
-
|
|
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
|
-
|
|
77
|
+
- Traces → `http://127.0.0.1:9009/api/traces`
|
|
132
78
|
|
|
133
|
-
|
|
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
|
-
|
|
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
|
-
|
|
166
|
-
|
|
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
|
-
|
|
87
|
+
// Or set per-operation chat ID
|
|
88
|
+
lupis.run(async () => {
|
|
89
|
+
// Your AI conversation code here
|
|
90
|
+
}, { chatId: 'conversation_123' });
|
|
172
91
|
|
|
173
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
97
|
+
### sessionId vs chatId
|
|
210
98
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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
|
-
###
|
|
108
|
+
### Example Usage
|
|
233
109
|
|
|
234
110
|
```javascript
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
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
|
-
//
|
|
244
|
-
|
|
245
|
-
```
|
|
118
|
+
// Start a new conversation
|
|
119
|
+
lupis.setChatId('conversation_1');
|
|
246
120
|
|
|
247
|
-
|
|
121
|
+
await lupis.run(async () => {
|
|
122
|
+
// AI conversation code
|
|
123
|
+
}, { chatId: 'conversation_1' });
|
|
248
124
|
|
|
249
|
-
|
|
125
|
+
// Start another conversation (same session, different chat)
|
|
126
|
+
lupis.setChatId('conversation_2');
|
|
250
127
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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
|
-
|
|
133
|
+
## OpenTelemetry Integration
|
|
134
|
+
|
|
135
|
+
The SDK automatically instruments HTTP requests and creates traces. Access the tracer:
|
|
259
136
|
|
|
260
137
|
```javascript
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
138
|
+
const tracer = lupis.getTracer();
|
|
139
|
+
|
|
140
|
+
const span = lupis.createSpan('custom-operation', {
|
|
141
|
+
'custom.attribute': 'value',
|
|
264
142
|
});
|
|
265
|
-
```
|
|
266
143
|
|
|
267
|
-
|
|
144
|
+
// Your code here
|
|
268
145
|
|
|
269
|
-
|
|
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
|
-
|
|
149
|
+
## Data Collection
|
|
277
150
|
|
|
278
|
-
|
|
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
|
-
|
|
153
|
+
### ✅ **Collected Data**
|
|
286
154
|
|
|
287
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
169
|
+
### 🔒 **Privacy Protection**
|
|
311
170
|
|
|
312
|
-
|
|
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
|
-
|
|
315
|
-
- `http.url` - Full URL
|
|
316
|
-
- `http.status_code` - Response status code
|
|
176
|
+
## Sensitive Data Filtering
|
|
317
177
|
|
|
318
|
-
**
|
|
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
|
-
|
|
321
|
-
- `lupis.chat.id` - Conversation ID (when set)
|
|
322
|
-
- `http.provider` - Detected provider (openai, claude, cohere, huggingface, google)
|
|
180
|
+
### Default Filtering
|
|
323
181
|
|
|
324
|
-
|
|
182
|
+
The SDK automatically filters these common sensitive patterns:
|
|
325
183
|
|
|
326
|
-
|
|
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
|
-
|
|
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
|
-
|
|
192
|
+
#### Authentication
|
|
335
193
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
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
|
-
|
|
198
|
+
#### Personal Data
|
|
353
199
|
|
|
354
|
-
|
|
200
|
+
- `ssn`, `social_security` - Social Security Numbers
|
|
201
|
+
- `credit_card`, `card_number` - Credit card numbers
|
|
202
|
+
- `cvv`, `cvc` - Security codes
|
|
355
203
|
|
|
356
|
-
|
|
204
|
+
### Redaction Modes
|
|
357
205
|
|
|
358
|
-
|
|
359
|
-
await sdk.run(async () => {
|
|
360
|
-
// Your code
|
|
361
|
-
}, { chatId: 'optional-chat-id' });
|
|
362
|
-
```
|
|
206
|
+
Choose how sensitive data is replaced:
|
|
363
207
|
|
|
364
|
-
####
|
|
208
|
+
#### Mask Mode (Default)
|
|
365
209
|
|
|
366
|
-
|
|
210
|
+
```javascript
|
|
211
|
+
const lupis = new LupisSDK({
|
|
212
|
+
projectId: 'your-project-id',
|
|
213
|
+
redactionMode: 'mask', // Default
|
|
214
|
+
});
|
|
367
215
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
//
|
|
371
|
-
|
|
216
|
+
// Examples:
|
|
217
|
+
// sk-1234567890abcdef1234567890abcdef12345678 → sk-1***5678
|
|
218
|
+
// Bearer sk-1234567890abcdef1234567890abcdef12345678 → Bear***5678
|
|
219
|
+
// password: 'secret-password' → password: '***'
|
|
372
220
|
```
|
|
373
221
|
|
|
374
|
-
####
|
|
222
|
+
#### Remove Mode
|
|
375
223
|
|
|
376
|
-
|
|
224
|
+
```javascript
|
|
225
|
+
const lupis = new LupisSDK({
|
|
226
|
+
projectId: 'your-project-id',
|
|
227
|
+
redactionMode: 'remove',
|
|
228
|
+
});
|
|
377
229
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
230
|
+
// Examples:
|
|
231
|
+
// sk-1234567890abcdef1234567890abcdef12345678 → [REDACTED]
|
|
232
|
+
// password: 'secret-password' → password: [REDACTED]
|
|
381
233
|
```
|
|
382
234
|
|
|
383
|
-
####
|
|
235
|
+
#### Hash Mode
|
|
384
236
|
|
|
385
|
-
|
|
237
|
+
```javascript
|
|
238
|
+
const lupis = new LupisSDK({
|
|
239
|
+
projectId: 'your-project-id',
|
|
240
|
+
redactionMode: 'hash',
|
|
241
|
+
});
|
|
386
242
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
}, SpanKind.INTERNAL);
|
|
243
|
+
// Examples:
|
|
244
|
+
// sk-1234567890abcdef1234567890abcdef12345678 → [HASH:2dd0e9d5]
|
|
245
|
+
// password: 'secret-password' → password: [HASHED]
|
|
391
246
|
```
|
|
392
247
|
|
|
393
|
-
|
|
248
|
+
### Custom Patterns
|
|
394
249
|
|
|
395
|
-
|
|
250
|
+
Add your own sensitive data patterns:
|
|
396
251
|
|
|
397
|
-
```
|
|
398
|
-
|
|
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
|
-
|
|
267
|
+
### What Gets Filtered
|
|
402
268
|
|
|
403
|
-
The SDK
|
|
269
|
+
The SDK filters sensitive data in:
|
|
404
270
|
|
|
405
|
-
|
|
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
|
-
|
|
274
|
+
**Note**: Request and response bodies are never collected, so no filtering is needed for them.
|
|
415
275
|
|
|
416
|
-
###
|
|
276
|
+
### Disable Filtering (Development Only)
|
|
417
277
|
|
|
418
|
-
|
|
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
|
-
|
|
432
|
-
|
|
433
|
-
|
|
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
|
-
###
|
|
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
|
|
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
|
-
##
|
|
303
|
+
## Testing
|
|
304
|
+
|
|
305
|
+
The SDK includes comprehensive tests for sensitive data filtering:
|
|
455
306
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
307
|
+
```bash
|
|
308
|
+
# Run unit tests
|
|
309
|
+
npm run test:sensitive:unit
|
|
459
310
|
|
|
460
|
-
|
|
311
|
+
# Run integration tests
|
|
312
|
+
npm run test:sensitive:detailed
|
|
313
|
+
|
|
314
|
+
# Run all tests
|
|
315
|
+
npm run test:all
|
|
316
|
+
```
|
|
461
317
|
|
|
462
|
-
|
|
318
|
+
### Test Coverage
|
|
463
319
|
|
|
464
|
-
|
|
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
|
-
|
|
326
|
+
## Examples
|
|
467
327
|
|
|
468
|
-
|
|
328
|
+
See the `examples/` directory for more usage examples:
|
|
469
329
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
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**
|