langwatch 1.0.0 → 1.2.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 (56) hide show
  1. package/README.md +33 -0
  2. package/dist/{chunk-TKSTXX3D.js → chunk-CLTKABMO.js} +52 -2
  3. package/dist/chunk-CLTKABMO.js.map +1 -0
  4. package/dist/{chunk-L5KBRKHS.mjs → chunk-CMZFFKLA.mjs} +51 -1
  5. package/dist/{chunk-L5KBRKHS.mjs.map → chunk-CMZFFKLA.mjs.map} +1 -1
  6. package/dist/{chunk-52VMSJ4O.js → chunk-DTSULVK5.js} +39 -19
  7. package/dist/chunk-DTSULVK5.js.map +1 -0
  8. package/dist/{chunk-5Q2DUSMQ.mjs → chunk-JYTJEAOU.mjs} +3 -3
  9. package/dist/chunk-JYTJEAOU.mjs.map +1 -0
  10. package/dist/chunk-K6KPNTQO.js +15624 -0
  11. package/dist/chunk-K6KPNTQO.js.map +1 -0
  12. package/dist/{chunk-2O4ILSP5.mjs → chunk-LTDUROCE.mjs} +2 -2
  13. package/dist/{chunk-ALPIFEXL.mjs → chunk-PDNXHBSL.mjs} +26 -6
  14. package/dist/chunk-PDNXHBSL.mjs.map +1 -0
  15. package/dist/chunk-SYJIEBJY.mjs +15624 -0
  16. package/dist/chunk-SYJIEBJY.mjs.map +1 -0
  17. package/dist/{chunk-WHBCX64R.js → chunk-UOFSG6R4.js} +19 -19
  18. package/dist/chunk-UOFSG6R4.js.map +1 -0
  19. package/dist/{chunk-IUSLT65Z.js → chunk-ZTOXEWNX.js} +2 -2
  20. package/dist/chunk-ZTOXEWNX.js.map +1 -0
  21. package/dist/cli/bundle.js +265 -180
  22. package/dist/{implementation-CPfDot-W.d.mts → implementation-CHXrVq_q.d.mts} +1 -1
  23. package/dist/{implementation-aYHmyVZ_.d.ts → implementation-D_v0fUvU.d.ts} +1 -1
  24. package/dist/index.d.mts +1125 -5
  25. package/dist/index.d.ts +1125 -5
  26. package/dist/index.js +1272 -151
  27. package/dist/index.js.map +1 -1
  28. package/dist/index.mjs +1197 -76
  29. package/dist/index.mjs.map +1 -1
  30. package/dist/observability-sdk/index.d.mts +3 -3
  31. package/dist/observability-sdk/index.d.ts +3 -3
  32. package/dist/observability-sdk/index.js +5 -5
  33. package/dist/observability-sdk/index.js.map +1 -1
  34. package/dist/observability-sdk/index.mjs +4 -4
  35. package/dist/observability-sdk/instrumentation/langchain/index.d.mts +1 -1
  36. package/dist/observability-sdk/instrumentation/langchain/index.d.ts +1 -1
  37. package/dist/observability-sdk/instrumentation/langchain/index.js +18 -18
  38. package/dist/observability-sdk/instrumentation/langchain/index.js.map +1 -1
  39. package/dist/observability-sdk/instrumentation/langchain/index.mjs +2 -2
  40. package/dist/observability-sdk/setup/node/index.js +4 -4
  41. package/dist/observability-sdk/setup/node/index.js.map +1 -1
  42. package/dist/observability-sdk/setup/node/index.mjs +3 -3
  43. package/dist/{types-Cw-3VUv7.d.mts → types-DlP7QdqU.d.mts} +15065 -6184
  44. package/dist/{types-CeZ-M8JZ.d.ts → types-av2kmt_i.d.ts} +15065 -6184
  45. package/package.json +9 -10
  46. package/dist/chunk-52VMSJ4O.js.map +0 -1
  47. package/dist/chunk-5Q2DUSMQ.mjs.map +0 -1
  48. package/dist/chunk-ADJOFPAZ.js +0 -1005
  49. package/dist/chunk-ADJOFPAZ.js.map +0 -1
  50. package/dist/chunk-ALPIFEXL.mjs.map +0 -1
  51. package/dist/chunk-C323F5VC.mjs +0 -1005
  52. package/dist/chunk-C323F5VC.mjs.map +0 -1
  53. package/dist/chunk-IUSLT65Z.js.map +0 -1
  54. package/dist/chunk-TKSTXX3D.js.map +0 -1
  55. package/dist/chunk-WHBCX64R.js.map +0 -1
  56. /package/dist/{chunk-2O4ILSP5.mjs.map → chunk-LTDUROCE.mjs.map} +0 -0
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { L as Logger, C as ConsoleLogger, N as NoOpLogger } from './index-D7rKIGrO.mjs';
2
- export { F as FilterableBatchSpanProcessor, L as LangWatchExporter, S as SpanProcessingExcludeRule, g as getLangWatchLogger, a as getLangWatchTracer } from './implementation-CPfDot-W.mjs';
2
+ export { F as FilterableBatchSpanProcessor, L as LangWatchExporter, S as SpanProcessingExcludeRule, g as getLangWatchLogger, a as getLangWatchTracer } from './implementation-CHXrVq_q.mjs';
3
3
  import { z } from 'zod';
4
- import { p as paths, P as PromptResponse, C as CreatePromptBody, U as UpdatePromptBody, T as TagDefinition, a as CreatedTag, o as operations, b as PromptData, F as FetchPolicy, c as Prompt, L as LangWatchSpan, d as components } from './types-Cw-3VUv7.mjs';
4
+ import { p as paths, P as PromptResponse, C as CreatePromptBody, U as UpdatePromptBody, T as TagDefinition, a as CreatedTag, o as operations, b as PromptData, F as FetchPolicy, c as Prompt, L as LangWatchSpan, d as components } from './types-DlP7QdqU.mjs';
5
5
  import openApiCreateClient from 'openapi-fetch';
6
6
  export { l as attributes } from './types-VOZv9LYO.mjs';
7
7
  import { CliHandledErrorReason, CliHandledError } from '@langwatch/langy/cards/handled-error';
@@ -28,7 +28,7 @@ declare const localPromptConfigSchema: z.ZodObject<{
28
28
  }>;
29
29
  content: z.ZodString;
30
30
  }, z.core.$loose>>;
31
- parameters: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
31
+ parameters: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodType<JsonValue, unknown, z.core.$ZodTypeInternals<JsonValue, unknown>>>>>;
32
32
  }, z.core.$loose>;
33
33
  type LocalPromptConfig = z.infer<typeof localPromptConfigSchema>;
34
34
 
@@ -39,7 +39,16 @@ type PromptDependency = string | {
39
39
  type PromptsConfig = {
40
40
  prompts: Record<string, PromptDependency>;
41
41
  };
42
- type RuntimeParameters = Record<string, unknown>;
42
+ /**
43
+ * A JSON value: what runtime parameters actually persist and what the API
44
+ * schema declares (the spec's recursive JsonValue component). Structurally
45
+ * identical to the generated client's RecursiveJsonValue, so values flow
46
+ * between hand-written and generated types without casts.
47
+ */
48
+ type JsonValue = string | number | boolean | null | JsonValue[] | {
49
+ [key: string]: JsonValue;
50
+ };
51
+ type RuntimeParameters = Record<string, JsonValue>;
43
52
  type MaterializedPrompt = {
44
53
  id: string;
45
54
  name: string;
@@ -2064,6 +2073,980 @@ declare class SecretsApiService {
2064
2073
  delete(id: string): Promise<SecretDeleteResponse>;
2065
2074
  }
2066
2075
 
2076
+ /**
2077
+ * The per-call options every mutating call on the billing surfaces takes.
2078
+ *
2079
+ * WHERE THEY GO. A call whose arguments already ride in an options bag
2080
+ * (`disable(id, { reason })`, `reset(id, { endUserId })`) gains these fields in
2081
+ * that same bag: one bag per call is what a caller expects. A call that takes a
2082
+ * request BODY (`create(input)`, `update(id, input)`) gets a separate trailing
2083
+ * parameter instead, because those body types mirror the wire verbatim and must
2084
+ * not grow keys the wire has never heard of.
2085
+ *
2086
+ * They are an interface rather than a bare `signal` so that the next thing a
2087
+ * call needs per invocation is an added field rather than an added parameter.
2088
+ */
2089
+ /** The request header the control plane deduplicates creates on. */
2090
+ declare const IDEMPOTENCY_KEY_HEADER = "Idempotency-Key";
2091
+ /**
2092
+ * The response header a replayed create carries. Only ever `"true"`, and
2093
+ * ABSENT rather than false on a first execution, so its presence is the whole
2094
+ * signal.
2095
+ */
2096
+ declare const IDEMPOTENT_REPLAY_HEADER = "X-Idempotent-Replay";
2097
+ interface MutationOptions {
2098
+ /**
2099
+ * Cancel the call. Without one, the request is bounded by the SDK's own
2100
+ * 30 second timeout so a hung control plane fails rather than freezes.
2101
+ */
2102
+ signal?: AbortSignal;
2103
+ }
2104
+ interface IdempotentCreateOptions extends MutationOptions {
2105
+ /**
2106
+ * Makes the create safe to retry. A dropped connection after the write but
2107
+ * before the response looks exactly like a dropped request, and sending it
2108
+ * again without a key mints a SECOND resource. Send the same key on the
2109
+ * retry and the server answers with the first response instead, byte for
2110
+ * byte, including the one-time secret a create hands back.
2111
+ *
2112
+ * Any string of 8 to 255 characters; a UUID minted per logical create is the
2113
+ * usual choice. Receipts answer for 24 hours, and only successful creates
2114
+ * leave one, so a create that failed is safe to run again either way.
2115
+ *
2116
+ * Reusing a key with a DIFFERENT body is refused with `idempotency_error`
2117
+ * rather than quietly answering for the wrong request.
2118
+ */
2119
+ idempotencyKey?: string;
2120
+ /**
2121
+ * Called when the response came from a receipt rather than a fresh write,
2122
+ * i.e. this exact create had already succeeded.
2123
+ *
2124
+ * A hook rather than a field on the returned resource: the resource is
2125
+ * identical either way, so nothing about handling it changes, and the
2126
+ * distinction is something a caller logs rather than branches on. Keeping it
2127
+ * off the return type also keeps the wire-shaped entities free of fields the
2128
+ * wire does not have.
2129
+ */
2130
+ onIdempotentReplay?: () => void;
2131
+ }
2132
+
2133
+ type VirtualKeyScopeType = "organization" | "team" | "project";
2134
+ interface VirtualKeyScope {
2135
+ scope_type: VirtualKeyScopeType;
2136
+ scope_id: string;
2137
+ }
2138
+ type VirtualKeyRoutingMode = "none" | "fallback_all" | "policy";
2139
+ /**
2140
+ * The snake DTO the server returns (`toVirtualKeySnakeDto`). The token
2141
+ * format is `vk-lw-<ulid>` with no live/test discriminator; the gateway
2142
+ * never branches on environment, so there is no env field.
2143
+ */
2144
+ interface VirtualKey {
2145
+ id: string;
2146
+ organization_id: string;
2147
+ name: string;
2148
+ description: string | null;
2149
+ /** `disabled` is the reversible stop; `revoked` is terminal. */
2150
+ status: "active" | "disabled" | "revoked";
2151
+ /** "langy" marks a product-managed key; customers can only mint "user". */
2152
+ purpose: "user" | "langy";
2153
+ /** e.g. "vk-lw-01HZX9" — the only secret material kept after creation. */
2154
+ display_prefix: string;
2155
+ principal_user_id: string | null;
2156
+ /**
2157
+ * Where an org- or team-owned key's traces and costs land. Not a
2158
+ * scope: it grants no access to the key.
2159
+ */
2160
+ trace_project_id: string | null;
2161
+ scopes: VirtualKeyScope[];
2162
+ routing_policy_id: string | null;
2163
+ routing_mode: VirtualKeyRoutingMode;
2164
+ config: Record<string, unknown>;
2165
+ revision: string;
2166
+ created_at: string;
2167
+ updated_at: string;
2168
+ last_used_at: string | null;
2169
+ revoked_at: string | null;
2170
+ }
2171
+ /**
2172
+ * The cap a key carries on itself, created atomically with the key. Only
2173
+ * the calendar windows a person reasons about; string amounts survive
2174
+ * JSON round-trips without float drift (numbers are stringified).
2175
+ */
2176
+ interface VirtualKeyBudgetInput {
2177
+ limit_usd: string | number;
2178
+ window: "day" | "week" | "month";
2179
+ on_breach?: "block" | "warn";
2180
+ name?: string;
2181
+ }
2182
+ interface CreateVirtualKeyInput {
2183
+ name: string;
2184
+ description?: string;
2185
+ principal_user_id?: string | null;
2186
+ /** Defaults to the caller's project when omitted. */
2187
+ scopes?: VirtualKeyScope[];
2188
+ /**
2189
+ * Explicit trace destination for org- and team-owned keys; requires
2190
+ * `virtualKeys:manage` on that project. NOT a scope.
2191
+ */
2192
+ trace_project_id?: string | null;
2193
+ routing_policy_id?: string | null;
2194
+ routing_mode?: VirtualKeyRoutingMode;
2195
+ /** Optional cap created atomically with the key. */
2196
+ budget?: VirtualKeyBudgetInput | null;
2197
+ config?: Record<string, unknown>;
2198
+ /**
2199
+ * Your own identifier for this key, unique within the organization. Lets
2200
+ * you look the key up by the id your system already has instead of storing
2201
+ * ours alongside it.
2202
+ */
2203
+ external_id?: string | null;
2204
+ /**
2205
+ * Free-form string labels, up to 40 of them. Sent WHOLE on an update: the
2206
+ * map you pass replaces the stored one rather than merging into it, and
2207
+ * `{}` clears it.
2208
+ */
2209
+ metadata?: Record<string, string>;
2210
+ }
2211
+ interface UpdateVirtualKeyInput {
2212
+ name?: string;
2213
+ description?: string | null;
2214
+ scopes?: VirtualKeyScope[];
2215
+ trace_project_id?: string | null;
2216
+ routing_policy_id?: string | null;
2217
+ routing_mode?: VirtualKeyRoutingMode;
2218
+ /** Undefined leaves the cap alone; a value upserts it; null archives it. */
2219
+ budget?: VirtualKeyBudgetInput | null;
2220
+ config?: Record<string, unknown>;
2221
+ /**
2222
+ * Your own identifier for this key, unique within the organization. Lets
2223
+ * you look the key up by the id your system already has instead of storing
2224
+ * ours alongside it.
2225
+ */
2226
+ external_id?: string | null;
2227
+ /**
2228
+ * Free-form string labels, up to 40 of them. Sent WHOLE on an update: the
2229
+ * map you pass replaces the stored one rather than merging into it, and
2230
+ * `{}` clears it.
2231
+ */
2232
+ metadata?: Record<string, string>;
2233
+ }
2234
+ interface VirtualKeyWithSecret {
2235
+ virtual_key: VirtualKey;
2236
+ secret: string;
2237
+ }
2238
+ /** One page of the virtual-key listing, exactly as the wire serves it. */
2239
+ interface VirtualKeyPage {
2240
+ data: VirtualKey[];
2241
+ /**
2242
+ * Pass back as `cursor` for the next page. Null means the walk is
2243
+ * exhausted. Neither page length tells you anything here: visibility is
2244
+ * applied to each page AFTER it is read, so a page can hold fewer rows
2245
+ * than `limit` with more still to come.
2246
+ */
2247
+ next_cursor: string | null;
2248
+ }
2249
+ /** Aggregate spend for one key over a window, from the cost path. */
2250
+ interface VirtualKeySpendSummary {
2251
+ virtual_key_id: string;
2252
+ spent_usd: string;
2253
+ requests: number;
2254
+ /** Epoch milliseconds, the unit every spend surface takes and returns. */
2255
+ window: {
2256
+ from: number;
2257
+ to: number;
2258
+ };
2259
+ }
2260
+ declare class VirtualKeysApiError extends Error {
2261
+ readonly operation: string;
2262
+ readonly originalError?: unknown | undefined;
2263
+ constructor(message: string, operation: string, originalError?: unknown | undefined);
2264
+ }
2265
+ /**
2266
+ * Client for the gateway virtual-key surface (/api/gateway/v1).
2267
+ *
2268
+ * Entity types and the create/update bodies mirror the wire verbatim, so
2269
+ * their fields are lowercase snake_case. Call options this SDK invents (query
2270
+ * filters, per-call behaviour, action arguments) are camelCase like the rest
2271
+ * of the SDK.
2272
+ */
2273
+ declare class VirtualKeysApiService {
2274
+ private readonly endpoint;
2275
+ private readonly apiKey;
2276
+ private readonly projectId;
2277
+ constructor(config?: {
2278
+ endpoint?: string;
2279
+ apiKey?: string;
2280
+ projectId?: string;
2281
+ });
2282
+ private headers;
2283
+ private request;
2284
+ /**
2285
+ * ONE page of the virtual keys visible to the caller, newest first. Pass
2286
+ * `next_cursor` back as `cursor` for the next page, verbatim: a cursor this
2287
+ * endpoint did not issue answers 400 rather than restarting the walk.
2288
+ *
2289
+ * `limit` is the page size (server default 50, capped at 200), and it caps
2290
+ * the rows READ, not the rows returned: the visibility filter runs on the
2291
+ * page afterwards. Prefer `list()` unless you mean to page deliberately.
2292
+ */
2293
+ listPage(options?: {
2294
+ cursor?: string;
2295
+ limit?: number;
2296
+ /** Exact match on your own identifier, not a prefix or a search. */
2297
+ externalId?: string;
2298
+ }): Promise<VirtualKeyPage>;
2299
+ /**
2300
+ * Every virtual key visible to the caller: keys scoped to this project, to
2301
+ * its team, or to the whole organization.
2302
+ *
2303
+ * The endpoint pages; this follows `next_cursor` until it comes back null.
2304
+ * Stopping on a short page would be wrong here specifically, because the
2305
+ * server filters each page for visibility after reading it, so a page can
2306
+ * hold fewer rows than the limit with more still to come.
2307
+ *
2308
+ * `limit` sizes each request in the walk, it does NOT cap what comes back.
2309
+ * `cursor` resumes an interrupted walk. Take a single page with
2310
+ * `listPage()`, or stream the walk with `iterate()`.
2311
+ */
2312
+ list(options?: {
2313
+ cursor?: string;
2314
+ limit?: number;
2315
+ /** Exact match on your own identifier, not a prefix or a search. */
2316
+ externalId?: string;
2317
+ }): Promise<VirtualKey[]>;
2318
+ /**
2319
+ * Every visible virtual key, one row at a time, fetching each page only
2320
+ * when the consumer reaches it. Stop early and the rest is never read,
2321
+ * which `list()` cannot offer because it materialises the whole listing
2322
+ * first. Raises rather than looping forever on a cursor chain that never
2323
+ * ends, exactly like `list()`.
2324
+ */
2325
+ iterate(options?: {
2326
+ cursor?: string;
2327
+ limit?: number;
2328
+ /** Exact match on your own identifier, not a prefix or a search. */
2329
+ externalId?: string;
2330
+ }): AsyncGenerator<VirtualKey>;
2331
+ get(id: string): Promise<VirtualKey>;
2332
+ /**
2333
+ * Mint a key. The response carries the secret ONCE; nothing ever serves it
2334
+ * again, so a create that times out is recovered with `idempotencyKey`
2335
+ * rather than by listing.
2336
+ */
2337
+ create(input: CreateVirtualKeyInput, options?: IdempotentCreateOptions): Promise<VirtualKeyWithSecret>;
2338
+ update(id: string, input: UpdateVirtualKeyInput, options?: MutationOptions): Promise<VirtualKey>;
2339
+ rotate(id: string, options?: MutationOptions): Promise<VirtualKeyWithSecret>;
2340
+ revoke(id: string, options?: MutationOptions): Promise<VirtualKey>;
2341
+ /** Reversible stop; enable() restores the key exactly as it was. */
2342
+ disable(id: string, options?: {
2343
+ reason?: string;
2344
+ } & MutationOptions): Promise<VirtualKey>;
2345
+ enable(id: string, options?: MutationOptions): Promise<VirtualKey>;
2346
+ /**
2347
+ * Aggregate spend for one key over a window in epoch milliseconds.
2348
+ * Defaults to the current UTC calendar month server-side. Reads the same
2349
+ * cost path the dashboard reads, so this number and the UI agree by
2350
+ * construction.
2351
+ */
2352
+ spend(id: string, options?: {
2353
+ from?: number;
2354
+ to?: number;
2355
+ }): Promise<VirtualKeySpendSummary>;
2356
+ }
2357
+
2358
+ type BudgetScopeKind = "organization" | "team" | "project" | "virtual_key" | "principal" | "group" | "attributed_user";
2359
+ type BudgetWindow = "minute" | "hour" | "day" | "week" | "month" | "total" | "manual";
2360
+ type BudgetOnBreach = "block" | "warn";
2361
+ interface GatewayBudget {
2362
+ id: string;
2363
+ organization_id: string;
2364
+ scope_type: BudgetScopeKind;
2365
+ scope_id: string;
2366
+ name: string;
2367
+ description: string | null;
2368
+ window: BudgetWindow;
2369
+ on_breach: BudgetOnBreach;
2370
+ /**
2371
+ * For `group` rows this is the PER-MEMBER allowance, not a group total;
2372
+ * `spent_usd` sums the whole group and `member_count` says how many
2373
+ * members the allowance currently covers. For `attributed_user` rows it is
2374
+ * the PER-PERSON cap, and `end_users_seen` / `end_users_over` carry the
2375
+ * standing instead of `spent_usd`.
2376
+ */
2377
+ limit_usd: string;
2378
+ /** Canonical integer limit, nano-USD. Null past the safe integer range. */
2379
+ limit_nano_usd: number | null;
2380
+ /**
2381
+ * Display value. NULL when `spend_available` is false: spend could not be
2382
+ * totalled, so there is no figure, and the API sends null rather than a
2383
+ * stale one a caller could mistake for real money.
2384
+ */
2385
+ spent_usd: string | null;
2386
+ /** Canonical integer spend, nano-USD. Null whenever `spent_usd` is. */
2387
+ spent_nano_usd: number | null;
2388
+ timezone: string | null;
2389
+ /** ModelProvider id the budget counts; null counts every provider. */
2390
+ provider_key: string | null;
2391
+ current_period_started_at: string;
2392
+ resets_at: string;
2393
+ /** Instant the cycle is phased from; null means calendar aligned. */
2394
+ cycle_anchor_at: string | null;
2395
+ last_reset_at: string | null;
2396
+ archived_at: string | null;
2397
+ created_at: string;
2398
+ /** `group` rows only. */
2399
+ member_count?: number;
2400
+ /** `attributed_user` rows only: end users with spend this period. */
2401
+ end_users_seen?: number;
2402
+ /** `attributed_user` rows only: how many of those are at or over the cap. */
2403
+ end_users_over?: number;
2404
+ }
2405
+ /**
2406
+ * One page of the budget listing, exactly as the wire serves it.
2407
+ *
2408
+ * Budgets come back in an envelope where virtual keys come back as a bare
2409
+ * array because `spend_available` is a correctness flag about the whole page,
2410
+ * and an array cannot carry it.
2411
+ */
2412
+ interface GatewayBudgetPage {
2413
+ data: GatewayBudget[];
2414
+ /**
2415
+ * False when spend could not be totalled: render "unavailable" rather
2416
+ * than trusting `spent_usd` as real spend.
2417
+ */
2418
+ spend_available: boolean;
2419
+ /**
2420
+ * Pass back as `cursor` for the next page. Null means the walk is
2421
+ * exhausted; a FULL page does not by itself mean there is more.
2422
+ */
2423
+ next_cursor: string | null;
2424
+ }
2425
+ type CreateGatewayBudgetScope = {
2426
+ kind: "organization";
2427
+ organization_id: string;
2428
+ } | {
2429
+ kind: "team";
2430
+ team_id: string;
2431
+ } | {
2432
+ kind: "project";
2433
+ project_id: string;
2434
+ } | {
2435
+ kind: "virtual_key";
2436
+ virtual_key_id: string;
2437
+ } | {
2438
+ kind: "principal";
2439
+ principal_user_id: string;
2440
+ } | {
2441
+ kind: "group";
2442
+ group_id: string;
2443
+ } | {
2444
+ kind: "attributed_user";
2445
+ anchor_virtual_key_id?: string;
2446
+ anchor_project_id?: string;
2447
+ };
2448
+ interface CreateGatewayBudgetInput {
2449
+ scope: CreateGatewayBudgetScope;
2450
+ name: string;
2451
+ description?: string;
2452
+ window: BudgetWindow;
2453
+ limit_usd: number | string;
2454
+ on_breach?: BudgetOnBreach;
2455
+ timezone?: string | null;
2456
+ /** ModelProvider id to pin the budget to one provider. */
2457
+ provider_key?: string | null;
2458
+ /**
2459
+ * RFC3339 instant that phases the budget's cycle instead of the calendar:
2460
+ * a `month` budget anchored `2026-01-17T09:00:00Z` rolls every 17th at
2461
+ * 09:00 UTC. Omit for calendar alignment. Immutable once created, and
2462
+ * rejected on the windows that never cycle (`total`, `manual`).
2463
+ */
2464
+ cycle_anchor_at?: string;
2465
+ /**
2466
+ * Your own identifier for this budget. Lets you look it up by the id your
2467
+ * system already has instead of storing ours alongside it.
2468
+ */
2469
+ external_id?: string | null;
2470
+ /**
2471
+ * Free-form string labels, up to 40 of them. Sent WHOLE on an update: the
2472
+ * map you pass replaces the stored one rather than merging into it, and
2473
+ * `{}` clears it.
2474
+ */
2475
+ metadata?: Record<string, string>;
2476
+ }
2477
+ interface UpdateGatewayBudgetInput {
2478
+ name?: string;
2479
+ description?: string | null;
2480
+ limit_usd?: number | string;
2481
+ on_breach?: BudgetOnBreach;
2482
+ timezone?: string | null;
2483
+ }
2484
+ declare class GatewayBudgetsApiError extends Error {
2485
+ readonly operation: string;
2486
+ readonly originalError?: unknown | undefined;
2487
+ constructor(message: string, operation: string, originalError?: unknown | undefined);
2488
+ }
2489
+ /**
2490
+ * Client for the gateway budget surface (/api/gateway/v1).
2491
+ *
2492
+ * Entity types and the create/update bodies mirror the wire verbatim, so
2493
+ * their fields are lowercase snake_case. Call options this SDK invents (query
2494
+ * filters, per-call behaviour, action arguments) are camelCase like the rest
2495
+ * of the SDK.
2496
+ */
2497
+ declare class GatewayBudgetsApiService {
2498
+ private readonly endpoint;
2499
+ private readonly apiKey;
2500
+ private readonly projectId;
2501
+ constructor(config?: {
2502
+ endpoint?: string;
2503
+ apiKey?: string;
2504
+ projectId?: string;
2505
+ });
2506
+ private headers;
2507
+ private request;
2508
+ /**
2509
+ * ONE page of non-archived budgets, exactly as the wire serves it. Pass
2510
+ * `next_cursor` back as `cursor` for the next page, verbatim: a cursor this
2511
+ * endpoint did not issue answers 400 rather than restarting the walk.
2512
+ *
2513
+ * `limit` is the page size (server default 50, capped at 200). Prefer
2514
+ * `list()` unless you mean to page deliberately: a full page is not a
2515
+ * promise of more, and a null `next_cursor` is the only end of the walk.
2516
+ */
2517
+ listPage(options?: {
2518
+ scopeTypes?: BudgetScopeKind[];
2519
+ cursor?: string;
2520
+ limit?: number;
2521
+ /** Exact match on your own identifier, not a prefix or a search. */
2522
+ externalId?: string;
2523
+ }): Promise<GatewayBudgetPage>;
2524
+ /**
2525
+ * Every non-archived budget in the organization across all seven scope
2526
+ * types, optionally filtered by `scopeTypes`.
2527
+ *
2528
+ * The endpoint pages; this follows `next_cursor` until it comes back null,
2529
+ * so the result is the complete listing and carries no cursor of its own.
2530
+ * Callers that count, total, or decide an all-clear on this list need that
2531
+ * completeness for correctness, not just for display.
2532
+ *
2533
+ * `limit` sizes each request in the walk, it does NOT cap what comes back.
2534
+ * `cursor` resumes an interrupted walk. Take a single page with
2535
+ * `listPage()`, or stream the walk with `iterate()`.
2536
+ *
2537
+ * A plain array, like every other exhaustive `list()` in the SDK: a walk
2538
+ * that ran to the end has no cursor left to report. Null `spent_usd` /
2539
+ * `spent_nano_usd` on a row is not by itself "spend unavailable": an
2540
+ * `attributed_user` template row serves null deliberately, because one
2541
+ * allowance per person has no single total. Use `listPage()` when you need
2542
+ * `spend_available` stated outright.
2543
+ */
2544
+ list(options?: {
2545
+ scopeTypes?: BudgetScopeKind[];
2546
+ cursor?: string;
2547
+ limit?: number;
2548
+ /** Exact match on your own identifier, not a prefix or a search. */
2549
+ externalId?: string;
2550
+ }): Promise<GatewayBudget[]>;
2551
+ /**
2552
+ * Every non-archived budget, one row at a time, fetching each page only
2553
+ * when the consumer reaches it.
2554
+ *
2555
+ * A null `spent_usd` means spend could not be totalled rather than that
2556
+ * nothing was spent.
2557
+ */
2558
+ iterate(options?: {
2559
+ scopeTypes?: BudgetScopeKind[];
2560
+ cursor?: string;
2561
+ limit?: number;
2562
+ /** Exact match on your own identifier, not a prefix or a search. */
2563
+ externalId?: string;
2564
+ }): AsyncGenerator<GatewayBudget>;
2565
+ /**
2566
+ * One budget by id, in the same row shape the listing serves.
2567
+ *
2568
+ * Archived budgets are not served, so a budget that existed yesterday can
2569
+ * answer 404 today. A null `spent_usd` means spend could not be totalled
2570
+ * rather than that nothing was spent, which is the same signal the listing
2571
+ * carries as `spend_available`.
2572
+ */
2573
+ get(id: string): Promise<GatewayBudget>;
2574
+ create(input: CreateGatewayBudgetInput, options?: IdempotentCreateOptions): Promise<GatewayBudget>;
2575
+ update(id: string, input: UpdateGatewayBudgetInput, options?: MutationOptions): Promise<GatewayBudget>;
2576
+ archive(id: string, options?: MutationOptions): Promise<GatewayBudget>;
2577
+ /**
2578
+ * Move the budget's period boundary to now. Recorded spend is never
2579
+ * mutated; with `endUserId` only that end-user bucket's boundary moves.
2580
+ */
2581
+ reset(id: string, options?: {
2582
+ endUserId?: string;
2583
+ reason?: string;
2584
+ } & MutationOptions): Promise<GatewayBudget>;
2585
+ }
2586
+
2587
+ interface SpendEvent {
2588
+ id: string;
2589
+ type: string;
2590
+ created: string;
2591
+ schema_version: string;
2592
+ data: {
2593
+ /** Type-suffixed, unique per (request, event type): a settled and a
2594
+ * completed event for one request never share an id. */
2595
+ event_id: string;
2596
+ /** "gateway.request.completed" (confirmed and failed outcomes) or
2597
+ * "gateway.request.settled" (confirmation never arrived). */
2598
+ event_type: string;
2599
+ /** The join key across a settled/completed pair: a completed event
2600
+ * SUPERSEDES an earlier settled one for the same request; replace the
2601
+ * figure, never sum the pair. */
2602
+ gateway_request_id: string;
2603
+ occurred_at: string;
2604
+ organization_id: string;
2605
+ project_id: string;
2606
+ virtual_key_id: string;
2607
+ principal_user_id: string | null;
2608
+ end_user_id: string | null;
2609
+ trace_id: string;
2610
+ model: string | null;
2611
+ model_provider_id: string | null;
2612
+ request_type: string | null;
2613
+ /** Null on settled events: unknown is not zero. */
2614
+ usage: {
2615
+ input_tokens: number;
2616
+ output_tokens: number;
2617
+ cache_read_input_tokens: number;
2618
+ cache_creation_input_tokens: number;
2619
+ reasoning_tokens: number;
2620
+ } | null;
2621
+ /** Null on settled events: unknown is not zero. */
2622
+ cost: {
2623
+ total_usd: string;
2624
+ nano_usd: number;
2625
+ rate_version: string | null;
2626
+ } | null;
2627
+ /** "success" | "error" on completed events, "settled" on settled ones. */
2628
+ status: string;
2629
+ needs_reconciliation: boolean | null;
2630
+ settle_reason: string | null;
2631
+ error: {
2632
+ class: string;
2633
+ http_status: number | null;
2634
+ } | null;
2635
+ duration_ms: number | null;
2636
+ labels: string[];
2637
+ metadata: Record<string, unknown>;
2638
+ };
2639
+ }
2640
+ interface SpendSummaryRow {
2641
+ key: string;
2642
+ /** Priced outcomes (confirmed and failed). */
2643
+ event_count: number;
2644
+ /** Unpriced settled requests, counted separately: never in cost sums. */
2645
+ settled_count: number;
2646
+ usage: {
2647
+ input_tokens: number;
2648
+ output_tokens: number;
2649
+ cache_read_input_tokens: number;
2650
+ cache_creation_input_tokens: number;
2651
+ reasoning_tokens: number;
2652
+ };
2653
+ cost: {
2654
+ total_usd: string;
2655
+ nano_usd: number;
2656
+ };
2657
+ }
2658
+ /**
2659
+ * The states a request can be filtered by, which is more than the two a
2660
+ * caller usually thinks in: a request is `admitted` when it starts,
2661
+ * `confirmed` or `failed` when it ends, and `settled` once its cost is final.
2662
+ * `success` and `error` are the coarse outcome pair over those.
2663
+ */
2664
+ type SpendEventStatus = "success" | "error" | "admitted" | "confirmed" | "failed" | "settled";
2665
+ interface SpendSummariesPage {
2666
+ data: SpendSummaryRow[];
2667
+ /**
2668
+ * Pass back as `cursor` for the next page; null means the walk is done.
2669
+ * A full page does NOT mean there is more, so follow this until null
2670
+ * rather than stopping when a page comes back short.
2671
+ */
2672
+ next_cursor: string | null;
2673
+ }
2674
+ interface SpendEventsPage {
2675
+ data: SpendEvent[];
2676
+ next_cursor: string | null;
2677
+ }
2678
+ interface SpendReplayResult {
2679
+ endpoint_id: string;
2680
+ replay_id: string;
2681
+ replayed: number;
2682
+ window: {
2683
+ from: string;
2684
+ to: string;
2685
+ };
2686
+ }
2687
+ interface EndUserSpend {
2688
+ end_user_id: string;
2689
+ window: string;
2690
+ from: string;
2691
+ to: string;
2692
+ cost: {
2693
+ total_usd: string;
2694
+ nano_usd?: number;
2695
+ };
2696
+ request_count: number;
2697
+ usage: {
2698
+ input_tokens: number;
2699
+ output_tokens: number;
2700
+ cache_read_input_tokens: number;
2701
+ cache_creation_input_tokens: number;
2702
+ reasoning_tokens: number;
2703
+ };
2704
+ /**
2705
+ * The attributed-user template caps that apply to this end user, each
2706
+ * with its boundary-aware current-period spend. Empty when the
2707
+ * organization runs no templates; never null.
2708
+ */
2709
+ caps: EndUserCap[];
2710
+ }
2711
+ interface EndUserCap {
2712
+ budget_id: string;
2713
+ anchor_id: string;
2714
+ window: string;
2715
+ on_breach: "block" | "warn";
2716
+ limit_usd: string;
2717
+ spent_usd: string;
2718
+ period_started_at: string;
2719
+ }
2720
+ declare class SpendEventsApiError extends Error {
2721
+ readonly operation: string;
2722
+ readonly originalError?: unknown | undefined;
2723
+ constructor(message: string, operation: string, originalError?: unknown | undefined);
2724
+ }
2725
+ /**
2726
+ * Client for the gateway spend reconciliation surface (/api/gateway/v1).
2727
+ * Authenticates with an ORGANIZATION API key (sk-lw-*).
2728
+ *
2729
+ * Entity types mirror the wire verbatim, so their fields are lowercase
2730
+ * snake_case. Call options this SDK invents (query filters, per-call
2731
+ * behaviour, action arguments) are camelCase like the rest of the SDK.
2732
+ *
2733
+ * There is no project id here: `/spend-summaries` takes `project_id` as a
2734
+ * query filter rather than scoping on a header, so the project belongs to the
2735
+ * call, not to the client.
2736
+ *
2737
+ * Neither collection on this service offers an eager whole-set read. The
2738
+ * ledger is unbounded, and materialising a window of it is the very
2739
+ * under-counting and out-of-memory footgun the page docstrings warn about:
2740
+ * take pages, or stream with `iterate()` / `iterSummaries()`.
2741
+ */
2742
+ declare class SpendEventsApiService {
2743
+ private readonly endpoint;
2744
+ private readonly apiKey;
2745
+ constructor(config?: {
2746
+ endpoint?: string;
2747
+ apiKey?: string;
2748
+ });
2749
+ private request;
2750
+ /**
2751
+ * ONE page of the per-request spend ledger for a window. Pass `next_cursor`
2752
+ * back as `cursor` for the next page, verbatim.
2753
+ *
2754
+ * A full page does NOT mean there is more and a short page does NOT mean
2755
+ * there is no more: only a null cursor ends the walk. A reconciler that
2756
+ * stops on the first page silently under-counts the window, so read every
2757
+ * page or stream them with `iterate()`.
2758
+ */
2759
+ listPage(options: {
2760
+ /** Required: the pull is a ranged read by contract. */
2761
+ from: number;
2762
+ to: number;
2763
+ cursor?: string;
2764
+ limit?: number;
2765
+ virtualKeyId?: string;
2766
+ endUserId?: string;
2767
+ projectId?: string;
2768
+ model?: string;
2769
+ status?: SpendEventStatus;
2770
+ }): Promise<SpendEventsPage>;
2771
+ /**
2772
+ * Every spend event in the window, one row at a time, fetching each page
2773
+ * only when the consumer reaches it.
2774
+ *
2775
+ * This is how a reconciler reads a whole window without holding it: the
2776
+ * ledger is unbounded, so there is deliberately no eager `list()` to
2777
+ * collect it into an array. Raises rather than looping forever on a cursor
2778
+ * chain that never ends.
2779
+ */
2780
+ iterate(options: {
2781
+ /** Required: the pull is a ranged read by contract. */
2782
+ from: number;
2783
+ to: number;
2784
+ cursor?: string;
2785
+ limit?: number;
2786
+ virtualKeyId?: string;
2787
+ endUserId?: string;
2788
+ projectId?: string;
2789
+ model?: string;
2790
+ status?: SpendEventStatus;
2791
+ }): AsyncGenerator<SpendEvent>;
2792
+ /**
2793
+ * ONE page of per-key spend rollups for a window, paged by group key
2794
+ * ascending.
2795
+ *
2796
+ * The page is a step of a walk, not a whole answer: follow `next_cursor`
2797
+ * until it comes back null, or stream the walk with `iterSummaries()`. A
2798
+ * reconciler that reads only the first page silently under-counts every
2799
+ * tenant past the limit.
2800
+ */
2801
+ summariesPage(options: {
2802
+ groupBy: "virtual_key" | "end_user";
2803
+ from: number;
2804
+ to: number;
2805
+ projectId?: string;
2806
+ /** Narrow the rollup to one key, exact match. */
2807
+ virtualKeyId?: string;
2808
+ cursor?: string;
2809
+ limit?: number;
2810
+ }): Promise<SpendSummariesPage>;
2811
+ /**
2812
+ * Every rollup row for the window, one at a time, fetching each page only
2813
+ * when the consumer reaches it.
2814
+ *
2815
+ * The rollup has one row per tenant seen in the window, which no bound
2816
+ * covers, so there is deliberately no eager whole-set read here either: a
2817
+ * checksum that quietly covers part of the window is worse than none.
2818
+ */
2819
+ iterSummaries(options: {
2820
+ groupBy: "virtual_key" | "end_user";
2821
+ from: number;
2822
+ to: number;
2823
+ projectId?: string;
2824
+ /** Narrow the rollup to one key, exact match. */
2825
+ virtualKeyId?: string;
2826
+ cursor?: string;
2827
+ limit?: number;
2828
+ }): AsyncGenerator<SpendSummaryRow>;
2829
+ /**
2830
+ * Re-deliver a window's spend envelopes to ONE endpoint through the
2831
+ * normal delivery path. Envelope ids are unchanged (your consumer's
2832
+ * dedup key); mind your downstream billing system's finite dedup
2833
+ * window before replaying old ranges. The window is capped server-side
2834
+ * at 7 days per call.
2835
+ */
2836
+ replay(options: {
2837
+ from: number;
2838
+ to: number;
2839
+ endpointId: string;
2840
+ } & MutationOptions): Promise<SpendReplayResult>;
2841
+ endUserSpend(endUserId: string, options?: {
2842
+ window?: "day" | "week" | "month";
2843
+ from?: number;
2844
+ to?: number;
2845
+ virtualKeyId?: string;
2846
+ }): Promise<EndUserSpend>;
2847
+ }
2848
+
2849
+ interface WebhookEndpointSummary {
2850
+ id: string;
2851
+ url: string;
2852
+ max_batch_size: number;
2853
+ max_batch_delay_ms: number;
2854
+ max_in_flight: number;
2855
+ enabled_events: string[];
2856
+ status: "active" | "disabled";
2857
+ disabled_reason: string | null;
2858
+ disabled_at: string | null;
2859
+ failing_since: string | null;
2860
+ last_success_at: string | null;
2861
+ last_failure_at: string | null;
2862
+ created_at: string;
2863
+ updated_at: string;
2864
+ }
2865
+ interface WebhookEndpointWithSecret extends WebhookEndpointSummary {
2866
+ /** Present only on create and roll-secret responses; never again. */
2867
+ secret: string;
2868
+ }
2869
+ /** The POST body, exactly as the wire takes it. */
2870
+ interface CreateWebhookEndpointInput {
2871
+ url: string;
2872
+ enabled_events: string[];
2873
+ /** Envelopes per delivery. The receiver always gets an array. */
2874
+ max_batch_size?: number;
2875
+ /** How long a partial batch waits for company before it is sent. */
2876
+ max_batch_delay_ms?: number;
2877
+ /** Concurrent in-flight deliveries to this endpoint. */
2878
+ max_in_flight?: number;
2879
+ }
2880
+ /** The PATCH body, exactly as the wire takes it. Omitted fields are left alone. */
2881
+ interface UpdateWebhookEndpointInput {
2882
+ url?: string;
2883
+ enabled_events?: string[];
2884
+ status?: "active" | "disabled";
2885
+ max_batch_size?: number;
2886
+ max_batch_delay_ms?: number;
2887
+ max_in_flight?: number;
2888
+ }
2889
+ interface WebhookDeliveryRecord {
2890
+ id: string;
2891
+ dispatch_id: string;
2892
+ attempt: number;
2893
+ event_count: number;
2894
+ outcome: string;
2895
+ response_status: number | null;
2896
+ latency_ms: number | null;
2897
+ error: string | null;
2898
+ fired_at: string;
2899
+ }
2900
+ interface WebhookTestResult {
2901
+ delivered: boolean;
2902
+ response_status: number | null;
2903
+ response_body?: string;
2904
+ error?: string;
2905
+ }
2906
+ interface WebhookEndpointHealth {
2907
+ status: "active" | "disabled";
2908
+ disabled_reason: string | null;
2909
+ failing_since: string | null;
2910
+ last_success_at: string | null;
2911
+ last_failure_at: string | null;
2912
+ /** The headline: age of the oldest envelope still buffered or retrying;
2913
+ * null when the feed is fully delivered. */
2914
+ oldest_undelivered_age_ms: number | null;
2915
+ dlq_depth: number;
2916
+ sends_per_minute: number;
2917
+ success_rate: number | null;
2918
+ p95_latency_ms: number | null;
2919
+ }
2920
+ interface WebhookEventType {
2921
+ type: string;
2922
+ family: string;
2923
+ schema_version: string;
2924
+ is_emitting: boolean;
2925
+ description: string;
2926
+ }
2927
+ interface EmittedEvent {
2928
+ id: string;
2929
+ type: string;
2930
+ created: string;
2931
+ schema_version: string;
2932
+ data: Record<string, unknown>;
2933
+ }
2934
+ /** One page of the organization's emitted-events log. */
2935
+ interface EmittedEventsPage {
2936
+ data: EmittedEvent[];
2937
+ /** Pass back as `cursor` for the next page; null ends the walk. */
2938
+ next_cursor: string | null;
2939
+ }
2940
+ /** One page of an endpoint's delivery log, newest first. */
2941
+ interface WebhookDeliveryPage {
2942
+ data: WebhookDeliveryRecord[];
2943
+ /** Pass back as `cursor` for the next page; null ends the walk. */
2944
+ next_cursor: string | null;
2945
+ }
2946
+ declare class WebhooksApiError extends Error {
2947
+ readonly operation: string;
2948
+ readonly originalError?: unknown | undefined;
2949
+ constructor(message: string, operation: string, originalError?: unknown | undefined);
2950
+ }
2951
+ /**
2952
+ * Client for the org-anchored webhook platform surface (/api/webhooks/v1).
2953
+ * Authenticates with an ORGANIZATION API key (sk-lw-*); project keys are
2954
+ * rejected by the server. The surface is anchored on the organization alone,
2955
+ * so there is no project id to give this client.
2956
+ *
2957
+ * The endpoint entity and the create/update bodies mirror the wire verbatim,
2958
+ * so their fields are lowercase snake_case: virtual keys and gateway budgets
2959
+ * already take the wire body as it is, and translating field by field here
2960
+ * only made the request bodies of the four billing surfaces disagree. Call
2961
+ * options this SDK invents (query filters, per-call behaviour, action
2962
+ * arguments) stay camelCase like the rest of the SDK.
2963
+ */
2964
+ declare class WebhooksApiService {
2965
+ private readonly endpoint;
2966
+ private readonly apiKey;
2967
+ constructor(config?: {
2968
+ endpoint?: string;
2969
+ apiKey?: string;
2970
+ });
2971
+ private request;
2972
+ list(): Promise<WebhookEndpointSummary[]>;
2973
+ get(id: string): Promise<WebhookEndpointSummary>;
2974
+ /**
2975
+ * The signing secret comes back on this response and never again, so a
2976
+ * create that times out is recovered with `idempotencyKey`: the replay
2977
+ * carries the same secret, and nothing else ever will.
2978
+ */
2979
+ create(input: CreateWebhookEndpointInput, options?: IdempotentCreateOptions): Promise<WebhookEndpointWithSecret>;
2980
+ update(id: string, input: UpdateWebhookEndpointInput, options?: MutationOptions): Promise<WebhookEndpointSummary>;
2981
+ /**
2982
+ * Retire an endpoint: the server soft-archives the row, stamping
2983
+ * `archived_at` and dropping the status to disabled, so the delivery
2984
+ * history stays readable for audit while nothing more is ever sent. The
2985
+ * row is archived, not removed, and `gatewayBudgets.archive()` already
2986
+ * names that operation, so the billing surfaces agree on the verb.
2987
+ *
2988
+ * Nothing comes back: the response body carries only an `archived: true`
2989
+ * acknowledgement, and a non-2xx already raises.
2990
+ */
2991
+ archive(id: string, options?: MutationOptions): Promise<void>;
2992
+ rollSecret(id: string, options?: MutationOptions): Promise<WebhookEndpointWithSecret>;
2993
+ test(id: string, options?: MutationOptions): Promise<WebhookTestResult>;
2994
+ /**
2995
+ * ONE page of the endpoint's delivery attempts, newest first.
2996
+ *
2997
+ * The cursor is why this is a page: the route has always served one, and
2998
+ * dropping it truncated the delivery log at whatever the first page held,
2999
+ * with nothing in the result to say the rest existed. Pass `next_cursor`
3000
+ * back as `cursor`, or walk the whole log with `iterDeliveries()`.
3001
+ */
3002
+ deliveriesPage(id: string, options?: {
3003
+ cursor?: string;
3004
+ limit?: number;
3005
+ }): Promise<WebhookDeliveryPage>;
3006
+ /**
3007
+ * Every recorded delivery attempt for the endpoint, one at a time,
3008
+ * fetching each page only when the consumer reaches it.
3009
+ */
3010
+ iterDeliveries(id: string, options?: {
3011
+ cursor?: string;
3012
+ limit?: number;
3013
+ }): AsyncGenerator<WebhookDeliveryRecord>;
3014
+ health(id: string): Promise<WebhookEndpointHealth>;
3015
+ eventTypes(): Promise<WebhookEventType[]>;
3016
+ /**
3017
+ * ONE page of the organization's emitted-events log, newest first.
3018
+ *
3019
+ * Webhooks are a push over this log, never the only copy of it: a consumer
3020
+ * that missed a delivery reads the window back from here. Walk the whole
3021
+ * window with `iterEvents()`.
3022
+ */
3023
+ eventsPage(options?: {
3024
+ type?: string;
3025
+ from?: number;
3026
+ to?: number;
3027
+ cursor?: string;
3028
+ limit?: number;
3029
+ }): Promise<EmittedEventsPage>;
3030
+ /**
3031
+ * Every emitted event matching the filter, one at a time, fetching each
3032
+ * page only when the consumer reaches it.
3033
+ */
3034
+ iterEvents(options?: {
3035
+ type?: string;
3036
+ from?: number;
3037
+ to?: number;
3038
+ cursor?: string;
3039
+ limit?: number;
3040
+ }): AsyncGenerator<EmittedEvent>;
3041
+ /**
3042
+ * One emitted event by id, the envelope exactly as it was delivered.
3043
+ *
3044
+ * A 404 covers every reason the log cannot answer: never emitted, past the
3045
+ * retention horizon, or belonging to another organization.
3046
+ */
3047
+ getEvent(id: string): Promise<EmittedEvent>;
3048
+ }
3049
+
2067
3050
  interface GetTraceParams {
2068
3051
  includeSpans?: boolean;
2069
3052
  }
@@ -2135,6 +3118,10 @@ declare class LangWatch {
2135
3118
  readonly simulationRuns: SimulationRunsApiService;
2136
3119
  readonly monitors: MonitorsApiService;
2137
3120
  readonly secrets: SecretsApiService;
3121
+ readonly virtualKeys: VirtualKeysApiService;
3122
+ readonly gatewayBudgets: GatewayBudgetsApiService;
3123
+ readonly spendEvents: SpendEventsApiService;
3124
+ readonly webhooks: WebhooksApiService;
2138
3125
  constructor(options?: LangWatchConstructorOptions);
2139
3126
  get apiClient(): LangwatchApiClient;
2140
3127
  }
@@ -2236,9 +3223,142 @@ declare class LangWatchApiError extends Error {
2236
3223
  safeParseBody(response: Response): Promise<void>;
2237
3224
  }
2238
3225
 
3226
+ /**
3227
+ * Receiver-side verification of a LangWatch webhook delivery.
3228
+ *
3229
+ * Every delivery carries
3230
+ *
3231
+ * X-LangWatch-Signature: t=<unix seconds>,v1=<hex hmac-sha256>[,v1=<hex>]
3232
+ *
3233
+ * where each `v1` is HMAC-SHA256 over `"<t>.<raw body>"` under one currently
3234
+ * valid signing secret. `v1` REPEATS during a secret rotation, newest first,
3235
+ * which is what lets a receiver swap secrets on its own schedule instead of
3236
+ * dropping deliveries mid-swap.
3237
+ *
3238
+ * That repetition is the reason this helper exists. A hand-rolled parser that
3239
+ * keeps the LAST `v1` it sees, or splits the header into a flat key/value map,
3240
+ * rejects every delivery to a receiver that has already moved to the new
3241
+ * secret: the signature it kept is the one computed from the OLD secret. The
3242
+ * bug only appears during a rotation, which is exactly when a receiver can
3243
+ * least afford to be dropping deliveries.
3244
+ *
3245
+ * The algorithm here is pinned to the sender's by the vectors in
3246
+ * `specs/webhooks/signature-vectors.json`, generated from the server's own
3247
+ * signing code and asserted by the suite next to this file.
3248
+ */
3249
+ /** The header a delivery carries its signature in. */
3250
+ declare const WEBHOOK_SIGNATURE_HEADER = "X-LangWatch-Signature";
3251
+ /**
3252
+ * Identifies one delivery ATTEMPT on the webhook platform's endpoints.
3253
+ *
3254
+ * The natural idempotency key for a receiver: retries of the same batch repeat
3255
+ * it, so a receiver that has already processed this id can acknowledge and
3256
+ * stop rather than applying the batch twice.
3257
+ */
3258
+ declare const WEBHOOK_DELIVERY_ID_HEADER = "X-LangWatch-Delivery-Id";
3259
+ /**
3260
+ * The same role on automation deliveries (graph alerts and friends), which
3261
+ * group their attempts by the logical fire rather than by the batch.
3262
+ *
3263
+ * Two names because they are two senders: read whichever the delivery carries.
3264
+ */
3265
+ declare const WEBHOOK_EVENT_ID_HEADER = "X-LangWatch-Event-Id";
3266
+ /**
3267
+ * How far a delivery's timestamp may sit from the receiver's clock, in
3268
+ * seconds. Matches the sender's documented window.
3269
+ */
3270
+ declare const WEBHOOK_SIGNATURE_DEFAULT_TOLERANCE_SECONDS = 300;
3271
+ /**
3272
+ * Why a delivery was refused. Switch on this rather than on the message: the
3273
+ * message is written for a human reading a log and will change, the code is
3274
+ * the contract.
3275
+ *
3276
+ * The three mean genuinely different things to an operator. `stale_timestamp`
3277
+ * is a clock or a replay and is worth alerting on; `invalid_signature` is a
3278
+ * wrong secret or a tampered body; `malformed_header` is almost always
3279
+ * something other than LangWatch posting to the URL.
3280
+ */
3281
+ type WebhookSignatureFailureCode = "malformed_header" | "stale_timestamp" | "invalid_signature";
3282
+ /**
3283
+ * A delivery that did not verify.
3284
+ *
3285
+ * One class carrying a `code` rather than three classes, because the SDK and
3286
+ * the platform both ask callers to branch on a stable code instead of on the
3287
+ * error's identity, which does not survive a serialization boundary.
3288
+ */
3289
+ declare class WebhookSignatureVerificationError extends Error {
3290
+ readonly code: WebhookSignatureFailureCode;
3291
+ constructor(code: WebhookSignatureFailureCode, message: string);
3292
+ }
3293
+ interface VerifyWebhookSignatureOptions {
3294
+ /**
3295
+ * The EXACT bytes of the request body, as received.
3296
+ *
3297
+ * Not a parsed object, and not the result of re-serializing one: the digest
3298
+ * is over the bytes the sender hashed, and `JSON.parse` followed by
3299
+ * `JSON.stringify` reorders keys, drops insignificant whitespace and
3300
+ * re-escapes non-ASCII, any of which changes the digest. Read the raw body
3301
+ * before your framework's JSON middleware does.
3302
+ */
3303
+ body: string | Uint8Array;
3304
+ /** The `X-LangWatch-Signature` header value, verbatim. */
3305
+ header: string;
3306
+ /**
3307
+ * The signing secret, or every secret this receiver currently accepts.
3308
+ *
3309
+ * Pass both values during a rotation and the delivery verifies under
3310
+ * either, so there is no window where deliveries are refused.
3311
+ */
3312
+ secret: string | readonly string[];
3313
+ /**
3314
+ * Freshness window in seconds, defaulting to the sender's five minutes.
3315
+ * Tighten it only if your clocks are disciplined.
3316
+ */
3317
+ toleranceSeconds?: number;
3318
+ /**
3319
+ * The current time in unix SECONDS. Defaults to the system clock; pass it
3320
+ * to verify a delivery captured earlier, or from a test.
3321
+ */
3322
+ nowSeconds?: number;
3323
+ }
3324
+ /**
3325
+ * Verify a webhook delivery, or throw explaining which check failed.
3326
+ *
3327
+ * ```ts
3328
+ * app.post("/langwatch", express.raw({ type: "application/json" }), (req, res) => {
3329
+ * try {
3330
+ * verifyWebhookSignature({
3331
+ * body: req.body, // the raw Buffer, before JSON parsing
3332
+ * header: req.header("X-LangWatch-Signature") ?? "",
3333
+ * secret: [process.env.WEBHOOK_SECRET_NEW, process.env.WEBHOOK_SECRET_OLD],
3334
+ * });
3335
+ * } catch (error) {
3336
+ * return res.status(400).send((error as WebhookSignatureVerificationError).code);
3337
+ * }
3338
+ * // Trusted from here.
3339
+ * });
3340
+ * ```
3341
+ *
3342
+ * Throws rather than returning false so that a delivery cannot be trusted by
3343
+ * forgetting to check a return value. The thrown
3344
+ * {@link WebhookSignatureVerificationError} carries a
3345
+ * {@link WebhookSignatureFailureCode} saying which check failed.
3346
+ *
3347
+ * Checks run in a fixed order, so a delivery that is both stale and wrongly
3348
+ * signed reports the staleness: a header that did not parse has no
3349
+ * trustworthy timestamp to judge, and a timestamp outside the window makes
3350
+ * the digest moot.
3351
+ *
3352
+ * A missing or empty secret is a configuration mistake rather than a bad
3353
+ * delivery, and raises `TypeError`. Reporting it as a failed verification
3354
+ * would let a receiver that lost its secret quietly refuse every delivery as
3355
+ * if the sender were at fault.
3356
+ */
3357
+ declare function verifyWebhookSignature(options: VerifyWebhookSignatureOptions): void;
3358
+
2239
3359
  declare const logger: {
2240
3360
  ConsoleLogger: typeof ConsoleLogger;
2241
3361
  NoOpLogger: typeof NoOpLogger;
2242
3362
  };
2243
3363
 
2244
- export { type BatchCreateRecordsResponse, type CreateDatasetOptions, type CreateEvaluatorBody, type CreateFromUploadResponse, type Dataset, DatasetApiError, type DatasetColumnType, type DatasetEntry, DatasetError, type DatasetListItem, type DatasetMetadata, DatasetNotFoundError, DatasetPlanLimitError, type DatasetRecordResponse, DatasetValidationError, DatasetsFacade, type DeleteRecordsResponse, type EvaluateOptions, type EvaluationCost, EvaluationError, type EvaluationResult, type EvaluationStatus, EvaluationsApiError, EvaluationsFacade, EvaluatorCallError, EvaluatorError, type EvaluatorField, EvaluatorNotFoundError, type EvaluatorResponse, EvaluatorsApiError, EvaluatorsApiService, Experiment, ExperimentApiError, ExperimentError, type EvaluateOptions$1 as ExperimentEvaluateOptions, type EvaluationResult$1 as ExperimentEvaluationResult, type EvaluationStatus$1 as ExperimentEvaluationStatus, ExperimentInitError, type ExperimentInitOptions, type ExperimentRowResult, type ExperimentRunWithResults, ExperimentsFacade, FetchPolicy, type GetDatasetOptions, type GetPromptOptions, LangWatch, LangWatchApiError, LangWatchHandledError, type ListDatasetsApiResponse, type ListDatasetsOptions, type ListRecordsApiResponse, type ListRecordsOptions, type LogOptions, type PaginatedResponse, type Pagination, type RunCallback, type RunContext, type RunOptions, type RunWithResultsOptions, type TargetInfo, type TargetMetadata, TargetMetadataConflictError, type TargetType, type UpdateDatasetOptions, type UploadResponse, isLangWatchHandledError, logger };
3364
+ export { type BatchCreateRecordsResponse, type BudgetOnBreach, type BudgetScopeKind, type BudgetWindow, type CreateDatasetOptions, type CreateEvaluatorBody, type CreateFromUploadResponse, type CreateGatewayBudgetInput, type CreateGatewayBudgetScope, type CreateVirtualKeyInput, type CreateWebhookEndpointInput, type Dataset, DatasetApiError, type DatasetColumnType, type DatasetEntry, DatasetError, type DatasetListItem, type DatasetMetadata, DatasetNotFoundError, DatasetPlanLimitError, type DatasetRecordResponse, DatasetValidationError, DatasetsFacade, type DeleteRecordsResponse, type EmittedEvent, type EmittedEventsPage, type EndUserCap, type EndUserSpend, type EvaluateOptions, type EvaluationCost, EvaluationError, type EvaluationResult, type EvaluationStatus, EvaluationsApiError, EvaluationsFacade, EvaluatorCallError, EvaluatorError, type EvaluatorField, EvaluatorNotFoundError, type EvaluatorResponse, EvaluatorsApiError, EvaluatorsApiService, Experiment, ExperimentApiError, ExperimentError, type EvaluateOptions$1 as ExperimentEvaluateOptions, type EvaluationResult$1 as ExperimentEvaluationResult, type EvaluationStatus$1 as ExperimentEvaluationStatus, ExperimentInitError, type ExperimentInitOptions, type ExperimentRowResult, type ExperimentRunWithResults, ExperimentsFacade, FetchPolicy, type GatewayBudget, type GatewayBudgetPage, GatewayBudgetsApiError, GatewayBudgetsApiService, type GetDatasetOptions, type GetPromptOptions, IDEMPOTENCY_KEY_HEADER, IDEMPOTENT_REPLAY_HEADER, type IdempotentCreateOptions, LangWatch, LangWatchApiError, LangWatchHandledError, type ListDatasetsApiResponse, type ListDatasetsOptions, type ListRecordsApiResponse, type ListRecordsOptions, type LogOptions, type MutationOptions, type PaginatedResponse, type Pagination, type RunCallback, type RunContext, type RunOptions, type RunWithResultsOptions, type SpendEvent, type SpendEventStatus, SpendEventsApiError, SpendEventsApiService, type SpendEventsPage, type SpendReplayResult, type SpendSummariesPage, type SpendSummaryRow, type TargetInfo, type TargetMetadata, TargetMetadataConflictError, type TargetType, type UpdateDatasetOptions, type UpdateGatewayBudgetInput, type UpdateVirtualKeyInput, type UpdateWebhookEndpointInput, type UploadResponse, type VerifyWebhookSignatureOptions, type VirtualKey, type VirtualKeyBudgetInput, type VirtualKeyPage, type VirtualKeyRoutingMode, type VirtualKeyScope, type VirtualKeyScopeType, type VirtualKeySpendSummary, type VirtualKeyWithSecret, VirtualKeysApiError, VirtualKeysApiService, WEBHOOK_DELIVERY_ID_HEADER, WEBHOOK_EVENT_ID_HEADER, WEBHOOK_SIGNATURE_DEFAULT_TOLERANCE_SECONDS, WEBHOOK_SIGNATURE_HEADER, type WebhookDeliveryPage, type WebhookDeliveryRecord, type WebhookEndpointHealth, type WebhookEndpointSummary, type WebhookEndpointWithSecret, type WebhookEventType, type WebhookSignatureFailureCode, WebhookSignatureVerificationError, type WebhookTestResult, WebhooksApiError, WebhooksApiService, isLangWatchHandledError, logger, verifyWebhookSignature };