@safekeylab/sdk 1.0.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/README.md +212 -0
- package/dist/index.d.mts +100 -0
- package/dist/index.d.ts +100 -0
- package/dist/index.js +241 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +231 -0
- package/dist/index.mjs.map +1 -0
- package/dist/integrations/anthropic.d.mts +65 -0
- package/dist/integrations/anthropic.d.ts +65 -0
- package/dist/integrations/anthropic.js +347 -0
- package/dist/integrations/anthropic.js.map +1 -0
- package/dist/integrations/anthropic.mjs +341 -0
- package/dist/integrations/anthropic.mjs.map +1 -0
- package/dist/integrations/langchain.d.mts +106 -0
- package/dist/integrations/langchain.d.ts +106 -0
- package/dist/integrations/langchain.js +415 -0
- package/dist/integrations/langchain.js.map +1 -0
- package/dist/integrations/langchain.mjs +406 -0
- package/dist/integrations/langchain.mjs.map +1 -0
- package/dist/integrations/openai.d.mts +72 -0
- package/dist/integrations/openai.d.ts +72 -0
- package/dist/integrations/openai.js +327 -0
- package/dist/integrations/openai.js.map +1 -0
- package/dist/integrations/openai.mjs +321 -0
- package/dist/integrations/openai.mjs.map +1 -0
- package/dist/integrations/vercel-ai.d.mts +80 -0
- package/dist/integrations/vercel-ai.d.ts +80 -0
- package/dist/integrations/vercel-ai.js +377 -0
- package/dist/integrations/vercel-ai.js.map +1 -0
- package/dist/integrations/vercel-ai.mjs +371 -0
- package/dist/integrations/vercel-ai.mjs.map +1 -0
- package/dist/types-CtDYLaOX.d.mts +129 -0
- package/dist/types-CtDYLaOX.d.ts +129 -0
- package/package.json +106 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
// src/types.ts
|
|
2
|
+
var SafeKeyLabError = class extends Error {
|
|
3
|
+
constructor(message, code, statusCode) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.code = code;
|
|
6
|
+
this.statusCode = statusCode;
|
|
7
|
+
this.name = "SafeKeyLabError";
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var PIIBlockedError = class extends SafeKeyLabError {
|
|
11
|
+
constructor(detections) {
|
|
12
|
+
super(
|
|
13
|
+
`Request blocked: PII detected (${detections.map((d) => d.type).join(", ")})`,
|
|
14
|
+
"PII_BLOCKED"
|
|
15
|
+
);
|
|
16
|
+
this.detections = detections;
|
|
17
|
+
this.name = "PIIBlockedError";
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
var ThreatBlockedError = class extends SafeKeyLabError {
|
|
21
|
+
constructor(threats) {
|
|
22
|
+
super(
|
|
23
|
+
`Request blocked: Threat detected (${threats.map((t) => t.type).join(", ")})`,
|
|
24
|
+
"THREAT_BLOCKED"
|
|
25
|
+
);
|
|
26
|
+
this.threats = threats;
|
|
27
|
+
this.name = "ThreatBlockedError";
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// src/client.ts
|
|
32
|
+
var DEFAULT_BASE_URL = "https://api.safekeylab.com";
|
|
33
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
34
|
+
var SafeKeyLab = class {
|
|
35
|
+
constructor(config) {
|
|
36
|
+
if (!config.apiKey) {
|
|
37
|
+
throw new SafeKeyLabError("API key is required", "MISSING_API_KEY");
|
|
38
|
+
}
|
|
39
|
+
this.apiKey = config.apiKey;
|
|
40
|
+
this.baseUrl = config.baseUrl || DEFAULT_BASE_URL;
|
|
41
|
+
this.timeout = config.timeout || DEFAULT_TIMEOUT;
|
|
42
|
+
this.debug = config.debug || false;
|
|
43
|
+
}
|
|
44
|
+
log(...args) {
|
|
45
|
+
if (this.debug) {
|
|
46
|
+
console.log("[SafeKeyLab]", ...args);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async request(method, endpoint, body) {
|
|
50
|
+
const url = `${this.baseUrl}${endpoint}`;
|
|
51
|
+
const controller = new AbortController();
|
|
52
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
53
|
+
this.log(`${method} ${url}`, body);
|
|
54
|
+
try {
|
|
55
|
+
const response = await fetch(url, {
|
|
56
|
+
method,
|
|
57
|
+
headers: {
|
|
58
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
59
|
+
"Content-Type": "application/json",
|
|
60
|
+
"User-Agent": "@safekeylab/sdk/1.0.0"
|
|
61
|
+
},
|
|
62
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
63
|
+
signal: controller.signal
|
|
64
|
+
});
|
|
65
|
+
clearTimeout(timeoutId);
|
|
66
|
+
const data = await response.json();
|
|
67
|
+
if (!response.ok) {
|
|
68
|
+
throw new SafeKeyLabError(
|
|
69
|
+
data.error || data.message || "Request failed",
|
|
70
|
+
data.code || "API_ERROR",
|
|
71
|
+
response.status
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
this.log("Response:", data);
|
|
75
|
+
return data;
|
|
76
|
+
} catch (error) {
|
|
77
|
+
clearTimeout(timeoutId);
|
|
78
|
+
if (error instanceof SafeKeyLabError) {
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
if (error instanceof Error) {
|
|
82
|
+
if (error.name === "AbortError") {
|
|
83
|
+
throw new SafeKeyLabError("Request timeout", "TIMEOUT");
|
|
84
|
+
}
|
|
85
|
+
throw new SafeKeyLabError(error.message, "NETWORK_ERROR");
|
|
86
|
+
}
|
|
87
|
+
throw new SafeKeyLabError("Unknown error", "UNKNOWN_ERROR");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Detect PII in text
|
|
92
|
+
*/
|
|
93
|
+
async detect(request) {
|
|
94
|
+
return this.request("POST", "/v1/detect", request);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Detect PII in text (convenience method)
|
|
98
|
+
*/
|
|
99
|
+
async detectPII(text, options) {
|
|
100
|
+
return this.detect({ text, ...options });
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Redact/protect PII in text
|
|
104
|
+
*/
|
|
105
|
+
async protect(request) {
|
|
106
|
+
return this.request("POST", "/v1/protect", request);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Redact PII from text (convenience method)
|
|
110
|
+
*/
|
|
111
|
+
async redact(text, options) {
|
|
112
|
+
const response = await this.protect({ text, ...options });
|
|
113
|
+
return response.redacted_text;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Validate a prompt for security threats
|
|
117
|
+
*/
|
|
118
|
+
async validatePrompt(request) {
|
|
119
|
+
return this.request("POST", "/v1/validate-prompt", request);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Check if a prompt is safe (convenience method)
|
|
123
|
+
*/
|
|
124
|
+
async isPromptSafe(prompt, context) {
|
|
125
|
+
const response = await this.validatePrompt({ prompt, context });
|
|
126
|
+
return response.is_safe;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Scan LLM output for issues
|
|
130
|
+
*/
|
|
131
|
+
async scanOutput(request) {
|
|
132
|
+
return this.request("POST", "/v1/scan-output", request);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Full protection pipeline: validate input, redact PII, return protected text
|
|
136
|
+
*/
|
|
137
|
+
async protectInput(text) {
|
|
138
|
+
const [detectResult, validateResult] = await Promise.all([
|
|
139
|
+
this.detect({ text }),
|
|
140
|
+
this.validatePrompt({ prompt: text })
|
|
141
|
+
]);
|
|
142
|
+
let protectedText = text;
|
|
143
|
+
let wasModified = false;
|
|
144
|
+
if (detectResult.count > 0) {
|
|
145
|
+
const protectResult = await this.protect({ text });
|
|
146
|
+
protectedText = protectResult.redacted_text;
|
|
147
|
+
wasModified = true;
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
text: protectedText,
|
|
151
|
+
wasModified,
|
|
152
|
+
detections: detectResult.detections,
|
|
153
|
+
threats: validateResult.threats
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Create a sandbox client (no API key required, rate limited)
|
|
158
|
+
*/
|
|
159
|
+
static sandbox(options) {
|
|
160
|
+
return new SafeKeyLabSandbox(options);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
var SafeKeyLabSandbox = class {
|
|
164
|
+
constructor(config) {
|
|
165
|
+
this.baseUrl = config?.baseUrl || DEFAULT_BASE_URL;
|
|
166
|
+
this.timeout = config?.timeout || DEFAULT_TIMEOUT;
|
|
167
|
+
this.debug = config?.debug || false;
|
|
168
|
+
}
|
|
169
|
+
log(...args) {
|
|
170
|
+
if (this.debug) {
|
|
171
|
+
console.log("[SafeKeyLab:Sandbox]", ...args);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
async request(method, endpoint, body) {
|
|
175
|
+
const url = `${this.baseUrl}${endpoint}`;
|
|
176
|
+
const controller = new AbortController();
|
|
177
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
178
|
+
this.log(`${method} ${url}`, body);
|
|
179
|
+
try {
|
|
180
|
+
const response = await fetch(url, {
|
|
181
|
+
method,
|
|
182
|
+
headers: {
|
|
183
|
+
"Content-Type": "application/json",
|
|
184
|
+
"User-Agent": "@safekeylab/sdk/1.0.0"
|
|
185
|
+
},
|
|
186
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
187
|
+
signal: controller.signal
|
|
188
|
+
});
|
|
189
|
+
clearTimeout(timeoutId);
|
|
190
|
+
const data = await response.json();
|
|
191
|
+
if (!response.ok) {
|
|
192
|
+
throw new SafeKeyLabError(
|
|
193
|
+
data.error || data.message || "Request failed",
|
|
194
|
+
data.code || "API_ERROR",
|
|
195
|
+
response.status
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
this.log("Response:", data);
|
|
199
|
+
return data;
|
|
200
|
+
} catch (error) {
|
|
201
|
+
clearTimeout(timeoutId);
|
|
202
|
+
if (error instanceof SafeKeyLabError) {
|
|
203
|
+
throw error;
|
|
204
|
+
}
|
|
205
|
+
if (error instanceof Error) {
|
|
206
|
+
if (error.name === "AbortError") {
|
|
207
|
+
throw new SafeKeyLabError("Request timeout", "TIMEOUT");
|
|
208
|
+
}
|
|
209
|
+
throw new SafeKeyLabError(error.message, "NETWORK_ERROR");
|
|
210
|
+
}
|
|
211
|
+
throw new SafeKeyLabError("Unknown error", "UNKNOWN_ERROR");
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
async detect(request) {
|
|
215
|
+
return this.request("POST", "/sandbox/v1/detect", request);
|
|
216
|
+
}
|
|
217
|
+
async protect(request) {
|
|
218
|
+
return this.request("POST", "/sandbox/v1/protect", request);
|
|
219
|
+
}
|
|
220
|
+
async validatePrompt(request) {
|
|
221
|
+
return this.request("POST", "/sandbox/v1/validate-prompt", request);
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// src/integrations/vercel-ai.ts
|
|
226
|
+
function withSafeKeyLab(model, options) {
|
|
227
|
+
const safekeylab = new SafeKeyLab({
|
|
228
|
+
apiKey: options.apiKey,
|
|
229
|
+
baseUrl: options.baseUrl,
|
|
230
|
+
timeout: options.timeout,
|
|
231
|
+
debug: options.debug
|
|
232
|
+
});
|
|
233
|
+
const config = {
|
|
234
|
+
blockOnPII: options.blockOnPII ?? false,
|
|
235
|
+
blockOnThreat: options.blockOnThreat ?? true,
|
|
236
|
+
piiTypes: options.piiTypes,
|
|
237
|
+
scanOutputs: options.scanOutputs ?? true,
|
|
238
|
+
onError: options.onError,
|
|
239
|
+
onPIIDetected: options.onPIIDetected,
|
|
240
|
+
onThreatDetected: options.onThreatDetected
|
|
241
|
+
};
|
|
242
|
+
const wrappedModel = {
|
|
243
|
+
specificationVersion: model.specificationVersion,
|
|
244
|
+
provider: `safekeylab:${model.provider}`,
|
|
245
|
+
modelId: model.modelId,
|
|
246
|
+
defaultObjectGenerationMode: model.defaultObjectGenerationMode,
|
|
247
|
+
async doGenerate(generateOptions) {
|
|
248
|
+
const allDetections = [];
|
|
249
|
+
const allThreats = [];
|
|
250
|
+
const protectedPrompt = await processPrompt(
|
|
251
|
+
safekeylab,
|
|
252
|
+
config,
|
|
253
|
+
generateOptions.prompt,
|
|
254
|
+
allDetections,
|
|
255
|
+
allThreats
|
|
256
|
+
);
|
|
257
|
+
const result = await model.doGenerate({
|
|
258
|
+
...generateOptions,
|
|
259
|
+
prompt: protectedPrompt
|
|
260
|
+
});
|
|
261
|
+
if (config.scanOutputs && result.text) {
|
|
262
|
+
const scanResult = await safekeylab.scanOutput({ output: result.text });
|
|
263
|
+
if (!scanResult.is_safe) {
|
|
264
|
+
result._safekeylab_output_issues = scanResult.issues;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
result._safekeylab = {
|
|
268
|
+
pii_detected: allDetections,
|
|
269
|
+
threats_detected: allThreats,
|
|
270
|
+
inputs_modified: allDetections.length > 0
|
|
271
|
+
};
|
|
272
|
+
return result;
|
|
273
|
+
},
|
|
274
|
+
async doStream(streamOptions) {
|
|
275
|
+
if (!model.doStream) {
|
|
276
|
+
throw new Error("Model does not support streaming");
|
|
277
|
+
}
|
|
278
|
+
const allDetections = [];
|
|
279
|
+
const allThreats = [];
|
|
280
|
+
const protectedPrompt = await processPrompt(
|
|
281
|
+
safekeylab,
|
|
282
|
+
config,
|
|
283
|
+
streamOptions.prompt,
|
|
284
|
+
allDetections,
|
|
285
|
+
allThreats
|
|
286
|
+
);
|
|
287
|
+
return model.doStream({
|
|
288
|
+
...streamOptions,
|
|
289
|
+
prompt: protectedPrompt
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
return wrappedModel;
|
|
294
|
+
}
|
|
295
|
+
async function processPrompt(client, config, prompt, allDetections, allThreats) {
|
|
296
|
+
const protectedPrompt = { ...prompt };
|
|
297
|
+
if (prompt.system) {
|
|
298
|
+
const [detectResult, validateResult] = await Promise.all([
|
|
299
|
+
client.detect({ text: prompt.system, types: config.piiTypes }),
|
|
300
|
+
client.validatePrompt({ prompt: prompt.system })
|
|
301
|
+
]);
|
|
302
|
+
if (detectResult.detections.length > 0) {
|
|
303
|
+
allDetections.push(...detectResult.detections);
|
|
304
|
+
config.onPIIDetected?.(detectResult.detections);
|
|
305
|
+
if (config.blockOnPII) {
|
|
306
|
+
throw new PIIBlockedError(detectResult.detections);
|
|
307
|
+
}
|
|
308
|
+
const protectResult = await client.protect({ text: prompt.system });
|
|
309
|
+
protectedPrompt.system = protectResult.redacted_text;
|
|
310
|
+
}
|
|
311
|
+
if (validateResult.threats.length > 0) {
|
|
312
|
+
allThreats.push(...validateResult.threats);
|
|
313
|
+
config.onThreatDetected?.(validateResult.threats);
|
|
314
|
+
if (config.blockOnThreat) {
|
|
315
|
+
throw new ThreatBlockedError(validateResult.threats);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
if (prompt.messages) {
|
|
320
|
+
protectedPrompt.messages = await Promise.all(
|
|
321
|
+
prompt.messages.map(async (message) => {
|
|
322
|
+
const content = extractContent(message.content);
|
|
323
|
+
if (!content) return message;
|
|
324
|
+
const [detectResult, validateResult] = await Promise.all([
|
|
325
|
+
client.detect({ text: content, types: config.piiTypes }),
|
|
326
|
+
client.validatePrompt({ prompt: content })
|
|
327
|
+
]);
|
|
328
|
+
if (detectResult.detections.length > 0) {
|
|
329
|
+
allDetections.push(...detectResult.detections);
|
|
330
|
+
config.onPIIDetected?.(detectResult.detections);
|
|
331
|
+
if (config.blockOnPII) {
|
|
332
|
+
throw new PIIBlockedError(detectResult.detections);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
if (validateResult.threats.length > 0) {
|
|
336
|
+
allThreats.push(...validateResult.threats);
|
|
337
|
+
config.onThreatDetected?.(validateResult.threats);
|
|
338
|
+
if (config.blockOnThreat) {
|
|
339
|
+
throw new ThreatBlockedError(validateResult.threats);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
if (detectResult.detections.length > 0) {
|
|
343
|
+
const protectResult = await client.protect({ text: content });
|
|
344
|
+
return {
|
|
345
|
+
...message,
|
|
346
|
+
content: protectResult.redacted_text
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
return message;
|
|
350
|
+
})
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
return protectedPrompt;
|
|
354
|
+
}
|
|
355
|
+
function extractContent(content) {
|
|
356
|
+
if (typeof content === "string") {
|
|
357
|
+
return content;
|
|
358
|
+
}
|
|
359
|
+
if (Array.isArray(content)) {
|
|
360
|
+
return content.filter((part) => part.type === "text" && part.text).map((part) => part.text).join("\n");
|
|
361
|
+
}
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
function createSafeKeyLabMiddleware(options) {
|
|
365
|
+
return (model) => withSafeKeyLab(model, options);
|
|
366
|
+
}
|
|
367
|
+
var vercel_ai_default = withSafeKeyLab;
|
|
368
|
+
|
|
369
|
+
export { createSafeKeyLabMiddleware, vercel_ai_default as default, withSafeKeyLab };
|
|
370
|
+
//# sourceMappingURL=vercel-ai.mjs.map
|
|
371
|
+
//# sourceMappingURL=vercel-ai.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/types.ts","../../src/client.ts","../../src/integrations/vercel-ai.ts"],"names":[],"mappings":"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","file":"vercel-ai.mjs","sourcesContent":["/**\n * SafeKeyLab SDK Types\n */\n\nexport interface SafeKeyLabConfig {\n /** API key for authentication */\n apiKey: string;\n /** Base URL for the API (default: https://api.safekeylab.com) */\n baseUrl?: string;\n /** Request timeout in milliseconds (default: 30000) */\n timeout?: number;\n /** Enable debug logging (default: false) */\n debug?: boolean;\n}\n\nexport interface PIIDetection {\n /** Type of PII detected (EMAIL, PHONE, SSN, etc.) */\n type: string;\n /** The detected value */\n value: string;\n /** Start position in text */\n start: number;\n /** End position in text */\n end: number;\n /** Confidence score (0-1) */\n confidence: number;\n}\n\nexport interface DetectRequest {\n /** Text to scan for PII */\n text: string;\n /** Types of PII to detect (default: all) */\n types?: string[];\n /** Minimum confidence threshold (default: 0.5) */\n minConfidence?: number;\n}\n\nexport interface DetectResponse {\n success: boolean;\n detections: PIIDetection[];\n count: number;\n processing_time_ms: number;\n}\n\nexport interface ProtectRequest {\n /** Text to redact PII from */\n text: string;\n /** Types of PII to redact (default: all) */\n types?: string[];\n /** Redaction style: 'placeholder' | 'mask' | 'hash' (default: placeholder) */\n style?: 'placeholder' | 'mask' | 'hash';\n}\n\nexport interface Redaction {\n type: string;\n original: string;\n start: number;\n end: number;\n}\n\nexport interface ProtectResponse {\n success: boolean;\n redacted_text: string;\n redactions: Redaction[];\n redactions_count: number;\n original_length: number;\n redacted_length: number;\n processing_time_ms: number;\n}\n\nexport interface ValidatePromptRequest {\n /** Prompt to validate */\n prompt: string;\n /** Additional context for validation */\n context?: string;\n}\n\nexport interface Threat {\n type: string;\n severity: 'low' | 'medium' | 'high' | 'critical';\n description: string;\n matched?: string;\n}\n\nexport interface ValidatePromptResponse {\n success: boolean;\n is_safe: boolean;\n threats: Threat[];\n threats_detected: number;\n recommendation: 'allow' | 'review' | 'block';\n processing_time_ms: number;\n}\n\nexport interface ScanOutputRequest {\n /** LLM output to scan */\n output: string;\n /** Original prompt for context */\n prompt?: string;\n}\n\nexport interface ScanOutputResponse {\n success: boolean;\n is_safe: boolean;\n issues: Array<{\n type: string;\n severity: string;\n description: string;\n }>;\n processing_time_ms: number;\n}\n\nexport interface WrapperConfig {\n /** Block requests containing PII (default: false, will redact instead) */\n blockOnPII?: boolean;\n /** Block requests with detected threats (default: true) */\n blockOnThreat?: boolean;\n /** Types of PII to detect/redact */\n piiTypes?: string[];\n /** Scan LLM outputs for issues (default: true) */\n scanOutputs?: boolean;\n /** Custom error handler */\n onError?: (error: Error) => void;\n /** Callback when PII is detected */\n onPIIDetected?: (detections: PIIDetection[]) => void;\n /** Callback when threat is detected */\n onThreatDetected?: (threats: Threat[]) => void;\n}\n\nexport class SafeKeyLabError extends Error {\n constructor(\n message: string,\n public code: string,\n public statusCode?: number\n ) {\n super(message);\n this.name = 'SafeKeyLabError';\n }\n}\n\nexport class PIIBlockedError extends SafeKeyLabError {\n constructor(\n public detections: PIIDetection[]\n ) {\n super(\n `Request blocked: PII detected (${detections.map(d => d.type).join(', ')})`,\n 'PII_BLOCKED'\n );\n this.name = 'PIIBlockedError';\n }\n}\n\nexport class ThreatBlockedError extends SafeKeyLabError {\n constructor(\n public threats: Threat[]\n ) {\n super(\n `Request blocked: Threat detected (${threats.map(t => t.type).join(', ')})`,\n 'THREAT_BLOCKED'\n );\n this.name = 'ThreatBlockedError';\n }\n}\n","/**\n * SafeKeyLab API Client\n */\n\nimport {\n SafeKeyLabConfig,\n DetectRequest,\n DetectResponse,\n ProtectRequest,\n ProtectResponse,\n ValidatePromptRequest,\n ValidatePromptResponse,\n ScanOutputRequest,\n ScanOutputResponse,\n SafeKeyLabError,\n} from './types';\n\nconst DEFAULT_BASE_URL = 'https://api.safekeylab.com';\nconst DEFAULT_TIMEOUT = 30000;\n\nexport class SafeKeyLab {\n private apiKey: string;\n private baseUrl: string;\n private timeout: number;\n private debug: boolean;\n\n constructor(config: SafeKeyLabConfig) {\n if (!config.apiKey) {\n throw new SafeKeyLabError('API key is required', 'MISSING_API_KEY');\n }\n this.apiKey = config.apiKey;\n this.baseUrl = config.baseUrl || DEFAULT_BASE_URL;\n this.timeout = config.timeout || DEFAULT_TIMEOUT;\n this.debug = config.debug || false;\n }\n\n private log(...args: unknown[]): void {\n if (this.debug) {\n console.log('[SafeKeyLab]', ...args);\n }\n }\n\n private async request<T>(\n method: string,\n endpoint: string,\n body?: unknown\n ): Promise<T> {\n const url = `${this.baseUrl}${endpoint}`;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n this.log(`${method} ${url}`, body);\n\n try {\n const response = await fetch(url, {\n method,\n headers: {\n 'Authorization': `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n 'User-Agent': '@safekeylab/sdk/1.0.0',\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n const data = await response.json() as Record<string, unknown>;\n\n if (!response.ok) {\n throw new SafeKeyLabError(\n (data.error as string) || (data.message as string) || 'Request failed',\n (data.code as string) || 'API_ERROR',\n response.status\n );\n }\n\n this.log('Response:', data);\n return data as T;\n } catch (error) {\n clearTimeout(timeoutId);\n if (error instanceof SafeKeyLabError) {\n throw error;\n }\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n throw new SafeKeyLabError('Request timeout', 'TIMEOUT');\n }\n throw new SafeKeyLabError(error.message, 'NETWORK_ERROR');\n }\n throw new SafeKeyLabError('Unknown error', 'UNKNOWN_ERROR');\n }\n }\n\n /**\n * Detect PII in text\n */\n async detect(request: DetectRequest): Promise<DetectResponse> {\n return this.request<DetectResponse>('POST', '/v1/detect', request);\n }\n\n /**\n * Detect PII in text (convenience method)\n */\n async detectPII(text: string, options?: Omit<DetectRequest, 'text'>): Promise<DetectResponse> {\n return this.detect({ text, ...options });\n }\n\n /**\n * Redact/protect PII in text\n */\n async protect(request: ProtectRequest): Promise<ProtectResponse> {\n return this.request<ProtectResponse>('POST', '/v1/protect', request);\n }\n\n /**\n * Redact PII from text (convenience method)\n */\n async redact(text: string, options?: Omit<ProtectRequest, 'text'>): Promise<string> {\n const response = await this.protect({ text, ...options });\n return response.redacted_text;\n }\n\n /**\n * Validate a prompt for security threats\n */\n async validatePrompt(request: ValidatePromptRequest): Promise<ValidatePromptResponse> {\n return this.request<ValidatePromptResponse>('POST', '/v1/validate-prompt', request);\n }\n\n /**\n * Check if a prompt is safe (convenience method)\n */\n async isPromptSafe(prompt: string, context?: string): Promise<boolean> {\n const response = await this.validatePrompt({ prompt, context });\n return response.is_safe;\n }\n\n /**\n * Scan LLM output for issues\n */\n async scanOutput(request: ScanOutputRequest): Promise<ScanOutputResponse> {\n return this.request<ScanOutputResponse>('POST', '/v1/scan-output', request);\n }\n\n /**\n * Full protection pipeline: validate input, redact PII, return protected text\n */\n async protectInput(text: string): Promise<{\n text: string;\n wasModified: boolean;\n detections: DetectResponse['detections'];\n threats: ValidatePromptResponse['threats'];\n }> {\n // Run detection and validation in parallel\n const [detectResult, validateResult] = await Promise.all([\n this.detect({ text }),\n this.validatePrompt({ prompt: text }),\n ]);\n\n let protectedText = text;\n let wasModified = false;\n\n // Redact if PII found\n if (detectResult.count > 0) {\n const protectResult = await this.protect({ text });\n protectedText = protectResult.redacted_text;\n wasModified = true;\n }\n\n return {\n text: protectedText,\n wasModified,\n detections: detectResult.detections,\n threats: validateResult.threats,\n };\n }\n\n /**\n * Create a sandbox client (no API key required, rate limited)\n */\n static sandbox(options?: Omit<SafeKeyLabConfig, 'apiKey'>): SafeKeyLabSandbox {\n return new SafeKeyLabSandbox(options);\n }\n}\n\n/**\n * Sandbox client for testing (no API key required)\n */\nexport class SafeKeyLabSandbox {\n private baseUrl: string;\n private timeout: number;\n private debug: boolean;\n\n constructor(config?: Omit<SafeKeyLabConfig, 'apiKey'>) {\n this.baseUrl = config?.baseUrl || DEFAULT_BASE_URL;\n this.timeout = config?.timeout || DEFAULT_TIMEOUT;\n this.debug = config?.debug || false;\n }\n\n private log(...args: unknown[]): void {\n if (this.debug) {\n console.log('[SafeKeyLab:Sandbox]', ...args);\n }\n }\n\n private async request<T>(\n method: string,\n endpoint: string,\n body?: unknown\n ): Promise<T> {\n const url = `${this.baseUrl}${endpoint}`;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n this.log(`${method} ${url}`, body);\n\n try {\n const response = await fetch(url, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n 'User-Agent': '@safekeylab/sdk/1.0.0',\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n const data = await response.json() as Record<string, unknown>;\n\n if (!response.ok) {\n throw new SafeKeyLabError(\n (data.error as string) || (data.message as string) || 'Request failed',\n (data.code as string) || 'API_ERROR',\n response.status\n );\n }\n\n this.log('Response:', data);\n return data as T;\n } catch (error) {\n clearTimeout(timeoutId);\n if (error instanceof SafeKeyLabError) {\n throw error;\n }\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n throw new SafeKeyLabError('Request timeout', 'TIMEOUT');\n }\n throw new SafeKeyLabError(error.message, 'NETWORK_ERROR');\n }\n throw new SafeKeyLabError('Unknown error', 'UNKNOWN_ERROR');\n }\n }\n\n async detect(request: DetectRequest): Promise<DetectResponse> {\n return this.request<DetectResponse>('POST', '/sandbox/v1/detect', request);\n }\n\n async protect(request: ProtectRequest): Promise<ProtectResponse> {\n return this.request<ProtectResponse>('POST', '/sandbox/v1/protect', request);\n }\n\n async validatePrompt(request: ValidatePromptRequest): Promise<ValidatePromptResponse> {\n return this.request<ValidatePromptResponse>('POST', '/sandbox/v1/validate-prompt', request);\n }\n}\n\nexport default SafeKeyLab;\n","/**\n * SafeKeyLab Vercel AI SDK Integration\n *\n * Provides middleware and wrappers for the Vercel AI SDK\n *\n * @example\n * ```typescript\n * import { openai } from '@ai-sdk/openai';\n * import { generateText } from 'ai';\n * import { withSafeKeyLab } from '@safekeylab/sdk/vercel-ai';\n *\n * // Wrap the model with SafeKeyLab protection\n * const protectedModel = withSafeKeyLab(openai('gpt-4'), {\n * apiKey: 'sk_live_...',\n * });\n *\n * const { text } = await generateText({\n * model: protectedModel,\n * prompt: 'My email is john@example.com',\n * });\n * // Input is automatically protected\n * ```\n */\n\nimport { SafeKeyLab } from '../client';\nimport {\n SafeKeyLabConfig,\n WrapperConfig,\n PIIDetection,\n Threat,\n PIIBlockedError,\n ThreatBlockedError,\n} from '../types';\n\n// Minimal Vercel AI types\ninterface LanguageModelV1 {\n specificationVersion: 'v1';\n provider: string;\n modelId: string;\n defaultObjectGenerationMode?: 'json' | 'tool' | 'grammar';\n doGenerate(options: DoGenerateOptions): Promise<DoGenerateResult>;\n doStream?(options: DoGenerateOptions): Promise<DoStreamResult>;\n}\n\ninterface DoGenerateOptions {\n inputFormat: 'prompt' | 'messages';\n mode: { type: string; [key: string]: unknown };\n prompt: LanguageModelPrompt;\n [key: string]: unknown;\n}\n\ninterface LanguageModelPrompt {\n system?: string;\n messages?: Array<{\n role: 'user' | 'assistant' | 'system' | 'tool';\n content: string | Array<{ type: string; text?: string; [key: string]: unknown }>;\n }>;\n}\n\ninterface DoGenerateResult {\n text?: string;\n toolCalls?: unknown[];\n finishReason: string;\n usage: { promptTokens: number; completionTokens: number };\n [key: string]: unknown;\n}\n\ninterface DoStreamResult {\n stream: ReadableStream;\n [key: string]: unknown;\n}\n\nexport interface VercelAIWrapperOptions extends Partial<SafeKeyLabConfig>, WrapperConfig {}\n\n/**\n * Wrap a Vercel AI SDK model with SafeKeyLab protection\n */\nexport function withSafeKeyLab<T extends LanguageModelV1>(\n model: T,\n options: VercelAIWrapperOptions\n): T {\n const safekeylab = new SafeKeyLab({\n apiKey: options.apiKey!,\n baseUrl: options.baseUrl,\n timeout: options.timeout,\n debug: options.debug,\n });\n\n const config: WrapperConfig = {\n blockOnPII: options.blockOnPII ?? false,\n blockOnThreat: options.blockOnThreat ?? true,\n piiTypes: options.piiTypes,\n scanOutputs: options.scanOutputs ?? true,\n onError: options.onError,\n onPIIDetected: options.onPIIDetected,\n onThreatDetected: options.onThreatDetected,\n };\n\n // Create wrapped model\n const wrappedModel: LanguageModelV1 = {\n specificationVersion: model.specificationVersion,\n provider: `safekeylab:${model.provider}`,\n modelId: model.modelId,\n defaultObjectGenerationMode: model.defaultObjectGenerationMode,\n\n async doGenerate(generateOptions: DoGenerateOptions): Promise<DoGenerateResult> {\n const allDetections: PIIDetection[] = [];\n const allThreats: Threat[] = [];\n\n // Process the prompt\n const protectedPrompt = await processPrompt(\n safekeylab,\n config,\n generateOptions.prompt,\n allDetections,\n allThreats\n );\n\n // Call the original model with protected prompt\n const result = await model.doGenerate({\n ...generateOptions,\n prompt: protectedPrompt,\n });\n\n // Scan output if enabled\n if (config.scanOutputs && result.text) {\n const scanResult = await safekeylab.scanOutput({ output: result.text });\n if (!scanResult.is_safe) {\n (result as Record<string, unknown>)._safekeylab_output_issues = scanResult.issues;\n }\n }\n\n // Attach metadata\n (result as Record<string, unknown>)._safekeylab = {\n pii_detected: allDetections,\n threats_detected: allThreats,\n inputs_modified: allDetections.length > 0,\n };\n\n return result;\n },\n\n async doStream(streamOptions: DoGenerateOptions): Promise<DoStreamResult> {\n if (!model.doStream) {\n throw new Error('Model does not support streaming');\n }\n\n const allDetections: PIIDetection[] = [];\n const allThreats: Threat[] = [];\n\n // Process the prompt\n const protectedPrompt = await processPrompt(\n safekeylab,\n config,\n streamOptions.prompt,\n allDetections,\n allThreats\n );\n\n // Call the original model with protected prompt\n return model.doStream({\n ...streamOptions,\n prompt: protectedPrompt,\n });\n },\n };\n\n return wrappedModel as T;\n}\n\n/**\n * Process prompt and apply protections\n */\nasync function processPrompt(\n client: SafeKeyLab,\n config: WrapperConfig,\n prompt: LanguageModelPrompt,\n allDetections: PIIDetection[],\n allThreats: Threat[]\n): Promise<LanguageModelPrompt> {\n const protectedPrompt: LanguageModelPrompt = { ...prompt };\n\n // Process system prompt\n if (prompt.system) {\n const [detectResult, validateResult] = await Promise.all([\n client.detect({ text: prompt.system, types: config.piiTypes }),\n client.validatePrompt({ prompt: prompt.system }),\n ]);\n\n if (detectResult.detections.length > 0) {\n allDetections.push(...detectResult.detections);\n config.onPIIDetected?.(detectResult.detections);\n\n if (config.blockOnPII) {\n throw new PIIBlockedError(detectResult.detections);\n }\n\n const protectResult = await client.protect({ text: prompt.system });\n protectedPrompt.system = protectResult.redacted_text;\n }\n\n if (validateResult.threats.length > 0) {\n allThreats.push(...validateResult.threats);\n config.onThreatDetected?.(validateResult.threats);\n\n if (config.blockOnThreat) {\n throw new ThreatBlockedError(validateResult.threats);\n }\n }\n }\n\n // Process messages\n if (prompt.messages) {\n protectedPrompt.messages = await Promise.all(\n prompt.messages.map(async (message) => {\n const content = extractContent(message.content);\n if (!content) return message;\n\n const [detectResult, validateResult] = await Promise.all([\n client.detect({ text: content, types: config.piiTypes }),\n client.validatePrompt({ prompt: content }),\n ]);\n\n if (detectResult.detections.length > 0) {\n allDetections.push(...detectResult.detections);\n config.onPIIDetected?.(detectResult.detections);\n\n if (config.blockOnPII) {\n throw new PIIBlockedError(detectResult.detections);\n }\n }\n\n if (validateResult.threats.length > 0) {\n allThreats.push(...validateResult.threats);\n config.onThreatDetected?.(validateResult.threats);\n\n if (config.blockOnThreat) {\n throw new ThreatBlockedError(validateResult.threats);\n }\n }\n\n if (detectResult.detections.length > 0) {\n const protectResult = await client.protect({ text: content });\n return {\n ...message,\n content: protectResult.redacted_text,\n };\n }\n\n return message;\n })\n );\n }\n\n return protectedPrompt;\n}\n\n/**\n * Extract text content from message content\n */\nfunction extractContent(\n content: string | Array<{ type: string; text?: string; [key: string]: unknown }>\n): string | null {\n if (typeof content === 'string') {\n return content;\n }\n if (Array.isArray(content)) {\n return content\n .filter((part) => part.type === 'text' && part.text)\n .map((part) => part.text)\n .join('\\n');\n }\n return null;\n}\n\n/**\n * Create a middleware function for Vercel AI SDK\n */\nexport function createSafeKeyLabMiddleware(options: VercelAIWrapperOptions) {\n return <T extends LanguageModelV1>(model: T): T => withSafeKeyLab(model, options);\n}\n\nexport default withSafeKeyLab;\n"]}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SafeKeyLab SDK Types
|
|
3
|
+
*/
|
|
4
|
+
interface SafeKeyLabConfig {
|
|
5
|
+
/** API key for authentication */
|
|
6
|
+
apiKey: string;
|
|
7
|
+
/** Base URL for the API (default: https://api.safekeylab.com) */
|
|
8
|
+
baseUrl?: string;
|
|
9
|
+
/** Request timeout in milliseconds (default: 30000) */
|
|
10
|
+
timeout?: number;
|
|
11
|
+
/** Enable debug logging (default: false) */
|
|
12
|
+
debug?: boolean;
|
|
13
|
+
}
|
|
14
|
+
interface PIIDetection {
|
|
15
|
+
/** Type of PII detected (EMAIL, PHONE, SSN, etc.) */
|
|
16
|
+
type: string;
|
|
17
|
+
/** The detected value */
|
|
18
|
+
value: string;
|
|
19
|
+
/** Start position in text */
|
|
20
|
+
start: number;
|
|
21
|
+
/** End position in text */
|
|
22
|
+
end: number;
|
|
23
|
+
/** Confidence score (0-1) */
|
|
24
|
+
confidence: number;
|
|
25
|
+
}
|
|
26
|
+
interface DetectRequest {
|
|
27
|
+
/** Text to scan for PII */
|
|
28
|
+
text: string;
|
|
29
|
+
/** Types of PII to detect (default: all) */
|
|
30
|
+
types?: string[];
|
|
31
|
+
/** Minimum confidence threshold (default: 0.5) */
|
|
32
|
+
minConfidence?: number;
|
|
33
|
+
}
|
|
34
|
+
interface DetectResponse {
|
|
35
|
+
success: boolean;
|
|
36
|
+
detections: PIIDetection[];
|
|
37
|
+
count: number;
|
|
38
|
+
processing_time_ms: number;
|
|
39
|
+
}
|
|
40
|
+
interface ProtectRequest {
|
|
41
|
+
/** Text to redact PII from */
|
|
42
|
+
text: string;
|
|
43
|
+
/** Types of PII to redact (default: all) */
|
|
44
|
+
types?: string[];
|
|
45
|
+
/** Redaction style: 'placeholder' | 'mask' | 'hash' (default: placeholder) */
|
|
46
|
+
style?: 'placeholder' | 'mask' | 'hash';
|
|
47
|
+
}
|
|
48
|
+
interface Redaction {
|
|
49
|
+
type: string;
|
|
50
|
+
original: string;
|
|
51
|
+
start: number;
|
|
52
|
+
end: number;
|
|
53
|
+
}
|
|
54
|
+
interface ProtectResponse {
|
|
55
|
+
success: boolean;
|
|
56
|
+
redacted_text: string;
|
|
57
|
+
redactions: Redaction[];
|
|
58
|
+
redactions_count: number;
|
|
59
|
+
original_length: number;
|
|
60
|
+
redacted_length: number;
|
|
61
|
+
processing_time_ms: number;
|
|
62
|
+
}
|
|
63
|
+
interface ValidatePromptRequest {
|
|
64
|
+
/** Prompt to validate */
|
|
65
|
+
prompt: string;
|
|
66
|
+
/** Additional context for validation */
|
|
67
|
+
context?: string;
|
|
68
|
+
}
|
|
69
|
+
interface Threat {
|
|
70
|
+
type: string;
|
|
71
|
+
severity: 'low' | 'medium' | 'high' | 'critical';
|
|
72
|
+
description: string;
|
|
73
|
+
matched?: string;
|
|
74
|
+
}
|
|
75
|
+
interface ValidatePromptResponse {
|
|
76
|
+
success: boolean;
|
|
77
|
+
is_safe: boolean;
|
|
78
|
+
threats: Threat[];
|
|
79
|
+
threats_detected: number;
|
|
80
|
+
recommendation: 'allow' | 'review' | 'block';
|
|
81
|
+
processing_time_ms: number;
|
|
82
|
+
}
|
|
83
|
+
interface ScanOutputRequest {
|
|
84
|
+
/** LLM output to scan */
|
|
85
|
+
output: string;
|
|
86
|
+
/** Original prompt for context */
|
|
87
|
+
prompt?: string;
|
|
88
|
+
}
|
|
89
|
+
interface ScanOutputResponse {
|
|
90
|
+
success: boolean;
|
|
91
|
+
is_safe: boolean;
|
|
92
|
+
issues: Array<{
|
|
93
|
+
type: string;
|
|
94
|
+
severity: string;
|
|
95
|
+
description: string;
|
|
96
|
+
}>;
|
|
97
|
+
processing_time_ms: number;
|
|
98
|
+
}
|
|
99
|
+
interface WrapperConfig {
|
|
100
|
+
/** Block requests containing PII (default: false, will redact instead) */
|
|
101
|
+
blockOnPII?: boolean;
|
|
102
|
+
/** Block requests with detected threats (default: true) */
|
|
103
|
+
blockOnThreat?: boolean;
|
|
104
|
+
/** Types of PII to detect/redact */
|
|
105
|
+
piiTypes?: string[];
|
|
106
|
+
/** Scan LLM outputs for issues (default: true) */
|
|
107
|
+
scanOutputs?: boolean;
|
|
108
|
+
/** Custom error handler */
|
|
109
|
+
onError?: (error: Error) => void;
|
|
110
|
+
/** Callback when PII is detected */
|
|
111
|
+
onPIIDetected?: (detections: PIIDetection[]) => void;
|
|
112
|
+
/** Callback when threat is detected */
|
|
113
|
+
onThreatDetected?: (threats: Threat[]) => void;
|
|
114
|
+
}
|
|
115
|
+
declare class SafeKeyLabError extends Error {
|
|
116
|
+
code: string;
|
|
117
|
+
statusCode?: number | undefined;
|
|
118
|
+
constructor(message: string, code: string, statusCode?: number | undefined);
|
|
119
|
+
}
|
|
120
|
+
declare class PIIBlockedError extends SafeKeyLabError {
|
|
121
|
+
detections: PIIDetection[];
|
|
122
|
+
constructor(detections: PIIDetection[]);
|
|
123
|
+
}
|
|
124
|
+
declare class ThreatBlockedError extends SafeKeyLabError {
|
|
125
|
+
threats: Threat[];
|
|
126
|
+
constructor(threats: Threat[]);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export { type DetectRequest as D, type ProtectRequest as P, type Redaction as R, type SafeKeyLabConfig as S, type Threat as T, type ValidatePromptRequest as V, type WrapperConfig as W, type DetectResponse as a, type ProtectResponse as b, type ValidatePromptResponse as c, type ScanOutputRequest as d, type ScanOutputResponse as e, type PIIDetection as f, SafeKeyLabError as g, PIIBlockedError as h, ThreatBlockedError as i };
|