langwatch 1.1.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-Z7RP3LP5.js → chunk-DTSULVK5.js} +39 -19
  7. package/dist/chunk-DTSULVK5.js.map +1 -0
  8. package/dist/{chunk-5AGWTUI2.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-EW233MAD.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-R7NIGAEB.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 +263 -195
  22. package/dist/{implementation-DmWrukzX.d.mts → implementation-CHXrVq_q.d.mts} +1 -1
  23. package/dist/{implementation-Psro9xt4.d.ts → implementation-D_v0fUvU.d.ts} +1 -1
  24. package/dist/index.d.mts +1103 -205
  25. package/dist/index.d.ts +1103 -205
  26. package/dist/index.js +1240 -328
  27. package/dist/index.js.map +1 -1
  28. package/dist/index.mjs +1171 -259
  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-Ck1U3XCH.d.mts → types-DlP7QdqU.d.mts} +14811 -6210
  44. package/dist/{types-DGBGlP9B.d.ts → types-av2kmt_i.d.ts} +14811 -6210
  45. package/package.json +9 -10
  46. package/dist/chunk-5AGWTUI2.mjs.map +0 -1
  47. package/dist/chunk-EW233MAD.mjs.map +0 -1
  48. package/dist/chunk-IUSLT65Z.js.map +0 -1
  49. package/dist/chunk-PYODMDPV.mjs +0 -1005
  50. package/dist/chunk-PYODMDPV.mjs.map +0 -1
  51. package/dist/chunk-R7NIGAEB.js.map +0 -1
  52. package/dist/chunk-SCLFEMNK.js +0 -1005
  53. package/dist/chunk-SCLFEMNK.js.map +0 -1
  54. package/dist/chunk-TKSTXX3D.js.map +0 -1
  55. package/dist/chunk-Z7RP3LP5.js.map +0 -1
  56. /package/dist/{chunk-2O4ILSP5.mjs.map → chunk-LTDUROCE.mjs.map} +0 -0
package/dist/index.mjs CHANGED
@@ -1,15 +1,16 @@
1
1
  import {
2
2
  FilterableBatchSpanProcessor
3
- } from "./chunk-2O4ILSP5.mjs";
3
+ } from "./chunk-LTDUROCE.mjs";
4
4
  import {
5
5
  createLangWatchSpan,
6
+ external_exports,
6
7
  getLangWatchTracer
7
- } from "./chunk-PYODMDPV.mjs";
8
+ } from "./chunk-SYJIEBJY.mjs";
8
9
  import {
9
- ensureSetup
10
- } from "./chunk-EW233MAD.mjs";
10
+ ensureSetup,
11
+ resolveEndpoint
12
+ } from "./chunk-PDNXHBSL.mjs";
11
13
  import {
12
- DEFAULT_ENDPOINT,
13
14
  LANGWATCH_SDK_LANGUAGE,
14
15
  LANGWATCH_SDK_NAME_CLIENT,
15
16
  LANGWATCH_SDK_NAME_OBSERVABILITY,
@@ -19,10 +20,13 @@ import {
19
20
  buildAuthHeaders,
20
21
  getLangWatchLogger,
21
22
  version
22
- } from "./chunk-5AGWTUI2.mjs";
23
+ } from "./chunk-JYTJEAOU.mjs";
23
24
  import {
24
25
  ConsoleLogger,
25
26
  NoOpLogger,
27
+ __asyncGenerator,
28
+ __await,
29
+ __forAwait,
26
30
  __objRest,
27
31
  __privateAdd,
28
32
  __privateGet,
@@ -30,10 +34,11 @@ import {
30
34
  __privateSet,
31
35
  __spreadProps,
32
36
  __spreadValues,
37
+ __yieldStar,
33
38
  attributes_exports,
34
39
  shouldCaptureInput,
35
40
  shouldCaptureOutput
36
- } from "./chunk-L5KBRKHS.mjs";
41
+ } from "./chunk-CMZFFKLA.mjs";
37
42
 
38
43
  // src/internal/credentialContext.ts
39
44
  import { AsyncLocalStorage } from "async_hooks";
@@ -47,9 +52,6 @@ function scopedApiKey() {
47
52
  return currentHolder().apiKey;
48
53
  }
49
54
 
50
- // src/client-sdk/services/prompts/prompts-api.service.ts
51
- import { z } from "zod";
52
-
53
55
  // src/cli/utils/responseFormat.ts
54
56
  var DEFAULT_TEXT_OUTPUT = {
55
57
  identifier: "output",
@@ -393,7 +395,7 @@ var isBuiltInMethod = (prop) => {
393
395
  // src/internal/api/client.ts
394
396
  import openApiCreateClient from "openapi-fetch";
395
397
 
396
- // ../packages/langy/src/cards/handled-error.ts
398
+ // ../../packages/langy/src/cards/handled-error.ts
397
399
  var SERVER_ERROR_STATUS = 500;
398
400
  var GENERIC_CODES = /* @__PURE__ */ new Set([
399
401
  "internal server error",
@@ -655,9 +657,9 @@ var handledErrorMiddleware = {
655
657
  if (handledError) throw handledError;
656
658
  }
657
659
  };
658
- var createLangWatchApiClient = (apiKey = ((_b) => (_b = ((_a) => (_a = scopedApiKey()) != null ? _a : process.env.LANGWATCH_API_KEY)()) != null ? _b : "")(), endpoint = ((_c) => (_c = process.env.LANGWATCH_ENDPOINT) != null ? _c : DEFAULT_ENDPOINT)(), projectId = process.env.LANGWATCH_PROJECT_ID) => {
660
+ var createLangWatchApiClient = (apiKey = ((_b) => (_b = ((_a) => (_a = scopedApiKey()) != null ? _a : process.env.LANGWATCH_API_KEY)()) != null ? _b : "")(), endpoint, projectId = process.env.LANGWATCH_PROJECT_ID) => {
659
661
  const client = openApiCreateClient({
660
- baseUrl: endpoint,
662
+ baseUrl: resolveEndpoint(endpoint),
661
663
  headers: __spreadProps(__spreadValues({}, buildAuthHeaders({ apiKey, projectId })), {
662
664
  "content-type": "application/json",
663
665
  "user-agent": `langwatch-sdk-node/${version}`,
@@ -855,22 +857,22 @@ function extractStatusFromResponse(value) {
855
857
  }
856
858
 
857
859
  // src/client-sdk/services/prompts/prompts-api.service.ts
858
- var syncActionSchema = z.enum([
860
+ var syncActionSchema = external_exports.enum([
859
861
  "created",
860
862
  "updated",
861
863
  "conflict",
862
864
  "up_to_date"
863
865
  ]);
864
- var syncResultSchema = z.object({
866
+ var syncResultSchema = external_exports.object({
865
867
  action: syncActionSchema,
866
868
  // `prompt` and `conflictInfo` are passed through untyped — they come from
867
869
  // the OpenAPI-derived shape which is already validated on the server side.
868
- prompt: z.unknown().optional(),
869
- conflictInfo: z.object({
870
- localVersion: z.number(),
871
- remoteVersion: z.number(),
872
- differences: z.array(z.string()),
873
- remoteConfigData: z.unknown()
870
+ prompt: external_exports.unknown().optional(),
871
+ conflictInfo: external_exports.object({
872
+ localVersion: external_exports.number(),
873
+ remoteVersion: external_exports.number(),
874
+ differences: external_exports.array(external_exports.string()),
875
+ remoteConfigData: external_exports.unknown()
874
876
  }).passthrough().optional()
875
877
  });
876
878
  var PromptsApiService = class {
@@ -1171,9 +1173,6 @@ var PromptsApiService = class {
1171
1173
  // src/client-sdk/services/prompts/prompt.ts
1172
1174
  import { Liquid } from "liquidjs";
1173
1175
 
1174
- // src/client-sdk/services/prompts/schema/prompt.schema.ts
1175
- import { z as z2 } from "zod";
1176
-
1177
1176
  // src/client-sdk/services/prompts/constants.ts
1178
1177
  var PromptScope = {
1179
1178
  ORGANIZATION: "ORGANIZATION",
@@ -1181,34 +1180,34 @@ var PromptScope = {
1181
1180
  };
1182
1181
 
1183
1182
  // src/client-sdk/services/prompts/schema/prompt.schema.ts
1184
- var messageSchema = z2.object({
1185
- role: z2.enum(["user", "assistant", "system"]),
1186
- content: z2.string()
1183
+ var messageSchema = external_exports.object({
1184
+ role: external_exports.enum(["user", "assistant", "system"]),
1185
+ content: external_exports.string()
1187
1186
  });
1188
- var responseFormatSchema = z2.object({
1189
- type: z2.literal("json_schema"),
1190
- json_schema: z2.object({
1191
- name: z2.string(),
1192
- schema: z2.record(z2.string(), z2.unknown())
1187
+ var responseFormatSchema = external_exports.object({
1188
+ type: external_exports.literal("json_schema"),
1189
+ json_schema: external_exports.object({
1190
+ name: external_exports.string(),
1191
+ schema: external_exports.record(external_exports.string(), external_exports.unknown())
1193
1192
  }).nullable()
1194
1193
  }).optional();
1195
- var corePromptDataSchema = z2.object({
1196
- model: z2.string().min(1, "Model cannot be empty"),
1197
- messages: z2.array(messageSchema).min(1, "At least one message is required"),
1198
- prompt: z2.string().optional(),
1199
- temperature: z2.number().min(0).max(2).optional(),
1200
- maxTokens: z2.number().positive().optional(),
1194
+ var corePromptDataSchema = external_exports.object({
1195
+ model: external_exports.string().min(1, "Model cannot be empty"),
1196
+ messages: external_exports.array(messageSchema).min(1, "At least one message is required"),
1197
+ prompt: external_exports.string().optional(),
1198
+ temperature: external_exports.number().min(0).max(2).optional(),
1199
+ maxTokens: external_exports.number().positive().optional(),
1201
1200
  responseFormat: responseFormatSchema
1202
1201
  });
1203
- var promptMetadataSchema = z2.object({
1204
- id: z2.string().optional(),
1205
- handle: z2.string().nullable().optional(),
1206
- version: z2.number().min(0).optional(),
1207
- versionId: z2.string().optional(),
1208
- scope: z2.enum(PromptScope).optional()
1202
+ var promptMetadataSchema = external_exports.object({
1203
+ id: external_exports.string().optional(),
1204
+ handle: external_exports.string().nullable().optional(),
1205
+ version: external_exports.number().min(0).optional(),
1206
+ versionId: external_exports.string().optional(),
1207
+ scope: external_exports.enum(PromptScope).optional()
1209
1208
  });
1210
- var promptDataSchema = z2.object(__spreadProps(__spreadValues(__spreadValues({}, corePromptDataSchema.shape), promptMetadataSchema.shape), {
1211
- parameters: z2.record(z2.string(), z2.unknown()).optional()
1209
+ var promptDataSchema = external_exports.object(__spreadProps(__spreadValues(__spreadValues({}, corePromptDataSchema.shape), promptMetadataSchema.shape), {
1210
+ parameters: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
1212
1211
  }));
1213
1212
 
1214
1213
  // src/client-sdk/services/prompts/prompt.ts
@@ -1300,20 +1299,32 @@ import * as yaml from "js-yaml";
1300
1299
  import chalk from "chalk";
1301
1300
 
1302
1301
  // src/cli/types-prompt.ts
1303
- import { z as z3 } from "zod";
1304
- var localPromptConfigSchema = z3.object({
1305
- model: z3.string().min(1, "Model is required"),
1306
- modelParameters: z3.object({
1307
- temperature: z3.number().optional(),
1308
- max_tokens: z3.number().optional()
1302
+ var jsonValueSchema = external_exports.lazy(
1303
+ () => external_exports.union([
1304
+ external_exports.string(),
1305
+ external_exports.number(),
1306
+ external_exports.boolean(),
1307
+ external_exports.null(),
1308
+ external_exports.array(jsonValueSchema),
1309
+ external_exports.record(external_exports.string(), jsonValueSchema)
1310
+ ])
1311
+ );
1312
+ var localPromptConfigSchema = external_exports.object({
1313
+ model: external_exports.string().min(1, "Model is required"),
1314
+ modelParameters: external_exports.object({
1315
+ temperature: external_exports.number().optional(),
1316
+ max_tokens: external_exports.number().optional()
1309
1317
  }).loose().optional(),
1310
- messages: z3.array(
1311
- z3.object({
1312
- role: z3.enum(["system", "user", "assistant"]),
1313
- content: z3.string().min(1, "Message content cannot be empty")
1318
+ messages: external_exports.array(
1319
+ external_exports.object({
1320
+ role: external_exports.enum(["system", "user", "assistant"]),
1321
+ content: external_exports.string().min(1, "Message content cannot be empty")
1314
1322
  }).loose()
1315
1323
  ).min(1, "At least one message is required"),
1316
- parameters: z3.record(z3.string(), z3.unknown()).optional().default({})
1324
+ // Parameters persist as JSON: parse them AS json so the value's type
1325
+ // matches the API contract (the spec's recursive JsonValue) instead of
1326
+ // laundering unknowns into a typed pipeline.
1327
+ parameters: external_exports.record(external_exports.string(), jsonValueSchema).optional().default({})
1317
1328
  }).loose();
1318
1329
 
1319
1330
  // src/cli/utils/errors/prompt-not-found.error.ts
@@ -1875,7 +1886,7 @@ var tracer2 = getLangWatchTracer(`${LANGWATCH_SDK_NAME_CLIENT}.datasets`, LANGWA
1875
1886
  // src/client-sdk/services/datasets/dataset.service.ts
1876
1887
  var DatasetService = class {
1877
1888
  constructor(config) {
1878
- this.config = config;
1889
+ this.config = __spreadProps(__spreadValues({}, config), { endpoint: resolveEndpoint(config.endpoint) });
1879
1890
  return createTracingProxy(this, tracer2);
1880
1891
  }
1881
1892
  /**
@@ -2153,7 +2164,7 @@ var DatasetService = class {
2153
2164
  */
2154
2165
  async fetchMultipart(path2, formData, operation, slugOrId) {
2155
2166
  const { endpoint, apiKey } = this.config;
2156
- const url = `${endpoint.replace(/\/$/, "")}${path2}`;
2167
+ const url = `${endpoint}${path2}`;
2157
2168
  const response = await fetch(url, {
2158
2169
  method: "POST",
2159
2170
  headers: buildAuthHeaders({ apiKey }),
@@ -2730,7 +2741,7 @@ var Experiment = class _Experiment {
2730
2741
  this.experimentSlug = name;
2731
2742
  this.runId = (_a = options.runId) != null ? _a : generateHumanReadableId();
2732
2743
  this.apiClient = options.apiClient;
2733
- this.endpoint = options.endpoint;
2744
+ this.endpoint = resolveEndpoint(options.endpoint);
2734
2745
  this.apiKey = options.apiKey;
2735
2746
  this.logger = options.logger;
2736
2747
  this.concurrency = (_b = options.concurrency) != null ? _b : DEFAULT_CONCURRENCY;
@@ -2776,7 +2787,7 @@ var Experiment = class _Experiment {
2776
2787
  const data = await response.json();
2777
2788
  this.experimentSlug = data.slug;
2778
2789
  const encodedRunId = encodeURIComponent(this.runId);
2779
- this.runUrl = `${this.endpoint.replace(/\/$/, "")}${data.path}?runId=${encodedRunId}`;
2790
+ this.runUrl = `${this.endpoint}${data.path}?runId=${encodedRunId}`;
2780
2791
  console.log(`Follow results at: ${this.runUrl}`);
2781
2792
  this.initialized = true;
2782
2793
  } catch (error) {
@@ -4602,9 +4613,9 @@ var WorkflowsApiError = class extends Error {
4602
4613
  };
4603
4614
  var WorkflowsApiService = class {
4604
4615
  constructor(config) {
4605
- var _a, _b, _c;
4606
- this.apiClient = (_a = config == null ? void 0 : config.langwatchApiClient) != null ? _a : createLangWatchApiClient();
4607
- this.endpoint = (_c = (_b = config == null ? void 0 : config.endpoint) != null ? _b : process.env.LANGWATCH_ENDPOINT) != null ? _c : "https://app.langwatch.ai";
4616
+ var _a;
4617
+ this.endpoint = resolveEndpoint(config == null ? void 0 : config.endpoint);
4618
+ this.apiClient = (_a = config == null ? void 0 : config.langwatchApiClient) != null ? _a : createLangWatchApiClient(void 0, this.endpoint);
4608
4619
  this.experimentsApiService = new ExperimentsApiService({
4609
4620
  langwatchApiClient: this.apiClient
4610
4621
  });
@@ -5161,9 +5172,9 @@ var MonitorsApiError = class extends Error {
5161
5172
  };
5162
5173
  var MonitorsApiService = class {
5163
5174
  constructor(config) {
5164
- var _a, _b, _c, _d, _e;
5175
+ var _a, _b, _c;
5165
5176
  this.apiKey = (_c = (_b = (_a = config == null ? void 0 : config.apiKey) != null ? _a : scopedApiKey()) != null ? _b : process.env.LANGWATCH_API_KEY) != null ? _c : "";
5166
- this.endpoint = (_e = (_d = config == null ? void 0 : config.endpoint) != null ? _d : process.env.LANGWATCH_ENDPOINT) != null ? _e : DEFAULT_ENDPOINT;
5177
+ this.endpoint = resolveEndpoint(config == null ? void 0 : config.endpoint);
5167
5178
  }
5168
5179
  async request(path2, options) {
5169
5180
  var _a, _b;
@@ -5236,9 +5247,9 @@ var SecretsApiError = class extends Error {
5236
5247
  };
5237
5248
  var SecretsApiService = class {
5238
5249
  constructor(config) {
5239
- var _a, _b, _c, _d, _e;
5250
+ var _a, _b, _c;
5240
5251
  this.apiKey = (_c = (_b = (_a = config == null ? void 0 : config.apiKey) != null ? _a : scopedApiKey()) != null ? _b : process.env.LANGWATCH_API_KEY) != null ? _c : "";
5241
- this.endpoint = (_e = (_d = config == null ? void 0 : config.endpoint) != null ? _d : process.env.LANGWATCH_ENDPOINT) != null ? _e : DEFAULT_ENDPOINT;
5252
+ this.endpoint = resolveEndpoint(config == null ? void 0 : config.endpoint);
5242
5253
  }
5243
5254
  async request(path2, options) {
5244
5255
  var _a, _b;
@@ -5294,148 +5305,72 @@ var SecretsApiService = class {
5294
5305
  }
5295
5306
  };
5296
5307
 
5297
- // src/client-sdk/services/traces/types.ts
5298
- var TracesError = class extends Error {
5299
- constructor(message, operation, originalError) {
5300
- super(message);
5301
- this.operation = operation;
5302
- this.originalError = originalError;
5303
- this.name = "TracesError";
5304
- }
5305
- };
5306
-
5307
- // src/client-sdk/services/traces/tracing/tracer.ts
5308
- var tracer3 = getLangWatchTracer(`${LANGWATCH_SDK_NAME_CLIENT}.traces`, LANGWATCH_SDK_VERSION);
5309
-
5310
- // src/client-sdk/services/traces/service.ts
5311
- var TracesService = class {
5312
- constructor(config) {
5313
- this.config = config;
5314
- return createTracingProxy(
5315
- this,
5316
- tracer3
5317
- );
5318
- }
5319
- /**
5320
- * Handles API errors by throwing a TracesError with operation context.
5321
- * @param operation Description of the operation being performed.
5322
- * @param error The error object returned from the API client.
5323
- * @throws {TracesError}
5324
- */
5325
- handleApiError(operation, error) {
5326
- var _a, _b;
5327
- const errorMessage = typeof error === "string" ? error : (_b = (_a = error == null ? void 0 : error.error) != null ? _a : error == null ? void 0 : error.message) != null ? _b : "Unknown error occurred";
5328
- const message = `Failed to ${operation}: ${errorMessage}`;
5329
- throw new TracesError(
5330
- message,
5331
- operation,
5332
- error
5333
- );
5334
- }
5335
- /**
5336
- * Retrieves a trace by its ID.
5337
- * @param traceId The trace's unique identifier.
5338
- * @param params Optional parameters for the request.
5339
- * @returns The trace response object.
5340
- * @throws {TracesError} If the API call fails.
5341
- */
5342
- async get(traceId, params) {
5343
- const { data, error } = await this.config.langwatchApiClient.GET("/api/trace/{id}", {
5344
- params: {
5345
- path: {
5346
- id: traceId
5347
- }
5348
- },
5349
- query: params
5350
- });
5351
- if (error) {
5352
- this.handleApiError("get trace", error);
5308
+ // src/client-sdk/services/_shared/collect-cursor-pages.ts
5309
+ var CURSOR_WALK_PAGE_SIZE = 200;
5310
+ var MAX_CURSOR_WALK_PAGES = 1e3;
5311
+ function walkCursorPages(options) {
5312
+ return __asyncGenerator(this, null, function* () {
5313
+ var _a;
5314
+ const served = /* @__PURE__ */ new Set();
5315
+ let cursor = options.startCursor;
5316
+ let pagesRead = 0;
5317
+ for (; ; ) {
5318
+ const page = yield new __await(options.fetchPage(cursor));
5319
+ pagesRead += 1;
5320
+ yield page;
5321
+ const next = (_a = options.nextCursorOf(page)) != null ? _a : null;
5322
+ if (next === null) return;
5323
+ if (served.has(next)) {
5324
+ throw options.onEndlessWalk(
5325
+ "the endpoint served the same page cursor twice, so the walk cannot advance"
5326
+ );
5327
+ }
5328
+ if (pagesRead >= MAX_CURSOR_WALK_PAGES) {
5329
+ throw options.onEndlessWalk(
5330
+ `the walk passed ${MAX_CURSOR_WALK_PAGES} pages without the cursor coming back null`
5331
+ );
5332
+ }
5333
+ served.add(next);
5334
+ cursor = next;
5335
+ }
5336
+ });
5337
+ }
5338
+ async function collectCursorPages(options) {
5339
+ const pages = [];
5340
+ try {
5341
+ for (var iter = __forAwait(walkCursorPages(options)), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
5342
+ const page = temp.value;
5343
+ pages.push(page);
5344
+ }
5345
+ } catch (temp) {
5346
+ error = [temp];
5347
+ } finally {
5348
+ try {
5349
+ more && (temp = iter.return) && await temp.call(iter);
5350
+ } finally {
5351
+ if (error)
5352
+ throw error[0];
5353
5353
  }
5354
- return data;
5355
- }
5356
- };
5357
-
5358
- // src/client-sdk/services/traces/facade.ts
5359
- var _service;
5360
- var TracesFacade = class {
5361
- constructor(config) {
5362
- __privateAdd(this, _service);
5363
- __privateSet(this, _service, new TracesService(config));
5364
- }
5365
- async get(traceId, params) {
5366
- return __privateGet(this, _service).get(traceId, params);
5367
5354
  }
5368
- };
5369
- _service = new WeakMap();
5355
+ return pages;
5356
+ }
5370
5357
 
5371
- // src/client-sdk/index.ts
5372
- var _LangWatch_instances, createInternalConfig_fn;
5373
- var LangWatch = class {
5374
- constructor(options = {}) {
5375
- __privateAdd(this, _LangWatch_instances);
5376
- var _a, _b, _c, _d, _e;
5377
- const apiKey = (_c = (_b = (_a = options.apiKey) != null ? _a : scopedApiKey()) != null ? _b : process.env.LANGWATCH_API_KEY) != null ? _c : "";
5378
- const endpoint = (_e = (_d = options.endpoint) != null ? _d : process.env.LANGWATCH_ENDPOINT) != null ? _e : DEFAULT_ENDPOINT;
5379
- this.config = __privateMethod(this, _LangWatch_instances, createInternalConfig_fn).call(this, {
5380
- apiKey,
5381
- endpoint,
5382
- options: options.options
5383
- });
5384
- this.prompts = new PromptsFacade(__spreadValues({
5385
- promptsApiService: new PromptsApiService(this.config),
5386
- localPromptsService: new LocalPromptsService()
5387
- }, this.config));
5388
- this.traces = new TracesFacade(this.config);
5389
- this.experiments = new ExperimentsFacade({
5390
- langwatchApiClient: this.config.langwatchApiClient,
5391
- endpoint: this.config.endpoint,
5392
- apiKey: this.config.apiKey,
5393
- logger: this.config.logger
5394
- });
5395
- this.datasets = new DatasetsFacade({
5396
- langwatchApiClient: this.config.langwatchApiClient,
5397
- logger: this.config.logger,
5398
- endpoint: this.config.endpoint,
5399
- apiKey: this.config.apiKey
5400
- });
5401
- this.evaluations = new EvaluationsFacade({
5402
- endpoint: this.config.endpoint,
5403
- apiKey: this.config.apiKey,
5404
- logger: this.config.logger
5405
- });
5406
- this.evaluators = new EvaluatorsApiService(this.config);
5407
- this.scenarios = new ScenariosApiService(this.config);
5408
- this.suites = new SuitesApiService(this.config);
5409
- this.workflows = new WorkflowsApiService(this.config);
5410
- this.agents = new AgentsApiService(this.config);
5411
- this.annotations = new AnnotationsApiService(this.config);
5412
- this.dashboards = new DashboardsApiService(this.config);
5413
- this.modelProviders = new ModelProvidersApiService(this.config);
5414
- this.analytics = new AnalyticsApiService(this.config);
5415
- this.triggers = new TriggersApiService(this.config);
5416
- this.graphs = new GraphsApiService(this.config);
5417
- this.simulationRuns = new SimulationRunsApiService(this.config);
5418
- this.monitors = new MonitorsApiService({ apiKey, endpoint });
5419
- this.secrets = new SecretsApiService({ apiKey, endpoint });
5420
- }
5421
- get apiClient() {
5422
- return this.config.langwatchApiClient;
5423
- }
5424
- };
5425
- _LangWatch_instances = new WeakSet();
5426
- createInternalConfig_fn = function({
5427
- apiKey,
5428
- endpoint,
5429
- options
5430
- }) {
5431
- var _a;
5432
- return {
5433
- logger: (_a = options == null ? void 0 : options.logger) != null ? _a : new NoOpLogger(),
5434
- langwatchApiClient: createLangWatchApiClient(apiKey, endpoint),
5435
- endpoint,
5436
- apiKey
5437
- };
5438
- };
5358
+ // src/client-sdk/services/_shared/mutation-options.ts
5359
+ var IDEMPOTENCY_KEY_HEADER = "Idempotency-Key";
5360
+ var IDEMPOTENT_REPLAY_HEADER = "X-Idempotent-Replay";
5361
+ function mutationInit(options) {
5362
+ return (options == null ? void 0 : options.signal) ? { signal: options.signal } : {};
5363
+ }
5364
+ function idempotentCreateInit(options) {
5365
+ const onIdempotentReplay = options == null ? void 0 : options.onIdempotentReplay;
5366
+ return __spreadValues(__spreadValues(__spreadValues({}, mutationInit(options)), (options == null ? void 0 : options.idempotencyKey) !== void 0 ? { headers: { [IDEMPOTENCY_KEY_HEADER]: options.idempotencyKey } } : {}), onIdempotentReplay ? {
5367
+ onResponse: (response) => {
5368
+ if (response.headers.get(IDEMPOTENT_REPLAY_HEADER) === "true") {
5369
+ onIdempotentReplay();
5370
+ }
5371
+ }
5372
+ } : {});
5373
+ }
5439
5374
 
5440
5375
  // src/client-sdk/services/virtual-keys/virtual-keys-api.service.ts
5441
5376
  var VirtualKeysApiError = class extends Error {
@@ -5448,20 +5383,23 @@ var VirtualKeysApiError = class extends Error {
5448
5383
  };
5449
5384
  var VirtualKeysApiService = class {
5450
5385
  constructor(config) {
5451
- var _a, _b, _c, _d, _e;
5452
- this.endpoint = ((_b = (_a = config == null ? void 0 : config.endpoint) != null ? _a : process.env.LANGWATCH_ENDPOINT) != null ? _b : DEFAULT_ENDPOINT).replace(/\/+$/, "");
5453
- this.apiKey = (_e = (_d = (_c = config == null ? void 0 : config.apiKey) != null ? _c : scopedApiKey()) != null ? _d : process.env.LANGWATCH_API_KEY) != null ? _e : "";
5386
+ var _a, _b, _c, _d;
5387
+ this.endpoint = resolveEndpoint(config == null ? void 0 : config.endpoint);
5388
+ this.apiKey = (_c = (_b = (_a = config == null ? void 0 : config.apiKey) != null ? _a : scopedApiKey()) != null ? _b : process.env.LANGWATCH_API_KEY) != null ? _c : "";
5389
+ this.projectId = (_d = config == null ? void 0 : config.projectId) != null ? _d : process.env.LANGWATCH_PROJECT_ID;
5454
5390
  }
5455
5391
  headers() {
5456
- return {
5392
+ return __spreadValues({
5457
5393
  Authorization: `Bearer ${this.apiKey}`,
5458
5394
  "Content-Type": "application/json"
5459
- };
5395
+ }, this.projectId ? { "X-Project-Id": this.projectId } : {});
5460
5396
  }
5461
5397
  async request(operation, path2, init) {
5462
- var _a;
5398
+ var _a, _b, _c;
5463
5399
  const response = await fetch(`${this.endpoint}${path2}`, __spreadProps(__spreadValues({}, init), {
5464
- headers: __spreadValues(__spreadValues({}, this.headers()), (_a = init == null ? void 0 : init.headers) != null ? _a : {})
5400
+ // A hung control plane must fail the command, not freeze it.
5401
+ signal: (_a = init == null ? void 0 : init.signal) != null ? _a : AbortSignal.timeout(3e4),
5402
+ headers: __spreadValues(__spreadValues({}, this.headers()), (_b = init == null ? void 0 : init.headers) != null ? _b : {})
5465
5403
  }));
5466
5404
  if (!response.ok) {
5467
5405
  let parsedBody;
@@ -5483,14 +5421,100 @@ var VirtualKeysApiService = class {
5483
5421
  });
5484
5422
  throw new VirtualKeysApiError(message, operation, parsedBody);
5485
5423
  }
5424
+ (_c = init == null ? void 0 : init.onResponse) == null ? void 0 : _c.call(init, response);
5486
5425
  return await response.json();
5487
5426
  }
5488
- async list() {
5489
- const { data } = await this.request(
5490
- "list virtual keys",
5491
- "/api/gateway/v1/virtual-keys"
5492
- );
5493
- return data;
5427
+ /**
5428
+ * ONE page of the virtual keys visible to the caller, newest first. Pass
5429
+ * `next_cursor` back as `cursor` for the next page, verbatim: a cursor this
5430
+ * endpoint did not issue answers 400 rather than restarting the walk.
5431
+ *
5432
+ * `limit` is the page size (server default 50, capped at 200), and it caps
5433
+ * the rows READ, not the rows returned: the visibility filter runs on the
5434
+ * page afterwards. Prefer `list()` unless you mean to page deliberately.
5435
+ */
5436
+ async listPage(options) {
5437
+ const params = new URLSearchParams();
5438
+ if (options == null ? void 0 : options.externalId) params.set("external_id", options.externalId);
5439
+ if (options == null ? void 0 : options.cursor) params.set("cursor", options.cursor);
5440
+ if ((options == null ? void 0 : options.limit) !== void 0) params.set("limit", String(options.limit));
5441
+ const query = params.toString() !== "" ? `?${params.toString()}` : "";
5442
+ const { data, next_cursor } = await this.request("list virtual keys", `/api/gateway/v1/virtual-keys${query}`);
5443
+ return { data, next_cursor: next_cursor != null ? next_cursor : null };
5444
+ }
5445
+ /**
5446
+ * Every virtual key visible to the caller: keys scoped to this project, to
5447
+ * its team, or to the whole organization.
5448
+ *
5449
+ * The endpoint pages; this follows `next_cursor` until it comes back null.
5450
+ * Stopping on a short page would be wrong here specifically, because the
5451
+ * server filters each page for visibility after reading it, so a page can
5452
+ * hold fewer rows than the limit with more still to come.
5453
+ *
5454
+ * `limit` sizes each request in the walk, it does NOT cap what comes back.
5455
+ * `cursor` resumes an interrupted walk. Take a single page with
5456
+ * `listPage()`, or stream the walk with `iterate()`.
5457
+ */
5458
+ async list(options) {
5459
+ const pages = await collectCursorPages({
5460
+ startCursor: options == null ? void 0 : options.cursor,
5461
+ nextCursorOf: (page) => page.next_cursor,
5462
+ onEndlessWalk: (reason) => new VirtualKeysApiError(
5463
+ `Failed to list virtual keys: ${reason}.`,
5464
+ "list virtual keys"
5465
+ ),
5466
+ fetchPage: (cursor) => {
5467
+ var _a;
5468
+ return this.listPage({
5469
+ cursor,
5470
+ limit: (_a = options == null ? void 0 : options.limit) != null ? _a : CURSOR_WALK_PAGE_SIZE,
5471
+ externalId: options == null ? void 0 : options.externalId
5472
+ });
5473
+ }
5474
+ });
5475
+ return pages.flatMap((page) => page.data);
5476
+ }
5477
+ /**
5478
+ * Every visible virtual key, one row at a time, fetching each page only
5479
+ * when the consumer reaches it. Stop early and the rest is never read,
5480
+ * which `list()` cannot offer because it materialises the whole listing
5481
+ * first. Raises rather than looping forever on a cursor chain that never
5482
+ * ends, exactly like `list()`.
5483
+ */
5484
+ iterate(options) {
5485
+ return __asyncGenerator(this, null, function* () {
5486
+ const pages = walkCursorPages({
5487
+ startCursor: options == null ? void 0 : options.cursor,
5488
+ nextCursorOf: (page) => page.next_cursor,
5489
+ onEndlessWalk: (reason) => new VirtualKeysApiError(
5490
+ `Failed to list virtual keys: ${reason}.`,
5491
+ "list virtual keys"
5492
+ ),
5493
+ fetchPage: (cursor) => {
5494
+ var _a;
5495
+ return this.listPage({
5496
+ cursor,
5497
+ limit: (_a = options == null ? void 0 : options.limit) != null ? _a : CURSOR_WALK_PAGE_SIZE,
5498
+ externalId: options == null ? void 0 : options.externalId
5499
+ });
5500
+ }
5501
+ });
5502
+ try {
5503
+ for (var iter = __forAwait(pages), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
5504
+ const page = temp.value;
5505
+ yield* __yieldStar(page.data);
5506
+ }
5507
+ } catch (temp) {
5508
+ error = [temp];
5509
+ } finally {
5510
+ try {
5511
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
5512
+ } finally {
5513
+ if (error)
5514
+ throw error[0];
5515
+ }
5516
+ }
5517
+ });
5494
5518
  }
5495
5519
  async get(id) {
5496
5520
  const { virtual_key } = await this.request(
@@ -5499,45 +5523,75 @@ var VirtualKeysApiService = class {
5499
5523
  );
5500
5524
  return virtual_key;
5501
5525
  }
5502
- async create(input) {
5526
+ /**
5527
+ * Mint a key. The response carries the secret ONCE; nothing ever serves it
5528
+ * again, so a create that times out is recovered with `idempotencyKey`
5529
+ * rather than by listing.
5530
+ */
5531
+ async create(input, options) {
5503
5532
  return this.request(
5504
5533
  "create virtual key",
5505
5534
  "/api/gateway/v1/virtual-keys",
5506
- { method: "POST", body: JSON.stringify(input) }
5535
+ __spreadValues({
5536
+ method: "POST",
5537
+ body: JSON.stringify(input)
5538
+ }, idempotentCreateInit(options))
5507
5539
  );
5508
5540
  }
5509
- async update(id, input) {
5541
+ async update(id, input, options) {
5510
5542
  const { virtual_key } = await this.request(
5511
5543
  `update virtual key "${id}"`,
5512
5544
  `/api/gateway/v1/virtual-keys/${encodeURIComponent(id)}`,
5513
- { method: "PATCH", body: JSON.stringify(input) }
5545
+ __spreadValues({ method: "PATCH", body: JSON.stringify(input) }, mutationInit(options))
5514
5546
  );
5515
5547
  return virtual_key;
5516
5548
  }
5517
- async rotate(id) {
5549
+ async rotate(id, options) {
5518
5550
  return this.request(
5519
5551
  `rotate virtual key "${id}"`,
5520
5552
  `/api/gateway/v1/virtual-keys/${encodeURIComponent(id)}/rotate`,
5521
- { method: "POST" }
5553
+ __spreadValues({ method: "POST" }, mutationInit(options))
5522
5554
  );
5523
5555
  }
5524
- async revoke(id) {
5556
+ async revoke(id, options) {
5525
5557
  const { virtual_key } = await this.request(
5526
5558
  `revoke virtual key "${id}"`,
5527
5559
  `/api/gateway/v1/virtual-keys/${encodeURIComponent(id)}/revoke`,
5528
- { method: "POST" }
5560
+ __spreadValues({ method: "POST" }, mutationInit(options))
5561
+ );
5562
+ return virtual_key;
5563
+ }
5564
+ /** Reversible stop; enable() restores the key exactly as it was. */
5565
+ async disable(id, options = {}) {
5566
+ const { virtual_key } = await this.request(
5567
+ `disable virtual key "${id}"`,
5568
+ `/api/gateway/v1/virtual-keys/${encodeURIComponent(id)}/disable`,
5569
+ __spreadValues({
5570
+ method: "POST",
5571
+ headers: { "Content-Type": "application/json" },
5572
+ body: JSON.stringify(options.reason ? { reason: options.reason } : {})
5573
+ }, mutationInit(options))
5574
+ );
5575
+ return virtual_key;
5576
+ }
5577
+ async enable(id, options) {
5578
+ const { virtual_key } = await this.request(
5579
+ `enable virtual key "${id}"`,
5580
+ `/api/gateway/v1/virtual-keys/${encodeURIComponent(id)}/enable`,
5581
+ __spreadValues({ method: "POST" }, mutationInit(options))
5529
5582
  );
5530
5583
  return virtual_key;
5531
5584
  }
5532
5585
  /**
5533
- * Aggregate spend for one key. Defaults to the current UTC calendar
5534
- * month server-side. Reads the same cost path the dashboard reads, so
5535
- * this number and the UI agree by construction.
5586
+ * Aggregate spend for one key over a window in epoch milliseconds.
5587
+ * Defaults to the current UTC calendar month server-side. Reads the same
5588
+ * cost path the dashboard reads, so this number and the UI agree by
5589
+ * construction.
5536
5590
  */
5537
- async spend(id, window) {
5591
+ async spend(id, options) {
5538
5592
  const params = new URLSearchParams();
5539
- if (window == null ? void 0 : window.from) params.set("from", window.from);
5540
- if (window == null ? void 0 : window.to) params.set("to", window.to);
5593
+ if ((options == null ? void 0 : options.from) !== void 0) params.set("from", String(options.from));
5594
+ if ((options == null ? void 0 : options.to) !== void 0) params.set("to", String(options.to));
5541
5595
  const query = params.size > 0 ? `?${params.toString()}` : "";
5542
5596
  return this.request(
5543
5597
  `read virtual key spend "${id}"`,
@@ -5557,20 +5611,23 @@ var GatewayBudgetsApiError = class extends Error {
5557
5611
  };
5558
5612
  var GatewayBudgetsApiService = class {
5559
5613
  constructor(config) {
5560
- var _a, _b, _c, _d, _e;
5561
- this.endpoint = ((_b = (_a = config == null ? void 0 : config.endpoint) != null ? _a : process.env.LANGWATCH_ENDPOINT) != null ? _b : DEFAULT_ENDPOINT).replace(/\/+$/, "");
5562
- this.apiKey = (_e = (_d = (_c = config == null ? void 0 : config.apiKey) != null ? _c : scopedApiKey()) != null ? _d : process.env.LANGWATCH_API_KEY) != null ? _e : "";
5614
+ var _a, _b, _c, _d;
5615
+ this.endpoint = resolveEndpoint(config == null ? void 0 : config.endpoint);
5616
+ this.apiKey = (_c = (_b = (_a = config == null ? void 0 : config.apiKey) != null ? _a : scopedApiKey()) != null ? _b : process.env.LANGWATCH_API_KEY) != null ? _c : "";
5617
+ this.projectId = (_d = config == null ? void 0 : config.projectId) != null ? _d : process.env.LANGWATCH_PROJECT_ID;
5563
5618
  }
5564
5619
  headers() {
5565
- return {
5620
+ return __spreadValues({
5566
5621
  Authorization: `Bearer ${this.apiKey}`,
5567
5622
  "Content-Type": "application/json"
5568
- };
5623
+ }, this.projectId ? { "X-Project-Id": this.projectId } : {});
5569
5624
  }
5570
5625
  async request(operation, path2, init) {
5571
- var _a;
5626
+ var _a, _b, _c;
5572
5627
  const response = await fetch(`${this.endpoint}${path2}`, __spreadProps(__spreadValues({}, init), {
5573
- headers: __spreadValues(__spreadValues({}, this.headers()), (_a = init == null ? void 0 : init.headers) != null ? _a : {})
5628
+ // A hung control plane must fail the command, not freeze it.
5629
+ signal: (_a = init == null ? void 0 : init.signal) != null ? _a : AbortSignal.timeout(3e4),
5630
+ headers: __spreadValues(__spreadValues({}, this.headers()), (_b = init == null ? void 0 : init.headers) != null ? _b : {})
5574
5631
  }));
5575
5632
  if (!response.ok) {
5576
5633
  let parsedBody;
@@ -5592,44 +5649,887 @@ var GatewayBudgetsApiService = class {
5592
5649
  });
5593
5650
  throw new GatewayBudgetsApiError(message, operation, parsedBody);
5594
5651
  }
5652
+ (_c = init == null ? void 0 : init.onResponse) == null ? void 0 : _c.call(init, response);
5595
5653
  return await response.json();
5596
5654
  }
5597
5655
  /**
5598
- * Every non-archived budget in the organization across all six scope
5656
+ * ONE page of non-archived budgets, exactly as the wire serves it. Pass
5657
+ * `next_cursor` back as `cursor` for the next page, verbatim: a cursor this
5658
+ * endpoint did not issue answers 400 rather than restarting the walk.
5659
+ *
5660
+ * `limit` is the page size (server default 50, capped at 200). Prefer
5661
+ * `list()` unless you mean to page deliberately: a full page is not a
5662
+ * promise of more, and a null `next_cursor` is the only end of the walk.
5663
+ */
5664
+ async listPage(options) {
5665
+ var _a;
5666
+ const params = new URLSearchParams();
5667
+ if (options == null ? void 0 : options.externalId) params.set("external_id", options.externalId);
5668
+ if ((_a = options == null ? void 0 : options.scopeTypes) == null ? void 0 : _a.length) {
5669
+ params.set("scope_type", options.scopeTypes.join(","));
5670
+ }
5671
+ if (options == null ? void 0 : options.cursor) params.set("cursor", options.cursor);
5672
+ if ((options == null ? void 0 : options.limit) !== void 0) params.set("limit", String(options.limit));
5673
+ const query = params.toString() !== "" ? `?${params.toString()}` : "";
5674
+ const { data, spend_available, next_cursor } = await this.request("list gateway budgets", `/api/gateway/v1/budgets${query}`);
5675
+ return {
5676
+ data,
5677
+ spend_available,
5678
+ next_cursor: next_cursor != null ? next_cursor : null
5679
+ };
5680
+ }
5681
+ /**
5682
+ * Every non-archived budget in the organization across all seven scope
5599
5683
  * types, optionally filtered by `scopeTypes`.
5684
+ *
5685
+ * The endpoint pages; this follows `next_cursor` until it comes back null,
5686
+ * so the result is the complete listing and carries no cursor of its own.
5687
+ * Callers that count, total, or decide an all-clear on this list need that
5688
+ * completeness for correctness, not just for display.
5689
+ *
5690
+ * `limit` sizes each request in the walk, it does NOT cap what comes back.
5691
+ * `cursor` resumes an interrupted walk. Take a single page with
5692
+ * `listPage()`, or stream the walk with `iterate()`.
5693
+ *
5694
+ * A plain array, like every other exhaustive `list()` in the SDK: a walk
5695
+ * that ran to the end has no cursor left to report. Null `spent_usd` /
5696
+ * `spent_nano_usd` on a row is not by itself "spend unavailable": an
5697
+ * `attributed_user` template row serves null deliberately, because one
5698
+ * allowance per person has no single total. Use `listPage()` when you need
5699
+ * `spend_available` stated outright.
5600
5700
  */
5601
5701
  async list(options) {
5602
- var _a;
5603
- const filter = ((_a = options == null ? void 0 : options.scopeTypes) == null ? void 0 : _a.length) ? `?scope_type=${options.scopeTypes.join(",")}` : "";
5604
- const { data, spend_available } = await this.request("list gateway budgets", `/api/gateway/v1/budgets${filter}`);
5605
- return { budgets: data, spend_available };
5702
+ const pages = await collectCursorPages({
5703
+ startCursor: options == null ? void 0 : options.cursor,
5704
+ nextCursorOf: (page) => page.next_cursor,
5705
+ onEndlessWalk: (reason) => new GatewayBudgetsApiError(
5706
+ `Failed to list gateway budgets: ${reason}.`,
5707
+ "list gateway budgets"
5708
+ ),
5709
+ fetchPage: (cursor) => {
5710
+ var _a;
5711
+ return this.listPage({
5712
+ scopeTypes: options == null ? void 0 : options.scopeTypes,
5713
+ cursor,
5714
+ limit: (_a = options == null ? void 0 : options.limit) != null ? _a : CURSOR_WALK_PAGE_SIZE,
5715
+ externalId: options == null ? void 0 : options.externalId
5716
+ });
5717
+ }
5718
+ });
5719
+ return pages.flatMap((page) => page.data);
5606
5720
  }
5607
- async create(input) {
5608
- const { budget } = await this.request(
5609
- "create gateway budget",
5610
- "/api/gateway/v1/budgets",
5611
- { method: "POST", body: JSON.stringify(input) }
5612
- );
5613
- return budget;
5721
+ /**
5722
+ * Every non-archived budget, one row at a time, fetching each page only
5723
+ * when the consumer reaches it.
5724
+ *
5725
+ * A null `spent_usd` means spend could not be totalled rather than that
5726
+ * nothing was spent.
5727
+ */
5728
+ iterate(options) {
5729
+ return __asyncGenerator(this, null, function* () {
5730
+ const pages = walkCursorPages({
5731
+ startCursor: options == null ? void 0 : options.cursor,
5732
+ nextCursorOf: (page) => page.next_cursor,
5733
+ onEndlessWalk: (reason) => new GatewayBudgetsApiError(
5734
+ `Failed to list gateway budgets: ${reason}.`,
5735
+ "list gateway budgets"
5736
+ ),
5737
+ fetchPage: (cursor) => {
5738
+ var _a;
5739
+ return this.listPage({
5740
+ scopeTypes: options == null ? void 0 : options.scopeTypes,
5741
+ cursor,
5742
+ limit: (_a = options == null ? void 0 : options.limit) != null ? _a : CURSOR_WALK_PAGE_SIZE,
5743
+ externalId: options == null ? void 0 : options.externalId
5744
+ });
5745
+ }
5746
+ });
5747
+ try {
5748
+ for (var iter = __forAwait(pages), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
5749
+ const page = temp.value;
5750
+ yield* __yieldStar(page.data);
5751
+ }
5752
+ } catch (temp) {
5753
+ error = [temp];
5754
+ } finally {
5755
+ try {
5756
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
5757
+ } finally {
5758
+ if (error)
5759
+ throw error[0];
5760
+ }
5761
+ }
5762
+ });
5614
5763
  }
5615
- async update(id, input) {
5616
- const { budget } = await this.request(
5764
+ /**
5765
+ * One budget by id, in the same row shape the listing serves.
5766
+ *
5767
+ * Archived budgets are not served, so a budget that existed yesterday can
5768
+ * answer 404 today. A null `spent_usd` means spend could not be totalled
5769
+ * rather than that nothing was spent, which is the same signal the listing
5770
+ * carries as `spend_available`.
5771
+ */
5772
+ async get(id) {
5773
+ const { budget } = await this.request(
5774
+ `get gateway budget "${id}"`,
5775
+ `/api/gateway/v1/budgets/${encodeURIComponent(id)}`
5776
+ );
5777
+ return budget;
5778
+ }
5779
+ async create(input, options) {
5780
+ const { budget } = await this.request(
5781
+ "create gateway budget",
5782
+ "/api/gateway/v1/budgets",
5783
+ __spreadValues({
5784
+ method: "POST",
5785
+ body: JSON.stringify(input)
5786
+ }, idempotentCreateInit(options))
5787
+ );
5788
+ return budget;
5789
+ }
5790
+ async update(id, input, options) {
5791
+ const { budget } = await this.request(
5617
5792
  `update gateway budget "${id}"`,
5618
5793
  `/api/gateway/v1/budgets/${encodeURIComponent(id)}`,
5619
- { method: "PATCH", body: JSON.stringify(input) }
5794
+ __spreadValues({ method: "PATCH", body: JSON.stringify(input) }, mutationInit(options))
5620
5795
  );
5621
5796
  return budget;
5622
5797
  }
5623
- async archive(id) {
5798
+ async archive(id, options) {
5624
5799
  const { budget } = await this.request(
5625
5800
  `archive gateway budget "${id}"`,
5626
5801
  `/api/gateway/v1/budgets/${encodeURIComponent(id)}`,
5627
- { method: "DELETE" }
5802
+ __spreadValues({ method: "DELETE" }, mutationInit(options))
5803
+ );
5804
+ return budget;
5805
+ }
5806
+ /**
5807
+ * Move the budget's period boundary to now. Recorded spend is never
5808
+ * mutated; with `endUserId` only that end-user bucket's boundary moves.
5809
+ */
5810
+ async reset(id, options = {}) {
5811
+ const query = options.endUserId ? `?end_user_id=${encodeURIComponent(options.endUserId)}` : "";
5812
+ const { budget } = await this.request(
5813
+ `reset gateway budget "${id}"`,
5814
+ `/api/gateway/v1/budgets/${encodeURIComponent(id)}/reset${query}`,
5815
+ __spreadValues({
5816
+ method: "POST",
5817
+ headers: { "Content-Type": "application/json" },
5818
+ body: JSON.stringify(options.reason ? { reason: options.reason } : {})
5819
+ }, mutationInit(options))
5628
5820
  );
5629
5821
  return budget;
5630
5822
  }
5631
5823
  };
5632
5824
 
5825
+ // src/client-sdk/services/spend-events/spend-events-api.service.ts
5826
+ var SpendEventsApiError = class extends Error {
5827
+ constructor(message, operation, originalError) {
5828
+ super(message);
5829
+ this.operation = operation;
5830
+ this.originalError = originalError;
5831
+ this.name = "SpendEventsApiError";
5832
+ }
5833
+ };
5834
+ var SpendEventsApiService = class {
5835
+ constructor(config) {
5836
+ var _a, _b, _c;
5837
+ this.endpoint = resolveEndpoint(config == null ? void 0 : config.endpoint);
5838
+ this.apiKey = (_c = (_b = (_a = config == null ? void 0 : config.apiKey) != null ? _a : scopedApiKey()) != null ? _b : process.env.LANGWATCH_API_KEY) != null ? _c : "";
5839
+ }
5840
+ async request(operation, path2, init) {
5841
+ var _a, _b;
5842
+ const response = await fetch(`${this.endpoint}${path2}`, __spreadProps(__spreadValues({}, init), {
5843
+ // A hung control plane must fail the command, not freeze it.
5844
+ signal: (_a = init == null ? void 0 : init.signal) != null ? _a : AbortSignal.timeout(3e4),
5845
+ headers: __spreadValues({
5846
+ Authorization: `Bearer ${this.apiKey}`,
5847
+ "Content-Type": "application/json"
5848
+ }, (_b = init == null ? void 0 : init.headers) != null ? _b : {})
5849
+ }));
5850
+ if (!response.ok) {
5851
+ let parsedBody;
5852
+ try {
5853
+ parsedBody = await response.json();
5854
+ } catch (e) {
5855
+ parsedBody = await response.text();
5856
+ }
5857
+ const message = formatApiErrorForOperation({
5858
+ operation,
5859
+ error: parsedBody,
5860
+ options: { status: response.status }
5861
+ });
5862
+ throwIfHandledError({
5863
+ operation,
5864
+ error: parsedBody,
5865
+ status: response.status,
5866
+ message
5867
+ });
5868
+ throw new SpendEventsApiError(message, operation, parsedBody);
5869
+ }
5870
+ return await response.json();
5871
+ }
5872
+ /**
5873
+ * ONE page of the per-request spend ledger for a window. Pass `next_cursor`
5874
+ * back as `cursor` for the next page, verbatim.
5875
+ *
5876
+ * A full page does NOT mean there is more and a short page does NOT mean
5877
+ * there is no more: only a null cursor ends the walk. A reconciler that
5878
+ * stops on the first page silently under-counts the window, so read every
5879
+ * page or stream them with `iterate()`.
5880
+ */
5881
+ async listPage(options) {
5882
+ const params = new URLSearchParams();
5883
+ params.set("from", String(options.from));
5884
+ params.set("to", String(options.to));
5885
+ if (options.cursor) params.set("cursor", options.cursor);
5886
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
5887
+ if (options.virtualKeyId) params.set("virtual_key_id", options.virtualKeyId);
5888
+ if (options.endUserId) params.set("end_user_id", options.endUserId);
5889
+ if (options.projectId) params.set("project_id", options.projectId);
5890
+ if (options.model) params.set("model", options.model);
5891
+ if (options.status) params.set("status", options.status);
5892
+ const qs = params.toString() !== "" ? `?${params.toString()}` : "";
5893
+ return await this.request(
5894
+ "list spend events",
5895
+ `/api/gateway/v1/spend-events${qs}`
5896
+ );
5897
+ }
5898
+ /**
5899
+ * Every spend event in the window, one row at a time, fetching each page
5900
+ * only when the consumer reaches it.
5901
+ *
5902
+ * This is how a reconciler reads a whole window without holding it: the
5903
+ * ledger is unbounded, so there is deliberately no eager `list()` to
5904
+ * collect it into an array. Raises rather than looping forever on a cursor
5905
+ * chain that never ends.
5906
+ */
5907
+ iterate(options) {
5908
+ return __asyncGenerator(this, null, function* () {
5909
+ const pages = walkCursorPages({
5910
+ startCursor: options.cursor,
5911
+ nextCursorOf: (page) => page.next_cursor,
5912
+ onEndlessWalk: (reason) => new SpendEventsApiError(
5913
+ `Failed to list spend events: ${reason}.`,
5914
+ "list spend events"
5915
+ ),
5916
+ fetchPage: (cursor) => {
5917
+ var _a;
5918
+ return this.listPage(__spreadProps(__spreadValues({}, options), {
5919
+ cursor,
5920
+ limit: (_a = options.limit) != null ? _a : CURSOR_WALK_PAGE_SIZE
5921
+ }));
5922
+ }
5923
+ });
5924
+ try {
5925
+ for (var iter = __forAwait(pages), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
5926
+ const page = temp.value;
5927
+ yield* __yieldStar(page.data);
5928
+ }
5929
+ } catch (temp) {
5930
+ error = [temp];
5931
+ } finally {
5932
+ try {
5933
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
5934
+ } finally {
5935
+ if (error)
5936
+ throw error[0];
5937
+ }
5938
+ }
5939
+ });
5940
+ }
5941
+ /**
5942
+ * ONE page of per-key spend rollups for a window, paged by group key
5943
+ * ascending.
5944
+ *
5945
+ * The page is a step of a walk, not a whole answer: follow `next_cursor`
5946
+ * until it comes back null, or stream the walk with `iterSummaries()`. A
5947
+ * reconciler that reads only the first page silently under-counts every
5948
+ * tenant past the limit.
5949
+ */
5950
+ async summariesPage(options) {
5951
+ const params = new URLSearchParams();
5952
+ params.set("group_by", options.groupBy);
5953
+ params.set("from", String(options.from));
5954
+ params.set("to", String(options.to));
5955
+ if (options.projectId) params.set("project_id", options.projectId);
5956
+ if (options.virtualKeyId)
5957
+ params.set("virtual_key_id", options.virtualKeyId);
5958
+ if (options.cursor) params.set("cursor", options.cursor);
5959
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
5960
+ return await this.request(
5961
+ "read spend summaries",
5962
+ `/api/gateway/v1/spend-summaries?${params.toString()}`
5963
+ );
5964
+ }
5965
+ /**
5966
+ * Every rollup row for the window, one at a time, fetching each page only
5967
+ * when the consumer reaches it.
5968
+ *
5969
+ * The rollup has one row per tenant seen in the window, which no bound
5970
+ * covers, so there is deliberately no eager whole-set read here either: a
5971
+ * checksum that quietly covers part of the window is worse than none.
5972
+ */
5973
+ iterSummaries(options) {
5974
+ return __asyncGenerator(this, null, function* () {
5975
+ const pages = walkCursorPages({
5976
+ startCursor: options.cursor,
5977
+ nextCursorOf: (page) => page.next_cursor,
5978
+ onEndlessWalk: (reason) => new SpendEventsApiError(
5979
+ `Failed to read spend summaries: ${reason}.`,
5980
+ "read spend summaries"
5981
+ ),
5982
+ fetchPage: (cursor) => {
5983
+ var _a;
5984
+ return this.summariesPage(__spreadProps(__spreadValues({}, options), {
5985
+ cursor,
5986
+ limit: (_a = options.limit) != null ? _a : CURSOR_WALK_PAGE_SIZE
5987
+ }));
5988
+ }
5989
+ });
5990
+ try {
5991
+ for (var iter = __forAwait(pages), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
5992
+ const page = temp.value;
5993
+ yield* __yieldStar(page.data);
5994
+ }
5995
+ } catch (temp) {
5996
+ error = [temp];
5997
+ } finally {
5998
+ try {
5999
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
6000
+ } finally {
6001
+ if (error)
6002
+ throw error[0];
6003
+ }
6004
+ }
6005
+ });
6006
+ }
6007
+ /**
6008
+ * Re-deliver a window's spend envelopes to ONE endpoint through the
6009
+ * normal delivery path. Envelope ids are unchanged (your consumer's
6010
+ * dedup key); mind your downstream billing system's finite dedup
6011
+ * window before replaying old ranges. The window is capped server-side
6012
+ * at 7 days per call.
6013
+ */
6014
+ async replay(options) {
6015
+ const response = await this.request(
6016
+ "replay spend events",
6017
+ "/api/gateway/v1/spend-events/replay",
6018
+ __spreadValues({
6019
+ method: "POST",
6020
+ body: JSON.stringify({
6021
+ from: options.from,
6022
+ to: options.to,
6023
+ endpoint_id: options.endpointId
6024
+ })
6025
+ }, mutationInit(options))
6026
+ );
6027
+ return response.data;
6028
+ }
6029
+ async endUserSpend(endUserId, options) {
6030
+ const params = new URLSearchParams();
6031
+ if (options == null ? void 0 : options.window) params.set("window", options.window);
6032
+ if ((options == null ? void 0 : options.from) !== void 0) params.set("from", String(options.from));
6033
+ if ((options == null ? void 0 : options.to) !== void 0) params.set("to", String(options.to));
6034
+ if (options == null ? void 0 : options.virtualKeyId) params.set("virtual_key_id", options.virtualKeyId);
6035
+ const qs = params.toString() !== "" ? `?${params.toString()}` : "";
6036
+ const res = await this.request(
6037
+ "read end-user spend",
6038
+ `/api/gateway/v1/end-users/${encodeURIComponent(endUserId)}/spend${qs}`
6039
+ );
6040
+ return res.data;
6041
+ }
6042
+ };
6043
+
6044
+ // src/client-sdk/services/webhooks/webhooks-api.service.ts
6045
+ var WebhooksApiError = class extends Error {
6046
+ constructor(message, operation, originalError) {
6047
+ super(message);
6048
+ this.operation = operation;
6049
+ this.originalError = originalError;
6050
+ this.name = "WebhooksApiError";
6051
+ }
6052
+ };
6053
+ var WebhooksApiService = class {
6054
+ constructor(config) {
6055
+ var _a, _b, _c;
6056
+ this.endpoint = resolveEndpoint(config == null ? void 0 : config.endpoint);
6057
+ this.apiKey = (_c = (_b = (_a = config == null ? void 0 : config.apiKey) != null ? _a : scopedApiKey()) != null ? _b : process.env.LANGWATCH_API_KEY) != null ? _c : "";
6058
+ }
6059
+ async request(operation, path2, init) {
6060
+ var _a, _b, _c;
6061
+ const response = await fetch(`${this.endpoint}${path2}`, __spreadProps(__spreadValues({}, init), {
6062
+ // A hung control plane must fail the command, not freeze it.
6063
+ signal: (_a = init == null ? void 0 : init.signal) != null ? _a : AbortSignal.timeout(3e4),
6064
+ headers: __spreadValues({
6065
+ Authorization: `Bearer ${this.apiKey}`,
6066
+ "Content-Type": "application/json"
6067
+ }, (_b = init == null ? void 0 : init.headers) != null ? _b : {})
6068
+ }));
6069
+ if (!response.ok) {
6070
+ let parsedBody;
6071
+ try {
6072
+ parsedBody = await response.json();
6073
+ } catch (e) {
6074
+ parsedBody = await response.text();
6075
+ }
6076
+ const message = formatApiErrorForOperation({
6077
+ operation,
6078
+ error: parsedBody,
6079
+ options: { status: response.status }
6080
+ });
6081
+ throwIfHandledError({
6082
+ operation,
6083
+ error: parsedBody,
6084
+ status: response.status,
6085
+ message
6086
+ });
6087
+ throw new WebhooksApiError(message, operation, parsedBody);
6088
+ }
6089
+ (_c = init == null ? void 0 : init.onResponse) == null ? void 0 : _c.call(init, response);
6090
+ return await response.json();
6091
+ }
6092
+ async list() {
6093
+ const res = await this.request(
6094
+ "list webhook endpoints",
6095
+ "/api/webhooks/v1/endpoints"
6096
+ );
6097
+ return res.data;
6098
+ }
6099
+ async get(id) {
6100
+ const res = await this.request(
6101
+ "get webhook endpoint",
6102
+ `/api/webhooks/v1/endpoints/${encodeURIComponent(id)}`
6103
+ );
6104
+ return res.data;
6105
+ }
6106
+ /**
6107
+ * The signing secret comes back on this response and never again, so a
6108
+ * create that times out is recovered with `idempotencyKey`: the replay
6109
+ * carries the same secret, and nothing else ever will.
6110
+ */
6111
+ async create(input, options) {
6112
+ const res = await this.request(
6113
+ "create webhook endpoint",
6114
+ "/api/webhooks/v1/endpoints",
6115
+ __spreadValues({
6116
+ method: "POST",
6117
+ body: JSON.stringify(input)
6118
+ }, idempotentCreateInit(options))
6119
+ );
6120
+ return res.data;
6121
+ }
6122
+ async update(id, input, options) {
6123
+ const res = await this.request(
6124
+ "update webhook endpoint",
6125
+ `/api/webhooks/v1/endpoints/${encodeURIComponent(id)}`,
6126
+ __spreadValues({ method: "PATCH", body: JSON.stringify(input) }, mutationInit(options))
6127
+ );
6128
+ return res.data;
6129
+ }
6130
+ /**
6131
+ * Retire an endpoint: the server soft-archives the row, stamping
6132
+ * `archived_at` and dropping the status to disabled, so the delivery
6133
+ * history stays readable for audit while nothing more is ever sent. The
6134
+ * row is archived, not removed, and `gatewayBudgets.archive()` already
6135
+ * names that operation, so the billing surfaces agree on the verb.
6136
+ *
6137
+ * Nothing comes back: the response body carries only an `archived: true`
6138
+ * acknowledgement, and a non-2xx already raises.
6139
+ */
6140
+ async archive(id, options) {
6141
+ await this.request(
6142
+ "archive webhook endpoint",
6143
+ `/api/webhooks/v1/endpoints/${encodeURIComponent(id)}`,
6144
+ __spreadValues({ method: "DELETE" }, mutationInit(options))
6145
+ );
6146
+ }
6147
+ async rollSecret(id, options) {
6148
+ const res = await this.request(
6149
+ "roll webhook endpoint secret",
6150
+ `/api/webhooks/v1/endpoints/${encodeURIComponent(id)}/roll-secret`,
6151
+ __spreadValues({ method: "POST" }, mutationInit(options))
6152
+ );
6153
+ return res.data;
6154
+ }
6155
+ async test(id, options) {
6156
+ const res = await this.request(
6157
+ "test webhook endpoint",
6158
+ `/api/webhooks/v1/endpoints/${encodeURIComponent(id)}/test`,
6159
+ __spreadValues({ method: "POST" }, mutationInit(options))
6160
+ );
6161
+ return res.data;
6162
+ }
6163
+ /**
6164
+ * ONE page of the endpoint's delivery attempts, newest first.
6165
+ *
6166
+ * The cursor is why this is a page: the route has always served one, and
6167
+ * dropping it truncated the delivery log at whatever the first page held,
6168
+ * with nothing in the result to say the rest existed. Pass `next_cursor`
6169
+ * back as `cursor`, or walk the whole log with `iterDeliveries()`.
6170
+ */
6171
+ async deliveriesPage(id, options) {
6172
+ const params = new URLSearchParams();
6173
+ if (options == null ? void 0 : options.cursor) params.set("cursor", options.cursor);
6174
+ if ((options == null ? void 0 : options.limit) !== void 0) params.set("limit", String(options.limit));
6175
+ const qs = params.toString() !== "" ? `?${params.toString()}` : "";
6176
+ const { data, next_cursor } = await this.request(
6177
+ "list webhook deliveries",
6178
+ `/api/webhooks/v1/endpoints/${encodeURIComponent(id)}/deliveries${qs}`
6179
+ );
6180
+ return { data, next_cursor: next_cursor != null ? next_cursor : null };
6181
+ }
6182
+ /**
6183
+ * Every recorded delivery attempt for the endpoint, one at a time,
6184
+ * fetching each page only when the consumer reaches it.
6185
+ */
6186
+ iterDeliveries(id, options) {
6187
+ return __asyncGenerator(this, null, function* () {
6188
+ const pages = walkCursorPages({
6189
+ startCursor: options == null ? void 0 : options.cursor,
6190
+ nextCursorOf: (page) => page.next_cursor,
6191
+ onEndlessWalk: (reason) => new WebhooksApiError(
6192
+ `Failed to list webhook deliveries: ${reason}.`,
6193
+ "list webhook deliveries"
6194
+ ),
6195
+ fetchPage: (cursor) => {
6196
+ var _a;
6197
+ return this.deliveriesPage(id, {
6198
+ cursor,
6199
+ limit: (_a = options == null ? void 0 : options.limit) != null ? _a : CURSOR_WALK_PAGE_SIZE
6200
+ });
6201
+ }
6202
+ });
6203
+ try {
6204
+ for (var iter = __forAwait(pages), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
6205
+ const page = temp.value;
6206
+ yield* __yieldStar(page.data);
6207
+ }
6208
+ } catch (temp) {
6209
+ error = [temp];
6210
+ } finally {
6211
+ try {
6212
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
6213
+ } finally {
6214
+ if (error)
6215
+ throw error[0];
6216
+ }
6217
+ }
6218
+ });
6219
+ }
6220
+ async health(id) {
6221
+ const res = await this.request(
6222
+ "read webhook endpoint health",
6223
+ `/api/webhooks/v1/endpoints/${encodeURIComponent(id)}/health`
6224
+ );
6225
+ return res.data;
6226
+ }
6227
+ async eventTypes() {
6228
+ const res = await this.request(
6229
+ "list webhook event types",
6230
+ "/api/webhooks/v1/event-types"
6231
+ );
6232
+ return res.data;
6233
+ }
6234
+ /**
6235
+ * ONE page of the organization's emitted-events log, newest first.
6236
+ *
6237
+ * Webhooks are a push over this log, never the only copy of it: a consumer
6238
+ * that missed a delivery reads the window back from here. Walk the whole
6239
+ * window with `iterEvents()`.
6240
+ */
6241
+ async eventsPage(options) {
6242
+ const params = new URLSearchParams();
6243
+ if (options == null ? void 0 : options.type) params.set("type", options.type);
6244
+ if ((options == null ? void 0 : options.from) !== void 0) params.set("from", String(options.from));
6245
+ if ((options == null ? void 0 : options.to) !== void 0) params.set("to", String(options.to));
6246
+ if (options == null ? void 0 : options.cursor) params.set("cursor", options.cursor);
6247
+ if ((options == null ? void 0 : options.limit) !== void 0) params.set("limit", String(options.limit));
6248
+ const qs = params.toString() !== "" ? `?${params.toString()}` : "";
6249
+ const { data, next_cursor } = await this.request("list emitted events", `/api/webhooks/v1/events${qs}`);
6250
+ return { data, next_cursor: next_cursor != null ? next_cursor : null };
6251
+ }
6252
+ /**
6253
+ * Every emitted event matching the filter, one at a time, fetching each
6254
+ * page only when the consumer reaches it.
6255
+ */
6256
+ iterEvents(options) {
6257
+ return __asyncGenerator(this, null, function* () {
6258
+ const pages = walkCursorPages({
6259
+ startCursor: options == null ? void 0 : options.cursor,
6260
+ nextCursorOf: (page) => page.next_cursor,
6261
+ onEndlessWalk: (reason) => new WebhooksApiError(
6262
+ `Failed to list emitted events: ${reason}.`,
6263
+ "list emitted events"
6264
+ ),
6265
+ fetchPage: (cursor) => {
6266
+ var _a;
6267
+ return this.eventsPage(__spreadProps(__spreadValues({}, options), {
6268
+ cursor,
6269
+ limit: (_a = options == null ? void 0 : options.limit) != null ? _a : CURSOR_WALK_PAGE_SIZE
6270
+ }));
6271
+ }
6272
+ });
6273
+ try {
6274
+ for (var iter = __forAwait(pages), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
6275
+ const page = temp.value;
6276
+ yield* __yieldStar(page.data);
6277
+ }
6278
+ } catch (temp) {
6279
+ error = [temp];
6280
+ } finally {
6281
+ try {
6282
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
6283
+ } finally {
6284
+ if (error)
6285
+ throw error[0];
6286
+ }
6287
+ }
6288
+ });
6289
+ }
6290
+ /**
6291
+ * One emitted event by id, the envelope exactly as it was delivered.
6292
+ *
6293
+ * A 404 covers every reason the log cannot answer: never emitted, past the
6294
+ * retention horizon, or belonging to another organization.
6295
+ */
6296
+ async getEvent(id) {
6297
+ const res = await this.request(
6298
+ "get emitted event",
6299
+ `/api/webhooks/v1/events/${encodeURIComponent(id)}`
6300
+ );
6301
+ return res.data;
6302
+ }
6303
+ };
6304
+
6305
+ // src/client-sdk/services/traces/types.ts
6306
+ var TracesError = class extends Error {
6307
+ constructor(message, operation, originalError) {
6308
+ super(message);
6309
+ this.operation = operation;
6310
+ this.originalError = originalError;
6311
+ this.name = "TracesError";
6312
+ }
6313
+ };
6314
+
6315
+ // src/client-sdk/services/traces/tracing/tracer.ts
6316
+ var tracer3 = getLangWatchTracer(`${LANGWATCH_SDK_NAME_CLIENT}.traces`, LANGWATCH_SDK_VERSION);
6317
+
6318
+ // src/client-sdk/services/traces/service.ts
6319
+ var TracesService = class {
6320
+ constructor(config) {
6321
+ this.config = config;
6322
+ return createTracingProxy(
6323
+ this,
6324
+ tracer3
6325
+ );
6326
+ }
6327
+ /**
6328
+ * Handles API errors by throwing a TracesError with operation context.
6329
+ * @param operation Description of the operation being performed.
6330
+ * @param error The error object returned from the API client.
6331
+ * @throws {TracesError}
6332
+ */
6333
+ handleApiError(operation, error) {
6334
+ var _a, _b;
6335
+ const errorMessage = typeof error === "string" ? error : (_b = (_a = error == null ? void 0 : error.error) != null ? _a : error == null ? void 0 : error.message) != null ? _b : "Unknown error occurred";
6336
+ const message = `Failed to ${operation}: ${errorMessage}`;
6337
+ throw new TracesError(
6338
+ message,
6339
+ operation,
6340
+ error
6341
+ );
6342
+ }
6343
+ /**
6344
+ * Retrieves a trace by its ID.
6345
+ * @param traceId The trace's unique identifier.
6346
+ * @param params Optional parameters for the request.
6347
+ * @returns The trace response object.
6348
+ * @throws {TracesError} If the API call fails.
6349
+ */
6350
+ async get(traceId, params) {
6351
+ const { data, error } = await this.config.langwatchApiClient.GET("/api/trace/{id}", {
6352
+ params: {
6353
+ path: {
6354
+ id: traceId
6355
+ }
6356
+ },
6357
+ query: params
6358
+ });
6359
+ if (error) {
6360
+ this.handleApiError("get trace", error);
6361
+ }
6362
+ return data;
6363
+ }
6364
+ };
6365
+
6366
+ // src/client-sdk/services/traces/facade.ts
6367
+ var _service;
6368
+ var TracesFacade = class {
6369
+ constructor(config) {
6370
+ __privateAdd(this, _service);
6371
+ __privateSet(this, _service, new TracesService(config));
6372
+ }
6373
+ async get(traceId, params) {
6374
+ return __privateGet(this, _service).get(traceId, params);
6375
+ }
6376
+ };
6377
+ _service = new WeakMap();
6378
+
6379
+ // src/client-sdk/index.ts
6380
+ var _LangWatch_instances, createInternalConfig_fn;
6381
+ var LangWatch = class {
6382
+ constructor(options = {}) {
6383
+ __privateAdd(this, _LangWatch_instances);
6384
+ var _a, _b, _c;
6385
+ const apiKey = (_c = (_b = (_a = options.apiKey) != null ? _a : scopedApiKey()) != null ? _b : process.env.LANGWATCH_API_KEY) != null ? _c : "";
6386
+ const endpoint = resolveEndpoint(options.endpoint);
6387
+ this.config = __privateMethod(this, _LangWatch_instances, createInternalConfig_fn).call(this, {
6388
+ apiKey,
6389
+ endpoint,
6390
+ options: options.options
6391
+ });
6392
+ this.prompts = new PromptsFacade(__spreadValues({
6393
+ promptsApiService: new PromptsApiService(this.config),
6394
+ localPromptsService: new LocalPromptsService()
6395
+ }, this.config));
6396
+ this.traces = new TracesFacade(this.config);
6397
+ this.experiments = new ExperimentsFacade({
6398
+ langwatchApiClient: this.config.langwatchApiClient,
6399
+ endpoint: this.config.endpoint,
6400
+ apiKey: this.config.apiKey,
6401
+ logger: this.config.logger
6402
+ });
6403
+ this.datasets = new DatasetsFacade({
6404
+ langwatchApiClient: this.config.langwatchApiClient,
6405
+ logger: this.config.logger,
6406
+ endpoint: this.config.endpoint,
6407
+ apiKey: this.config.apiKey
6408
+ });
6409
+ this.evaluations = new EvaluationsFacade({
6410
+ endpoint: this.config.endpoint,
6411
+ apiKey: this.config.apiKey,
6412
+ logger: this.config.logger
6413
+ });
6414
+ this.evaluators = new EvaluatorsApiService(this.config);
6415
+ this.scenarios = new ScenariosApiService(this.config);
6416
+ this.suites = new SuitesApiService(this.config);
6417
+ this.workflows = new WorkflowsApiService(this.config);
6418
+ this.agents = new AgentsApiService(this.config);
6419
+ this.annotations = new AnnotationsApiService(this.config);
6420
+ this.dashboards = new DashboardsApiService(this.config);
6421
+ this.modelProviders = new ModelProvidersApiService(this.config);
6422
+ this.analytics = new AnalyticsApiService(this.config);
6423
+ this.triggers = new TriggersApiService(this.config);
6424
+ this.graphs = new GraphsApiService(this.config);
6425
+ this.simulationRuns = new SimulationRunsApiService(this.config);
6426
+ this.monitors = new MonitorsApiService({ apiKey, endpoint });
6427
+ this.secrets = new SecretsApiService({ apiKey, endpoint });
6428
+ this.virtualKeys = new VirtualKeysApiService({ apiKey, endpoint });
6429
+ this.gatewayBudgets = new GatewayBudgetsApiService({ apiKey, endpoint });
6430
+ this.spendEvents = new SpendEventsApiService({ apiKey, endpoint });
6431
+ this.webhooks = new WebhooksApiService({ apiKey, endpoint });
6432
+ }
6433
+ get apiClient() {
6434
+ return this.config.langwatchApiClient;
6435
+ }
6436
+ };
6437
+ _LangWatch_instances = new WeakSet();
6438
+ createInternalConfig_fn = function({
6439
+ apiKey,
6440
+ endpoint,
6441
+ options
6442
+ }) {
6443
+ var _a;
6444
+ return {
6445
+ logger: (_a = options == null ? void 0 : options.logger) != null ? _a : new NoOpLogger(),
6446
+ langwatchApiClient: createLangWatchApiClient(apiKey, endpoint),
6447
+ endpoint,
6448
+ apiKey
6449
+ };
6450
+ };
6451
+
6452
+ // src/client-sdk/services/webhooks/verify-signature.ts
6453
+ import { createHmac, timingSafeEqual } from "crypto";
6454
+ var WEBHOOK_SIGNATURE_HEADER = "X-LangWatch-Signature";
6455
+ var WEBHOOK_DELIVERY_ID_HEADER = "X-LangWatch-Delivery-Id";
6456
+ var WEBHOOK_EVENT_ID_HEADER = "X-LangWatch-Event-Id";
6457
+ var WEBHOOK_SIGNATURE_DEFAULT_TOLERANCE_SECONDS = 300;
6458
+ var WebhookSignatureVerificationError = class extends Error {
6459
+ constructor(code, message) {
6460
+ super(message);
6461
+ this.name = "WebhookSignatureVerificationError";
6462
+ this.code = code;
6463
+ }
6464
+ };
6465
+ function parseSignatureHeader(header) {
6466
+ let timestamp;
6467
+ const candidates = [];
6468
+ for (const piece of header.split(",")) {
6469
+ const eq = piece.indexOf("=");
6470
+ if (eq <= 0) continue;
6471
+ const key = piece.slice(0, eq).trim();
6472
+ const value = piece.slice(eq + 1).trim();
6473
+ if (key === "v1") candidates.push(value);
6474
+ else if (key === "t" && value.length > 0) timestamp = Number(value);
6475
+ }
6476
+ return { timestamp, candidates };
6477
+ }
6478
+ function digestsMatch(expected, candidate) {
6479
+ const a = Buffer.from(expected, "utf8");
6480
+ const b = Buffer.from(candidate, "utf8");
6481
+ return a.length === b.length && timingSafeEqual(a, b);
6482
+ }
6483
+ function signedPayload(timestamp, body) {
6484
+ const prefix = Buffer.from(`${timestamp}.`, "utf8");
6485
+ const bytes = typeof body === "string" ? Buffer.from(body, "utf8") : Buffer.from(body);
6486
+ return Buffer.concat([prefix, bytes]);
6487
+ }
6488
+ function verifyWebhookSignature(options) {
6489
+ var _a, _b;
6490
+ const secrets = (typeof options.secret === "string" ? [options.secret] : options.secret).filter((secret) => typeof secret === "string" && secret.length > 0);
6491
+ if (secrets.length === 0) {
6492
+ throw new TypeError(
6493
+ "verifyWebhookSignature needs at least one non-empty signing secret"
6494
+ );
6495
+ }
6496
+ const tolerance = (_a = options.toleranceSeconds) != null ? _a : WEBHOOK_SIGNATURE_DEFAULT_TOLERANCE_SECONDS;
6497
+ const now = (_b = options.nowSeconds) != null ? _b : Math.floor(Date.now() / 1e3);
6498
+ const { timestamp, candidates } = parseSignatureHeader(options.header);
6499
+ if (timestamp === void 0 || !Number.isFinite(timestamp)) {
6500
+ throw new WebhookSignatureVerificationError(
6501
+ "malformed_header",
6502
+ `${WEBHOOK_SIGNATURE_HEADER} carries no readable t= timestamp, so the delivery cannot be checked for freshness`
6503
+ );
6504
+ }
6505
+ if (candidates.length === 0) {
6506
+ throw new WebhookSignatureVerificationError(
6507
+ "malformed_header",
6508
+ `${WEBHOOK_SIGNATURE_HEADER} carries no v1= signature, so there is nothing to compare`
6509
+ );
6510
+ }
6511
+ if (Math.abs(now - timestamp) > tolerance) {
6512
+ throw new WebhookSignatureVerificationError(
6513
+ "stale_timestamp",
6514
+ `the delivery was signed ${Math.abs(now - timestamp)}s from now, outside the ${tolerance}s tolerance`
6515
+ );
6516
+ }
6517
+ const payload = signedPayload(timestamp, options.body);
6518
+ let matched = false;
6519
+ for (const secret of secrets) {
6520
+ const expected = createHmac("sha256", secret).update(payload).digest("hex");
6521
+ for (const candidate of candidates) {
6522
+ if (digestsMatch(expected, candidate)) matched = true;
6523
+ }
6524
+ }
6525
+ if (!matched) {
6526
+ throw new WebhookSignatureVerificationError(
6527
+ "invalid_signature",
6528
+ `no v1 signature in ${WEBHOOK_SIGNATURE_HEADER} matched the ${secrets.length === 1 ? "secret" : "secrets"} held, so the body was signed with something else or changed in transit`
6529
+ );
6530
+ }
6531
+ }
6532
+
5633
6533
  // src/index.ts
5634
6534
  var logger = {
5635
6535
  ConsoleLogger,
@@ -5659,17 +6559,29 @@ export {
5659
6559
  FilterableBatchSpanProcessor,
5660
6560
  GatewayBudgetsApiError,
5661
6561
  GatewayBudgetsApiService,
6562
+ IDEMPOTENCY_KEY_HEADER,
6563
+ IDEMPOTENT_REPLAY_HEADER,
5662
6564
  LangWatch,
5663
6565
  LangWatchApiError,
5664
6566
  LangWatchTraceExporter as LangWatchExporter,
5665
6567
  LangWatchHandledError,
6568
+ SpendEventsApiError,
6569
+ SpendEventsApiService,
5666
6570
  TargetMetadataConflictError,
5667
6571
  VirtualKeysApiError,
5668
6572
  VirtualKeysApiService,
6573
+ WEBHOOK_DELIVERY_ID_HEADER,
6574
+ WEBHOOK_EVENT_ID_HEADER,
6575
+ WEBHOOK_SIGNATURE_DEFAULT_TOLERANCE_SECONDS,
6576
+ WEBHOOK_SIGNATURE_HEADER,
6577
+ WebhookSignatureVerificationError,
6578
+ WebhooksApiError,
6579
+ WebhooksApiService,
5669
6580
  attributes_exports as attributes,
5670
6581
  getLangWatchLogger,
5671
6582
  getLangWatchTracer,
5672
6583
  isLangWatchHandledError,
5673
- logger
6584
+ logger,
6585
+ verifyWebhookSignature
5674
6586
  };
5675
6587
  //# sourceMappingURL=index.mjs.map