risicare 0.3.0 → 0.4.2

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 (80) hide show
  1. package/README.md +26 -10
  2. package/dist/frameworks/instructor.cjs +94 -81
  3. package/dist/frameworks/instructor.cjs.map +1 -1
  4. package/dist/frameworks/instructor.d.cts +19 -7
  5. package/dist/frameworks/instructor.d.ts +19 -7
  6. package/dist/frameworks/instructor.js +94 -83
  7. package/dist/frameworks/instructor.js.map +1 -1
  8. package/dist/frameworks/langchain.cjs +192 -101
  9. package/dist/frameworks/langchain.cjs.map +1 -1
  10. package/dist/frameworks/langchain.d.cts +97 -3
  11. package/dist/frameworks/langchain.d.ts +97 -3
  12. package/dist/frameworks/langchain.js +196 -101
  13. package/dist/frameworks/langchain.js.map +1 -1
  14. package/dist/frameworks/langgraph.cjs +192 -101
  15. package/dist/frameworks/langgraph.cjs.map +1 -1
  16. package/dist/frameworks/langgraph.js +196 -101
  17. package/dist/frameworks/langgraph.js.map +1 -1
  18. package/dist/frameworks/llamaindex.cjs +92 -74
  19. package/dist/frameworks/llamaindex.cjs.map +1 -1
  20. package/dist/frameworks/llamaindex.d.cts +33 -17
  21. package/dist/frameworks/llamaindex.d.ts +33 -17
  22. package/dist/frameworks/llamaindex.js +92 -76
  23. package/dist/frameworks/llamaindex.js.map +1 -1
  24. package/dist/index.cjs +2864 -2346
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +196 -6
  27. package/dist/index.d.ts +196 -6
  28. package/dist/index.js +2811 -2315
  29. package/dist/index.js.map +1 -1
  30. package/dist/providers/anthropic/index.cjs +41 -49
  31. package/dist/providers/anthropic/index.cjs.map +1 -1
  32. package/dist/providers/anthropic/index.js +41 -51
  33. package/dist/providers/anthropic/index.js.map +1 -1
  34. package/dist/providers/bedrock/index.cjs +64 -59
  35. package/dist/providers/bedrock/index.cjs.map +1 -1
  36. package/dist/providers/bedrock/index.d.cts +13 -1
  37. package/dist/providers/bedrock/index.d.ts +13 -1
  38. package/dist/providers/bedrock/index.js +63 -61
  39. package/dist/providers/bedrock/index.js.map +1 -1
  40. package/dist/providers/cerebras/index.cjs +41 -49
  41. package/dist/providers/cerebras/index.cjs.map +1 -1
  42. package/dist/providers/cerebras/index.js +41 -51
  43. package/dist/providers/cerebras/index.js.map +1 -1
  44. package/dist/providers/cohere/index.cjs +43 -51
  45. package/dist/providers/cohere/index.cjs.map +1 -1
  46. package/dist/providers/cohere/index.js +43 -53
  47. package/dist/providers/cohere/index.js.map +1 -1
  48. package/dist/providers/google/index.cjs +41 -49
  49. package/dist/providers/google/index.cjs.map +1 -1
  50. package/dist/providers/google/index.js +41 -51
  51. package/dist/providers/google/index.js.map +1 -1
  52. package/dist/providers/groq/index.cjs +41 -49
  53. package/dist/providers/groq/index.cjs.map +1 -1
  54. package/dist/providers/groq/index.js +41 -51
  55. package/dist/providers/groq/index.js.map +1 -1
  56. package/dist/providers/huggingface/index.cjs +41 -49
  57. package/dist/providers/huggingface/index.cjs.map +1 -1
  58. package/dist/providers/huggingface/index.js +41 -51
  59. package/dist/providers/huggingface/index.js.map +1 -1
  60. package/dist/providers/mistral/index.cjs +45 -53
  61. package/dist/providers/mistral/index.cjs.map +1 -1
  62. package/dist/providers/mistral/index.js +45 -55
  63. package/dist/providers/mistral/index.js.map +1 -1
  64. package/dist/providers/ollama/index.cjs +49 -49
  65. package/dist/providers/ollama/index.cjs.map +1 -1
  66. package/dist/providers/ollama/index.js +49 -51
  67. package/dist/providers/ollama/index.js.map +1 -1
  68. package/dist/providers/openai/index.cjs +60 -1377
  69. package/dist/providers/openai/index.cjs.map +1 -1
  70. package/dist/providers/openai/index.js +60 -1395
  71. package/dist/providers/openai/index.js.map +1 -1
  72. package/dist/providers/together/index.cjs +41 -49
  73. package/dist/providers/together/index.cjs.map +1 -1
  74. package/dist/providers/together/index.js +41 -51
  75. package/dist/providers/together/index.js.map +1 -1
  76. package/dist/providers/vercel-ai/index.cjs +28 -43
  77. package/dist/providers/vercel-ai/index.cjs.map +1 -1
  78. package/dist/providers/vercel-ai/index.js +28 -45
  79. package/dist/providers/vercel-ai/index.js.map +1 -1
  80. package/package.json +98 -36
package/dist/index.d.cts CHANGED
@@ -371,7 +371,7 @@ declare function getMetrics(): {
371
371
  queueUtilization: number;
372
372
  };
373
373
  /**
374
- * Report a caught exception to the self-healing pipeline.
374
+ * Report a caught exception to the error diagnosis pipeline.
375
375
  *
376
376
  * Creates an error span that triggers diagnosis and fix generation.
377
377
  * Deduplicates identical errors within a 5-minute window (SHA256 fingerprint).
@@ -430,6 +430,17 @@ declare function withAgent<T>(options: AgentOptions, fn: () => T): T;
430
430
  * Wraps a function to execute within an agent context. All spans created
431
431
  * inside will be tagged with the agent's identity.
432
432
  *
433
+ * Two equivalent calling forms are supported:
434
+ *
435
+ * // 2-arg form
436
+ * const research = agent({ name: 'researcher' }, async (q) => { ... });
437
+ *
438
+ * // Curried form (decorator factory)
439
+ * const research = agent({ name: 'researcher' })(async (q) => { ... });
440
+ *
441
+ * Both return a wrapped function — call it to actually run the body inside
442
+ * the agent context.
443
+ *
433
444
  * @example
434
445
  * const research = agent({ name: 'researcher', role: 'worker' }, async (query: string) => {
435
446
  * const result = await openai.chat.completions.create({ ... });
@@ -439,10 +450,8 @@ declare function withAgent<T>(options: AgentOptions, fn: () => T): T;
439
450
  * const answer = await research('What is quantum computing?');
440
451
  */
441
452
 
442
- /**
443
- * Wrap a function with agent context and an automatic span.
444
- */
445
453
  declare function agent<TArgs extends unknown[], TReturn>(options: AgentOptions, fn: (...args: TArgs) => TReturn): (...args: TArgs) => TReturn;
454
+ declare function agent(options: AgentOptions): <TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => TReturn) => (...args: TArgs) => TReturn;
446
455
 
447
456
  /**
448
457
  * Session context — groups multiple traces from the same user interaction.
@@ -483,10 +492,19 @@ declare function withSession<T>(options: SessionOptions, fn: () => T): T;
483
492
  /**
484
493
  * Wrap a function with session context.
485
494
  *
495
+ * Two equivalent calling forms are supported (F-54 ergonomics):
496
+ *
497
+ * // 2-arg form
498
+ * const handle = session({ sessionId: 's1' }, async (req) => { ... });
499
+ *
500
+ * // Curried form (decorator factory)
501
+ * const handle = session({ sessionId: 's1' })(async (req) => { ... });
502
+ *
486
503
  * @param optionsOrResolver - Static session options, or a function that derives them from args
487
- * @param fn - The function to wrap
504
+ * @param fn - The function to wrap. If omitted, returns a decorator factory.
488
505
  */
489
506
  declare function session<TArgs extends unknown[], TReturn>(optionsOrResolver: SessionOptions | ((...args: TArgs) => SessionOptions), fn: (...args: TArgs) => TReturn): (...args: TArgs) => TReturn;
507
+ declare function session<TArgs extends unknown[]>(optionsOrResolver: SessionOptions | ((...args: TArgs) => SessionOptions)): <TR>(fn: (...args: TArgs) => TR) => (...args: TArgs) => TR;
490
508
 
491
509
  /**
492
510
  * Phase decorators — decision phase tracking (Tier 4).
@@ -855,6 +873,13 @@ interface ApplyResult {
855
873
  fixType?: string;
856
874
  modifications: Record<string, unknown>;
857
875
  error?: string;
876
+ /**
877
+ * Guard-only: human-readable reason a guard failed (passed=false). Used
878
+ * by GuardRejectedError to surface an actionable message to the customer.
879
+ * `error` carries the raw exception text; `reason` carries the audit
880
+ * category ('guard_exception', 'content_filter', 'format_check', etc.).
881
+ */
882
+ reason?: string;
858
883
  }
859
884
  declare class FixApplier {
860
885
  private readonly _config;
@@ -1006,6 +1031,33 @@ declare class FixLoader {
1006
1031
  * Port of Python SDK's runtime/interceptors.py adapted for Node.js.
1007
1032
  */
1008
1033
 
1034
+ /**
1035
+ * Thrown by the fix interceptor when a guard fix returns `passed: false`.
1036
+ *
1037
+ * PR-4+5 review B2 (2026-05-25): pre-fix, `applyGuardFix` returned
1038
+ * `passed:false` correctly but no caller read `passed` — the provider
1039
+ * patcher consumed `result.messages` / `result.params` and proceeded to the
1040
+ * LLM with the attacker payload anyway. The `fail-CLOSED` was advisory only.
1041
+ *
1042
+ * Now the interceptor THROWS this error on both pre-call and post-call
1043
+ * guard rejection. The provider patcher's surrounding span.startSpan
1044
+ * already catches and records exceptions, so the customer sees a
1045
+ * `GuardRejectedError` propagated out of their `openai.chat.completions.create`
1046
+ * call — the LLM is NEVER invoked.
1047
+ *
1048
+ * Customers who want to handle rejection gracefully can:
1049
+ * try { await openai.chat.completions.create({ ... }); }
1050
+ * catch (e) {
1051
+ * if (e instanceof GuardRejectedError) { ... fallback ... }
1052
+ * else throw e;
1053
+ * }
1054
+ */
1055
+ declare class GuardRejectedError extends Error {
1056
+ readonly guardId: string;
1057
+ readonly reason: string;
1058
+ readonly phase: 'pre_call' | 'post_call';
1059
+ constructor(guardId: string, reason: string, phase: 'pre_call' | 'post_call');
1060
+ }
1009
1061
  interface InterceptContext {
1010
1062
  /** Type of operation: "llm_call", "tool_call", "agent_delegate" */
1011
1063
  operationType: string;
@@ -1163,4 +1215,142 @@ declare function initFixRuntime(config: FixRuntimeConfig): FixRuntime;
1163
1215
  */
1164
1216
  declare function shutdownFixRuntime(): void;
1165
1217
 
1166
- export { type ActiveFix, type AgentContext, type AgentOptions, AgentRole, type FixRuntimeConfig, MessageType, type RisicareConfig, SemanticPhase, type SessionContext, type SessionOptions, Span, SpanKind, type SpanOptions, SpanStatus, type StartSpanOptions, type TraceContext, type TracedStreamOptions, Tracer, agent, disable, enable, extractTraceContext, flush, getCurrentAgent, getCurrentAgentId, getCurrentContext, getCurrentPhase, getCurrentSession, getCurrentSessionId, getCurrentSpan, getCurrentSpanId, getCurrentTraceId, getFixRuntime, getMetrics, getSpanById, getTraceContent, getTraceContext, getTracer, init, initFixRuntime, injectTraceContext, isEnabled, isProviderInstrumentationSuppressed, registerSpan, reportError, score, session, shutdown, shutdownFixRuntime, suppressProviderInstrumentation, traceAct, traceCoordinate, traceDecide, traceDelegate, traceMessage, traceObserve, traceThink, tracedStream, unregisterSpan, withAgent, withPhase, withSession };
1218
+ /**
1219
+ * Webhook signature verification helpers (CON-195 / B-7, F-34).
1220
+ *
1221
+ * Customers receive Risicare webhooks at endpoints they configure. Each
1222
+ * delivery is signed by the sender (`packages/workers/src/workers/
1223
+ * webhook_dispatch.py`) with HMAC-SHA256 over `<timestamp>.<payload_bytes>`
1224
+ * using the per-webhook shared secret. The signature is delivered in the
1225
+ * `X-Risicare-Signature` header in Stripe-style format `t=<unix>,v1=<hex>`,
1226
+ * and the timestamp is also exposed verbatim as `X-Risicare-Timestamp`.
1227
+ *
1228
+ * This module is the TypeScript port of `risicare-sdk/src/risicare/
1229
+ * webhooks.py`. It enforces THREE checks (all must pass):
1230
+ *
1231
+ * 1. Header parsing — both headers must be present and well-formed.
1232
+ * 2. Time skew — `Math.abs(now - timestamp) <= toleranceS` (default
1233
+ * 5 minutes). This is what makes captured signed payloads
1234
+ * non-replayable past the tolerance window.
1235
+ * 3. HMAC equality — constant-time compare against a fresh signature
1236
+ * computed from the secret + the SAME timestamp + the raw body.
1237
+ *
1238
+ * Example (Express/Node receiver):
1239
+ *
1240
+ * import express from 'express';
1241
+ * import { verifyWebhookSignature, WebhookVerificationError } from 'risicare';
1242
+ *
1243
+ * const app = express();
1244
+ * // IMPORTANT: use raw body, not parsed JSON — the signature is
1245
+ * // over the EXACT bytes received; JSON re-serialization changes
1246
+ * // key ordering / whitespace and the signature will not match.
1247
+ * app.post('/risicare-webhook', express.raw({ type: '*\/*' }), (req, res) => {
1248
+ * try {
1249
+ * verifyWebhookSignature(req.body, req.headers, YOUR_WEBHOOK_SECRET);
1250
+ * } catch (e) {
1251
+ * if (e instanceof WebhookVerificationError) {
1252
+ * return res.status(401).send(e.message);
1253
+ * }
1254
+ * throw e;
1255
+ * }
1256
+ * // ... process the verified event ...
1257
+ * res.status(200).end();
1258
+ * });
1259
+ *
1260
+ * The helper is dependency-light (Node `crypto` stdlib only) so customers
1261
+ * can use it without pulling in the rest of the SDK if they only need
1262
+ * verification.
1263
+ *
1264
+ * Edge runtime note: this verifier is synchronous and uses Node's
1265
+ * `crypto.timingSafeEqual` + `crypto.createHmac`. It will not run in
1266
+ * Cloudflare Workers / Vercel Edge / Deno Deploy as-is. An async Web
1267
+ * Crypto variant can be added if customers request it.
1268
+ */
1269
+ /**
1270
+ * Default skew window (seconds). 5 minutes matches Stripe / GitHub /
1271
+ * common industry practice. Customers can override per-call if their
1272
+ * clock infrastructure warrants a tighter or looser bound.
1273
+ *
1274
+ * Mirrors `DEFAULT_TIMESTAMP_TOLERANCE_S` in the Python SDK.
1275
+ */
1276
+ declare const DEFAULT_TIMESTAMP_TOLERANCE_S = 300;
1277
+ /**
1278
+ * Raised when a webhook delivery fails any verification check.
1279
+ *
1280
+ * Customers should catch this specifically rather than a generic `Error`
1281
+ * so verification failures are not conflated with other input problems
1282
+ * (e.g. body-parsing errors at the framework layer).
1283
+ *
1284
+ * The `message` is safe to log — it never includes the secret, the
1285
+ * expected signature, or the computed signature.
1286
+ */
1287
+ declare class WebhookVerificationError extends Error {
1288
+ constructor(message: string);
1289
+ }
1290
+ /**
1291
+ * Options for `verifyWebhookSignature`. All fields are optional.
1292
+ */
1293
+ interface VerifyWebhookOptions {
1294
+ /**
1295
+ * Maximum clock-skew tolerance in seconds. Defaults to
1296
+ * `DEFAULT_TIMESTAMP_TOLERANCE_S` (300). Setting to 0 is supported
1297
+ * (strict same-second match) but discouraged in distributed
1298
+ * deployments.
1299
+ */
1300
+ toleranceS?: number;
1301
+ /**
1302
+ * Test hook — override "current time" in unix seconds.
1303
+ * Customers should not pass this.
1304
+ */
1305
+ _now?: number;
1306
+ }
1307
+ /**
1308
+ * Header-like inputs accepted by `verifyWebhookSignature`.
1309
+ *
1310
+ * Covers (a) Web API `Headers` (case-insensitive `.get`), (b) Node
1311
+ * `IncomingHttpHeaders` (plain object with lowercase keys, possibly
1312
+ * array-valued for multi-set headers), (c) `Map<string, string>`
1313
+ * (case-sensitive `.get`), and (d) plain `Record` (case-sensitive
1314
+ * property lookup, possibly array-valued).
1315
+ *
1316
+ * Lookup strategy: try the canonical mixed-case name first
1317
+ * (`X-Risicare-Signature`). If that returns undefined, fall back to the
1318
+ * lowercased form (`x-risicare-signature`). Mirrors the Python
1319
+ * `_get_header` helper.
1320
+ */
1321
+ type HeaderLookup = Headers | Map<string, string> | Record<string, string | string[] | undefined>;
1322
+ /**
1323
+ * Payload shapes accepted by `verifyWebhookSignature`.
1324
+ *
1325
+ * `Buffer extends Uint8Array` in Node, so callers passing `Buffer`
1326
+ * satisfy the `Uint8Array` arm. `ArrayBuffer` is explicitly accepted
1327
+ * for callers using Web-API request bodies. `string` is UTF-8 encoded
1328
+ * internally.
1329
+ *
1330
+ * Crucially, callers must pass the EXACT bytes received over the
1331
+ * wire. Parsing JSON and re-serializing changes byte order and
1332
+ * whitespace; the signature will not match.
1333
+ */
1334
+ type WebhookPayload = Uint8Array | ArrayBuffer | string;
1335
+ /**
1336
+ * Verify a Risicare webhook delivery. Throws `WebhookVerificationError`
1337
+ * on any failure; returns `undefined` on success.
1338
+ *
1339
+ * @param payload Raw request body bytes — the EXACT bytes received over
1340
+ * the wire. Re-serializing parsed JSON will change byte ordering and
1341
+ * break the signature.
1342
+ * @param headers Header lookup. Web `Headers`, `Map<string,string>`,
1343
+ * Node `IncomingHttpHeaders`, or plain `Record` all work. Lookup is
1344
+ * case-insensitive (canonical mixed-case tried first, then lowercase).
1345
+ * @param secret The shared secret configured on the Risicare webhook
1346
+ * record. Returned by `POST /v1/webhooks` once at create time.
1347
+ * @param opts Optional overrides — `toleranceS` (default 300) and
1348
+ * `_now` (test hook).
1349
+ *
1350
+ * @throws WebhookVerificationError on any of: missing headers, malformed
1351
+ * signature, timestamp outside tolerance, HMAC mismatch, or invalid
1352
+ * payload type.
1353
+ */
1354
+ declare function verifyWebhookSignature(payload: WebhookPayload, headers: HeaderLookup, secret: string, opts?: VerifyWebhookOptions): void;
1355
+
1356
+ export { type ActiveFix, type AgentContext, type AgentOptions, AgentRole, DEFAULT_TIMESTAMP_TOLERANCE_S, type FixRuntimeConfig, GuardRejectedError, type HeaderLookup, MessageType, type RisicareConfig, SemanticPhase, type SessionContext, type SessionOptions, Span, SpanKind, type SpanOptions, SpanStatus, type StartSpanOptions, type TraceContext, type TracedStreamOptions, Tracer, type VerifyWebhookOptions, type WebhookPayload, WebhookVerificationError, agent, disable, enable, extractTraceContext, flush, getCurrentAgent, getCurrentAgentId, getCurrentContext, getCurrentPhase, getCurrentSession, getCurrentSessionId, getCurrentSpan, getCurrentSpanId, getCurrentTraceId, getFixRuntime, getMetrics, getSpanById, getTraceContent, getTraceContext, getTracer, init, initFixRuntime, injectTraceContext, isEnabled, isProviderInstrumentationSuppressed, registerSpan, reportError, score, session, shutdown, shutdownFixRuntime, suppressProviderInstrumentation, traceAct, traceCoordinate, traceDecide, traceDelegate, traceMessage, traceObserve, traceThink, tracedStream, unregisterSpan, verifyWebhookSignature, withAgent, withPhase, withSession };
package/dist/index.d.ts CHANGED
@@ -371,7 +371,7 @@ declare function getMetrics(): {
371
371
  queueUtilization: number;
372
372
  };
373
373
  /**
374
- * Report a caught exception to the self-healing pipeline.
374
+ * Report a caught exception to the error diagnosis pipeline.
375
375
  *
376
376
  * Creates an error span that triggers diagnosis and fix generation.
377
377
  * Deduplicates identical errors within a 5-minute window (SHA256 fingerprint).
@@ -430,6 +430,17 @@ declare function withAgent<T>(options: AgentOptions, fn: () => T): T;
430
430
  * Wraps a function to execute within an agent context. All spans created
431
431
  * inside will be tagged with the agent's identity.
432
432
  *
433
+ * Two equivalent calling forms are supported:
434
+ *
435
+ * // 2-arg form
436
+ * const research = agent({ name: 'researcher' }, async (q) => { ... });
437
+ *
438
+ * // Curried form (decorator factory)
439
+ * const research = agent({ name: 'researcher' })(async (q) => { ... });
440
+ *
441
+ * Both return a wrapped function — call it to actually run the body inside
442
+ * the agent context.
443
+ *
433
444
  * @example
434
445
  * const research = agent({ name: 'researcher', role: 'worker' }, async (query: string) => {
435
446
  * const result = await openai.chat.completions.create({ ... });
@@ -439,10 +450,8 @@ declare function withAgent<T>(options: AgentOptions, fn: () => T): T;
439
450
  * const answer = await research('What is quantum computing?');
440
451
  */
441
452
 
442
- /**
443
- * Wrap a function with agent context and an automatic span.
444
- */
445
453
  declare function agent<TArgs extends unknown[], TReturn>(options: AgentOptions, fn: (...args: TArgs) => TReturn): (...args: TArgs) => TReturn;
454
+ declare function agent(options: AgentOptions): <TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => TReturn) => (...args: TArgs) => TReturn;
446
455
 
447
456
  /**
448
457
  * Session context — groups multiple traces from the same user interaction.
@@ -483,10 +492,19 @@ declare function withSession<T>(options: SessionOptions, fn: () => T): T;
483
492
  /**
484
493
  * Wrap a function with session context.
485
494
  *
495
+ * Two equivalent calling forms are supported (F-54 ergonomics):
496
+ *
497
+ * // 2-arg form
498
+ * const handle = session({ sessionId: 's1' }, async (req) => { ... });
499
+ *
500
+ * // Curried form (decorator factory)
501
+ * const handle = session({ sessionId: 's1' })(async (req) => { ... });
502
+ *
486
503
  * @param optionsOrResolver - Static session options, or a function that derives them from args
487
- * @param fn - The function to wrap
504
+ * @param fn - The function to wrap. If omitted, returns a decorator factory.
488
505
  */
489
506
  declare function session<TArgs extends unknown[], TReturn>(optionsOrResolver: SessionOptions | ((...args: TArgs) => SessionOptions), fn: (...args: TArgs) => TReturn): (...args: TArgs) => TReturn;
507
+ declare function session<TArgs extends unknown[]>(optionsOrResolver: SessionOptions | ((...args: TArgs) => SessionOptions)): <TR>(fn: (...args: TArgs) => TR) => (...args: TArgs) => TR;
490
508
 
491
509
  /**
492
510
  * Phase decorators — decision phase tracking (Tier 4).
@@ -855,6 +873,13 @@ interface ApplyResult {
855
873
  fixType?: string;
856
874
  modifications: Record<string, unknown>;
857
875
  error?: string;
876
+ /**
877
+ * Guard-only: human-readable reason a guard failed (passed=false). Used
878
+ * by GuardRejectedError to surface an actionable message to the customer.
879
+ * `error` carries the raw exception text; `reason` carries the audit
880
+ * category ('guard_exception', 'content_filter', 'format_check', etc.).
881
+ */
882
+ reason?: string;
858
883
  }
859
884
  declare class FixApplier {
860
885
  private readonly _config;
@@ -1006,6 +1031,33 @@ declare class FixLoader {
1006
1031
  * Port of Python SDK's runtime/interceptors.py adapted for Node.js.
1007
1032
  */
1008
1033
 
1034
+ /**
1035
+ * Thrown by the fix interceptor when a guard fix returns `passed: false`.
1036
+ *
1037
+ * PR-4+5 review B2 (2026-05-25): pre-fix, `applyGuardFix` returned
1038
+ * `passed:false` correctly but no caller read `passed` — the provider
1039
+ * patcher consumed `result.messages` / `result.params` and proceeded to the
1040
+ * LLM with the attacker payload anyway. The `fail-CLOSED` was advisory only.
1041
+ *
1042
+ * Now the interceptor THROWS this error on both pre-call and post-call
1043
+ * guard rejection. The provider patcher's surrounding span.startSpan
1044
+ * already catches and records exceptions, so the customer sees a
1045
+ * `GuardRejectedError` propagated out of their `openai.chat.completions.create`
1046
+ * call — the LLM is NEVER invoked.
1047
+ *
1048
+ * Customers who want to handle rejection gracefully can:
1049
+ * try { await openai.chat.completions.create({ ... }); }
1050
+ * catch (e) {
1051
+ * if (e instanceof GuardRejectedError) { ... fallback ... }
1052
+ * else throw e;
1053
+ * }
1054
+ */
1055
+ declare class GuardRejectedError extends Error {
1056
+ readonly guardId: string;
1057
+ readonly reason: string;
1058
+ readonly phase: 'pre_call' | 'post_call';
1059
+ constructor(guardId: string, reason: string, phase: 'pre_call' | 'post_call');
1060
+ }
1009
1061
  interface InterceptContext {
1010
1062
  /** Type of operation: "llm_call", "tool_call", "agent_delegate" */
1011
1063
  operationType: string;
@@ -1163,4 +1215,142 @@ declare function initFixRuntime(config: FixRuntimeConfig): FixRuntime;
1163
1215
  */
1164
1216
  declare function shutdownFixRuntime(): void;
1165
1217
 
1166
- export { type ActiveFix, type AgentContext, type AgentOptions, AgentRole, type FixRuntimeConfig, MessageType, type RisicareConfig, SemanticPhase, type SessionContext, type SessionOptions, Span, SpanKind, type SpanOptions, SpanStatus, type StartSpanOptions, type TraceContext, type TracedStreamOptions, Tracer, agent, disable, enable, extractTraceContext, flush, getCurrentAgent, getCurrentAgentId, getCurrentContext, getCurrentPhase, getCurrentSession, getCurrentSessionId, getCurrentSpan, getCurrentSpanId, getCurrentTraceId, getFixRuntime, getMetrics, getSpanById, getTraceContent, getTraceContext, getTracer, init, initFixRuntime, injectTraceContext, isEnabled, isProviderInstrumentationSuppressed, registerSpan, reportError, score, session, shutdown, shutdownFixRuntime, suppressProviderInstrumentation, traceAct, traceCoordinate, traceDecide, traceDelegate, traceMessage, traceObserve, traceThink, tracedStream, unregisterSpan, withAgent, withPhase, withSession };
1218
+ /**
1219
+ * Webhook signature verification helpers (CON-195 / B-7, F-34).
1220
+ *
1221
+ * Customers receive Risicare webhooks at endpoints they configure. Each
1222
+ * delivery is signed by the sender (`packages/workers/src/workers/
1223
+ * webhook_dispatch.py`) with HMAC-SHA256 over `<timestamp>.<payload_bytes>`
1224
+ * using the per-webhook shared secret. The signature is delivered in the
1225
+ * `X-Risicare-Signature` header in Stripe-style format `t=<unix>,v1=<hex>`,
1226
+ * and the timestamp is also exposed verbatim as `X-Risicare-Timestamp`.
1227
+ *
1228
+ * This module is the TypeScript port of `risicare-sdk/src/risicare/
1229
+ * webhooks.py`. It enforces THREE checks (all must pass):
1230
+ *
1231
+ * 1. Header parsing — both headers must be present and well-formed.
1232
+ * 2. Time skew — `Math.abs(now - timestamp) <= toleranceS` (default
1233
+ * 5 minutes). This is what makes captured signed payloads
1234
+ * non-replayable past the tolerance window.
1235
+ * 3. HMAC equality — constant-time compare against a fresh signature
1236
+ * computed from the secret + the SAME timestamp + the raw body.
1237
+ *
1238
+ * Example (Express/Node receiver):
1239
+ *
1240
+ * import express from 'express';
1241
+ * import { verifyWebhookSignature, WebhookVerificationError } from 'risicare';
1242
+ *
1243
+ * const app = express();
1244
+ * // IMPORTANT: use raw body, not parsed JSON — the signature is
1245
+ * // over the EXACT bytes received; JSON re-serialization changes
1246
+ * // key ordering / whitespace and the signature will not match.
1247
+ * app.post('/risicare-webhook', express.raw({ type: '*\/*' }), (req, res) => {
1248
+ * try {
1249
+ * verifyWebhookSignature(req.body, req.headers, YOUR_WEBHOOK_SECRET);
1250
+ * } catch (e) {
1251
+ * if (e instanceof WebhookVerificationError) {
1252
+ * return res.status(401).send(e.message);
1253
+ * }
1254
+ * throw e;
1255
+ * }
1256
+ * // ... process the verified event ...
1257
+ * res.status(200).end();
1258
+ * });
1259
+ *
1260
+ * The helper is dependency-light (Node `crypto` stdlib only) so customers
1261
+ * can use it without pulling in the rest of the SDK if they only need
1262
+ * verification.
1263
+ *
1264
+ * Edge runtime note: this verifier is synchronous and uses Node's
1265
+ * `crypto.timingSafeEqual` + `crypto.createHmac`. It will not run in
1266
+ * Cloudflare Workers / Vercel Edge / Deno Deploy as-is. An async Web
1267
+ * Crypto variant can be added if customers request it.
1268
+ */
1269
+ /**
1270
+ * Default skew window (seconds). 5 minutes matches Stripe / GitHub /
1271
+ * common industry practice. Customers can override per-call if their
1272
+ * clock infrastructure warrants a tighter or looser bound.
1273
+ *
1274
+ * Mirrors `DEFAULT_TIMESTAMP_TOLERANCE_S` in the Python SDK.
1275
+ */
1276
+ declare const DEFAULT_TIMESTAMP_TOLERANCE_S = 300;
1277
+ /**
1278
+ * Raised when a webhook delivery fails any verification check.
1279
+ *
1280
+ * Customers should catch this specifically rather than a generic `Error`
1281
+ * so verification failures are not conflated with other input problems
1282
+ * (e.g. body-parsing errors at the framework layer).
1283
+ *
1284
+ * The `message` is safe to log — it never includes the secret, the
1285
+ * expected signature, or the computed signature.
1286
+ */
1287
+ declare class WebhookVerificationError extends Error {
1288
+ constructor(message: string);
1289
+ }
1290
+ /**
1291
+ * Options for `verifyWebhookSignature`. All fields are optional.
1292
+ */
1293
+ interface VerifyWebhookOptions {
1294
+ /**
1295
+ * Maximum clock-skew tolerance in seconds. Defaults to
1296
+ * `DEFAULT_TIMESTAMP_TOLERANCE_S` (300). Setting to 0 is supported
1297
+ * (strict same-second match) but discouraged in distributed
1298
+ * deployments.
1299
+ */
1300
+ toleranceS?: number;
1301
+ /**
1302
+ * Test hook — override "current time" in unix seconds.
1303
+ * Customers should not pass this.
1304
+ */
1305
+ _now?: number;
1306
+ }
1307
+ /**
1308
+ * Header-like inputs accepted by `verifyWebhookSignature`.
1309
+ *
1310
+ * Covers (a) Web API `Headers` (case-insensitive `.get`), (b) Node
1311
+ * `IncomingHttpHeaders` (plain object with lowercase keys, possibly
1312
+ * array-valued for multi-set headers), (c) `Map<string, string>`
1313
+ * (case-sensitive `.get`), and (d) plain `Record` (case-sensitive
1314
+ * property lookup, possibly array-valued).
1315
+ *
1316
+ * Lookup strategy: try the canonical mixed-case name first
1317
+ * (`X-Risicare-Signature`). If that returns undefined, fall back to the
1318
+ * lowercased form (`x-risicare-signature`). Mirrors the Python
1319
+ * `_get_header` helper.
1320
+ */
1321
+ type HeaderLookup = Headers | Map<string, string> | Record<string, string | string[] | undefined>;
1322
+ /**
1323
+ * Payload shapes accepted by `verifyWebhookSignature`.
1324
+ *
1325
+ * `Buffer extends Uint8Array` in Node, so callers passing `Buffer`
1326
+ * satisfy the `Uint8Array` arm. `ArrayBuffer` is explicitly accepted
1327
+ * for callers using Web-API request bodies. `string` is UTF-8 encoded
1328
+ * internally.
1329
+ *
1330
+ * Crucially, callers must pass the EXACT bytes received over the
1331
+ * wire. Parsing JSON and re-serializing changes byte order and
1332
+ * whitespace; the signature will not match.
1333
+ */
1334
+ type WebhookPayload = Uint8Array | ArrayBuffer | string;
1335
+ /**
1336
+ * Verify a Risicare webhook delivery. Throws `WebhookVerificationError`
1337
+ * on any failure; returns `undefined` on success.
1338
+ *
1339
+ * @param payload Raw request body bytes — the EXACT bytes received over
1340
+ * the wire. Re-serializing parsed JSON will change byte ordering and
1341
+ * break the signature.
1342
+ * @param headers Header lookup. Web `Headers`, `Map<string,string>`,
1343
+ * Node `IncomingHttpHeaders`, or plain `Record` all work. Lookup is
1344
+ * case-insensitive (canonical mixed-case tried first, then lowercase).
1345
+ * @param secret The shared secret configured on the Risicare webhook
1346
+ * record. Returned by `POST /v1/webhooks` once at create time.
1347
+ * @param opts Optional overrides — `toleranceS` (default 300) and
1348
+ * `_now` (test hook).
1349
+ *
1350
+ * @throws WebhookVerificationError on any of: missing headers, malformed
1351
+ * signature, timestamp outside tolerance, HMAC mismatch, or invalid
1352
+ * payload type.
1353
+ */
1354
+ declare function verifyWebhookSignature(payload: WebhookPayload, headers: HeaderLookup, secret: string, opts?: VerifyWebhookOptions): void;
1355
+
1356
+ export { type ActiveFix, type AgentContext, type AgentOptions, AgentRole, DEFAULT_TIMESTAMP_TOLERANCE_S, type FixRuntimeConfig, GuardRejectedError, type HeaderLookup, MessageType, type RisicareConfig, SemanticPhase, type SessionContext, type SessionOptions, Span, SpanKind, type SpanOptions, SpanStatus, type StartSpanOptions, type TraceContext, type TracedStreamOptions, Tracer, type VerifyWebhookOptions, type WebhookPayload, WebhookVerificationError, agent, disable, enable, extractTraceContext, flush, getCurrentAgent, getCurrentAgentId, getCurrentContext, getCurrentPhase, getCurrentSession, getCurrentSessionId, getCurrentSpan, getCurrentSpanId, getCurrentTraceId, getFixRuntime, getMetrics, getSpanById, getTraceContent, getTraceContext, getTracer, init, initFixRuntime, injectTraceContext, isEnabled, isProviderInstrumentationSuppressed, registerSpan, reportError, score, session, shutdown, shutdownFixRuntime, suppressProviderInstrumentation, traceAct, traceCoordinate, traceDecide, traceDelegate, traceMessage, traceObserve, traceThink, tracedStream, unregisterSpan, verifyWebhookSignature, withAgent, withPhase, withSession };