@mastra/duckdb 1.0.1 → 1.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/LICENSE.md +15 -0
  3. package/dist/chunk-37GBWD4M.js +195 -0
  4. package/dist/chunk-37GBWD4M.js.map +1 -0
  5. package/dist/chunk-S2AWBPTS.cjs +198 -0
  6. package/dist/chunk-S2AWBPTS.cjs.map +1 -0
  7. package/dist/docs/SKILL.md +2 -2
  8. package/dist/docs/assets/SOURCE_MAP.json +8 -2
  9. package/dist/docs/references/reference-vectors-duckdb.md +46 -46
  10. package/dist/index.cjs +241 -4
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.ts +5 -2
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +238 -6
  15. package/dist/index.js.map +1 -1
  16. package/dist/observability-PW6J27KS.js +1675 -0
  17. package/dist/observability-PW6J27KS.js.map +1 -0
  18. package/dist/observability-W2QRBK56.cjs +1677 -0
  19. package/dist/observability-W2QRBK56.cjs.map +1 -0
  20. package/dist/storage/db/index.d.ts +46 -0
  21. package/dist/storage/db/index.d.ts.map +1 -0
  22. package/dist/storage/domains/observability/ddl.d.ts +25 -0
  23. package/dist/storage/domains/observability/ddl.d.ts.map +1 -0
  24. package/dist/storage/domains/observability/discovery.d.ts +13 -0
  25. package/dist/storage/domains/observability/discovery.d.ts.map +1 -0
  26. package/dist/storage/domains/observability/feedback.d.ts +9 -0
  27. package/dist/storage/domains/observability/feedback.d.ts.map +1 -0
  28. package/dist/storage/domains/observability/filters.d.ts +27 -0
  29. package/dist/storage/domains/observability/filters.d.ts.map +1 -0
  30. package/dist/storage/domains/observability/helpers.d.ts +14 -0
  31. package/dist/storage/domains/observability/helpers.d.ts.map +1 -0
  32. package/dist/storage/domains/observability/index.d.ts +54 -0
  33. package/dist/storage/domains/observability/index.d.ts.map +1 -0
  34. package/dist/storage/domains/observability/logs.d.ts +7 -0
  35. package/dist/storage/domains/observability/logs.d.ts.map +1 -0
  36. package/dist/storage/domains/observability/metrics.d.ts +21 -0
  37. package/dist/storage/domains/observability/metrics.d.ts.map +1 -0
  38. package/dist/storage/domains/observability/scores.d.ts +9 -0
  39. package/dist/storage/domains/observability/scores.d.ts.map +1 -0
  40. package/dist/storage/domains/observability/tracing.d.ts +17 -0
  41. package/dist/storage/domains/observability/tracing.d.ts.map +1 -0
  42. package/dist/storage/index.d.ts +101 -0
  43. package/dist/storage/index.d.ts.map +1 -0
  44. package/dist/vector/filter-builder.d.ts +1 -0
  45. package/dist/vector/filter-builder.d.ts.map +1 -1
  46. package/dist/vector/index.d.ts +9 -0
  47. package/dist/vector/index.d.ts.map +1 -1
  48. package/package.json +7 -7
@@ -0,0 +1,1675 @@
1
+ import { DuckDBConnection } from './chunk-37GBWD4M.js';
2
+ import { ObservabilityStorage, toTraceSpans } from '@mastra/core/storage';
3
+ import { EntityType } from '@mastra/core/observability';
4
+ import { parseFieldKey } from '@mastra/core/utils';
5
+
6
+ // src/storage/domains/observability/ddl.ts
7
+ var SPAN_EVENTS_DDL = `
8
+ CREATE TABLE IF NOT EXISTS span_events (
9
+ -- Event metadata
10
+ eventType VARCHAR NOT NULL,
11
+ timestamp TIMESTAMP NOT NULL,
12
+
13
+ -- IDs
14
+ traceId VARCHAR NOT NULL,
15
+ spanId VARCHAR NOT NULL,
16
+ parentSpanId VARCHAR,
17
+ experimentId VARCHAR,
18
+
19
+ -- Entity
20
+ entityType VARCHAR,
21
+ entityId VARCHAR,
22
+ entityName VARCHAR,
23
+
24
+ -- Context
25
+ userId VARCHAR,
26
+ organizationId VARCHAR,
27
+ resourceId VARCHAR,
28
+ runId VARCHAR,
29
+ sessionId VARCHAR,
30
+ threadId VARCHAR,
31
+ requestId VARCHAR,
32
+ environment VARCHAR,
33
+ source VARCHAR,
34
+ serviceName VARCHAR,
35
+ requestContext JSON,
36
+
37
+ -- Span-specific scalars
38
+ name VARCHAR,
39
+ spanType VARCHAR,
40
+ isEvent BOOLEAN,
41
+ endedAt TIMESTAMP,
42
+
43
+ -- JSON fields
44
+ attributes JSON,
45
+ metadata JSON,
46
+ tags JSON,
47
+ scope JSON,
48
+ links JSON,
49
+ input JSON,
50
+ output JSON,
51
+ error JSON
52
+ )`;
53
+ var METRIC_EVENTS_DDL = `
54
+ CREATE TABLE IF NOT EXISTS metric_events (
55
+ -- Event metadata
56
+ timestamp TIMESTAMP NOT NULL,
57
+
58
+ -- IDs
59
+ traceId VARCHAR,
60
+ spanId VARCHAR,
61
+ experimentId VARCHAR,
62
+
63
+ -- Entity hierarchy
64
+ entityType VARCHAR,
65
+ entityId VARCHAR,
66
+ entityName VARCHAR,
67
+ parentEntityType VARCHAR,
68
+ parentEntityId VARCHAR,
69
+ parentEntityName VARCHAR,
70
+ rootEntityType VARCHAR,
71
+ rootEntityId VARCHAR,
72
+ rootEntityName VARCHAR,
73
+
74
+ -- Context
75
+ userId VARCHAR,
76
+ organizationId VARCHAR,
77
+ resourceId VARCHAR,
78
+ runId VARCHAR,
79
+ sessionId VARCHAR,
80
+ threadId VARCHAR,
81
+ requestId VARCHAR,
82
+ environment VARCHAR,
83
+ source VARCHAR,
84
+ serviceName VARCHAR,
85
+
86
+ -- Metric-specific scalars
87
+ name VARCHAR NOT NULL,
88
+ value DOUBLE NOT NULL,
89
+ provider VARCHAR,
90
+ model VARCHAR,
91
+ estimatedCost DOUBLE,
92
+ costUnit VARCHAR,
93
+
94
+ -- JSON fields
95
+ tags JSON,
96
+ labels JSON,
97
+ costMetadata JSON,
98
+ metadata JSON,
99
+ scope JSON
100
+ )`;
101
+ var LOG_EVENTS_DDL = `
102
+ CREATE TABLE IF NOT EXISTS log_events (
103
+ -- Event metadata
104
+ timestamp TIMESTAMP NOT NULL,
105
+
106
+ -- IDs
107
+ traceId VARCHAR,
108
+ spanId VARCHAR,
109
+ experimentId VARCHAR,
110
+
111
+ -- Entity hierarchy
112
+ entityType VARCHAR,
113
+ entityId VARCHAR,
114
+ entityName VARCHAR,
115
+ parentEntityType VARCHAR,
116
+ parentEntityId VARCHAR,
117
+ parentEntityName VARCHAR,
118
+ rootEntityType VARCHAR,
119
+ rootEntityId VARCHAR,
120
+ rootEntityName VARCHAR,
121
+
122
+ -- Context
123
+ userId VARCHAR,
124
+ organizationId VARCHAR,
125
+ resourceId VARCHAR,
126
+ runId VARCHAR,
127
+ sessionId VARCHAR,
128
+ threadId VARCHAR,
129
+ requestId VARCHAR,
130
+ environment VARCHAR,
131
+ source VARCHAR,
132
+ serviceName VARCHAR,
133
+
134
+ -- Log-specific scalars
135
+ level VARCHAR NOT NULL,
136
+ message VARCHAR NOT NULL,
137
+
138
+ -- JSON fields
139
+ data JSON,
140
+ tags JSON,
141
+ metadata JSON,
142
+ scope JSON
143
+ )`;
144
+ var SCORE_EVENTS_DDL = `
145
+ CREATE TABLE IF NOT EXISTS score_events (
146
+ -- Event metadata
147
+ timestamp TIMESTAMP NOT NULL,
148
+
149
+ -- IDs
150
+ traceId VARCHAR NOT NULL,
151
+ spanId VARCHAR,
152
+ experimentId VARCHAR,
153
+ scoreTraceId VARCHAR,
154
+
155
+ -- Score-specific scalars
156
+ scorerId VARCHAR NOT NULL,
157
+ scorerVersion VARCHAR,
158
+ source VARCHAR,
159
+ score DOUBLE NOT NULL,
160
+ reason VARCHAR,
161
+
162
+ -- JSON fields
163
+ metadata JSON
164
+ )`;
165
+ var FEEDBACK_EVENTS_DDL = `
166
+ CREATE TABLE IF NOT EXISTS feedback_events (
167
+ -- Event metadata
168
+ timestamp TIMESTAMP NOT NULL,
169
+
170
+ -- IDs
171
+ traceId VARCHAR NOT NULL,
172
+ spanId VARCHAR,
173
+ experimentId VARCHAR,
174
+ userId VARCHAR,
175
+ sourceId VARCHAR,
176
+
177
+ -- Feedback-specific scalars
178
+ source VARCHAR NOT NULL,
179
+ feedbackType VARCHAR NOT NULL,
180
+ value VARCHAR NOT NULL,
181
+ comment VARCHAR,
182
+
183
+ -- JSON fields
184
+ metadata JSON
185
+ )`;
186
+ var ALL_DDL = [SPAN_EVENTS_DDL, METRIC_EVENTS_DDL, LOG_EVENTS_DDL, SCORE_EVENTS_DDL, FEEDBACK_EVENTS_DDL];
187
+ function unionDistinctQueries(selects, orderBy) {
188
+ return `${selects.join("\nUNION\n")}
189
+ ORDER BY ${orderBy}`;
190
+ }
191
+ async function getEntityTypes(db, _args) {
192
+ const rows = await db.query(
193
+ unionDistinctQueries(
194
+ [
195
+ `SELECT entityType FROM span_events WHERE entityType IS NOT NULL`,
196
+ `SELECT entityType FROM metric_events WHERE entityType IS NOT NULL`,
197
+ `SELECT entityType FROM log_events WHERE entityType IS NOT NULL`
198
+ ],
199
+ "entityType"
200
+ )
201
+ );
202
+ const validTypes = new Set(Object.values(EntityType));
203
+ const typeSet = /* @__PURE__ */ new Set();
204
+ for (const row of rows) {
205
+ if (row.entityType && validTypes.has(row.entityType)) {
206
+ typeSet.add(row.entityType);
207
+ }
208
+ }
209
+ return { entityTypes: Array.from(typeSet).sort() };
210
+ }
211
+ async function getEntityNames(db, args) {
212
+ const buildSelect = (table) => {
213
+ const conditions = [`entityName IS NOT NULL`];
214
+ if (args.entityType) {
215
+ conditions.push(`entityType = ?`);
216
+ }
217
+ return `SELECT entityName FROM ${table} WHERE ${conditions.join(" AND ")}`;
218
+ };
219
+ const params = args.entityType ? [args.entityType, args.entityType, args.entityType] : [];
220
+ const rows = await db.query(
221
+ unionDistinctQueries(
222
+ [buildSelect("span_events"), buildSelect("metric_events"), buildSelect("log_events")],
223
+ "entityName"
224
+ ),
225
+ params
226
+ );
227
+ return { names: rows.map((r) => r.entityName) };
228
+ }
229
+ async function getServiceNames(db, _args) {
230
+ const rows = await db.query(
231
+ unionDistinctQueries(
232
+ [
233
+ `SELECT serviceName FROM span_events WHERE serviceName IS NOT NULL`,
234
+ `SELECT serviceName FROM metric_events WHERE serviceName IS NOT NULL`,
235
+ `SELECT serviceName FROM log_events WHERE serviceName IS NOT NULL`
236
+ ],
237
+ "serviceName"
238
+ )
239
+ );
240
+ return { serviceNames: rows.map((r) => r.serviceName) };
241
+ }
242
+ async function getEnvironments(db, _args) {
243
+ const rows = await db.query(
244
+ unionDistinctQueries(
245
+ [
246
+ `SELECT environment FROM span_events WHERE environment IS NOT NULL`,
247
+ `SELECT environment FROM metric_events WHERE environment IS NOT NULL`,
248
+ `SELECT environment FROM log_events WHERE environment IS NOT NULL`
249
+ ],
250
+ "environment"
251
+ )
252
+ );
253
+ return { environments: rows.map((r) => r.environment) };
254
+ }
255
+ async function getTags(db, args) {
256
+ const buildSelect = (table) => {
257
+ const conditions = [`tags IS NOT NULL`];
258
+ if (args.entityType) {
259
+ conditions.push(`entityType = ?`);
260
+ }
261
+ return `SELECT unnest(CAST(tags AS VARCHAR[])) AS tag FROM ${table} WHERE ${conditions.join(" AND ")}`;
262
+ };
263
+ const params = args.entityType ? [args.entityType, args.entityType, args.entityType] : [];
264
+ const rows = await db.query(
265
+ unionDistinctQueries([buildSelect("span_events"), buildSelect("metric_events"), buildSelect("log_events")], "tag"),
266
+ params
267
+ );
268
+ return { tags: rows.map((r) => r.tag) };
269
+ }
270
+ function buildJsonPath(key) {
271
+ try {
272
+ return `$.${parseFieldKey(key)}`;
273
+ } catch {
274
+ const escaped = key.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
275
+ return `$."${escaped}"`;
276
+ }
277
+ }
278
+ function normalizeJsonFilterValue(value) {
279
+ if (value === void 0) return null;
280
+ if (typeof value === "string") return value;
281
+ const json = JSON.stringify(value);
282
+ return json ?? null;
283
+ }
284
+ function sanitizeColumn(column) {
285
+ return parseFieldKey(column);
286
+ }
287
+ function buildWhereClause(filters, fieldMappings) {
288
+ if (!filters) return { clause: "", params: [] };
289
+ const conditions = [];
290
+ const params = [];
291
+ for (const [key, value] of Object.entries(filters)) {
292
+ if (value === void 0 || value === null) continue;
293
+ const column = sanitizeColumn(key);
294
+ if (key === "timestamp" || key === "startedAt" || key === "endedAt") {
295
+ const dateRange = value;
296
+ if (dateRange.start) {
297
+ const op = dateRange.startExclusive ? ">" : ">=";
298
+ conditions.push(`${column} ${op} ?`);
299
+ params.push(dateRange.start);
300
+ }
301
+ if (dateRange.end) {
302
+ const op = dateRange.endExclusive ? "<" : "<=";
303
+ conditions.push(`${column} ${op} ?`);
304
+ params.push(dateRange.end);
305
+ }
306
+ continue;
307
+ }
308
+ if (key === "labels") {
309
+ const labelsObj = value;
310
+ for (const [labelKey, labelValue] of Object.entries(labelsObj)) {
311
+ conditions.push(`json_extract_string(${column}, ?) = ?`);
312
+ params.push(buildJsonPath(labelKey), labelValue);
313
+ }
314
+ continue;
315
+ }
316
+ if (key === "tags") {
317
+ const tags = value;
318
+ for (const tag of tags) {
319
+ conditions.push(`list_contains(CAST(${column} AS VARCHAR[]), ?)`);
320
+ params.push(tag);
321
+ }
322
+ continue;
323
+ }
324
+ if (key === "status") {
325
+ const status = value;
326
+ if (status === "error") {
327
+ conditions.push(`error IS NOT NULL`);
328
+ } else if (status === "running") {
329
+ conditions.push(`endedAt IS NULL AND error IS NULL`);
330
+ } else if (status === "success") {
331
+ conditions.push(`endedAt IS NOT NULL AND error IS NULL`);
332
+ }
333
+ continue;
334
+ }
335
+ if (key === "hasChildError") {
336
+ continue;
337
+ }
338
+ if (key === "metadata" || key === "scope") {
339
+ const jsonObj = value;
340
+ for (const [jsonKey, jsonValue] of Object.entries(jsonObj)) {
341
+ const normalized = normalizeJsonFilterValue(jsonValue);
342
+ if (normalized === null) continue;
343
+ conditions.push(`json_extract_string(${column}, ?) = ?`);
344
+ params.push(buildJsonPath(jsonKey), normalized);
345
+ }
346
+ continue;
347
+ }
348
+ if (Array.isArray(value)) {
349
+ if (value.length === 0) continue;
350
+ const placeholders = value.map(() => "?").join(", ");
351
+ conditions.push(`${column} IN (${placeholders})`);
352
+ params.push(...value);
353
+ continue;
354
+ }
355
+ conditions.push(`${column} = ?`);
356
+ params.push(value);
357
+ }
358
+ const clause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
359
+ return { clause, params };
360
+ }
361
+ function buildOrderByClause(orderBy) {
362
+ if (!orderBy) return "";
363
+ const dir = orderBy.direction.toUpperCase();
364
+ if (dir !== "ASC" && dir !== "DESC") {
365
+ throw new Error(`Invalid sort direction: ${orderBy.direction}`);
366
+ }
367
+ const field = parseFieldKey(orderBy.field);
368
+ return `ORDER BY ${field} ${dir}`;
369
+ }
370
+ function buildPaginationClause(pagination) {
371
+ if (!pagination) return { clause: "", params: [] };
372
+ if (!Number.isInteger(pagination.page) || pagination.page < 0) {
373
+ throw new Error(`Invalid page: ${pagination.page}`);
374
+ }
375
+ if (!Number.isInteger(pagination.perPage) || pagination.perPage <= 0) {
376
+ throw new Error(`Invalid perPage: ${pagination.perPage}`);
377
+ }
378
+ const offset = pagination.page * pagination.perPage;
379
+ return {
380
+ clause: `LIMIT ? OFFSET ?`,
381
+ params: [pagination.perPage, offset]
382
+ };
383
+ }
384
+
385
+ // src/storage/domains/observability/helpers.ts
386
+ var v = DuckDBConnection.sqlValue;
387
+ function jsonV(val) {
388
+ if (val === null || val === void 0) return "NULL";
389
+ return DuckDBConnection.sqlValue(JSON.stringify(val));
390
+ }
391
+ function toDate(val) {
392
+ if (val === null || val === void 0) {
393
+ throw new Error("Expected date value but received null/undefined");
394
+ }
395
+ const date = val instanceof Date ? val : new Date(String(val));
396
+ if (Number.isNaN(date.getTime())) {
397
+ throw new Error("Expected valid date but received invalid date");
398
+ }
399
+ return date;
400
+ }
401
+ function toDateOrNull(val) {
402
+ if (val === null || val === void 0) return null;
403
+ return val instanceof Date ? val : new Date(String(val));
404
+ }
405
+ function parseJson(value) {
406
+ if (value === null || value === void 0) return null;
407
+ if (typeof value === "string") {
408
+ try {
409
+ return JSON.parse(value);
410
+ } catch {
411
+ return value;
412
+ }
413
+ }
414
+ return value;
415
+ }
416
+ function parseJsonArray(value) {
417
+ if (value === null || value === void 0) return null;
418
+ const parsed = parseJson(value);
419
+ return Array.isArray(parsed) ? parsed : null;
420
+ }
421
+
422
+ // src/storage/domains/observability/feedback.ts
423
+ async function createFeedback(db, args) {
424
+ const f = args.feedback;
425
+ await db.execute(
426
+ `INSERT INTO feedback_events (timestamp, traceId, spanId, experimentId, userId, sourceId, source, feedbackType, value, comment, metadata)
427
+ VALUES (${[
428
+ v(f.timestamp),
429
+ v(f.traceId),
430
+ v(f.spanId ?? null),
431
+ v(f.experimentId ?? null),
432
+ v(f.userId ?? null),
433
+ v(f.sourceId ?? null),
434
+ v(f.source),
435
+ v(f.feedbackType),
436
+ v(String(f.value)),
437
+ v(f.comment ?? null),
438
+ jsonV(f.metadata)
439
+ ].join(", ")})`
440
+ );
441
+ }
442
+ async function batchCreateFeedback(db, args) {
443
+ if (args.feedbacks.length === 0) return;
444
+ const tuples = args.feedbacks.map(
445
+ (f) => `(${[
446
+ v(f.timestamp),
447
+ v(f.traceId),
448
+ v(f.spanId ?? null),
449
+ v(f.experimentId ?? null),
450
+ v(f.userId ?? null),
451
+ v(f.sourceId ?? null),
452
+ v(f.source),
453
+ v(f.feedbackType),
454
+ v(String(f.value)),
455
+ v(f.comment ?? null),
456
+ jsonV(f.metadata)
457
+ ].join(", ")})`
458
+ );
459
+ await db.execute(
460
+ `INSERT INTO feedback_events (timestamp, traceId, spanId, experimentId, userId, sourceId, source, feedbackType, value, comment, metadata)
461
+ VALUES ${tuples.join(",\n ")}`
462
+ );
463
+ }
464
+ async function listFeedback(db, args) {
465
+ const filters = args.filters ?? {};
466
+ const page = Number(args.pagination?.page ?? 0);
467
+ const perPage = Number(args.pagination?.perPage ?? 10);
468
+ const orderBy = { field: args.orderBy?.field ?? "timestamp", direction: args.orderBy?.direction ?? "DESC" };
469
+ const { clause: filterClause, params: filterParams } = buildWhereClause(filters);
470
+ const orderByClause = buildOrderByClause(orderBy);
471
+ const { clause: paginationClause, params: paginationParams } = buildPaginationClause({ page, perPage });
472
+ const countResult = await db.query(
473
+ `SELECT COUNT(*) as total FROM feedback_events ${filterClause}`,
474
+ filterParams
475
+ );
476
+ const total = Number(countResult[0]?.total ?? 0);
477
+ const rows = await db.query(`SELECT * FROM feedback_events ${filterClause} ${orderByClause} ${paginationClause}`, [
478
+ ...filterParams,
479
+ ...paginationParams
480
+ ]);
481
+ const feedback = rows.map((row) => {
482
+ const r = row;
483
+ const rawValue = r.value;
484
+ let value = rawValue;
485
+ const numValue = Number(rawValue);
486
+ if (!isNaN(numValue)) value = numValue;
487
+ return {
488
+ timestamp: toDate(r.timestamp),
489
+ traceId: r.traceId,
490
+ spanId: r.spanId ?? null,
491
+ experimentId: r.experimentId ?? null,
492
+ userId: r.userId ?? null,
493
+ sourceId: r.sourceId ?? null,
494
+ source: r.source,
495
+ feedbackType: r.feedbackType,
496
+ value,
497
+ comment: r.comment ?? null,
498
+ metadata: parseJson(r.metadata)
499
+ };
500
+ });
501
+ return {
502
+ pagination: { total, page, perPage, hasMore: (page + 1) * perPage < total },
503
+ feedback
504
+ };
505
+ }
506
+
507
+ // src/storage/domains/observability/logs.ts
508
+ var COLUMNS = [
509
+ "timestamp",
510
+ "level",
511
+ "message",
512
+ "data",
513
+ "traceId",
514
+ "spanId",
515
+ "entityType",
516
+ "entityId",
517
+ "entityName",
518
+ "parentEntityType",
519
+ "parentEntityId",
520
+ "parentEntityName",
521
+ "rootEntityType",
522
+ "rootEntityId",
523
+ "rootEntityName",
524
+ "userId",
525
+ "organizationId",
526
+ "resourceId",
527
+ "runId",
528
+ "sessionId",
529
+ "threadId",
530
+ "requestId",
531
+ "environment",
532
+ "source",
533
+ "serviceName",
534
+ "experimentId",
535
+ "tags",
536
+ "metadata",
537
+ "scope"
538
+ ];
539
+ var COLUMNS_SQL = COLUMNS.join(", ");
540
+ function rowToLogRecord(row) {
541
+ return {
542
+ timestamp: toDate(row.timestamp),
543
+ level: row.level,
544
+ message: row.message,
545
+ data: parseJson(row.data),
546
+ traceId: row.traceId ?? null,
547
+ spanId: row.spanId ?? null,
548
+ entityType: row.entityType ?? null,
549
+ entityId: row.entityId ?? null,
550
+ entityName: row.entityName ?? null,
551
+ parentEntityType: row.parentEntityType ?? null,
552
+ parentEntityId: row.parentEntityId ?? null,
553
+ parentEntityName: row.parentEntityName ?? null,
554
+ rootEntityType: row.rootEntityType ?? null,
555
+ rootEntityId: row.rootEntityId ?? null,
556
+ rootEntityName: row.rootEntityName ?? null,
557
+ userId: row.userId ?? null,
558
+ organizationId: row.organizationId ?? null,
559
+ resourceId: row.resourceId ?? null,
560
+ runId: row.runId ?? null,
561
+ sessionId: row.sessionId ?? null,
562
+ threadId: row.threadId ?? null,
563
+ requestId: row.requestId ?? null,
564
+ environment: row.environment ?? null,
565
+ source: row.source ?? null,
566
+ serviceName: row.serviceName ?? null,
567
+ experimentId: row.experimentId ?? null,
568
+ tags: parseJsonArray(row.tags),
569
+ metadata: parseJson(row.metadata),
570
+ scope: parseJson(row.scope)
571
+ };
572
+ }
573
+ async function batchCreateLogs(db, args) {
574
+ if (args.logs.length === 0) return;
575
+ const tuples = args.logs.map((log) => {
576
+ return `(${[
577
+ v(log.timestamp),
578
+ v(log.level),
579
+ v(log.message),
580
+ jsonV(log.data),
581
+ v(log.traceId ?? null),
582
+ v(log.spanId ?? null),
583
+ v(log.entityType ?? null),
584
+ v(log.entityId ?? null),
585
+ v(log.entityName ?? null),
586
+ v(log.parentEntityType ?? null),
587
+ v(log.parentEntityId ?? null),
588
+ v(log.parentEntityName ?? null),
589
+ v(log.rootEntityType ?? null),
590
+ v(log.rootEntityId ?? null),
591
+ v(log.rootEntityName ?? null),
592
+ v(log.userId ?? null),
593
+ v(log.organizationId ?? null),
594
+ v(log.resourceId ?? null),
595
+ v(log.runId ?? null),
596
+ v(log.sessionId ?? null),
597
+ v(log.threadId ?? null),
598
+ v(log.requestId ?? null),
599
+ v(log.environment ?? null),
600
+ v(log.source ?? null),
601
+ v(log.serviceName ?? null),
602
+ v(log.experimentId ?? null),
603
+ jsonV(log.tags),
604
+ jsonV(log.metadata),
605
+ jsonV(log.scope)
606
+ ].join(", ")})`;
607
+ });
608
+ await db.execute(`INSERT INTO log_events (${COLUMNS_SQL}) VALUES ${tuples.join(",\n")}`);
609
+ }
610
+ async function listLogs(db, args) {
611
+ const filters = args.filters ?? {};
612
+ const page = Number(args.pagination?.page ?? 0);
613
+ const perPage = Number(args.pagination?.perPage ?? 10);
614
+ const orderBy = { field: args.orderBy?.field ?? "timestamp", direction: args.orderBy?.direction ?? "DESC" };
615
+ const { clause: filterClause, params: filterParams } = buildWhereClause(filters);
616
+ const orderByClause = buildOrderByClause(orderBy);
617
+ const { clause: paginationClause, params: paginationParams } = buildPaginationClause({ page, perPage });
618
+ const countResult = await db.query(
619
+ `SELECT COUNT(*) as total FROM log_events ${filterClause}`,
620
+ filterParams
621
+ );
622
+ const total = Number(countResult[0]?.total ?? 0);
623
+ const rows = await db.query(`SELECT * FROM log_events ${filterClause} ${orderByClause} ${paginationClause}`, [
624
+ ...filterParams,
625
+ ...paginationParams
626
+ ]);
627
+ const logs = rows.map((row) => rowToLogRecord(row));
628
+ return {
629
+ pagination: { total, page, perPage, hasMore: (page + 1) * perPage < total },
630
+ logs
631
+ };
632
+ }
633
+ function getAggregationSql(aggregation, measure = "value") {
634
+ switch (aggregation) {
635
+ case "sum":
636
+ return `SUM(${measure})`;
637
+ case "avg":
638
+ return `AVG(${measure})`;
639
+ case "min":
640
+ return `MIN(${measure})`;
641
+ case "max":
642
+ return `MAX(${measure})`;
643
+ case "count":
644
+ return `CAST(COUNT(${measure}) AS DOUBLE)`;
645
+ case "last":
646
+ return `arg_max(${measure}, timestamp)`;
647
+ default:
648
+ return `SUM(${measure})`;
649
+ }
650
+ }
651
+ function getIntervalSql(interval) {
652
+ switch (interval) {
653
+ case "1m":
654
+ return "1 minute";
655
+ case "5m":
656
+ return "5 minutes";
657
+ case "15m":
658
+ return "15 minutes";
659
+ case "1h":
660
+ return "1 hour";
661
+ case "1d":
662
+ return "1 day";
663
+ default:
664
+ return "1 hour";
665
+ }
666
+ }
667
+ function buildMetricNameFilter(name) {
668
+ if (Array.isArray(name)) {
669
+ const placeholders = name.map(() => "?").join(", ");
670
+ return { clause: `name IN (${placeholders})`, params: name };
671
+ }
672
+ return { clause: `name = ?`, params: [name] };
673
+ }
674
+ var METRIC_COLUMNS = [
675
+ "timestamp",
676
+ "name",
677
+ "value",
678
+ "traceId",
679
+ "spanId",
680
+ "entityType",
681
+ "entityId",
682
+ "entityName",
683
+ "parentEntityType",
684
+ "parentEntityId",
685
+ "parentEntityName",
686
+ "rootEntityType",
687
+ "rootEntityId",
688
+ "rootEntityName",
689
+ "userId",
690
+ "organizationId",
691
+ "resourceId",
692
+ "runId",
693
+ "sessionId",
694
+ "threadId",
695
+ "requestId",
696
+ "environment",
697
+ "source",
698
+ "serviceName",
699
+ "experimentId",
700
+ "provider",
701
+ "model",
702
+ "estimatedCost",
703
+ "costUnit",
704
+ "tags",
705
+ "labels",
706
+ "costMetadata",
707
+ "metadata",
708
+ "scope"
709
+ ];
710
+ var METRIC_COLUMNS_SQL = METRIC_COLUMNS.join(", ");
711
+ var METRIC_COLUMN_SET = new Set(METRIC_COLUMNS);
712
+ var METRIC_LABEL_ONLY_GROUP_BY_EXCLUDED = /* @__PURE__ */ new Set(["metadata", "scope", "costMetadata", "tags"]);
713
+ function buildGroupByAlias(index) {
714
+ return `group_by_${index}`;
715
+ }
716
+ function toSeriesDisplayValue(value) {
717
+ return value === null || value === void 0 ? "" : String(value);
718
+ }
719
+ function getCostSummarySelect(prefix = "") {
720
+ const ref = (column) => `${prefix}${column}`;
721
+ return [
722
+ `SUM(${ref("estimatedCost")}) FILTER (WHERE ${ref("estimatedCost")} IS NOT NULL) AS estimatedCost`,
723
+ `,`,
724
+ `CASE`,
725
+ ` WHEN COUNT(DISTINCT ${ref("costUnit")}) FILTER (WHERE ${ref("costUnit")} IS NOT NULL) = 1`,
726
+ ` THEN MIN(${ref("costUnit")}) FILTER (WHERE ${ref("costUnit")} IS NOT NULL)`,
727
+ ` ELSE NULL`,
728
+ `END AS costUnit`
729
+ ].join(" ");
730
+ }
731
+ function normalizeCostSummaryRow(row) {
732
+ return {
733
+ estimatedCost: row.estimatedCost === null || row.estimatedCost === void 0 ? null : Number(row.estimatedCost),
734
+ costUnit: row.costUnit === null || row.costUnit === void 0 ? null : String(row.costUnit)
735
+ };
736
+ }
737
+ function buildCombinedWhereClause(nameClause, nameParams, filterClause, filterParams) {
738
+ const conditions = [nameClause];
739
+ const params = [...nameParams];
740
+ if (filterClause) {
741
+ conditions.push(filterClause.replace("WHERE ", ""));
742
+ params.push(...filterParams);
743
+ }
744
+ return { clause: `WHERE ${conditions.join(" AND ")}`, params };
745
+ }
746
+ function resolveGroupBy(groupBy) {
747
+ return groupBy.map((key, index) => {
748
+ if (METRIC_COLUMN_SET.has(key)) {
749
+ const parsed = parseFieldKey(key);
750
+ if (METRIC_LABEL_ONLY_GROUP_BY_EXCLUDED.has(parsed)) {
751
+ throw new Error(`Invalid groupBy column(s): ${key}`);
752
+ }
753
+ return {
754
+ kind: "column",
755
+ key,
756
+ selectSql: `${parsed} AS "${key}"`,
757
+ groupSql: parsed,
758
+ resultKey: key
759
+ };
760
+ }
761
+ const labelPath = buildJsonPath(key).replace(/'/g, "''");
762
+ const labelExpr = `json_extract_string(labels, '${labelPath}')`;
763
+ const alias = buildGroupByAlias(index);
764
+ return {
765
+ kind: "label",
766
+ key,
767
+ selectSql: `${labelExpr} AS ${alias}`,
768
+ groupSql: alias,
769
+ resultKey: alias
770
+ };
771
+ });
772
+ }
773
+ function rowToMetricRecord(row) {
774
+ return {
775
+ timestamp: toDate(row.timestamp),
776
+ name: row.name,
777
+ value: Number(row.value),
778
+ traceId: row.traceId ?? null,
779
+ spanId: row.spanId ?? null,
780
+ entityType: row.entityType ?? null,
781
+ entityId: row.entityId ?? null,
782
+ entityName: row.entityName ?? null,
783
+ parentEntityType: row.parentEntityType ?? null,
784
+ parentEntityId: row.parentEntityId ?? null,
785
+ parentEntityName: row.parentEntityName ?? null,
786
+ rootEntityType: row.rootEntityType ?? null,
787
+ rootEntityId: row.rootEntityId ?? null,
788
+ rootEntityName: row.rootEntityName ?? null,
789
+ userId: row.userId ?? null,
790
+ organizationId: row.organizationId ?? null,
791
+ resourceId: row.resourceId ?? null,
792
+ runId: row.runId ?? null,
793
+ sessionId: row.sessionId ?? null,
794
+ threadId: row.threadId ?? null,
795
+ requestId: row.requestId ?? null,
796
+ environment: row.environment ?? null,
797
+ source: row.source ?? null,
798
+ serviceName: row.serviceName ?? null,
799
+ experimentId: row.experimentId ?? null,
800
+ provider: row.provider ?? null,
801
+ model: row.model ?? null,
802
+ estimatedCost: row.estimatedCost === null || row.estimatedCost === void 0 ? null : Number(row.estimatedCost),
803
+ costUnit: row.costUnit ?? null,
804
+ costMetadata: parseJson(row.costMetadata),
805
+ tags: parseJsonArray(row.tags),
806
+ labels: parseJson(row.labels) ?? {},
807
+ metadata: parseJson(row.metadata),
808
+ scope: parseJson(row.scope)
809
+ };
810
+ }
811
+ async function batchCreateMetrics(db, args) {
812
+ if (args.metrics.length === 0) return;
813
+ const tuples = args.metrics.map((m) => {
814
+ return `(${[
815
+ v(m.timestamp),
816
+ v(m.name),
817
+ v(m.value),
818
+ v(m.traceId ?? null),
819
+ v(m.spanId ?? null),
820
+ v(m.entityType ?? null),
821
+ v(m.entityId ?? null),
822
+ v(m.entityName ?? null),
823
+ v(m.parentEntityType ?? null),
824
+ v(m.parentEntityId ?? null),
825
+ v(m.parentEntityName ?? null),
826
+ v(m.rootEntityType ?? null),
827
+ v(m.rootEntityId ?? null),
828
+ v(m.rootEntityName ?? null),
829
+ v(m.userId ?? null),
830
+ v(m.organizationId ?? null),
831
+ v(m.resourceId ?? null),
832
+ v(m.runId ?? null),
833
+ v(m.sessionId ?? null),
834
+ v(m.threadId ?? null),
835
+ v(m.requestId ?? null),
836
+ v(m.environment ?? null),
837
+ v(m.source ?? null),
838
+ v(m.serviceName ?? null),
839
+ v(m.experimentId ?? null),
840
+ v(m.provider ?? null),
841
+ v(m.model ?? null),
842
+ v(m.estimatedCost ?? null),
843
+ v(m.costUnit ?? null),
844
+ jsonV(m.tags ?? null),
845
+ v(JSON.stringify(m.labels ?? {})),
846
+ jsonV(m.costMetadata ?? null),
847
+ jsonV(m.metadata ?? null),
848
+ jsonV(m.scope ?? null)
849
+ ].join(", ")})`;
850
+ });
851
+ await db.execute(`INSERT INTO metric_events (${METRIC_COLUMNS_SQL}) VALUES ${tuples.join(",\n")}`);
852
+ }
853
+ async function listMetrics(db, args) {
854
+ const filters = args.filters ?? {};
855
+ const page = Number(args.pagination?.page ?? 0);
856
+ const perPage = Number(args.pagination?.perPage ?? 10);
857
+ const orderBy = { field: args.orderBy?.field ?? "timestamp", direction: args.orderBy?.direction ?? "DESC" };
858
+ const { clause: filterClause, params: filterParams } = buildWhereClause(filters);
859
+ const orderByClause = buildOrderByClause(orderBy);
860
+ const { clause: paginationClause, params: paginationParams } = buildPaginationClause({ page, perPage });
861
+ const countResult = await db.query(
862
+ `SELECT COUNT(*) AS total FROM metric_events ${filterClause}`,
863
+ filterParams
864
+ );
865
+ const total = Number(countResult[0]?.total ?? 0);
866
+ const rows = await db.query(
867
+ `SELECT * FROM metric_events ${filterClause} ${orderByClause} ${paginationClause}`,
868
+ [...filterParams, ...paginationParams]
869
+ );
870
+ return {
871
+ pagination: { total, page, perPage, hasMore: (page + 1) * perPage < total },
872
+ metrics: rows.map((row) => rowToMetricRecord(row))
873
+ };
874
+ }
875
+ async function getMetricAggregate(db, args) {
876
+ const aggSql = getAggregationSql(args.aggregation);
877
+ const { clause: nameClause, params: nameParams } = buildMetricNameFilter(args.name);
878
+ const { clause: filterClause, params: filterParams } = buildWhereClause(
879
+ args.filters
880
+ );
881
+ const { clause: whereClause, params: allParams } = buildCombinedWhereClause(
882
+ nameClause,
883
+ nameParams,
884
+ filterClause,
885
+ filterParams
886
+ );
887
+ const sql = `SELECT ${aggSql} AS value, ${getCostSummarySelect()} FROM metric_events ${whereClause}`;
888
+ const result = await db.query(sql, allParams);
889
+ const row = result[0] ?? {};
890
+ const value = row.value === null || row.value === void 0 ? null : Number(row.value);
891
+ const costSummary = normalizeCostSummaryRow(row);
892
+ if (args.comparePeriod && args.filters?.timestamp) {
893
+ const ts = args.filters.timestamp;
894
+ if (ts.start && ts.end) {
895
+ const duration = ts.end.getTime() - ts.start.getTime();
896
+ let prevStart;
897
+ let prevEnd;
898
+ switch (args.comparePeriod) {
899
+ case "previous_period":
900
+ prevStart = new Date(ts.start.getTime() - duration);
901
+ prevEnd = new Date(ts.end.getTime() - duration);
902
+ break;
903
+ case "previous_day":
904
+ prevStart = new Date(ts.start.getTime() - 864e5);
905
+ prevEnd = new Date(ts.end.getTime() - 864e5);
906
+ break;
907
+ case "previous_week":
908
+ prevStart = new Date(ts.start.getTime() - 6048e5);
909
+ prevEnd = new Date(ts.end.getTime() - 6048e5);
910
+ break;
911
+ default:
912
+ prevStart = new Date(ts.start.getTime() - duration);
913
+ prevEnd = new Date(ts.end.getTime() - duration);
914
+ }
915
+ const prevFilters = {
916
+ ...args.filters ?? {},
917
+ timestamp: {
918
+ start: prevStart,
919
+ end: prevEnd,
920
+ startExclusive: ts.startExclusive,
921
+ endExclusive: ts.endExclusive
922
+ }
923
+ };
924
+ const { clause: prevFilterClause, params: prevFilterParams } = buildWhereClause(
925
+ prevFilters
926
+ );
927
+ const { clause: prevWhereClause, params: prevParams } = buildCombinedWhereClause(
928
+ nameClause,
929
+ nameParams,
930
+ prevFilterClause,
931
+ prevFilterParams
932
+ );
933
+ const prevSql = `SELECT ${aggSql} AS value, ${getCostSummarySelect()} FROM metric_events ${prevWhereClause}`;
934
+ const prevResult = await db.query(prevSql, prevParams);
935
+ const prevRow = prevResult[0] ?? {};
936
+ const previousValue = prevRow.value === null || prevRow.value === void 0 ? null : Number(prevRow.value);
937
+ const previousCostSummary = normalizeCostSummaryRow(prevRow);
938
+ let changePercent = null;
939
+ if (previousValue !== null && previousValue !== 0 && value !== null) {
940
+ changePercent = (value - previousValue) / Math.abs(previousValue) * 100;
941
+ }
942
+ let costChangePercent = null;
943
+ if (previousCostSummary.estimatedCost !== null && previousCostSummary.estimatedCost !== 0 && costSummary.estimatedCost !== null) {
944
+ costChangePercent = (costSummary.estimatedCost - previousCostSummary.estimatedCost) / Math.abs(previousCostSummary.estimatedCost) * 100;
945
+ }
946
+ return {
947
+ value,
948
+ estimatedCost: costSummary.estimatedCost,
949
+ costUnit: costSummary.costUnit,
950
+ previousValue,
951
+ previousEstimatedCost: previousCostSummary.estimatedCost,
952
+ changePercent,
953
+ costChangePercent
954
+ };
955
+ }
956
+ }
957
+ return { value, estimatedCost: costSummary.estimatedCost, costUnit: costSummary.costUnit };
958
+ }
959
+ async function getMetricBreakdown(db, args) {
960
+ const aggSql = getAggregationSql(args.aggregation);
961
+ const { clause: nameClause, params: nameParams } = buildMetricNameFilter(args.name);
962
+ const { clause: filterClause, params: filterParams } = buildWhereClause(
963
+ args.filters
964
+ );
965
+ const { clause: whereClause, params: allParams } = buildCombinedWhereClause(
966
+ nameClause,
967
+ nameParams,
968
+ filterClause,
969
+ filterParams
970
+ );
971
+ const resolvedGroupBy = resolveGroupBy(args.groupBy);
972
+ const selectGroupBy = resolvedGroupBy.map((entry) => entry.selectSql).join(", ");
973
+ const groupByCols = resolvedGroupBy.map((entry) => entry.groupSql).join(", ");
974
+ const sql = `SELECT ${selectGroupBy}, ${aggSql} AS value, ${getCostSummarySelect()} FROM metric_events ${whereClause} GROUP BY ${groupByCols} ORDER BY value DESC`;
975
+ const rows = await db.query(sql, allParams);
976
+ const groups = rows.map((row) => {
977
+ const dimensions = {};
978
+ for (const entry of resolvedGroupBy) {
979
+ const value = row[entry.resultKey];
980
+ dimensions[entry.key] = value === null || value === void 0 ? null : String(value);
981
+ }
982
+ const costSummary = normalizeCostSummaryRow(row);
983
+ return {
984
+ dimensions,
985
+ value: Number(row.value ?? 0),
986
+ estimatedCost: costSummary.estimatedCost,
987
+ costUnit: costSummary.costUnit
988
+ };
989
+ });
990
+ return { groups };
991
+ }
992
+ async function getMetricTimeSeries(db, args) {
993
+ const aggSql = getAggregationSql(args.aggregation);
994
+ const intervalSql = getIntervalSql(args.interval);
995
+ const { clause: nameClause, params: nameParams } = buildMetricNameFilter(args.name);
996
+ const { clause: filterClause, params: filterParams } = buildWhereClause(
997
+ args.filters
998
+ );
999
+ const { clause: whereClause, params: allParams } = buildCombinedWhereClause(
1000
+ nameClause,
1001
+ nameParams,
1002
+ filterClause,
1003
+ filterParams
1004
+ );
1005
+ if (args.groupBy && args.groupBy.length > 0) {
1006
+ const resolvedGroupBy = resolveGroupBy(args.groupBy);
1007
+ const selectGroupBy = resolvedGroupBy.map((entry) => entry.selectSql).join(", ");
1008
+ const groupByCols = resolvedGroupBy.map((entry) => entry.groupSql).join(", ");
1009
+ const sql2 = `
1010
+ SELECT time_bucket(INTERVAL '${intervalSql}', timestamp) AS bucket,
1011
+ ${selectGroupBy},
1012
+ ${aggSql} AS value,
1013
+ ${getCostSummarySelect()}
1014
+ FROM metric_events ${whereClause}
1015
+ GROUP BY bucket, ${groupByCols}
1016
+ ORDER BY bucket
1017
+ `;
1018
+ const rows2 = await db.query(sql2, allParams);
1019
+ const seriesMap = /* @__PURE__ */ new Map();
1020
+ for (const row of rows2) {
1021
+ const dimensionValues = resolvedGroupBy.map((entry) => row[entry.resultKey]);
1022
+ const seriesKey = JSON.stringify(dimensionValues);
1023
+ const name = dimensionValues.map(toSeriesDisplayValue).join("|");
1024
+ const costSummary = normalizeCostSummaryRow(row);
1025
+ if (!seriesMap.has(seriesKey)) {
1026
+ seriesMap.set(seriesKey, {
1027
+ name,
1028
+ costUnits: /* @__PURE__ */ new Set(),
1029
+ points: []
1030
+ });
1031
+ }
1032
+ if (costSummary.costUnit) {
1033
+ seriesMap.get(seriesKey).costUnits.add(costSummary.costUnit);
1034
+ }
1035
+ seriesMap.get(seriesKey).points.push({
1036
+ timestamp: row.bucket instanceof Date ? row.bucket : new Date(String(row.bucket)),
1037
+ value: Number(row.value ?? 0),
1038
+ estimatedCost: costSummary.estimatedCost
1039
+ });
1040
+ }
1041
+ return {
1042
+ series: Array.from(seriesMap.values()).map((series) => ({
1043
+ name: series.name,
1044
+ costUnit: series.costUnits.size === 1 ? Array.from(series.costUnits)[0] : null,
1045
+ points: series.points
1046
+ }))
1047
+ };
1048
+ }
1049
+ const sql = `
1050
+ SELECT time_bucket(INTERVAL '${intervalSql}', timestamp) AS bucket,
1051
+ ${aggSql} AS value,
1052
+ ${getCostSummarySelect()}
1053
+ FROM metric_events ${whereClause}
1054
+ GROUP BY bucket
1055
+ ORDER BY bucket
1056
+ `;
1057
+ const rows = await db.query(sql, allParams);
1058
+ const metricName = Array.isArray(args.name) ? args.name.join(",") : args.name;
1059
+ const overallCostUnits = new Set(
1060
+ rows.map((row) => row.costUnit).filter((value) => typeof value === "string")
1061
+ );
1062
+ return {
1063
+ series: [
1064
+ {
1065
+ name: metricName,
1066
+ costUnit: overallCostUnits.size === 1 ? Array.from(overallCostUnits)[0] : null,
1067
+ points: rows.map((row) => {
1068
+ const costSummary = normalizeCostSummaryRow(row);
1069
+ return {
1070
+ timestamp: row.bucket instanceof Date ? row.bucket : new Date(String(row.bucket)),
1071
+ value: Number(row.value ?? 0),
1072
+ estimatedCost: costSummary.estimatedCost
1073
+ };
1074
+ })
1075
+ }
1076
+ ]
1077
+ };
1078
+ }
1079
+ async function getMetricPercentiles(db, args) {
1080
+ const intervalSql = getIntervalSql(args.interval);
1081
+ const { clause: filterClause, params: filterParams } = buildWhereClause(
1082
+ args.filters
1083
+ );
1084
+ const allConditions = [`name = ?`];
1085
+ const allParams = [args.name];
1086
+ if (filterClause) {
1087
+ allConditions.push(filterClause.replace("WHERE ", ""));
1088
+ allParams.push(...filterParams);
1089
+ }
1090
+ const whereClause = `WHERE ${allConditions.join(" AND ")}`;
1091
+ const series = [];
1092
+ for (const p of args.percentiles) {
1093
+ const sql = `
1094
+ SELECT time_bucket(INTERVAL '${intervalSql}', timestamp) AS bucket,
1095
+ percentile_cont(${p}) WITHIN GROUP (ORDER BY value) AS pvalue
1096
+ FROM metric_events ${whereClause}
1097
+ GROUP BY bucket
1098
+ ORDER BY bucket
1099
+ `;
1100
+ const rows = await db.query(sql, allParams);
1101
+ series.push({
1102
+ percentile: p,
1103
+ points: rows.map((row) => ({
1104
+ timestamp: row.bucket instanceof Date ? row.bucket : new Date(String(row.bucket)),
1105
+ value: Number(row.pvalue ?? 0)
1106
+ }))
1107
+ });
1108
+ }
1109
+ return { series };
1110
+ }
1111
+ async function getMetricNames(db, args) {
1112
+ const conditions = [];
1113
+ const params = [];
1114
+ if (args.prefix) {
1115
+ conditions.push(`name LIKE ?`);
1116
+ params.push(`${args.prefix}%`);
1117
+ }
1118
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1119
+ const limitClause = args.limit ? `LIMIT ?` : "";
1120
+ if (args.limit) params.push(args.limit);
1121
+ const rows = await db.query(
1122
+ `SELECT DISTINCT name FROM metric_events ${whereClause} ORDER BY name ${limitClause}`,
1123
+ params
1124
+ );
1125
+ return { names: rows.map((r) => r.name) };
1126
+ }
1127
+ async function getMetricLabelKeys(db, args) {
1128
+ const rows = await db.query(
1129
+ `SELECT DISTINCT unnest(json_keys(labels)) AS key FROM metric_events WHERE name = ? AND labels IS NOT NULL`,
1130
+ [args.metricName]
1131
+ );
1132
+ return { keys: rows.map((r) => r.key) };
1133
+ }
1134
+ async function getMetricLabelValues(db, args) {
1135
+ const labelPath = buildJsonPath(args.labelKey);
1136
+ const conditions = [`name = ?`, `json_extract_string(labels, ?) IS NOT NULL`];
1137
+ const params = [args.metricName, labelPath];
1138
+ if (args.prefix) {
1139
+ conditions.push(`json_extract_string(labels, ?) LIKE ?`);
1140
+ params.push(labelPath, `${args.prefix}%`);
1141
+ }
1142
+ const limitClause = args.limit ? `LIMIT ?` : "";
1143
+ if (args.limit) params.push(args.limit);
1144
+ const rows = await db.query(
1145
+ `SELECT DISTINCT json_extract_string(labels, ?) AS val FROM metric_events WHERE ${conditions.join(" AND ")} ORDER BY val ${limitClause}`,
1146
+ [labelPath, ...params]
1147
+ );
1148
+ return { values: rows.map((r) => r.val) };
1149
+ }
1150
+
1151
+ // src/storage/domains/observability/scores.ts
1152
+ async function createScore(db, args) {
1153
+ const s = args.score;
1154
+ await db.execute(
1155
+ `INSERT INTO score_events (timestamp, traceId, spanId, scorerId, scorerVersion, source, score, reason, experimentId, scoreTraceId, metadata)
1156
+ VALUES (${[
1157
+ v(s.timestamp),
1158
+ v(s.traceId),
1159
+ v(s.spanId ?? null),
1160
+ v(s.scorerId),
1161
+ v(s.scorerVersion ?? null),
1162
+ v(s.source ?? null),
1163
+ v(s.score),
1164
+ v(s.reason ?? null),
1165
+ v(s.experimentId ?? null),
1166
+ v(s.scoreTraceId ?? null),
1167
+ jsonV(s.metadata)
1168
+ ].join(", ")})`
1169
+ );
1170
+ }
1171
+ async function batchCreateScores(db, args) {
1172
+ if (args.scores.length === 0) return;
1173
+ const tuples = args.scores.map(
1174
+ (s) => `(${[
1175
+ v(s.timestamp),
1176
+ v(s.traceId),
1177
+ v(s.spanId ?? null),
1178
+ v(s.scorerId),
1179
+ v(s.scorerVersion ?? null),
1180
+ v(s.source ?? null),
1181
+ v(s.score),
1182
+ v(s.reason ?? null),
1183
+ v(s.experimentId ?? null),
1184
+ v(s.scoreTraceId ?? null),
1185
+ jsonV(s.metadata)
1186
+ ].join(", ")})`
1187
+ );
1188
+ await db.execute(
1189
+ `INSERT INTO score_events (timestamp, traceId, spanId, scorerId, scorerVersion, source, score, reason, experimentId, scoreTraceId, metadata)
1190
+ VALUES ${tuples.join(",\n ")}`
1191
+ );
1192
+ }
1193
+ async function listScores(db, args) {
1194
+ const filters = args.filters ?? {};
1195
+ const page = Number(args.pagination?.page ?? 0);
1196
+ const perPage = Number(args.pagination?.perPage ?? 10);
1197
+ const orderBy = { field: args.orderBy?.field ?? "timestamp", direction: args.orderBy?.direction ?? "DESC" };
1198
+ const { clause: filterClause, params: filterParams } = buildWhereClause(filters);
1199
+ const orderByClause = buildOrderByClause(orderBy);
1200
+ const { clause: paginationClause, params: paginationParams } = buildPaginationClause({ page, perPage });
1201
+ const countResult = await db.query(
1202
+ `SELECT COUNT(*) as total FROM score_events ${filterClause}`,
1203
+ filterParams
1204
+ );
1205
+ const total = Number(countResult[0]?.total ?? 0);
1206
+ const rows = await db.query(`SELECT * FROM score_events ${filterClause} ${orderByClause} ${paginationClause}`, [
1207
+ ...filterParams,
1208
+ ...paginationParams
1209
+ ]);
1210
+ const scores = rows.map((row) => {
1211
+ const r = row;
1212
+ return {
1213
+ timestamp: toDate(r.timestamp),
1214
+ traceId: r.traceId,
1215
+ spanId: r.spanId ?? null,
1216
+ scorerId: r.scorerId,
1217
+ scorerVersion: r.scorerVersion ?? null,
1218
+ source: r.source ?? null,
1219
+ score: Number(r.score),
1220
+ reason: r.reason ?? null,
1221
+ experimentId: r.experimentId ?? null,
1222
+ scoreTraceId: r.scoreTraceId ?? null,
1223
+ metadata: parseJson(r.metadata)
1224
+ };
1225
+ });
1226
+ return {
1227
+ pagination: { total, page, perPage, hasMore: (page + 1) * perPage < total },
1228
+ scores
1229
+ };
1230
+ }
1231
+ var COLUMNS2 = [
1232
+ "eventType",
1233
+ "timestamp",
1234
+ "traceId",
1235
+ "spanId",
1236
+ "parentSpanId",
1237
+ "name",
1238
+ "spanType",
1239
+ "isEvent",
1240
+ "endedAt",
1241
+ "experimentId",
1242
+ "entityType",
1243
+ "entityId",
1244
+ "entityName",
1245
+ "userId",
1246
+ "organizationId",
1247
+ "resourceId",
1248
+ "runId",
1249
+ "sessionId",
1250
+ "threadId",
1251
+ "requestId",
1252
+ "environment",
1253
+ "source",
1254
+ "serviceName",
1255
+ "attributes",
1256
+ "metadata",
1257
+ "tags",
1258
+ "scope",
1259
+ "links",
1260
+ "input",
1261
+ "output",
1262
+ "error",
1263
+ "requestContext"
1264
+ ];
1265
+ var COLUMNS_SQL2 = COLUMNS2.join(", ");
1266
+ function argMaxNonNull(col) {
1267
+ return `arg_max(${col}, timestamp) FILTER (WHERE ${col} IS NOT NULL) as ${col}`;
1268
+ }
1269
+ var SPAN_RECONSTRUCT_SELECT = `
1270
+ SELECT
1271
+ traceId, spanId,
1272
+ ${argMaxNonNull("name")},
1273
+ ${argMaxNonNull("spanType")},
1274
+ ${argMaxNonNull("parentSpanId")},
1275
+ ${argMaxNonNull("isEvent")},
1276
+ coalesce(min(timestamp) FILTER (WHERE eventType = 'start'), min(timestamp)) as startedAt,
1277
+ ${argMaxNonNull("endedAt")},
1278
+ ${argMaxNonNull("experimentId")},
1279
+ ${argMaxNonNull("entityType")},
1280
+ ${argMaxNonNull("entityId")},
1281
+ ${argMaxNonNull("entityName")},
1282
+ ${argMaxNonNull("userId")},
1283
+ ${argMaxNonNull("organizationId")},
1284
+ ${argMaxNonNull("resourceId")},
1285
+ ${argMaxNonNull("runId")},
1286
+ ${argMaxNonNull("sessionId")},
1287
+ ${argMaxNonNull("threadId")},
1288
+ ${argMaxNonNull("requestId")},
1289
+ ${argMaxNonNull("environment")},
1290
+ ${argMaxNonNull("source")},
1291
+ ${argMaxNonNull("serviceName")},
1292
+ ${argMaxNonNull("attributes")},
1293
+ ${argMaxNonNull("metadata")},
1294
+ ${argMaxNonNull("tags")},
1295
+ ${argMaxNonNull("scope")},
1296
+ ${argMaxNonNull("links")},
1297
+ ${argMaxNonNull("input")},
1298
+ ${argMaxNonNull("output")},
1299
+ ${argMaxNonNull("error")},
1300
+ ${argMaxNonNull("requestContext")}
1301
+ FROM span_events
1302
+ `;
1303
+ function rowToSpanRecord(row) {
1304
+ return {
1305
+ traceId: row.traceId,
1306
+ spanId: row.spanId,
1307
+ name: row.name,
1308
+ spanType: row.spanType,
1309
+ parentSpanId: row.parentSpanId ?? null,
1310
+ isEvent: row.isEvent,
1311
+ startedAt: toDate(row.startedAt),
1312
+ endedAt: toDateOrNull(row.endedAt),
1313
+ experimentId: row.experimentId ?? null,
1314
+ entityType: row.entityType ?? null,
1315
+ entityId: row.entityId ?? null,
1316
+ entityName: row.entityName ?? null,
1317
+ userId: row.userId ?? null,
1318
+ organizationId: row.organizationId ?? null,
1319
+ resourceId: row.resourceId ?? null,
1320
+ runId: row.runId ?? null,
1321
+ sessionId: row.sessionId ?? null,
1322
+ threadId: row.threadId ?? null,
1323
+ requestId: row.requestId ?? null,
1324
+ environment: row.environment ?? null,
1325
+ source: row.source ?? null,
1326
+ serviceName: row.serviceName ?? null,
1327
+ attributes: parseJson(row.attributes),
1328
+ metadata: parseJson(row.metadata),
1329
+ tags: parseJsonArray(row.tags),
1330
+ scope: parseJson(row.scope),
1331
+ links: parseJsonArray(row.links),
1332
+ input: parseJson(row.input),
1333
+ output: parseJson(row.output),
1334
+ error: parseJson(row.error),
1335
+ requestContext: parseJson(row.requestContext),
1336
+ createdAt: toDate(row.startedAt),
1337
+ updatedAt: null
1338
+ };
1339
+ }
1340
+ function buildHasChildErrorClause(hasChildError) {
1341
+ if (hasChildError === void 0) return "";
1342
+ const base = `SELECT 1 FROM reconstructed_spans c WHERE c.traceId = root_spans.traceId AND c.spanId != root_spans.spanId AND c.error IS NOT NULL`;
1343
+ return hasChildError ? `EXISTS (${base})` : `NOT EXISTS (${base})`;
1344
+ }
1345
+ function toValuesTuple(row) {
1346
+ return [
1347
+ v(row.eventType),
1348
+ v(row.timestamp),
1349
+ v(row.traceId),
1350
+ v(row.spanId),
1351
+ v(row.parentSpanId),
1352
+ v(row.name),
1353
+ v(row.spanType),
1354
+ v(row.isEvent),
1355
+ v(row.endedAt),
1356
+ v(row.experimentId),
1357
+ v(row.entityType),
1358
+ v(row.entityId),
1359
+ v(row.entityName),
1360
+ v(row.userId),
1361
+ v(row.organizationId),
1362
+ v(row.resourceId),
1363
+ v(row.runId),
1364
+ v(row.sessionId),
1365
+ v(row.threadId),
1366
+ v(row.requestId),
1367
+ v(row.environment),
1368
+ v(row.source),
1369
+ v(row.serviceName),
1370
+ jsonV(row.attributes),
1371
+ jsonV(row.metadata),
1372
+ jsonV(row.tags),
1373
+ jsonV(row.scope),
1374
+ jsonV(row.links),
1375
+ jsonV(row.input),
1376
+ jsonV(row.output),
1377
+ jsonV(row.error),
1378
+ jsonV(row.requestContext)
1379
+ ].join(", ");
1380
+ }
1381
+ async function insertSpanEvents(db, rows) {
1382
+ if (rows.length === 0) return;
1383
+ const tuples = rows.map((row) => `(${toValuesTuple(row)})`).join(",\n");
1384
+ await db.execute(`INSERT INTO span_events (${COLUMNS_SQL2}) VALUES ${tuples}`);
1385
+ }
1386
+ function createStartSpanRow(s) {
1387
+ return {
1388
+ eventType: "start",
1389
+ timestamp: s.startedAt,
1390
+ traceId: s.traceId,
1391
+ spanId: s.spanId,
1392
+ parentSpanId: s.parentSpanId ?? null,
1393
+ name: s.name,
1394
+ spanType: s.spanType,
1395
+ isEvent: s.isEvent,
1396
+ endedAt: null,
1397
+ experimentId: s.experimentId ?? null,
1398
+ entityType: s.entityType ?? null,
1399
+ entityId: s.entityId ?? null,
1400
+ entityName: s.entityName ?? null,
1401
+ userId: s.userId ?? null,
1402
+ organizationId: s.organizationId ?? null,
1403
+ resourceId: s.resourceId ?? null,
1404
+ runId: s.runId ?? null,
1405
+ sessionId: s.sessionId ?? null,
1406
+ threadId: s.threadId ?? null,
1407
+ requestId: s.requestId ?? null,
1408
+ environment: s.environment ?? null,
1409
+ source: s.source ?? null,
1410
+ serviceName: s.serviceName ?? null,
1411
+ attributes: s.attributes ?? null,
1412
+ metadata: s.metadata ?? null,
1413
+ tags: s.tags ?? null,
1414
+ scope: s.scope ?? null,
1415
+ links: null,
1416
+ input: s.input ?? null,
1417
+ output: null,
1418
+ error: null,
1419
+ requestContext: s.requestContext ?? null
1420
+ };
1421
+ }
1422
+ function createEndSpanRow(s) {
1423
+ return {
1424
+ eventType: "end",
1425
+ timestamp: s.endedAt,
1426
+ traceId: s.traceId,
1427
+ spanId: s.spanId,
1428
+ parentSpanId: s.parentSpanId ?? null,
1429
+ name: s.name,
1430
+ spanType: s.spanType,
1431
+ isEvent: s.isEvent,
1432
+ endedAt: s.endedAt ?? null,
1433
+ experimentId: s.experimentId ?? null,
1434
+ entityType: s.entityType ?? null,
1435
+ entityId: s.entityId ?? null,
1436
+ entityName: s.entityName ?? null,
1437
+ userId: s.userId ?? null,
1438
+ organizationId: s.organizationId ?? null,
1439
+ resourceId: s.resourceId ?? null,
1440
+ runId: s.runId ?? null,
1441
+ sessionId: s.sessionId ?? null,
1442
+ threadId: s.threadId ?? null,
1443
+ requestId: s.requestId ?? null,
1444
+ environment: s.environment ?? null,
1445
+ source: s.source ?? null,
1446
+ serviceName: s.serviceName ?? null,
1447
+ attributes: s.attributes ?? null,
1448
+ metadata: s.metadata ?? null,
1449
+ tags: s.tags ?? null,
1450
+ scope: s.scope ?? null,
1451
+ links: s.links ?? null,
1452
+ input: s.input ?? null,
1453
+ output: s.output ?? null,
1454
+ error: s.error ?? null,
1455
+ requestContext: s.requestContext ?? null
1456
+ };
1457
+ }
1458
+ async function createSpan(db, args) {
1459
+ const rows = [createStartSpanRow(args.span)];
1460
+ if (args.span.endedAt) {
1461
+ rows.push(createEndSpanRow(args.span));
1462
+ }
1463
+ await insertSpanEvents(db, rows);
1464
+ }
1465
+ async function batchCreateSpans(db, args) {
1466
+ if (args.records.length === 0) return;
1467
+ const rows = args.records.flatMap((record) => {
1468
+ const events = [createStartSpanRow(record)];
1469
+ if (record.endedAt) {
1470
+ events.push(createEndSpanRow(record));
1471
+ }
1472
+ return events;
1473
+ });
1474
+ await insertSpanEvents(db, rows);
1475
+ }
1476
+ async function batchDeleteTraces(db, args) {
1477
+ if (args.traceIds.length === 0) return;
1478
+ const placeholders = args.traceIds.map(() => "?").join(", ");
1479
+ await db.execute(`DELETE FROM span_events WHERE traceId IN (${placeholders})`, args.traceIds);
1480
+ }
1481
+ async function getSpan(db, args) {
1482
+ const rows = await db.query(`${SPAN_RECONSTRUCT_SELECT} WHERE traceId = ? AND spanId = ? GROUP BY traceId, spanId`, [
1483
+ args.traceId,
1484
+ args.spanId
1485
+ ]);
1486
+ if (rows.length === 0) return null;
1487
+ return { span: rowToSpanRecord(rows[0]) };
1488
+ }
1489
+ async function getRootSpan(db, args) {
1490
+ const rows = await db.query(
1491
+ `${SPAN_RECONSTRUCT_SELECT} WHERE traceId = ? GROUP BY traceId, spanId HAVING arg_max(parentSpanId, timestamp) IS NULL LIMIT 1`,
1492
+ [args.traceId]
1493
+ );
1494
+ if (rows.length === 0) return null;
1495
+ return { span: rowToSpanRecord(rows[0]) };
1496
+ }
1497
+ async function getTrace(db, args) {
1498
+ const rows = await db.query(`${SPAN_RECONSTRUCT_SELECT} WHERE traceId = ? GROUP BY traceId, spanId`, [args.traceId]);
1499
+ if (rows.length === 0) return null;
1500
+ return {
1501
+ traceId: args.traceId,
1502
+ spans: rows.map((row) => rowToSpanRecord(row))
1503
+ };
1504
+ }
1505
+ async function listTraces(db, args) {
1506
+ const filters = args.filters ?? {};
1507
+ const page = Number(args.pagination?.page ?? 0);
1508
+ const perPage = Number(args.pagination?.perPage ?? 10);
1509
+ const orderBy = { field: args.orderBy?.field ?? "startedAt", direction: args.orderBy?.direction ?? "DESC" };
1510
+ const { clause: filterClause, params: filterParams } = buildWhereClause(filters);
1511
+ const orderByClause = buildOrderByClause(orderBy);
1512
+ const { clause: paginationClause, params: paginationParams } = buildPaginationClause({ page, perPage });
1513
+ const filterParts = [];
1514
+ if (filterClause) filterParts.push(filterClause.replace(/^WHERE\s+/i, ""));
1515
+ const hasChildError = typeof filters.hasChildError === "boolean" ? filters.hasChildError : void 0;
1516
+ const childErrorClause = buildHasChildErrorClause(hasChildError);
1517
+ if (childErrorClause) filterParts.push(childErrorClause);
1518
+ const combinedFilterClause = filterParts.length > 0 ? `WHERE ${filterParts.join(" AND ")}` : "";
1519
+ const cteSql = `
1520
+ WITH reconstructed_spans AS (
1521
+ ${SPAN_RECONSTRUCT_SELECT}
1522
+ GROUP BY traceId, spanId
1523
+ ),
1524
+ root_spans AS (
1525
+ SELECT * FROM reconstructed_spans
1526
+ WHERE parentSpanId IS NULL
1527
+ )
1528
+ `;
1529
+ const countSql = `
1530
+ ${cteSql}
1531
+ SELECT COUNT(*) as total FROM root_spans ${combinedFilterClause}
1532
+ `;
1533
+ const countResult = await db.query(countSql, filterParams);
1534
+ const total = Number(countResult[0]?.total ?? 0);
1535
+ const dataSql = `
1536
+ ${cteSql}
1537
+ SELECT * FROM root_spans ${combinedFilterClause} ${orderByClause} ${paginationClause}
1538
+ `;
1539
+ const rows = await db.query(dataSql, [...filterParams, ...paginationParams]);
1540
+ const spans = rows.map((row) => rowToSpanRecord(row));
1541
+ return {
1542
+ pagination: {
1543
+ total,
1544
+ page,
1545
+ perPage,
1546
+ hasMore: (page + 1) * perPage < total
1547
+ },
1548
+ spans: toTraceSpans(spans)
1549
+ };
1550
+ }
1551
+
1552
+ // src/storage/domains/observability/index.ts
1553
+ var ObservabilityStorageDuckDB = class extends ObservabilityStorage {
1554
+ db;
1555
+ constructor(config) {
1556
+ super();
1557
+ this.db = config.db;
1558
+ }
1559
+ /** Create all observability tables if they don't exist. */
1560
+ async init() {
1561
+ for (const ddl of ALL_DDL) {
1562
+ await this.db.execute(ddl);
1563
+ }
1564
+ }
1565
+ /** Delete all rows from every observability table. Use with caution. */
1566
+ async dangerouslyClearAll() {
1567
+ for (const table of ["span_events", "metric_events", "log_events", "score_events", "feedback_events"]) {
1568
+ await this.db.execute(`TRUNCATE TABLE ${table}`);
1569
+ }
1570
+ }
1571
+ get observabilityStrategy() {
1572
+ return {
1573
+ preferred: "event-sourced",
1574
+ supported: ["event-sourced"]
1575
+ };
1576
+ }
1577
+ // Tracing
1578
+ async createSpan(args) {
1579
+ return createSpan(this.db, args);
1580
+ }
1581
+ async batchCreateSpans(args) {
1582
+ return batchCreateSpans(this.db, args);
1583
+ }
1584
+ async batchDeleteTraces(args) {
1585
+ return batchDeleteTraces(this.db, args);
1586
+ }
1587
+ async getSpan(args) {
1588
+ return getSpan(this.db, args);
1589
+ }
1590
+ async getRootSpan(args) {
1591
+ return getRootSpan(this.db, args);
1592
+ }
1593
+ async getTrace(args) {
1594
+ return getTrace(this.db, args);
1595
+ }
1596
+ async listTraces(args) {
1597
+ return listTraces(this.db, args);
1598
+ }
1599
+ // Logs
1600
+ async batchCreateLogs(args) {
1601
+ return batchCreateLogs(this.db, args);
1602
+ }
1603
+ async listLogs(args) {
1604
+ return listLogs(this.db, args);
1605
+ }
1606
+ // Metrics
1607
+ async batchCreateMetrics(args) {
1608
+ return batchCreateMetrics(this.db, args);
1609
+ }
1610
+ async listMetrics(args) {
1611
+ return listMetrics(this.db, args);
1612
+ }
1613
+ async getMetricAggregate(args) {
1614
+ return getMetricAggregate(this.db, args);
1615
+ }
1616
+ async getMetricBreakdown(args) {
1617
+ return getMetricBreakdown(this.db, args);
1618
+ }
1619
+ async getMetricTimeSeries(args) {
1620
+ return getMetricTimeSeries(this.db, args);
1621
+ }
1622
+ async getMetricPercentiles(args) {
1623
+ return getMetricPercentiles(this.db, args);
1624
+ }
1625
+ // Metric Discovery
1626
+ async getMetricNames(args) {
1627
+ return getMetricNames(this.db, args);
1628
+ }
1629
+ async getMetricLabelKeys(args) {
1630
+ return getMetricLabelKeys(this.db, args);
1631
+ }
1632
+ async getMetricLabelValues(args) {
1633
+ return getMetricLabelValues(this.db, args);
1634
+ }
1635
+ // Span Discovery
1636
+ async getEntityTypes(args) {
1637
+ return getEntityTypes(this.db);
1638
+ }
1639
+ async getEntityNames(args) {
1640
+ return getEntityNames(this.db, args);
1641
+ }
1642
+ async getServiceNames(args) {
1643
+ return getServiceNames(this.db);
1644
+ }
1645
+ async getEnvironments(args) {
1646
+ return getEnvironments(this.db);
1647
+ }
1648
+ async getTags(args) {
1649
+ return getTags(this.db, args);
1650
+ }
1651
+ // Scores
1652
+ async createScore(args) {
1653
+ return createScore(this.db, args);
1654
+ }
1655
+ async batchCreateScores(args) {
1656
+ return batchCreateScores(this.db, args);
1657
+ }
1658
+ async listScores(args) {
1659
+ return listScores(this.db, args);
1660
+ }
1661
+ // Feedback
1662
+ async createFeedback(args) {
1663
+ return createFeedback(this.db, args);
1664
+ }
1665
+ async batchCreateFeedback(args) {
1666
+ return batchCreateFeedback(this.db, args);
1667
+ }
1668
+ async listFeedback(args) {
1669
+ return listFeedback(this.db, args);
1670
+ }
1671
+ };
1672
+
1673
+ export { ObservabilityStorageDuckDB };
1674
+ //# sourceMappingURL=observability-PW6J27KS.js.map
1675
+ //# sourceMappingURL=observability-PW6J27KS.js.map