promptguard-sdk 1.9.0 → 1.10.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 (67) hide show
  1. package/README.md +71 -6
  2. package/dist/auto.d.ts +50 -0
  3. package/dist/auto.d.ts.map +1 -1
  4. package/dist/auto.js +75 -5
  5. package/dist/auto.js.map +1 -1
  6. package/dist/client.d.ts +102 -36
  7. package/dist/client.d.ts.map +1 -1
  8. package/dist/client.js +171 -22
  9. package/dist/client.js.map +1 -1
  10. package/dist/generated/api-types.d.ts +226 -27
  11. package/dist/generated/api-types.d.ts.map +1 -1
  12. package/dist/guard.d.ts +48 -1
  13. package/dist/guard.d.ts.map +1 -1
  14. package/dist/guard.js +110 -21
  15. package/dist/guard.js.map +1 -1
  16. package/dist/index.d.ts +4 -3
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +2 -5
  19. package/dist/index.js.map +1 -1
  20. package/dist/integrations/langchain.d.ts +41 -1
  21. package/dist/integrations/langchain.d.ts.map +1 -1
  22. package/dist/integrations/langchain.js +88 -7
  23. package/dist/integrations/langchain.js.map +1 -1
  24. package/dist/integrations/vercel-ai.d.ts +14 -1
  25. package/dist/integrations/vercel-ai.d.ts.map +1 -1
  26. package/dist/integrations/vercel-ai.js +149 -27
  27. package/dist/integrations/vercel-ai.js.map +1 -1
  28. package/dist/logger.d.ts +7 -0
  29. package/dist/logger.d.ts.map +1 -1
  30. package/dist/logger.js +7 -0
  31. package/dist/logger.js.map +1 -1
  32. package/dist/patches/anthropic.d.ts +16 -0
  33. package/dist/patches/anthropic.d.ts.map +1 -1
  34. package/dist/patches/anthropic.js +69 -32
  35. package/dist/patches/anthropic.js.map +1 -1
  36. package/dist/patches/base.d.ts +17 -1
  37. package/dist/patches/base.d.ts.map +1 -1
  38. package/dist/patches/base.js +85 -4
  39. package/dist/patches/base.js.map +1 -1
  40. package/dist/patches/bedrock.d.ts +35 -2
  41. package/dist/patches/bedrock.d.ts.map +1 -1
  42. package/dist/patches/bedrock.js +195 -23
  43. package/dist/patches/bedrock.js.map +1 -1
  44. package/dist/patches/cohere.d.ts +11 -0
  45. package/dist/patches/cohere.d.ts.map +1 -1
  46. package/dist/patches/cohere.js +76 -2
  47. package/dist/patches/cohere.js.map +1 -1
  48. package/dist/patches/google.d.ts +8 -0
  49. package/dist/patches/google.d.ts.map +1 -1
  50. package/dist/patches/google.js +54 -0
  51. package/dist/patches/google.js.map +1 -1
  52. package/dist/patches/openai.d.ts +26 -5
  53. package/dist/patches/openai.d.ts.map +1 -1
  54. package/dist/patches/openai.js +225 -21
  55. package/dist/patches/openai.js.map +1 -1
  56. package/dist/resolve.d.ts.map +1 -1
  57. package/dist/resolve.js +6 -2
  58. package/dist/resolve.js.map +1 -1
  59. package/dist/retry.d.ts +54 -0
  60. package/dist/retry.d.ts.map +1 -0
  61. package/dist/retry.js +99 -0
  62. package/dist/retry.js.map +1 -0
  63. package/dist/version.d.ts +1 -1
  64. package/dist/version.d.ts.map +1 -1
  65. package/dist/version.js +2 -1
  66. package/dist/version.js.map +1 -1
  67. package/package.json +35 -6
package/README.md CHANGED
@@ -25,6 +25,8 @@ Get a free API key at [app.promptguard.co](https://app.promptguard.co).
25
25
  > **PromptGuard fails open by default** — if the Guard API is unavailable, calls proceed *unscanned* so your app stays up. Set `failOpen: false` to block (fail closed) on a Guard outage instead.
26
26
 
27
27
  > **Module format:** the package currently ships **CommonJS** (`require`) builds. It works in ESM projects via Node's CJS interop (`import { init } from 'promptguard-sdk'` transpiles to a `require`), and in plain CommonJS via `const { init } = require('promptguard-sdk')`.
28
+ >
29
+ > **Running a native-ESM app?** Auto-instrumentation (`init()`) may not cover your LLM calls — see [Limitations: ESM apps](#limitations) before relying on enforce mode.
28
30
 
29
31
  ## Option 1: Auto-Instrumentation (Recommended)
30
32
 
@@ -50,20 +52,36 @@ const response = await client.chat.completions.create({
50
52
  });
51
53
  ```
52
54
 
55
+ > `init()` is intentionally quiet on success (SDK logging defaults to `warn`). To confirm which provider SDKs are actually being protected, read `getAppliedPatches()` — the source of truth for what got patched:
56
+ > ```typescript
57
+ > import { init, getAppliedPatches } from 'promptguard-sdk';
58
+ > init({ apiKey: 'pg_live_xxx' });
59
+ > console.log('PromptGuard protecting:', getAppliedPatches()); // e.g. ['openai']
60
+ > ```
61
+ > If this list is empty, nothing is being scanned (see [Limitations: ESM apps](#limitations)). Set `logLevel: 'info'` on `init()` to also emit a one-line confirmation banner.
62
+
53
63
  ### Supported SDKs
54
64
 
55
65
  Auto-instrumentation patches the `create` / `generateContent` / `chat` / `send` methods on:
56
66
 
57
67
  | SDK | npm Package | What Gets Patched |
58
68
  |-----|------------|-------------------|
59
- | OpenAI | `openai` | `chat.completions.create` |
69
+ | OpenAI | `openai` | `chat.completions.create`, `responses.create` (string and message-item `input` forms) |
60
70
  | Anthropic | `@anthropic-ai/sdk` | `messages.create` |
61
71
  | Google Generative AI | `@google/generative-ai` | `generateContent` |
62
72
  | Cohere | `cohere-ai` | `Client.chat` / `ClientV2.chat` |
63
- | AWS Bedrock | `@aws-sdk/client-bedrock-runtime` | `BedrockRuntimeClient.send` (InvokeModel, Converse) |
73
+ | AWS Bedrock | `@aws-sdk/client-bedrock-runtime` | `BedrockRuntimeClient.send` (InvokeModel, InvokeModelWithResponseStream, Converse, ConverseStream) |
64
74
 
65
75
  Any framework built on these SDKs is automatically covered: **LangChain.js**, **Vercel AI SDK**, **AutoGen**, **Semantic Kernel**, and more.
66
76
 
77
+ > Patches attach to the modules resolved via CommonJS `require()`. If `init()` finds **no** patchable SDK it logs a warning (nothing would be scanned). You can also verify at runtime with `getAppliedPatches()`:
78
+ > ```typescript
79
+ > import { init, getAppliedPatches } from 'promptguard-sdk';
80
+ > init({ apiKey: 'pg_live_xxx' });
81
+ > console.log(getAppliedPatches()); // e.g. ['openai', 'anthropic']
82
+ > ```
83
+ > Native-ESM apps: see [Limitations: ESM apps](#limitations).
84
+
67
85
  ### Modes
68
86
 
69
87
  ```typescript
@@ -159,6 +177,10 @@ const result = await chain.invoke(
159
177
 
160
178
  The callback handler provides rich context to PromptGuard - chain names, tool calls, agent steps - for more precise threat detection.
161
179
 
180
+ > **Redact decisions block in enforce mode:** LangChain callbacks observe calls but cannot rewrite the inputs of the in-flight LLM call, so a `redact` decision cannot be honored — in enforce mode it is escalated to a block (`PromptGuardBlockedError`) rather than silently sending the content the Guard API asked to redact. Use auto-instrumentation or explicit `GuardClient.scan()` calls if you need actual redaction.
181
+ >
182
+ > `scanResponses` defaults to `false` (consistent with `init()` and the Vercel AI middleware) — pass `scanResponses: true` to opt in to output scanning.
183
+
162
184
  ### Vercel AI SDK
163
185
 
164
186
  ```typescript
@@ -215,17 +237,35 @@ const outputDecision = await guard.scan(
215
237
 
216
238
  ## Retry Logic
217
239
 
218
- Both `PromptGuard` and `GuardClient` support configurable retry behavior for transient failures:
240
+ Both the proxy client (`PromptGuard`) and the Guard client (`GuardClient`) support configurable retry behavior for transient failures:
219
241
 
220
242
  ```typescript
243
+ // Proxy client
221
244
  const pg = new PromptGuard({
222
245
  apiKey: 'pg_live_xxx',
223
246
  maxRetries: 3, // Number of retry attempts (default: 3)
224
247
  retryDelay: 500, // Base delay in ms between retries (default: 1000)
225
248
  });
249
+
250
+ // Guard client (standalone scanning)
251
+ const guard = new GuardClient({
252
+ apiKey: 'pg_live_xxx',
253
+ maxRetries: 3, // default: 3
254
+ retryDelay: 500, // default: 1000
255
+ });
226
256
  ```
227
257
 
228
- Retries use exponential backoff starting from `retryDelay`. Only transient errors (network timeouts, 5xx responses) are retried; client errors (4xx) fail immediately.
258
+ Because auto-instrumentation (`init()`) and the framework integrations all scan through `GuardClient`, they retry transient Guard API failures too — pass `maxRetries` / `retryDelay` to `init()`, `PromptGuardCallbackHandler`, or `promptGuardMiddleware`:
259
+
260
+ ```typescript
261
+ init({ apiKey: 'pg_live_xxx', maxRetries: 3, retryDelay: 500 });
262
+ ```
263
+
264
+ Retries use exponential backoff starting from `retryDelay`, with jitter so concurrent clients don't retry in lockstep. A server-provided `Retry-After` header is honored but clamped to 60 seconds. Only transient errors (network timeouts, 429/5xx responses) are retried; client errors (4xx) fail immediately.
265
+
266
+ > **Enforcement is unchanged by retries.** Retrying only affects *transient* Guard failures (network errors, 429/5xx). A real `block` / `redact` decision is terminal and is never retried, and once retries are exhausted a `GuardApiError` is raised so your existing `failOpen` policy governs — exactly as it would with `maxRetries: 0`. Retries never turn a would-be error into an allow.
267
+
268
+ > **Idempotency caveat:** all requests — including `POST`s — are retried on transient failure. If a request reached the server but the response was lost, the retry re-submits it. Chat/completion/scan calls are safe to re-submit, but each attempt may bill separately; set `maxRetries: 0` if you need strict at-most-once semantics.
229
269
 
230
270
  ## Embeddings
231
271
 
@@ -275,11 +315,11 @@ const report = await pg.redteam.runAutonomous({
275
315
  budget: 200,
276
316
  targetPreset: 'support_bot:strict', // snake_case `target_preset` also accepted
277
317
  });
278
- console.log(`Grade: ${report.grade}, Bypass rate: ${(report.bypass_rate * 100).toFixed(0)}%`);
318
+ console.log(`Grade: ${report.grade}, Bypass rate: ${(report.bypassRate * 100).toFixed(0)}%`);
279
319
 
280
320
  // Get Attack Intelligence stats
281
321
  const stats = await pg.redteam.intelligenceStats();
282
- console.log(`Total patterns: ${stats.total_patterns}`);
322
+ console.log(`Total patterns: ${stats.totalPatterns}`);
283
323
  ```
284
324
 
285
325
  ## Configuration
@@ -298,6 +338,29 @@ console.log(`Total patterns: ${stats.total_patterns}`);
298
338
  > The proxy client (`PromptGuard`) talks to the `/api/v1/proxy` endpoints. If you set `baseUrl` / `PROMPTGUARD_BASE_URL` to `.../api/v1` (without `/proxy`), the SDK appends the `/proxy` suffix for you, so requests still land on the proxy.
299
339
  >
300
340
  > **Security:** the SDK sends your API key (and, in proxy mode, your prompt content) to whatever `PROMPTGUARD_BASE_URL` points at. Self-hosting is supported, so only point it at a host you trust.
341
+ >
342
+ > **Logging is process-global:** `logLevel` / `silent` set a single shared log level for the whole SDK. If several integrations or `init()` calls pass different values, the most recently constructed one wins. Use `setLogLevel()` directly for fine-grained control.
343
+
344
+ ## Limitations
345
+
346
+ ### ESM apps (auto-instrumentation)
347
+
348
+ Auto-instrumentation (`init()`) patches the provider modules that Node resolves via **CommonJS `require()`**. If your application runs as **native ESM** (`"type": "module"` in package.json, or `.mjs` files) and a provider ships separate ESM builds, the module instances your code `import`s can be *different objects* from the ones the SDK patched — the **dual-package hazard**. In that case your LLM calls bypass the patches entirely and **enforce mode silently protects nothing**.
349
+
350
+ What to do:
351
+
352
+ - **Verify at runtime** with `getAppliedPatches()` after `init()` — and note that a patch being listed proves the CJS build was patched, not that your ESM imports go through it. `init()` also logs a warning when it applies zero patches.
353
+ - **Prefer the ESM-safe APIs**, which don't rely on module patching:
354
+ - LangChain: `PromptGuardCallbackHandler` (`promptguard-sdk/integrations/langchain`)
355
+ - Vercel AI SDK: `promptGuardMiddleware` (`promptguard-sdk/integrations/vercel-ai`)
356
+ - Any framework: explicit `GuardClient.scan()` calls around your LLM invocations
357
+ - Transpiled-to-CJS TypeScript apps (the common `tsc`/`ts-node` default) are **not** affected — their `import`s compile to `require()` and hit the patched modules.
358
+
359
+ ### Other limitations
360
+
361
+ - **Streaming responses are not output-scanned.** With auto-instrumentation and `scanResponses: true`, streaming calls (`stream: true`, Bedrock `ConverseStreamCommand`, etc.) skip the output scan — the stream is consumed incrementally by your code and cannot be buffered without breaking stream semantics. Input scanning still applies. A `debug`-level log is emitted when the output scan is skipped. The same applies to the Vercel AI SDK middleware: `streamText()` outputs are not scanned (`wrapStream` logs the skip); `generateText()` outputs are.
362
+ - **OpenAI `APIPromise` helpers are not preserved by auto-instrumentation.** Patched methods return a plain `Promise`, so `.withResponse()` / `.asResponse()` on `client.chat.completions.create(...)` are unavailable while `init()` is active. `await` the call and use the plain result instead.
363
+ - **Proxy client streaming:** `pg.chat.completions.create({ stream: true })` is rejected with a clear error — streaming is not yet supported by the proxy client.
301
364
 
302
365
  ## Error Handling
303
366
 
@@ -338,6 +401,8 @@ import type {
338
401
  } from 'promptguard-sdk';
339
402
  ```
340
403
 
404
+ > **Response fields are camelCase — with one deliberate exception.** The SDK's normalized response objects (the `security`, `redteam`, `agent`, `scrape`, and `guard` namespaces) use camelCase field names (e.g. `report.bypassRate`, `stats.totalPatterns`, `validation.riskScore`, `result.threatsDetected`) regardless of the snake_case wire format — consistent with `GuardDecision` and `SecurityScanResult`. The **OpenAI-compatible** responses (`chat.completions`, `completions`, `embeddings`, i.e. `ChatCompletionResponse`) are the exception: they intentionally preserve OpenAI's snake_case shape (`choices[].finish_reason`, `usage.prompt_tokens`, …) so they stay drop-in compatible with the `openai` client. Request options are camelCase throughout (`maxTokens`, `targetPreset`), including `GuardContext` (`chainName`, `agentId`, `sessionId`, `toolCalls`).
405
+
341
406
  ## Links
342
407
 
343
408
  - [Documentation](https://docs.promptguard.co)
package/dist/auto.d.ts CHANGED
@@ -30,18 +30,68 @@ export interface InitOptions {
30
30
  scanResponses?: boolean;
31
31
  /** HTTP timeout in ms for Guard API calls (default: `10000`). */
32
32
  timeout?: number;
33
+ /**
34
+ * Retry attempts for transient Guard API failures (network errors and
35
+ * 429/5xx responses) before the `failOpen` policy governs. Default: `3`.
36
+ * Retries never change the eventual decision — see {@link GuardClientConfig}.
37
+ */
38
+ maxRetries?: number;
39
+ /** Base delay in ms between Guard API retries (exponential backoff). Default: `1000`. */
40
+ retryDelay?: number;
33
41
  /**
34
42
  * SDK log verbosity (default: `"warn"`). Set to `"silent"` to suppress all
35
43
  * SDK logging, or `"info"`/`"debug"` for the init banner and more detail.
44
+ * NOTE: this sets the **process-global** SDK log level (shared with the
45
+ * framework integrations); the most recent setter wins.
36
46
  */
37
47
  logLevel?: LogLevel;
38
48
  /** Convenience shorthand for `logLevel: "silent"`. */
39
49
  silent?: boolean;
40
50
  }
51
+ /**
52
+ * Initialise PromptGuard auto-instrumentation.
53
+ *
54
+ * Patches the provider SDKs (`openai`, `@anthropic-ai/sdk`,
55
+ * `@google/generative-ai`, `cohere-ai`, `@aws-sdk/client-bedrock-runtime`)
56
+ * so every LLM call they make is scanned by the Guard API.
57
+ *
58
+ * **Limitation — ESM apps (dual-package hazard):** patches are applied to the
59
+ * module instances resolved via CommonJS `require()`. If your application runs
60
+ * as native ESM (`"type": "module"` / `.mjs`) and the provider ships separate
61
+ * ESM builds, your `import`ed module instances can be *different objects* from
62
+ * the patched CJS ones — in that case auto-instrumentation silently protects
63
+ * nothing. Use {@link getAppliedPatches} as a runtime canary to verify the
64
+ * providers you use were actually patched, and prefer the ESM-safe
65
+ * alternatives: the LangChain callback handler
66
+ * (`promptguard-sdk/integrations/langchain`), the Vercel AI SDK middleware
67
+ * (`promptguard-sdk/integrations/vercel-ai`), or explicit `GuardClient.scan()`
68
+ * calls. See README "Limitations: ESM apps".
69
+ *
70
+ * When zero patches could be applied, a warning is logged so a
71
+ * misconfiguration never fails silently.
72
+ */
41
73
  export declare function init(options?: InitOptions): void;
42
74
  export declare function shutdown(): void;
43
75
  export declare function getGuardClient(): GuardClient | null;
44
76
  export declare function getMode(): "enforce" | "monitor";
45
77
  export declare function isFailOpen(): boolean;
46
78
  export declare function shouldScanResponses(): boolean;
79
+ /**
80
+ * Runtime canary: the names of the auto-instrumentation patches that were
81
+ * actually applied by {@link init} (e.g. `["openai", "anthropic"]`).
82
+ *
83
+ * Because patches attach to the CJS-resolved provider modules, an ESM app can
84
+ * call `init()` successfully and still be unprotected (see the dual-package
85
+ * hazard note on {@link init}). Assert on this at startup when you rely on
86
+ * enforce mode:
87
+ *
88
+ * @example
89
+ * ```ts
90
+ * init({ apiKey: "pg_live_xxx" });
91
+ * if (!getAppliedPatches().includes("openai")) {
92
+ * throw new Error("PromptGuard did not patch the openai SDK");
93
+ * }
94
+ * ```
95
+ */
96
+ export declare function getAppliedPatches(): string[];
47
97
  //# sourceMappingURL=auto.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auto.d.ts","sourceRoot":"","sources":["../src/auto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACrC,OAAO,EAAE,KAAK,QAAQ,EAAuB,MAAM,UAAU,CAAA;AAkB7D,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,mFAAmF;IACnF,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;IAC5B,uEAAuE;IACvE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,kDAAkD;IAClD,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB,sDAAsD;IACtD,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,wBAAgB,IAAI,CAAC,OAAO,GAAE,WAAgB,GAAG,IAAI,CA4BpD;AAED,wBAAgB,QAAQ,IAAI,IAAI,CAU/B;AAMD,wBAAgB,cAAc,IAAI,WAAW,GAAG,IAAI,CAEnD;AAED,wBAAgB,OAAO,IAAI,SAAS,GAAG,SAAS,CAE/C;AAED,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAED,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C"}
1
+ {"version":3,"file":"auto.d.ts","sourceRoot":"","sources":["../src/auto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACrC,OAAO,EAAE,KAAK,QAAQ,EAAuB,MAAM,UAAU,CAAA;AAkB7D,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,mFAAmF;IACnF,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;IAC5B,uEAAuE;IACvE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,kDAAkD;IAClD,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,yFAAyF;IACzF,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB,sDAAsD;IACtD,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,IAAI,CAAC,OAAO,GAAE,WAAgB,GAAG,IAAI,CAqCpD;AAED,wBAAgB,QAAQ,IAAI,IAAI,CAU/B;AAMD,wBAAgB,cAAc,IAAI,WAAW,GAAG,IAAI,CAEnD;AAED,wBAAgB,OAAO,IAAI,SAAS,GAAG,SAAS,CAE/C;AAED,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAED,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,EAAE,CAE5C"}
package/dist/auto.js CHANGED
@@ -25,6 +25,7 @@ exports.getGuardClient = getGuardClient;
25
25
  exports.getMode = getMode;
26
26
  exports.isFailOpen = isFailOpen;
27
27
  exports.shouldScanResponses = shouldScanResponses;
28
+ exports.getAppliedPatches = getAppliedPatches;
28
29
  const guard_1 = require("./guard");
29
30
  const logger_1 = require("./logger");
30
31
  const resolve_1 = require("./resolve");
@@ -36,6 +37,28 @@ let mode = "enforce";
36
37
  let failOpen = true;
37
38
  let scanResponses = false;
38
39
  const appliedPatches = [];
40
+ /**
41
+ * Initialise PromptGuard auto-instrumentation.
42
+ *
43
+ * Patches the provider SDKs (`openai`, `@anthropic-ai/sdk`,
44
+ * `@google/generative-ai`, `cohere-ai`, `@aws-sdk/client-bedrock-runtime`)
45
+ * so every LLM call they make is scanned by the Guard API.
46
+ *
47
+ * **Limitation — ESM apps (dual-package hazard):** patches are applied to the
48
+ * module instances resolved via CommonJS `require()`. If your application runs
49
+ * as native ESM (`"type": "module"` / `.mjs`) and the provider ships separate
50
+ * ESM builds, your `import`ed module instances can be *different objects* from
51
+ * the patched CJS ones — in that case auto-instrumentation silently protects
52
+ * nothing. Use {@link getAppliedPatches} as a runtime canary to verify the
53
+ * providers you use were actually patched, and prefer the ESM-safe
54
+ * alternatives: the LangChain callback handler
55
+ * (`promptguard-sdk/integrations/langchain`), the Vercel AI SDK middleware
56
+ * (`promptguard-sdk/integrations/vercel-ai`), or explicit `GuardClient.scan()`
57
+ * calls. See README "Limitations: ESM apps".
58
+ *
59
+ * When zero patches could be applied, a warning is logged so a
60
+ * misconfiguration never fails silently.
61
+ */
39
62
  function init(options = {}) {
40
63
  if (options.silent) {
41
64
  (0, logger_1.setLogLevel)("silent");
@@ -52,13 +75,20 @@ function init(options = {}) {
52
75
  apiKey,
53
76
  baseUrl,
54
77
  timeout: options.timeout ?? 10000,
78
+ maxRetries: options.maxRetries,
79
+ retryDelay: options.retryDelay,
55
80
  });
56
81
  mode = resolvedMode;
57
82
  failOpen = options.failOpen ?? true;
58
83
  scanResponses = options.scanResponses ?? false;
59
84
  applyPatches();
60
- // Suppressed by default (info level). Set logLevel: "info" to see this.
61
- logger_1.logger.info(`auto-instrumentation initialised (mode=${mode}, fail_open=${failOpen})`);
85
+ // One-line confirmation of which provider SDKs are actually protected.
86
+ // Suppressed by default (info level); set logLevel: "info" to see it, or
87
+ // read the same list programmatically via getAppliedPatches(). When ZERO
88
+ // patches applied, applyPatches() already logged a warn (visible by default).
89
+ const protecting = getAppliedPatches();
90
+ logger_1.logger.info(`auto-instrumentation initialised (mode=${mode}, fail_open=${failOpen}) — ` +
91
+ `protecting: ${protecting.length ? protecting.join(", ") : "none"}`);
62
92
  }
63
93
  function shutdown() {
64
94
  for (const patch of appliedPatches) {
@@ -87,6 +117,26 @@ function isFailOpen() {
87
117
  function shouldScanResponses() {
88
118
  return scanResponses;
89
119
  }
120
+ /**
121
+ * Runtime canary: the names of the auto-instrumentation patches that were
122
+ * actually applied by {@link init} (e.g. `["openai", "anthropic"]`).
123
+ *
124
+ * Because patches attach to the CJS-resolved provider modules, an ESM app can
125
+ * call `init()` successfully and still be unprotected (see the dual-package
126
+ * hazard note on {@link init}). Assert on this at startup when you rely on
127
+ * enforce mode:
128
+ *
129
+ * @example
130
+ * ```ts
131
+ * init({ apiKey: "pg_live_xxx" });
132
+ * if (!getAppliedPatches().includes("openai")) {
133
+ * throw new Error("PromptGuard did not patch the openai SDK");
134
+ * }
135
+ * ```
136
+ */
137
+ function getAppliedPatches() {
138
+ return appliedPatches.map((p) => p.name);
139
+ }
90
140
  // ---------------------------------------------------------------------------
91
141
  // Patch orchestration
92
142
  // ---------------------------------------------------------------------------
@@ -102,12 +152,32 @@ function applyPatches() {
102
152
  try {
103
153
  const patchModule = require(mod.path);
104
154
  if (patchModule.apply()) {
105
- appliedPatches.push({ name: mod.name, revert: patchModule.revert });
155
+ // apply() is idempotent per patch module, so a second init() without
156
+ // shutdown() reports "already patched" success. Skip the push when
157
+ // the patch is already tracked — a duplicate entry would make the
158
+ // getAppliedPatches() canary lie and call revert() twice on
159
+ // shutdown().
160
+ if (!appliedPatches.some((p) => p.name === mod.name)) {
161
+ appliedPatches.push({ name: mod.name, revert: patchModule.revert });
162
+ }
163
+ }
164
+ else {
165
+ logger_1.logger.debug(`${mod.name} patch not applied: SDK not resolvable via require() ` +
166
+ `(not installed, or only reachable as ESM)`);
106
167
  }
107
168
  }
108
- catch {
109
- // SDK not installed or incompatible - skip silently
169
+ catch (err) {
170
+ logger_1.logger.debug(`${mod.name} patch not applied: ${err instanceof Error ? err.message : String(err)}`);
110
171
  }
111
172
  }
173
+ if (appliedPatches.length === 0) {
174
+ logger_1.logger.warn("init() applied ZERO auto-instrumentation patches — no supported LLM SDK was " +
175
+ "resolvable via CommonJS require(), so NO calls are being scanned. If your app " +
176
+ 'runs as native ESM ("type": "module" / .mjs), auto-instrumentation cannot see ' +
177
+ "the module instances your code imports (dual-package hazard). Use the ESM-safe " +
178
+ "integrations instead: the LangChain callback handler, the Vercel AI SDK " +
179
+ "middleware, or explicit GuardClient.scan() calls. " +
180
+ 'See README "Limitations: ESM apps". Set logLevel: "debug" for per-SDK reasons.');
181
+ }
112
182
  }
113
183
  //# sourceMappingURL=auto.js.map
package/dist/auto.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"auto.js","sourceRoot":"","sources":["../src/auto.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auto.js","sourceRoot":"","sources":["../src/auto.ts"],"names":[],"mappings":"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"}
package/dist/client.d.ts CHANGED
@@ -2,26 +2,47 @@
2
2
  * PromptGuard proxy client — OpenAI-compatible API with built-in
3
3
  * security scanning, retry logic, and namespace helpers.
4
4
  */
5
- interface PromptGuardConfig {
5
+ export interface PromptGuardConfig {
6
6
  apiKey: string;
7
+ /**
8
+ * API base URL. Defaults to the public PromptGuard proxy
9
+ * (`https://api.promptguard.co/api/v1/proxy`) or `PROMPTGUARD_BASE_URL`.
10
+ * The `/proxy` suffix is appended automatically when missing.
11
+ */
7
12
  baseUrl?: string;
13
+ /** HTTP timeout in milliseconds for each request attempt. Default: `30000`. */
8
14
  timeout?: number;
15
+ /**
16
+ * Number of retry attempts for transient failures (network errors and
17
+ * 429/5xx responses). Default: `3`. Set to `0` for strict at-most-once
18
+ * semantics. Negative values are clamped to `0`.
19
+ */
9
20
  maxRetries?: number;
21
+ /** Base delay in ms between retries (exponential backoff). Default: `1000`. */
10
22
  retryDelay?: number;
11
23
  }
12
- interface Message {
13
- role: "system" | "user" | "assistant";
24
+ export interface Message {
25
+ role: "system" | "user" | "assistant" | "tool" | "function";
14
26
  content: string;
15
27
  }
16
- interface ChatCompletionRequest {
28
+ export interface ChatCompletionRequest {
17
29
  model: string;
18
30
  messages: Message[];
19
31
  temperature?: number;
32
+ /** Maximum tokens to generate. Serialized to the wire as `max_tokens`. */
20
33
  maxTokens?: number;
21
- stream?: boolean;
34
+ /**
35
+ * OpenAI-compatible escape hatch: any additional keys (e.g. `top_p`,
36
+ * `frequency_penalty`, `stop`, `tools`) are forwarded verbatim to the proxy.
37
+ * Because these keys are not type-checked, a misspelled parameter is silently
38
+ * passed through rather than flagged at compile time — double-check the
39
+ * spelling of options not listed above. (`stream: true` is the one key
40
+ * rejected: the client parses a single JSON response body, so it throws at
41
+ * runtime instead of forwarding.)
42
+ */
22
43
  [key: string]: unknown;
23
44
  }
24
- interface ChatCompletionResponse {
45
+ export interface ChatCompletionResponse {
25
46
  id: string;
26
47
  object: string;
27
48
  created: number;
@@ -37,14 +58,22 @@ interface ChatCompletionResponse {
37
58
  total_tokens: number;
38
59
  };
39
60
  }
40
- interface CompletionRequest {
61
+ export interface CompletionRequest {
41
62
  model: string;
42
63
  prompt: string;
43
64
  temperature?: number;
65
+ /** Maximum tokens to generate. Serialized to the wire as `max_tokens`. */
44
66
  maxTokens?: number;
67
+ /**
68
+ * OpenAI-compatible escape hatch: any additional keys are forwarded verbatim
69
+ * to the proxy. Because these keys are not type-checked, a misspelled
70
+ * parameter is silently passed through rather than flagged at compile time.
71
+ * (`stream: true` is rejected at runtime — the client parses a single JSON
72
+ * response body.)
73
+ */
45
74
  [key: string]: unknown;
46
75
  }
47
- interface CompletionResponse {
76
+ export interface CompletionResponse {
48
77
  id: string;
49
78
  object: string;
50
79
  created: number;
@@ -60,12 +89,18 @@ interface CompletionResponse {
60
89
  total_tokens: number;
61
90
  };
62
91
  }
63
- interface EmbeddingRequest {
92
+ export interface EmbeddingRequest {
64
93
  model: string;
65
94
  input: string | string[];
95
+ /**
96
+ * OpenAI-compatible escape hatch: any additional keys (e.g. `dimensions`,
97
+ * `encoding_format`, `user`) are forwarded verbatim to the proxy. Because
98
+ * these keys are not type-checked, a misspelled parameter is silently passed
99
+ * through rather than flagged at compile time.
100
+ */
66
101
  [key: string]: unknown;
67
102
  }
68
- interface EmbeddingResponse {
103
+ export interface EmbeddingResponse {
69
104
  object: string;
70
105
  data: Array<{
71
106
  object: string;
@@ -78,51 +113,59 @@ interface EmbeddingResponse {
78
113
  total_tokens: number;
79
114
  };
80
115
  }
81
- interface SecurityScanResult {
116
+ export interface SecurityScanResult {
82
117
  blocked: boolean;
83
118
  decision: "allow" | "block" | "redact";
84
119
  reason?: string;
85
120
  threatType?: string;
86
121
  confidence?: number;
87
122
  }
88
- interface RedactResult {
123
+ export interface RedactResult {
89
124
  original: string;
90
125
  redacted: string;
91
126
  piiFound: string[];
92
127
  }
93
- interface ScrapeResult {
128
+ export interface ScrapeResult {
94
129
  url: string;
95
130
  status: "safe" | "blocked";
96
131
  content: string;
97
- threats_detected: string[];
132
+ /** Normalized from the wire field `threats_detected`. */
133
+ threatsDetected: string[];
98
134
  message?: string;
99
135
  }
100
- interface ToolValidationResult {
136
+ export interface ToolValidationResult {
101
137
  allowed: boolean;
102
- risk_score: number;
103
- risk_level: string;
138
+ /** Normalized from the wire field `risk_score`. */
139
+ riskScore: number;
140
+ /** Normalized from the wire field `risk_level`. */
141
+ riskLevel: string;
104
142
  reason: string;
105
143
  warnings: string[];
106
- blocked_reasons: string[];
144
+ /** Normalized from the wire field `blocked_reasons`. */
145
+ blockedReasons: string[];
107
146
  }
108
- interface RedTeamTestResult {
109
- test_name: string;
147
+ export interface RedTeamTestResult {
148
+ /** Normalized from the wire field `test_name`. */
149
+ testName: string;
110
150
  prompt: string;
111
151
  decision: string;
112
152
  reason: string;
113
- threat_type?: string;
153
+ /** Normalized from the wire field `threat_type`. */
154
+ threatType?: string;
114
155
  confidence: number;
115
156
  blocked: boolean;
116
157
  details: Record<string, unknown>;
117
158
  }
118
- interface RedTeamSummary {
119
- total_tests: number;
159
+ export interface RedTeamSummary {
160
+ /** Normalized from the wire field `total_tests`. */
161
+ totalTests: number;
120
162
  blocked: number;
121
163
  allowed: number;
122
- block_rate: number;
164
+ /** Normalized from the wire field `block_rate`. */
165
+ blockRate: number;
123
166
  results: RedTeamTestResult[];
124
167
  }
125
- interface AutonomousRedTeamRequest {
168
+ export interface AutonomousRedTeamRequest {
126
169
  budget?: number;
127
170
  /** Target preset to attack (camelCase, preferred). */
128
171
  targetPreset?: string;
@@ -133,19 +176,26 @@ interface AutonomousRedTeamRequest {
133
176
  /** @deprecated snake_case alias for `enabledDetectors`; kept for back-compat. */
134
177
  enabled_detectors?: string[];
135
178
  }
136
- interface AutonomousRedTeamReport {
179
+ export interface AutonomousRedTeamReport {
137
180
  grade: string;
138
- bypass_rate: number;
139
- total_attempts: number;
140
- bypasses_found: number;
181
+ /** Normalized from the wire field `bypass_rate`. */
182
+ bypassRate: number;
183
+ /** Normalized from the wire field `total_attempts`. */
184
+ totalAttempts: number;
185
+ /** Normalized from the wire field `bypasses_found`. */
186
+ bypassesFound: number;
141
187
  bypasses: Array<Record<string, unknown>>;
142
188
  recommendations: string[];
143
189
  }
144
- interface IntelligenceStats {
145
- total_patterns: number;
146
- by_category: Record<string, number>;
147
- by_severity: Record<string, number>;
148
- recent_discoveries: number;
190
+ export interface IntelligenceStats {
191
+ /** Normalized from the wire field `total_patterns`. */
192
+ totalPatterns: number;
193
+ /** Normalized from the wire field `by_category`. */
194
+ byCategory: Record<string, number>;
195
+ /** Normalized from the wire field `by_severity`. */
196
+ bySeverity: Record<string, number>;
197
+ /** Normalized from the wire field `recent_discoveries`. */
198
+ recentDiscoveries: number;
149
199
  }
150
200
  /**
151
201
  * Ensure the proxy base URL's path ends with `/proxy`.
@@ -159,6 +209,16 @@ interface IntelligenceStats {
159
209
  * correctly and the scheme/host/port/query/fragment are preserved exactly.
160
210
  */
161
211
  export declare function ensureProxySuffix(baseUrl: string): string;
212
+ /**
213
+ * Join an endpoint path onto the configured base URL.
214
+ *
215
+ * Plain string concatenation broke base URLs carrying a query string or
216
+ * fragment (which `ensureProxySuffix` deliberately preserves): the endpoint
217
+ * path landed inside the query/fragment value and every namespaced call
218
+ * routed to the wrong endpoint. Splice the path onto the URL's pathname so
219
+ * the query/fragment stay where they belong.
220
+ */
221
+ export declare function buildRequestUrl(baseUrl: string, path: string): string;
162
222
  declare class ChatCompletions {
163
223
  private client;
164
224
  constructor(client: PromptGuard);
@@ -193,7 +253,7 @@ declare class Scrape {
193
253
  timeout?: number;
194
254
  }): Promise<ScrapeResult>;
195
255
  batch(urls: string[], options?: Record<string, unknown>): Promise<{
196
- job_id: string;
256
+ jobId: string;
197
257
  }>;
198
258
  }
199
259
  declare class Agent {
@@ -229,6 +289,12 @@ export declare class PromptGuard {
229
289
  request<T>(method: string, path: string, body?: unknown): Promise<T>;
230
290
  }
231
291
  export declare class PromptGuardError extends Error {
292
+ /**
293
+ * Machine-readable error code. Server-forwarded codes pass through verbatim
294
+ * (their own casing). Codes minted by the SDK itself use lower_snake_case:
295
+ * `missing_api_key`, `streaming_not_supported`, `invalid_response_body`,
296
+ * `max_retries`, and the fallback `unknown`.
297
+ */
232
298
  code: string;
233
299
  statusCode: number;
234
300
  errorType?: string;
@@ -244,5 +310,5 @@ export declare class PromptGuardError extends Error {
244
310
  requestsLimit?: number;
245
311
  });
246
312
  }
247
- export default PromptGuard;
313
+ export {};
248
314
  //# sourceMappingURL=client.d.ts.map