@privacyscrubber/sdk 2.3.9 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +85 -27
  2. package/benchmark.js +355 -0
  3. package/browser.js +276 -39
  4. package/cli.js +1 -1
  5. package/examples/python-bridge/MANIFEST.in +5 -0
  6. package/examples/python-bridge/README.md +265 -0
  7. package/examples/python-bridge/bridge_daemon.cjs +241 -0
  8. package/examples/python-bridge/fastapi_example.py +206 -0
  9. package/examples/python-bridge/langchain_adapter.py +20 -0
  10. package/examples/python-bridge/langchain_example.py +126 -0
  11. package/examples/python-bridge/llamaindex_example.py +103 -0
  12. package/examples/python-bridge/privacyscrubber/__init__.py +42 -0
  13. package/examples/python-bridge/privacyscrubber/bridge_daemon.cjs +241 -0
  14. package/examples/python-bridge/privacyscrubber/cli.py +138 -0
  15. package/examples/python-bridge/privacyscrubber/client.py +548 -0
  16. package/examples/python-bridge/privacyscrubber/exceptions.py +26 -0
  17. package/examples/python-bridge/privacyscrubber/langchain.py +161 -0
  18. package/examples/python-bridge/privacyscrubber/types.py +52 -0
  19. package/examples/python-bridge/privacyscrubber.py +36 -0
  20. package/examples/python-bridge/pyproject.toml +62 -0
  21. package/examples/python-bridge/setup.py +66 -0
  22. package/examples/python-bridge/test_python_bridge.py +320 -0
  23. package/examples/vercel-ai-stream.js +195 -0
  24. package/fastmcp.cjs +289 -8
  25. package/fastmcp.d.ts +18 -0
  26. package/fastmcp.js +4 -0
  27. package/index.cjs +99 -42
  28. package/index.js +103 -46
  29. package/package.json +15 -3
  30. package/ps-license-manager.js +1 -1
  31. package/ps-pii-engine.cjs +1 -1
  32. package/scrubber-core.cjs +1 -1
  33. package/vercel-ai.cjs +400 -0
  34. package/vercel-ai.d.ts +156 -0
  35. package/vercel-ai.js +36 -0
  36. package/vision.cjs +13 -5
  37. package/vision.js +13 -5
package/fastmcp.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @privacyscrubber/fastmcp-guard
3
3
  * Zero-Trust Data Sanitization (ZTDS) In-Memory Middleware for FastMCP
4
- * Conforms to IETF Standards Track: draft-sibiryakov-ztds-protocol-02
4
+ * Conforms to IETF Standards Track: draft-sibiryakov-ztds-protocol-01
5
5
  *
6
6
  * Core Protocol Invariants:
7
7
  * 1. Zero External Egress Prior to Sanitization
@@ -14,7 +14,7 @@
14
14
  const crypto = require("node:crypto");
15
15
 
16
16
  const ZTDS_PATTERNS = {
17
- API_SECRET: /\b(?:sk-(?:proj-)?[A-Za-z0-9_-]{20,}|(?:ghp|gho|ghu|ghs|ghr|github_pat_)[A-Za-z0-9_]{20,}|eyJ[a-zA-Z0-9_-]{20,}\.[a-zA-Z0-9_-]{20,}\.[a-zA-Z0-9_-]{20,})\b/g,
17
+ API_SECRET: /\b(?:sk-ant-(?:api\d{2}|admin\d{2}|sid\d{2})-[a-zA-Z0-9_-]{16,128}|sk-(?:proj-)?[A-Za-z0-9_-]{20,}|AIza[0-9A-Za-z_-]{35}|(?:ghp|gho|ghu|ghs|ghr|github_pat_|glpat-|xox[baprs]-)[A-Za-z0-9_-]{16,}|(?:[rs]k)_(?:test|live)_[a-zA-Z0-9]{10,}|eyJ[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,})\b/g,
18
18
  AWS_KEY: /\b(?:AKIA|ASIA|AGPA|AIDA|AROA|AIPA)[A-Z0-9]{16}\b/g,
19
19
  CREDIT_CARD: /\b(?:\d{4}[-\s]?){3}\d{4}\b/g,
20
20
  EMAIL: /[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9-]{1,63}(?:\.[A-Za-z0-9-]{1,63})*\.[A-Za-z]{2,24}/g,
@@ -24,7 +24,213 @@ const ZTDS_PATTERNS = {
24
24
  SSN: /\b\d{3}-\d{2}-\d{4}\b/g,
25
25
  };
26
26
 
27
- const TOKEN_PATTERN = /\[([A-Z_]+)_TOKEN_([a-zA-Z0-9_-]+)\]/g;
27
+ const TOKEN_PATTERN = /(?:%5[Bb]|\\u005[Bb]|&(?:amp;)?#0*91;|\[|<|\{\{?|__|【|[)[*`_~\s]*([A-Z_]+)_TOKEN_([a-zA-Z0-9_-]+)[*`_~.,;:!?\s]*(?:%5[Dd]|\\u005[Dd]|&(?:amp;)?#0*93;|\]|>|\}\}?|__|】|])/gi;
28
+
29
+ function escapeRegex(s) {
30
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
31
+ }
32
+
33
+ function buildStreamReplacer(tokenMap = {}, options = {}) {
34
+ if (!tokenMap || typeof tokenMap !== 'object' || Object.keys(tokenMap).length === 0) {
35
+ return (text) => text || '';
36
+ }
37
+
38
+ const lookup = new Map();
39
+ const patterns = [];
40
+ const sortedKeys = Object.keys(tokenMap).sort((a, b) => b.length - a.length);
41
+
42
+ for (const k of sortedKeys) {
43
+ const val = tokenMap[k];
44
+ const inner = k.replace(/^(?:\[|<|\{\{?|__|【|[|〔|「|『)|(?:\]|>|\}\}?|__|】|]|〕|」|』)$/g, '');
45
+ const match = inner.match(/^([A-Za-z_0-9]+?)[-_ ]([a-zA-Z0-9]+)$/);
46
+
47
+ if (match) {
48
+ const label = escapeRegex(match[1]);
49
+ const idx = escapeRegex(match[2]);
50
+ const idxPat = /^\d+$/.test(match[2]) ? '0*' + idx : idx;
51
+ const corePat = '[*`_~\\s]*' + label + '[*`_~]*[-_\\s]*' + idxPat + '[*`_~.,;:!?\\s]*';
52
+ const patternStr = '(?:\\[' + corePat + '\\]|<' + corePat + '>|\\{\\{' + corePat + '\\}\\}|\\{' + corePat + '\\}|__' + corePat + '__|[【[〔「『]' + corePat + '[】]〕」』]|%5B' + corePat + '%5D|&#(?:91|091|x5[bB]);' + corePat + '&#(?:93|093|x5[dD]);|&(?:lbrack|lsqb);' + corePat + '&(?:rbrack|rsqb);|\\\\u005[bB]' + corePat + '\\\\u005[dD]|\\b' + label + '[-_\\s]+' + idxPat + '\\b)';
53
+ patterns.push(patternStr);
54
+ const normSuffix = /^\d+$/.test(match[2]) ? String(parseInt(match[2], 10)) : match[2].toUpperCase();
55
+ const normKey = (match[1] + '_' + normSuffix).toUpperCase();
56
+ lookup.set(normKey, val);
57
+ lookup.set(k, val);
58
+ lookup.set(k.toUpperCase(), val);
59
+ } else {
60
+ const safe = escapeRegex(k);
61
+ patterns.push(safe);
62
+ lookup.set(k, val);
63
+ lookup.set(k.toUpperCase(), val);
64
+ }
65
+ }
66
+
67
+ const unifiedRegex = new RegExp('(?:' + patterns.join('|') + ')(\'s|’s|s)?', 'gi');
68
+
69
+ return function replaceTokens(text) {
70
+ if (!text) return '';
71
+ unifiedRegex.lastIndex = 0;
72
+ return text.replace(unifiedRegex, (match, suffix) => {
73
+ const isPossessive = suffix && /('s|’s)$/i.test(suffix);
74
+ const coreMatch = suffix ? match.slice(0, match.length - suffix.length) : match;
75
+ let restored = null;
76
+
77
+ if (lookup.has(coreMatch)) {
78
+ restored = lookup.get(coreMatch);
79
+ } else if (lookup.has(coreMatch.toUpperCase())) {
80
+ restored = lookup.get(coreMatch.toUpperCase());
81
+ } else {
82
+ const inner = coreMatch
83
+ .replace(/^(?:%5B|&#(?:91|091|x5[bB]);|&(?:lbrack|lsqb);|\\u005[bB]|\[|<|\{\{?|__|【|[|〔|「|『)/i, '')
84
+ .replace(/(?:%5D|&#(?:93|093|x5[dD]);|&(?:rbrack|rsqb);|\\u005[dD]|\]|>|\}\}?|__|】|]|〕|」|』)$/i, '')
85
+ .replace(/[*`_~.,;:!?\s]+/g, ' ')
86
+ .trim();
87
+ const m = inner.match(/^([A-Za-z_0-9]+?)[-_ ]([a-zA-Z0-9]+)$/);
88
+ if (m) {
89
+ const normSuffix = /^\d+$/.test(m[2]) ? String(parseInt(m[2], 10)) : m[2].toUpperCase();
90
+ const normKey = (m[1] + '_' + normSuffix).toUpperCase();
91
+ if (lookup.has(normKey)) {
92
+ restored = lookup.get(normKey);
93
+ }
94
+ }
95
+ }
96
+
97
+ if (restored !== null) {
98
+ return restored + (isPossessive ? "'s" : '');
99
+ }
100
+
101
+ if (lookup.has(match)) {
102
+ return lookup.get(match);
103
+ }
104
+
105
+ return match;
106
+ });
107
+ };
108
+ }
109
+
110
+ class StreamingDetokenizer {
111
+ constructor(tokenMap = {}, options = {}) {
112
+ this.tokenMap = tokenMap && typeof tokenMap === 'object' ? tokenMap : {};
113
+ this.options = options || {};
114
+ this.replacer = buildStreamReplacer(this.tokenMap, this.options);
115
+ this.pendingBuffer = '';
116
+ this.hasTokens = Object.keys(this.tokenMap).length > 0;
117
+ this._lastTokenCount = Object.keys(this.tokenMap).length;
118
+ this.decoder = new TextDecoder('utf-8', { fatal: false });
119
+ }
120
+
121
+ get buffer() {
122
+ return this.pendingBuffer;
123
+ }
124
+
125
+ set buffer(val) {
126
+ this.pendingBuffer = typeof val === 'string' ? val : '';
127
+ }
128
+
129
+ updateTokenMap(newMap) {
130
+ if (newMap && typeof newMap === 'object') {
131
+ this.tokenMap = newMap;
132
+ this.replacer = buildStreamReplacer(this.tokenMap, this.options);
133
+ this.hasTokens = Object.keys(this.tokenMap).length > 0;
134
+ this._lastTokenCount = Object.keys(this.tokenMap).length;
135
+ }
136
+ }
137
+
138
+ reset() {
139
+ this.pendingBuffer = '';
140
+ }
141
+
142
+ feed(chunk) {
143
+ if (chunk === undefined || chunk === null) return '';
144
+ let text = '';
145
+ if (typeof chunk === 'string') {
146
+ text = chunk;
147
+ } else if (chunk instanceof Uint8Array || (typeof Buffer !== 'undefined' && Buffer.isBuffer(chunk))) {
148
+ text = this.decoder.decode(chunk, { stream: true });
149
+ } else {
150
+ text = String(chunk);
151
+ }
152
+
153
+ if (!text) return '';
154
+
155
+ const currentTokenCount = Object.keys(this.tokenMap).length;
156
+ if (currentTokenCount !== this._lastTokenCount) {
157
+ this.replacer = buildStreamReplacer(this.tokenMap, this.options);
158
+ this.hasTokens = currentTokenCount > 0;
159
+ this._lastTokenCount = currentTokenCount;
160
+ }
161
+
162
+ if (!this.hasTokens) return text;
163
+
164
+ this.pendingBuffer += text;
165
+
166
+ const tailLen = 160;
167
+ const tail = this.pendingBuffer.length > tailLen ? this.pendingBuffer.slice(-tailLen) : this.pendingBuffer;
168
+ const offset = this.pendingBuffer.length > tailLen ? this.pendingBuffer.length - tailLen : 0;
169
+ const m = tail.match(/(?:(?:\[|【|[|〔|「|『|<|\{\{?|__?|%5[Bb]|\\u005[Bb]|&(?:amp;)?(?:#0*91;|#[xX]0*5[Bb];|lbrack;))[A-Za-z0-9_\-А-Яа-яЁё *`~.\\]{0,128}(?:%5?|&(?:a(?:m(?:p(?:;)?)?)?)?(?:#(?:0*9?3?|[xX]0*5?[Dd]?)?|r(?:b(?:r(?:a(?:c(?:k)?)?)?)?)?)?)?|%[0-9A-Fa-f]?|\\(?:u(?:0(?:0(?:5)?)?)?)?|&(?:a(?:m(?:p(?:;)?)?)?)?(?:#(?:0*9?1?|[xX]0*5?)?|l(?:b(?:r(?:a(?:c(?:k)?)?)?)?)?)?)$/);
170
+
171
+ if (m) {
172
+ const candidate = m[0];
173
+ const isClosedUnderscoreOrUnicode = (candidate.length >= 4 && candidate.startsWith('__') && candidate.endsWith('__')) || /\\u005[Dd]/.test(candidate);
174
+ if (isClosedUnderscoreOrUnicode && this.replacer(candidate) !== candidate) {
175
+ const toEmit = this.pendingBuffer;
176
+ this.pendingBuffer = '';
177
+ return this.replacer(toEmit);
178
+ }
179
+ const splitIdx = offset + m.index;
180
+ const safeToEmit = this.pendingBuffer.slice(0, splitIdx);
181
+ this.pendingBuffer = this.pendingBuffer.slice(splitIdx);
182
+ return safeToEmit ? this.replacer(safeToEmit) : '';
183
+ }
184
+
185
+ const toEmit = this.pendingBuffer;
186
+ this.pendingBuffer = '';
187
+ return this.replacer(toEmit);
188
+ }
189
+
190
+ process(chunk) {
191
+ return this.feed(chunk);
192
+ }
193
+
194
+ flush() {
195
+ let text = '';
196
+ try {
197
+ text = this.decoder.decode(new Uint8Array(), { stream: false });
198
+ } catch (_) {}
199
+
200
+ if (text) {
201
+ this.pendingBuffer += text;
202
+ }
203
+
204
+ if (!this.pendingBuffer) return '';
205
+ const remaining = this.pendingBuffer;
206
+ this.pendingBuffer = '';
207
+ return this.replacer(remaining);
208
+ }
209
+
210
+ async* wrapStream(asyncIterable) {
211
+ for await (const chunk of asyncIterable) {
212
+ if (chunk === null || chunk === undefined) continue;
213
+ let text = '';
214
+ if (typeof chunk === 'string') {
215
+ text = chunk;
216
+ } else if (typeof chunk?.text === 'string') {
217
+ text = chunk.text;
218
+ } else if (typeof chunk?.content === 'string') {
219
+ text = chunk.content;
220
+ } else if (chunk instanceof Uint8Array || (typeof Buffer !== 'undefined' && Buffer.isBuffer(chunk))) {
221
+ text = chunk;
222
+ } else {
223
+ text = String(chunk);
224
+ }
225
+
226
+ const emitted = this.feed(text);
227
+ if (emitted) yield emitted;
228
+ }
229
+
230
+ const finalChunk = this.flush();
231
+ if (finalChunk) yield finalChunk;
232
+ }
233
+ }
28
234
 
29
235
  class ZTDSFastMCPGuard {
30
236
  constructor(options = {}) {
@@ -36,6 +242,7 @@ class ZTDSFastMCPGuard {
36
242
  this.maxSessionTokens = options.maxSessionTokens || 5000;
37
243
  this._sessionMaps = new Map();
38
244
  this._entityMaps = new Map();
245
+ this._streamDetokenizers = new Map();
39
246
  }
40
247
 
41
248
  _generateToken(entityType, tokenMap) {
@@ -69,7 +276,9 @@ class ZTDSFastMCPGuard {
69
276
 
70
277
  const tokenMap = this._sessionMaps.get(sessionId);
71
278
  const entityMap = this._entityMaps.get(sessionId);
72
- let sanitized = text;
279
+ let sanitized = text
280
+ .replace(/[\u200B-\u200F\u202A-\u202E\u2060-\u206F\uFEFF\u00AD]/g, "")
281
+ .replace(/[\uFF01-\uFF5E]/g, (ch) => String.fromCharCode(ch.charCodeAt(0) - 0xFEE0));
73
282
 
74
283
  for (const entityType of this.enabledEntities) {
75
284
  const pattern = ZTDS_PATTERNS[entityType];
@@ -118,8 +327,9 @@ class ZTDSFastMCPGuard {
118
327
  return text;
119
328
  }
120
329
 
121
- return text.replace(TOKEN_PATTERN, (match) => {
122
- return tokenMap.get(match) || match;
330
+ return text.replace(TOKEN_PATTERN, (match, entityType, tokenId) => {
331
+ const canonical = `[${entityType.toUpperCase()}_TOKEN_${tokenId}]`;
332
+ return tokenMap.get(canonical) || tokenMap.get(match) || match;
123
333
  });
124
334
  }
125
335
 
@@ -157,6 +367,65 @@ class ZTDSFastMCPGuard {
157
367
  return val;
158
368
  }
159
369
 
370
+ getStreamDetokenizer(sessionId) {
371
+ if (!this._streamDetokenizers.has(sessionId)) {
372
+ const mapProxy = this._sessionMaps.get(sessionId) || new Map();
373
+ const objMap = {};
374
+ for (const [k, v] of mapProxy.entries()) {
375
+ objMap[k] = v;
376
+ }
377
+ this._streamDetokenizers.set(sessionId, new StreamingDetokenizer(objMap));
378
+ } else {
379
+ const mapProxy = this._sessionMaps.get(sessionId);
380
+ if (mapProxy) {
381
+ const objMap = {};
382
+ for (const [k, v] of mapProxy.entries()) {
383
+ objMap[k] = v;
384
+ }
385
+ this._streamDetokenizers.get(sessionId).updateTokenMap(objMap);
386
+ }
387
+ }
388
+ return this._streamDetokenizers.get(sessionId);
389
+ }
390
+
391
+ feedStream(chunk, sessionId) {
392
+ return this.getStreamDetokenizer(sessionId).feed(chunk);
393
+ }
394
+
395
+ flushStream(sessionId) {
396
+ const detok = this._streamDetokenizers.get(sessionId);
397
+ return detok ? detok.flush() : "";
398
+ }
399
+
400
+ async *restoreStream(asyncIterable, sessionId) {
401
+ const detok = this.getStreamDetokenizer(sessionId);
402
+ try {
403
+ for await (const chunk of asyncIterable) {
404
+ if (chunk === null || chunk === undefined) continue;
405
+ let text = "";
406
+ if (typeof chunk === "string") {
407
+ text = chunk;
408
+ } else if (typeof chunk?.text === "string") {
409
+ text = chunk.text;
410
+ } else if (typeof chunk?.content === "string") {
411
+ text = chunk.content;
412
+ } else if (chunk instanceof Uint8Array || (typeof Buffer !== "undefined" && Buffer.isBuffer(chunk))) {
413
+ text = chunk;
414
+ } else {
415
+ text = String(chunk);
416
+ }
417
+ const emitted = detok.feed(text);
418
+ if (emitted) yield emitted;
419
+ }
420
+ const finalChunk = detok.flush();
421
+ if (finalChunk) yield finalChunk;
422
+ } finally {
423
+ if (this.autoZeroize) {
424
+ this.zeroizeSession(sessionId);
425
+ }
426
+ }
427
+ }
428
+
160
429
  wrapTool(toolName, handler) {
161
430
  return async (args, context = {}) => {
162
431
  const sessionId =
@@ -169,6 +438,7 @@ class ZTDSFastMCPGuard {
169
438
  unmask: (val) => this.restoreObject(val, sessionId),
170
439
  };
171
440
 
441
+ let isStreaming = false;
172
442
  try {
173
443
  let processedArgs = args;
174
444
  if (this.sanitizeInputs && args !== undefined && args !== null) {
@@ -177,6 +447,11 @@ class ZTDSFastMCPGuard {
177
447
 
178
448
  const rawResult = await handler(processedArgs, enrichedContext);
179
449
 
450
+ if (rawResult && typeof rawResult[Symbol.asyncIterator] === "function") {
451
+ isStreaming = true;
452
+ return this.restoreStream(rawResult, sessionId);
453
+ }
454
+
180
455
  let finalResult = rawResult;
181
456
  if (this.sanitizeOutputs && rawResult !== undefined && rawResult !== null) {
182
457
  if (typeof rawResult === "string") {
@@ -211,7 +486,7 @@ class ZTDSFastMCPGuard {
211
486
 
212
487
  const ztdsMeta = {
213
488
  sessionId,
214
- standard: "IETF draft-sibiryakov-ztds-protocol-02",
489
+ standard: "IETF draft-sibiryakov-ztds-protocol-01",
215
490
  zeroEgress: true,
216
491
  };
217
492
 
@@ -234,7 +509,7 @@ class ZTDSFastMCPGuard {
234
509
  _ztds: ztdsMeta,
235
510
  };
236
511
  } finally {
237
- if (this.autoZeroize) {
512
+ if (!isStreaming && this.autoZeroize) {
238
513
  this.zeroizeSession(sessionId);
239
514
  }
240
515
  }
@@ -250,6 +525,10 @@ class ZTDSFastMCPGuard {
250
525
  this._entityMaps.get(sessionId).clear();
251
526
  this._entityMaps.delete(sessionId);
252
527
  }
528
+ if (this._streamDetokenizers.has(sessionId)) {
529
+ this._streamDetokenizers.get(sessionId).reset();
530
+ this._streamDetokenizers.delete(sessionId);
531
+ }
253
532
  }
254
533
  }
255
534
 
@@ -285,6 +564,8 @@ module.exports = {
285
564
  ZTDSFastMCPGuard,
286
565
  ZTDS_PATTERNS,
287
566
  TOKEN_PATTERN,
567
+ StreamingDetokenizer,
568
+ createStreamTokenRestorer: (tokenMap, options) => new StreamingDetokenizer(tokenMap, options),
288
569
  createZTDSGuard,
289
570
  ztdsGuardTool,
290
571
  wrapExecute,
package/fastmcp.d.ts CHANGED
@@ -26,6 +26,19 @@ export interface ZTDSContext {
26
26
  export declare const ZTDS_PATTERNS: Record<string, RegExp>;
27
27
  export declare const TOKEN_PATTERN: RegExp;
28
28
 
29
+ export declare class StreamingDetokenizer {
30
+ constructor(tokenMap?: Record<string, string>, options?: object);
31
+ buffer: string;
32
+ feed(chunk: string | Uint8Array | Buffer): string;
33
+ process(chunk: string | Uint8Array | Buffer): string;
34
+ flush(): string;
35
+ reset(): void;
36
+ updateTokenMap(newMap: Record<string, string>): void;
37
+ wrapStream<T = any>(asyncIterable: AsyncIterable<T>): AsyncGenerator<T>;
38
+ }
39
+
40
+ export declare function createStreamTokenRestorer(tokenMap: Record<string, string>, options?: object): StreamingDetokenizer;
41
+
29
42
  export declare class ZTDSFastMCPGuard {
30
43
  constructor(options?: ZTDSGuardOptions);
31
44
  enabledEntities: string[];
@@ -39,6 +52,11 @@ export declare class ZTDSFastMCPGuard {
39
52
  sanitizeObject(val: unknown, sessionId: string): unknown;
40
53
  restoreObject(val: unknown, sessionId: string): unknown;
41
54
 
55
+ getStreamDetokenizer(sessionId: string): StreamingDetokenizer;
56
+ feedStream(chunk: string, sessionId: string): string;
57
+ flushStream(sessionId: string): string;
58
+ restoreStream<T = any>(asyncIterable: AsyncIterable<T>, sessionId: string): AsyncGenerator<T>;
59
+
42
60
  wrapTool<TArgs = unknown, TResult = unknown>(
43
61
  toolName: string,
44
62
  handler: (args: TArgs, context: ZTDSContext) => Promise<TResult>
package/fastmcp.js CHANGED
@@ -11,6 +11,8 @@ const fastmcpGuard = require('./fastmcp.cjs');
11
11
  export const ZTDSFastMCPGuard = fastmcpGuard.ZTDSFastMCPGuard;
12
12
  export const ZTDS_PATTERNS = fastmcpGuard.ZTDS_PATTERNS;
13
13
  export const TOKEN_PATTERN = fastmcpGuard.TOKEN_PATTERN;
14
+ export const StreamingDetokenizer = fastmcpGuard.StreamingDetokenizer;
15
+ export const createStreamTokenRestorer = fastmcpGuard.createStreamTokenRestorer;
14
16
  export const createZTDSGuard = fastmcpGuard.createZTDSGuard;
15
17
  export const ztdsGuardTool = fastmcpGuard.ztdsGuardTool;
16
18
  export const wrapExecute = fastmcpGuard.wrapExecute;
@@ -20,6 +22,8 @@ export default {
20
22
  ZTDSFastMCPGuard,
21
23
  ZTDS_PATTERNS,
22
24
  TOKEN_PATTERN,
25
+ StreamingDetokenizer,
26
+ createStreamTokenRestorer,
23
27
  createZTDSGuard,
24
28
  ztdsGuardTool,
25
29
  wrapExecute,