@lmnr-ai/client 0.8.26 → 0.8.27

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.
package/dist/index.cjs CHANGED
@@ -28,8 +28,9 @@ let pino = require("pino");
28
28
  pino = __toESM(pino);
29
29
  let pino_pretty = require("pino-pretty");
30
30
  let uuid = require("uuid");
31
+ let _lmnr_ai_types = require("@lmnr-ai/types");
31
32
  //#region package.json
32
- var version = "0.8.26";
33
+ var version = "0.8.27";
33
34
  //#endregion
34
35
  //#region src/version.ts
35
36
  function getLangVersion() {
@@ -94,7 +95,7 @@ function initializeLogger(options) {
94
95
  minimumLevel: level
95
96
  }));
96
97
  }
97
- const logger$3 = initializeLogger();
98
+ const logger$4 = initializeLogger();
98
99
  const isStringUUID = (id) => /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(id);
99
100
  const newUUID = () => {
100
101
  if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
@@ -103,9 +104,9 @@ const newUUID = () => {
103
104
  const otelSpanIdToUUID = (spanId) => {
104
105
  let id = spanId.toLowerCase();
105
106
  if (id.startsWith("0x")) id = id.slice(2);
106
- if (id.length !== 16) logger$3.warn(`Span ID ${spanId} is not 16 hex chars long. This is not a valid OpenTelemetry span ID.`);
107
+ if (id.length !== 16) logger$4.warn(`Span ID ${spanId} is not 16 hex chars long. This is not a valid OpenTelemetry span ID.`);
107
108
  if (!/^[0-9a-f]+$/.test(id)) {
108
- logger$3.error(`Span ID ${spanId} is not a valid hex string. Generating a random UUID instead.`);
109
+ logger$4.error(`Span ID ${spanId} is not a valid hex string. Generating a random UUID instead.`);
109
110
  return newUUID();
110
111
  }
111
112
  return id.padStart(32, "0").replace(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/, "$1-$2-$3-$4-$5");
@@ -113,9 +114,9 @@ const otelSpanIdToUUID = (spanId) => {
113
114
  const otelTraceIdToUUID = (traceId) => {
114
115
  let id = traceId.toLowerCase();
115
116
  if (id.startsWith("0x")) id = id.slice(2);
116
- if (id.length !== 32) logger$3.warn(`Trace ID ${traceId} is not 32 hex chars long. This is not a valid OpenTelemetry trace ID.`);
117
+ if (id.length !== 32) logger$4.warn(`Trace ID ${traceId} is not 32 hex chars long. This is not a valid OpenTelemetry trace ID.`);
117
118
  if (!/^[0-9a-f]+$/.test(id)) {
118
- logger$3.error(`Trace ID ${traceId} is not a valid hex string. Generating a random UUID instead.`);
119
+ logger$4.error(`Trace ID ${traceId} is not a valid hex string. Generating a random UUID instead.`);
119
120
  return newUUID();
120
121
  }
121
122
  return id.replace(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/, "$1-$2-$3-$4-$5");
@@ -145,7 +146,7 @@ const loadEnv = (options) => {
145
146
  };
146
147
  //#endregion
147
148
  //#region src/resources/datasets.ts
148
- const logger$2 = initializeLogger();
149
+ const logger$3 = initializeLogger();
149
150
  const DEFAULT_DATASET_PULL_LIMIT = 100;
150
151
  const DEFAULT_DATASET_PUSH_BATCH_SIZE = 100;
151
152
  var DatasetsResource = class extends BaseResource {
@@ -200,7 +201,7 @@ var DatasetsResource = class extends BaseResource {
200
201
  let response;
201
202
  for (let i = 0; i < points.length; i += batchSize) {
202
203
  const batchNum = Math.floor(i / batchSize) + 1;
203
- logger$2.debug(`Pushing batch ${batchNum} of ${totalBatches}`);
204
+ logger$3.debug(`Pushing batch ${batchNum} of ${totalBatches}`);
204
205
  const batch = points.slice(i, i + batchSize);
205
206
  const fetchResponse = await fetch(this.baseHttpUrl + "/v1/datasets/datapoints", {
206
207
  method: "POST",
@@ -250,7 +251,7 @@ var DatasetsResource = class extends BaseResource {
250
251
  };
251
252
  //#endregion
252
253
  //#region src/resources/evals.ts
253
- const logger$1 = initializeLogger();
254
+ const logger$2 = initializeLogger();
254
255
  const INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH = 16e6;
255
256
  var EvalsResource = class extends BaseResource {
256
257
  constructor(baseHttpUrl, projectApiKey) {
@@ -386,7 +387,7 @@ var EvalsResource = class extends BaseResource {
386
387
  * @returns {Promise<GetDatapointsResponse>} Response from the datapoint retrieval
387
388
  */
388
389
  async getDatapoints({ datasetName, offset, limit }) {
389
- logger$1.warn("evals.getDatapoints() is deprecated. Use client.datasets.pull() instead.");
390
+ logger$2.warn("evals.getDatapoints() is deprecated. Use client.datasets.pull() instead.");
390
391
  const params = new URLSearchParams({
391
392
  name: datasetName,
392
393
  offset: offset.toString(),
@@ -403,7 +404,7 @@ var EvalsResource = class extends BaseResource {
403
404
  let length = initialLength;
404
405
  let lastResponse = null;
405
406
  for (let i = 0; i < maxRetries; i++) {
406
- logger$1.debug(`Retrying save datapoints... ${i + 1} of ${maxRetries}, length: ${length}`);
407
+ logger$2.debug(`Retrying save datapoints... ${i + 1} of ${maxRetries}, length: ${length}`);
407
408
  const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {
408
409
  method: "POST",
409
410
  headers: this.headers(),
@@ -489,60 +490,51 @@ var EvaluatorsResource = class extends BaseResource {
489
490
  };
490
491
  //#endregion
491
492
  //#region src/resources/rollout-sessions.ts
493
+ const logger$1 = initializeLogger();
492
494
  var RolloutSessionsResource = class extends BaseResource {
493
495
  constructor(baseHttpUrl, projectApiKey) {
494
496
  super(baseHttpUrl, projectApiKey);
495
497
  }
496
498
  /**
497
- * Connects to the SSE stream for rollout debugging sessions
498
- * Returns the Response object for streaming SSE events
499
+ * Idempotently register (upsert) a debug session on the backend, keyed on the
500
+ * SDK-supplied session id. The backend stores the row so the session is
501
+ * visible in the UI; a null/omitted name never clobbers a name set elsewhere.
502
+ *
503
+ * Returns the backend-resolved `projectId` (derived from the API key) so the
504
+ * caller can build the debugger URL; null if the body can't be parsed.
499
505
  */
500
- async connect({ sessionId, name, params, signal }) {
506
+ async register({ sessionId, name }) {
501
507
  const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}`, {
502
508
  method: "POST",
503
- headers: {
504
- ...this.headers(),
505
- "Accept": "text/event-stream"
506
- },
507
- body: JSON.stringify({
508
- name,
509
- params
510
- }),
511
- signal
512
- });
513
- if (!response.ok) throw new Error(`SSE connection failed: ${response.status} ${response.statusText}`);
514
- if (!response.body) throw new Error("No response body");
515
- return response;
516
- }
517
- async delete({ sessionId }) {
518
- const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}`, {
519
- method: "DELETE",
520
- headers: this.headers()
509
+ headers: this.headers(),
510
+ body: JSON.stringify({ name })
521
511
  });
522
512
  if (!response.ok) await this.handleError(response);
513
+ try {
514
+ return (await response.json()).projectId ?? null;
515
+ } catch (e) {
516
+ logger$1.warn(`Failed to parse rollout register response: ${(0, _lmnr_ai_types.errorMessage)(e)}`);
517
+ return null;
518
+ }
523
519
  }
524
- async setStatus({ sessionId, status }) {
525
- const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}/status`, {
520
+ /**
521
+ * Rename an existing debug session. Update-only: the backend returns 404 (and
522
+ * this throws) when the session id is unknown for the project, so a mistyped
523
+ * id surfaces as an error rather than silently creating a session. Creation
524
+ * stays the SDK's job via {@link register}.
525
+ */
526
+ async setName({ sessionId, name }) {
527
+ const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}/name`, {
526
528
  method: "PATCH",
527
529
  headers: this.headers(),
528
- body: JSON.stringify({ status })
530
+ body: JSON.stringify({ name })
529
531
  });
530
532
  if (!response.ok) await this.handleError(response);
531
533
  }
532
- async sendSpanUpdate({ sessionId, span }) {
533
- const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}/update`, {
534
- method: "PATCH",
535
- headers: this.headers(),
536
- body: JSON.stringify({
537
- type: "spanStart",
538
- spanId: otelSpanIdToUUID(span.spanId),
539
- traceId: otelTraceIdToUUID(span.traceId),
540
- parentSpanId: span.parentSpanId ? otelSpanIdToUUID(span.parentSpanId) : void 0,
541
- attributes: span.attributes,
542
- startTime: span.startTime,
543
- name: span.name,
544
- spanType: span.spanType
545
- })
534
+ async delete({ sessionId }) {
535
+ const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}`, {
536
+ method: "DELETE",
537
+ headers: this.headers()
546
538
  });
547
539
  if (!response.ok) await this.handleError(response);
548
540
  }
@@ -651,13 +643,16 @@ var TracesResource = class extends BaseResource {
651
643
  *
652
644
  * A 404 response (the trace was not found in the project — typically because
653
645
  * it has not been flushed yet) is logged as a warning and the call returns
654
- * without throwing; any other non-OK status throws.
646
+ * without throwing, since the 404 may be expected when pushing too soon
647
+ * after the trace run. Pass `failOnNotFound: true` to throw instead (e.g.
648
+ * CLI callers that must report the failure). Any other non-OK status throws.
655
649
  *
656
650
  * @param traceId - The trace id to push metadata to. Accepts a UUID string
657
651
  * or a 32-char OTel hex trace id.
658
652
  * @param metadata - The metadata patch. Top-level keys are merged into the
659
653
  * trace's existing metadata. Must be non-empty (the server rejects empty
660
654
  * patches with 400).
655
+ * @param options - `failOnNotFound`: throw on 404 instead of warn-and-return.
661
656
  * @example
662
657
  * ```typescript
663
658
  * import { Laminar, observe, LaminarClient } from "@lmnr-ai/lmnr";
@@ -679,7 +674,7 @@ var TracesResource = class extends BaseResource {
679
674
  * }
680
675
  * ```
681
676
  */
682
- async pushMetadata(traceId, metadata) {
677
+ async pushMetadata(traceId, metadata, options) {
683
678
  if (!metadata || Object.keys(metadata).length === 0) throw new Error("metadata must be a non-empty object");
684
679
  const formattedTraceId = isStringUUID(traceId) ? traceId : otelTraceIdToUUID(traceId);
685
680
  const url = this.baseHttpUrl + "/v1/traces/metadata";
@@ -692,7 +687,9 @@ var TracesResource = class extends BaseResource {
692
687
  })
693
688
  });
694
689
  if (response.status === 404) {
695
- logger.warn(`Trace ${formattedTraceId} not found. The trace may not have been flushed yet — call await Laminar.flush() and retry.`);
690
+ const message = `Trace ${formattedTraceId} not found. The trace may not have been flushed yet — call await Laminar.flush() and retry.`;
691
+ if (options?.failOnNotFound) throw new Error(message);
692
+ logger.warn(message);
696
693
  return;
697
694
  }
698
695
  if (!response.ok) await this.handleError(response);
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["SDK_VERSION","logger","logger","logger"],"sources":["../package.json","../src/version.ts","../src/resources/index.ts","../src/resources/browser-events.ts","../src/utils.ts","../src/resources/datasets.ts","../src/resources/evals.ts","../src/resources/evaluators.ts","../src/resources/rollout-sessions.ts","../src/resources/sql.ts","../src/resources/tags.ts","../src/resources/traces.ts","../src/index.ts"],"sourcesContent":["","// Version detection for runtime environment\nexport function getLangVersion(): string | null {\n if (typeof process !== 'undefined' && process.versions && process.versions.node) {\n return `node-${process.versions.node}`;\n }\n if (typeof navigator !== 'undefined' && navigator.userAgent) {\n return `browser-${navigator.userAgent}`;\n }\n return null;\n}\n","class BaseResource {\n protected readonly baseHttpUrl: string;\n protected readonly projectApiKey: string;\n\n constructor(baseHttpUrl: string, projectApiKey: string) {\n this.baseHttpUrl = baseHttpUrl;\n this.projectApiKey = projectApiKey;\n }\n\n protected headers() {\n return {\n Authorization: `Bearer ${this.projectApiKey}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n }\n\n protected async handleError(response: Response) {\n const errorMsg = await response.text();\n throw new Error(`${response.status} ${errorMsg}`);\n }\n}\n\nexport { BaseResource };\n","import { version as SDK_VERSION } from '../../package.json';\nimport { getLangVersion } from \"../version\";\nimport { BaseResource } from \"./index\";\n\nexport class BrowserEventsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n public async send({\n sessionId,\n traceId,\n events,\n }: {\n sessionId: string;\n traceId: string;\n events: Record<string, any>[];\n }): Promise<void> {\n const payload = {\n sessionId,\n traceId,\n events,\n source: getLangVersion() ?? 'javascript',\n sdkVersion: SDK_VERSION,\n };\n\n const jsonString = JSON.stringify(payload);\n const blob = new Blob([jsonString], { type: 'application/json' });\n const compressedStream = blob.stream().pipeThrough(new CompressionStream('gzip'));\n const compressedResponse = new Response(compressedStream);\n const compressedData = await compressedResponse.arrayBuffer();\n\n const response = await fetch(this.baseHttpUrl + \"/v1/browser-sessions/events\", {\n method: \"POST\",\n headers: {\n ...this.headers(),\n 'Content-Encoding': 'gzip',\n },\n body: compressedData,\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { type StringUUID } from '@lmnr-ai/types';\nimport { config } from 'dotenv';\nimport * as path from 'path';\nimport pino, { Level } from 'pino';\nimport { PinoPretty } from 'pino-pretty';\nimport { v4 as uuidv4 } from 'uuid';\n\nexport function initializeLogger(options?: { colorize?: boolean; level?: Level }) {\n const colorize = options?.colorize ?? true;\n const level =\n options?.level ??\n (process.env.LMNR_LOG_LEVEL?.toLowerCase()?.trim() as Level) ??\n 'info';\n\n return pino(\n {\n level,\n },\n PinoPretty({\n colorize,\n minimumLevel: level,\n }),\n );\n}\n\nconst logger = initializeLogger();\n\nexport const isStringUUID = (id: string): id is StringUUID =>\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(id);\n\nexport const NIL_UUID: StringUUID = '00000000-0000-0000-0000-000000000000';\n\nexport const newUUID = (): StringUUID => {\n // crypto.randomUUID is available in most of the modern browsers and node,\n // but is not available in \"insecure\" contexts, e.g. not https, not localhost\n // so we fallback to uuidv4 in those cases, which is less secure, but works\n // just fine.\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n } else {\n return uuidv4() as `${string}-${string}-${string}-${string}-${string}`;\n }\n};\n\nexport const otelSpanIdToUUID = (spanId: string): string => {\n let id = spanId.toLowerCase();\n if (id.startsWith('0x')) {\n id = id.slice(2);\n }\n if (id.length !== 16) {\n logger.warn(\n `Span ID ${spanId} is not 16 hex chars long. ` +\n 'This is not a valid OpenTelemetry span ID.',\n );\n }\n\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(\n `Span ID ${spanId} is not a valid hex string. ` +\n 'Generating a random UUID instead.',\n );\n return newUUID();\n }\n\n return id.padStart(32, '0').replace(\n /^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/,\n '$1-$2-$3-$4-$5',\n );\n};\n\nexport const otelTraceIdToUUID = (traceId: string): StringUUID => {\n let id = traceId.toLowerCase();\n if (id.startsWith('0x')) {\n id = id.slice(2);\n }\n if (id.length !== 32) {\n logger.warn(\n `Trace ID ${traceId} is not 32 hex chars long. ` +\n 'This is not a valid OpenTelemetry trace ID.',\n );\n }\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(\n `Trace ID ${traceId} is not a valid hex string. ` +\n 'Generating a random UUID instead.',\n );\n return newUUID();\n }\n\n return id.replace(\n /^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/,\n '$1-$2-$3-$4-$5',\n ) as StringUUID;\n};\n\nexport const slicePayload = <T>(value: T, length: number) => {\n if (value === null || value === undefined) {\n return value;\n }\n\n const str = JSON.stringify(value);\n if (str.length <= length) {\n return value;\n }\n\n return str.slice(0, length) + '...';\n};\n\nexport const loadEnv = (\n options?: {\n quiet?: boolean;\n paths?: string[];\n },\n): void => {\n const nodeEnv = process.env.NODE_ENV || 'development';\n const envDir = process.cwd();\n\n // Files to load in order (lowest to highest priority)\n // Later files override earlier ones\n const envFiles = [\n '.env',\n '.env.local',\n `.env.${nodeEnv}`,\n `.env.${nodeEnv}.local`,\n ];\n\n const logLevel = process.env.LMNR_LOG_LEVEL ?? 'info';\n const verbose = ['debug', 'trace'].includes(logLevel.trim().toLowerCase());\n\n const quiet = options?.quiet ?? !verbose;\n\n config({\n path: options?.paths ?? envFiles.map((envFile) => path.resolve(envDir, envFile)),\n quiet,\n });\n};\n","import {\n type Datapoint,\n type Dataset,\n type GetDatapointsResponse,\n type PushDatapointsResponse,\n type StringUUID,\n} from \"@lmnr-ai/types\";\n\nimport { initializeLogger } from \"../utils\";\nimport { BaseResource } from \".\";\n\nconst logger = initializeLogger();\nconst DEFAULT_DATASET_PULL_LIMIT = 100;\nconst DEFAULT_DATASET_PUSH_BATCH_SIZE = 100;\n\nexport class DatasetsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * List all datasets.\n *\n * @returns {Promise<Dataset[]>} Array of datasets\n */\n public async listDatasets(): Promise<Dataset[]> {\n const response = await fetch(this.baseHttpUrl + \"/v1/datasets\", {\n method: \"GET\",\n headers: this.headers(),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<Dataset[]>;\n }\n\n /**\n * Get a dataset by name.\n *\n * @param {string} name - Name of the dataset\n * @returns {Promise<Dataset[]>} Array of datasets with matching name\n */\n public async getDatasetByName(name: string): Promise<Dataset[]> {\n const params = new URLSearchParams({ name });\n const response = await fetch(\n this.baseHttpUrl + `/v1/datasets?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<Dataset[]>;\n }\n\n /**\n * Push datapoints to a dataset.\n *\n * @param {Object} options - Push options\n * @param {Datapoint<D, T>[]} options.points - Datapoints to push\n * @param {string} [options.name] - Name of the dataset (either name or id must be provided)\n * @param {StringUUID} [options.id] - ID of the dataset (either name or id must be provided)\n * @param {number} [options.batchSize] - Batch size for pushing (default: 100)\n * @param {boolean} [options.createDataset] - Whether to create the dataset if it doesn't exist\n * @returns {Promise<PushDatapointsResponse | undefined>}\n */\n public async push<D, T>({\n points,\n name,\n id,\n batchSize = DEFAULT_DATASET_PUSH_BATCH_SIZE,\n createDataset = false,\n }: {\n points: Datapoint<D, T>[];\n name?: string;\n id?: StringUUID;\n batchSize?: number;\n createDataset?: boolean;\n }): Promise<PushDatapointsResponse | undefined> {\n if (!name && !id) {\n throw new Error(\"Either name or id must be provided\");\n }\n\n if (name && id) {\n throw new Error(\"Only one of name or id must be provided\");\n }\n\n if (createDataset && !name) {\n throw new Error(\"Name must be provided when creating a new dataset\");\n }\n\n const identifier = name ? { name } : { datasetId: id! };\n const totalBatches = Math.ceil(points.length / batchSize);\n\n let response: PushDatapointsResponse | undefined;\n for (let i = 0; i < points.length; i += batchSize) {\n const batchNum = Math.floor(i / batchSize) + 1;\n logger.debug(`Pushing batch ${batchNum} of ${totalBatches}`);\n\n const batch = points.slice(i, i + batchSize);\n const fetchResponse = await fetch(\n this.baseHttpUrl + \"/v1/datasets/datapoints\",\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n ...identifier,\n datapoints: batch.map((point) => ({\n data: point.data,\n target: point.target ?? {},\n metadata: point.metadata ?? {},\n })),\n createDataset,\n }),\n },\n );\n\n // 201 when creating a new dataset\n if (fetchResponse.status !== 200 && fetchResponse.status !== 201) {\n await this.handleError(fetchResponse);\n }\n\n response = (await fetchResponse.json()) as PushDatapointsResponse;\n }\n\n return response;\n }\n\n /**\n * Pull datapoints from a dataset.\n *\n * @param {Object} options - Pull options\n * @param {string} [options.name] - Name of the dataset (either name or id must be provided)\n * @param {StringUUID} [options.id] - ID of the dataset (either name or id must be provided)\n * @param {number} [options.limit] - Maximum number of datapoints to return (default: 100)\n * @param {number} [options.offset] - Offset for pagination (default: 0)\n * @returns {Promise<GetDatapointsResponse<D, T>>}\n */\n public async pull<D, T>({\n name,\n id,\n limit = DEFAULT_DATASET_PULL_LIMIT,\n offset = 0,\n }: {\n name?: string;\n id?: StringUUID;\n limit?: number;\n offset?: number;\n }): Promise<GetDatapointsResponse<D, T>> {\n if (!name && !id) {\n throw new Error(\"Either name or id must be provided\");\n }\n\n if (name && id) {\n throw new Error(\"Only one of name or id must be provided\");\n }\n\n const paramsObj: Record<string, string> = {\n offset: offset.toString(),\n limit: limit.toString(),\n };\n\n if (name) {\n paramsObj.name = name;\n } else {\n paramsObj.datasetId = id!;\n }\n\n const params = new URLSearchParams(paramsObj);\n\n const response = await fetch(\n this.baseHttpUrl + `/v1/datasets/datapoints?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<GetDatapointsResponse<D, T>>;\n }\n}\n","import {\n type EvaluationDatapoint,\n type GetDatapointsResponse,\n type InitEvaluationResponse,\n type StringUUID,\n} from \"@lmnr-ai/types\";\n\nimport { initializeLogger, newUUID, slicePayload } from \"../utils\";\nimport { BaseResource } from \".\";\n\nconst logger = initializeLogger();\nconst INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH = 16_000_000; // 16MB\n\nexport class EvalsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Initialize an evaluation.\n *\n * @param {string} name - Name of the evaluation\n * @param {string} groupName - Group name of the evaluation\n * @param {Record<string, any>} metadata - Optional metadata\n * @returns {Promise<InitEvaluationResponse>} Response from the evaluation initialization\n */\n public async init(\n name?: string,\n groupName?: string,\n metadata?: Record<string, any>,\n ): Promise<InitEvaluationResponse> {\n const response = await fetch(this.baseHttpUrl + \"/v1/evals\", {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n name: name ?? null,\n groupName: groupName ?? null,\n metadata: metadata ?? null,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<InitEvaluationResponse>;\n }\n\n /**\n * Create a new evaluation and return its ID.\n *\n * @param {string} [name] - Optional name of the evaluation\n * @param {string} [groupName] - An identifier to group evaluations\n * @param {Record<string, any>} [metadata] - Optional metadata\n * @returns {Promise<StringUUID>} The evaluation ID\n */\n\n public async create(args?: {\n name?: string, groupName?: string, metadata?: Record<string, any>\n }): Promise<StringUUID> {\n const evaluation = await this.init(args?.name, args?.groupName, args?.metadata);\n return evaluation.id;\n }\n\n /**\n * Create a new evaluation and return its ID.\n * @deprecated use `create` instead.\n */\n public async createEvaluation(\n name?: string,\n groupName?: string,\n metadata?: Record<string, any>,\n ): Promise<StringUUID> {\n const evaluation = await this.init(name, groupName, metadata);\n return evaluation.id;\n }\n\n /**\n * Create a datapoint for an evaluation.\n *\n * @param {Object} options - Create datapoint options\n * @param {string} options.evalId - The evaluation ID\n * @param {D} options.data - The input data for the executor\n * @param {T} [options.target] - The target/expected output for evaluators\n * @param {Record<string, any>} [options.metadata] - Optional metadata\n * @param {number} [options.index] - Optional index of the datapoint\n * @param {string} [options.traceId] - Optional trace ID\n * @returns {Promise<StringUUID>} The datapoint ID\n */\n public async createDatapoint<D, T>({\n evalId,\n data,\n target,\n metadata,\n index,\n traceId,\n }: {\n evalId: string;\n data: D;\n target?: T;\n metadata?: Record<string, any>;\n index?: number;\n traceId?: string;\n }): Promise<StringUUID> {\n const datapointId = newUUID();\n\n const partialDatapoint: EvaluationDatapoint<D, T, any> = {\n id: datapointId,\n data,\n target,\n index: index ?? 0,\n traceId: traceId ?? newUUID(),\n executorSpanId: newUUID(),\n metadata,\n };\n\n await this.saveDatapoints({\n evalId,\n datapoints: [partialDatapoint],\n });\n\n return datapointId;\n }\n\n /**\n * Update a datapoint with evaluation results.\n *\n * @param {Object} options - Update datapoint options\n * @param {string} options.evalId - The evaluation ID\n * @param {string} options.datapointId - The datapoint ID\n * @param {Record<string, number>} options.scores - The scores\n * @param {O} [options.executorOutput] - The executor output\n * @returns {Promise<void>}\n */\n public async updateDatapoint<O>({\n evalId,\n datapointId,\n scores,\n executorOutput,\n }: {\n evalId: string;\n datapointId: string;\n scores: Record<string, number>;\n executorOutput?: O;\n }): Promise<void> {\n const response = await fetch(\n this.baseHttpUrl + `/v1/evals/${evalId}/datapoints/${datapointId}`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n executorOutput,\n scores,\n }),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n /**\n * Save evaluation datapoints.\n *\n * @param {Object} options - Save datapoints options\n * @param {string} options.evalId - ID of the evaluation\n * @param {EvaluationDatapoint<D, T, O>[]} options.datapoints - Datapoint to add\n * @param {string} [options.groupName] - Group name of the evaluation\n * @returns {Promise<void>} Response from the datapoint addition\n */\n public async saveDatapoints<D, T, O>({\n evalId,\n datapoints,\n groupName,\n }: {\n evalId: string;\n datapoints: EvaluationDatapoint<D, T, O>[];\n groupName?: string;\n }): Promise<void> {\n const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n points: datapoints.map((d) => (\n {\n ...d,\n data: slicePayload(d.data, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH),\n target: slicePayload(d.target, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH),\n executorOutput: slicePayload(\n d.executorOutput,\n INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH,\n ),\n })),\n groupName: groupName ?? null,\n }),\n });\n\n if (response.status === 413) {\n return await this.retrySaveDatapoints({\n evalId,\n datapoints,\n groupName,\n });\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n /**\n * Get evaluation datapoints.\n *\n * @deprecated Use `client.datasets.pull()` instead.\n * @param {Object} options - Get datapoints options\n * @param {string} options.datasetName - Name of the dataset\n * @param {number} options.offset - Offset at which to start the query\n * @param {number} options.limit - Maximum number of datapoints to return\n * @returns {Promise<GetDatapointsResponse>} Response from the datapoint retrieval\n */\n public async getDatapoints<D, T>({\n datasetName,\n offset,\n limit,\n }: {\n datasetName: string;\n offset: number;\n limit: number;\n }): Promise<GetDatapointsResponse<D, T>> {\n logger.warn(\n 'evals.getDatapoints() is deprecated. Use client.datasets.pull() instead.',\n );\n\n const params = new URLSearchParams({\n name: datasetName,\n offset: offset.toString(),\n limit: limit.toString(),\n });\n const response = await fetch(\n this.baseHttpUrl + `/v1/datasets/datapoints?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()) as GetDatapointsResponse<D, T>;\n }\n\n private async retrySaveDatapoints<D, T, O>({\n evalId,\n datapoints,\n groupName,\n maxRetries = 25,\n initialLength = INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH,\n }: {\n evalId: string;\n datapoints: EvaluationDatapoint<D, T, O>[];\n groupName?: string;\n maxRetries?: number;\n initialLength?: number;\n }): Promise<void> {\n let length = initialLength;\n let lastResponse: Response | null = null;\n for (let i = 0; i < maxRetries; i++) {\n logger.debug(`Retrying save datapoints... ${i + 1} of ${maxRetries}, length: ${length}`);\n const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n points: datapoints.map((d) => (\n {\n ...d,\n data: slicePayload(d.data, length),\n target: slicePayload(d.target, length),\n executorOutput: slicePayload(d.executorOutput, length),\n })),\n groupName: groupName ?? null,\n }),\n });\n lastResponse = response;\n length = Math.floor(length / 2);\n if (response.status !== 413) {\n break;\n }\n }\n if (lastResponse && !lastResponse.ok) {\n await this.handleError(lastResponse);\n }\n }\n}\n","import { type StringUUID } from \"@lmnr-ai/types\";\n\nimport { isStringUUID, otelSpanIdToUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \".\";\n\nenum EvaluatorScoreSourceType {\n Evaluator = \"Evaluator\",\n Code = \"Code\",\n}\n\ninterface CreateEvaluatorScoreBase {\n name: string;\n metadata?: Record<string, any>;\n score: number;\n source: EvaluatorScoreSourceType;\n}\n\ninterface CreateEvaluatorScoreRequestWithTraceId extends CreateEvaluatorScoreBase {\n traceId: string;\n}\n\ninterface CreateEvaluatorScoreRequestWithSpanId extends CreateEvaluatorScoreBase {\n spanId: string;\n}\n\ntype ScoreOptions =\n | { name: string; metadata?: Record<string, any>; score: number; traceId: string; }\n | { name: string; metadata?: Record<string, any>; score: number; spanId: string; };\n\n/**\n * Resource for creating evaluator scores\n */\nexport class EvaluatorsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Create a score for a span or trace\n *\n * @param {ScoreOptions} options - Score creation options\n * @param {string} options.name - Name of the score\n * @param {string} [options.traceId] - The trace ID to score (will be attached to top-level span)\n * @param {string} [options.spanId] - The span ID to score\n * @param {Record<string, any>} [options.metadata] - Additional metadata\n * @param {number} options.score - The score value (float)\n * @returns {Promise<void>}\n *\n * @example\n * // Score by trace ID (will attach to root span)\n * await evaluators.score({\n * name: \"quality\",\n * traceId: \"trace-id-here\",\n * score: 0.95,\n * metadata: { model: \"gpt-4\" }\n * });\n *\n * @example\n * // Score by span ID\n * await evaluators.score({\n * name: \"relevance\",\n * spanId: \"span-id-here\",\n * score: 0.87\n * });\n */\n public async score(options: ScoreOptions): Promise<void> {\n const { name, metadata, score } = options;\n\n let payload: CreateEvaluatorScoreRequestWithTraceId | CreateEvaluatorScoreRequestWithSpanId;\n\n if ('traceId' in options && options.traceId) {\n const formattedTraceId = isStringUUID(options.traceId)\n ? options.traceId\n : otelTraceIdToUUID(options.traceId);\n\n payload = {\n name,\n metadata,\n score,\n source: EvaluatorScoreSourceType.Code,\n traceId: formattedTraceId,\n };\n } else if ('spanId' in options && options.spanId) {\n const formattedSpanId = isStringUUID(options.spanId)\n ? options.spanId\n : otelSpanIdToUUID(options.spanId) as StringUUID;\n\n payload = {\n name,\n metadata,\n score,\n source: EvaluatorScoreSourceType.Code,\n spanId: formattedSpanId,\n };\n } else {\n throw new Error(\"Either 'traceId' or 'spanId' must be provided.\");\n }\n\n const response = await fetch(this.baseHttpUrl + \"/v1/evaluators/score\", {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { type RolloutParam, type SpanType } from \"@lmnr-ai/types\";\n\nimport { otelSpanIdToUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \"./index\";\n\nexport class RolloutSessionsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Connects to the SSE stream for rollout debugging sessions\n * Returns the Response object for streaming SSE events\n */\n public async connect({\n sessionId,\n name,\n params,\n signal,\n }: {\n sessionId: string;\n params: RolloutParam[];\n name: string;\n signal?: AbortSignal;\n }): Promise<Response> {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}`, {\n method: \"POST\",\n headers: {\n ...this.headers(),\n 'Accept': 'text/event-stream',\n },\n body: JSON.stringify({ name, params }),\n signal,\n });\n\n if (!response.ok) {\n throw new Error(`SSE connection failed: ${response.status} ${response.statusText}`);\n }\n\n if (!response.body) {\n throw new Error('No response body');\n }\n\n return response;\n }\n\n public async delete({\n sessionId,\n }: {\n sessionId: string;\n }) {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}`, {\n method: \"DELETE\",\n headers: this.headers(),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n public async setStatus({\n sessionId,\n status,\n }: {\n sessionId: string;\n status: 'PENDING' | 'RUNNING' | 'FINISHED' | 'STOPPED';\n }) {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}/status`, {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify({ status }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n public async sendSpanUpdate({\n sessionId,\n span,\n }: {\n sessionId: string;\n span: {\n name: string;\n startTime: string;\n spanId: string;\n traceId: string;\n parentSpanId: string | undefined;\n attributes: Record<string, any>;\n spanType: SpanType;\n };\n }) {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}/update`, {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify({\n type: \"spanStart\",\n spanId: otelSpanIdToUUID(span.spanId),\n traceId: otelTraceIdToUUID(span.traceId),\n parentSpanId: span.parentSpanId ? otelSpanIdToUUID(span.parentSpanId) : undefined,\n attributes: span.attributes,\n startTime: span.startTime,\n name: span.name,\n spanType: span.spanType,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BaseResource } from \"./index\";\n\nexport class SqlResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n public async query(\n sql: string,\n parameters: Record<string, any> = {},\n ): Promise<Array<Record<string, any>>> {\n const response = await fetch(`${this.baseHttpUrl}/v1/sql/query`, {\n method: \"POST\",\n headers: {\n ...this.headers(),\n },\n body: JSON.stringify({\n query: sql,\n parameters,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()).data as Array<Record<string, any>>;\n }\n}\n","/** Resource for tagging traces. */\n\n\nimport { isStringUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \"./index\";\n\nexport class TagsResource extends BaseResource {\n /** Resource for tagging traces. */\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Tag a trace with a list of tags. Note that the trace must be ended before\n * tagging it. You may want to call `await Laminar.flush()` after the trace\n * that you want to tag.\n *\n * @param {string | StringUUID} trace_id - The trace id to tag.\n * @param {string[] | string} tags - The tag or list of tags to add to the trace.\n * @returns {Promise<any>} The response from the server.\n * @example\n * ```javascript\n * import { Laminar, observe, LaminarClient } from \"@lmnr-ai/lmnr\";\n * Laminar.initialize();\n * const client = new LaminarClient();\n * let traceId: StringUUID | null = null;\n * // Make sure this is called outside of traced context.\n * await observe(\n * {\n * name: \"my-trace\",\n * },\n * async () => {\n * traceId = await Laminar.getTraceId();\n * await foo();\n * },\n * );\n *\n * // or make sure the trace is ended by this point.\n * await Laminar.flush();\n * if (traceId) {\n * await client.tags.tag(traceId, [\"tag1\", \"tag2\"]);\n * }\n * ```\n */\n public async tag(\n trace_id: string,\n tags: string[] | string,\n ): Promise<any> {\n const traceTags = Array.isArray(tags) ? tags : [tags];\n const formattedTraceId = isStringUUID(trace_id)\n ? trace_id\n : otelTraceIdToUUID(trace_id);\n\n const url = this.baseHttpUrl + \"/v1/tag\";\n const payload = {\n \"traceId\": formattedTraceId,\n \"names\": traceTags,\n };\n const response = await fetch(\n url,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(payload),\n },\n );\n if (!response.ok) {\n await this.handleError(response);\n }\n return response.json();\n }\n}\n","/** Resource for post-factum operations on existing traces. */\n\nimport { initializeLogger, isStringUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \"./index\";\n\nconst logger = initializeLogger();\n\nexport class TracesResource extends BaseResource {\n /** Resource for post-factum operations on existing traces. */\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Push a metadata patch to an existing trace.\n *\n * The patch is shallow-merged server-side into the trace's existing metadata\n * (`existing || patch`, last-write-wins per top-level key). Useful for\n * attaching post-factum signals — quality scores, human edits, triage labels —\n * to a trace that has already finished. The patch does NOT extend `endTime`\n * or change tokens / cost / top span / tags / span names. `numSpans` is\n * incremented by 1 (paid by the virtual span that carried the patch through\n * the ingestion queue) so the new ClickHouse row beats the prior version on\n * `ReplacingMergeTree(numSpans)`. No row is added to the `spans` table.\n *\n * Compared to `Laminar.setTraceMetadata` (which sets metadata on the\n * currently in-flight trace via OpenTelemetry attributes), this method\n * operates on a finished trace by trace id, so it must be called after the\n * trace has been flushed.\n *\n * A 404 response (the trace was not found in the project — typically because\n * it has not been flushed yet) is logged as a warning and the call returns\n * without throwing; any other non-OK status throws.\n *\n * @param traceId - The trace id to push metadata to. Accepts a UUID string\n * or a 32-char OTel hex trace id.\n * @param metadata - The metadata patch. Top-level keys are merged into the\n * trace's existing metadata. Must be non-empty (the server rejects empty\n * patches with 400).\n * @example\n * ```typescript\n * import { Laminar, observe, LaminarClient } from \"@lmnr-ai/lmnr\";\n * Laminar.initialize();\n * const client = new LaminarClient();\n *\n * let traceId: string | null = null;\n * await observe({ name: \"generate\" }, async () => {\n * traceId = await Laminar.getTraceId();\n * });\n * await Laminar.flush();\n *\n * if (traceId) {\n * await client.traces.pushMetadata(traceId, {\n * score: 0.85,\n * reviewer: \"alice\",\n * needsReview: false,\n * });\n * }\n * ```\n */\n public async pushMetadata(\n traceId: string,\n metadata: Record<string, unknown>,\n ): Promise<void> {\n if (!metadata || Object.keys(metadata).length === 0) {\n throw new Error(\"metadata must be a non-empty object\");\n }\n\n const formattedTraceId = isStringUUID(traceId)\n ? traceId\n : otelTraceIdToUUID(traceId);\n\n const url = this.baseHttpUrl + \"/v1/traces/metadata\";\n const response = await fetch(url, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n traceId: formattedTraceId,\n metadata,\n }),\n });\n\n if (response.status === 404) {\n // Trace not found in this project — likely not flushed yet. Don't throw,\n // but surface a warning so callers debugging an empty patch see it.\n logger.warn(\n `Trace ${formattedTraceId} not found. The trace may not have been ` +\n \"flushed yet — call await Laminar.flush() and retry.\",\n );\n return;\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BrowserEventsResource } from \"./resources/browser-events\";\nimport { DatasetsResource } from \"./resources/datasets\";\nimport { EvalsResource } from \"./resources/evals\";\nimport { EvaluatorsResource } from \"./resources/evaluators\";\nimport { RolloutSessionsResource } from \"./resources/rollout-sessions\";\nimport { SqlResource } from \"./resources/sql\";\nimport { TagsResource } from \"./resources/tags\";\nimport { TracesResource } from \"./resources/traces\";\nimport { loadEnv } from \"./utils\";\n\nexport class LaminarClient {\n private baseUrl: string;\n private projectApiKey: string;\n private _browserEvents: BrowserEventsResource;\n private _datasets: DatasetsResource;\n private _evals: EvalsResource;\n private _evaluators: EvaluatorsResource;\n private _rolloutSessions: RolloutSessionsResource;\n private _sql: SqlResource;\n private _tags: TagsResource;\n private _traces: TracesResource;\n\n constructor({\n baseUrl,\n projectApiKey,\n port,\n }: {\n baseUrl?: string,\n projectApiKey?: string,\n port?: number,\n } = {}) {\n loadEnv();\n this.projectApiKey = projectApiKey ?? process.env.LMNR_PROJECT_API_KEY!;\n const httpPort = port ?? (\n baseUrl?.match(/:\\d{1,5}$/g)\n ? parseInt(baseUrl.match(/:\\d{1,5}$/g)![0].slice(1))\n : 443);\n const baseUrlNoPort = (baseUrl ?? process.env.LMNR_BASE_URL)\n ?.replace(/\\/$/, '').replace(/:\\d{1,5}$/g, '');\n this.baseUrl = `${baseUrlNoPort ?? 'https://api.lmnr.ai'}:${httpPort}`;\n this._browserEvents = new BrowserEventsResource(this.baseUrl, this.projectApiKey);\n this._datasets = new DatasetsResource(this.baseUrl, this.projectApiKey);\n this._evals = new EvalsResource(this.baseUrl, this.projectApiKey);\n this._evaluators = new EvaluatorsResource(this.baseUrl, this.projectApiKey);\n this._rolloutSessions = new RolloutSessionsResource(this.baseUrl, this.projectApiKey);\n this._sql = new SqlResource(this.baseUrl, this.projectApiKey);\n this._tags = new TagsResource(this.baseUrl, this.projectApiKey);\n this._traces = new TracesResource(this.baseUrl, this.projectApiKey);\n }\n\n public get browserEvents() {\n return this._browserEvents;\n }\n\n public get datasets() {\n return this._datasets;\n }\n\n public get evals() {\n return this._evals;\n }\n\n public get evaluators() {\n return this._evaluators;\n }\n\n public get rolloutSessions() {\n return this._rolloutSessions;\n }\n\n public get sql() {\n return this._sql;\n }\n\n public get tags() {\n return this._tags;\n }\n\n public get traces() {\n return this._traces;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACCA,SAAgB,iBAAgC;CAC9C,IAAI,OAAO,YAAY,eAAe,QAAQ,YAAY,QAAQ,SAAS,MACzE,OAAO,QAAQ,QAAQ,SAAS;CAElC,IAAI,OAAO,cAAc,eAAe,UAAU,WAChD,OAAO,WAAW,UAAU;CAE9B,OAAO;;;;ACRT,IAAM,eAAN,MAAmB;CAIjB,YAAY,aAAqB,eAAuB;EACtD,KAAK,cAAc;EACnB,KAAK,gBAAgB;;CAGvB,UAAoB;EAClB,OAAO;GACL,eAAe,UAAU,KAAK;GAC9B,gBAAgB;GAChB,QAAQ;GACT;;CAGH,MAAgB,YAAY,UAAoB;EAC9C,MAAM,WAAW,MAAM,SAAS,MAAM;EACtC,MAAM,IAAI,MAAM,GAAG,SAAS,OAAO,GAAG,WAAW;;;;;ACfrD,IAAa,wBAAb,cAA2C,aAAa;CACtD,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;CAGnC,MAAa,KAAK,EAChB,WACA,SACA,UAKgB;EAChB,MAAM,UAAU;GACd;GACA;GACA;GACA,QAAQ,gBAAgB,IAAI;GAC5B,YAAYA;GACb;EAED,MAAM,aAAa,KAAK,UAAU,QAAQ;EAE1C,MAAM,mBAAmB,IADR,KAAK,CAAC,WAAW,EAAE,EAAE,MAAM,oBAAoB,CACnC,CAAC,QAAQ,CAAC,YAAY,IAAI,kBAAkB,OAAO,CAAC;EAEjF,MAAM,iBAAiB,MAAM,IADE,SAAS,iBACO,CAAC,aAAa;EAE7D,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,+BAA+B;GAC7E,QAAQ;GACR,SAAS;IACP,GAAG,KAAK,SAAS;IACjB,oBAAoB;IACrB;GACD,MAAM;GACP,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;;;;ACnCtC,SAAgB,iBAAiB,SAAiD;CAChF,MAAM,WAAW,SAAS,YAAY;CACtC,MAAM,QACJ,SAAS,SACR,QAAQ,IAAI,gBAAgB,aAAa,EAAE,MAAM,IAClD;CAEF,QAAA,GAAA,KAAA,SACE,EACE,OACD,GAAA,GAAA,YAAA,YACU;EACT;EACA,cAAc;EACf,CAAC,CACH;;AAGH,MAAMC,WAAS,kBAAkB;AAEjC,MAAa,gBAAgB,OAC3B,iEAAiE,KAAK,GAAG;AAI3E,MAAa,gBAA4B;CAKvC,IAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAChE,OAAO,OAAO,YAAY;MAE1B,QAAA,GAAA,KAAA,KAAe;;AAInB,MAAa,oBAAoB,WAA2B;CAC1D,IAAI,KAAK,OAAO,aAAa;CAC7B,IAAI,GAAG,WAAW,KAAK,EACrB,KAAK,GAAG,MAAM,EAAE;CAElB,IAAI,GAAG,WAAW,IAChB,SAAO,KACL,WAAW,OAAO,uEAEnB;CAGH,IAAI,CAAC,cAAc,KAAK,GAAG,EAAE;EAC3B,SAAO,MACL,WAAW,OAAO,+DAEnB;EACD,OAAO,SAAS;;CAGlB,OAAO,GAAG,SAAS,IAAI,IAAI,CAAC,QAC1B,wEACA,iBACD;;AAGH,MAAa,qBAAqB,YAAgC;CAChE,IAAI,KAAK,QAAQ,aAAa;CAC9B,IAAI,GAAG,WAAW,KAAK,EACrB,KAAK,GAAG,MAAM,EAAE;CAElB,IAAI,GAAG,WAAW,IAChB,SAAO,KACL,YAAY,QAAQ,wEAErB;CAEH,IAAI,CAAC,cAAc,KAAK,GAAG,EAAE;EAC3B,SAAO,MACL,YAAY,QAAQ,+DAErB;EACD,OAAO,SAAS;;CAGlB,OAAO,GAAG,QACR,wEACA,iBACD;;AAGH,MAAa,gBAAmB,OAAU,WAAmB;CAC3D,IAAI,UAAU,QAAQ,UAAU,KAAA,GAC9B,OAAO;CAGT,MAAM,MAAM,KAAK,UAAU,MAAM;CACjC,IAAI,IAAI,UAAU,QAChB,OAAO;CAGT,OAAO,IAAI,MAAM,GAAG,OAAO,GAAG;;AAGhC,MAAa,WACX,YAIS;CACT,MAAM,UAAU,QAAQ,IAAI,YAAY;CACxC,MAAM,SAAS,QAAQ,KAAK;CAI5B,MAAM,WAAW;EACf;EACA;EACA,QAAQ;EACR,QAAQ,QAAQ;EACjB;CAED,MAAM,WAAW,QAAQ,IAAI,kBAAkB;CAC/C,MAAM,UAAU,CAAC,SAAS,QAAQ,CAAC,SAAS,SAAS,MAAM,CAAC,aAAa,CAAC;CAE1E,MAAM,QAAQ,SAAS,SAAS,CAAC;CAEjC,CAAA,GAAA,OAAA,QAAO;EACL,MAAM,SAAS,SAAS,SAAS,KAAK,YAAY,KAAK,QAAQ,QAAQ,QAAQ,CAAC;EAChF;EACD,CAAC;;;;AC3HJ,MAAMC,WAAS,kBAAkB;AACjC,MAAM,6BAA6B;AACnC,MAAM,kCAAkC;AAExC,IAAa,mBAAb,cAAsC,aAAa;CACjD,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;;;;;;CAQnC,MAAa,eAAmC;EAC9C,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,gBAAgB;GAC9D,QAAQ;GACR,SAAS,KAAK,SAAS;GACxB,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;EAGlC,OAAO,SAAS,MAAM;;;;;;;;CASxB,MAAa,iBAAiB,MAAkC;EAC9D,MAAM,SAAS,IAAI,gBAAgB,EAAE,MAAM,CAAC;EAC5C,MAAM,WAAW,MAAM,MACrB,KAAK,cAAc,gBAAgB,OAAO,UAAU,IACpD;GACE,QAAQ;GACR,SAAS,KAAK,SAAS;GACxB,CACF;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;EAGlC,OAAO,SAAS,MAAM;;;;;;;;;;;;;CAcxB,MAAa,KAAW,EACtB,QACA,MACA,IACA,YAAY,iCACZ,gBAAgB,SAO8B;EAC9C,IAAI,CAAC,QAAQ,CAAC,IACZ,MAAM,IAAI,MAAM,qCAAqC;EAGvD,IAAI,QAAQ,IACV,MAAM,IAAI,MAAM,0CAA0C;EAG5D,IAAI,iBAAiB,CAAC,MACpB,MAAM,IAAI,MAAM,oDAAoD;EAGtE,MAAM,aAAa,OAAO,EAAE,MAAM,GAAG,EAAE,WAAW,IAAK;EACvD,MAAM,eAAe,KAAK,KAAK,OAAO,SAAS,UAAU;EAEzD,IAAI;EACJ,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK,WAAW;GACjD,MAAM,WAAW,KAAK,MAAM,IAAI,UAAU,GAAG;GAC7C,SAAO,MAAM,iBAAiB,SAAS,MAAM,eAAe;GAE5D,MAAM,QAAQ,OAAO,MAAM,GAAG,IAAI,UAAU;GAC5C,MAAM,gBAAgB,MAAM,MAC1B,KAAK,cAAc,2BACnB;IACE,QAAQ;IACR,SAAS,KAAK,SAAS;IACvB,MAAM,KAAK,UAAU;KACnB,GAAG;KACH,YAAY,MAAM,KAAK,WAAW;MAChC,MAAM,MAAM;MACZ,QAAQ,MAAM,UAAU,EAAE;MAC1B,UAAU,MAAM,YAAY,EAAE;MAC/B,EAAE;KACH;KACD,CAAC;IACH,CACF;GAGD,IAAI,cAAc,WAAW,OAAO,cAAc,WAAW,KAC3D,MAAM,KAAK,YAAY,cAAc;GAGvC,WAAY,MAAM,cAAc,MAAM;;EAGxC,OAAO;;;;;;;;;;;;CAaT,MAAa,KAAW,EACtB,MACA,IACA,QAAQ,4BACR,SAAS,KAM8B;EACvC,IAAI,CAAC,QAAQ,CAAC,IACZ,MAAM,IAAI,MAAM,qCAAqC;EAGvD,IAAI,QAAQ,IACV,MAAM,IAAI,MAAM,0CAA0C;EAG5D,MAAM,YAAoC;GACxC,QAAQ,OAAO,UAAU;GACzB,OAAO,MAAM,UAAU;GACxB;EAED,IAAI,MACF,UAAU,OAAO;OAEjB,UAAU,YAAY;EAGxB,MAAM,SAAS,IAAI,gBAAgB,UAAU;EAE7C,MAAM,WAAW,MAAM,MACrB,KAAK,cAAc,2BAA2B,OAAO,UAAU,IAC/D;GACE,QAAQ;GACR,SAAS,KAAK,SAAS;GACxB,CACF;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;EAGlC,OAAO,SAAS,MAAM;;;;;AClL1B,MAAMC,WAAS,kBAAkB;AACjC,MAAM,+CAA+C;AAErD,IAAa,gBAAb,cAAmC,aAAa;CAC9C,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;;;;;;;;;CAWnC,MAAa,KACX,MACA,WACA,UACiC;EACjC,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,aAAa;GAC3D,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU;IACnB,MAAM,QAAQ;IACd,WAAW,aAAa;IACxB,UAAU,YAAY;IACvB,CAAC;GACH,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;EAGlC,OAAO,SAAS,MAAM;;;;;;;;;;CAYxB,MAAa,OAAO,MAEI;EAEtB,QAAO,MADkB,KAAK,KAAK,MAAM,MAAM,MAAM,WAAW,MAAM,SAAS,EAC7D;;;;;;CAOpB,MAAa,iBACX,MACA,WACA,UACqB;EAErB,QAAO,MADkB,KAAK,KAAK,MAAM,WAAW,SAAS,EAC3C;;;;;;;;;;;;;;CAepB,MAAa,gBAAsB,EACjC,QACA,MACA,QACA,UACA,OACA,WAQsB;EACtB,MAAM,cAAc,SAAS;EAE7B,MAAM,mBAAmD;GACvD,IAAI;GACJ;GACA;GACA,OAAO,SAAS;GAChB,SAAS,WAAW,SAAS;GAC7B,gBAAgB,SAAS;GACzB;GACD;EAED,MAAM,KAAK,eAAe;GACxB;GACA,YAAY,CAAC,iBAAiB;GAC/B,CAAC;EAEF,OAAO;;;;;;;;;;;;CAaT,MAAa,gBAAmB,EAC9B,QACA,aACA,QACA,kBAMgB;EAChB,MAAM,WAAW,MAAM,MACrB,KAAK,cAAc,aAAa,OAAO,cAAc,eACrD;GACE,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU;IACnB;IACA;IACD,CAAC;GACH,CACF;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;;;;;;;;;;CAapC,MAAa,eAAwB,EACnC,QACA,YACA,aAKgB;EAChB,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,aAAa,OAAO,cAAc;GAChF,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU;IACnB,QAAQ,WAAW,KAAK,OACtB;KACE,GAAG;KACH,MAAM,aAAa,EAAE,MAAM,6CAA6C;KACxE,QAAQ,aAAa,EAAE,QAAQ,6CAA6C;KAC5E,gBAAgB,aACd,EAAE,gBACF,6CACD;KACF,EAAE;IACL,WAAW,aAAa;IACzB,CAAC;GACH,CAAC;EAEF,IAAI,SAAS,WAAW,KACtB,OAAO,MAAM,KAAK,oBAAoB;GACpC;GACA;GACA;GACD,CAAC;EAGJ,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;;;;;;;;;;;CAcpC,MAAa,cAAoB,EAC/B,aACA,QACA,SAKuC;EACvC,SAAO,KACL,2EACD;EAED,MAAM,SAAS,IAAI,gBAAgB;GACjC,MAAM;GACN,QAAQ,OAAO,UAAU;GACzB,OAAO,MAAM,UAAU;GACxB,CAAC;EACF,MAAM,WAAW,MAAM,MACrB,KAAK,cAAc,2BAA2B,OAAO,UAAU,IAC/D;GACE,QAAQ;GACR,SAAS,KAAK,SAAS;GACxB,CACF;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;EAGlC,OAAQ,MAAM,SAAS,MAAM;;CAG/B,MAAc,oBAA6B,EACzC,QACA,YACA,WACA,aAAa,IACb,gBAAgB,gDAOA;EAChB,IAAI,SAAS;EACb,IAAI,eAAgC;EACpC,KAAK,IAAI,IAAI,GAAG,IAAI,YAAY,KAAK;GACnC,SAAO,MAAM,+BAA+B,IAAI,EAAE,MAAM,WAAW,YAAY,SAAS;GACxF,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,aAAa,OAAO,cAAc;IAChF,QAAQ;IACR,SAAS,KAAK,SAAS;IACvB,MAAM,KAAK,UAAU;KACnB,QAAQ,WAAW,KAAK,OACtB;MACE,GAAG;MACH,MAAM,aAAa,EAAE,MAAM,OAAO;MAClC,QAAQ,aAAa,EAAE,QAAQ,OAAO;MACtC,gBAAgB,aAAa,EAAE,gBAAgB,OAAO;MACvD,EAAE;KACL,WAAW,aAAa;KACzB,CAAC;IACH,CAAC;GACF,eAAe;GACf,SAAS,KAAK,MAAM,SAAS,EAAE;GAC/B,IAAI,SAAS,WAAW,KACtB;;EAGJ,IAAI,gBAAgB,CAAC,aAAa,IAChC,MAAM,KAAK,YAAY,aAAa;;;;;;;;ACpQ1C,IAAa,qBAAb,cAAwC,aAAa;CACnD,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BnC,MAAa,MAAM,SAAsC;EACvD,MAAM,EAAE,MAAM,UAAU,UAAU;EAElC,IAAI;EAEJ,IAAI,aAAa,WAAW,QAAQ,SAKlC,UAAU;GACR;GACA;GACA;GACA,QAAA;GACA,SATuB,aAAa,QAAQ,QAAQ,GAClD,QAAQ,UACR,kBAAkB,QAAQ,QAAQ;GAQrC;OACI,IAAI,YAAY,WAAW,QAAQ,QAKxC,UAAU;GACR;GACA;GACA;GACA,QAAA;GACA,QATsB,aAAa,QAAQ,OAAO,GAChD,QAAQ,SACR,iBAAiB,QAAQ,OAAO;GAQnC;OAED,MAAM,IAAI,MAAM,iDAAiD;EAGnE,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,wBAAwB;GACtE,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU,QAAQ;GAC9B,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;;;;ACpGtC,IAAa,0BAAb,cAA6C,aAAa;CACxD,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;;;;;CAOnC,MAAa,QAAQ,EACnB,WACA,MACA,QACA,UAMoB;EACpB,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,YAAY,eAAe,aAAa;GAC3E,QAAQ;GACR,SAAS;IACP,GAAG,KAAK,SAAS;IACjB,UAAU;IACX;GACD,MAAM,KAAK,UAAU;IAAE;IAAM;IAAQ,CAAC;GACtC;GACD,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,0BAA0B,SAAS,OAAO,GAAG,SAAS,aAAa;EAGrF,IAAI,CAAC,SAAS,MACZ,MAAM,IAAI,MAAM,mBAAmB;EAGrC,OAAO;;CAGT,MAAa,OAAO,EAClB,aAGC;EACD,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,YAAY,eAAe,aAAa;GAC3E,QAAQ;GACR,SAAS,KAAK,SAAS;GACxB,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;CAIpC,MAAa,UAAU,EACrB,WACA,UAIC;EACD,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,YAAY,eAAe,UAAU,UAAU;GAClF,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU,EAAE,QAAQ,CAAC;GACjC,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;CAIpC,MAAa,eAAe,EAC1B,WACA,QAYC;EACD,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,YAAY,eAAe,UAAU,UAAU;GAClF,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU;IACnB,MAAM;IACN,QAAQ,iBAAiB,KAAK,OAAO;IACrC,SAAS,kBAAkB,KAAK,QAAQ;IACxC,cAAc,KAAK,eAAe,iBAAiB,KAAK,aAAa,GAAG,KAAA;IACxE,YAAY,KAAK;IACjB,WAAW,KAAK;IAChB,MAAM,KAAK;IACX,UAAU,KAAK;IAChB,CAAC;GACH,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;;;;AC5GtC,IAAa,cAAb,cAAiC,aAAa;CAC5C,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;CAGnC,MAAa,MACX,KACA,aAAkC,EAAE,EACC;EACrC,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,YAAY,gBAAgB;GAC/D,QAAQ;GACR,SAAS,EACP,GAAG,KAAK,SAAS,EAClB;GACD,MAAM,KAAK,UAAU;IACnB,OAAO;IACP;IACD,CAAC;GACH,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;EAGlC,QAAQ,MAAM,SAAS,MAAM,EAAE;;;;;;ACpBnC,IAAa,eAAb,cAAkC,aAAa;;CAE7C,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCnC,MAAa,IACX,UACA,MACc;EACd,MAAM,YAAY,MAAM,QAAQ,KAAK,GAAG,OAAO,CAAC,KAAK;EACrD,MAAM,mBAAmB,aAAa,SAAS,GAC3C,WACA,kBAAkB,SAAS;EAE/B,MAAM,MAAM,KAAK,cAAc;EAC/B,MAAM,UAAU;GACd,WAAW;GACX,SAAS;GACV;EACD,MAAM,WAAW,MAAM,MACrB,KACA;GACE,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU,QAAQ;GAC9B,CACF;EACD,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;EAElC,OAAO,SAAS,MAAM;;;;;;AChE1B,MAAM,SAAS,kBAAkB;AAEjC,IAAa,iBAAb,cAAoC,aAAa;;CAE/C,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkDnC,MAAa,aACX,SACA,UACe;EACf,IAAI,CAAC,YAAY,OAAO,KAAK,SAAS,CAAC,WAAW,GAChD,MAAM,IAAI,MAAM,sCAAsC;EAGxD,MAAM,mBAAmB,aAAa,QAAQ,GAC1C,UACA,kBAAkB,QAAQ;EAE9B,MAAM,MAAM,KAAK,cAAc;EAC/B,MAAM,WAAW,MAAM,MAAM,KAAK;GAChC,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU;IACnB,SAAS;IACT;IACD,CAAC;GACH,CAAC;EAEF,IAAI,SAAS,WAAW,KAAK;GAG3B,OAAO,KACL,SAAS,iBAAiB,6FAE3B;GACD;;EAGF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;;;;ACnFtC,IAAa,gBAAb,MAA2B;CAYzB,YAAY,EACV,SACA,eACA,SAKE,EAAE,EAAE;EACN,SAAS;EACT,KAAK,gBAAgB,iBAAiB,QAAQ,IAAI;EAClD,MAAM,WAAW,SACf,SAAS,MAAM,aAAa,GACxB,SAAS,QAAQ,MAAM,aAAa,CAAE,GAAG,MAAM,EAAE,CAAC,GAClD;EACN,MAAM,iBAAiB,WAAW,QAAQ,IAAI,gBAC1C,QAAQ,OAAO,GAAG,CAAC,QAAQ,cAAc,GAAG;EAChD,KAAK,UAAU,GAAG,iBAAiB,sBAAsB,GAAG;EAC5D,KAAK,iBAAiB,IAAI,sBAAsB,KAAK,SAAS,KAAK,cAAc;EACjF,KAAK,YAAY,IAAI,iBAAiB,KAAK,SAAS,KAAK,cAAc;EACvE,KAAK,SAAS,IAAI,cAAc,KAAK,SAAS,KAAK,cAAc;EACjE,KAAK,cAAc,IAAI,mBAAmB,KAAK,SAAS,KAAK,cAAc;EAC3E,KAAK,mBAAmB,IAAI,wBAAwB,KAAK,SAAS,KAAK,cAAc;EACrF,KAAK,OAAO,IAAI,YAAY,KAAK,SAAS,KAAK,cAAc;EAC7D,KAAK,QAAQ,IAAI,aAAa,KAAK,SAAS,KAAK,cAAc;EAC/D,KAAK,UAAU,IAAI,eAAe,KAAK,SAAS,KAAK,cAAc;;CAGrE,IAAW,gBAAgB;EACzB,OAAO,KAAK;;CAGd,IAAW,WAAW;EACpB,OAAO,KAAK;;CAGd,IAAW,QAAQ;EACjB,OAAO,KAAK;;CAGd,IAAW,aAAa;EACtB,OAAO,KAAK;;CAGd,IAAW,kBAAkB;EAC3B,OAAO,KAAK;;CAGd,IAAW,MAAM;EACf,OAAO,KAAK;;CAGd,IAAW,OAAO;EAChB,OAAO,KAAK;;CAGd,IAAW,SAAS;EAClB,OAAO,KAAK"}
1
+ {"version":3,"file":"index.cjs","names":["SDK_VERSION","logger","logger","logger","logger"],"sources":["../package.json","../src/version.ts","../src/resources/index.ts","../src/resources/browser-events.ts","../src/utils.ts","../src/resources/datasets.ts","../src/resources/evals.ts","../src/resources/evaluators.ts","../src/resources/rollout-sessions.ts","../src/resources/sql.ts","../src/resources/tags.ts","../src/resources/traces.ts","../src/index.ts"],"sourcesContent":["","// Version detection for runtime environment\nexport function getLangVersion(): string | null {\n if (typeof process !== 'undefined' && process.versions && process.versions.node) {\n return `node-${process.versions.node}`;\n }\n if (typeof navigator !== 'undefined' && navigator.userAgent) {\n return `browser-${navigator.userAgent}`;\n }\n return null;\n}\n","class BaseResource {\n protected readonly baseHttpUrl: string;\n protected readonly projectApiKey: string;\n\n constructor(baseHttpUrl: string, projectApiKey: string) {\n this.baseHttpUrl = baseHttpUrl;\n this.projectApiKey = projectApiKey;\n }\n\n protected headers() {\n return {\n Authorization: `Bearer ${this.projectApiKey}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n }\n\n protected async handleError(response: Response) {\n const errorMsg = await response.text();\n throw new Error(`${response.status} ${errorMsg}`);\n }\n}\n\nexport { BaseResource };\n","import { version as SDK_VERSION } from '../../package.json';\nimport { getLangVersion } from \"../version\";\nimport { BaseResource } from \"./index\";\n\nexport class BrowserEventsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n public async send({\n sessionId,\n traceId,\n events,\n }: {\n sessionId: string;\n traceId: string;\n events: Record<string, any>[];\n }): Promise<void> {\n const payload = {\n sessionId,\n traceId,\n events,\n source: getLangVersion() ?? 'javascript',\n sdkVersion: SDK_VERSION,\n };\n\n const jsonString = JSON.stringify(payload);\n const blob = new Blob([jsonString], { type: 'application/json' });\n const compressedStream = blob.stream().pipeThrough(new CompressionStream('gzip'));\n const compressedResponse = new Response(compressedStream);\n const compressedData = await compressedResponse.arrayBuffer();\n\n const response = await fetch(this.baseHttpUrl + \"/v1/browser-sessions/events\", {\n method: \"POST\",\n headers: {\n ...this.headers(),\n 'Content-Encoding': 'gzip',\n },\n body: compressedData,\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { type StringUUID } from '@lmnr-ai/types';\nimport { config } from 'dotenv';\nimport * as path from 'path';\nimport pino, { Level } from 'pino';\nimport { PinoPretty } from 'pino-pretty';\nimport { v4 as uuidv4 } from 'uuid';\n\nexport function initializeLogger(options?: { colorize?: boolean; level?: Level }) {\n const colorize = options?.colorize ?? true;\n const level =\n options?.level ??\n (process.env.LMNR_LOG_LEVEL?.toLowerCase()?.trim() as Level) ??\n 'info';\n\n return pino(\n {\n level,\n },\n PinoPretty({\n colorize,\n minimumLevel: level,\n }),\n );\n}\n\nconst logger = initializeLogger();\n\nexport const isStringUUID = (id: string): id is StringUUID =>\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(id);\n\nexport const NIL_UUID: StringUUID = '00000000-0000-0000-0000-000000000000';\n\nexport const newUUID = (): StringUUID => {\n // crypto.randomUUID is available in most of the modern browsers and node,\n // but is not available in \"insecure\" contexts, e.g. not https, not localhost\n // so we fallback to uuidv4 in those cases, which is less secure, but works\n // just fine.\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n } else {\n return uuidv4() as `${string}-${string}-${string}-${string}-${string}`;\n }\n};\n\nexport const otelSpanIdToUUID = (spanId: string): string => {\n let id = spanId.toLowerCase();\n if (id.startsWith('0x')) {\n id = id.slice(2);\n }\n if (id.length !== 16) {\n logger.warn(\n `Span ID ${spanId} is not 16 hex chars long. ` +\n 'This is not a valid OpenTelemetry span ID.',\n );\n }\n\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(\n `Span ID ${spanId} is not a valid hex string. ` +\n 'Generating a random UUID instead.',\n );\n return newUUID();\n }\n\n return id.padStart(32, '0').replace(\n /^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/,\n '$1-$2-$3-$4-$5',\n );\n};\n\nexport const otelTraceIdToUUID = (traceId: string): StringUUID => {\n let id = traceId.toLowerCase();\n if (id.startsWith('0x')) {\n id = id.slice(2);\n }\n if (id.length !== 32) {\n logger.warn(\n `Trace ID ${traceId} is not 32 hex chars long. ` +\n 'This is not a valid OpenTelemetry trace ID.',\n );\n }\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(\n `Trace ID ${traceId} is not a valid hex string. ` +\n 'Generating a random UUID instead.',\n );\n return newUUID();\n }\n\n return id.replace(\n /^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/,\n '$1-$2-$3-$4-$5',\n ) as StringUUID;\n};\n\nexport const slicePayload = <T>(value: T, length: number) => {\n if (value === null || value === undefined) {\n return value;\n }\n\n const str = JSON.stringify(value);\n if (str.length <= length) {\n return value;\n }\n\n return str.slice(0, length) + '...';\n};\n\nexport const loadEnv = (\n options?: {\n quiet?: boolean;\n paths?: string[];\n },\n): void => {\n const nodeEnv = process.env.NODE_ENV || 'development';\n const envDir = process.cwd();\n\n // Files to load in order (lowest to highest priority)\n // Later files override earlier ones\n const envFiles = [\n '.env',\n '.env.local',\n `.env.${nodeEnv}`,\n `.env.${nodeEnv}.local`,\n ];\n\n const logLevel = process.env.LMNR_LOG_LEVEL ?? 'info';\n const verbose = ['debug', 'trace'].includes(logLevel.trim().toLowerCase());\n\n const quiet = options?.quiet ?? !verbose;\n\n config({\n path: options?.paths ?? envFiles.map((envFile) => path.resolve(envDir, envFile)),\n quiet,\n });\n};\n","import {\n type Datapoint,\n type Dataset,\n type GetDatapointsResponse,\n type PushDatapointsResponse,\n type StringUUID,\n} from \"@lmnr-ai/types\";\n\nimport { initializeLogger } from \"../utils\";\nimport { BaseResource } from \".\";\n\nconst logger = initializeLogger();\nconst DEFAULT_DATASET_PULL_LIMIT = 100;\nconst DEFAULT_DATASET_PUSH_BATCH_SIZE = 100;\n\nexport class DatasetsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * List all datasets.\n *\n * @returns {Promise<Dataset[]>} Array of datasets\n */\n public async listDatasets(): Promise<Dataset[]> {\n const response = await fetch(this.baseHttpUrl + \"/v1/datasets\", {\n method: \"GET\",\n headers: this.headers(),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<Dataset[]>;\n }\n\n /**\n * Get a dataset by name.\n *\n * @param {string} name - Name of the dataset\n * @returns {Promise<Dataset[]>} Array of datasets with matching name\n */\n public async getDatasetByName(name: string): Promise<Dataset[]> {\n const params = new URLSearchParams({ name });\n const response = await fetch(\n this.baseHttpUrl + `/v1/datasets?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<Dataset[]>;\n }\n\n /**\n * Push datapoints to a dataset.\n *\n * @param {Object} options - Push options\n * @param {Datapoint<D, T>[]} options.points - Datapoints to push\n * @param {string} [options.name] - Name of the dataset (either name or id must be provided)\n * @param {StringUUID} [options.id] - ID of the dataset (either name or id must be provided)\n * @param {number} [options.batchSize] - Batch size for pushing (default: 100)\n * @param {boolean} [options.createDataset] - Whether to create the dataset if it doesn't exist\n * @returns {Promise<PushDatapointsResponse | undefined>}\n */\n public async push<D, T>({\n points,\n name,\n id,\n batchSize = DEFAULT_DATASET_PUSH_BATCH_SIZE,\n createDataset = false,\n }: {\n points: Datapoint<D, T>[];\n name?: string;\n id?: StringUUID;\n batchSize?: number;\n createDataset?: boolean;\n }): Promise<PushDatapointsResponse | undefined> {\n if (!name && !id) {\n throw new Error(\"Either name or id must be provided\");\n }\n\n if (name && id) {\n throw new Error(\"Only one of name or id must be provided\");\n }\n\n if (createDataset && !name) {\n throw new Error(\"Name must be provided when creating a new dataset\");\n }\n\n const identifier = name ? { name } : { datasetId: id! };\n const totalBatches = Math.ceil(points.length / batchSize);\n\n let response: PushDatapointsResponse | undefined;\n for (let i = 0; i < points.length; i += batchSize) {\n const batchNum = Math.floor(i / batchSize) + 1;\n logger.debug(`Pushing batch ${batchNum} of ${totalBatches}`);\n\n const batch = points.slice(i, i + batchSize);\n const fetchResponse = await fetch(\n this.baseHttpUrl + \"/v1/datasets/datapoints\",\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n ...identifier,\n datapoints: batch.map((point) => ({\n data: point.data,\n target: point.target ?? {},\n metadata: point.metadata ?? {},\n })),\n createDataset,\n }),\n },\n );\n\n // 201 when creating a new dataset\n if (fetchResponse.status !== 200 && fetchResponse.status !== 201) {\n await this.handleError(fetchResponse);\n }\n\n response = (await fetchResponse.json()) as PushDatapointsResponse;\n }\n\n return response;\n }\n\n /**\n * Pull datapoints from a dataset.\n *\n * @param {Object} options - Pull options\n * @param {string} [options.name] - Name of the dataset (either name or id must be provided)\n * @param {StringUUID} [options.id] - ID of the dataset (either name or id must be provided)\n * @param {number} [options.limit] - Maximum number of datapoints to return (default: 100)\n * @param {number} [options.offset] - Offset for pagination (default: 0)\n * @returns {Promise<GetDatapointsResponse<D, T>>}\n */\n public async pull<D, T>({\n name,\n id,\n limit = DEFAULT_DATASET_PULL_LIMIT,\n offset = 0,\n }: {\n name?: string;\n id?: StringUUID;\n limit?: number;\n offset?: number;\n }): Promise<GetDatapointsResponse<D, T>> {\n if (!name && !id) {\n throw new Error(\"Either name or id must be provided\");\n }\n\n if (name && id) {\n throw new Error(\"Only one of name or id must be provided\");\n }\n\n const paramsObj: Record<string, string> = {\n offset: offset.toString(),\n limit: limit.toString(),\n };\n\n if (name) {\n paramsObj.name = name;\n } else {\n paramsObj.datasetId = id!;\n }\n\n const params = new URLSearchParams(paramsObj);\n\n const response = await fetch(\n this.baseHttpUrl + `/v1/datasets/datapoints?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<GetDatapointsResponse<D, T>>;\n }\n}\n","import {\n type EvaluationDatapoint,\n type GetDatapointsResponse,\n type InitEvaluationResponse,\n type StringUUID,\n} from \"@lmnr-ai/types\";\n\nimport { initializeLogger, newUUID, slicePayload } from \"../utils\";\nimport { BaseResource } from \".\";\n\nconst logger = initializeLogger();\nconst INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH = 16_000_000; // 16MB\n\nexport class EvalsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Initialize an evaluation.\n *\n * @param {string} name - Name of the evaluation\n * @param {string} groupName - Group name of the evaluation\n * @param {Record<string, any>} metadata - Optional metadata\n * @returns {Promise<InitEvaluationResponse>} Response from the evaluation initialization\n */\n public async init(\n name?: string,\n groupName?: string,\n metadata?: Record<string, any>,\n ): Promise<InitEvaluationResponse> {\n const response = await fetch(this.baseHttpUrl + \"/v1/evals\", {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n name: name ?? null,\n groupName: groupName ?? null,\n metadata: metadata ?? null,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<InitEvaluationResponse>;\n }\n\n /**\n * Create a new evaluation and return its ID.\n *\n * @param {string} [name] - Optional name of the evaluation\n * @param {string} [groupName] - An identifier to group evaluations\n * @param {Record<string, any>} [metadata] - Optional metadata\n * @returns {Promise<StringUUID>} The evaluation ID\n */\n\n public async create(args?: {\n name?: string, groupName?: string, metadata?: Record<string, any>\n }): Promise<StringUUID> {\n const evaluation = await this.init(args?.name, args?.groupName, args?.metadata);\n return evaluation.id;\n }\n\n /**\n * Create a new evaluation and return its ID.\n * @deprecated use `create` instead.\n */\n public async createEvaluation(\n name?: string,\n groupName?: string,\n metadata?: Record<string, any>,\n ): Promise<StringUUID> {\n const evaluation = await this.init(name, groupName, metadata);\n return evaluation.id;\n }\n\n /**\n * Create a datapoint for an evaluation.\n *\n * @param {Object} options - Create datapoint options\n * @param {string} options.evalId - The evaluation ID\n * @param {D} options.data - The input data for the executor\n * @param {T} [options.target] - The target/expected output for evaluators\n * @param {Record<string, any>} [options.metadata] - Optional metadata\n * @param {number} [options.index] - Optional index of the datapoint\n * @param {string} [options.traceId] - Optional trace ID\n * @returns {Promise<StringUUID>} The datapoint ID\n */\n public async createDatapoint<D, T>({\n evalId,\n data,\n target,\n metadata,\n index,\n traceId,\n }: {\n evalId: string;\n data: D;\n target?: T;\n metadata?: Record<string, any>;\n index?: number;\n traceId?: string;\n }): Promise<StringUUID> {\n const datapointId = newUUID();\n\n const partialDatapoint: EvaluationDatapoint<D, T, any> = {\n id: datapointId,\n data,\n target,\n index: index ?? 0,\n traceId: traceId ?? newUUID(),\n executorSpanId: newUUID(),\n metadata,\n };\n\n await this.saveDatapoints({\n evalId,\n datapoints: [partialDatapoint],\n });\n\n return datapointId;\n }\n\n /**\n * Update a datapoint with evaluation results.\n *\n * @param {Object} options - Update datapoint options\n * @param {string} options.evalId - The evaluation ID\n * @param {string} options.datapointId - The datapoint ID\n * @param {Record<string, number>} options.scores - The scores\n * @param {O} [options.executorOutput] - The executor output\n * @returns {Promise<void>}\n */\n public async updateDatapoint<O>({\n evalId,\n datapointId,\n scores,\n executorOutput,\n }: {\n evalId: string;\n datapointId: string;\n scores: Record<string, number>;\n executorOutput?: O;\n }): Promise<void> {\n const response = await fetch(\n this.baseHttpUrl + `/v1/evals/${evalId}/datapoints/${datapointId}`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n executorOutput,\n scores,\n }),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n /**\n * Save evaluation datapoints.\n *\n * @param {Object} options - Save datapoints options\n * @param {string} options.evalId - ID of the evaluation\n * @param {EvaluationDatapoint<D, T, O>[]} options.datapoints - Datapoint to add\n * @param {string} [options.groupName] - Group name of the evaluation\n * @returns {Promise<void>} Response from the datapoint addition\n */\n public async saveDatapoints<D, T, O>({\n evalId,\n datapoints,\n groupName,\n }: {\n evalId: string;\n datapoints: EvaluationDatapoint<D, T, O>[];\n groupName?: string;\n }): Promise<void> {\n const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n points: datapoints.map((d) => (\n {\n ...d,\n data: slicePayload(d.data, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH),\n target: slicePayload(d.target, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH),\n executorOutput: slicePayload(\n d.executorOutput,\n INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH,\n ),\n })),\n groupName: groupName ?? null,\n }),\n });\n\n if (response.status === 413) {\n return await this.retrySaveDatapoints({\n evalId,\n datapoints,\n groupName,\n });\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n /**\n * Get evaluation datapoints.\n *\n * @deprecated Use `client.datasets.pull()` instead.\n * @param {Object} options - Get datapoints options\n * @param {string} options.datasetName - Name of the dataset\n * @param {number} options.offset - Offset at which to start the query\n * @param {number} options.limit - Maximum number of datapoints to return\n * @returns {Promise<GetDatapointsResponse>} Response from the datapoint retrieval\n */\n public async getDatapoints<D, T>({\n datasetName,\n offset,\n limit,\n }: {\n datasetName: string;\n offset: number;\n limit: number;\n }): Promise<GetDatapointsResponse<D, T>> {\n logger.warn(\n 'evals.getDatapoints() is deprecated. Use client.datasets.pull() instead.',\n );\n\n const params = new URLSearchParams({\n name: datasetName,\n offset: offset.toString(),\n limit: limit.toString(),\n });\n const response = await fetch(\n this.baseHttpUrl + `/v1/datasets/datapoints?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()) as GetDatapointsResponse<D, T>;\n }\n\n private async retrySaveDatapoints<D, T, O>({\n evalId,\n datapoints,\n groupName,\n maxRetries = 25,\n initialLength = INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH,\n }: {\n evalId: string;\n datapoints: EvaluationDatapoint<D, T, O>[];\n groupName?: string;\n maxRetries?: number;\n initialLength?: number;\n }): Promise<void> {\n let length = initialLength;\n let lastResponse: Response | null = null;\n for (let i = 0; i < maxRetries; i++) {\n logger.debug(`Retrying save datapoints... ${i + 1} of ${maxRetries}, length: ${length}`);\n const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n points: datapoints.map((d) => (\n {\n ...d,\n data: slicePayload(d.data, length),\n target: slicePayload(d.target, length),\n executorOutput: slicePayload(d.executorOutput, length),\n })),\n groupName: groupName ?? null,\n }),\n });\n lastResponse = response;\n length = Math.floor(length / 2);\n if (response.status !== 413) {\n break;\n }\n }\n if (lastResponse && !lastResponse.ok) {\n await this.handleError(lastResponse);\n }\n }\n}\n","import { type StringUUID } from \"@lmnr-ai/types\";\n\nimport { isStringUUID, otelSpanIdToUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \".\";\n\nenum EvaluatorScoreSourceType {\n Evaluator = \"Evaluator\",\n Code = \"Code\",\n}\n\ninterface CreateEvaluatorScoreBase {\n name: string;\n metadata?: Record<string, any>;\n score: number;\n source: EvaluatorScoreSourceType;\n}\n\ninterface CreateEvaluatorScoreRequestWithTraceId extends CreateEvaluatorScoreBase {\n traceId: string;\n}\n\ninterface CreateEvaluatorScoreRequestWithSpanId extends CreateEvaluatorScoreBase {\n spanId: string;\n}\n\ntype ScoreOptions =\n | { name: string; metadata?: Record<string, any>; score: number; traceId: string; }\n | { name: string; metadata?: Record<string, any>; score: number; spanId: string; };\n\n/**\n * Resource for creating evaluator scores\n */\nexport class EvaluatorsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Create a score for a span or trace\n *\n * @param {ScoreOptions} options - Score creation options\n * @param {string} options.name - Name of the score\n * @param {string} [options.traceId] - The trace ID to score (will be attached to top-level span)\n * @param {string} [options.spanId] - The span ID to score\n * @param {Record<string, any>} [options.metadata] - Additional metadata\n * @param {number} options.score - The score value (float)\n * @returns {Promise<void>}\n *\n * @example\n * // Score by trace ID (will attach to root span)\n * await evaluators.score({\n * name: \"quality\",\n * traceId: \"trace-id-here\",\n * score: 0.95,\n * metadata: { model: \"gpt-4\" }\n * });\n *\n * @example\n * // Score by span ID\n * await evaluators.score({\n * name: \"relevance\",\n * spanId: \"span-id-here\",\n * score: 0.87\n * });\n */\n public async score(options: ScoreOptions): Promise<void> {\n const { name, metadata, score } = options;\n\n let payload: CreateEvaluatorScoreRequestWithTraceId | CreateEvaluatorScoreRequestWithSpanId;\n\n if ('traceId' in options && options.traceId) {\n const formattedTraceId = isStringUUID(options.traceId)\n ? options.traceId\n : otelTraceIdToUUID(options.traceId);\n\n payload = {\n name,\n metadata,\n score,\n source: EvaluatorScoreSourceType.Code,\n traceId: formattedTraceId,\n };\n } else if ('spanId' in options && options.spanId) {\n const formattedSpanId = isStringUUID(options.spanId)\n ? options.spanId\n : otelSpanIdToUUID(options.spanId) as StringUUID;\n\n payload = {\n name,\n metadata,\n score,\n source: EvaluatorScoreSourceType.Code,\n spanId: formattedSpanId,\n };\n } else {\n throw new Error(\"Either 'traceId' or 'spanId' must be provided.\");\n }\n\n const response = await fetch(this.baseHttpUrl + \"/v1/evaluators/score\", {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { errorMessage } from \"@lmnr-ai/types\";\n\nimport { initializeLogger } from \"../utils\";\nimport { BaseResource } from \"./index\";\n\nconst logger = initializeLogger();\n\nexport class RolloutSessionsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Idempotently register (upsert) a debug session on the backend, keyed on the\n * SDK-supplied session id. The backend stores the row so the session is\n * visible in the UI; a null/omitted name never clobbers a name set elsewhere.\n *\n * Returns the backend-resolved `projectId` (derived from the API key) so the\n * caller can build the debugger URL; null if the body can't be parsed.\n */\n public async register({\n sessionId,\n name,\n }: {\n sessionId: string;\n name?: string;\n }): Promise<string | null> {\n const response = await fetch(\n `${this.baseHttpUrl}/v1/rollouts/${sessionId}`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({ name }),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n try {\n const body = (await response.json()) as { projectId?: string };\n return body.projectId ?? null;\n } catch (e) {\n logger.warn(\n `Failed to parse rollout register response: ${errorMessage(e)}`,\n );\n return null;\n }\n }\n\n /**\n * Rename an existing debug session. Update-only: the backend returns 404 (and\n * this throws) when the session id is unknown for the project, so a mistyped\n * id surfaces as an error rather than silently creating a session. Creation\n * stays the SDK's job via {@link register}.\n */\n public async setName({\n sessionId,\n name,\n }: {\n sessionId: string;\n name: string;\n }): Promise<void> {\n const response = await fetch(\n `${this.baseHttpUrl}/v1/rollouts/${sessionId}/name`,\n {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify({ name }),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n public async delete({ sessionId }: { sessionId: string }): Promise<void> {\n const response = await fetch(\n `${this.baseHttpUrl}/v1/rollouts/${sessionId}`,\n {\n method: \"DELETE\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BaseResource } from \"./index\";\n\nexport class SqlResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n public async query(\n sql: string,\n parameters: Record<string, any> = {},\n ): Promise<Array<Record<string, any>>> {\n const response = await fetch(`${this.baseHttpUrl}/v1/sql/query`, {\n method: \"POST\",\n headers: {\n ...this.headers(),\n },\n body: JSON.stringify({\n query: sql,\n parameters,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()).data as Array<Record<string, any>>;\n }\n}\n","/** Resource for tagging traces. */\n\n\nimport { isStringUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \"./index\";\n\nexport class TagsResource extends BaseResource {\n /** Resource for tagging traces. */\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Tag a trace with a list of tags. Note that the trace must be ended before\n * tagging it. You may want to call `await Laminar.flush()` after the trace\n * that you want to tag.\n *\n * @param {string | StringUUID} trace_id - The trace id to tag.\n * @param {string[] | string} tags - The tag or list of tags to add to the trace.\n * @returns {Promise<any>} The response from the server.\n * @example\n * ```javascript\n * import { Laminar, observe, LaminarClient } from \"@lmnr-ai/lmnr\";\n * Laminar.initialize();\n * const client = new LaminarClient();\n * let traceId: StringUUID | null = null;\n * // Make sure this is called outside of traced context.\n * await observe(\n * {\n * name: \"my-trace\",\n * },\n * async () => {\n * traceId = await Laminar.getTraceId();\n * await foo();\n * },\n * );\n *\n * // or make sure the trace is ended by this point.\n * await Laminar.flush();\n * if (traceId) {\n * await client.tags.tag(traceId, [\"tag1\", \"tag2\"]);\n * }\n * ```\n */\n public async tag(\n trace_id: string,\n tags: string[] | string,\n ): Promise<any> {\n const traceTags = Array.isArray(tags) ? tags : [tags];\n const formattedTraceId = isStringUUID(trace_id)\n ? trace_id\n : otelTraceIdToUUID(trace_id);\n\n const url = this.baseHttpUrl + \"/v1/tag\";\n const payload = {\n \"traceId\": formattedTraceId,\n \"names\": traceTags,\n };\n const response = await fetch(\n url,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(payload),\n },\n );\n if (!response.ok) {\n await this.handleError(response);\n }\n return response.json();\n }\n}\n","/** Resource for post-factum operations on existing traces. */\n\nimport { initializeLogger, isStringUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \"./index\";\n\nconst logger = initializeLogger();\n\nexport class TracesResource extends BaseResource {\n /** Resource for post-factum operations on existing traces. */\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Push a metadata patch to an existing trace.\n *\n * The patch is shallow-merged server-side into the trace's existing metadata\n * (`existing || patch`, last-write-wins per top-level key). Useful for\n * attaching post-factum signals — quality scores, human edits, triage labels —\n * to a trace that has already finished. The patch does NOT extend `endTime`\n * or change tokens / cost / top span / tags / span names. `numSpans` is\n * incremented by 1 (paid by the virtual span that carried the patch through\n * the ingestion queue) so the new ClickHouse row beats the prior version on\n * `ReplacingMergeTree(numSpans)`. No row is added to the `spans` table.\n *\n * Compared to `Laminar.setTraceMetadata` (which sets metadata on the\n * currently in-flight trace via OpenTelemetry attributes), this method\n * operates on a finished trace by trace id, so it must be called after the\n * trace has been flushed.\n *\n * A 404 response (the trace was not found in the project — typically because\n * it has not been flushed yet) is logged as a warning and the call returns\n * without throwing, since the 404 may be expected when pushing too soon\n * after the trace run. Pass `failOnNotFound: true` to throw instead (e.g.\n * CLI callers that must report the failure). Any other non-OK status throws.\n *\n * @param traceId - The trace id to push metadata to. Accepts a UUID string\n * or a 32-char OTel hex trace id.\n * @param metadata - The metadata patch. Top-level keys are merged into the\n * trace's existing metadata. Must be non-empty (the server rejects empty\n * patches with 400).\n * @param options - `failOnNotFound`: throw on 404 instead of warn-and-return.\n * @example\n * ```typescript\n * import { Laminar, observe, LaminarClient } from \"@lmnr-ai/lmnr\";\n * Laminar.initialize();\n * const client = new LaminarClient();\n *\n * let traceId: string | null = null;\n * await observe({ name: \"generate\" }, async () => {\n * traceId = await Laminar.getTraceId();\n * });\n * await Laminar.flush();\n *\n * if (traceId) {\n * await client.traces.pushMetadata(traceId, {\n * score: 0.85,\n * reviewer: \"alice\",\n * needsReview: false,\n * });\n * }\n * ```\n */\n public async pushMetadata(\n traceId: string,\n metadata: Record<string, unknown>,\n options?: { failOnNotFound?: boolean },\n ): Promise<void> {\n if (!metadata || Object.keys(metadata).length === 0) {\n throw new Error(\"metadata must be a non-empty object\");\n }\n\n const formattedTraceId = isStringUUID(traceId)\n ? traceId\n : otelTraceIdToUUID(traceId);\n\n const url = this.baseHttpUrl + \"/v1/traces/metadata\";\n const response = await fetch(url, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n traceId: formattedTraceId,\n metadata,\n }),\n });\n\n if (response.status === 404) {\n const message =\n `Trace ${formattedTraceId} not found. The trace may not have been ` +\n \"flushed yet — call await Laminar.flush() and retry.\";\n if (options?.failOnNotFound) {\n throw new Error(message);\n }\n // Trace not found in this project — likely not flushed yet. Don't throw,\n // but surface a warning so callers debugging an empty patch see it.\n logger.warn(message);\n return;\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BrowserEventsResource } from \"./resources/browser-events\";\nimport { DatasetsResource } from \"./resources/datasets\";\nimport { EvalsResource } from \"./resources/evals\";\nimport { EvaluatorsResource } from \"./resources/evaluators\";\nimport { RolloutSessionsResource } from \"./resources/rollout-sessions\";\nimport { SqlResource } from \"./resources/sql\";\nimport { TagsResource } from \"./resources/tags\";\nimport { TracesResource } from \"./resources/traces\";\nimport { loadEnv } from \"./utils\";\n\nexport class LaminarClient {\n private baseUrl: string;\n private projectApiKey: string;\n private _browserEvents: BrowserEventsResource;\n private _datasets: DatasetsResource;\n private _evals: EvalsResource;\n private _evaluators: EvaluatorsResource;\n private _rolloutSessions: RolloutSessionsResource;\n private _sql: SqlResource;\n private _tags: TagsResource;\n private _traces: TracesResource;\n\n constructor({\n baseUrl,\n projectApiKey,\n port,\n }: {\n baseUrl?: string,\n projectApiKey?: string,\n port?: number,\n } = {}) {\n loadEnv();\n this.projectApiKey = projectApiKey ?? process.env.LMNR_PROJECT_API_KEY!;\n const httpPort = port ?? (\n baseUrl?.match(/:\\d{1,5}$/g)\n ? parseInt(baseUrl.match(/:\\d{1,5}$/g)![0].slice(1))\n : 443);\n const baseUrlNoPort = (baseUrl ?? process.env.LMNR_BASE_URL)\n ?.replace(/\\/$/, '').replace(/:\\d{1,5}$/g, '');\n this.baseUrl = `${baseUrlNoPort ?? 'https://api.lmnr.ai'}:${httpPort}`;\n this._browserEvents = new BrowserEventsResource(this.baseUrl, this.projectApiKey);\n this._datasets = new DatasetsResource(this.baseUrl, this.projectApiKey);\n this._evals = new EvalsResource(this.baseUrl, this.projectApiKey);\n this._evaluators = new EvaluatorsResource(this.baseUrl, this.projectApiKey);\n this._rolloutSessions = new RolloutSessionsResource(this.baseUrl, this.projectApiKey);\n this._sql = new SqlResource(this.baseUrl, this.projectApiKey);\n this._tags = new TagsResource(this.baseUrl, this.projectApiKey);\n this._traces = new TracesResource(this.baseUrl, this.projectApiKey);\n }\n\n public get browserEvents() {\n return this._browserEvents;\n }\n\n public get datasets() {\n return this._datasets;\n }\n\n public get evals() {\n return this._evals;\n }\n\n public get evaluators() {\n return this._evaluators;\n }\n\n public get rolloutSessions() {\n return this._rolloutSessions;\n }\n\n public get sql() {\n return this._sql;\n }\n\n public get tags() {\n return this._tags;\n }\n\n public get traces() {\n return this._traces;\n }\n}\n"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { Datapoint, Dataset, EvaluationDatapoint, GetDatapointsResponse, InitEvaluationResponse, PushDatapointsResponse, RolloutParam, SpanType, StringUUID } from "@lmnr-ai/types";
1
+ import { Datapoint, Dataset, EvaluationDatapoint, GetDatapointsResponse, InitEvaluationResponse, PushDatapointsResponse, StringUUID } from "@lmnr-ai/types";
2
2
 
3
3
  //#region src/resources/index.d.ts
4
4
  declare class BaseResource {
@@ -260,46 +260,37 @@ declare class EvaluatorsResource extends BaseResource {
260
260
  declare class RolloutSessionsResource extends BaseResource {
261
261
  constructor(baseHttpUrl: string, projectApiKey: string);
262
262
  /**
263
- * Connects to the SSE stream for rollout debugging sessions
264
- * Returns the Response object for streaming SSE events
263
+ * Idempotently register (upsert) a debug session on the backend, keyed on the
264
+ * SDK-supplied session id. The backend stores the row so the session is
265
+ * visible in the UI; a null/omitted name never clobbers a name set elsewhere.
266
+ *
267
+ * Returns the backend-resolved `projectId` (derived from the API key) so the
268
+ * caller can build the debugger URL; null if the body can't be parsed.
265
269
  */
266
- connect({
270
+ register({
267
271
  sessionId,
268
- name,
269
- params,
270
- signal
271
- }: {
272
- sessionId: string;
273
- params: RolloutParam[];
274
- name: string;
275
- signal?: AbortSignal;
276
- }): Promise<Response>;
277
- delete({
278
- sessionId
272
+ name
279
273
  }: {
280
274
  sessionId: string;
281
- }): Promise<void>;
282
- setStatus({
275
+ name?: string;
276
+ }): Promise<string | null>;
277
+ /**
278
+ * Rename an existing debug session. Update-only: the backend returns 404 (and
279
+ * this throws) when the session id is unknown for the project, so a mistyped
280
+ * id surfaces as an error rather than silently creating a session. Creation
281
+ * stays the SDK's job via {@link register}.
282
+ */
283
+ setName({
283
284
  sessionId,
284
- status
285
+ name
285
286
  }: {
286
287
  sessionId: string;
287
- status: 'PENDING' | 'RUNNING' | 'FINISHED' | 'STOPPED';
288
+ name: string;
288
289
  }): Promise<void>;
289
- sendSpanUpdate({
290
- sessionId,
291
- span
290
+ delete({
291
+ sessionId
292
292
  }: {
293
293
  sessionId: string;
294
- span: {
295
- name: string;
296
- startTime: string;
297
- spanId: string;
298
- traceId: string;
299
- parentSpanId: string | undefined;
300
- attributes: Record<string, any>;
301
- spanType: SpanType;
302
- };
303
294
  }): Promise<void>;
304
295
  }
305
296
  //#endregion
@@ -371,13 +362,16 @@ declare class TracesResource extends BaseResource {
371
362
  *
372
363
  * A 404 response (the trace was not found in the project — typically because
373
364
  * it has not been flushed yet) is logged as a warning and the call returns
374
- * without throwing; any other non-OK status throws.
365
+ * without throwing, since the 404 may be expected when pushing too soon
366
+ * after the trace run. Pass `failOnNotFound: true` to throw instead (e.g.
367
+ * CLI callers that must report the failure). Any other non-OK status throws.
375
368
  *
376
369
  * @param traceId - The trace id to push metadata to. Accepts a UUID string
377
370
  * or a 32-char OTel hex trace id.
378
371
  * @param metadata - The metadata patch. Top-level keys are merged into the
379
372
  * trace's existing metadata. Must be non-empty (the server rejects empty
380
373
  * patches with 400).
374
+ * @param options - `failOnNotFound`: throw on 404 instead of warn-and-return.
381
375
  * @example
382
376
  * ```typescript
383
377
  * import { Laminar, observe, LaminarClient } from "@lmnr-ai/lmnr";
@@ -399,7 +393,9 @@ declare class TracesResource extends BaseResource {
399
393
  * }
400
394
  * ```
401
395
  */
402
- pushMetadata(traceId: string, metadata: Record<string, unknown>): Promise<void>;
396
+ pushMetadata(traceId: string, metadata: Record<string, unknown>, options?: {
397
+ failOnNotFound?: boolean;
398
+ }): Promise<void>;
403
399
  }
404
400
  //#endregion
405
401
  //#region src/index.d.ts
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { Datapoint, Dataset, EvaluationDatapoint, GetDatapointsResponse, InitEvaluationResponse, PushDatapointsResponse, RolloutParam, SpanType, StringUUID } from "@lmnr-ai/types";
1
+ import { Datapoint, Dataset, EvaluationDatapoint, GetDatapointsResponse, InitEvaluationResponse, PushDatapointsResponse, StringUUID } from "@lmnr-ai/types";
2
2
 
3
3
  //#region src/resources/index.d.ts
4
4
  declare class BaseResource {
@@ -260,46 +260,37 @@ declare class EvaluatorsResource extends BaseResource {
260
260
  declare class RolloutSessionsResource extends BaseResource {
261
261
  constructor(baseHttpUrl: string, projectApiKey: string);
262
262
  /**
263
- * Connects to the SSE stream for rollout debugging sessions
264
- * Returns the Response object for streaming SSE events
263
+ * Idempotently register (upsert) a debug session on the backend, keyed on the
264
+ * SDK-supplied session id. The backend stores the row so the session is
265
+ * visible in the UI; a null/omitted name never clobbers a name set elsewhere.
266
+ *
267
+ * Returns the backend-resolved `projectId` (derived from the API key) so the
268
+ * caller can build the debugger URL; null if the body can't be parsed.
265
269
  */
266
- connect({
270
+ register({
267
271
  sessionId,
268
- name,
269
- params,
270
- signal
271
- }: {
272
- sessionId: string;
273
- params: RolloutParam[];
274
- name: string;
275
- signal?: AbortSignal;
276
- }): Promise<Response>;
277
- delete({
278
- sessionId
272
+ name
279
273
  }: {
280
274
  sessionId: string;
281
- }): Promise<void>;
282
- setStatus({
275
+ name?: string;
276
+ }): Promise<string | null>;
277
+ /**
278
+ * Rename an existing debug session. Update-only: the backend returns 404 (and
279
+ * this throws) when the session id is unknown for the project, so a mistyped
280
+ * id surfaces as an error rather than silently creating a session. Creation
281
+ * stays the SDK's job via {@link register}.
282
+ */
283
+ setName({
283
284
  sessionId,
284
- status
285
+ name
285
286
  }: {
286
287
  sessionId: string;
287
- status: 'PENDING' | 'RUNNING' | 'FINISHED' | 'STOPPED';
288
+ name: string;
288
289
  }): Promise<void>;
289
- sendSpanUpdate({
290
- sessionId,
291
- span
290
+ delete({
291
+ sessionId
292
292
  }: {
293
293
  sessionId: string;
294
- span: {
295
- name: string;
296
- startTime: string;
297
- spanId: string;
298
- traceId: string;
299
- parentSpanId: string | undefined;
300
- attributes: Record<string, any>;
301
- spanType: SpanType;
302
- };
303
294
  }): Promise<void>;
304
295
  }
305
296
  //#endregion
@@ -371,13 +362,16 @@ declare class TracesResource extends BaseResource {
371
362
  *
372
363
  * A 404 response (the trace was not found in the project — typically because
373
364
  * it has not been flushed yet) is logged as a warning and the call returns
374
- * without throwing; any other non-OK status throws.
365
+ * without throwing, since the 404 may be expected when pushing too soon
366
+ * after the trace run. Pass `failOnNotFound: true` to throw instead (e.g.
367
+ * CLI callers that must report the failure). Any other non-OK status throws.
375
368
  *
376
369
  * @param traceId - The trace id to push metadata to. Accepts a UUID string
377
370
  * or a 32-char OTel hex trace id.
378
371
  * @param metadata - The metadata patch. Top-level keys are merged into the
379
372
  * trace's existing metadata. Must be non-empty (the server rejects empty
380
373
  * patches with 400).
374
+ * @param options - `failOnNotFound`: throw on 404 instead of warn-and-return.
381
375
  * @example
382
376
  * ```typescript
383
377
  * import { Laminar, observe, LaminarClient } from "@lmnr-ai/lmnr";
@@ -399,7 +393,9 @@ declare class TracesResource extends BaseResource {
399
393
  * }
400
394
  * ```
401
395
  */
402
- pushMetadata(traceId: string, metadata: Record<string, unknown>): Promise<void>;
396
+ pushMetadata(traceId: string, metadata: Record<string, unknown>, options?: {
397
+ failOnNotFound?: boolean;
398
+ }): Promise<void>;
403
399
  }
404
400
  //#endregion
405
401
  //#region src/index.d.ts
package/dist/index.mjs CHANGED
@@ -3,8 +3,9 @@ import * as path from "path";
3
3
  import pino from "pino";
4
4
  import { PinoPretty } from "pino-pretty";
5
5
  import { v4 } from "uuid";
6
+ import { errorMessage } from "@lmnr-ai/types";
6
7
  //#region package.json
7
- var version = "0.8.26";
8
+ var version = "0.8.27";
8
9
  //#endregion
9
10
  //#region src/version.ts
10
11
  function getLangVersion() {
@@ -69,7 +70,7 @@ function initializeLogger(options) {
69
70
  minimumLevel: level
70
71
  }));
71
72
  }
72
- const logger$3 = initializeLogger();
73
+ const logger$4 = initializeLogger();
73
74
  const isStringUUID = (id) => /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(id);
74
75
  const newUUID = () => {
75
76
  if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
@@ -78,9 +79,9 @@ const newUUID = () => {
78
79
  const otelSpanIdToUUID = (spanId) => {
79
80
  let id = spanId.toLowerCase();
80
81
  if (id.startsWith("0x")) id = id.slice(2);
81
- if (id.length !== 16) logger$3.warn(`Span ID ${spanId} is not 16 hex chars long. This is not a valid OpenTelemetry span ID.`);
82
+ if (id.length !== 16) logger$4.warn(`Span ID ${spanId} is not 16 hex chars long. This is not a valid OpenTelemetry span ID.`);
82
83
  if (!/^[0-9a-f]+$/.test(id)) {
83
- logger$3.error(`Span ID ${spanId} is not a valid hex string. Generating a random UUID instead.`);
84
+ logger$4.error(`Span ID ${spanId} is not a valid hex string. Generating a random UUID instead.`);
84
85
  return newUUID();
85
86
  }
86
87
  return id.padStart(32, "0").replace(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/, "$1-$2-$3-$4-$5");
@@ -88,9 +89,9 @@ const otelSpanIdToUUID = (spanId) => {
88
89
  const otelTraceIdToUUID = (traceId) => {
89
90
  let id = traceId.toLowerCase();
90
91
  if (id.startsWith("0x")) id = id.slice(2);
91
- if (id.length !== 32) logger$3.warn(`Trace ID ${traceId} is not 32 hex chars long. This is not a valid OpenTelemetry trace ID.`);
92
+ if (id.length !== 32) logger$4.warn(`Trace ID ${traceId} is not 32 hex chars long. This is not a valid OpenTelemetry trace ID.`);
92
93
  if (!/^[0-9a-f]+$/.test(id)) {
93
- logger$3.error(`Trace ID ${traceId} is not a valid hex string. Generating a random UUID instead.`);
94
+ logger$4.error(`Trace ID ${traceId} is not a valid hex string. Generating a random UUID instead.`);
94
95
  return newUUID();
95
96
  }
96
97
  return id.replace(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/, "$1-$2-$3-$4-$5");
@@ -120,7 +121,7 @@ const loadEnv = (options) => {
120
121
  };
121
122
  //#endregion
122
123
  //#region src/resources/datasets.ts
123
- const logger$2 = initializeLogger();
124
+ const logger$3 = initializeLogger();
124
125
  const DEFAULT_DATASET_PULL_LIMIT = 100;
125
126
  const DEFAULT_DATASET_PUSH_BATCH_SIZE = 100;
126
127
  var DatasetsResource = class extends BaseResource {
@@ -175,7 +176,7 @@ var DatasetsResource = class extends BaseResource {
175
176
  let response;
176
177
  for (let i = 0; i < points.length; i += batchSize) {
177
178
  const batchNum = Math.floor(i / batchSize) + 1;
178
- logger$2.debug(`Pushing batch ${batchNum} of ${totalBatches}`);
179
+ logger$3.debug(`Pushing batch ${batchNum} of ${totalBatches}`);
179
180
  const batch = points.slice(i, i + batchSize);
180
181
  const fetchResponse = await fetch(this.baseHttpUrl + "/v1/datasets/datapoints", {
181
182
  method: "POST",
@@ -225,7 +226,7 @@ var DatasetsResource = class extends BaseResource {
225
226
  };
226
227
  //#endregion
227
228
  //#region src/resources/evals.ts
228
- const logger$1 = initializeLogger();
229
+ const logger$2 = initializeLogger();
229
230
  const INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH = 16e6;
230
231
  var EvalsResource = class extends BaseResource {
231
232
  constructor(baseHttpUrl, projectApiKey) {
@@ -361,7 +362,7 @@ var EvalsResource = class extends BaseResource {
361
362
  * @returns {Promise<GetDatapointsResponse>} Response from the datapoint retrieval
362
363
  */
363
364
  async getDatapoints({ datasetName, offset, limit }) {
364
- logger$1.warn("evals.getDatapoints() is deprecated. Use client.datasets.pull() instead.");
365
+ logger$2.warn("evals.getDatapoints() is deprecated. Use client.datasets.pull() instead.");
365
366
  const params = new URLSearchParams({
366
367
  name: datasetName,
367
368
  offset: offset.toString(),
@@ -378,7 +379,7 @@ var EvalsResource = class extends BaseResource {
378
379
  let length = initialLength;
379
380
  let lastResponse = null;
380
381
  for (let i = 0; i < maxRetries; i++) {
381
- logger$1.debug(`Retrying save datapoints... ${i + 1} of ${maxRetries}, length: ${length}`);
382
+ logger$2.debug(`Retrying save datapoints... ${i + 1} of ${maxRetries}, length: ${length}`);
382
383
  const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {
383
384
  method: "POST",
384
385
  headers: this.headers(),
@@ -464,60 +465,51 @@ var EvaluatorsResource = class extends BaseResource {
464
465
  };
465
466
  //#endregion
466
467
  //#region src/resources/rollout-sessions.ts
468
+ const logger$1 = initializeLogger();
467
469
  var RolloutSessionsResource = class extends BaseResource {
468
470
  constructor(baseHttpUrl, projectApiKey) {
469
471
  super(baseHttpUrl, projectApiKey);
470
472
  }
471
473
  /**
472
- * Connects to the SSE stream for rollout debugging sessions
473
- * Returns the Response object for streaming SSE events
474
+ * Idempotently register (upsert) a debug session on the backend, keyed on the
475
+ * SDK-supplied session id. The backend stores the row so the session is
476
+ * visible in the UI; a null/omitted name never clobbers a name set elsewhere.
477
+ *
478
+ * Returns the backend-resolved `projectId` (derived from the API key) so the
479
+ * caller can build the debugger URL; null if the body can't be parsed.
474
480
  */
475
- async connect({ sessionId, name, params, signal }) {
481
+ async register({ sessionId, name }) {
476
482
  const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}`, {
477
483
  method: "POST",
478
- headers: {
479
- ...this.headers(),
480
- "Accept": "text/event-stream"
481
- },
482
- body: JSON.stringify({
483
- name,
484
- params
485
- }),
486
- signal
487
- });
488
- if (!response.ok) throw new Error(`SSE connection failed: ${response.status} ${response.statusText}`);
489
- if (!response.body) throw new Error("No response body");
490
- return response;
491
- }
492
- async delete({ sessionId }) {
493
- const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}`, {
494
- method: "DELETE",
495
- headers: this.headers()
484
+ headers: this.headers(),
485
+ body: JSON.stringify({ name })
496
486
  });
497
487
  if (!response.ok) await this.handleError(response);
488
+ try {
489
+ return (await response.json()).projectId ?? null;
490
+ } catch (e) {
491
+ logger$1.warn(`Failed to parse rollout register response: ${errorMessage(e)}`);
492
+ return null;
493
+ }
498
494
  }
499
- async setStatus({ sessionId, status }) {
500
- const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}/status`, {
495
+ /**
496
+ * Rename an existing debug session. Update-only: the backend returns 404 (and
497
+ * this throws) when the session id is unknown for the project, so a mistyped
498
+ * id surfaces as an error rather than silently creating a session. Creation
499
+ * stays the SDK's job via {@link register}.
500
+ */
501
+ async setName({ sessionId, name }) {
502
+ const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}/name`, {
501
503
  method: "PATCH",
502
504
  headers: this.headers(),
503
- body: JSON.stringify({ status })
505
+ body: JSON.stringify({ name })
504
506
  });
505
507
  if (!response.ok) await this.handleError(response);
506
508
  }
507
- async sendSpanUpdate({ sessionId, span }) {
508
- const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}/update`, {
509
- method: "PATCH",
510
- headers: this.headers(),
511
- body: JSON.stringify({
512
- type: "spanStart",
513
- spanId: otelSpanIdToUUID(span.spanId),
514
- traceId: otelTraceIdToUUID(span.traceId),
515
- parentSpanId: span.parentSpanId ? otelSpanIdToUUID(span.parentSpanId) : void 0,
516
- attributes: span.attributes,
517
- startTime: span.startTime,
518
- name: span.name,
519
- spanType: span.spanType
520
- })
509
+ async delete({ sessionId }) {
510
+ const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}`, {
511
+ method: "DELETE",
512
+ headers: this.headers()
521
513
  });
522
514
  if (!response.ok) await this.handleError(response);
523
515
  }
@@ -626,13 +618,16 @@ var TracesResource = class extends BaseResource {
626
618
  *
627
619
  * A 404 response (the trace was not found in the project — typically because
628
620
  * it has not been flushed yet) is logged as a warning and the call returns
629
- * without throwing; any other non-OK status throws.
621
+ * without throwing, since the 404 may be expected when pushing too soon
622
+ * after the trace run. Pass `failOnNotFound: true` to throw instead (e.g.
623
+ * CLI callers that must report the failure). Any other non-OK status throws.
630
624
  *
631
625
  * @param traceId - The trace id to push metadata to. Accepts a UUID string
632
626
  * or a 32-char OTel hex trace id.
633
627
  * @param metadata - The metadata patch. Top-level keys are merged into the
634
628
  * trace's existing metadata. Must be non-empty (the server rejects empty
635
629
  * patches with 400).
630
+ * @param options - `failOnNotFound`: throw on 404 instead of warn-and-return.
636
631
  * @example
637
632
  * ```typescript
638
633
  * import { Laminar, observe, LaminarClient } from "@lmnr-ai/lmnr";
@@ -654,7 +649,7 @@ var TracesResource = class extends BaseResource {
654
649
  * }
655
650
  * ```
656
651
  */
657
- async pushMetadata(traceId, metadata) {
652
+ async pushMetadata(traceId, metadata, options) {
658
653
  if (!metadata || Object.keys(metadata).length === 0) throw new Error("metadata must be a non-empty object");
659
654
  const formattedTraceId = isStringUUID(traceId) ? traceId : otelTraceIdToUUID(traceId);
660
655
  const url = this.baseHttpUrl + "/v1/traces/metadata";
@@ -667,7 +662,9 @@ var TracesResource = class extends BaseResource {
667
662
  })
668
663
  });
669
664
  if (response.status === 404) {
670
- logger.warn(`Trace ${formattedTraceId} not found. The trace may not have been flushed yet — call await Laminar.flush() and retry.`);
665
+ const message = `Trace ${formattedTraceId} not found. The trace may not have been flushed yet — call await Laminar.flush() and retry.`;
666
+ if (options?.failOnNotFound) throw new Error(message);
667
+ logger.warn(message);
671
668
  return;
672
669
  }
673
670
  if (!response.ok) await this.handleError(response);
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["SDK_VERSION","logger","uuidv4","logger","logger"],"sources":["../package.json","../src/version.ts","../src/resources/index.ts","../src/resources/browser-events.ts","../src/utils.ts","../src/resources/datasets.ts","../src/resources/evals.ts","../src/resources/evaluators.ts","../src/resources/rollout-sessions.ts","../src/resources/sql.ts","../src/resources/tags.ts","../src/resources/traces.ts","../src/index.ts"],"sourcesContent":["","// Version detection for runtime environment\nexport function getLangVersion(): string | null {\n if (typeof process !== 'undefined' && process.versions && process.versions.node) {\n return `node-${process.versions.node}`;\n }\n if (typeof navigator !== 'undefined' && navigator.userAgent) {\n return `browser-${navigator.userAgent}`;\n }\n return null;\n}\n","class BaseResource {\n protected readonly baseHttpUrl: string;\n protected readonly projectApiKey: string;\n\n constructor(baseHttpUrl: string, projectApiKey: string) {\n this.baseHttpUrl = baseHttpUrl;\n this.projectApiKey = projectApiKey;\n }\n\n protected headers() {\n return {\n Authorization: `Bearer ${this.projectApiKey}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n }\n\n protected async handleError(response: Response) {\n const errorMsg = await response.text();\n throw new Error(`${response.status} ${errorMsg}`);\n }\n}\n\nexport { BaseResource };\n","import { version as SDK_VERSION } from '../../package.json';\nimport { getLangVersion } from \"../version\";\nimport { BaseResource } from \"./index\";\n\nexport class BrowserEventsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n public async send({\n sessionId,\n traceId,\n events,\n }: {\n sessionId: string;\n traceId: string;\n events: Record<string, any>[];\n }): Promise<void> {\n const payload = {\n sessionId,\n traceId,\n events,\n source: getLangVersion() ?? 'javascript',\n sdkVersion: SDK_VERSION,\n };\n\n const jsonString = JSON.stringify(payload);\n const blob = new Blob([jsonString], { type: 'application/json' });\n const compressedStream = blob.stream().pipeThrough(new CompressionStream('gzip'));\n const compressedResponse = new Response(compressedStream);\n const compressedData = await compressedResponse.arrayBuffer();\n\n const response = await fetch(this.baseHttpUrl + \"/v1/browser-sessions/events\", {\n method: \"POST\",\n headers: {\n ...this.headers(),\n 'Content-Encoding': 'gzip',\n },\n body: compressedData,\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { type StringUUID } from '@lmnr-ai/types';\nimport { config } from 'dotenv';\nimport * as path from 'path';\nimport pino, { Level } from 'pino';\nimport { PinoPretty } from 'pino-pretty';\nimport { v4 as uuidv4 } from 'uuid';\n\nexport function initializeLogger(options?: { colorize?: boolean; level?: Level }) {\n const colorize = options?.colorize ?? true;\n const level =\n options?.level ??\n (process.env.LMNR_LOG_LEVEL?.toLowerCase()?.trim() as Level) ??\n 'info';\n\n return pino(\n {\n level,\n },\n PinoPretty({\n colorize,\n minimumLevel: level,\n }),\n );\n}\n\nconst logger = initializeLogger();\n\nexport const isStringUUID = (id: string): id is StringUUID =>\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(id);\n\nexport const NIL_UUID: StringUUID = '00000000-0000-0000-0000-000000000000';\n\nexport const newUUID = (): StringUUID => {\n // crypto.randomUUID is available in most of the modern browsers and node,\n // but is not available in \"insecure\" contexts, e.g. not https, not localhost\n // so we fallback to uuidv4 in those cases, which is less secure, but works\n // just fine.\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n } else {\n return uuidv4() as `${string}-${string}-${string}-${string}-${string}`;\n }\n};\n\nexport const otelSpanIdToUUID = (spanId: string): string => {\n let id = spanId.toLowerCase();\n if (id.startsWith('0x')) {\n id = id.slice(2);\n }\n if (id.length !== 16) {\n logger.warn(\n `Span ID ${spanId} is not 16 hex chars long. ` +\n 'This is not a valid OpenTelemetry span ID.',\n );\n }\n\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(\n `Span ID ${spanId} is not a valid hex string. ` +\n 'Generating a random UUID instead.',\n );\n return newUUID();\n }\n\n return id.padStart(32, '0').replace(\n /^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/,\n '$1-$2-$3-$4-$5',\n );\n};\n\nexport const otelTraceIdToUUID = (traceId: string): StringUUID => {\n let id = traceId.toLowerCase();\n if (id.startsWith('0x')) {\n id = id.slice(2);\n }\n if (id.length !== 32) {\n logger.warn(\n `Trace ID ${traceId} is not 32 hex chars long. ` +\n 'This is not a valid OpenTelemetry trace ID.',\n );\n }\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(\n `Trace ID ${traceId} is not a valid hex string. ` +\n 'Generating a random UUID instead.',\n );\n return newUUID();\n }\n\n return id.replace(\n /^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/,\n '$1-$2-$3-$4-$5',\n ) as StringUUID;\n};\n\nexport const slicePayload = <T>(value: T, length: number) => {\n if (value === null || value === undefined) {\n return value;\n }\n\n const str = JSON.stringify(value);\n if (str.length <= length) {\n return value;\n }\n\n return str.slice(0, length) + '...';\n};\n\nexport const loadEnv = (\n options?: {\n quiet?: boolean;\n paths?: string[];\n },\n): void => {\n const nodeEnv = process.env.NODE_ENV || 'development';\n const envDir = process.cwd();\n\n // Files to load in order (lowest to highest priority)\n // Later files override earlier ones\n const envFiles = [\n '.env',\n '.env.local',\n `.env.${nodeEnv}`,\n `.env.${nodeEnv}.local`,\n ];\n\n const logLevel = process.env.LMNR_LOG_LEVEL ?? 'info';\n const verbose = ['debug', 'trace'].includes(logLevel.trim().toLowerCase());\n\n const quiet = options?.quiet ?? !verbose;\n\n config({\n path: options?.paths ?? envFiles.map((envFile) => path.resolve(envDir, envFile)),\n quiet,\n });\n};\n","import {\n type Datapoint,\n type Dataset,\n type GetDatapointsResponse,\n type PushDatapointsResponse,\n type StringUUID,\n} from \"@lmnr-ai/types\";\n\nimport { initializeLogger } from \"../utils\";\nimport { BaseResource } from \".\";\n\nconst logger = initializeLogger();\nconst DEFAULT_DATASET_PULL_LIMIT = 100;\nconst DEFAULT_DATASET_PUSH_BATCH_SIZE = 100;\n\nexport class DatasetsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * List all datasets.\n *\n * @returns {Promise<Dataset[]>} Array of datasets\n */\n public async listDatasets(): Promise<Dataset[]> {\n const response = await fetch(this.baseHttpUrl + \"/v1/datasets\", {\n method: \"GET\",\n headers: this.headers(),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<Dataset[]>;\n }\n\n /**\n * Get a dataset by name.\n *\n * @param {string} name - Name of the dataset\n * @returns {Promise<Dataset[]>} Array of datasets with matching name\n */\n public async getDatasetByName(name: string): Promise<Dataset[]> {\n const params = new URLSearchParams({ name });\n const response = await fetch(\n this.baseHttpUrl + `/v1/datasets?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<Dataset[]>;\n }\n\n /**\n * Push datapoints to a dataset.\n *\n * @param {Object} options - Push options\n * @param {Datapoint<D, T>[]} options.points - Datapoints to push\n * @param {string} [options.name] - Name of the dataset (either name or id must be provided)\n * @param {StringUUID} [options.id] - ID of the dataset (either name or id must be provided)\n * @param {number} [options.batchSize] - Batch size for pushing (default: 100)\n * @param {boolean} [options.createDataset] - Whether to create the dataset if it doesn't exist\n * @returns {Promise<PushDatapointsResponse | undefined>}\n */\n public async push<D, T>({\n points,\n name,\n id,\n batchSize = DEFAULT_DATASET_PUSH_BATCH_SIZE,\n createDataset = false,\n }: {\n points: Datapoint<D, T>[];\n name?: string;\n id?: StringUUID;\n batchSize?: number;\n createDataset?: boolean;\n }): Promise<PushDatapointsResponse | undefined> {\n if (!name && !id) {\n throw new Error(\"Either name or id must be provided\");\n }\n\n if (name && id) {\n throw new Error(\"Only one of name or id must be provided\");\n }\n\n if (createDataset && !name) {\n throw new Error(\"Name must be provided when creating a new dataset\");\n }\n\n const identifier = name ? { name } : { datasetId: id! };\n const totalBatches = Math.ceil(points.length / batchSize);\n\n let response: PushDatapointsResponse | undefined;\n for (let i = 0; i < points.length; i += batchSize) {\n const batchNum = Math.floor(i / batchSize) + 1;\n logger.debug(`Pushing batch ${batchNum} of ${totalBatches}`);\n\n const batch = points.slice(i, i + batchSize);\n const fetchResponse = await fetch(\n this.baseHttpUrl + \"/v1/datasets/datapoints\",\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n ...identifier,\n datapoints: batch.map((point) => ({\n data: point.data,\n target: point.target ?? {},\n metadata: point.metadata ?? {},\n })),\n createDataset,\n }),\n },\n );\n\n // 201 when creating a new dataset\n if (fetchResponse.status !== 200 && fetchResponse.status !== 201) {\n await this.handleError(fetchResponse);\n }\n\n response = (await fetchResponse.json()) as PushDatapointsResponse;\n }\n\n return response;\n }\n\n /**\n * Pull datapoints from a dataset.\n *\n * @param {Object} options - Pull options\n * @param {string} [options.name] - Name of the dataset (either name or id must be provided)\n * @param {StringUUID} [options.id] - ID of the dataset (either name or id must be provided)\n * @param {number} [options.limit] - Maximum number of datapoints to return (default: 100)\n * @param {number} [options.offset] - Offset for pagination (default: 0)\n * @returns {Promise<GetDatapointsResponse<D, T>>}\n */\n public async pull<D, T>({\n name,\n id,\n limit = DEFAULT_DATASET_PULL_LIMIT,\n offset = 0,\n }: {\n name?: string;\n id?: StringUUID;\n limit?: number;\n offset?: number;\n }): Promise<GetDatapointsResponse<D, T>> {\n if (!name && !id) {\n throw new Error(\"Either name or id must be provided\");\n }\n\n if (name && id) {\n throw new Error(\"Only one of name or id must be provided\");\n }\n\n const paramsObj: Record<string, string> = {\n offset: offset.toString(),\n limit: limit.toString(),\n };\n\n if (name) {\n paramsObj.name = name;\n } else {\n paramsObj.datasetId = id!;\n }\n\n const params = new URLSearchParams(paramsObj);\n\n const response = await fetch(\n this.baseHttpUrl + `/v1/datasets/datapoints?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<GetDatapointsResponse<D, T>>;\n }\n}\n","import {\n type EvaluationDatapoint,\n type GetDatapointsResponse,\n type InitEvaluationResponse,\n type StringUUID,\n} from \"@lmnr-ai/types\";\n\nimport { initializeLogger, newUUID, slicePayload } from \"../utils\";\nimport { BaseResource } from \".\";\n\nconst logger = initializeLogger();\nconst INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH = 16_000_000; // 16MB\n\nexport class EvalsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Initialize an evaluation.\n *\n * @param {string} name - Name of the evaluation\n * @param {string} groupName - Group name of the evaluation\n * @param {Record<string, any>} metadata - Optional metadata\n * @returns {Promise<InitEvaluationResponse>} Response from the evaluation initialization\n */\n public async init(\n name?: string,\n groupName?: string,\n metadata?: Record<string, any>,\n ): Promise<InitEvaluationResponse> {\n const response = await fetch(this.baseHttpUrl + \"/v1/evals\", {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n name: name ?? null,\n groupName: groupName ?? null,\n metadata: metadata ?? null,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<InitEvaluationResponse>;\n }\n\n /**\n * Create a new evaluation and return its ID.\n *\n * @param {string} [name] - Optional name of the evaluation\n * @param {string} [groupName] - An identifier to group evaluations\n * @param {Record<string, any>} [metadata] - Optional metadata\n * @returns {Promise<StringUUID>} The evaluation ID\n */\n\n public async create(args?: {\n name?: string, groupName?: string, metadata?: Record<string, any>\n }): Promise<StringUUID> {\n const evaluation = await this.init(args?.name, args?.groupName, args?.metadata);\n return evaluation.id;\n }\n\n /**\n * Create a new evaluation and return its ID.\n * @deprecated use `create` instead.\n */\n public async createEvaluation(\n name?: string,\n groupName?: string,\n metadata?: Record<string, any>,\n ): Promise<StringUUID> {\n const evaluation = await this.init(name, groupName, metadata);\n return evaluation.id;\n }\n\n /**\n * Create a datapoint for an evaluation.\n *\n * @param {Object} options - Create datapoint options\n * @param {string} options.evalId - The evaluation ID\n * @param {D} options.data - The input data for the executor\n * @param {T} [options.target] - The target/expected output for evaluators\n * @param {Record<string, any>} [options.metadata] - Optional metadata\n * @param {number} [options.index] - Optional index of the datapoint\n * @param {string} [options.traceId] - Optional trace ID\n * @returns {Promise<StringUUID>} The datapoint ID\n */\n public async createDatapoint<D, T>({\n evalId,\n data,\n target,\n metadata,\n index,\n traceId,\n }: {\n evalId: string;\n data: D;\n target?: T;\n metadata?: Record<string, any>;\n index?: number;\n traceId?: string;\n }): Promise<StringUUID> {\n const datapointId = newUUID();\n\n const partialDatapoint: EvaluationDatapoint<D, T, any> = {\n id: datapointId,\n data,\n target,\n index: index ?? 0,\n traceId: traceId ?? newUUID(),\n executorSpanId: newUUID(),\n metadata,\n };\n\n await this.saveDatapoints({\n evalId,\n datapoints: [partialDatapoint],\n });\n\n return datapointId;\n }\n\n /**\n * Update a datapoint with evaluation results.\n *\n * @param {Object} options - Update datapoint options\n * @param {string} options.evalId - The evaluation ID\n * @param {string} options.datapointId - The datapoint ID\n * @param {Record<string, number>} options.scores - The scores\n * @param {O} [options.executorOutput] - The executor output\n * @returns {Promise<void>}\n */\n public async updateDatapoint<O>({\n evalId,\n datapointId,\n scores,\n executorOutput,\n }: {\n evalId: string;\n datapointId: string;\n scores: Record<string, number>;\n executorOutput?: O;\n }): Promise<void> {\n const response = await fetch(\n this.baseHttpUrl + `/v1/evals/${evalId}/datapoints/${datapointId}`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n executorOutput,\n scores,\n }),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n /**\n * Save evaluation datapoints.\n *\n * @param {Object} options - Save datapoints options\n * @param {string} options.evalId - ID of the evaluation\n * @param {EvaluationDatapoint<D, T, O>[]} options.datapoints - Datapoint to add\n * @param {string} [options.groupName] - Group name of the evaluation\n * @returns {Promise<void>} Response from the datapoint addition\n */\n public async saveDatapoints<D, T, O>({\n evalId,\n datapoints,\n groupName,\n }: {\n evalId: string;\n datapoints: EvaluationDatapoint<D, T, O>[];\n groupName?: string;\n }): Promise<void> {\n const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n points: datapoints.map((d) => (\n {\n ...d,\n data: slicePayload(d.data, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH),\n target: slicePayload(d.target, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH),\n executorOutput: slicePayload(\n d.executorOutput,\n INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH,\n ),\n })),\n groupName: groupName ?? null,\n }),\n });\n\n if (response.status === 413) {\n return await this.retrySaveDatapoints({\n evalId,\n datapoints,\n groupName,\n });\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n /**\n * Get evaluation datapoints.\n *\n * @deprecated Use `client.datasets.pull()` instead.\n * @param {Object} options - Get datapoints options\n * @param {string} options.datasetName - Name of the dataset\n * @param {number} options.offset - Offset at which to start the query\n * @param {number} options.limit - Maximum number of datapoints to return\n * @returns {Promise<GetDatapointsResponse>} Response from the datapoint retrieval\n */\n public async getDatapoints<D, T>({\n datasetName,\n offset,\n limit,\n }: {\n datasetName: string;\n offset: number;\n limit: number;\n }): Promise<GetDatapointsResponse<D, T>> {\n logger.warn(\n 'evals.getDatapoints() is deprecated. Use client.datasets.pull() instead.',\n );\n\n const params = new URLSearchParams({\n name: datasetName,\n offset: offset.toString(),\n limit: limit.toString(),\n });\n const response = await fetch(\n this.baseHttpUrl + `/v1/datasets/datapoints?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()) as GetDatapointsResponse<D, T>;\n }\n\n private async retrySaveDatapoints<D, T, O>({\n evalId,\n datapoints,\n groupName,\n maxRetries = 25,\n initialLength = INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH,\n }: {\n evalId: string;\n datapoints: EvaluationDatapoint<D, T, O>[];\n groupName?: string;\n maxRetries?: number;\n initialLength?: number;\n }): Promise<void> {\n let length = initialLength;\n let lastResponse: Response | null = null;\n for (let i = 0; i < maxRetries; i++) {\n logger.debug(`Retrying save datapoints... ${i + 1} of ${maxRetries}, length: ${length}`);\n const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n points: datapoints.map((d) => (\n {\n ...d,\n data: slicePayload(d.data, length),\n target: slicePayload(d.target, length),\n executorOutput: slicePayload(d.executorOutput, length),\n })),\n groupName: groupName ?? null,\n }),\n });\n lastResponse = response;\n length = Math.floor(length / 2);\n if (response.status !== 413) {\n break;\n }\n }\n if (lastResponse && !lastResponse.ok) {\n await this.handleError(lastResponse);\n }\n }\n}\n","import { type StringUUID } from \"@lmnr-ai/types\";\n\nimport { isStringUUID, otelSpanIdToUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \".\";\n\nenum EvaluatorScoreSourceType {\n Evaluator = \"Evaluator\",\n Code = \"Code\",\n}\n\ninterface CreateEvaluatorScoreBase {\n name: string;\n metadata?: Record<string, any>;\n score: number;\n source: EvaluatorScoreSourceType;\n}\n\ninterface CreateEvaluatorScoreRequestWithTraceId extends CreateEvaluatorScoreBase {\n traceId: string;\n}\n\ninterface CreateEvaluatorScoreRequestWithSpanId extends CreateEvaluatorScoreBase {\n spanId: string;\n}\n\ntype ScoreOptions =\n | { name: string; metadata?: Record<string, any>; score: number; traceId: string; }\n | { name: string; metadata?: Record<string, any>; score: number; spanId: string; };\n\n/**\n * Resource for creating evaluator scores\n */\nexport class EvaluatorsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Create a score for a span or trace\n *\n * @param {ScoreOptions} options - Score creation options\n * @param {string} options.name - Name of the score\n * @param {string} [options.traceId] - The trace ID to score (will be attached to top-level span)\n * @param {string} [options.spanId] - The span ID to score\n * @param {Record<string, any>} [options.metadata] - Additional metadata\n * @param {number} options.score - The score value (float)\n * @returns {Promise<void>}\n *\n * @example\n * // Score by trace ID (will attach to root span)\n * await evaluators.score({\n * name: \"quality\",\n * traceId: \"trace-id-here\",\n * score: 0.95,\n * metadata: { model: \"gpt-4\" }\n * });\n *\n * @example\n * // Score by span ID\n * await evaluators.score({\n * name: \"relevance\",\n * spanId: \"span-id-here\",\n * score: 0.87\n * });\n */\n public async score(options: ScoreOptions): Promise<void> {\n const { name, metadata, score } = options;\n\n let payload: CreateEvaluatorScoreRequestWithTraceId | CreateEvaluatorScoreRequestWithSpanId;\n\n if ('traceId' in options && options.traceId) {\n const formattedTraceId = isStringUUID(options.traceId)\n ? options.traceId\n : otelTraceIdToUUID(options.traceId);\n\n payload = {\n name,\n metadata,\n score,\n source: EvaluatorScoreSourceType.Code,\n traceId: formattedTraceId,\n };\n } else if ('spanId' in options && options.spanId) {\n const formattedSpanId = isStringUUID(options.spanId)\n ? options.spanId\n : otelSpanIdToUUID(options.spanId) as StringUUID;\n\n payload = {\n name,\n metadata,\n score,\n source: EvaluatorScoreSourceType.Code,\n spanId: formattedSpanId,\n };\n } else {\n throw new Error(\"Either 'traceId' or 'spanId' must be provided.\");\n }\n\n const response = await fetch(this.baseHttpUrl + \"/v1/evaluators/score\", {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { type RolloutParam, type SpanType } from \"@lmnr-ai/types\";\n\nimport { otelSpanIdToUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \"./index\";\n\nexport class RolloutSessionsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Connects to the SSE stream for rollout debugging sessions\n * Returns the Response object for streaming SSE events\n */\n public async connect({\n sessionId,\n name,\n params,\n signal,\n }: {\n sessionId: string;\n params: RolloutParam[];\n name: string;\n signal?: AbortSignal;\n }): Promise<Response> {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}`, {\n method: \"POST\",\n headers: {\n ...this.headers(),\n 'Accept': 'text/event-stream',\n },\n body: JSON.stringify({ name, params }),\n signal,\n });\n\n if (!response.ok) {\n throw new Error(`SSE connection failed: ${response.status} ${response.statusText}`);\n }\n\n if (!response.body) {\n throw new Error('No response body');\n }\n\n return response;\n }\n\n public async delete({\n sessionId,\n }: {\n sessionId: string;\n }) {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}`, {\n method: \"DELETE\",\n headers: this.headers(),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n public async setStatus({\n sessionId,\n status,\n }: {\n sessionId: string;\n status: 'PENDING' | 'RUNNING' | 'FINISHED' | 'STOPPED';\n }) {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}/status`, {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify({ status }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n public async sendSpanUpdate({\n sessionId,\n span,\n }: {\n sessionId: string;\n span: {\n name: string;\n startTime: string;\n spanId: string;\n traceId: string;\n parentSpanId: string | undefined;\n attributes: Record<string, any>;\n spanType: SpanType;\n };\n }) {\n const response = await fetch(`${this.baseHttpUrl}/v1/rollouts/${sessionId}/update`, {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify({\n type: \"spanStart\",\n spanId: otelSpanIdToUUID(span.spanId),\n traceId: otelTraceIdToUUID(span.traceId),\n parentSpanId: span.parentSpanId ? otelSpanIdToUUID(span.parentSpanId) : undefined,\n attributes: span.attributes,\n startTime: span.startTime,\n name: span.name,\n spanType: span.spanType,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BaseResource } from \"./index\";\n\nexport class SqlResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n public async query(\n sql: string,\n parameters: Record<string, any> = {},\n ): Promise<Array<Record<string, any>>> {\n const response = await fetch(`${this.baseHttpUrl}/v1/sql/query`, {\n method: \"POST\",\n headers: {\n ...this.headers(),\n },\n body: JSON.stringify({\n query: sql,\n parameters,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()).data as Array<Record<string, any>>;\n }\n}\n","/** Resource for tagging traces. */\n\n\nimport { isStringUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \"./index\";\n\nexport class TagsResource extends BaseResource {\n /** Resource for tagging traces. */\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Tag a trace with a list of tags. Note that the trace must be ended before\n * tagging it. You may want to call `await Laminar.flush()` after the trace\n * that you want to tag.\n *\n * @param {string | StringUUID} trace_id - The trace id to tag.\n * @param {string[] | string} tags - The tag or list of tags to add to the trace.\n * @returns {Promise<any>} The response from the server.\n * @example\n * ```javascript\n * import { Laminar, observe, LaminarClient } from \"@lmnr-ai/lmnr\";\n * Laminar.initialize();\n * const client = new LaminarClient();\n * let traceId: StringUUID | null = null;\n * // Make sure this is called outside of traced context.\n * await observe(\n * {\n * name: \"my-trace\",\n * },\n * async () => {\n * traceId = await Laminar.getTraceId();\n * await foo();\n * },\n * );\n *\n * // or make sure the trace is ended by this point.\n * await Laminar.flush();\n * if (traceId) {\n * await client.tags.tag(traceId, [\"tag1\", \"tag2\"]);\n * }\n * ```\n */\n public async tag(\n trace_id: string,\n tags: string[] | string,\n ): Promise<any> {\n const traceTags = Array.isArray(tags) ? tags : [tags];\n const formattedTraceId = isStringUUID(trace_id)\n ? trace_id\n : otelTraceIdToUUID(trace_id);\n\n const url = this.baseHttpUrl + \"/v1/tag\";\n const payload = {\n \"traceId\": formattedTraceId,\n \"names\": traceTags,\n };\n const response = await fetch(\n url,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(payload),\n },\n );\n if (!response.ok) {\n await this.handleError(response);\n }\n return response.json();\n }\n}\n","/** Resource for post-factum operations on existing traces. */\n\nimport { initializeLogger, isStringUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \"./index\";\n\nconst logger = initializeLogger();\n\nexport class TracesResource extends BaseResource {\n /** Resource for post-factum operations on existing traces. */\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Push a metadata patch to an existing trace.\n *\n * The patch is shallow-merged server-side into the trace's existing metadata\n * (`existing || patch`, last-write-wins per top-level key). Useful for\n * attaching post-factum signals — quality scores, human edits, triage labels —\n * to a trace that has already finished. The patch does NOT extend `endTime`\n * or change tokens / cost / top span / tags / span names. `numSpans` is\n * incremented by 1 (paid by the virtual span that carried the patch through\n * the ingestion queue) so the new ClickHouse row beats the prior version on\n * `ReplacingMergeTree(numSpans)`. No row is added to the `spans` table.\n *\n * Compared to `Laminar.setTraceMetadata` (which sets metadata on the\n * currently in-flight trace via OpenTelemetry attributes), this method\n * operates on a finished trace by trace id, so it must be called after the\n * trace has been flushed.\n *\n * A 404 response (the trace was not found in the project — typically because\n * it has not been flushed yet) is logged as a warning and the call returns\n * without throwing; any other non-OK status throws.\n *\n * @param traceId - The trace id to push metadata to. Accepts a UUID string\n * or a 32-char OTel hex trace id.\n * @param metadata - The metadata patch. Top-level keys are merged into the\n * trace's existing metadata. Must be non-empty (the server rejects empty\n * patches with 400).\n * @example\n * ```typescript\n * import { Laminar, observe, LaminarClient } from \"@lmnr-ai/lmnr\";\n * Laminar.initialize();\n * const client = new LaminarClient();\n *\n * let traceId: string | null = null;\n * await observe({ name: \"generate\" }, async () => {\n * traceId = await Laminar.getTraceId();\n * });\n * await Laminar.flush();\n *\n * if (traceId) {\n * await client.traces.pushMetadata(traceId, {\n * score: 0.85,\n * reviewer: \"alice\",\n * needsReview: false,\n * });\n * }\n * ```\n */\n public async pushMetadata(\n traceId: string,\n metadata: Record<string, unknown>,\n ): Promise<void> {\n if (!metadata || Object.keys(metadata).length === 0) {\n throw new Error(\"metadata must be a non-empty object\");\n }\n\n const formattedTraceId = isStringUUID(traceId)\n ? traceId\n : otelTraceIdToUUID(traceId);\n\n const url = this.baseHttpUrl + \"/v1/traces/metadata\";\n const response = await fetch(url, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n traceId: formattedTraceId,\n metadata,\n }),\n });\n\n if (response.status === 404) {\n // Trace not found in this project — likely not flushed yet. Don't throw,\n // but surface a warning so callers debugging an empty patch see it.\n logger.warn(\n `Trace ${formattedTraceId} not found. The trace may not have been ` +\n \"flushed yet — call await Laminar.flush() and retry.\",\n );\n return;\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BrowserEventsResource } from \"./resources/browser-events\";\nimport { DatasetsResource } from \"./resources/datasets\";\nimport { EvalsResource } from \"./resources/evals\";\nimport { EvaluatorsResource } from \"./resources/evaluators\";\nimport { RolloutSessionsResource } from \"./resources/rollout-sessions\";\nimport { SqlResource } from \"./resources/sql\";\nimport { TagsResource } from \"./resources/tags\";\nimport { TracesResource } from \"./resources/traces\";\nimport { loadEnv } from \"./utils\";\n\nexport class LaminarClient {\n private baseUrl: string;\n private projectApiKey: string;\n private _browserEvents: BrowserEventsResource;\n private _datasets: DatasetsResource;\n private _evals: EvalsResource;\n private _evaluators: EvaluatorsResource;\n private _rolloutSessions: RolloutSessionsResource;\n private _sql: SqlResource;\n private _tags: TagsResource;\n private _traces: TracesResource;\n\n constructor({\n baseUrl,\n projectApiKey,\n port,\n }: {\n baseUrl?: string,\n projectApiKey?: string,\n port?: number,\n } = {}) {\n loadEnv();\n this.projectApiKey = projectApiKey ?? process.env.LMNR_PROJECT_API_KEY!;\n const httpPort = port ?? (\n baseUrl?.match(/:\\d{1,5}$/g)\n ? parseInt(baseUrl.match(/:\\d{1,5}$/g)![0].slice(1))\n : 443);\n const baseUrlNoPort = (baseUrl ?? process.env.LMNR_BASE_URL)\n ?.replace(/\\/$/, '').replace(/:\\d{1,5}$/g, '');\n this.baseUrl = `${baseUrlNoPort ?? 'https://api.lmnr.ai'}:${httpPort}`;\n this._browserEvents = new BrowserEventsResource(this.baseUrl, this.projectApiKey);\n this._datasets = new DatasetsResource(this.baseUrl, this.projectApiKey);\n this._evals = new EvalsResource(this.baseUrl, this.projectApiKey);\n this._evaluators = new EvaluatorsResource(this.baseUrl, this.projectApiKey);\n this._rolloutSessions = new RolloutSessionsResource(this.baseUrl, this.projectApiKey);\n this._sql = new SqlResource(this.baseUrl, this.projectApiKey);\n this._tags = new TagsResource(this.baseUrl, this.projectApiKey);\n this._traces = new TracesResource(this.baseUrl, this.projectApiKey);\n }\n\n public get browserEvents() {\n return this._browserEvents;\n }\n\n public get datasets() {\n return this._datasets;\n }\n\n public get evals() {\n return this._evals;\n }\n\n public get evaluators() {\n return this._evaluators;\n }\n\n public get rolloutSessions() {\n return this._rolloutSessions;\n }\n\n public get sql() {\n return this._sql;\n }\n\n public get tags() {\n return this._tags;\n }\n\n public get traces() {\n return this._traces;\n }\n}\n"],"mappings":";;;;;;;;;ACCA,SAAgB,iBAAgC;CAC9C,IAAI,OAAO,YAAY,eAAe,QAAQ,YAAY,QAAQ,SAAS,MACzE,OAAO,QAAQ,QAAQ,SAAS;CAElC,IAAI,OAAO,cAAc,eAAe,UAAU,WAChD,OAAO,WAAW,UAAU;CAE9B,OAAO;;;;ACRT,IAAM,eAAN,MAAmB;CAIjB,YAAY,aAAqB,eAAuB;EACtD,KAAK,cAAc;EACnB,KAAK,gBAAgB;;CAGvB,UAAoB;EAClB,OAAO;GACL,eAAe,UAAU,KAAK;GAC9B,gBAAgB;GAChB,QAAQ;GACT;;CAGH,MAAgB,YAAY,UAAoB;EAC9C,MAAM,WAAW,MAAM,SAAS,MAAM;EACtC,MAAM,IAAI,MAAM,GAAG,SAAS,OAAO,GAAG,WAAW;;;;;ACfrD,IAAa,wBAAb,cAA2C,aAAa;CACtD,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;CAGnC,MAAa,KAAK,EAChB,WACA,SACA,UAKgB;EAChB,MAAM,UAAU;GACd;GACA;GACA;GACA,QAAQ,gBAAgB,IAAI;GAC5B,YAAYA;GACb;EAED,MAAM,aAAa,KAAK,UAAU,QAAQ;EAE1C,MAAM,mBAAmB,IADR,KAAK,CAAC,WAAW,EAAE,EAAE,MAAM,oBAAoB,CACnC,CAAC,QAAQ,CAAC,YAAY,IAAI,kBAAkB,OAAO,CAAC;EAEjF,MAAM,iBAAiB,MAAM,IADE,SAAS,iBACO,CAAC,aAAa;EAE7D,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,+BAA+B;GAC7E,QAAQ;GACR,SAAS;IACP,GAAG,KAAK,SAAS;IACjB,oBAAoB;IACrB;GACD,MAAM;GACP,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;;;;ACnCtC,SAAgB,iBAAiB,SAAiD;CAChF,MAAM,WAAW,SAAS,YAAY;CACtC,MAAM,QACJ,SAAS,SACR,QAAQ,IAAI,gBAAgB,aAAa,EAAE,MAAM,IAClD;CAEF,OAAO,KACL,EACE,OACD,EACD,WAAW;EACT;EACA,cAAc;EACf,CAAC,CACH;;AAGH,MAAMC,WAAS,kBAAkB;AAEjC,MAAa,gBAAgB,OAC3B,iEAAiE,KAAK,GAAG;AAI3E,MAAa,gBAA4B;CAKvC,IAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAChE,OAAO,OAAO,YAAY;MAE1B,OAAOC,IAAQ;;AAInB,MAAa,oBAAoB,WAA2B;CAC1D,IAAI,KAAK,OAAO,aAAa;CAC7B,IAAI,GAAG,WAAW,KAAK,EACrB,KAAK,GAAG,MAAM,EAAE;CAElB,IAAI,GAAG,WAAW,IAChB,SAAO,KACL,WAAW,OAAO,uEAEnB;CAGH,IAAI,CAAC,cAAc,KAAK,GAAG,EAAE;EAC3B,SAAO,MACL,WAAW,OAAO,+DAEnB;EACD,OAAO,SAAS;;CAGlB,OAAO,GAAG,SAAS,IAAI,IAAI,CAAC,QAC1B,wEACA,iBACD;;AAGH,MAAa,qBAAqB,YAAgC;CAChE,IAAI,KAAK,QAAQ,aAAa;CAC9B,IAAI,GAAG,WAAW,KAAK,EACrB,KAAK,GAAG,MAAM,EAAE;CAElB,IAAI,GAAG,WAAW,IAChB,SAAO,KACL,YAAY,QAAQ,wEAErB;CAEH,IAAI,CAAC,cAAc,KAAK,GAAG,EAAE;EAC3B,SAAO,MACL,YAAY,QAAQ,+DAErB;EACD,OAAO,SAAS;;CAGlB,OAAO,GAAG,QACR,wEACA,iBACD;;AAGH,MAAa,gBAAmB,OAAU,WAAmB;CAC3D,IAAI,UAAU,QAAQ,UAAU,KAAA,GAC9B,OAAO;CAGT,MAAM,MAAM,KAAK,UAAU,MAAM;CACjC,IAAI,IAAI,UAAU,QAChB,OAAO;CAGT,OAAO,IAAI,MAAM,GAAG,OAAO,GAAG;;AAGhC,MAAa,WACX,YAIS;CACT,MAAM,UAAU,QAAQ,IAAI,YAAY;CACxC,MAAM,SAAS,QAAQ,KAAK;CAI5B,MAAM,WAAW;EACf;EACA;EACA,QAAQ;EACR,QAAQ,QAAQ;EACjB;CAED,MAAM,WAAW,QAAQ,IAAI,kBAAkB;CAC/C,MAAM,UAAU,CAAC,SAAS,QAAQ,CAAC,SAAS,SAAS,MAAM,CAAC,aAAa,CAAC;CAE1E,MAAM,QAAQ,SAAS,SAAS,CAAC;CAEjC,OAAO;EACL,MAAM,SAAS,SAAS,SAAS,KAAK,YAAY,KAAK,QAAQ,QAAQ,QAAQ,CAAC;EAChF;EACD,CAAC;;;;AC3HJ,MAAMC,WAAS,kBAAkB;AACjC,MAAM,6BAA6B;AACnC,MAAM,kCAAkC;AAExC,IAAa,mBAAb,cAAsC,aAAa;CACjD,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;;;;;;CAQnC,MAAa,eAAmC;EAC9C,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,gBAAgB;GAC9D,QAAQ;GACR,SAAS,KAAK,SAAS;GACxB,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;EAGlC,OAAO,SAAS,MAAM;;;;;;;;CASxB,MAAa,iBAAiB,MAAkC;EAC9D,MAAM,SAAS,IAAI,gBAAgB,EAAE,MAAM,CAAC;EAC5C,MAAM,WAAW,MAAM,MACrB,KAAK,cAAc,gBAAgB,OAAO,UAAU,IACpD;GACE,QAAQ;GACR,SAAS,KAAK,SAAS;GACxB,CACF;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;EAGlC,OAAO,SAAS,MAAM;;;;;;;;;;;;;CAcxB,MAAa,KAAW,EACtB,QACA,MACA,IACA,YAAY,iCACZ,gBAAgB,SAO8B;EAC9C,IAAI,CAAC,QAAQ,CAAC,IACZ,MAAM,IAAI,MAAM,qCAAqC;EAGvD,IAAI,QAAQ,IACV,MAAM,IAAI,MAAM,0CAA0C;EAG5D,IAAI,iBAAiB,CAAC,MACpB,MAAM,IAAI,MAAM,oDAAoD;EAGtE,MAAM,aAAa,OAAO,EAAE,MAAM,GAAG,EAAE,WAAW,IAAK;EACvD,MAAM,eAAe,KAAK,KAAK,OAAO,SAAS,UAAU;EAEzD,IAAI;EACJ,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK,WAAW;GACjD,MAAM,WAAW,KAAK,MAAM,IAAI,UAAU,GAAG;GAC7C,SAAO,MAAM,iBAAiB,SAAS,MAAM,eAAe;GAE5D,MAAM,QAAQ,OAAO,MAAM,GAAG,IAAI,UAAU;GAC5C,MAAM,gBAAgB,MAAM,MAC1B,KAAK,cAAc,2BACnB;IACE,QAAQ;IACR,SAAS,KAAK,SAAS;IACvB,MAAM,KAAK,UAAU;KACnB,GAAG;KACH,YAAY,MAAM,KAAK,WAAW;MAChC,MAAM,MAAM;MACZ,QAAQ,MAAM,UAAU,EAAE;MAC1B,UAAU,MAAM,YAAY,EAAE;MAC/B,EAAE;KACH;KACD,CAAC;IACH,CACF;GAGD,IAAI,cAAc,WAAW,OAAO,cAAc,WAAW,KAC3D,MAAM,KAAK,YAAY,cAAc;GAGvC,WAAY,MAAM,cAAc,MAAM;;EAGxC,OAAO;;;;;;;;;;;;CAaT,MAAa,KAAW,EACtB,MACA,IACA,QAAQ,4BACR,SAAS,KAM8B;EACvC,IAAI,CAAC,QAAQ,CAAC,IACZ,MAAM,IAAI,MAAM,qCAAqC;EAGvD,IAAI,QAAQ,IACV,MAAM,IAAI,MAAM,0CAA0C;EAG5D,MAAM,YAAoC;GACxC,QAAQ,OAAO,UAAU;GACzB,OAAO,MAAM,UAAU;GACxB;EAED,IAAI,MACF,UAAU,OAAO;OAEjB,UAAU,YAAY;EAGxB,MAAM,SAAS,IAAI,gBAAgB,UAAU;EAE7C,MAAM,WAAW,MAAM,MACrB,KAAK,cAAc,2BAA2B,OAAO,UAAU,IAC/D;GACE,QAAQ;GACR,SAAS,KAAK,SAAS;GACxB,CACF;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;EAGlC,OAAO,SAAS,MAAM;;;;;AClL1B,MAAMC,WAAS,kBAAkB;AACjC,MAAM,+CAA+C;AAErD,IAAa,gBAAb,cAAmC,aAAa;CAC9C,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;;;;;;;;;CAWnC,MAAa,KACX,MACA,WACA,UACiC;EACjC,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,aAAa;GAC3D,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU;IACnB,MAAM,QAAQ;IACd,WAAW,aAAa;IACxB,UAAU,YAAY;IACvB,CAAC;GACH,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;EAGlC,OAAO,SAAS,MAAM;;;;;;;;;;CAYxB,MAAa,OAAO,MAEI;EAEtB,QAAO,MADkB,KAAK,KAAK,MAAM,MAAM,MAAM,WAAW,MAAM,SAAS,EAC7D;;;;;;CAOpB,MAAa,iBACX,MACA,WACA,UACqB;EAErB,QAAO,MADkB,KAAK,KAAK,MAAM,WAAW,SAAS,EAC3C;;;;;;;;;;;;;;CAepB,MAAa,gBAAsB,EACjC,QACA,MACA,QACA,UACA,OACA,WAQsB;EACtB,MAAM,cAAc,SAAS;EAE7B,MAAM,mBAAmD;GACvD,IAAI;GACJ;GACA;GACA,OAAO,SAAS;GAChB,SAAS,WAAW,SAAS;GAC7B,gBAAgB,SAAS;GACzB;GACD;EAED,MAAM,KAAK,eAAe;GACxB;GACA,YAAY,CAAC,iBAAiB;GAC/B,CAAC;EAEF,OAAO;;;;;;;;;;;;CAaT,MAAa,gBAAmB,EAC9B,QACA,aACA,QACA,kBAMgB;EAChB,MAAM,WAAW,MAAM,MACrB,KAAK,cAAc,aAAa,OAAO,cAAc,eACrD;GACE,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU;IACnB;IACA;IACD,CAAC;GACH,CACF;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;;;;;;;;;;CAapC,MAAa,eAAwB,EACnC,QACA,YACA,aAKgB;EAChB,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,aAAa,OAAO,cAAc;GAChF,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU;IACnB,QAAQ,WAAW,KAAK,OACtB;KACE,GAAG;KACH,MAAM,aAAa,EAAE,MAAM,6CAA6C;KACxE,QAAQ,aAAa,EAAE,QAAQ,6CAA6C;KAC5E,gBAAgB,aACd,EAAE,gBACF,6CACD;KACF,EAAE;IACL,WAAW,aAAa;IACzB,CAAC;GACH,CAAC;EAEF,IAAI,SAAS,WAAW,KACtB,OAAO,MAAM,KAAK,oBAAoB;GACpC;GACA;GACA;GACD,CAAC;EAGJ,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;;;;;;;;;;;CAcpC,MAAa,cAAoB,EAC/B,aACA,QACA,SAKuC;EACvC,SAAO,KACL,2EACD;EAED,MAAM,SAAS,IAAI,gBAAgB;GACjC,MAAM;GACN,QAAQ,OAAO,UAAU;GACzB,OAAO,MAAM,UAAU;GACxB,CAAC;EACF,MAAM,WAAW,MAAM,MACrB,KAAK,cAAc,2BAA2B,OAAO,UAAU,IAC/D;GACE,QAAQ;GACR,SAAS,KAAK,SAAS;GACxB,CACF;EAED,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;EAGlC,OAAQ,MAAM,SAAS,MAAM;;CAG/B,MAAc,oBAA6B,EACzC,QACA,YACA,WACA,aAAa,IACb,gBAAgB,gDAOA;EAChB,IAAI,SAAS;EACb,IAAI,eAAgC;EACpC,KAAK,IAAI,IAAI,GAAG,IAAI,YAAY,KAAK;GACnC,SAAO,MAAM,+BAA+B,IAAI,EAAE,MAAM,WAAW,YAAY,SAAS;GACxF,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,aAAa,OAAO,cAAc;IAChF,QAAQ;IACR,SAAS,KAAK,SAAS;IACvB,MAAM,KAAK,UAAU;KACnB,QAAQ,WAAW,KAAK,OACtB;MACE,GAAG;MACH,MAAM,aAAa,EAAE,MAAM,OAAO;MAClC,QAAQ,aAAa,EAAE,QAAQ,OAAO;MACtC,gBAAgB,aAAa,EAAE,gBAAgB,OAAO;MACvD,EAAE;KACL,WAAW,aAAa;KACzB,CAAC;IACH,CAAC;GACF,eAAe;GACf,SAAS,KAAK,MAAM,SAAS,EAAE;GAC/B,IAAI,SAAS,WAAW,KACtB;;EAGJ,IAAI,gBAAgB,CAAC,aAAa,IAChC,MAAM,KAAK,YAAY,aAAa;;;;;;;;ACpQ1C,IAAa,qBAAb,cAAwC,aAAa;CACnD,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BnC,MAAa,MAAM,SAAsC;EACvD,MAAM,EAAE,MAAM,UAAU,UAAU;EAElC,IAAI;EAEJ,IAAI,aAAa,WAAW,QAAQ,SAKlC,UAAU;GACR;GACA;GACA;GACA,QAAA;GACA,SATuB,aAAa,QAAQ,QAAQ,GAClD,QAAQ,UACR,kBAAkB,QAAQ,QAAQ;GAQrC;OACI,IAAI,YAAY,WAAW,QAAQ,QAKxC,UAAU;GACR;GACA;GACA;GACA,QAAA;GACA,QATsB,aAAa,QAAQ,OAAO,GAChD,QAAQ,SACR,iBAAiB,QAAQ,OAAO;GAQnC;OAED,MAAM,IAAI,MAAM,iDAAiD;EAGnE,MAAM,WAAW,MAAM,MAAM,KAAK,cAAc,wBAAwB;GACtE,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU,QAAQ;GAC9B,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;;;;ACpGtC,IAAa,0BAAb,cAA6C,aAAa;CACxD,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;;;;;CAOnC,MAAa,QAAQ,EACnB,WACA,MACA,QACA,UAMoB;EACpB,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,YAAY,eAAe,aAAa;GAC3E,QAAQ;GACR,SAAS;IACP,GAAG,KAAK,SAAS;IACjB,UAAU;IACX;GACD,MAAM,KAAK,UAAU;IAAE;IAAM;IAAQ,CAAC;GACtC;GACD,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,0BAA0B,SAAS,OAAO,GAAG,SAAS,aAAa;EAGrF,IAAI,CAAC,SAAS,MACZ,MAAM,IAAI,MAAM,mBAAmB;EAGrC,OAAO;;CAGT,MAAa,OAAO,EAClB,aAGC;EACD,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,YAAY,eAAe,aAAa;GAC3E,QAAQ;GACR,SAAS,KAAK,SAAS;GACxB,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;CAIpC,MAAa,UAAU,EACrB,WACA,UAIC;EACD,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,YAAY,eAAe,UAAU,UAAU;GAClF,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU,EAAE,QAAQ,CAAC;GACjC,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;CAIpC,MAAa,eAAe,EAC1B,WACA,QAYC;EACD,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,YAAY,eAAe,UAAU,UAAU;GAClF,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU;IACnB,MAAM;IACN,QAAQ,iBAAiB,KAAK,OAAO;IACrC,SAAS,kBAAkB,KAAK,QAAQ;IACxC,cAAc,KAAK,eAAe,iBAAiB,KAAK,aAAa,GAAG,KAAA;IACxE,YAAY,KAAK;IACjB,WAAW,KAAK;IAChB,MAAM,KAAK;IACX,UAAU,KAAK;IAChB,CAAC;GACH,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;;;;AC5GtC,IAAa,cAAb,cAAiC,aAAa;CAC5C,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;CAGnC,MAAa,MACX,KACA,aAAkC,EAAE,EACC;EACrC,MAAM,WAAW,MAAM,MAAM,GAAG,KAAK,YAAY,gBAAgB;GAC/D,QAAQ;GACR,SAAS,EACP,GAAG,KAAK,SAAS,EAClB;GACD,MAAM,KAAK,UAAU;IACnB,OAAO;IACP;IACD,CAAC;GACH,CAAC;EAEF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;EAGlC,QAAQ,MAAM,SAAS,MAAM,EAAE;;;;;;ACpBnC,IAAa,eAAb,cAAkC,aAAa;;CAE7C,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCnC,MAAa,IACX,UACA,MACc;EACd,MAAM,YAAY,MAAM,QAAQ,KAAK,GAAG,OAAO,CAAC,KAAK;EACrD,MAAM,mBAAmB,aAAa,SAAS,GAC3C,WACA,kBAAkB,SAAS;EAE/B,MAAM,MAAM,KAAK,cAAc;EAC/B,MAAM,UAAU;GACd,WAAW;GACX,SAAS;GACV;EACD,MAAM,WAAW,MAAM,MACrB,KACA;GACE,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU,QAAQ;GAC9B,CACF;EACD,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;EAElC,OAAO,SAAS,MAAM;;;;;;AChE1B,MAAM,SAAS,kBAAkB;AAEjC,IAAa,iBAAb,cAAoC,aAAa;;CAE/C,YAAY,aAAqB,eAAuB;EACtD,MAAM,aAAa,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkDnC,MAAa,aACX,SACA,UACe;EACf,IAAI,CAAC,YAAY,OAAO,KAAK,SAAS,CAAC,WAAW,GAChD,MAAM,IAAI,MAAM,sCAAsC;EAGxD,MAAM,mBAAmB,aAAa,QAAQ,GAC1C,UACA,kBAAkB,QAAQ;EAE9B,MAAM,MAAM,KAAK,cAAc;EAC/B,MAAM,WAAW,MAAM,MAAM,KAAK;GAChC,QAAQ;GACR,SAAS,KAAK,SAAS;GACvB,MAAM,KAAK,UAAU;IACnB,SAAS;IACT;IACD,CAAC;GACH,CAAC;EAEF,IAAI,SAAS,WAAW,KAAK;GAG3B,OAAO,KACL,SAAS,iBAAiB,6FAE3B;GACD;;EAGF,IAAI,CAAC,SAAS,IACZ,MAAM,KAAK,YAAY,SAAS;;;;;ACnFtC,IAAa,gBAAb,MAA2B;CAYzB,YAAY,EACV,SACA,eACA,SAKE,EAAE,EAAE;EACN,SAAS;EACT,KAAK,gBAAgB,iBAAiB,QAAQ,IAAI;EAClD,MAAM,WAAW,SACf,SAAS,MAAM,aAAa,GACxB,SAAS,QAAQ,MAAM,aAAa,CAAE,GAAG,MAAM,EAAE,CAAC,GAClD;EACN,MAAM,iBAAiB,WAAW,QAAQ,IAAI,gBAC1C,QAAQ,OAAO,GAAG,CAAC,QAAQ,cAAc,GAAG;EAChD,KAAK,UAAU,GAAG,iBAAiB,sBAAsB,GAAG;EAC5D,KAAK,iBAAiB,IAAI,sBAAsB,KAAK,SAAS,KAAK,cAAc;EACjF,KAAK,YAAY,IAAI,iBAAiB,KAAK,SAAS,KAAK,cAAc;EACvE,KAAK,SAAS,IAAI,cAAc,KAAK,SAAS,KAAK,cAAc;EACjE,KAAK,cAAc,IAAI,mBAAmB,KAAK,SAAS,KAAK,cAAc;EAC3E,KAAK,mBAAmB,IAAI,wBAAwB,KAAK,SAAS,KAAK,cAAc;EACrF,KAAK,OAAO,IAAI,YAAY,KAAK,SAAS,KAAK,cAAc;EAC7D,KAAK,QAAQ,IAAI,aAAa,KAAK,SAAS,KAAK,cAAc;EAC/D,KAAK,UAAU,IAAI,eAAe,KAAK,SAAS,KAAK,cAAc;;CAGrE,IAAW,gBAAgB;EACzB,OAAO,KAAK;;CAGd,IAAW,WAAW;EACpB,OAAO,KAAK;;CAGd,IAAW,QAAQ;EACjB,OAAO,KAAK;;CAGd,IAAW,aAAa;EACtB,OAAO,KAAK;;CAGd,IAAW,kBAAkB;EAC3B,OAAO,KAAK;;CAGd,IAAW,MAAM;EACf,OAAO,KAAK;;CAGd,IAAW,OAAO;EAChB,OAAO,KAAK;;CAGd,IAAW,SAAS;EAClB,OAAO,KAAK"}
1
+ {"version":3,"file":"index.mjs","names":["SDK_VERSION","logger","uuidv4","logger","logger","logger"],"sources":["../package.json","../src/version.ts","../src/resources/index.ts","../src/resources/browser-events.ts","../src/utils.ts","../src/resources/datasets.ts","../src/resources/evals.ts","../src/resources/evaluators.ts","../src/resources/rollout-sessions.ts","../src/resources/sql.ts","../src/resources/tags.ts","../src/resources/traces.ts","../src/index.ts"],"sourcesContent":["","// Version detection for runtime environment\nexport function getLangVersion(): string | null {\n if (typeof process !== 'undefined' && process.versions && process.versions.node) {\n return `node-${process.versions.node}`;\n }\n if (typeof navigator !== 'undefined' && navigator.userAgent) {\n return `browser-${navigator.userAgent}`;\n }\n return null;\n}\n","class BaseResource {\n protected readonly baseHttpUrl: string;\n protected readonly projectApiKey: string;\n\n constructor(baseHttpUrl: string, projectApiKey: string) {\n this.baseHttpUrl = baseHttpUrl;\n this.projectApiKey = projectApiKey;\n }\n\n protected headers() {\n return {\n Authorization: `Bearer ${this.projectApiKey}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n }\n\n protected async handleError(response: Response) {\n const errorMsg = await response.text();\n throw new Error(`${response.status} ${errorMsg}`);\n }\n}\n\nexport { BaseResource };\n","import { version as SDK_VERSION } from '../../package.json';\nimport { getLangVersion } from \"../version\";\nimport { BaseResource } from \"./index\";\n\nexport class BrowserEventsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n public async send({\n sessionId,\n traceId,\n events,\n }: {\n sessionId: string;\n traceId: string;\n events: Record<string, any>[];\n }): Promise<void> {\n const payload = {\n sessionId,\n traceId,\n events,\n source: getLangVersion() ?? 'javascript',\n sdkVersion: SDK_VERSION,\n };\n\n const jsonString = JSON.stringify(payload);\n const blob = new Blob([jsonString], { type: 'application/json' });\n const compressedStream = blob.stream().pipeThrough(new CompressionStream('gzip'));\n const compressedResponse = new Response(compressedStream);\n const compressedData = await compressedResponse.arrayBuffer();\n\n const response = await fetch(this.baseHttpUrl + \"/v1/browser-sessions/events\", {\n method: \"POST\",\n headers: {\n ...this.headers(),\n 'Content-Encoding': 'gzip',\n },\n body: compressedData,\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { type StringUUID } from '@lmnr-ai/types';\nimport { config } from 'dotenv';\nimport * as path from 'path';\nimport pino, { Level } from 'pino';\nimport { PinoPretty } from 'pino-pretty';\nimport { v4 as uuidv4 } from 'uuid';\n\nexport function initializeLogger(options?: { colorize?: boolean; level?: Level }) {\n const colorize = options?.colorize ?? true;\n const level =\n options?.level ??\n (process.env.LMNR_LOG_LEVEL?.toLowerCase()?.trim() as Level) ??\n 'info';\n\n return pino(\n {\n level,\n },\n PinoPretty({\n colorize,\n minimumLevel: level,\n }),\n );\n}\n\nconst logger = initializeLogger();\n\nexport const isStringUUID = (id: string): id is StringUUID =>\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(id);\n\nexport const NIL_UUID: StringUUID = '00000000-0000-0000-0000-000000000000';\n\nexport const newUUID = (): StringUUID => {\n // crypto.randomUUID is available in most of the modern browsers and node,\n // but is not available in \"insecure\" contexts, e.g. not https, not localhost\n // so we fallback to uuidv4 in those cases, which is less secure, but works\n // just fine.\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n } else {\n return uuidv4() as `${string}-${string}-${string}-${string}-${string}`;\n }\n};\n\nexport const otelSpanIdToUUID = (spanId: string): string => {\n let id = spanId.toLowerCase();\n if (id.startsWith('0x')) {\n id = id.slice(2);\n }\n if (id.length !== 16) {\n logger.warn(\n `Span ID ${spanId} is not 16 hex chars long. ` +\n 'This is not a valid OpenTelemetry span ID.',\n );\n }\n\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(\n `Span ID ${spanId} is not a valid hex string. ` +\n 'Generating a random UUID instead.',\n );\n return newUUID();\n }\n\n return id.padStart(32, '0').replace(\n /^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/,\n '$1-$2-$3-$4-$5',\n );\n};\n\nexport const otelTraceIdToUUID = (traceId: string): StringUUID => {\n let id = traceId.toLowerCase();\n if (id.startsWith('0x')) {\n id = id.slice(2);\n }\n if (id.length !== 32) {\n logger.warn(\n `Trace ID ${traceId} is not 32 hex chars long. ` +\n 'This is not a valid OpenTelemetry trace ID.',\n );\n }\n if (!/^[0-9a-f]+$/.test(id)) {\n logger.error(\n `Trace ID ${traceId} is not a valid hex string. ` +\n 'Generating a random UUID instead.',\n );\n return newUUID();\n }\n\n return id.replace(\n /^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/,\n '$1-$2-$3-$4-$5',\n ) as StringUUID;\n};\n\nexport const slicePayload = <T>(value: T, length: number) => {\n if (value === null || value === undefined) {\n return value;\n }\n\n const str = JSON.stringify(value);\n if (str.length <= length) {\n return value;\n }\n\n return str.slice(0, length) + '...';\n};\n\nexport const loadEnv = (\n options?: {\n quiet?: boolean;\n paths?: string[];\n },\n): void => {\n const nodeEnv = process.env.NODE_ENV || 'development';\n const envDir = process.cwd();\n\n // Files to load in order (lowest to highest priority)\n // Later files override earlier ones\n const envFiles = [\n '.env',\n '.env.local',\n `.env.${nodeEnv}`,\n `.env.${nodeEnv}.local`,\n ];\n\n const logLevel = process.env.LMNR_LOG_LEVEL ?? 'info';\n const verbose = ['debug', 'trace'].includes(logLevel.trim().toLowerCase());\n\n const quiet = options?.quiet ?? !verbose;\n\n config({\n path: options?.paths ?? envFiles.map((envFile) => path.resolve(envDir, envFile)),\n quiet,\n });\n};\n","import {\n type Datapoint,\n type Dataset,\n type GetDatapointsResponse,\n type PushDatapointsResponse,\n type StringUUID,\n} from \"@lmnr-ai/types\";\n\nimport { initializeLogger } from \"../utils\";\nimport { BaseResource } from \".\";\n\nconst logger = initializeLogger();\nconst DEFAULT_DATASET_PULL_LIMIT = 100;\nconst DEFAULT_DATASET_PUSH_BATCH_SIZE = 100;\n\nexport class DatasetsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * List all datasets.\n *\n * @returns {Promise<Dataset[]>} Array of datasets\n */\n public async listDatasets(): Promise<Dataset[]> {\n const response = await fetch(this.baseHttpUrl + \"/v1/datasets\", {\n method: \"GET\",\n headers: this.headers(),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<Dataset[]>;\n }\n\n /**\n * Get a dataset by name.\n *\n * @param {string} name - Name of the dataset\n * @returns {Promise<Dataset[]>} Array of datasets with matching name\n */\n public async getDatasetByName(name: string): Promise<Dataset[]> {\n const params = new URLSearchParams({ name });\n const response = await fetch(\n this.baseHttpUrl + `/v1/datasets?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<Dataset[]>;\n }\n\n /**\n * Push datapoints to a dataset.\n *\n * @param {Object} options - Push options\n * @param {Datapoint<D, T>[]} options.points - Datapoints to push\n * @param {string} [options.name] - Name of the dataset (either name or id must be provided)\n * @param {StringUUID} [options.id] - ID of the dataset (either name or id must be provided)\n * @param {number} [options.batchSize] - Batch size for pushing (default: 100)\n * @param {boolean} [options.createDataset] - Whether to create the dataset if it doesn't exist\n * @returns {Promise<PushDatapointsResponse | undefined>}\n */\n public async push<D, T>({\n points,\n name,\n id,\n batchSize = DEFAULT_DATASET_PUSH_BATCH_SIZE,\n createDataset = false,\n }: {\n points: Datapoint<D, T>[];\n name?: string;\n id?: StringUUID;\n batchSize?: number;\n createDataset?: boolean;\n }): Promise<PushDatapointsResponse | undefined> {\n if (!name && !id) {\n throw new Error(\"Either name or id must be provided\");\n }\n\n if (name && id) {\n throw new Error(\"Only one of name or id must be provided\");\n }\n\n if (createDataset && !name) {\n throw new Error(\"Name must be provided when creating a new dataset\");\n }\n\n const identifier = name ? { name } : { datasetId: id! };\n const totalBatches = Math.ceil(points.length / batchSize);\n\n let response: PushDatapointsResponse | undefined;\n for (let i = 0; i < points.length; i += batchSize) {\n const batchNum = Math.floor(i / batchSize) + 1;\n logger.debug(`Pushing batch ${batchNum} of ${totalBatches}`);\n\n const batch = points.slice(i, i + batchSize);\n const fetchResponse = await fetch(\n this.baseHttpUrl + \"/v1/datasets/datapoints\",\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n ...identifier,\n datapoints: batch.map((point) => ({\n data: point.data,\n target: point.target ?? {},\n metadata: point.metadata ?? {},\n })),\n createDataset,\n }),\n },\n );\n\n // 201 when creating a new dataset\n if (fetchResponse.status !== 200 && fetchResponse.status !== 201) {\n await this.handleError(fetchResponse);\n }\n\n response = (await fetchResponse.json()) as PushDatapointsResponse;\n }\n\n return response;\n }\n\n /**\n * Pull datapoints from a dataset.\n *\n * @param {Object} options - Pull options\n * @param {string} [options.name] - Name of the dataset (either name or id must be provided)\n * @param {StringUUID} [options.id] - ID of the dataset (either name or id must be provided)\n * @param {number} [options.limit] - Maximum number of datapoints to return (default: 100)\n * @param {number} [options.offset] - Offset for pagination (default: 0)\n * @returns {Promise<GetDatapointsResponse<D, T>>}\n */\n public async pull<D, T>({\n name,\n id,\n limit = DEFAULT_DATASET_PULL_LIMIT,\n offset = 0,\n }: {\n name?: string;\n id?: StringUUID;\n limit?: number;\n offset?: number;\n }): Promise<GetDatapointsResponse<D, T>> {\n if (!name && !id) {\n throw new Error(\"Either name or id must be provided\");\n }\n\n if (name && id) {\n throw new Error(\"Only one of name or id must be provided\");\n }\n\n const paramsObj: Record<string, string> = {\n offset: offset.toString(),\n limit: limit.toString(),\n };\n\n if (name) {\n paramsObj.name = name;\n } else {\n paramsObj.datasetId = id!;\n }\n\n const params = new URLSearchParams(paramsObj);\n\n const response = await fetch(\n this.baseHttpUrl + `/v1/datasets/datapoints?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<GetDatapointsResponse<D, T>>;\n }\n}\n","import {\n type EvaluationDatapoint,\n type GetDatapointsResponse,\n type InitEvaluationResponse,\n type StringUUID,\n} from \"@lmnr-ai/types\";\n\nimport { initializeLogger, newUUID, slicePayload } from \"../utils\";\nimport { BaseResource } from \".\";\n\nconst logger = initializeLogger();\nconst INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH = 16_000_000; // 16MB\n\nexport class EvalsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Initialize an evaluation.\n *\n * @param {string} name - Name of the evaluation\n * @param {string} groupName - Group name of the evaluation\n * @param {Record<string, any>} metadata - Optional metadata\n * @returns {Promise<InitEvaluationResponse>} Response from the evaluation initialization\n */\n public async init(\n name?: string,\n groupName?: string,\n metadata?: Record<string, any>,\n ): Promise<InitEvaluationResponse> {\n const response = await fetch(this.baseHttpUrl + \"/v1/evals\", {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n name: name ?? null,\n groupName: groupName ?? null,\n metadata: metadata ?? null,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return response.json() as Promise<InitEvaluationResponse>;\n }\n\n /**\n * Create a new evaluation and return its ID.\n *\n * @param {string} [name] - Optional name of the evaluation\n * @param {string} [groupName] - An identifier to group evaluations\n * @param {Record<string, any>} [metadata] - Optional metadata\n * @returns {Promise<StringUUID>} The evaluation ID\n */\n\n public async create(args?: {\n name?: string, groupName?: string, metadata?: Record<string, any>\n }): Promise<StringUUID> {\n const evaluation = await this.init(args?.name, args?.groupName, args?.metadata);\n return evaluation.id;\n }\n\n /**\n * Create a new evaluation and return its ID.\n * @deprecated use `create` instead.\n */\n public async createEvaluation(\n name?: string,\n groupName?: string,\n metadata?: Record<string, any>,\n ): Promise<StringUUID> {\n const evaluation = await this.init(name, groupName, metadata);\n return evaluation.id;\n }\n\n /**\n * Create a datapoint for an evaluation.\n *\n * @param {Object} options - Create datapoint options\n * @param {string} options.evalId - The evaluation ID\n * @param {D} options.data - The input data for the executor\n * @param {T} [options.target] - The target/expected output for evaluators\n * @param {Record<string, any>} [options.metadata] - Optional metadata\n * @param {number} [options.index] - Optional index of the datapoint\n * @param {string} [options.traceId] - Optional trace ID\n * @returns {Promise<StringUUID>} The datapoint ID\n */\n public async createDatapoint<D, T>({\n evalId,\n data,\n target,\n metadata,\n index,\n traceId,\n }: {\n evalId: string;\n data: D;\n target?: T;\n metadata?: Record<string, any>;\n index?: number;\n traceId?: string;\n }): Promise<StringUUID> {\n const datapointId = newUUID();\n\n const partialDatapoint: EvaluationDatapoint<D, T, any> = {\n id: datapointId,\n data,\n target,\n index: index ?? 0,\n traceId: traceId ?? newUUID(),\n executorSpanId: newUUID(),\n metadata,\n };\n\n await this.saveDatapoints({\n evalId,\n datapoints: [partialDatapoint],\n });\n\n return datapointId;\n }\n\n /**\n * Update a datapoint with evaluation results.\n *\n * @param {Object} options - Update datapoint options\n * @param {string} options.evalId - The evaluation ID\n * @param {string} options.datapointId - The datapoint ID\n * @param {Record<string, number>} options.scores - The scores\n * @param {O} [options.executorOutput] - The executor output\n * @returns {Promise<void>}\n */\n public async updateDatapoint<O>({\n evalId,\n datapointId,\n scores,\n executorOutput,\n }: {\n evalId: string;\n datapointId: string;\n scores: Record<string, number>;\n executorOutput?: O;\n }): Promise<void> {\n const response = await fetch(\n this.baseHttpUrl + `/v1/evals/${evalId}/datapoints/${datapointId}`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n executorOutput,\n scores,\n }),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n /**\n * Save evaluation datapoints.\n *\n * @param {Object} options - Save datapoints options\n * @param {string} options.evalId - ID of the evaluation\n * @param {EvaluationDatapoint<D, T, O>[]} options.datapoints - Datapoint to add\n * @param {string} [options.groupName] - Group name of the evaluation\n * @returns {Promise<void>} Response from the datapoint addition\n */\n public async saveDatapoints<D, T, O>({\n evalId,\n datapoints,\n groupName,\n }: {\n evalId: string;\n datapoints: EvaluationDatapoint<D, T, O>[];\n groupName?: string;\n }): Promise<void> {\n const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n points: datapoints.map((d) => (\n {\n ...d,\n data: slicePayload(d.data, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH),\n target: slicePayload(d.target, INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH),\n executorOutput: slicePayload(\n d.executorOutput,\n INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH,\n ),\n })),\n groupName: groupName ?? null,\n }),\n });\n\n if (response.status === 413) {\n return await this.retrySaveDatapoints({\n evalId,\n datapoints,\n groupName,\n });\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n /**\n * Get evaluation datapoints.\n *\n * @deprecated Use `client.datasets.pull()` instead.\n * @param {Object} options - Get datapoints options\n * @param {string} options.datasetName - Name of the dataset\n * @param {number} options.offset - Offset at which to start the query\n * @param {number} options.limit - Maximum number of datapoints to return\n * @returns {Promise<GetDatapointsResponse>} Response from the datapoint retrieval\n */\n public async getDatapoints<D, T>({\n datasetName,\n offset,\n limit,\n }: {\n datasetName: string;\n offset: number;\n limit: number;\n }): Promise<GetDatapointsResponse<D, T>> {\n logger.warn(\n 'evals.getDatapoints() is deprecated. Use client.datasets.pull() instead.',\n );\n\n const params = new URLSearchParams({\n name: datasetName,\n offset: offset.toString(),\n limit: limit.toString(),\n });\n const response = await fetch(\n this.baseHttpUrl + `/v1/datasets/datapoints?${params.toString()}`,\n {\n method: \"GET\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()) as GetDatapointsResponse<D, T>;\n }\n\n private async retrySaveDatapoints<D, T, O>({\n evalId,\n datapoints,\n groupName,\n maxRetries = 25,\n initialLength = INITIAL_EVALUATION_DATAPOINT_MAX_DATA_LENGTH,\n }: {\n evalId: string;\n datapoints: EvaluationDatapoint<D, T, O>[];\n groupName?: string;\n maxRetries?: number;\n initialLength?: number;\n }): Promise<void> {\n let length = initialLength;\n let lastResponse: Response | null = null;\n for (let i = 0; i < maxRetries; i++) {\n logger.debug(`Retrying save datapoints... ${i + 1} of ${maxRetries}, length: ${length}`);\n const response = await fetch(this.baseHttpUrl + `/v1/evals/${evalId}/datapoints`, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n points: datapoints.map((d) => (\n {\n ...d,\n data: slicePayload(d.data, length),\n target: slicePayload(d.target, length),\n executorOutput: slicePayload(d.executorOutput, length),\n })),\n groupName: groupName ?? null,\n }),\n });\n lastResponse = response;\n length = Math.floor(length / 2);\n if (response.status !== 413) {\n break;\n }\n }\n if (lastResponse && !lastResponse.ok) {\n await this.handleError(lastResponse);\n }\n }\n}\n","import { type StringUUID } from \"@lmnr-ai/types\";\n\nimport { isStringUUID, otelSpanIdToUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \".\";\n\nenum EvaluatorScoreSourceType {\n Evaluator = \"Evaluator\",\n Code = \"Code\",\n}\n\ninterface CreateEvaluatorScoreBase {\n name: string;\n metadata?: Record<string, any>;\n score: number;\n source: EvaluatorScoreSourceType;\n}\n\ninterface CreateEvaluatorScoreRequestWithTraceId extends CreateEvaluatorScoreBase {\n traceId: string;\n}\n\ninterface CreateEvaluatorScoreRequestWithSpanId extends CreateEvaluatorScoreBase {\n spanId: string;\n}\n\ntype ScoreOptions =\n | { name: string; metadata?: Record<string, any>; score: number; traceId: string; }\n | { name: string; metadata?: Record<string, any>; score: number; spanId: string; };\n\n/**\n * Resource for creating evaluator scores\n */\nexport class EvaluatorsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Create a score for a span or trace\n *\n * @param {ScoreOptions} options - Score creation options\n * @param {string} options.name - Name of the score\n * @param {string} [options.traceId] - The trace ID to score (will be attached to top-level span)\n * @param {string} [options.spanId] - The span ID to score\n * @param {Record<string, any>} [options.metadata] - Additional metadata\n * @param {number} options.score - The score value (float)\n * @returns {Promise<void>}\n *\n * @example\n * // Score by trace ID (will attach to root span)\n * await evaluators.score({\n * name: \"quality\",\n * traceId: \"trace-id-here\",\n * score: 0.95,\n * metadata: { model: \"gpt-4\" }\n * });\n *\n * @example\n * // Score by span ID\n * await evaluators.score({\n * name: \"relevance\",\n * spanId: \"span-id-here\",\n * score: 0.87\n * });\n */\n public async score(options: ScoreOptions): Promise<void> {\n const { name, metadata, score } = options;\n\n let payload: CreateEvaluatorScoreRequestWithTraceId | CreateEvaluatorScoreRequestWithSpanId;\n\n if ('traceId' in options && options.traceId) {\n const formattedTraceId = isStringUUID(options.traceId)\n ? options.traceId\n : otelTraceIdToUUID(options.traceId);\n\n payload = {\n name,\n metadata,\n score,\n source: EvaluatorScoreSourceType.Code,\n traceId: formattedTraceId,\n };\n } else if ('spanId' in options && options.spanId) {\n const formattedSpanId = isStringUUID(options.spanId)\n ? options.spanId\n : otelSpanIdToUUID(options.spanId) as StringUUID;\n\n payload = {\n name,\n metadata,\n score,\n source: EvaluatorScoreSourceType.Code,\n spanId: formattedSpanId,\n };\n } else {\n throw new Error(\"Either 'traceId' or 'spanId' must be provided.\");\n }\n\n const response = await fetch(this.baseHttpUrl + \"/v1/evaluators/score\", {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { errorMessage } from \"@lmnr-ai/types\";\n\nimport { initializeLogger } from \"../utils\";\nimport { BaseResource } from \"./index\";\n\nconst logger = initializeLogger();\n\nexport class RolloutSessionsResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Idempotently register (upsert) a debug session on the backend, keyed on the\n * SDK-supplied session id. The backend stores the row so the session is\n * visible in the UI; a null/omitted name never clobbers a name set elsewhere.\n *\n * Returns the backend-resolved `projectId` (derived from the API key) so the\n * caller can build the debugger URL; null if the body can't be parsed.\n */\n public async register({\n sessionId,\n name,\n }: {\n sessionId: string;\n name?: string;\n }): Promise<string | null> {\n const response = await fetch(\n `${this.baseHttpUrl}/v1/rollouts/${sessionId}`,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({ name }),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n try {\n const body = (await response.json()) as { projectId?: string };\n return body.projectId ?? null;\n } catch (e) {\n logger.warn(\n `Failed to parse rollout register response: ${errorMessage(e)}`,\n );\n return null;\n }\n }\n\n /**\n * Rename an existing debug session. Update-only: the backend returns 404 (and\n * this throws) when the session id is unknown for the project, so a mistyped\n * id surfaces as an error rather than silently creating a session. Creation\n * stays the SDK's job via {@link register}.\n */\n public async setName({\n sessionId,\n name,\n }: {\n sessionId: string;\n name: string;\n }): Promise<void> {\n const response = await fetch(\n `${this.baseHttpUrl}/v1/rollouts/${sessionId}/name`,\n {\n method: \"PATCH\",\n headers: this.headers(),\n body: JSON.stringify({ name }),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n\n public async delete({ sessionId }: { sessionId: string }): Promise<void> {\n const response = await fetch(\n `${this.baseHttpUrl}/v1/rollouts/${sessionId}`,\n {\n method: \"DELETE\",\n headers: this.headers(),\n },\n );\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BaseResource } from \"./index\";\n\nexport class SqlResource extends BaseResource {\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n public async query(\n sql: string,\n parameters: Record<string, any> = {},\n ): Promise<Array<Record<string, any>>> {\n const response = await fetch(`${this.baseHttpUrl}/v1/sql/query`, {\n method: \"POST\",\n headers: {\n ...this.headers(),\n },\n body: JSON.stringify({\n query: sql,\n parameters,\n }),\n });\n\n if (!response.ok) {\n await this.handleError(response);\n }\n\n return (await response.json()).data as Array<Record<string, any>>;\n }\n}\n","/** Resource for tagging traces. */\n\n\nimport { isStringUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \"./index\";\n\nexport class TagsResource extends BaseResource {\n /** Resource for tagging traces. */\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Tag a trace with a list of tags. Note that the trace must be ended before\n * tagging it. You may want to call `await Laminar.flush()` after the trace\n * that you want to tag.\n *\n * @param {string | StringUUID} trace_id - The trace id to tag.\n * @param {string[] | string} tags - The tag or list of tags to add to the trace.\n * @returns {Promise<any>} The response from the server.\n * @example\n * ```javascript\n * import { Laminar, observe, LaminarClient } from \"@lmnr-ai/lmnr\";\n * Laminar.initialize();\n * const client = new LaminarClient();\n * let traceId: StringUUID | null = null;\n * // Make sure this is called outside of traced context.\n * await observe(\n * {\n * name: \"my-trace\",\n * },\n * async () => {\n * traceId = await Laminar.getTraceId();\n * await foo();\n * },\n * );\n *\n * // or make sure the trace is ended by this point.\n * await Laminar.flush();\n * if (traceId) {\n * await client.tags.tag(traceId, [\"tag1\", \"tag2\"]);\n * }\n * ```\n */\n public async tag(\n trace_id: string,\n tags: string[] | string,\n ): Promise<any> {\n const traceTags = Array.isArray(tags) ? tags : [tags];\n const formattedTraceId = isStringUUID(trace_id)\n ? trace_id\n : otelTraceIdToUUID(trace_id);\n\n const url = this.baseHttpUrl + \"/v1/tag\";\n const payload = {\n \"traceId\": formattedTraceId,\n \"names\": traceTags,\n };\n const response = await fetch(\n url,\n {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify(payload),\n },\n );\n if (!response.ok) {\n await this.handleError(response);\n }\n return response.json();\n }\n}\n","/** Resource for post-factum operations on existing traces. */\n\nimport { initializeLogger, isStringUUID, otelTraceIdToUUID } from \"../utils\";\nimport { BaseResource } from \"./index\";\n\nconst logger = initializeLogger();\n\nexport class TracesResource extends BaseResource {\n /** Resource for post-factum operations on existing traces. */\n constructor(baseHttpUrl: string, projectApiKey: string) {\n super(baseHttpUrl, projectApiKey);\n }\n\n /**\n * Push a metadata patch to an existing trace.\n *\n * The patch is shallow-merged server-side into the trace's existing metadata\n * (`existing || patch`, last-write-wins per top-level key). Useful for\n * attaching post-factum signals — quality scores, human edits, triage labels —\n * to a trace that has already finished. The patch does NOT extend `endTime`\n * or change tokens / cost / top span / tags / span names. `numSpans` is\n * incremented by 1 (paid by the virtual span that carried the patch through\n * the ingestion queue) so the new ClickHouse row beats the prior version on\n * `ReplacingMergeTree(numSpans)`. No row is added to the `spans` table.\n *\n * Compared to `Laminar.setTraceMetadata` (which sets metadata on the\n * currently in-flight trace via OpenTelemetry attributes), this method\n * operates on a finished trace by trace id, so it must be called after the\n * trace has been flushed.\n *\n * A 404 response (the trace was not found in the project — typically because\n * it has not been flushed yet) is logged as a warning and the call returns\n * without throwing, since the 404 may be expected when pushing too soon\n * after the trace run. Pass `failOnNotFound: true` to throw instead (e.g.\n * CLI callers that must report the failure). Any other non-OK status throws.\n *\n * @param traceId - The trace id to push metadata to. Accepts a UUID string\n * or a 32-char OTel hex trace id.\n * @param metadata - The metadata patch. Top-level keys are merged into the\n * trace's existing metadata. Must be non-empty (the server rejects empty\n * patches with 400).\n * @param options - `failOnNotFound`: throw on 404 instead of warn-and-return.\n * @example\n * ```typescript\n * import { Laminar, observe, LaminarClient } from \"@lmnr-ai/lmnr\";\n * Laminar.initialize();\n * const client = new LaminarClient();\n *\n * let traceId: string | null = null;\n * await observe({ name: \"generate\" }, async () => {\n * traceId = await Laminar.getTraceId();\n * });\n * await Laminar.flush();\n *\n * if (traceId) {\n * await client.traces.pushMetadata(traceId, {\n * score: 0.85,\n * reviewer: \"alice\",\n * needsReview: false,\n * });\n * }\n * ```\n */\n public async pushMetadata(\n traceId: string,\n metadata: Record<string, unknown>,\n options?: { failOnNotFound?: boolean },\n ): Promise<void> {\n if (!metadata || Object.keys(metadata).length === 0) {\n throw new Error(\"metadata must be a non-empty object\");\n }\n\n const formattedTraceId = isStringUUID(traceId)\n ? traceId\n : otelTraceIdToUUID(traceId);\n\n const url = this.baseHttpUrl + \"/v1/traces/metadata\";\n const response = await fetch(url, {\n method: \"POST\",\n headers: this.headers(),\n body: JSON.stringify({\n traceId: formattedTraceId,\n metadata,\n }),\n });\n\n if (response.status === 404) {\n const message =\n `Trace ${formattedTraceId} not found. The trace may not have been ` +\n \"flushed yet — call await Laminar.flush() and retry.\";\n if (options?.failOnNotFound) {\n throw new Error(message);\n }\n // Trace not found in this project — likely not flushed yet. Don't throw,\n // but surface a warning so callers debugging an empty patch see it.\n logger.warn(message);\n return;\n }\n\n if (!response.ok) {\n await this.handleError(response);\n }\n }\n}\n","import { BrowserEventsResource } from \"./resources/browser-events\";\nimport { DatasetsResource } from \"./resources/datasets\";\nimport { EvalsResource } from \"./resources/evals\";\nimport { EvaluatorsResource } from \"./resources/evaluators\";\nimport { RolloutSessionsResource } from \"./resources/rollout-sessions\";\nimport { SqlResource } from \"./resources/sql\";\nimport { TagsResource } from \"./resources/tags\";\nimport { TracesResource } from \"./resources/traces\";\nimport { loadEnv } from \"./utils\";\n\nexport class LaminarClient {\n private baseUrl: string;\n private projectApiKey: string;\n private _browserEvents: BrowserEventsResource;\n private _datasets: DatasetsResource;\n private _evals: EvalsResource;\n private _evaluators: EvaluatorsResource;\n private _rolloutSessions: RolloutSessionsResource;\n private _sql: SqlResource;\n private _tags: TagsResource;\n private _traces: TracesResource;\n\n constructor({\n baseUrl,\n projectApiKey,\n port,\n }: {\n baseUrl?: string,\n projectApiKey?: string,\n port?: number,\n } = {}) {\n loadEnv();\n this.projectApiKey = projectApiKey ?? process.env.LMNR_PROJECT_API_KEY!;\n const httpPort = port ?? (\n baseUrl?.match(/:\\d{1,5}$/g)\n ? parseInt(baseUrl.match(/:\\d{1,5}$/g)![0].slice(1))\n : 443);\n const baseUrlNoPort = (baseUrl ?? process.env.LMNR_BASE_URL)\n ?.replace(/\\/$/, '').replace(/:\\d{1,5}$/g, '');\n this.baseUrl = `${baseUrlNoPort ?? 'https://api.lmnr.ai'}:${httpPort}`;\n this._browserEvents = new BrowserEventsResource(this.baseUrl, this.projectApiKey);\n this._datasets = new DatasetsResource(this.baseUrl, this.projectApiKey);\n this._evals = new EvalsResource(this.baseUrl, this.projectApiKey);\n this._evaluators = new EvaluatorsResource(this.baseUrl, this.projectApiKey);\n this._rolloutSessions = new RolloutSessionsResource(this.baseUrl, this.projectApiKey);\n this._sql = new SqlResource(this.baseUrl, this.projectApiKey);\n this._tags = new TagsResource(this.baseUrl, this.projectApiKey);\n this._traces = new TracesResource(this.baseUrl, this.projectApiKey);\n }\n\n public get browserEvents() {\n return this._browserEvents;\n }\n\n public get datasets() {\n return this._datasets;\n }\n\n public get evals() {\n return this._evals;\n }\n\n public get evaluators() {\n return this._evaluators;\n }\n\n public get rolloutSessions() {\n return this._rolloutSessions;\n }\n\n public get sql() {\n return this._sql;\n }\n\n public get tags() {\n return this._tags;\n }\n\n public get traces() {\n return this._traces;\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lmnr-ai/client",
3
- "version": "0.8.26",
3
+ "version": "0.8.27",
4
4
  "description": "HTTP client for Laminar AI API",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",
@@ -39,7 +39,7 @@
39
39
  "devDependencies": {
40
40
  "nock": "^14.0.8",
41
41
  "tsx": "^4.20.3",
42
- "@lmnr-ai/types": "0.8.26"
42
+ "@lmnr-ai/types": "0.8.27"
43
43
  },
44
44
  "scripts": {
45
45
  "build": "tsdown",