@mastra/spanner 1.7.0 → 1.8.0-alpha.1

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.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Spanner } from "@google-cloud/spanner";
2
2
  import { ErrorCategory, ErrorDomain, MastraError } from "@mastra/core/error";
3
- import { AGENTS_SCHEMA, AGENT_VERSIONS_SCHEMA, AgentsStorage, BackgroundTasksStorage, BlobStore, ChannelsStorage, DatasetsStorage, ExperimentsStorage, FavoritesStorage, MCPClientsStorage, MCPServersStorage, MCP_CLIENTS_SCHEMA, MCP_CLIENT_VERSIONS_SCHEMA, MCP_SERVERS_SCHEMA, MCP_SERVER_VERSIONS_SCHEMA, METRIC_DISTINCT_COLUMNS, MastraCompositeStore, MemoryStorage, ObservabilityStorage, PROMPT_BLOCKS_SCHEMA, PROMPT_BLOCK_VERSIONS_SCHEMA, PromptBlocksStorage, SCORER_DEFINITIONS_SCHEMA, SCORER_DEFINITION_VERSIONS_SCHEMA, SKILLS_SCHEMA, SKILL_BLOBS_SCHEMA, SKILL_VERSIONS_SCHEMA, SchedulesStorage, ScorerDefinitionsStorage, ScoresStorage, SkillsStorage, TABLE_AGENTS, TABLE_AGENT_VERSIONS, TABLE_BACKGROUND_TASKS, TABLE_CHANNEL_CONFIG, TABLE_CHANNEL_INSTALLATIONS, TABLE_CONFIGS, TABLE_DATASETS, TABLE_DATASET_ITEMS, TABLE_DATASET_VERSIONS, TABLE_EXPERIMENTS, TABLE_EXPERIMENT_RESULTS, TABLE_FAVORITES, TABLE_MCP_CLIENTS, TABLE_MCP_CLIENT_VERSIONS, TABLE_MCP_SERVERS, TABLE_MCP_SERVER_VERSIONS, TABLE_MESSAGES, TABLE_PROMPT_BLOCKS, TABLE_PROMPT_BLOCK_VERSIONS, TABLE_RESOURCES, TABLE_SCHEDULES, TABLE_SCHEDULE_TRIGGERS, TABLE_SCHEMAS, TABLE_SCORERS, TABLE_SCORER_DEFINITIONS, TABLE_SCORER_DEFINITION_VERSIONS, TABLE_SKILLS, TABLE_SKILL_BLOBS, TABLE_SKILL_VERSIONS, TABLE_SPANS, TABLE_THREADS, TABLE_WORKFLOW_DEFINITIONS, TABLE_WORKFLOW_SNAPSHOT, TABLE_WORKSPACES, TABLE_WORKSPACE_VERSIONS, TraceStatus, WORKFLOW_DEFINITIONS_SCHEMA, WORKSPACES_SCHEMA, WORKSPACE_VERSIONS_SCHEMA, WorkflowDefinitionsStorage, WorkflowsStorage, WorkspacesStorage, calculatePagination, createStorageErrorId, getDefaultValue, hasErrorCode, listMetricsArgsSchema, listTracesArgsSchema, matchesExpectedWorkflowStatus, normalizePerPage, normalizeScheduleTarget, toTraceSpans, transformScoreRow, validateStorageMetadataFilter } from "@mastra/core/storage";
3
+ import { AGENTS_SCHEMA, AGENT_VERSIONS_SCHEMA, AgentsStorage, BackgroundTasksStorage, BlobStore, ChannelsStorage, DatasetsStorage, ExperimentsStorage, FavoritesStorage, MCPClientsStorage, MCPServersStorage, MCP_CLIENTS_SCHEMA, MCP_CLIENT_VERSIONS_SCHEMA, MCP_SERVERS_SCHEMA, MCP_SERVER_VERSIONS_SCHEMA, METRIC_DISTINCT_COLUMNS, MastraCompositeStore, MemoryStorage, ObservabilityStorage, PROMPT_BLOCKS_SCHEMA, PROMPT_BLOCK_VERSIONS_SCHEMA, PromptBlocksStorage, SCORER_DEFINITIONS_SCHEMA, SCORER_DEFINITION_VERSIONS_SCHEMA, SKILLS_SCHEMA, SKILL_BLOBS_SCHEMA, SKILL_VERSIONS_SCHEMA, SchedulesStorage, ScorerDefinitionsStorage, ScoresStorage, SkillsStorage, TABLE_AGENTS, TABLE_AGENT_VERSIONS, TABLE_BACKGROUND_TASKS, TABLE_CHANNEL_CONFIG, TABLE_CHANNEL_INSTALLATIONS, TABLE_CONFIGS, TABLE_DATASETS, TABLE_DATASET_ITEMS, TABLE_DATASET_VERSIONS, TABLE_EXPERIMENTS, TABLE_EXPERIMENT_RESULTS, TABLE_FAVORITES, TABLE_MCP_CLIENTS, TABLE_MCP_CLIENT_VERSIONS, TABLE_MCP_SERVERS, TABLE_MCP_SERVER_VERSIONS, TABLE_MESSAGES, TABLE_PROMPT_BLOCKS, TABLE_PROMPT_BLOCK_VERSIONS, TABLE_RESOURCES, TABLE_SCHEDULES, TABLE_SCHEDULE_TRIGGERS, TABLE_SCHEMAS, TABLE_SCORERS, TABLE_SCORER_DEFINITIONS, TABLE_SCORER_DEFINITION_VERSIONS, TABLE_SKILLS, TABLE_SKILL_BLOBS, TABLE_SKILL_VERSIONS, TABLE_SPANS, TABLE_THREADS, TABLE_WORKFLOW_DEFINITIONS, TABLE_WORKFLOW_SNAPSHOT, TABLE_WORKSPACES, TABLE_WORKSPACE_VERSIONS, TraceStatus, WORKFLOW_DEFINITIONS_SCHEMA, WORKSPACES_SCHEMA, WORKSPACE_VERSIONS_SCHEMA, WorkflowDefinitionsStorage, WorkflowsStorage, WorkspacesStorage, calculatePagination, createStorageErrorId, executeRetentionPrune, getDefaultValue, hasErrorCode, listMetricsArgsSchema, listTracesArgsSchema, matchesExpectedWorkflowStatus, normalizePerPage, normalizeScheduleTarget, resolveListOrderBy, resolveRetentionTargets, retentionCutoffMs, toTraceSpans, transformScoreRow, validateStorageMetadataFilter } from "@mastra/core/storage";
4
4
  import { MastraBase } from "@mastra/core/base";
5
5
  import { parseSqlIdentifier } from "@mastra/core/utils";
6
6
  import { randomUUID } from "crypto";
@@ -3173,6 +3173,14 @@ var DatasetsSpanner = class DatasetsSpanner extends DatasetsStorage {
3173
3173
  }
3174
3174
  }
3175
3175
  async listDatasets(args) {
3176
+ const orderBy = resolveListOrderBy(args.orderBy, [
3177
+ "createdAt",
3178
+ "updatedAt",
3179
+ "name"
3180
+ ], {
3181
+ field: "createdAt",
3182
+ direction: "DESC"
3183
+ });
3176
3184
  const { page = 0, perPage: perPageInput } = args.pagination;
3177
3185
  const perPage = normalizePerPage(perPageInput, 100);
3178
3186
  const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
@@ -3232,7 +3240,7 @@ var DatasetsSpanner = class DatasetsSpanner extends DatasetsStorage {
3232
3240
  const limit = perPageInput === false ? total : perPage;
3233
3241
  const [rows] = await this.database.run({
3234
3242
  sql: `SELECT * FROM ${tableName} ${whereClause}
3235
- ORDER BY ${quoteIdent("createdAt", "column name")} DESC, ${quoteIdent("id", "column name")} ASC
3243
+ ORDER BY ${quoteIdent(orderBy.field, "column name")} ${orderBy.direction}, ${quoteIdent("id", "column name")} ASC
3236
3244
  LIMIT @limit OFFSET @offset`,
3237
3245
  params: {
3238
3246
  ...filterParams,
@@ -3670,6 +3678,10 @@ var DatasetsSpanner = class DatasetsSpanner extends DatasetsStorage {
3670
3678
  }
3671
3679
  }
3672
3680
  async listItems(args) {
3681
+ const orderBy = resolveListOrderBy(args.orderBy, ["createdAt", "updatedAt"], {
3682
+ field: "createdAt",
3683
+ direction: "DESC"
3684
+ });
3673
3685
  const { page = 0, perPage: perPageInput } = args.pagination;
3674
3686
  const perPage = normalizePerPage(perPageInput, 100);
3675
3687
  const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
@@ -3717,7 +3729,7 @@ var DatasetsSpanner = class DatasetsSpanner extends DatasetsStorage {
3717
3729
  const limit = perPageInput === false ? total : perPage;
3718
3730
  const [rows] = await this.database.run({
3719
3731
  sql: `SELECT * FROM ${tableName} ${whereSql}
3720
- ORDER BY ${quoteIdent("createdAt", "column name")} DESC, ${quoteIdent("id", "column name")} ASC
3732
+ ORDER BY ${quoteIdent(orderBy.field, "column name")} ${orderBy.direction}, ${quoteIdent("id", "column name")} ASC
3721
3733
  LIMIT @limit OFFSET @offset`,
3722
3734
  params: {
3723
3735
  ...params,
@@ -4450,6 +4462,10 @@ var ExperimentsSpanner = class ExperimentsSpanner extends ExperimentsStorage {
4450
4462
  }
4451
4463
  }
4452
4464
  async listExperiments(args) {
4465
+ const orderBy = resolveListOrderBy(args.orderBy, ["createdAt", "status"], {
4466
+ field: "createdAt",
4467
+ direction: "DESC"
4468
+ });
4453
4469
  const { page = 0, perPage: perPageInput } = args.pagination;
4454
4470
  const perPage = normalizePerPage(perPageInput, 100);
4455
4471
  const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
@@ -4523,7 +4539,7 @@ var ExperimentsSpanner = class ExperimentsSpanner extends ExperimentsStorage {
4523
4539
  const limit = perPageInput === false ? total : perPage;
4524
4540
  const [rows] = await this.database.run({
4525
4541
  sql: `SELECT * FROM ${tableName} ${whereSql}
4526
- ORDER BY ${quoteIdent("createdAt", "column name")} DESC
4542
+ ORDER BY ${quoteIdent(orderBy.field, "column name")} ${orderBy.direction}, ${quoteIdent("id", "column name")} ASC
4527
4543
  LIMIT @limit OFFSET @offset`,
4528
4544
  params: {
4529
4545
  ...params,
@@ -4911,6 +4927,10 @@ var ExperimentsSpanner = class ExperimentsSpanner extends ExperimentsStorage {
4911
4927
  }
4912
4928
  }
4913
4929
  async listExperimentResults(args) {
4930
+ const orderBy = resolveListOrderBy(args.orderBy, ["startedAt", "createdAt"], {
4931
+ field: "startedAt",
4932
+ direction: "ASC"
4933
+ });
4914
4934
  const { page = 0, perPage: perPageInput } = args.pagination;
4915
4935
  const perPage = normalizePerPage(perPageInput, 100);
4916
4936
  const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
@@ -4962,7 +4982,7 @@ var ExperimentsSpanner = class ExperimentsSpanner extends ExperimentsStorage {
4962
4982
  const limit = perPageInput === false ? total : perPage;
4963
4983
  const [rows] = await this.database.run({
4964
4984
  sql: `SELECT * FROM ${tableName} ${whereSql}
4965
- ORDER BY ${quoteIdent("startedAt", "column name")} ASC
4985
+ ORDER BY ${quoteIdent(orderBy.field, "column name")} ${orderBy.direction}, ${quoteIdent("id", "column name")} ASC
4966
4986
  LIMIT @limit OFFSET @offset`,
4967
4987
  params: {
4968
4988
  ...params,
@@ -8861,6 +8881,18 @@ function invalidTraceFilterKey(kind, key) {
8861
8881
  * waterfall view, and root-span pagination with the listTraces filters.
8862
8882
  */
8863
8883
  var ObservabilitySpanner = class ObservabilitySpanner extends ObservabilityStorage {
8884
+ static retentionTables = {
8885
+ spans: {
8886
+ table: TABLE_SPANS,
8887
+ column: "startedAt",
8888
+ indexed: false
8889
+ },
8890
+ metrics: {
8891
+ table: TABLE_AI_METRICS,
8892
+ column: "timestamp",
8893
+ indexed: false
8894
+ }
8895
+ };
8864
8896
  database;
8865
8897
  db;
8866
8898
  skipDefaultIndexes;
@@ -8895,6 +8927,50 @@ var ObservabilitySpanner = class ObservabilitySpanner extends ObservabilityStora
8895
8927
  this.disableMetrics = disableMetrics ?? true;
8896
8928
  this.indexes = indexes?.filter((idx) => ObservabilitySpanner.MANAGED_TABLES.includes(idx.table));
8897
8929
  }
8930
+ async prune(policies, options) {
8931
+ return executeRetentionPrune({
8932
+ domain: "observability",
8933
+ targets: resolveRetentionTargets({
8934
+ policies,
8935
+ descriptor: this.disableMetrics ? { spans: {
8936
+ table: TABLE_SPANS,
8937
+ column: "startedAt",
8938
+ indexed: false
8939
+ } } : ObservabilitySpanner.retentionTables,
8940
+ order: ["spans", "metrics"]
8941
+ }),
8942
+ options,
8943
+ cutoffFor: (target, now) => new Date(retentionCutoffMs(target.policy, now)).toISOString(),
8944
+ deleteBatch: async (target, cutoff, limit) => {
8945
+ const table = quoteIdent(target.table, "table name");
8946
+ const column = quoteIdent(target.column, "column name");
8947
+ const keyPredicate = target.table === TABLE_SPANS ? `(traceId, spanId) IN (SELECT AS STRUCT traceId, spanId FROM ${table} WHERE ${column} < @cutoff ORDER BY ${column} LIMIT @limit)` : `metricId IN (SELECT metricId FROM ${table} WHERE ${column} < @cutoff ORDER BY ${column} LIMIT @limit)`;
8948
+ return this.db.runWithAbortRetry(async () => {
8949
+ let deleted = 0;
8950
+ await this.database.runTransactionAsync(async (tx) => {
8951
+ try {
8952
+ const [count] = await tx.runUpdate({
8953
+ sql: `DELETE FROM ${table} WHERE ${keyPredicate}`,
8954
+ params: {
8955
+ cutoff,
8956
+ limit
8957
+ },
8958
+ types: { cutoff: "timestamp" }
8959
+ });
8960
+ deleted = Number(count ?? 0);
8961
+ await tx.commit();
8962
+ } catch (error) {
8963
+ await tx.rollback().catch((rollbackError) => {
8964
+ throw new AggregateError([error, rollbackError], "Transaction and rollback both failed");
8965
+ });
8966
+ throw error;
8967
+ }
8968
+ });
8969
+ return deleted;
8970
+ });
8971
+ }
8972
+ });
8973
+ }
8898
8974
  /** Build the read-options object that every metrics read path threads through. */
8899
8975
  readOptions() {
8900
8976
  return { stalenessMs: this.dashboardStalenessMs };
@@ -13370,7 +13446,8 @@ var SpannerStore = class extends MastraCompositeStore {
13370
13446
  super({
13371
13447
  id: config.id,
13372
13448
  name: "SpannerStore",
13373
- disableInit: config.disableInit
13449
+ disableInit: config.disableInit,
13450
+ retention: config.retention
13374
13451
  });
13375
13452
  try {
13376
13453
  if (isPreConfiguredDatabase(config)) {