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.js CHANGED
@@ -2040,7 +2040,14 @@ var BatchSpanProcessor = class _BatchSpanProcessor {
2040
2040
  failedExports = 0;
2041
2041
  constructor(options) {
2042
2042
  this._exporters = [...options.exporters];
2043
- this._batchSize = options.batchSize ?? 100;
2043
+ const requestedBatchSize = options.batchSize ?? 100;
2044
+ const clampedBatchSize = Math.max(1, Math.min(requestedBatchSize, 1e4));
2045
+ if (clampedBatchSize !== requestedBatchSize) {
2046
+ warn(
2047
+ `batchSize=${requestedBatchSize} is outside the allowed range [1, 10000]; clamping to ${clampedBatchSize}`
2048
+ );
2049
+ }
2050
+ this._batchSize = clampedBatchSize;
2044
2051
  this._batchTimeoutMs = options.batchTimeoutMs ?? 1e3;
2045
2052
  this._maxQueueSize = options.maxQueueSize ?? 1e4;
2046
2053
  this._debug = options.debug ?? false;
@@ -2181,11 +2188,15 @@ var HttpExporter = class {
2181
2188
  _timeoutMs;
2182
2189
  _maxRetries;
2183
2190
  _compress;
2184
- // Circuit breaker
2191
+ // Circuit breaker (CON-201 / B-16). Threshold and cooldown sized for
2192
+ // a "30-second prod restart" scenario: with default 1s batch flush a
2193
+ // 5-failure threshold opens the circuit ~5s into an outage and the 60s
2194
+ // cooldown gives the gateway time to come back before the half-open
2195
+ // probe fires. Lower numbers (was 3@30s) tripped on transient blips.
2185
2196
  _consecutiveFailures = 0;
2186
2197
  _circuitOpenUntil = 0;
2187
- _circuitBreakerThreshold = 3;
2188
- _circuitBreakerCooldownMs = 3e4;
2198
+ _circuitBreakerThreshold = 5;
2199
+ _circuitBreakerCooldownMs = 6e4;
2189
2200
  constructor(options) {
2190
2201
  this._endpoint = options.endpoint.replace(/\/+$/, "");
2191
2202
  this._apiKey = options.apiKey;
@@ -2346,7 +2357,18 @@ var RisicareClient = class {
2346
2357
  enabled: true,
2347
2358
  debug: this.config.debug
2348
2359
  });
2349
- } catch {
2360
+ } catch (e) {
2361
+ const errName = e instanceof Error ? e.name : "Error";
2362
+ const errMsg = e instanceof Error ? e.message : String(e);
2363
+ try {
2364
+ console.warn(
2365
+ `[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.`
2366
+ );
2367
+ } catch {
2368
+ }
2369
+ if (this.config.debug) {
2370
+ debug(`FixRuntime init traceback: ${e instanceof Error && e.stack ? e.stack : String(e)}`);
2371
+ }
2350
2372
  }
2351
2373
  }
2352
2374
  this._registerShutdownHooks();
@@ -2498,7 +2520,7 @@ function reportError(error, options) {
2498
2520
  }
2499
2521
  function score(traceId, name, value, options) {
2500
2522
  try {
2501
- if (typeof value !== "number" || value < 0 || value > 1) {
2523
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 1) {
2502
2524
  debug(`score: value must be in [0.0, 1.0], got ${value}. Score not sent.`);
2503
2525
  return;
2504
2526
  }
@@ -2548,7 +2570,7 @@ function withAgent(options, fn) {
2548
2570
  }
2549
2571
 
2550
2572
  // src/decorators/agent.ts
2551
- function agent(options, fn) {
2573
+ function _wrapAgent(options, fn) {
2552
2574
  const spanName = `agent:${options.name ?? "agent"}`;
2553
2575
  return (...args) => {
2554
2576
  const tracer = getTracer2();
@@ -2562,6 +2584,12 @@ function agent(options, fn) {
2562
2584
  });
2563
2585
  };
2564
2586
  }
2587
+ function agent(options, fn) {
2588
+ if (fn === void 0) {
2589
+ return (realFn) => _wrapAgent(options, realFn);
2590
+ }
2591
+ return _wrapAgent(options, fn);
2592
+ }
2565
2593
 
2566
2594
  // src/context/session.ts
2567
2595
  function withSession(options, fn) {
@@ -2576,12 +2604,18 @@ function withSession(options, fn) {
2576
2604
  }
2577
2605
 
2578
2606
  // src/decorators/session.ts
2579
- function session(optionsOrResolver, fn) {
2607
+ function _wrapSession(optionsOrResolver, fn) {
2580
2608
  return (...args) => {
2581
2609
  const options = typeof optionsOrResolver === "function" ? optionsOrResolver(...args) : optionsOrResolver;
2582
2610
  return withSession(options, () => fn(...args));
2583
2611
  };
2584
2612
  }
2613
+ function session(optionsOrResolver, fn) {
2614
+ if (fn === void 0) {
2615
+ return (realFn) => _wrapSession(optionsOrResolver, realFn);
2616
+ }
2617
+ return _wrapSession(optionsOrResolver, fn);
2618
+ }
2585
2619
 
2586
2620
  // src/context/phase.ts
2587
2621
  function withPhase(phase, fn) {
@@ -3203,14 +3237,180 @@ var RisicareLlamaIndexHandler = class {
3203
3237
 
3204
3238
  // src/index.ts
3205
3239
  init_runtime();
3240
+
3241
+ // src/webhooks.ts
3242
+ import { createHmac, timingSafeEqual } from "crypto";
3243
+ import { Buffer as Buffer2 } from "buffer";
3244
+ var DEFAULT_TIMESTAMP_TOLERANCE_S = 300;
3245
+ var SIGNATURE_HEADER = "X-Risicare-Signature";
3246
+ var TIMESTAMP_HEADER = "X-Risicare-Timestamp";
3247
+ var SUPPORTED_SCHEMES = ["v1"];
3248
+ var HEX_SHA256_RE = /^[0-9a-f]{64}$/;
3249
+ var WebhookVerificationError = class _WebhookVerificationError extends Error {
3250
+ constructor(message) {
3251
+ super(message);
3252
+ this.name = "WebhookVerificationError";
3253
+ Object.setPrototypeOf(this, _WebhookVerificationError.prototype);
3254
+ }
3255
+ };
3256
+ function getHeader(headers, name) {
3257
+ const lower = name.toLowerCase();
3258
+ if (typeof headers.get === "function") {
3259
+ const accessor = headers;
3260
+ const v = accessor.get(name) ?? accessor.get(lower);
3261
+ return v ?? void 0;
3262
+ }
3263
+ const dict = headers;
3264
+ const raw = dict[name] ?? dict[lower];
3265
+ if (raw === void 0) {
3266
+ return void 0;
3267
+ }
3268
+ if (Array.isArray(raw)) {
3269
+ return raw[0];
3270
+ }
3271
+ return raw;
3272
+ }
3273
+ function coercePayload(payload) {
3274
+ if (typeof payload === "string") {
3275
+ return Buffer2.from(payload, "utf-8");
3276
+ }
3277
+ if (payload instanceof Uint8Array) {
3278
+ return Buffer2.from(
3279
+ payload.buffer,
3280
+ payload.byteOffset,
3281
+ payload.byteLength
3282
+ );
3283
+ }
3284
+ if (payload instanceof ArrayBuffer) {
3285
+ return Buffer2.from(payload);
3286
+ }
3287
+ throw new WebhookVerificationError(
3288
+ `payload must be Uint8Array, ArrayBuffer, Buffer, or string, got ${typeof payload}`
3289
+ );
3290
+ }
3291
+ function parseSignatureHeader(raw) {
3292
+ const parts = /* @__PURE__ */ Object.create(null);
3293
+ for (const rawSegment of raw.split(",")) {
3294
+ const segment = rawSegment.trim();
3295
+ if (segment === "") {
3296
+ continue;
3297
+ }
3298
+ const eqIdx = segment.indexOf("=");
3299
+ if (eqIdx === -1) {
3300
+ throw new WebhookVerificationError(
3301
+ `Malformed segment in ${SIGNATURE_HEADER}: ${JSON.stringify(segment)}`
3302
+ );
3303
+ }
3304
+ const key = segment.slice(0, eqIdx).trim();
3305
+ const value = segment.slice(eqIdx + 1).trim();
3306
+ parts[key] = value;
3307
+ }
3308
+ if (!("t" in parts)) {
3309
+ throw new WebhookVerificationError(
3310
+ `Missing \`t=\` (timestamp) in ${SIGNATURE_HEADER}`
3311
+ );
3312
+ }
3313
+ let scheme;
3314
+ for (const candidate of SUPPORTED_SCHEMES) {
3315
+ if (candidate in parts) {
3316
+ scheme = candidate;
3317
+ break;
3318
+ }
3319
+ }
3320
+ if (scheme === void 0) {
3321
+ const keys = Object.keys(parts).sort();
3322
+ throw new WebhookVerificationError(
3323
+ `No supported signature scheme in ${SIGNATURE_HEADER}; expected one of (${SUPPORTED_SCHEMES.map((s) => `'${s}'`).join(", ")}), got keys [${keys.map((k) => `'${k}'`).join(", ")}]`
3324
+ );
3325
+ }
3326
+ const tRaw = parts["t"];
3327
+ if (!/^-?\d+$/.test(tRaw)) {
3328
+ throw new WebhookVerificationError(
3329
+ `Non-integer timestamp in ${SIGNATURE_HEADER}: ${JSON.stringify(tRaw)}`
3330
+ );
3331
+ }
3332
+ const ts = parseInt(tRaw, 10);
3333
+ if (!Number.isFinite(ts)) {
3334
+ throw new WebhookVerificationError(
3335
+ `Non-integer timestamp in ${SIGNATURE_HEADER}: ${JSON.stringify(tRaw)}`
3336
+ );
3337
+ }
3338
+ const sigHex = parts[scheme];
3339
+ if (sigHex === void 0 || sigHex === "") {
3340
+ throw new WebhookVerificationError(
3341
+ `Empty ${scheme}= value in ${SIGNATURE_HEADER}`
3342
+ );
3343
+ }
3344
+ return [ts, sigHex];
3345
+ }
3346
+ function safeHexEqual(computed, expected) {
3347
+ if (!HEX_SHA256_RE.test(expected)) {
3348
+ return false;
3349
+ }
3350
+ const a = Buffer2.from(computed, "hex");
3351
+ const b = Buffer2.from(expected, "hex");
3352
+ if (a.length !== b.length) {
3353
+ return false;
3354
+ }
3355
+ return timingSafeEqual(a, b);
3356
+ }
3357
+ function verifyWebhookSignature(payload, headers, secret, opts = {}) {
3358
+ const toleranceS = opts.toleranceS ?? DEFAULT_TIMESTAMP_TOLERANCE_S;
3359
+ const payloadBytes = coercePayload(payload);
3360
+ const sigHeader = getHeader(headers, SIGNATURE_HEADER);
3361
+ if (sigHeader === void 0 || sigHeader === "") {
3362
+ throw new WebhookVerificationError(
3363
+ `Missing ${SIGNATURE_HEADER} header`
3364
+ );
3365
+ }
3366
+ const tsHeader = getHeader(headers, TIMESTAMP_HEADER);
3367
+ if (tsHeader === void 0 || tsHeader === "") {
3368
+ throw new WebhookVerificationError(
3369
+ `Missing ${TIMESTAMP_HEADER} header`
3370
+ );
3371
+ }
3372
+ const [tsInSig, expectedHex] = parseSignatureHeader(sigHeader);
3373
+ if (!/^-?\d+$/.test(tsHeader)) {
3374
+ throw new WebhookVerificationError(
3375
+ `Non-integer ${TIMESTAMP_HEADER}: ${JSON.stringify(tsHeader)}`
3376
+ );
3377
+ }
3378
+ const tsStandalone = parseInt(tsHeader, 10);
3379
+ if (!Number.isFinite(tsStandalone)) {
3380
+ throw new WebhookVerificationError(
3381
+ `Non-integer ${TIMESTAMP_HEADER}: ${JSON.stringify(tsHeader)}`
3382
+ );
3383
+ }
3384
+ if (tsStandalone !== tsInSig) {
3385
+ throw new WebhookVerificationError(
3386
+ `Timestamp mismatch: ${TIMESTAMP_HEADER}=${tsStandalone}, signature t=${tsInSig}`
3387
+ );
3388
+ }
3389
+ const now = opts._now !== void 0 ? Math.trunc(opts._now) : Math.floor(Date.now() / 1e3);
3390
+ const skew = Math.abs(now - tsInSig);
3391
+ if (skew > toleranceS) {
3392
+ throw new WebhookVerificationError(
3393
+ `Webhook timestamp outside tolerance: skew=${skew}s, max=${toleranceS}s`
3394
+ );
3395
+ }
3396
+ const hmac = createHmac("sha256", secret);
3397
+ hmac.update(`${tsInSig}.`);
3398
+ hmac.update(payloadBytes);
3399
+ const computed = hmac.digest("hex");
3400
+ if (!safeHexEqual(computed, expectedHex)) {
3401
+ throw new WebhookVerificationError("Webhook signature mismatch");
3402
+ }
3403
+ }
3206
3404
  export {
3207
3405
  AgentRole,
3406
+ DEFAULT_TIMESTAMP_TOLERANCE_S,
3208
3407
  MessageType,
3209
3408
  RisicareCallbackHandler,
3210
3409
  RisicareLlamaIndexHandler,
3211
3410
  SemanticPhase,
3212
3411
  SpanKind,
3213
3412
  SpanStatus,
3413
+ WebhookVerificationError,
3214
3414
  agent,
3215
3415
  disable,
3216
3416
  enable,
@@ -3254,6 +3454,7 @@ export {
3254
3454
  traceThink,
3255
3455
  tracedStream,
3256
3456
  unregisterSpan,
3457
+ verifyWebhookSignature,
3257
3458
  withAgent,
3258
3459
  withPhase,
3259
3460
  withSession