risicare 0.3.0 → 0.4.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.
Files changed (42) hide show
  1. package/README.md +26 -10
  2. package/dist/frameworks/instructor.cjs.map +1 -1
  3. package/dist/frameworks/instructor.js.map +1 -1
  4. package/dist/frameworks/langchain.cjs.map +1 -1
  5. package/dist/frameworks/langchain.js.map +1 -1
  6. package/dist/frameworks/langgraph.cjs.map +1 -1
  7. package/dist/frameworks/langgraph.js.map +1 -1
  8. package/dist/frameworks/llamaindex.cjs.map +1 -1
  9. package/dist/frameworks/llamaindex.js.map +1 -1
  10. package/dist/index.cjs +212 -8
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +162 -6
  13. package/dist/index.d.ts +162 -6
  14. package/dist/index.js +209 -8
  15. package/dist/index.js.map +1 -1
  16. package/dist/providers/anthropic/index.cjs.map +1 -1
  17. package/dist/providers/anthropic/index.js.map +1 -1
  18. package/dist/providers/bedrock/index.cjs.map +1 -1
  19. package/dist/providers/bedrock/index.js.map +1 -1
  20. package/dist/providers/cerebras/index.cjs.map +1 -1
  21. package/dist/providers/cerebras/index.js.map +1 -1
  22. package/dist/providers/cohere/index.cjs.map +1 -1
  23. package/dist/providers/cohere/index.js.map +1 -1
  24. package/dist/providers/google/index.cjs.map +1 -1
  25. package/dist/providers/google/index.js.map +1 -1
  26. package/dist/providers/groq/index.cjs.map +1 -1
  27. package/dist/providers/groq/index.js.map +1 -1
  28. package/dist/providers/huggingface/index.cjs.map +1 -1
  29. package/dist/providers/huggingface/index.js.map +1 -1
  30. package/dist/providers/mistral/index.cjs.map +1 -1
  31. package/dist/providers/mistral/index.js.map +1 -1
  32. package/dist/providers/ollama/index.cjs.map +1 -1
  33. package/dist/providers/ollama/index.js.map +1 -1
  34. package/dist/providers/openai/index.cjs +16 -1327
  35. package/dist/providers/openai/index.cjs.map +1 -1
  36. package/dist/providers/openai/index.js +16 -1343
  37. package/dist/providers/openai/index.js.map +1 -1
  38. package/dist/providers/together/index.cjs.map +1 -1
  39. package/dist/providers/together/index.js.map +1 -1
  40. package/dist/providers/vercel-ai/index.cjs.map +1 -1
  41. package/dist/providers/vercel-ai/index.js.map +1 -1
  42. package/package.json +5 -4
package/dist/index.cjs CHANGED
@@ -1423,12 +1423,14 @@ var init_runtime = __esm({
1423
1423
  var src_exports = {};
1424
1424
  __export(src_exports, {
1425
1425
  AgentRole: () => AgentRole,
1426
+ DEFAULT_TIMESTAMP_TOLERANCE_S: () => DEFAULT_TIMESTAMP_TOLERANCE_S,
1426
1427
  MessageType: () => MessageType,
1427
1428
  RisicareCallbackHandler: () => RisicareCallbackHandler,
1428
1429
  RisicareLlamaIndexHandler: () => RisicareLlamaIndexHandler,
1429
1430
  SemanticPhase: () => SemanticPhase,
1430
1431
  SpanKind: () => SpanKind,
1431
1432
  SpanStatus: () => SpanStatus,
1433
+ WebhookVerificationError: () => WebhookVerificationError,
1432
1434
  agent: () => agent,
1433
1435
  disable: () => disable,
1434
1436
  enable: () => enable,
@@ -1472,6 +1474,7 @@ __export(src_exports, {
1472
1474
  traceThink: () => traceThink,
1473
1475
  tracedStream: () => tracedStream,
1474
1476
  unregisterSpan: () => unregisterSpan,
1477
+ verifyWebhookSignature: () => verifyWebhookSignature,
1475
1478
  withAgent: () => withAgent,
1476
1479
  withPhase: () => withPhase,
1477
1480
  withSession: () => withSession
@@ -2104,7 +2107,14 @@ var BatchSpanProcessor = class _BatchSpanProcessor {
2104
2107
  failedExports = 0;
2105
2108
  constructor(options) {
2106
2109
  this._exporters = [...options.exporters];
2107
- this._batchSize = options.batchSize ?? 100;
2110
+ const requestedBatchSize = options.batchSize ?? 100;
2111
+ const clampedBatchSize = Math.max(1, Math.min(requestedBatchSize, 1e4));
2112
+ if (clampedBatchSize !== requestedBatchSize) {
2113
+ warn(
2114
+ `batchSize=${requestedBatchSize} is outside the allowed range [1, 10000]; clamping to ${clampedBatchSize}`
2115
+ );
2116
+ }
2117
+ this._batchSize = clampedBatchSize;
2108
2118
  this._batchTimeoutMs = options.batchTimeoutMs ?? 1e3;
2109
2119
  this._maxQueueSize = options.maxQueueSize ?? 1e4;
2110
2120
  this._debug = options.debug ?? false;
@@ -2245,11 +2255,15 @@ var HttpExporter = class {
2245
2255
  _timeoutMs;
2246
2256
  _maxRetries;
2247
2257
  _compress;
2248
- // Circuit breaker
2258
+ // Circuit breaker (CON-201 / B-16). Threshold and cooldown sized for
2259
+ // a "30-second prod restart" scenario: with default 1s batch flush a
2260
+ // 5-failure threshold opens the circuit ~5s into an outage and the 60s
2261
+ // cooldown gives the gateway time to come back before the half-open
2262
+ // probe fires. Lower numbers (was 3@30s) tripped on transient blips.
2249
2263
  _consecutiveFailures = 0;
2250
2264
  _circuitOpenUntil = 0;
2251
- _circuitBreakerThreshold = 3;
2252
- _circuitBreakerCooldownMs = 3e4;
2265
+ _circuitBreakerThreshold = 5;
2266
+ _circuitBreakerCooldownMs = 6e4;
2253
2267
  constructor(options) {
2254
2268
  this._endpoint = options.endpoint.replace(/\/+$/, "");
2255
2269
  this._apiKey = options.apiKey;
@@ -2410,7 +2424,18 @@ var RisicareClient = class {
2410
2424
  enabled: true,
2411
2425
  debug: this.config.debug
2412
2426
  });
2413
- } catch {
2427
+ } catch (e) {
2428
+ const errName = e instanceof Error ? e.name : "Error";
2429
+ const errMsg = e instanceof Error ? e.message : String(e);
2430
+ try {
2431
+ console.warn(
2432
+ `[risicare] FixRuntime initialization failed \u2014 auto-fix is OFFLINE for this process. endpoint=${this.config.endpoint} error=${errName}: ${errMsg}. Tracing + reporting still work; only fix application is disabled. Pass debug:true in init() options for the full traceback.`
2433
+ );
2434
+ } catch {
2435
+ }
2436
+ if (this.config.debug) {
2437
+ debug(`FixRuntime init traceback: ${e instanceof Error && e.stack ? e.stack : String(e)}`);
2438
+ }
2414
2439
  }
2415
2440
  }
2416
2441
  this._registerShutdownHooks();
@@ -2562,7 +2587,7 @@ function reportError(error, options) {
2562
2587
  }
2563
2588
  function score(traceId, name, value, options) {
2564
2589
  try {
2565
- if (typeof value !== "number" || value < 0 || value > 1) {
2590
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 1) {
2566
2591
  debug(`score: value must be in [0.0, 1.0], got ${value}. Score not sent.`);
2567
2592
  return;
2568
2593
  }
@@ -2612,7 +2637,7 @@ function withAgent(options, fn) {
2612
2637
  }
2613
2638
 
2614
2639
  // src/decorators/agent.ts
2615
- function agent(options, fn) {
2640
+ function _wrapAgent(options, fn) {
2616
2641
  const spanName = `agent:${options.name ?? "agent"}`;
2617
2642
  return (...args) => {
2618
2643
  const tracer = getTracer2();
@@ -2626,6 +2651,12 @@ function agent(options, fn) {
2626
2651
  });
2627
2652
  };
2628
2653
  }
2654
+ function agent(options, fn) {
2655
+ if (fn === void 0) {
2656
+ return (realFn) => _wrapAgent(options, realFn);
2657
+ }
2658
+ return _wrapAgent(options, fn);
2659
+ }
2629
2660
 
2630
2661
  // src/context/session.ts
2631
2662
  function withSession(options, fn) {
@@ -2640,12 +2671,18 @@ function withSession(options, fn) {
2640
2671
  }
2641
2672
 
2642
2673
  // src/decorators/session.ts
2643
- function session(optionsOrResolver, fn) {
2674
+ function _wrapSession(optionsOrResolver, fn) {
2644
2675
  return (...args) => {
2645
2676
  const options = typeof optionsOrResolver === "function" ? optionsOrResolver(...args) : optionsOrResolver;
2646
2677
  return withSession(options, () => fn(...args));
2647
2678
  };
2648
2679
  }
2680
+ function session(optionsOrResolver, fn) {
2681
+ if (fn === void 0) {
2682
+ return (realFn) => _wrapSession(optionsOrResolver, realFn);
2683
+ }
2684
+ return _wrapSession(optionsOrResolver, fn);
2685
+ }
2649
2686
 
2650
2687
  // src/context/phase.ts
2651
2688
  function withPhase(phase, fn) {
@@ -3267,15 +3304,181 @@ var RisicareLlamaIndexHandler = class {
3267
3304
 
3268
3305
  // src/index.ts
3269
3306
  init_runtime();
3307
+
3308
+ // src/webhooks.ts
3309
+ var import_node_crypto3 = require("crypto");
3310
+ var import_node_buffer = require("buffer");
3311
+ var DEFAULT_TIMESTAMP_TOLERANCE_S = 300;
3312
+ var SIGNATURE_HEADER = "X-Risicare-Signature";
3313
+ var TIMESTAMP_HEADER = "X-Risicare-Timestamp";
3314
+ var SUPPORTED_SCHEMES = ["v1"];
3315
+ var HEX_SHA256_RE = /^[0-9a-f]{64}$/;
3316
+ var WebhookVerificationError = class _WebhookVerificationError extends Error {
3317
+ constructor(message) {
3318
+ super(message);
3319
+ this.name = "WebhookVerificationError";
3320
+ Object.setPrototypeOf(this, _WebhookVerificationError.prototype);
3321
+ }
3322
+ };
3323
+ function getHeader(headers, name) {
3324
+ const lower = name.toLowerCase();
3325
+ if (typeof headers.get === "function") {
3326
+ const accessor = headers;
3327
+ const v = accessor.get(name) ?? accessor.get(lower);
3328
+ return v ?? void 0;
3329
+ }
3330
+ const dict = headers;
3331
+ const raw = dict[name] ?? dict[lower];
3332
+ if (raw === void 0) {
3333
+ return void 0;
3334
+ }
3335
+ if (Array.isArray(raw)) {
3336
+ return raw[0];
3337
+ }
3338
+ return raw;
3339
+ }
3340
+ function coercePayload(payload) {
3341
+ if (typeof payload === "string") {
3342
+ return import_node_buffer.Buffer.from(payload, "utf-8");
3343
+ }
3344
+ if (payload instanceof Uint8Array) {
3345
+ return import_node_buffer.Buffer.from(
3346
+ payload.buffer,
3347
+ payload.byteOffset,
3348
+ payload.byteLength
3349
+ );
3350
+ }
3351
+ if (payload instanceof ArrayBuffer) {
3352
+ return import_node_buffer.Buffer.from(payload);
3353
+ }
3354
+ throw new WebhookVerificationError(
3355
+ `payload must be Uint8Array, ArrayBuffer, Buffer, or string, got ${typeof payload}`
3356
+ );
3357
+ }
3358
+ function parseSignatureHeader(raw) {
3359
+ const parts = /* @__PURE__ */ Object.create(null);
3360
+ for (const rawSegment of raw.split(",")) {
3361
+ const segment = rawSegment.trim();
3362
+ if (segment === "") {
3363
+ continue;
3364
+ }
3365
+ const eqIdx = segment.indexOf("=");
3366
+ if (eqIdx === -1) {
3367
+ throw new WebhookVerificationError(
3368
+ `Malformed segment in ${SIGNATURE_HEADER}: ${JSON.stringify(segment)}`
3369
+ );
3370
+ }
3371
+ const key = segment.slice(0, eqIdx).trim();
3372
+ const value = segment.slice(eqIdx + 1).trim();
3373
+ parts[key] = value;
3374
+ }
3375
+ if (!("t" in parts)) {
3376
+ throw new WebhookVerificationError(
3377
+ `Missing \`t=\` (timestamp) in ${SIGNATURE_HEADER}`
3378
+ );
3379
+ }
3380
+ let scheme;
3381
+ for (const candidate of SUPPORTED_SCHEMES) {
3382
+ if (candidate in parts) {
3383
+ scheme = candidate;
3384
+ break;
3385
+ }
3386
+ }
3387
+ if (scheme === void 0) {
3388
+ const keys = Object.keys(parts).sort();
3389
+ throw new WebhookVerificationError(
3390
+ `No supported signature scheme in ${SIGNATURE_HEADER}; expected one of (${SUPPORTED_SCHEMES.map((s) => `'${s}'`).join(", ")}), got keys [${keys.map((k) => `'${k}'`).join(", ")}]`
3391
+ );
3392
+ }
3393
+ const tRaw = parts["t"];
3394
+ if (!/^-?\d+$/.test(tRaw)) {
3395
+ throw new WebhookVerificationError(
3396
+ `Non-integer timestamp in ${SIGNATURE_HEADER}: ${JSON.stringify(tRaw)}`
3397
+ );
3398
+ }
3399
+ const ts = parseInt(tRaw, 10);
3400
+ if (!Number.isFinite(ts)) {
3401
+ throw new WebhookVerificationError(
3402
+ `Non-integer timestamp in ${SIGNATURE_HEADER}: ${JSON.stringify(tRaw)}`
3403
+ );
3404
+ }
3405
+ const sigHex = parts[scheme];
3406
+ if (sigHex === void 0 || sigHex === "") {
3407
+ throw new WebhookVerificationError(
3408
+ `Empty ${scheme}= value in ${SIGNATURE_HEADER}`
3409
+ );
3410
+ }
3411
+ return [ts, sigHex];
3412
+ }
3413
+ function safeHexEqual(computed, expected) {
3414
+ if (!HEX_SHA256_RE.test(expected)) {
3415
+ return false;
3416
+ }
3417
+ const a = import_node_buffer.Buffer.from(computed, "hex");
3418
+ const b = import_node_buffer.Buffer.from(expected, "hex");
3419
+ if (a.length !== b.length) {
3420
+ return false;
3421
+ }
3422
+ return (0, import_node_crypto3.timingSafeEqual)(a, b);
3423
+ }
3424
+ function verifyWebhookSignature(payload, headers, secret, opts = {}) {
3425
+ const toleranceS = opts.toleranceS ?? DEFAULT_TIMESTAMP_TOLERANCE_S;
3426
+ const payloadBytes = coercePayload(payload);
3427
+ const sigHeader = getHeader(headers, SIGNATURE_HEADER);
3428
+ if (sigHeader === void 0 || sigHeader === "") {
3429
+ throw new WebhookVerificationError(
3430
+ `Missing ${SIGNATURE_HEADER} header`
3431
+ );
3432
+ }
3433
+ const tsHeader = getHeader(headers, TIMESTAMP_HEADER);
3434
+ if (tsHeader === void 0 || tsHeader === "") {
3435
+ throw new WebhookVerificationError(
3436
+ `Missing ${TIMESTAMP_HEADER} header`
3437
+ );
3438
+ }
3439
+ const [tsInSig, expectedHex] = parseSignatureHeader(sigHeader);
3440
+ if (!/^-?\d+$/.test(tsHeader)) {
3441
+ throw new WebhookVerificationError(
3442
+ `Non-integer ${TIMESTAMP_HEADER}: ${JSON.stringify(tsHeader)}`
3443
+ );
3444
+ }
3445
+ const tsStandalone = parseInt(tsHeader, 10);
3446
+ if (!Number.isFinite(tsStandalone)) {
3447
+ throw new WebhookVerificationError(
3448
+ `Non-integer ${TIMESTAMP_HEADER}: ${JSON.stringify(tsHeader)}`
3449
+ );
3450
+ }
3451
+ if (tsStandalone !== tsInSig) {
3452
+ throw new WebhookVerificationError(
3453
+ `Timestamp mismatch: ${TIMESTAMP_HEADER}=${tsStandalone}, signature t=${tsInSig}`
3454
+ );
3455
+ }
3456
+ const now = opts._now !== void 0 ? Math.trunc(opts._now) : Math.floor(Date.now() / 1e3);
3457
+ const skew = Math.abs(now - tsInSig);
3458
+ if (skew > toleranceS) {
3459
+ throw new WebhookVerificationError(
3460
+ `Webhook timestamp outside tolerance: skew=${skew}s, max=${toleranceS}s`
3461
+ );
3462
+ }
3463
+ const hmac = (0, import_node_crypto3.createHmac)("sha256", secret);
3464
+ hmac.update(`${tsInSig}.`);
3465
+ hmac.update(payloadBytes);
3466
+ const computed = hmac.digest("hex");
3467
+ if (!safeHexEqual(computed, expectedHex)) {
3468
+ throw new WebhookVerificationError("Webhook signature mismatch");
3469
+ }
3470
+ }
3270
3471
  // Annotate the CommonJS export names for ESM import in node:
3271
3472
  0 && (module.exports = {
3272
3473
  AgentRole,
3474
+ DEFAULT_TIMESTAMP_TOLERANCE_S,
3273
3475
  MessageType,
3274
3476
  RisicareCallbackHandler,
3275
3477
  RisicareLlamaIndexHandler,
3276
3478
  SemanticPhase,
3277
3479
  SpanKind,
3278
3480
  SpanStatus,
3481
+ WebhookVerificationError,
3279
3482
  agent,
3280
3483
  disable,
3281
3484
  enable,
@@ -3319,6 +3522,7 @@ init_runtime();
3319
3522
  traceThink,
3320
3523
  tracedStream,
3321
3524
  unregisterSpan,
3525
+ verifyWebhookSignature,
3322
3526
  withAgent,
3323
3527
  withPhase,
3324
3528
  withSession