@mastra/clickhouse 1.16.1-alpha.2 → 1.17.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.
@@ -3,7 +3,7 @@ name: mastra-clickhouse
3
3
  description: Documentation for @mastra/clickhouse. Use when working with @mastra/clickhouse APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/clickhouse"
6
- version: "1.16.1-alpha.2"
6
+ version: "1.17.0-alpha.0"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.16.1-alpha.2",
2
+ "version": "1.17.0-alpha.0",
3
3
  "package": "@mastra/clickhouse",
4
4
  "exports": {},
5
5
  "modules": {}
package/dist/index.cjs CHANGED
@@ -1,7 +1,30 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
2
24
  let _clickhouse_client = require("@clickhouse/client");
3
25
  let _mastra_core_error = require("@mastra/core/error");
4
26
  let _mastra_core_storage = require("@mastra/core/storage");
27
+ _mastra_core_storage = __toESM(_mastra_core_storage, 1);
5
28
  let _mastra_core_agent = require("@mastra/core/agent");
6
29
  let _mastra_core_base = require("@mastra/core/base");
7
30
  let _mastra_core_utils = require("@mastra/core/utils");
@@ -6092,6 +6115,269 @@ async function getScorePercentiles(client, args) {
6092
6115
  return { series };
6093
6116
  }
6094
6117
  //#endregion
6118
+ //#region src/storage/domains/observability/v-next/trace-query.ts
6119
+ const TRACE_STATUS_SQL = `if(isNotNull(r.error), 'error', 'success')`;
6120
+ const TRACE_FIELDS = {
6121
+ traceId: {
6122
+ sql: "r.traceId",
6123
+ parameterType: "String"
6124
+ },
6125
+ threadId: {
6126
+ sql: "r.threadId",
6127
+ parameterType: "String"
6128
+ },
6129
+ resourceId: {
6130
+ sql: "r.resourceId",
6131
+ parameterType: "String"
6132
+ },
6133
+ startedAt: {
6134
+ sql: "r.startedAt",
6135
+ parameterType: "DateTime64(3, 'UTC')"
6136
+ },
6137
+ endedAt: {
6138
+ sql: "r.endedAt",
6139
+ parameterType: "DateTime64(3, 'UTC')"
6140
+ },
6141
+ entityName: {
6142
+ sql: "r.entityName",
6143
+ parameterType: "String"
6144
+ },
6145
+ entityType: {
6146
+ sql: "r.entityType",
6147
+ parameterType: "String"
6148
+ },
6149
+ environment: {
6150
+ sql: "r.environment",
6151
+ parameterType: "String"
6152
+ },
6153
+ status: {
6154
+ sql: TRACE_STATUS_SQL,
6155
+ parameterType: "String"
6156
+ }
6157
+ };
6158
+ const SPAN_FIELDS = {
6159
+ spanType: {
6160
+ sql: "s.spanType",
6161
+ parameterType: "String"
6162
+ },
6163
+ error: {
6164
+ sql: "s.error",
6165
+ parameterType: "String"
6166
+ }
6167
+ };
6168
+ const SCORE_FIELDS = {
6169
+ scorerId: {
6170
+ sql: "s.scorerId",
6171
+ parameterType: "String"
6172
+ },
6173
+ score: {
6174
+ sql: "s.score",
6175
+ parameterType: "Float64"
6176
+ }
6177
+ };
6178
+ const TRACE_SELECT = `
6179
+ r.traceId AS traceId,
6180
+ r.spanId AS rootSpanId,
6181
+ r.threadId AS threadId,
6182
+ r.resourceId AS resourceId,
6183
+ r.startedAt AS startedAt,
6184
+ r.endedAt AS endedAt,
6185
+ r.entityName AS entityName,
6186
+ r.entityType AS entityType,
6187
+ r.environment AS environment,
6188
+ ${TRACE_STATUS_SQL} AS status`;
6189
+ var ParameterBuilder = class {
6190
+ params = {};
6191
+ #next = 1;
6192
+ add(value, type) {
6193
+ const name = `trace_query_${this.#next++}`;
6194
+ this.params[name] = type === "DateTime64(3, 'UTC')" ? new Date(value).toISOString().replace("T", " ").replace(/Z$/, "") : value;
6195
+ return `{${name}:${type}}`;
6196
+ }
6197
+ };
6198
+ function fieldDefinition(registry, field) {
6199
+ const definition = registry[field];
6200
+ if (definition === void 0) throw new Error(`Unsupported trusted trace-query field: ${field}`);
6201
+ return definition;
6202
+ }
6203
+ function resolveOrderField(field) {
6204
+ if (field === "startedAt" || field === "endedAt") return field;
6205
+ throw new Error(`Unsupported trusted trace-query field: ${field}`);
6206
+ }
6207
+ function compileScalarPredicate(predicate, registry, parameters) {
6208
+ if (predicate.type === "boolean") return predicate.args.map((arg) => `(${compileScalarPredicate(arg, registry, parameters)})`).join(predicate.operator === "and" ? " AND " : " OR ");
6209
+ if (predicate.type === "not") return `NOT (${compileScalarPredicate(predicate.arg, registry, parameters)})`;
6210
+ const field = fieldDefinition(registry, predicate.field);
6211
+ if (predicate.type === "presence") return `${predicate.operator === "exists" ? "isNotNull" : "isNull"}(${field.sql})`;
6212
+ if (predicate.type === "membership") {
6213
+ const values = predicate.values.map((value) => parameters.add(value, field.parameterType)).join(", ");
6214
+ return `ifNull(${`${field.sql} ${predicate.operator === "in" ? "IN" : "NOT IN"} (${values})`}, ${predicate.operator === "in" ? "0" : "1"})`;
6215
+ }
6216
+ const parameter = parameters.add(predicate.value, field.parameterType);
6217
+ const operator = {
6218
+ eq: "=",
6219
+ ne: "!=",
6220
+ lt: "<",
6221
+ lte: "<=",
6222
+ gt: ">",
6223
+ gte: ">="
6224
+ }[predicate.operator];
6225
+ if (operator === void 0) throw new Error(`Unsupported trusted trace-query operator: ${predicate.operator}`);
6226
+ return `ifNull(${field.sql} ${operator} ${parameter}, ${predicate.operator === "ne" ? "1" : "0"})`;
6227
+ }
6228
+ function collectRelationCollections(predicate, collections = /* @__PURE__ */ new Set()) {
6229
+ if (!predicate) return collections;
6230
+ if (predicate.type === "relation") collections.add(predicate.collection);
6231
+ else if (predicate.type === "boolean") for (const arg of predicate.args) collectRelationCollections(arg, collections);
6232
+ else if (predicate.type === "not") collectRelationCollections(predicate.arg, collections);
6233
+ return collections;
6234
+ }
6235
+ function compilePredicate(predicate, parameters) {
6236
+ if (predicate.type === "relation") {
6237
+ const registry = predicate.collection === "spans" ? SPAN_FIELDS : SCORE_FIELDS;
6238
+ const existence = `EXISTS (
6239
+ SELECT 1 FROM ${predicate.collection === "spans" ? "current_spans" : "current_scores"} s
6240
+ WHERE s.traceId = r.traceId
6241
+ AND (${compileScalarPredicate(predicate.predicate, registry, parameters)})
6242
+ )`;
6243
+ return predicate.quantifier === "some" ? existence : `NOT ${existence}`;
6244
+ }
6245
+ if (predicate.type === "boolean") return predicate.args.map((arg) => `(${compilePredicate(arg, parameters)})`).join(predicate.operator === "and" ? " AND " : " OR ");
6246
+ if (predicate.type === "not") return `NOT (${compilePredicate(predicate.arg, parameters)})`;
6247
+ return compileScalarPredicate(predicate, TRACE_FIELDS, parameters);
6248
+ }
6249
+ function compileClickHouseTraceQuery(plan) {
6250
+ const parameters = new ParameterBuilder();
6251
+ const from = parameters.add(plan.timeRange.from, "DateTime64(3, 'UTC')");
6252
+ const to = parameters.add(plan.timeRange.to, "DateTime64(3, 'UTC')");
6253
+ const relationCollections = collectRelationCollections(plan.where);
6254
+ const ctes = [`current_roots AS (
6255
+ SELECT * FROM (
6256
+ SELECT *
6257
+ FROM ${TABLE_TRACE_ROOTS}
6258
+ ORDER BY dedupeKey
6259
+ LIMIT 1 BY dedupeKey
6260
+ )
6261
+ ORDER BY traceId, dedupeKey
6262
+ LIMIT 1 BY traceId
6263
+ )`, `root_scope AS (
6264
+ SELECT *
6265
+ FROM current_roots
6266
+ WHERE startedAt >= ${from}
6267
+ AND startedAt < ${to}
6268
+ )`];
6269
+ if (relationCollections.has("spans")) ctes.push(`current_spans AS (
6270
+ SELECT traceId, spanType, error
6271
+ FROM ${TABLE_SPAN_EVENTS}
6272
+ WHERE traceId IN (SELECT traceId FROM root_scope)
6273
+ ORDER BY dedupeKey
6274
+ LIMIT 1 BY dedupeKey
6275
+ )`);
6276
+ if (relationCollections.has("scores")) ctes.push(`current_scores AS (
6277
+ SELECT traceId, scorerId, score
6278
+ FROM ${TABLE_SCORE_EVENTS}
6279
+ WHERE isNotNull(traceId)
6280
+ AND traceId IN (SELECT traceId FROM root_scope)
6281
+ )`);
6282
+ const predicate = plan.where ? compilePredicate(plan.where, parameters) : "1";
6283
+ ctes.push(`candidates AS (
6284
+ SELECT ${TRACE_SELECT}
6285
+ FROM root_scope r
6286
+ WHERE ${predicate}
6287
+ )`);
6288
+ const candidates = `WITH ${ctes.join(",\n")}`;
6289
+ if (plan.result === "groups") return {
6290
+ query: `${candidates}
6291
+ SELECT threadId
6292
+ FROM candidates
6293
+ WHERE isNotNull(threadId) ${plan.cursor ? `AND threadId > ${parameters.add(plan.cursor.threadId, "String")}` : ""}
6294
+ GROUP BY threadId
6295
+ ORDER BY threadId ASC
6296
+ LIMIT ${parameters.add(plan.limit + 1, "UInt64")}`,
6297
+ query_params: parameters.params
6298
+ };
6299
+ const orderField = resolveOrderField(plan.orderBy.field);
6300
+ const direction = plan.orderBy.direction === "asc" ? "ASC" : "DESC";
6301
+ let pageCondition = "";
6302
+ if (plan.cursor) {
6303
+ const comparison = plan.orderBy.direction === "asc" ? ">" : "<";
6304
+ const sortValue = parameters.add(plan.cursor.sortValue, "DateTime64(3, 'UTC')");
6305
+ pageCondition = `WHERE (${orderField} ${comparison} ${sortValue} OR (${orderField} = ${sortValue} AND traceId > ${parameters.add(plan.cursor.traceId, "String")}))`;
6306
+ }
6307
+ const limit = parameters.add(plan.limit + 1, "UInt64");
6308
+ return {
6309
+ query: `${candidates}
6310
+ SELECT *
6311
+ FROM candidates
6312
+ ${pageCondition}
6313
+ ORDER BY ${orderField} ${direction}, traceId ASC
6314
+ LIMIT ${limit}`,
6315
+ query_params: parameters.params
6316
+ };
6317
+ }
6318
+ function asIsoTimestamp(value) {
6319
+ return new Date(value).toISOString();
6320
+ }
6321
+ function isClickHouseExecutionTimeout(error) {
6322
+ if (!error || typeof error !== "object") return false;
6323
+ const candidate = error;
6324
+ return String(candidate.code ?? "") === "159" || candidate.type === "TIMEOUT_EXCEEDED";
6325
+ }
6326
+ async function runWithClickHouseTraceQueryTimeout(client, timeoutMs, compiled, queryId) {
6327
+ const resolvedTimeoutMs = _mastra_core_storage.resolveTraceQueryTimeoutMs(timeoutMs);
6328
+ try {
6329
+ return await (await client.query({
6330
+ query: compiled.query,
6331
+ query_params: compiled.query_params,
6332
+ query_id: queryId,
6333
+ format: "JSONEachRow",
6334
+ clickhouse_settings: {
6335
+ ...CH_SETTINGS,
6336
+ max_execution_time: resolvedTimeoutMs / 1e3
6337
+ }
6338
+ })).json();
6339
+ } catch (error) {
6340
+ if (isClickHouseExecutionTimeout(error)) throw new _mastra_core_storage.TraceQueryExecutionError();
6341
+ throw error;
6342
+ }
6343
+ }
6344
+ async function queryTraces(client, plan, timeoutMs) {
6345
+ const rows = await runWithClickHouseTraceQueryTimeout(client, timeoutMs, compileClickHouseTraceQuery(plan));
6346
+ const visibleRows = rows.slice(0, plan.limit);
6347
+ if (plan.result === "groups") {
6348
+ const groups = visibleRows.map((row) => ({ threadId: String(row.threadId) }));
6349
+ const last = groups.at(-1);
6350
+ return _mastra_core_storage.traceQueryResponseSchema.parse({
6351
+ groups,
6352
+ page: { next: rows.length > plan.limit && last ? _mastra_core_storage.encodeTraceQueryCursor(plan, {
6353
+ result: "groups",
6354
+ threadId: last.threadId
6355
+ }) : null }
6356
+ });
6357
+ }
6358
+ const traces = visibleRows.map((row) => ({
6359
+ traceId: String(row.traceId),
6360
+ rootSpanId: String(row.rootSpanId),
6361
+ threadId: row.threadId == null ? null : String(row.threadId),
6362
+ resourceId: row.resourceId == null ? null : String(row.resourceId),
6363
+ startedAt: asIsoTimestamp(row.startedAt),
6364
+ endedAt: asIsoTimestamp(row.endedAt),
6365
+ entityName: row.entityName == null ? null : String(row.entityName),
6366
+ entityType: row.entityType == null ? null : String(row.entityType),
6367
+ environment: row.environment == null ? null : String(row.environment),
6368
+ status: row.status
6369
+ }));
6370
+ const last = traces.at(-1);
6371
+ return _mastra_core_storage.traceQueryResponseSchema.parse({
6372
+ traces,
6373
+ page: { next: rows.length > plan.limit && last ? _mastra_core_storage.encodeTraceQueryCursor(plan, {
6374
+ result: "traces",
6375
+ sortValue: last[plan.orderBy.field],
6376
+ traceId: last.traceId
6377
+ }) : null }
6378
+ });
6379
+ }
6380
+ //#endregion
6095
6381
  //#region src/storage/domains/observability/v-next/trace-roots.ts
6096
6382
  /**
6097
6383
  * Get the root span for a trace, reading from trace_roots as compatibility path.
@@ -7034,6 +7320,7 @@ var ObservabilityStorageClickhouseVNext = class extends _mastra_core_storage.Obs
7034
7320
  #retention;
7035
7321
  #replication;
7036
7322
  #deltaCursorStrategyOverride;
7323
+ #traceQueryTimeoutMs;
7037
7324
  #deltaCursorStrategy = "fallback";
7038
7325
  constructor(config) {
7039
7326
  super();
@@ -7042,6 +7329,7 @@ var ObservabilityStorageClickhouseVNext = class extends _mastra_core_storage.Obs
7042
7329
  this.#replication = replication;
7043
7330
  this.#retention = config.retention;
7044
7331
  this.#deltaCursorStrategyOverride = config.deltaCursorStrategy;
7332
+ this.#traceQueryTimeoutMs = _mastra_core_storage.resolveTraceQueryTimeoutMs(config.traceQueryTimeoutMs);
7045
7333
  }
7046
7334
  async init() {
7047
7335
  const migrationStatus = await checkSignalTablesMigrationStatus(this.#client);
@@ -7145,11 +7433,16 @@ var ObservabilityStorageClickhouseVNext = class extends _mastra_core_storage.Obs
7145
7433
  };
7146
7434
  }
7147
7435
  getFeatures() {
7148
- if (!deltaPollingSupported(this.#deltaCursorStrategy)) return ["metrics", "logs"];
7436
+ if (!deltaPollingSupported(this.#deltaCursorStrategy)) return [
7437
+ "metrics",
7438
+ "logs",
7439
+ "trace-query"
7440
+ ];
7149
7441
  return [
7150
7442
  "metrics",
7151
7443
  "logs",
7152
- "delta-polling"
7444
+ "delta-polling",
7445
+ "trace-query"
7153
7446
  ];
7154
7447
  }
7155
7448
  async createSpan(args) {
@@ -7264,6 +7557,18 @@ var ObservabilityStorageClickhouseVNext = class extends _mastra_core_storage.Obs
7264
7557
  }, error);
7265
7558
  }
7266
7559
  }
7560
+ async queryTraces(plan) {
7561
+ try {
7562
+ return await queryTraces(this.#client, plan, this.#traceQueryTimeoutMs);
7563
+ } catch (error) {
7564
+ if (error instanceof _mastra_core_error.MastraError || error instanceof _mastra_core_storage.TraceQueryExecutionError) throw error;
7565
+ throw new _mastra_core_error.MastraError({
7566
+ id: (0, _mastra_core_storage.createStorageErrorId)("CLICKHOUSE", "QUERY_TRACES", "FAILED"),
7567
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
7568
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY
7569
+ }, error);
7570
+ }
7571
+ }
7267
7572
  async listTracesLight(args) {
7268
7573
  try {
7269
7574
  return await listTracesLight(this.#client, args, this.#deltaCursorStrategy);
@@ -8540,7 +8845,8 @@ var ClickhouseStoreVNext = class extends ClickhouseStore {
8540
8845
  this.name = "ClickhouseStoreVNext";
8541
8846
  const observability = new ObservabilityStorageClickhouseVNext({
8542
8847
  client: this.db,
8543
- replication: config.replication
8848
+ replication: config.replication,
8849
+ traceQueryTimeoutMs: config.traceQueryTimeoutMs
8544
8850
  });
8545
8851
  this.stores = {
8546
8852
  ...this.stores,