@blindfold/sdk 1.0.0 → 1.1.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/LICENSE +21 -0
- package/README.md +49 -21
- package/dist/index.d.mts +61 -7
- package/dist/index.d.ts +61 -7
- package/dist/index.js +109 -40
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +109 -40
- package/dist/index.mjs.map +1 -1
- package/package.json +42 -5
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Blindfold
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -4,7 +4,11 @@ The official JavaScript/TypeScript SDK for Blindfold - The Privacy API for AI.
|
|
|
4
4
|
|
|
5
5
|
Securely tokenize, mask, redact, and encrypt sensitive data (PII) before sending it to LLMs or third-party services.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## How to use it
|
|
8
|
+
|
|
9
|
+
### 1. Install SDK
|
|
10
|
+
|
|
11
|
+
Javascript/ Typescript
|
|
8
12
|
|
|
9
13
|
```bash
|
|
10
14
|
npm install @blindfold/sdk
|
|
@@ -14,7 +18,21 @@ yarn add @blindfold/sdk
|
|
|
14
18
|
pnpm add @blindfold/sdk
|
|
15
19
|
```
|
|
16
20
|
|
|
17
|
-
|
|
21
|
+
Python SDK
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install blindfold-sdk
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 2. Get Blindfold API key
|
|
28
|
+
|
|
29
|
+
1. Sign up to Blindfold here.
|
|
30
|
+
1. Sign up to Blindfold [here](https://www.blindfold.dev/).
|
|
31
|
+
3. Get your API key [here](https://app.blindfold.dev/api-keys).
|
|
32
|
+
3. Set environment variable with your API key
|
|
33
|
+
```
|
|
34
|
+
BLINDFOLD_API_KEY=sk-***
|
|
35
|
+
```
|
|
18
36
|
|
|
19
37
|
### Initialization
|
|
20
38
|
|
|
@@ -30,38 +48,46 @@ const client = new Blindfold({
|
|
|
30
48
|
|
|
31
49
|
### Tokenize (Reversible)
|
|
32
50
|
|
|
33
|
-
Replace sensitive data with reversible tokens (e.g., `<
|
|
51
|
+
Replace sensitive data with reversible tokens (e.g., `<Person_1>`).
|
|
34
52
|
|
|
35
53
|
```typescript
|
|
36
54
|
const response = await client.tokenize(
|
|
37
55
|
"Contact John Doe at john@example.com",
|
|
38
56
|
{
|
|
57
|
+
// Optional: Use a pre-configured policy
|
|
58
|
+
policy: 'gdpr_eu', // or 'hipaa_us', 'basic'
|
|
39
59
|
// Optional: Filter specific entities
|
|
40
|
-
entities: ['
|
|
60
|
+
entities: ['person', 'email address'],
|
|
41
61
|
// Optional: Set confidence threshold
|
|
42
62
|
score_threshold: 0.4
|
|
43
63
|
}
|
|
44
64
|
);
|
|
45
65
|
|
|
46
|
-
console.log(response.text);
|
|
47
|
-
// "Contact <
|
|
66
|
+
console.log(response.text);
|
|
67
|
+
// "Contact <Person_1> at <Email Address_1>"
|
|
48
68
|
|
|
49
69
|
console.log(response.mapping);
|
|
50
|
-
// { "<
|
|
70
|
+
// { "<Person_1>": "John Doe", "<Email Address_1>": "john@example.com" }
|
|
51
71
|
```
|
|
52
72
|
|
|
53
73
|
### Detokenize
|
|
54
74
|
|
|
55
75
|
Restore original values from tokens.
|
|
56
76
|
|
|
77
|
+
**⚡ Note:** Detokenization is performed **client-side** for better performance, security, and offline support. No API call is made.
|
|
78
|
+
|
|
57
79
|
```typescript
|
|
58
|
-
|
|
59
|
-
|
|
80
|
+
// No await needed - runs locally!
|
|
81
|
+
const original = client.detokenize(
|
|
82
|
+
"AI response for <Person_1>",
|
|
60
83
|
response.mapping
|
|
61
84
|
);
|
|
62
85
|
|
|
63
86
|
console.log(original.text);
|
|
64
87
|
// "AI response for John Doe"
|
|
88
|
+
|
|
89
|
+
console.log(original.replacements_made);
|
|
90
|
+
// 1
|
|
65
91
|
```
|
|
66
92
|
|
|
67
93
|
### Mask
|
|
@@ -90,7 +116,7 @@ Permanently remove sensitive data.
|
|
|
90
116
|
const response = await client.redact(
|
|
91
117
|
"My password is secret123",
|
|
92
118
|
{
|
|
93
|
-
entities: ['
|
|
119
|
+
entities: ['person', 'email address']
|
|
94
120
|
}
|
|
95
121
|
);
|
|
96
122
|
```
|
|
@@ -143,17 +169,19 @@ const response = await client.encrypt(
|
|
|
143
169
|
### Entity Types
|
|
144
170
|
|
|
145
171
|
Common supported entities:
|
|
146
|
-
- `
|
|
147
|
-
- `
|
|
148
|
-
- `
|
|
149
|
-
- `
|
|
150
|
-
- `
|
|
151
|
-
- `
|
|
152
|
-
- `
|
|
153
|
-
- `
|
|
154
|
-
- `
|
|
155
|
-
- `
|
|
156
|
-
- `
|
|
172
|
+
- `person`
|
|
173
|
+
- `email address`
|
|
174
|
+
- `phone number`
|
|
175
|
+
- `credit card number`
|
|
176
|
+
- `ip address`
|
|
177
|
+
- `address`
|
|
178
|
+
- `date of birth`
|
|
179
|
+
- `organization`
|
|
180
|
+
- `iban`
|
|
181
|
+
- `social security number`
|
|
182
|
+
- `medical condition`
|
|
183
|
+
- `passport number`
|
|
184
|
+
- `driver's license number`
|
|
157
185
|
|
|
158
186
|
### Error Handling
|
|
159
187
|
|
package/dist/index.d.mts
CHANGED
|
@@ -4,10 +4,14 @@
|
|
|
4
4
|
interface BlindfoldConfig {
|
|
5
5
|
/** API key for authentication */
|
|
6
6
|
apiKey: string;
|
|
7
|
-
/** Base URL for the API (default:
|
|
7
|
+
/** Base URL for the API (default: https://api.blindfold.dev/api/public/v1) */
|
|
8
8
|
baseUrl?: string;
|
|
9
9
|
/** Optional user ID to track who is making the request */
|
|
10
10
|
userId?: string;
|
|
11
|
+
/** Maximum number of retries on transient errors (default: 2, 0 to disable) */
|
|
12
|
+
maxRetries?: number;
|
|
13
|
+
/** Initial delay in seconds before first retry (default: 0.5) */
|
|
14
|
+
retryDelay?: number;
|
|
11
15
|
}
|
|
12
16
|
/**
|
|
13
17
|
* Configuration options for tokenization
|
|
@@ -17,12 +21,34 @@ interface TokenizeConfig {
|
|
|
17
21
|
entities?: string[];
|
|
18
22
|
/** Minimum confidence score for entity detection (0.0-1.0) */
|
|
19
23
|
score_threshold?: number;
|
|
24
|
+
/** Policy name to use for detection configuration (e.g., 'gdpr_eu', 'hipaa_us', 'basic') */
|
|
25
|
+
policy?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Configuration options for detection (no text transformation)
|
|
29
|
+
*/
|
|
30
|
+
interface DetectConfig {
|
|
31
|
+
/** List of entities to detect */
|
|
32
|
+
entities?: string[];
|
|
33
|
+
/** Minimum confidence score for entity detection (0.0-1.0) */
|
|
34
|
+
score_threshold?: number;
|
|
35
|
+
/** Policy name to use for detection configuration (e.g., 'gdpr_eu', 'hipaa_us', 'basic') */
|
|
36
|
+
policy?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Response from detect endpoint
|
|
40
|
+
*/
|
|
41
|
+
interface DetectResponse {
|
|
42
|
+
/** List of detected entities */
|
|
43
|
+
detected_entities: DetectedEntity[];
|
|
44
|
+
/** Count of detected entities */
|
|
45
|
+
entities_count: number;
|
|
20
46
|
}
|
|
21
47
|
/**
|
|
22
48
|
* Detected entity information
|
|
23
49
|
*/
|
|
24
50
|
interface DetectedEntity {
|
|
25
|
-
/** Entity type (e.g.,
|
|
51
|
+
/** Entity type (e.g., "person", "email address", "phone number") */
|
|
26
52
|
entity_type: string;
|
|
27
53
|
/** Original text of the entity */
|
|
28
54
|
text: string;
|
|
@@ -65,6 +91,8 @@ interface RedactConfig {
|
|
|
65
91
|
entities?: string[];
|
|
66
92
|
/** Minimum confidence score for entity detection (0.0-1.0) */
|
|
67
93
|
score_threshold?: number;
|
|
94
|
+
/** Policy name to use for detection configuration (e.g., 'gdpr_eu', 'hipaa_us', 'basic') */
|
|
95
|
+
policy?: string;
|
|
68
96
|
}
|
|
69
97
|
/**
|
|
70
98
|
* Response from redact endpoint
|
|
@@ -91,6 +119,8 @@ interface MaskConfig {
|
|
|
91
119
|
entities?: string[];
|
|
92
120
|
/** Minimum confidence score for entity detection (0.0-1.0) */
|
|
93
121
|
score_threshold?: number;
|
|
122
|
+
/** Policy name to use for detection configuration (e.g., 'gdpr_eu', 'hipaa_us', 'basic') */
|
|
123
|
+
policy?: string;
|
|
94
124
|
}
|
|
95
125
|
/**
|
|
96
126
|
* Response from mask endpoint
|
|
@@ -113,6 +143,8 @@ interface SynthesizeConfig {
|
|
|
113
143
|
entities?: string[];
|
|
114
144
|
/** Minimum confidence score for entity detection (0.0-1.0) */
|
|
115
145
|
score_threshold?: number;
|
|
146
|
+
/** Policy name to use for detection configuration (e.g., 'gdpr_eu', 'hipaa_us', 'basic') */
|
|
147
|
+
policy?: string;
|
|
116
148
|
}
|
|
117
149
|
/**
|
|
118
150
|
* Response from synthesis endpoint
|
|
@@ -139,6 +171,8 @@ interface HashConfig {
|
|
|
139
171
|
entities?: string[];
|
|
140
172
|
/** Minimum confidence score for entity detection (0.0-1.0) */
|
|
141
173
|
score_threshold?: number;
|
|
174
|
+
/** Policy name to use for detection configuration (e.g., 'gdpr_eu', 'hipaa_us', 'basic') */
|
|
175
|
+
policy?: string;
|
|
142
176
|
}
|
|
143
177
|
/**
|
|
144
178
|
* Response from hash endpoint
|
|
@@ -161,6 +195,8 @@ interface EncryptConfig {
|
|
|
161
195
|
entities?: string[];
|
|
162
196
|
/** Minimum confidence score for entity detection (0.0-1.0) */
|
|
163
197
|
score_threshold?: number;
|
|
198
|
+
/** Policy name to use for detection configuration (e.g., 'gdpr_eu', 'hipaa_us', 'basic') */
|
|
199
|
+
policy?: string;
|
|
164
200
|
}
|
|
165
201
|
/**
|
|
166
202
|
* Response from encrypt endpoint
|
|
@@ -188,11 +224,14 @@ declare class Blindfold {
|
|
|
188
224
|
private apiKey;
|
|
189
225
|
private baseUrl;
|
|
190
226
|
private userId?;
|
|
227
|
+
private maxRetries;
|
|
228
|
+
private retryDelay;
|
|
191
229
|
/**
|
|
192
230
|
* Create a new Blindfold client
|
|
193
231
|
* @param config - Configuration options
|
|
194
232
|
*/
|
|
195
233
|
constructor(config: BlindfoldConfig);
|
|
234
|
+
private retryWait;
|
|
196
235
|
/**
|
|
197
236
|
* Make an authenticated request to the API
|
|
198
237
|
*/
|
|
@@ -204,13 +243,28 @@ declare class Blindfold {
|
|
|
204
243
|
* @returns Promise with tokenized text and mapping
|
|
205
244
|
*/
|
|
206
245
|
tokenize(text: string, config?: TokenizeConfig): Promise<TokenizeResponse>;
|
|
246
|
+
/**
|
|
247
|
+
* Detect PII in text without modifying it
|
|
248
|
+
*
|
|
249
|
+
* Returns only the detected entities with their types, positions,
|
|
250
|
+
* and confidence scores. The original text is not transformed.
|
|
251
|
+
*
|
|
252
|
+
* @param text - Text to analyze for PII
|
|
253
|
+
* @param config - Optional configuration (entities, score_threshold, policy)
|
|
254
|
+
* @returns Promise with detected entities
|
|
255
|
+
*/
|
|
256
|
+
detect(text: string, config?: DetectConfig): Promise<DetectResponse>;
|
|
207
257
|
/**
|
|
208
258
|
* Detokenize text by replacing tokens with original values
|
|
259
|
+
*
|
|
260
|
+
* This method performs detokenization CLIENT-SIDE for better performance,
|
|
261
|
+
* security, and to work offline. No API call is made.
|
|
262
|
+
*
|
|
209
263
|
* @param text - Tokenized text
|
|
210
264
|
* @param mapping - Token mapping from tokenize response
|
|
211
|
-
* @returns
|
|
265
|
+
* @returns DetokenizeResponse with original text
|
|
212
266
|
*/
|
|
213
|
-
detokenize(text: string, mapping: Record<string, string>):
|
|
267
|
+
detokenize(text: string, mapping: Record<string, string>): DetokenizeResponse;
|
|
214
268
|
/**
|
|
215
269
|
* Redact (permanently remove) sensitive information from text
|
|
216
270
|
*
|
|
@@ -272,8 +326,8 @@ declare class AuthenticationError extends BlindfoldError {
|
|
|
272
326
|
*/
|
|
273
327
|
declare class APIError extends BlindfoldError {
|
|
274
328
|
statusCode: number;
|
|
275
|
-
responseBody?:
|
|
276
|
-
constructor(message: string, statusCode: number, responseBody?:
|
|
329
|
+
responseBody?: unknown;
|
|
330
|
+
constructor(message: string, statusCode: number, responseBody?: unknown);
|
|
277
331
|
}
|
|
278
332
|
/**
|
|
279
333
|
* Error thrown when network request fails
|
|
@@ -282,4 +336,4 @@ declare class NetworkError extends BlindfoldError {
|
|
|
282
336
|
constructor(message?: string);
|
|
283
337
|
}
|
|
284
338
|
|
|
285
|
-
export { APIError, type APIErrorResponse, AuthenticationError, Blindfold, type BlindfoldConfig, BlindfoldError, type DetectedEntity, type DetokenizeResponse, NetworkError, type TokenizeConfig, type TokenizeResponse };
|
|
339
|
+
export { APIError, type APIErrorResponse, AuthenticationError, Blindfold, type BlindfoldConfig, BlindfoldError, type DetectConfig, type DetectResponse, type DetectedEntity, type DetokenizeResponse, NetworkError, type TokenizeConfig, type TokenizeResponse };
|
package/dist/index.d.ts
CHANGED
|
@@ -4,10 +4,14 @@
|
|
|
4
4
|
interface BlindfoldConfig {
|
|
5
5
|
/** API key for authentication */
|
|
6
6
|
apiKey: string;
|
|
7
|
-
/** Base URL for the API (default:
|
|
7
|
+
/** Base URL for the API (default: https://api.blindfold.dev/api/public/v1) */
|
|
8
8
|
baseUrl?: string;
|
|
9
9
|
/** Optional user ID to track who is making the request */
|
|
10
10
|
userId?: string;
|
|
11
|
+
/** Maximum number of retries on transient errors (default: 2, 0 to disable) */
|
|
12
|
+
maxRetries?: number;
|
|
13
|
+
/** Initial delay in seconds before first retry (default: 0.5) */
|
|
14
|
+
retryDelay?: number;
|
|
11
15
|
}
|
|
12
16
|
/**
|
|
13
17
|
* Configuration options for tokenization
|
|
@@ -17,12 +21,34 @@ interface TokenizeConfig {
|
|
|
17
21
|
entities?: string[];
|
|
18
22
|
/** Minimum confidence score for entity detection (0.0-1.0) */
|
|
19
23
|
score_threshold?: number;
|
|
24
|
+
/** Policy name to use for detection configuration (e.g., 'gdpr_eu', 'hipaa_us', 'basic') */
|
|
25
|
+
policy?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Configuration options for detection (no text transformation)
|
|
29
|
+
*/
|
|
30
|
+
interface DetectConfig {
|
|
31
|
+
/** List of entities to detect */
|
|
32
|
+
entities?: string[];
|
|
33
|
+
/** Minimum confidence score for entity detection (0.0-1.0) */
|
|
34
|
+
score_threshold?: number;
|
|
35
|
+
/** Policy name to use for detection configuration (e.g., 'gdpr_eu', 'hipaa_us', 'basic') */
|
|
36
|
+
policy?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Response from detect endpoint
|
|
40
|
+
*/
|
|
41
|
+
interface DetectResponse {
|
|
42
|
+
/** List of detected entities */
|
|
43
|
+
detected_entities: DetectedEntity[];
|
|
44
|
+
/** Count of detected entities */
|
|
45
|
+
entities_count: number;
|
|
20
46
|
}
|
|
21
47
|
/**
|
|
22
48
|
* Detected entity information
|
|
23
49
|
*/
|
|
24
50
|
interface DetectedEntity {
|
|
25
|
-
/** Entity type (e.g.,
|
|
51
|
+
/** Entity type (e.g., "person", "email address", "phone number") */
|
|
26
52
|
entity_type: string;
|
|
27
53
|
/** Original text of the entity */
|
|
28
54
|
text: string;
|
|
@@ -65,6 +91,8 @@ interface RedactConfig {
|
|
|
65
91
|
entities?: string[];
|
|
66
92
|
/** Minimum confidence score for entity detection (0.0-1.0) */
|
|
67
93
|
score_threshold?: number;
|
|
94
|
+
/** Policy name to use for detection configuration (e.g., 'gdpr_eu', 'hipaa_us', 'basic') */
|
|
95
|
+
policy?: string;
|
|
68
96
|
}
|
|
69
97
|
/**
|
|
70
98
|
* Response from redact endpoint
|
|
@@ -91,6 +119,8 @@ interface MaskConfig {
|
|
|
91
119
|
entities?: string[];
|
|
92
120
|
/** Minimum confidence score for entity detection (0.0-1.0) */
|
|
93
121
|
score_threshold?: number;
|
|
122
|
+
/** Policy name to use for detection configuration (e.g., 'gdpr_eu', 'hipaa_us', 'basic') */
|
|
123
|
+
policy?: string;
|
|
94
124
|
}
|
|
95
125
|
/**
|
|
96
126
|
* Response from mask endpoint
|
|
@@ -113,6 +143,8 @@ interface SynthesizeConfig {
|
|
|
113
143
|
entities?: string[];
|
|
114
144
|
/** Minimum confidence score for entity detection (0.0-1.0) */
|
|
115
145
|
score_threshold?: number;
|
|
146
|
+
/** Policy name to use for detection configuration (e.g., 'gdpr_eu', 'hipaa_us', 'basic') */
|
|
147
|
+
policy?: string;
|
|
116
148
|
}
|
|
117
149
|
/**
|
|
118
150
|
* Response from synthesis endpoint
|
|
@@ -139,6 +171,8 @@ interface HashConfig {
|
|
|
139
171
|
entities?: string[];
|
|
140
172
|
/** Minimum confidence score for entity detection (0.0-1.0) */
|
|
141
173
|
score_threshold?: number;
|
|
174
|
+
/** Policy name to use for detection configuration (e.g., 'gdpr_eu', 'hipaa_us', 'basic') */
|
|
175
|
+
policy?: string;
|
|
142
176
|
}
|
|
143
177
|
/**
|
|
144
178
|
* Response from hash endpoint
|
|
@@ -161,6 +195,8 @@ interface EncryptConfig {
|
|
|
161
195
|
entities?: string[];
|
|
162
196
|
/** Minimum confidence score for entity detection (0.0-1.0) */
|
|
163
197
|
score_threshold?: number;
|
|
198
|
+
/** Policy name to use for detection configuration (e.g., 'gdpr_eu', 'hipaa_us', 'basic') */
|
|
199
|
+
policy?: string;
|
|
164
200
|
}
|
|
165
201
|
/**
|
|
166
202
|
* Response from encrypt endpoint
|
|
@@ -188,11 +224,14 @@ declare class Blindfold {
|
|
|
188
224
|
private apiKey;
|
|
189
225
|
private baseUrl;
|
|
190
226
|
private userId?;
|
|
227
|
+
private maxRetries;
|
|
228
|
+
private retryDelay;
|
|
191
229
|
/**
|
|
192
230
|
* Create a new Blindfold client
|
|
193
231
|
* @param config - Configuration options
|
|
194
232
|
*/
|
|
195
233
|
constructor(config: BlindfoldConfig);
|
|
234
|
+
private retryWait;
|
|
196
235
|
/**
|
|
197
236
|
* Make an authenticated request to the API
|
|
198
237
|
*/
|
|
@@ -204,13 +243,28 @@ declare class Blindfold {
|
|
|
204
243
|
* @returns Promise with tokenized text and mapping
|
|
205
244
|
*/
|
|
206
245
|
tokenize(text: string, config?: TokenizeConfig): Promise<TokenizeResponse>;
|
|
246
|
+
/**
|
|
247
|
+
* Detect PII in text without modifying it
|
|
248
|
+
*
|
|
249
|
+
* Returns only the detected entities with their types, positions,
|
|
250
|
+
* and confidence scores. The original text is not transformed.
|
|
251
|
+
*
|
|
252
|
+
* @param text - Text to analyze for PII
|
|
253
|
+
* @param config - Optional configuration (entities, score_threshold, policy)
|
|
254
|
+
* @returns Promise with detected entities
|
|
255
|
+
*/
|
|
256
|
+
detect(text: string, config?: DetectConfig): Promise<DetectResponse>;
|
|
207
257
|
/**
|
|
208
258
|
* Detokenize text by replacing tokens with original values
|
|
259
|
+
*
|
|
260
|
+
* This method performs detokenization CLIENT-SIDE for better performance,
|
|
261
|
+
* security, and to work offline. No API call is made.
|
|
262
|
+
*
|
|
209
263
|
* @param text - Tokenized text
|
|
210
264
|
* @param mapping - Token mapping from tokenize response
|
|
211
|
-
* @returns
|
|
265
|
+
* @returns DetokenizeResponse with original text
|
|
212
266
|
*/
|
|
213
|
-
detokenize(text: string, mapping: Record<string, string>):
|
|
267
|
+
detokenize(text: string, mapping: Record<string, string>): DetokenizeResponse;
|
|
214
268
|
/**
|
|
215
269
|
* Redact (permanently remove) sensitive information from text
|
|
216
270
|
*
|
|
@@ -272,8 +326,8 @@ declare class AuthenticationError extends BlindfoldError {
|
|
|
272
326
|
*/
|
|
273
327
|
declare class APIError extends BlindfoldError {
|
|
274
328
|
statusCode: number;
|
|
275
|
-
responseBody?:
|
|
276
|
-
constructor(message: string, statusCode: number, responseBody?:
|
|
329
|
+
responseBody?: unknown;
|
|
330
|
+
constructor(message: string, statusCode: number, responseBody?: unknown);
|
|
277
331
|
}
|
|
278
332
|
/**
|
|
279
333
|
* Error thrown when network request fails
|
|
@@ -282,4 +336,4 @@ declare class NetworkError extends BlindfoldError {
|
|
|
282
336
|
constructor(message?: string);
|
|
283
337
|
}
|
|
284
338
|
|
|
285
|
-
export { APIError, type APIErrorResponse, AuthenticationError, Blindfold, type BlindfoldConfig, BlindfoldError, type DetectedEntity, type DetokenizeResponse, NetworkError, type TokenizeConfig, type TokenizeResponse };
|
|
339
|
+
export { APIError, type APIErrorResponse, AuthenticationError, Blindfold, type BlindfoldConfig, BlindfoldError, type DetectConfig, type DetectResponse, type DetectedEntity, type DetokenizeResponse, NetworkError, type TokenizeConfig, type TokenizeResponse };
|
package/dist/index.js
CHANGED
|
@@ -34,6 +34,10 @@ var NetworkError = class _NetworkError extends BlindfoldError {
|
|
|
34
34
|
|
|
35
35
|
// src/client.ts
|
|
36
36
|
var DEFAULT_BASE_URL = "https://api.blindfold.dev/api/public/v1";
|
|
37
|
+
var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
|
|
38
|
+
function sleep(ms) {
|
|
39
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
40
|
+
}
|
|
37
41
|
var Blindfold = class {
|
|
38
42
|
/**
|
|
39
43
|
* Create a new Blindfold client
|
|
@@ -43,6 +47,19 @@ var Blindfold = class {
|
|
|
43
47
|
this.apiKey = config.apiKey;
|
|
44
48
|
this.baseUrl = config.baseUrl || DEFAULT_BASE_URL;
|
|
45
49
|
this.userId = config.userId;
|
|
50
|
+
this.maxRetries = config.maxRetries ?? 2;
|
|
51
|
+
this.retryDelay = config.retryDelay ?? 0.5;
|
|
52
|
+
}
|
|
53
|
+
retryWait(attempt, error) {
|
|
54
|
+
if (error && error.statusCode === 429) {
|
|
55
|
+
const body = error.responseBody;
|
|
56
|
+
if (body && typeof body.retry_after === "number") {
|
|
57
|
+
return body.retry_after * 1e3;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const delay = this.retryDelay * 2 ** attempt * 1e3;
|
|
61
|
+
const jitter = delay * 0.1 * Math.random();
|
|
62
|
+
return delay + jitter;
|
|
46
63
|
}
|
|
47
64
|
/**
|
|
48
65
|
* Make an authenticated request to the API
|
|
@@ -56,43 +73,63 @@ var Blindfold = class {
|
|
|
56
73
|
if (this.userId) {
|
|
57
74
|
headers["X-Blindfold-User-Id"] = this.userId;
|
|
58
75
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
if (!response.ok) {
|
|
71
|
-
let errorMessage = `API request failed with status ${response.status}`;
|
|
72
|
-
let responseBody;
|
|
73
|
-
try {
|
|
74
|
-
responseBody = await response.json();
|
|
75
|
-
const errorData = responseBody;
|
|
76
|
-
errorMessage = errorData.detail || errorData.message || errorMessage;
|
|
77
|
-
} catch {
|
|
78
|
-
errorMessage = `${errorMessage}: ${response.statusText}`;
|
|
76
|
+
let lastError = new NetworkError("Request failed");
|
|
77
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
78
|
+
try {
|
|
79
|
+
const response = await fetch(url, {
|
|
80
|
+
method,
|
|
81
|
+
headers,
|
|
82
|
+
body: body ? JSON.stringify(body) : void 0
|
|
83
|
+
});
|
|
84
|
+
if (response.status === 401 || response.status === 403) {
|
|
85
|
+
throw new AuthenticationError("Authentication failed. Please check your API key.");
|
|
79
86
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
if (!response.ok) {
|
|
88
|
+
let errorMessage = `API request failed with status ${response.status}`;
|
|
89
|
+
let responseBody;
|
|
90
|
+
try {
|
|
91
|
+
responseBody = await response.json();
|
|
92
|
+
const errorData = responseBody;
|
|
93
|
+
errorMessage = errorData.detail || errorData.message || errorMessage;
|
|
94
|
+
} catch {
|
|
95
|
+
errorMessage = `${errorMessage}: ${response.statusText}`;
|
|
96
|
+
}
|
|
97
|
+
throw new APIError(errorMessage, response.status, responseBody);
|
|
98
|
+
}
|
|
99
|
+
return await response.json();
|
|
100
|
+
} catch (error) {
|
|
101
|
+
if (error instanceof AuthenticationError) {
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
if (error instanceof APIError) {
|
|
105
|
+
if (RETRYABLE_STATUS_CODES.has(error.statusCode) && attempt < this.maxRetries) {
|
|
106
|
+
await sleep(this.retryWait(attempt, error));
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
if (error instanceof NetworkError) {
|
|
112
|
+
lastError = error;
|
|
113
|
+
if (attempt < this.maxRetries) {
|
|
114
|
+
await sleep(this.retryWait(attempt));
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
119
|
+
if (error instanceof TypeError && error.message.includes("fetch")) {
|
|
120
|
+
lastError = new NetworkError(
|
|
121
|
+
"Network request failed. Please check your connection and the API URL."
|
|
122
|
+
);
|
|
123
|
+
if (attempt < this.maxRetries) {
|
|
124
|
+
await sleep(this.retryWait(attempt));
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
throw lastError;
|
|
128
|
+
}
|
|
129
|
+
throw new NetworkError(error instanceof Error ? error.message : "Unknown error occurred");
|
|
91
130
|
}
|
|
92
|
-
throw new NetworkError(
|
|
93
|
-
error instanceof Error ? error.message : "Unknown error occurred"
|
|
94
|
-
);
|
|
95
131
|
}
|
|
132
|
+
throw lastError;
|
|
96
133
|
}
|
|
97
134
|
/**
|
|
98
135
|
* Tokenize text by replacing sensitive information with tokens
|
|
@@ -106,17 +143,49 @@ var Blindfold = class {
|
|
|
106
143
|
...config
|
|
107
144
|
});
|
|
108
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Detect PII in text without modifying it
|
|
148
|
+
*
|
|
149
|
+
* Returns only the detected entities with their types, positions,
|
|
150
|
+
* and confidence scores. The original text is not transformed.
|
|
151
|
+
*
|
|
152
|
+
* @param text - Text to analyze for PII
|
|
153
|
+
* @param config - Optional configuration (entities, score_threshold, policy)
|
|
154
|
+
* @returns Promise with detected entities
|
|
155
|
+
*/
|
|
156
|
+
async detect(text, config) {
|
|
157
|
+
return this.request("/detect", "POST", {
|
|
158
|
+
text,
|
|
159
|
+
...config
|
|
160
|
+
});
|
|
161
|
+
}
|
|
109
162
|
/**
|
|
110
163
|
* Detokenize text by replacing tokens with original values
|
|
164
|
+
*
|
|
165
|
+
* This method performs detokenization CLIENT-SIDE for better performance,
|
|
166
|
+
* security, and to work offline. No API call is made.
|
|
167
|
+
*
|
|
111
168
|
* @param text - Tokenized text
|
|
112
169
|
* @param mapping - Token mapping from tokenize response
|
|
113
|
-
* @returns
|
|
170
|
+
* @returns DetokenizeResponse with original text
|
|
114
171
|
*/
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
172
|
+
detokenize(text, mapping) {
|
|
173
|
+
let result = text;
|
|
174
|
+
let replacements = 0;
|
|
175
|
+
const sortedTokens = Object.keys(mapping).sort((a, b) => b.length - a.length);
|
|
176
|
+
for (const token of sortedTokens) {
|
|
177
|
+
const originalValue = mapping[token];
|
|
178
|
+
const regex = new RegExp(token.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g");
|
|
179
|
+
const matches = result.match(regex);
|
|
180
|
+
if (matches) {
|
|
181
|
+
result = result.replace(regex, originalValue);
|
|
182
|
+
replacements += matches.length;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
text: result,
|
|
187
|
+
replacements_made: replacements
|
|
188
|
+
};
|
|
120
189
|
}
|
|
121
190
|
/**
|
|
122
191
|
* Redact (permanently remove) sensitive information from text
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Base error class for Blindfold SDK\n */\nexport class BlindfoldError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'BlindfoldError'\n Object.setPrototypeOf(this, BlindfoldError.prototype)\n }\n}\n\n/**\n * Error thrown when authentication fails\n */\nexport class AuthenticationError extends BlindfoldError {\n constructor(message: string = 'Authentication failed. Please check your API key.') {\n super(message)\n this.name = 'AuthenticationError'\n Object.setPrototypeOf(this, AuthenticationError.prototype)\n }\n}\n\n/**\n * Error thrown when API request fails\n */\nexport class APIError extends BlindfoldError {\n statusCode: number\n responseBody?: any\n\n constructor(message: string, statusCode: number, responseBody?: any) {\n super(message)\n this.name = 'APIError'\n this.statusCode = statusCode\n this.responseBody = responseBody\n Object.setPrototypeOf(this, APIError.prototype)\n }\n}\n\n/**\n * Error thrown when network request fails\n */\nexport class NetworkError extends BlindfoldError {\n constructor(message: string = 'Network request failed. Please check your connection.') {\n super(message)\n this.name = 'NetworkError'\n Object.setPrototypeOf(this, NetworkError.prototype)\n }\n}\n","import type {\n BlindfoldConfig,\n TokenizeConfig,\n TokenizeResponse,\n DetokenizeResponse,\n RedactConfig,\n RedactResponse,\n MaskConfig,\n MaskResponse,\n SynthesizeConfig,\n SynthesizeResponse,\n HashConfig,\n HashResponse,\n EncryptConfig,\n EncryptResponse,\n APIErrorResponse,\n} from './types'\nimport { AuthenticationError, APIError, NetworkError } from './errors'\n\nconst DEFAULT_BASE_URL = 'https://api.blindfold.dev/api/public/v1'\n\n/**\n * Blindfold client for tokenization and detokenization\n */\nexport class Blindfold {\n private apiKey: string\n private baseUrl: string\n private userId?: string\n\n /**\n * Create a new Blindfold client\n * @param config - Configuration options\n */\n constructor(config: BlindfoldConfig) {\n this.apiKey = config.apiKey\n this.baseUrl = config.baseUrl || DEFAULT_BASE_URL\n this.userId = config.userId\n }\n\n /**\n * Make an authenticated request to the API\n */\n private async request<T>(\n endpoint: string,\n method: string,\n body?: any\n ): Promise<T> {\n const url = `${this.baseUrl}${endpoint}`\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-API-Key': this.apiKey,\n }\n\n if (this.userId) {\n headers['X-Blindfold-User-Id'] = this.userId\n }\n\n try {\n const response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n })\n\n // Handle authentication errors\n if (response.status === 401 || response.status === 403) {\n throw new AuthenticationError(\n 'Authentication failed. Please check your API key.'\n )\n }\n\n // Handle other error responses\n if (!response.ok) {\n let errorMessage = `API request failed with status ${response.status}`\n let responseBody: any\n\n try {\n responseBody = await response.json()\n const errorData = responseBody as APIErrorResponse\n errorMessage = errorData.detail || errorData.message || errorMessage\n } catch {\n // If we can't parse the error response, use the status text\n errorMessage = `${errorMessage}: ${response.statusText}`\n }\n\n throw new APIError(errorMessage, response.status, responseBody)\n }\n\n return (await response.json()) as T\n } catch (error) {\n // Re-throw our custom errors\n if (\n error instanceof AuthenticationError ||\n error instanceof APIError\n ) {\n throw error\n }\n\n // Handle network errors\n if (error instanceof TypeError && error.message.includes('fetch')) {\n throw new NetworkError(\n 'Network request failed. Please check your connection and the API URL.'\n )\n }\n\n // Handle other errors\n throw new NetworkError(\n error instanceof Error ? error.message : 'Unknown error occurred'\n )\n }\n }\n\n /**\n * Tokenize text by replacing sensitive information with tokens\n * @param text - Text to tokenize\n * @param config - Optional configuration\n * @returns Promise with tokenized text and mapping\n */\n async tokenize(\n text: string,\n config?: TokenizeConfig\n ): Promise<TokenizeResponse> {\n return this.request<TokenizeResponse>('/tokenize', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Detokenize text by replacing tokens with original values\n * @param text - Tokenized text\n * @param mapping - Token mapping from tokenize response\n * @returns Promise with original text\n */\n async detokenize(\n text: string,\n mapping: Record<string, string>\n ): Promise<DetokenizeResponse> {\n return this.request<DetokenizeResponse>('/detokenize', 'POST', {\n text,\n mapping,\n })\n }\n\n /**\n * Redact (permanently remove) sensitive information from text\n *\n * WARNING: Redaction is irreversible - original data cannot be restored!\n *\n * @param text - Text to redact\n * @param config - Optional configuration (masking_char, entities)\n * @returns Promise with redacted text and detected entities\n */\n async redact(\n text: string,\n config?: RedactConfig\n ): Promise<RedactResponse> {\n return this.request<RedactResponse>('/redact', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Mask (partially hide) sensitive information from text\n *\n * @param text - Text to mask\n * @param config - Optional configuration (chars_to_show, from_end, masking_char, entities)\n * @returns Promise with masked text and detected entities\n */\n async mask(\n text: string,\n config?: MaskConfig\n ): Promise<MaskResponse> {\n return this.request<MaskResponse>('/mask', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Synthesize (replace real data with synthetic fake data)\n *\n * @param text - Text to synthesize\n * @param config - Optional configuration (language, entities)\n * @returns Promise with synthetic text and detected entities\n */\n async synthesize(\n text: string,\n config?: SynthesizeConfig\n ): Promise<SynthesizeResponse> {\n return this.request<SynthesizeResponse>('/synthesize', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Hash (replace with deterministic hash values)\n *\n * @param text - Text to hash\n * @param config - Optional configuration (hash_type, hash_prefix, hash_length, entities)\n * @returns Promise with hashed text and detected entities\n */\n async hash(\n text: string,\n config?: HashConfig\n ): Promise<HashResponse> {\n return this.request<HashResponse>('/hash', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Encrypt (reversibly protect) sensitive data in text using AES encryption\n *\n * @param text - Text to encrypt\n * @param config - Optional configuration (encryption_key, entities)\n * @returns Promise with encrypted text and detected entities\n */\n async encrypt(\n text: string,\n config?: EncryptConfig\n ): Promise<EncryptResponse> {\n return this.request<EncryptResponse>('/encrypt', 'POST', {\n text,\n ...config,\n })\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Base error class for Blindfold SDK\n */\nexport class BlindfoldError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'BlindfoldError'\n Object.setPrototypeOf(this, BlindfoldError.prototype)\n }\n}\n\n/**\n * Error thrown when authentication fails\n */\nexport class AuthenticationError extends BlindfoldError {\n constructor(message: string = 'Authentication failed. Please check your API key.') {\n super(message)\n this.name = 'AuthenticationError'\n Object.setPrototypeOf(this, AuthenticationError.prototype)\n }\n}\n\n/**\n * Error thrown when API request fails\n */\nexport class APIError extends BlindfoldError {\n statusCode: number\n responseBody?: unknown\n\n constructor(message: string, statusCode: number, responseBody?: unknown) {\n super(message)\n this.name = 'APIError'\n this.statusCode = statusCode\n this.responseBody = responseBody\n Object.setPrototypeOf(this, APIError.prototype)\n }\n}\n\n/**\n * Error thrown when network request fails\n */\nexport class NetworkError extends BlindfoldError {\n constructor(message: string = 'Network request failed. Please check your connection.') {\n super(message)\n this.name = 'NetworkError'\n Object.setPrototypeOf(this, NetworkError.prototype)\n }\n}\n","import type {\n BlindfoldConfig,\n DetectConfig,\n DetectResponse,\n TokenizeConfig,\n TokenizeResponse,\n DetokenizeResponse,\n RedactConfig,\n RedactResponse,\n MaskConfig,\n MaskResponse,\n SynthesizeConfig,\n SynthesizeResponse,\n HashConfig,\n HashResponse,\n EncryptConfig,\n EncryptResponse,\n APIErrorResponse,\n} from './types'\nimport { AuthenticationError, APIError, NetworkError } from './errors'\n\nconst DEFAULT_BASE_URL = 'https://api.blindfold.dev/api/public/v1'\nconst RETRYABLE_STATUS_CODES = new Set([429, 500, 502, 503, 504])\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\n/**\n * Blindfold client for tokenization and detokenization\n */\nexport class Blindfold {\n private apiKey: string\n private baseUrl: string\n private userId?: string\n private maxRetries: number\n private retryDelay: number\n\n /**\n * Create a new Blindfold client\n * @param config - Configuration options\n */\n constructor(config: BlindfoldConfig) {\n this.apiKey = config.apiKey\n this.baseUrl = config.baseUrl || DEFAULT_BASE_URL\n this.userId = config.userId\n this.maxRetries = config.maxRetries ?? 2\n this.retryDelay = config.retryDelay ?? 0.5\n }\n\n private retryWait(attempt: number, error?: APIError): number {\n if (error && error.statusCode === 429) {\n const body = error.responseBody as Record<string, unknown> | undefined\n if (body && typeof body.retry_after === 'number') {\n return body.retry_after * 1000\n }\n }\n const delay = this.retryDelay * (2 ** attempt) * 1000\n const jitter = delay * 0.1 * Math.random()\n return delay + jitter\n }\n\n /**\n * Make an authenticated request to the API\n */\n private async request<T>(\n endpoint: string,\n method: string,\n body?: Record<string, unknown>\n ): Promise<T> {\n const url = `${this.baseUrl}${endpoint}`\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-API-Key': this.apiKey,\n }\n\n if (this.userId) {\n headers['X-Blindfold-User-Id'] = this.userId\n }\n\n let lastError: Error = new NetworkError('Request failed')\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n try {\n const response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n })\n\n // Handle authentication errors\n if (response.status === 401 || response.status === 403) {\n throw new AuthenticationError('Authentication failed. Please check your API key.')\n }\n\n // Handle other error responses\n if (!response.ok) {\n let errorMessage = `API request failed with status ${response.status}`\n let responseBody: unknown\n\n try {\n responseBody = await response.json()\n const errorData = responseBody as APIErrorResponse\n errorMessage = errorData.detail || errorData.message || errorMessage\n } catch {\n // If we can't parse the error response, use the status text\n errorMessage = `${errorMessage}: ${response.statusText}`\n }\n\n throw new APIError(errorMessage, response.status, responseBody)\n }\n\n return (await response.json()) as T\n } catch (error) {\n // Never retry auth errors\n if (error instanceof AuthenticationError) {\n throw error\n }\n\n // Retry retryable API errors\n if (error instanceof APIError) {\n if (RETRYABLE_STATUS_CODES.has(error.statusCode) && attempt < this.maxRetries) {\n await sleep(this.retryWait(attempt, error))\n continue\n }\n throw error\n }\n\n // Retry network errors\n if (error instanceof NetworkError) {\n lastError = error\n if (attempt < this.maxRetries) {\n await sleep(this.retryWait(attempt))\n continue\n }\n throw error\n }\n\n // Handle raw fetch errors (network failures)\n if (error instanceof TypeError && error.message.includes('fetch')) {\n lastError = new NetworkError(\n 'Network request failed. Please check your connection and the API URL.'\n )\n if (attempt < this.maxRetries) {\n await sleep(this.retryWait(attempt))\n continue\n }\n throw lastError\n }\n\n // Non-retryable unknown errors\n throw new NetworkError(error instanceof Error ? error.message : 'Unknown error occurred')\n }\n }\n\n throw lastError\n }\n\n /**\n * Tokenize text by replacing sensitive information with tokens\n * @param text - Text to tokenize\n * @param config - Optional configuration\n * @returns Promise with tokenized text and mapping\n */\n async tokenize(text: string, config?: TokenizeConfig): Promise<TokenizeResponse> {\n return this.request<TokenizeResponse>('/tokenize', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Detect PII in text without modifying it\n *\n * Returns only the detected entities with their types, positions,\n * and confidence scores. The original text is not transformed.\n *\n * @param text - Text to analyze for PII\n * @param config - Optional configuration (entities, score_threshold, policy)\n * @returns Promise with detected entities\n */\n async detect(text: string, config?: DetectConfig): Promise<DetectResponse> {\n return this.request<DetectResponse>('/detect', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Detokenize text by replacing tokens with original values\n *\n * This method performs detokenization CLIENT-SIDE for better performance,\n * security, and to work offline. No API call is made.\n *\n * @param text - Tokenized text\n * @param mapping - Token mapping from tokenize response\n * @returns DetokenizeResponse with original text\n */\n detokenize(text: string, mapping: Record<string, string>): DetokenizeResponse {\n let result = text\n let replacements = 0\n\n // Sort tokens by length (longest first) to avoid partial replacements\n const sortedTokens = Object.keys(mapping).sort((a, b) => b.length - a.length)\n\n for (const token of sortedTokens) {\n const originalValue = mapping[token]\n const regex = new RegExp(token.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'g')\n const matches = result.match(regex)\n\n if (matches) {\n result = result.replace(regex, originalValue)\n replacements += matches.length\n }\n }\n\n return {\n text: result,\n replacements_made: replacements,\n }\n }\n\n /**\n * Redact (permanently remove) sensitive information from text\n *\n * WARNING: Redaction is irreversible - original data cannot be restored!\n *\n * @param text - Text to redact\n * @param config - Optional configuration (masking_char, entities)\n * @returns Promise with redacted text and detected entities\n */\n async redact(text: string, config?: RedactConfig): Promise<RedactResponse> {\n return this.request<RedactResponse>('/redact', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Mask (partially hide) sensitive information from text\n *\n * @param text - Text to mask\n * @param config - Optional configuration (chars_to_show, from_end, masking_char, entities)\n * @returns Promise with masked text and detected entities\n */\n async mask(text: string, config?: MaskConfig): Promise<MaskResponse> {\n return this.request<MaskResponse>('/mask', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Synthesize (replace real data with synthetic fake data)\n *\n * @param text - Text to synthesize\n * @param config - Optional configuration (language, entities)\n * @returns Promise with synthetic text and detected entities\n */\n async synthesize(text: string, config?: SynthesizeConfig): Promise<SynthesizeResponse> {\n return this.request<SynthesizeResponse>('/synthesize', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Hash (replace with deterministic hash values)\n *\n * @param text - Text to hash\n * @param config - Optional configuration (hash_type, hash_prefix, hash_length, entities)\n * @returns Promise with hashed text and detected entities\n */\n async hash(text: string, config?: HashConfig): Promise<HashResponse> {\n return this.request<HashResponse>('/hash', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Encrypt (reversibly protect) sensitive data in text using AES encryption\n *\n * @param text - Text to encrypt\n * @param config - Optional configuration (encryption_key, entities)\n * @returns Promise with encrypted text and detected entities\n */\n async encrypt(text: string, config?: EncryptConfig): Promise<EncryptResponse> {\n return this.request<EncryptResponse>('/encrypt', 'POST', {\n text,\n ...config,\n })\n }\n}\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -32,6 +32,10 @@ var NetworkError = class _NetworkError extends BlindfoldError {
|
|
|
32
32
|
|
|
33
33
|
// src/client.ts
|
|
34
34
|
var DEFAULT_BASE_URL = "https://api.blindfold.dev/api/public/v1";
|
|
35
|
+
var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
|
|
36
|
+
function sleep(ms) {
|
|
37
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
38
|
+
}
|
|
35
39
|
var Blindfold = class {
|
|
36
40
|
/**
|
|
37
41
|
* Create a new Blindfold client
|
|
@@ -41,6 +45,19 @@ var Blindfold = class {
|
|
|
41
45
|
this.apiKey = config.apiKey;
|
|
42
46
|
this.baseUrl = config.baseUrl || DEFAULT_BASE_URL;
|
|
43
47
|
this.userId = config.userId;
|
|
48
|
+
this.maxRetries = config.maxRetries ?? 2;
|
|
49
|
+
this.retryDelay = config.retryDelay ?? 0.5;
|
|
50
|
+
}
|
|
51
|
+
retryWait(attempt, error) {
|
|
52
|
+
if (error && error.statusCode === 429) {
|
|
53
|
+
const body = error.responseBody;
|
|
54
|
+
if (body && typeof body.retry_after === "number") {
|
|
55
|
+
return body.retry_after * 1e3;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const delay = this.retryDelay * 2 ** attempt * 1e3;
|
|
59
|
+
const jitter = delay * 0.1 * Math.random();
|
|
60
|
+
return delay + jitter;
|
|
44
61
|
}
|
|
45
62
|
/**
|
|
46
63
|
* Make an authenticated request to the API
|
|
@@ -54,43 +71,63 @@ var Blindfold = class {
|
|
|
54
71
|
if (this.userId) {
|
|
55
72
|
headers["X-Blindfold-User-Id"] = this.userId;
|
|
56
73
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
if (!response.ok) {
|
|
69
|
-
let errorMessage = `API request failed with status ${response.status}`;
|
|
70
|
-
let responseBody;
|
|
71
|
-
try {
|
|
72
|
-
responseBody = await response.json();
|
|
73
|
-
const errorData = responseBody;
|
|
74
|
-
errorMessage = errorData.detail || errorData.message || errorMessage;
|
|
75
|
-
} catch {
|
|
76
|
-
errorMessage = `${errorMessage}: ${response.statusText}`;
|
|
74
|
+
let lastError = new NetworkError("Request failed");
|
|
75
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
76
|
+
try {
|
|
77
|
+
const response = await fetch(url, {
|
|
78
|
+
method,
|
|
79
|
+
headers,
|
|
80
|
+
body: body ? JSON.stringify(body) : void 0
|
|
81
|
+
});
|
|
82
|
+
if (response.status === 401 || response.status === 403) {
|
|
83
|
+
throw new AuthenticationError("Authentication failed. Please check your API key.");
|
|
77
84
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
if (!response.ok) {
|
|
86
|
+
let errorMessage = `API request failed with status ${response.status}`;
|
|
87
|
+
let responseBody;
|
|
88
|
+
try {
|
|
89
|
+
responseBody = await response.json();
|
|
90
|
+
const errorData = responseBody;
|
|
91
|
+
errorMessage = errorData.detail || errorData.message || errorMessage;
|
|
92
|
+
} catch {
|
|
93
|
+
errorMessage = `${errorMessage}: ${response.statusText}`;
|
|
94
|
+
}
|
|
95
|
+
throw new APIError(errorMessage, response.status, responseBody);
|
|
96
|
+
}
|
|
97
|
+
return await response.json();
|
|
98
|
+
} catch (error) {
|
|
99
|
+
if (error instanceof AuthenticationError) {
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
if (error instanceof APIError) {
|
|
103
|
+
if (RETRYABLE_STATUS_CODES.has(error.statusCode) && attempt < this.maxRetries) {
|
|
104
|
+
await sleep(this.retryWait(attempt, error));
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
if (error instanceof NetworkError) {
|
|
110
|
+
lastError = error;
|
|
111
|
+
if (attempt < this.maxRetries) {
|
|
112
|
+
await sleep(this.retryWait(attempt));
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
if (error instanceof TypeError && error.message.includes("fetch")) {
|
|
118
|
+
lastError = new NetworkError(
|
|
119
|
+
"Network request failed. Please check your connection and the API URL."
|
|
120
|
+
);
|
|
121
|
+
if (attempt < this.maxRetries) {
|
|
122
|
+
await sleep(this.retryWait(attempt));
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
throw lastError;
|
|
126
|
+
}
|
|
127
|
+
throw new NetworkError(error instanceof Error ? error.message : "Unknown error occurred");
|
|
89
128
|
}
|
|
90
|
-
throw new NetworkError(
|
|
91
|
-
error instanceof Error ? error.message : "Unknown error occurred"
|
|
92
|
-
);
|
|
93
129
|
}
|
|
130
|
+
throw lastError;
|
|
94
131
|
}
|
|
95
132
|
/**
|
|
96
133
|
* Tokenize text by replacing sensitive information with tokens
|
|
@@ -104,17 +141,49 @@ var Blindfold = class {
|
|
|
104
141
|
...config
|
|
105
142
|
});
|
|
106
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* Detect PII in text without modifying it
|
|
146
|
+
*
|
|
147
|
+
* Returns only the detected entities with their types, positions,
|
|
148
|
+
* and confidence scores. The original text is not transformed.
|
|
149
|
+
*
|
|
150
|
+
* @param text - Text to analyze for PII
|
|
151
|
+
* @param config - Optional configuration (entities, score_threshold, policy)
|
|
152
|
+
* @returns Promise with detected entities
|
|
153
|
+
*/
|
|
154
|
+
async detect(text, config) {
|
|
155
|
+
return this.request("/detect", "POST", {
|
|
156
|
+
text,
|
|
157
|
+
...config
|
|
158
|
+
});
|
|
159
|
+
}
|
|
107
160
|
/**
|
|
108
161
|
* Detokenize text by replacing tokens with original values
|
|
162
|
+
*
|
|
163
|
+
* This method performs detokenization CLIENT-SIDE for better performance,
|
|
164
|
+
* security, and to work offline. No API call is made.
|
|
165
|
+
*
|
|
109
166
|
* @param text - Tokenized text
|
|
110
167
|
* @param mapping - Token mapping from tokenize response
|
|
111
|
-
* @returns
|
|
168
|
+
* @returns DetokenizeResponse with original text
|
|
112
169
|
*/
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
170
|
+
detokenize(text, mapping) {
|
|
171
|
+
let result = text;
|
|
172
|
+
let replacements = 0;
|
|
173
|
+
const sortedTokens = Object.keys(mapping).sort((a, b) => b.length - a.length);
|
|
174
|
+
for (const token of sortedTokens) {
|
|
175
|
+
const originalValue = mapping[token];
|
|
176
|
+
const regex = new RegExp(token.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g");
|
|
177
|
+
const matches = result.match(regex);
|
|
178
|
+
if (matches) {
|
|
179
|
+
result = result.replace(regex, originalValue);
|
|
180
|
+
replacements += matches.length;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return {
|
|
184
|
+
text: result,
|
|
185
|
+
replacements_made: replacements
|
|
186
|
+
};
|
|
118
187
|
}
|
|
119
188
|
/**
|
|
120
189
|
* Redact (permanently remove) sensitive information from text
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Base error class for Blindfold SDK\n */\nexport class BlindfoldError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'BlindfoldError'\n Object.setPrototypeOf(this, BlindfoldError.prototype)\n }\n}\n\n/**\n * Error thrown when authentication fails\n */\nexport class AuthenticationError extends BlindfoldError {\n constructor(message: string = 'Authentication failed. Please check your API key.') {\n super(message)\n this.name = 'AuthenticationError'\n Object.setPrototypeOf(this, AuthenticationError.prototype)\n }\n}\n\n/**\n * Error thrown when API request fails\n */\nexport class APIError extends BlindfoldError {\n statusCode: number\n responseBody?: any\n\n constructor(message: string, statusCode: number, responseBody?: any) {\n super(message)\n this.name = 'APIError'\n this.statusCode = statusCode\n this.responseBody = responseBody\n Object.setPrototypeOf(this, APIError.prototype)\n }\n}\n\n/**\n * Error thrown when network request fails\n */\nexport class NetworkError extends BlindfoldError {\n constructor(message: string = 'Network request failed. Please check your connection.') {\n super(message)\n this.name = 'NetworkError'\n Object.setPrototypeOf(this, NetworkError.prototype)\n }\n}\n","import type {\n BlindfoldConfig,\n TokenizeConfig,\n TokenizeResponse,\n DetokenizeResponse,\n RedactConfig,\n RedactResponse,\n MaskConfig,\n MaskResponse,\n SynthesizeConfig,\n SynthesizeResponse,\n HashConfig,\n HashResponse,\n EncryptConfig,\n EncryptResponse,\n APIErrorResponse,\n} from './types'\nimport { AuthenticationError, APIError, NetworkError } from './errors'\n\nconst DEFAULT_BASE_URL = 'https://api.blindfold.dev/api/public/v1'\n\n/**\n * Blindfold client for tokenization and detokenization\n */\nexport class Blindfold {\n private apiKey: string\n private baseUrl: string\n private userId?: string\n\n /**\n * Create a new Blindfold client\n * @param config - Configuration options\n */\n constructor(config: BlindfoldConfig) {\n this.apiKey = config.apiKey\n this.baseUrl = config.baseUrl || DEFAULT_BASE_URL\n this.userId = config.userId\n }\n\n /**\n * Make an authenticated request to the API\n */\n private async request<T>(\n endpoint: string,\n method: string,\n body?: any\n ): Promise<T> {\n const url = `${this.baseUrl}${endpoint}`\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-API-Key': this.apiKey,\n }\n\n if (this.userId) {\n headers['X-Blindfold-User-Id'] = this.userId\n }\n\n try {\n const response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n })\n\n // Handle authentication errors\n if (response.status === 401 || response.status === 403) {\n throw new AuthenticationError(\n 'Authentication failed. Please check your API key.'\n )\n }\n\n // Handle other error responses\n if (!response.ok) {\n let errorMessage = `API request failed with status ${response.status}`\n let responseBody: any\n\n try {\n responseBody = await response.json()\n const errorData = responseBody as APIErrorResponse\n errorMessage = errorData.detail || errorData.message || errorMessage\n } catch {\n // If we can't parse the error response, use the status text\n errorMessage = `${errorMessage}: ${response.statusText}`\n }\n\n throw new APIError(errorMessage, response.status, responseBody)\n }\n\n return (await response.json()) as T\n } catch (error) {\n // Re-throw our custom errors\n if (\n error instanceof AuthenticationError ||\n error instanceof APIError\n ) {\n throw error\n }\n\n // Handle network errors\n if (error instanceof TypeError && error.message.includes('fetch')) {\n throw new NetworkError(\n 'Network request failed. Please check your connection and the API URL.'\n )\n }\n\n // Handle other errors\n throw new NetworkError(\n error instanceof Error ? error.message : 'Unknown error occurred'\n )\n }\n }\n\n /**\n * Tokenize text by replacing sensitive information with tokens\n * @param text - Text to tokenize\n * @param config - Optional configuration\n * @returns Promise with tokenized text and mapping\n */\n async tokenize(\n text: string,\n config?: TokenizeConfig\n ): Promise<TokenizeResponse> {\n return this.request<TokenizeResponse>('/tokenize', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Detokenize text by replacing tokens with original values\n * @param text - Tokenized text\n * @param mapping - Token mapping from tokenize response\n * @returns Promise with original text\n */\n async detokenize(\n text: string,\n mapping: Record<string, string>\n ): Promise<DetokenizeResponse> {\n return this.request<DetokenizeResponse>('/detokenize', 'POST', {\n text,\n mapping,\n })\n }\n\n /**\n * Redact (permanently remove) sensitive information from text\n *\n * WARNING: Redaction is irreversible - original data cannot be restored!\n *\n * @param text - Text to redact\n * @param config - Optional configuration (masking_char, entities)\n * @returns Promise with redacted text and detected entities\n */\n async redact(\n text: string,\n config?: RedactConfig\n ): Promise<RedactResponse> {\n return this.request<RedactResponse>('/redact', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Mask (partially hide) sensitive information from text\n *\n * @param text - Text to mask\n * @param config - Optional configuration (chars_to_show, from_end, masking_char, entities)\n * @returns Promise with masked text and detected entities\n */\n async mask(\n text: string,\n config?: MaskConfig\n ): Promise<MaskResponse> {\n return this.request<MaskResponse>('/mask', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Synthesize (replace real data with synthetic fake data)\n *\n * @param text - Text to synthesize\n * @param config - Optional configuration (language, entities)\n * @returns Promise with synthetic text and detected entities\n */\n async synthesize(\n text: string,\n config?: SynthesizeConfig\n ): Promise<SynthesizeResponse> {\n return this.request<SynthesizeResponse>('/synthesize', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Hash (replace with deterministic hash values)\n *\n * @param text - Text to hash\n * @param config - Optional configuration (hash_type, hash_prefix, hash_length, entities)\n * @returns Promise with hashed text and detected entities\n */\n async hash(\n text: string,\n config?: HashConfig\n ): Promise<HashResponse> {\n return this.request<HashResponse>('/hash', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Encrypt (reversibly protect) sensitive data in text using AES encryption\n *\n * @param text - Text to encrypt\n * @param config - Optional configuration (encryption_key, entities)\n * @returns Promise with encrypted text and detected entities\n */\n async encrypt(\n text: string,\n config?: EncryptConfig\n ): Promise<EncryptResponse> {\n return this.request<EncryptResponse>('/encrypt', 'POST', {\n text,\n ...config,\n })\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Base error class for Blindfold SDK\n */\nexport class BlindfoldError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'BlindfoldError'\n Object.setPrototypeOf(this, BlindfoldError.prototype)\n }\n}\n\n/**\n * Error thrown when authentication fails\n */\nexport class AuthenticationError extends BlindfoldError {\n constructor(message: string = 'Authentication failed. Please check your API key.') {\n super(message)\n this.name = 'AuthenticationError'\n Object.setPrototypeOf(this, AuthenticationError.prototype)\n }\n}\n\n/**\n * Error thrown when API request fails\n */\nexport class APIError extends BlindfoldError {\n statusCode: number\n responseBody?: unknown\n\n constructor(message: string, statusCode: number, responseBody?: unknown) {\n super(message)\n this.name = 'APIError'\n this.statusCode = statusCode\n this.responseBody = responseBody\n Object.setPrototypeOf(this, APIError.prototype)\n }\n}\n\n/**\n * Error thrown when network request fails\n */\nexport class NetworkError extends BlindfoldError {\n constructor(message: string = 'Network request failed. Please check your connection.') {\n super(message)\n this.name = 'NetworkError'\n Object.setPrototypeOf(this, NetworkError.prototype)\n }\n}\n","import type {\n BlindfoldConfig,\n DetectConfig,\n DetectResponse,\n TokenizeConfig,\n TokenizeResponse,\n DetokenizeResponse,\n RedactConfig,\n RedactResponse,\n MaskConfig,\n MaskResponse,\n SynthesizeConfig,\n SynthesizeResponse,\n HashConfig,\n HashResponse,\n EncryptConfig,\n EncryptResponse,\n APIErrorResponse,\n} from './types'\nimport { AuthenticationError, APIError, NetworkError } from './errors'\n\nconst DEFAULT_BASE_URL = 'https://api.blindfold.dev/api/public/v1'\nconst RETRYABLE_STATUS_CODES = new Set([429, 500, 502, 503, 504])\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\n/**\n * Blindfold client for tokenization and detokenization\n */\nexport class Blindfold {\n private apiKey: string\n private baseUrl: string\n private userId?: string\n private maxRetries: number\n private retryDelay: number\n\n /**\n * Create a new Blindfold client\n * @param config - Configuration options\n */\n constructor(config: BlindfoldConfig) {\n this.apiKey = config.apiKey\n this.baseUrl = config.baseUrl || DEFAULT_BASE_URL\n this.userId = config.userId\n this.maxRetries = config.maxRetries ?? 2\n this.retryDelay = config.retryDelay ?? 0.5\n }\n\n private retryWait(attempt: number, error?: APIError): number {\n if (error && error.statusCode === 429) {\n const body = error.responseBody as Record<string, unknown> | undefined\n if (body && typeof body.retry_after === 'number') {\n return body.retry_after * 1000\n }\n }\n const delay = this.retryDelay * (2 ** attempt) * 1000\n const jitter = delay * 0.1 * Math.random()\n return delay + jitter\n }\n\n /**\n * Make an authenticated request to the API\n */\n private async request<T>(\n endpoint: string,\n method: string,\n body?: Record<string, unknown>\n ): Promise<T> {\n const url = `${this.baseUrl}${endpoint}`\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-API-Key': this.apiKey,\n }\n\n if (this.userId) {\n headers['X-Blindfold-User-Id'] = this.userId\n }\n\n let lastError: Error = new NetworkError('Request failed')\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n try {\n const response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n })\n\n // Handle authentication errors\n if (response.status === 401 || response.status === 403) {\n throw new AuthenticationError('Authentication failed. Please check your API key.')\n }\n\n // Handle other error responses\n if (!response.ok) {\n let errorMessage = `API request failed with status ${response.status}`\n let responseBody: unknown\n\n try {\n responseBody = await response.json()\n const errorData = responseBody as APIErrorResponse\n errorMessage = errorData.detail || errorData.message || errorMessage\n } catch {\n // If we can't parse the error response, use the status text\n errorMessage = `${errorMessage}: ${response.statusText}`\n }\n\n throw new APIError(errorMessage, response.status, responseBody)\n }\n\n return (await response.json()) as T\n } catch (error) {\n // Never retry auth errors\n if (error instanceof AuthenticationError) {\n throw error\n }\n\n // Retry retryable API errors\n if (error instanceof APIError) {\n if (RETRYABLE_STATUS_CODES.has(error.statusCode) && attempt < this.maxRetries) {\n await sleep(this.retryWait(attempt, error))\n continue\n }\n throw error\n }\n\n // Retry network errors\n if (error instanceof NetworkError) {\n lastError = error\n if (attempt < this.maxRetries) {\n await sleep(this.retryWait(attempt))\n continue\n }\n throw error\n }\n\n // Handle raw fetch errors (network failures)\n if (error instanceof TypeError && error.message.includes('fetch')) {\n lastError = new NetworkError(\n 'Network request failed. Please check your connection and the API URL.'\n )\n if (attempt < this.maxRetries) {\n await sleep(this.retryWait(attempt))\n continue\n }\n throw lastError\n }\n\n // Non-retryable unknown errors\n throw new NetworkError(error instanceof Error ? error.message : 'Unknown error occurred')\n }\n }\n\n throw lastError\n }\n\n /**\n * Tokenize text by replacing sensitive information with tokens\n * @param text - Text to tokenize\n * @param config - Optional configuration\n * @returns Promise with tokenized text and mapping\n */\n async tokenize(text: string, config?: TokenizeConfig): Promise<TokenizeResponse> {\n return this.request<TokenizeResponse>('/tokenize', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Detect PII in text without modifying it\n *\n * Returns only the detected entities with their types, positions,\n * and confidence scores. The original text is not transformed.\n *\n * @param text - Text to analyze for PII\n * @param config - Optional configuration (entities, score_threshold, policy)\n * @returns Promise with detected entities\n */\n async detect(text: string, config?: DetectConfig): Promise<DetectResponse> {\n return this.request<DetectResponse>('/detect', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Detokenize text by replacing tokens with original values\n *\n * This method performs detokenization CLIENT-SIDE for better performance,\n * security, and to work offline. No API call is made.\n *\n * @param text - Tokenized text\n * @param mapping - Token mapping from tokenize response\n * @returns DetokenizeResponse with original text\n */\n detokenize(text: string, mapping: Record<string, string>): DetokenizeResponse {\n let result = text\n let replacements = 0\n\n // Sort tokens by length (longest first) to avoid partial replacements\n const sortedTokens = Object.keys(mapping).sort((a, b) => b.length - a.length)\n\n for (const token of sortedTokens) {\n const originalValue = mapping[token]\n const regex = new RegExp(token.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'g')\n const matches = result.match(regex)\n\n if (matches) {\n result = result.replace(regex, originalValue)\n replacements += matches.length\n }\n }\n\n return {\n text: result,\n replacements_made: replacements,\n }\n }\n\n /**\n * Redact (permanently remove) sensitive information from text\n *\n * WARNING: Redaction is irreversible - original data cannot be restored!\n *\n * @param text - Text to redact\n * @param config - Optional configuration (masking_char, entities)\n * @returns Promise with redacted text and detected entities\n */\n async redact(text: string, config?: RedactConfig): Promise<RedactResponse> {\n return this.request<RedactResponse>('/redact', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Mask (partially hide) sensitive information from text\n *\n * @param text - Text to mask\n * @param config - Optional configuration (chars_to_show, from_end, masking_char, entities)\n * @returns Promise with masked text and detected entities\n */\n async mask(text: string, config?: MaskConfig): Promise<MaskResponse> {\n return this.request<MaskResponse>('/mask', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Synthesize (replace real data with synthetic fake data)\n *\n * @param text - Text to synthesize\n * @param config - Optional configuration (language, entities)\n * @returns Promise with synthetic text and detected entities\n */\n async synthesize(text: string, config?: SynthesizeConfig): Promise<SynthesizeResponse> {\n return this.request<SynthesizeResponse>('/synthesize', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Hash (replace with deterministic hash values)\n *\n * @param text - Text to hash\n * @param config - Optional configuration (hash_type, hash_prefix, hash_length, entities)\n * @returns Promise with hashed text and detected entities\n */\n async hash(text: string, config?: HashConfig): Promise<HashResponse> {\n return this.request<HashResponse>('/hash', 'POST', {\n text,\n ...config,\n })\n }\n\n /**\n * Encrypt (reversibly protect) sensitive data in text using AES encryption\n *\n * @param text - Text to encrypt\n * @param config - Optional configuration (encryption_key, entities)\n * @returns Promise with encrypted text and detected entities\n */\n async encrypt(text: string, config?: EncryptConfig): Promise<EncryptResponse> {\n return this.request<EncryptResponse>('/encrypt', 'POST', {\n text,\n ...config,\n })\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blindfold/sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "JavaScript/TypeScript SDK for Blindfold Gateway",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -13,24 +13,61 @@
|
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
|
-
"dist"
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
17
18
|
],
|
|
18
19
|
"scripts": {
|
|
19
20
|
"build": "tsup",
|
|
20
21
|
"dev": "tsup --watch",
|
|
21
|
-
"type-check": "tsc --noEmit"
|
|
22
|
+
"type-check": "tsc --noEmit",
|
|
23
|
+
"test": "jest",
|
|
24
|
+
"test:watch": "jest --watch",
|
|
25
|
+
"test:coverage": "jest --coverage",
|
|
26
|
+
"lint": "eslint src tests --ext .ts",
|
|
27
|
+
"lint:fix": "eslint src tests --ext .ts --fix",
|
|
28
|
+
"format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"",
|
|
29
|
+
"format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"",
|
|
30
|
+
"clean": "rm -rf dist",
|
|
31
|
+
"prepublishOnly": "npm run clean && npm run build && npm run test",
|
|
32
|
+
"validate": "npm run type-check && npm run lint && npm run test"
|
|
22
33
|
},
|
|
23
34
|
"keywords": [
|
|
24
35
|
"blindfold",
|
|
25
36
|
"tokenization",
|
|
26
37
|
"pii",
|
|
27
|
-
"security"
|
|
38
|
+
"security",
|
|
39
|
+
"privacy",
|
|
40
|
+
"gdpr",
|
|
41
|
+
"hipaa",
|
|
42
|
+
"llm",
|
|
43
|
+
"ai"
|
|
28
44
|
],
|
|
29
|
-
"author": "",
|
|
45
|
+
"author": "Blindfold Team",
|
|
30
46
|
"license": "MIT",
|
|
47
|
+
"repository": {
|
|
48
|
+
"type": "git",
|
|
49
|
+
"url": "git+https://github.com/blindfold-dev/blindfold-github.git",
|
|
50
|
+
"directory": "packages/js-sdk"
|
|
51
|
+
},
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/blindfold-dev/blindfold-github/issues"
|
|
54
|
+
},
|
|
55
|
+
"homepage": "https://blindfold.dev",
|
|
31
56
|
"devDependencies": {
|
|
57
|
+
"@types/jest": "^29.5.11",
|
|
32
58
|
"@types/node": "^20.10.0",
|
|
59
|
+
"@typescript-eslint/eslint-plugin": "^6.18.0",
|
|
60
|
+
"@typescript-eslint/parser": "^6.18.0",
|
|
61
|
+
"eslint": "^8.56.0",
|
|
62
|
+
"eslint-config-prettier": "^9.1.0",
|
|
63
|
+
"eslint-plugin-prettier": "^5.1.2",
|
|
64
|
+
"jest": "^29.7.0",
|
|
65
|
+
"prettier": "^3.1.1",
|
|
66
|
+
"ts-jest": "^29.1.1",
|
|
33
67
|
"tsup": "^8.0.1",
|
|
34
68
|
"typescript": "^5.3.3"
|
|
69
|
+
},
|
|
70
|
+
"engines": {
|
|
71
|
+
"node": ">=16.0.0"
|
|
35
72
|
}
|
|
36
73
|
}
|