@mastra/pg 1.12.1 → 1.13.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.
Files changed (68) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/dist/docs/SKILL.md +1 -1
  3. package/dist/docs/assets/SOURCE_MAP.json +1 -1
  4. package/dist/docs/references/docs-memory-working-memory.md +2 -2
  5. package/dist/docs/references/reference-storage-composite.md +34 -2
  6. package/dist/docs/references/reference-storage-postgresql.md +1 -1
  7. package/dist/index.cjs +3837 -147
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.js +3836 -149
  10. package/dist/index.js.map +1 -1
  11. package/dist/{storage → shared}/pool-config.d.ts +10 -2
  12. package/dist/shared/pool-config.d.ts.map +1 -0
  13. package/dist/storage/domains/agents/index.d.ts.map +1 -1
  14. package/dist/storage/domains/background-tasks/index.d.ts.map +1 -1
  15. package/dist/storage/domains/blobs/index.d.ts +1 -0
  16. package/dist/storage/domains/blobs/index.d.ts.map +1 -1
  17. package/dist/storage/domains/mcp-clients/index.d.ts +2 -0
  18. package/dist/storage/domains/mcp-clients/index.d.ts.map +1 -1
  19. package/dist/storage/domains/mcp-servers/index.d.ts +2 -0
  20. package/dist/storage/domains/mcp-servers/index.d.ts.map +1 -1
  21. package/dist/storage/domains/observability/v-next/ddl.d.ts +55 -0
  22. package/dist/storage/domains/observability/v-next/ddl.d.ts.map +1 -0
  23. package/dist/storage/domains/observability/v-next/discovery.d.ts +52 -0
  24. package/dist/storage/domains/observability/v-next/discovery.d.ts.map +1 -0
  25. package/dist/storage/domains/observability/v-next/feedback.d.ts +17 -0
  26. package/dist/storage/domains/observability/v-next/feedback.d.ts.map +1 -0
  27. package/dist/storage/domains/observability/v-next/filters.d.ts +29 -0
  28. package/dist/storage/domains/observability/v-next/filters.d.ts.map +1 -0
  29. package/dist/storage/domains/observability/v-next/helpers.d.ts +33 -0
  30. package/dist/storage/domains/observability/v-next/helpers.d.ts.map +1 -0
  31. package/dist/storage/domains/observability/v-next/index.d.ts +104 -0
  32. package/dist/storage/domains/observability/v-next/index.d.ts.map +1 -0
  33. package/dist/storage/domains/observability/v-next/listing.d.ts +53 -0
  34. package/dist/storage/domains/observability/v-next/listing.d.ts.map +1 -0
  35. package/dist/storage/domains/observability/v-next/logs.d.ts +8 -0
  36. package/dist/storage/domains/observability/v-next/logs.d.ts.map +1 -0
  37. package/dist/storage/domains/observability/v-next/metrics.d.ts +19 -0
  38. package/dist/storage/domains/observability/v-next/metrics.d.ts.map +1 -0
  39. package/dist/storage/domains/observability/v-next/olap.d.ts +93 -0
  40. package/dist/storage/domains/observability/v-next/olap.d.ts.map +1 -0
  41. package/dist/storage/domains/observability/v-next/partitioning.d.ts +76 -0
  42. package/dist/storage/domains/observability/v-next/partitioning.d.ts.map +1 -0
  43. package/dist/storage/domains/observability/v-next/pg-errors.d.ts +25 -0
  44. package/dist/storage/domains/observability/v-next/pg-errors.d.ts.map +1 -0
  45. package/dist/storage/domains/observability/v-next/polling.d.ts +28 -0
  46. package/dist/storage/domains/observability/v-next/polling.d.ts.map +1 -0
  47. package/dist/storage/domains/observability/v-next/scores.d.ts +17 -0
  48. package/dist/storage/domains/observability/v-next/scores.d.ts.map +1 -0
  49. package/dist/storage/domains/observability/v-next/signal-schema.d.ts +776 -0
  50. package/dist/storage/domains/observability/v-next/signal-schema.d.ts.map +1 -0
  51. package/dist/storage/domains/observability/v-next/sql.d.ts +31 -0
  52. package/dist/storage/domains/observability/v-next/sql.d.ts.map +1 -0
  53. package/dist/storage/domains/observability/v-next/traces.d.ts +16 -0
  54. package/dist/storage/domains/observability/v-next/traces.d.ts.map +1 -0
  55. package/dist/storage/domains/observability/v-next/tracing.d.ts +19 -0
  56. package/dist/storage/domains/observability/v-next/tracing.d.ts.map +1 -0
  57. package/dist/storage/domains/skills/index.d.ts +2 -0
  58. package/dist/storage/domains/skills/index.d.ts.map +1 -1
  59. package/dist/storage/domains/tool-provider-connections/index.d.ts +20 -0
  60. package/dist/storage/domains/tool-provider-connections/index.d.ts.map +1 -0
  61. package/dist/storage/domains/workflows/index.d.ts.map +1 -1
  62. package/dist/storage/domains/workspaces/index.d.ts +2 -0
  63. package/dist/storage/domains/workspaces/index.d.ts.map +1 -1
  64. package/dist/storage/index.d.ts +89 -1
  65. package/dist/storage/index.d.ts.map +1 -1
  66. package/dist/vector/index.d.ts.map +1 -1
  67. package/package.json +9 -7
  68. package/dist/storage/pool-config.d.ts.map +0 -1
package/dist/index.cjs CHANGED
@@ -7,13 +7,14 @@ var vector = require('@mastra/core/vector');
7
7
  var asyncMutex = require('async-mutex');
8
8
  var pg = require('pg');
9
9
  var xxhash = require('xxhash-wasm');
10
+ var pgConnectionString = require('pg-connection-string');
10
11
  var filter = require('@mastra/core/vector/filter');
11
12
  var base = require('@mastra/core/base');
12
13
  var crypto$1 = require('crypto');
13
14
  var module$1 = require('module');
14
15
  var agent = require('@mastra/core/agent');
16
+ var features = require('@mastra/core/features');
15
17
  var evals = require('@mastra/core/evals');
16
- var pgConnectionString = require('pg-connection-string');
17
18
 
18
19
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
19
20
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -90,6 +91,15 @@ var validateConfig = (name, config) => {
90
91
  );
91
92
  }
92
93
  };
94
+ function buildConnectionStringPoolConfig(config, defaults) {
95
+ const parsed = pgConnectionString.parse(config.connectionString);
96
+ return {
97
+ ...parsed,
98
+ ...config.ssl !== void 0 ? { ssl: config.ssl } : {},
99
+ max: config.max ?? defaults.max,
100
+ idleTimeoutMillis: config.idleTimeoutMillis ?? defaults.idleTimeoutMillis
101
+ };
102
+ }
93
103
  var PGFilterTranslator = class extends filter.BaseFilterTranslator {
94
104
  getSupportedOperators() {
95
105
  return {
@@ -637,10 +647,7 @@ var PgVector = class extends vector.MastraVector {
637
647
  let poolConfig;
638
648
  if (isConnectionStringConfig(config)) {
639
649
  poolConfig = {
640
- connectionString: config.connectionString,
641
- ssl: config.ssl,
642
- max: config.max ?? 20,
643
- idleTimeoutMillis: config.idleTimeoutMillis ?? 3e4,
650
+ ...buildConnectionStringPoolConfig(config, { max: 20, idleTimeoutMillis: 3e4 }),
644
651
  connectionTimeoutMillis: 2e3,
645
652
  ...config.pgPoolOptions
646
653
  };
@@ -3554,7 +3561,15 @@ var AgentsPG = class _AgentsPG extends storage.AgentsStorage {
3554
3561
  await this.#db.alterTable({
3555
3562
  tableName: storage.TABLE_AGENT_VERSIONS,
3556
3563
  schema: storage.TABLE_SCHEMAS[storage.TABLE_AGENT_VERSIONS],
3557
- ifNotExists: ["mcpClients", "requestContextSchema", "workspace", "skills", "skillsFormat", "browser"]
3564
+ ifNotExists: [
3565
+ "mcpClients",
3566
+ "requestContextSchema",
3567
+ "workspace",
3568
+ "skills",
3569
+ "skillsFormat",
3570
+ "browser",
3571
+ "toolProviders"
3572
+ ]
3558
3573
  });
3559
3574
  await this.#migrateToolsToJsonbFormat();
3560
3575
  await this.createDefaultIndexes();
@@ -3607,9 +3622,9 @@ var AgentsPG = class _AgentsPG extends storage.AgentsStorage {
3607
3622
  await this.#db.client.none(
3608
3623
  `INSERT INTO ${fullVersionsTableName}
3609
3624
  (id, "agentId", "versionNumber", name, description, instructions, model, tools,
3610
- "defaultOptions", workflows, agents, "integrationTools", "inputProcessors",
3625
+ "defaultOptions", workflows, agents, "integrationTools", "toolProviders", "inputProcessors",
3611
3626
  "outputProcessors", memory, scorers, "changedFields", "changeMessage", "createdAt")
3612
- VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19)
3627
+ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20)
3613
3628
  ON CONFLICT (id) DO NOTHING`,
3614
3629
  [
3615
3630
  versionId,
@@ -3624,6 +3639,7 @@ var AgentsPG = class _AgentsPG extends storage.AgentsStorage {
3624
3639
  row.workflows ? JSON.stringify(row.workflows) : null,
3625
3640
  row.agents ? JSON.stringify(row.agents) : null,
3626
3641
  row.integrationTools ? JSON.stringify(row.integrationTools) : null,
3642
+ row.toolProviders ? JSON.stringify(row.toolProviders) : null,
3627
3643
  row.inputProcessors ? JSON.stringify(row.inputProcessors) : null,
3628
3644
  row.outputProcessors ? JSON.stringify(row.outputProcessors) : null,
3629
3645
  row.memory ? JSON.stringify(row.memory) : null,
@@ -4076,13 +4092,13 @@ var AgentsPG = class _AgentsPG extends storage.AgentsStorage {
4076
4092
  `INSERT INTO ${tableName} (
4077
4093
  id, "agentId", "versionNumber",
4078
4094
  name, description, instructions, model, tools,
4079
- "defaultOptions", workflows, agents, "integrationTools",
4095
+ "defaultOptions", workflows, agents, "integrationTools", "toolProviders",
4080
4096
  "inputProcessors", "outputProcessors", memory, scorers,
4081
4097
  "mcpClients", "requestContextSchema", workspace, skills, "skillsFormat",
4082
4098
  browser,
4083
4099
  "changedFields", "changeMessage",
4084
4100
  "createdAt", "createdAtZ"
4085
- ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26)`,
4101
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27)`,
4086
4102
  [
4087
4103
  input.id,
4088
4104
  input.agentId,
@@ -4096,6 +4112,7 @@ var AgentsPG = class _AgentsPG extends storage.AgentsStorage {
4096
4112
  input.workflows ? JSON.stringify(input.workflows) : null,
4097
4113
  input.agents ? JSON.stringify(input.agents) : null,
4098
4114
  input.integrationTools ? JSON.stringify(input.integrationTools) : null,
4115
+ input.toolProviders ? JSON.stringify(input.toolProviders) : null,
4099
4116
  input.inputProcessors ? JSON.stringify(input.inputProcessors) : null,
4100
4117
  input.outputProcessors ? JSON.stringify(input.outputProcessors) : null,
4101
4118
  input.memory ? JSON.stringify(input.memory) : null,
@@ -4346,6 +4363,7 @@ var AgentsPG = class _AgentsPG extends storage.AgentsStorage {
4346
4363
  workflows: parseJsonResilient(row.workflows),
4347
4364
  agents: parseJsonResilient(row.agents),
4348
4365
  integrationTools: parseJsonResilient(row.integrationTools),
4366
+ toolProviders: parseJsonResilient(row.toolProviders),
4349
4367
  inputProcessors: parseJsonResilient(row.inputProcessors),
4350
4368
  outputProcessors: parseJsonResilient(row.outputProcessors),
4351
4369
  memory: parseJsonResilient(row.memory),
@@ -4384,6 +4402,10 @@ function parseJson(v) {
4384
4402
  return v ?? void 0;
4385
4403
  }
4386
4404
  function rowToTask(row) {
4405
+ const createdAt = row.createdAtZ || row.createdAt;
4406
+ const startedAt = row.startedAtZ || row.startedAt;
4407
+ const suspendedAt = row.suspendedAtZ || row.suspendedAt;
4408
+ const completedAt = row.completedAtZ || row.completedAt;
4387
4409
  return {
4388
4410
  id: row.id,
4389
4411
  status: row.status,
@@ -4400,10 +4422,10 @@ function rowToTask(row) {
4400
4422
  retryCount: Number(row.retry_count),
4401
4423
  maxRetries: Number(row.max_retries),
4402
4424
  timeoutMs: Number(row.timeout_ms),
4403
- createdAt: new Date(row.createdAtZ || row.createdAt),
4404
- startedAt: row.startedAtZ || row.startedAt ? new Date(row.startedAtZ || row.startedAt) : void 0,
4405
- suspendedAt: row.suspendedAtZ || row.suspendedAt ? new Date(row.suspendedAtZ || row.suspendedAt) : void 0,
4406
- completedAt: row.completedAtZ || row.completedAt ? new Date(row.completedAtZ || row.completedAt) : void 0
4425
+ createdAt: createdAt instanceof Date ? createdAt : new Date(createdAt),
4426
+ startedAt: startedAt ? startedAt instanceof Date ? startedAt : new Date(startedAt) : void 0,
4427
+ suspendedAt: suspendedAt ? suspendedAt instanceof Date ? suspendedAt : new Date(suspendedAt) : void 0,
4428
+ completedAt: completedAt ? completedAt instanceof Date ? completedAt : new Date(completedAt) : void 0
4407
4429
  };
4408
4430
  }
4409
4431
  var BackgroundTasksPG = class _BackgroundTasksPG extends storage.BackgroundTasksStorage {
@@ -4521,9 +4543,13 @@ var BackgroundTasksPG = class _BackgroundTasksPG extends storage.BackgroundTasks
4521
4543
  max_retries: task.maxRetries,
4522
4544
  timeout_ms: task.timeoutMs,
4523
4545
  createdAt: task.createdAt.toISOString(),
4546
+ createdAtZ: task.createdAt.toISOString(),
4524
4547
  startedAt: task.startedAt?.toISOString() ?? null,
4548
+ startedAtZ: task.startedAt?.toISOString() ?? null,
4525
4549
  suspendedAt: task.suspendedAt?.toISOString() ?? null,
4526
- completedAt: task.completedAt?.toISOString() ?? null
4550
+ suspendedAtZ: task.suspendedAt?.toISOString() ?? null,
4551
+ completedAt: task.completedAt?.toISOString() ?? null,
4552
+ completedAtZ: task.completedAt?.toISOString() ?? null
4527
4553
  }
4528
4554
  });
4529
4555
  }
@@ -4700,6 +4726,16 @@ var BlobsPG = class extends storage.BlobStore {
4700
4726
  this.#db = new PgDB({ client, schemaName, skipDefaultIndexes });
4701
4727
  this.#schema = schemaName || "public";
4702
4728
  }
4729
+ static getExportDDL(schemaName) {
4730
+ return [
4731
+ generateTableSQL({
4732
+ tableName: storage.TABLE_SKILL_BLOBS,
4733
+ schema: storage.TABLE_SCHEMAS[storage.TABLE_SKILL_BLOBS],
4734
+ schemaName,
4735
+ includeAllConstraints: true
4736
+ })
4737
+ ];
4738
+ }
4703
4739
  async init() {
4704
4740
  await this.#db.createTable({
4705
4741
  tableName: storage.TABLE_SKILL_BLOBS,
@@ -6778,16 +6814,39 @@ var MCPClientsPG = class _MCPClientsPG extends storage.MCPClientsStorage {
6778
6814
  this.#skipDefaultIndexes = skipDefaultIndexes;
6779
6815
  this.#indexes = indexes?.filter((idx) => _MCPClientsPG.MANAGED_TABLES.includes(idx.table));
6780
6816
  }
6781
- getDefaultIndexDefinitions() {
6817
+ static getDefaultIndexDefs(schemaPrefix) {
6782
6818
  return [
6783
6819
  {
6784
- name: "idx_mcp_client_versions_client_version",
6820
+ name: `${schemaPrefix}idx_mcp_client_versions_client_version`,
6785
6821
  table: storage.TABLE_MCP_CLIENT_VERSIONS,
6786
6822
  columns: ["mcpClientId", "versionNumber"],
6787
6823
  unique: true
6788
6824
  }
6789
6825
  ];
6790
6826
  }
6827
+ static getExportDDL(schemaName) {
6828
+ const statements = [];
6829
+ const parsedSchema = schemaName ? utils.parseSqlIdentifier(schemaName, "schema name") : "";
6830
+ const schemaPrefix = parsedSchema && parsedSchema !== "public" ? `${parsedSchema}_` : "";
6831
+ for (const tableName of _MCPClientsPG.MANAGED_TABLES) {
6832
+ statements.push(
6833
+ generateTableSQL({
6834
+ tableName,
6835
+ schema: storage.TABLE_SCHEMAS[tableName],
6836
+ schemaName,
6837
+ includeAllConstraints: true
6838
+ })
6839
+ );
6840
+ }
6841
+ for (const idx of _MCPClientsPG.getDefaultIndexDefs(schemaPrefix)) {
6842
+ statements.push(generateIndexSQL(idx, schemaName));
6843
+ }
6844
+ return statements;
6845
+ }
6846
+ getDefaultIndexDefinitions() {
6847
+ const schemaPrefix = this.#schema !== "public" ? `${this.#schema}_` : "";
6848
+ return _MCPClientsPG.getDefaultIndexDefs(schemaPrefix);
6849
+ }
6791
6850
  async createDefaultIndexes() {
6792
6851
  if (this.#skipDefaultIndexes) {
6793
6852
  return;
@@ -7391,16 +7450,39 @@ var MCPServersPG = class _MCPServersPG extends storage.MCPServersStorage {
7391
7450
  this.#skipDefaultIndexes = skipDefaultIndexes;
7392
7451
  this.#indexes = indexes?.filter((idx) => _MCPServersPG.MANAGED_TABLES.includes(idx.table));
7393
7452
  }
7394
- getDefaultIndexDefinitions() {
7453
+ static getDefaultIndexDefs(schemaPrefix) {
7395
7454
  return [
7396
7455
  {
7397
- name: "idx_mcp_server_versions_server_version",
7456
+ name: `${schemaPrefix}idx_mcp_server_versions_server_version`,
7398
7457
  table: storage.TABLE_MCP_SERVER_VERSIONS,
7399
7458
  columns: ["mcpServerId", "versionNumber"],
7400
7459
  unique: true
7401
7460
  }
7402
7461
  ];
7403
7462
  }
7463
+ static getExportDDL(schemaName) {
7464
+ const statements = [];
7465
+ const parsedSchema = schemaName ? utils.parseSqlIdentifier(schemaName, "schema name") : "";
7466
+ const schemaPrefix = parsedSchema && parsedSchema !== "public" ? `${parsedSchema}_` : "";
7467
+ for (const tableName of _MCPServersPG.MANAGED_TABLES) {
7468
+ statements.push(
7469
+ generateTableSQL({
7470
+ tableName,
7471
+ schema: storage.TABLE_SCHEMAS[tableName],
7472
+ schemaName,
7473
+ includeAllConstraints: true
7474
+ })
7475
+ );
7476
+ }
7477
+ for (const idx of _MCPServersPG.getDefaultIndexDefs(schemaPrefix)) {
7478
+ statements.push(generateIndexSQL(idx, schemaName));
7479
+ }
7480
+ return statements;
7481
+ }
7482
+ getDefaultIndexDefinitions() {
7483
+ const schemaPrefix = this.#schema !== "public" ? `${this.#schema}_` : "";
7484
+ return _MCPServersPG.getDefaultIndexDefs(schemaPrefix);
7485
+ }
7404
7486
  async createDefaultIndexes() {
7405
7487
  if (this.#skipDefaultIndexes) {
7406
7488
  return;
@@ -11463,109 +11545,3348 @@ var ObservabilityPG = class _ObservabilityPG extends storage.ObservabilityStorag
11463
11545
  }
11464
11546
  }
11465
11547
  };
11466
- var SNAPSHOT_FIELDS3 = ["name", "description", "content", "rules", "requestContextSchema"];
11467
- var PromptBlocksPG = class _PromptBlocksPG extends storage.PromptBlocksStorage {
11468
- #db;
11469
- #schema;
11470
- #skipDefaultIndexes;
11471
- #indexes;
11472
- static MANAGED_TABLES = [storage.TABLE_PROMPT_BLOCKS, storage.TABLE_PROMPT_BLOCK_VERSIONS];
11473
- constructor(config) {
11474
- super();
11475
- const { client, schemaName, skipDefaultIndexes, indexes } = resolvePgConfig(config);
11476
- this.#db = new PgDB({ client, schemaName, skipDefaultIndexes });
11477
- this.#schema = schemaName || "public";
11478
- this.#skipDefaultIndexes = skipDefaultIndexes;
11479
- this.#indexes = indexes?.filter((idx) => _PromptBlocksPG.MANAGED_TABLES.includes(idx.table));
11480
- }
11481
- /**
11482
- * Returns default index definitions for the prompt blocks domain tables.
11483
- * @param schemaPrefix - Prefix for index names (e.g. "my_schema_" or "")
11484
- */
11485
- static getDefaultIndexDefs(schemaPrefix) {
11486
- return [
11487
- {
11488
- name: `${schemaPrefix}idx_prompt_block_versions_block_version`,
11489
- table: storage.TABLE_PROMPT_BLOCK_VERSIONS,
11490
- columns: ["blockId", "versionNumber"],
11491
- unique: true
11548
+
11549
+ // src/storage/domains/observability/v-next/signal-schema.ts
11550
+ var CURSOR_ID_COLUMN = { name: "cursorId", type: "bigserial" };
11551
+ var XACT_ID_COLUMN = {
11552
+ name: "xactId",
11553
+ type: "xid8",
11554
+ defaultSql: "pg_current_xact_id()"
11555
+ };
11556
+ var COMMON_CONTEXT_COLUMNS = [
11557
+ { name: "traceId", type: "text", nullable: true },
11558
+ { name: "spanId", type: "text", nullable: true },
11559
+ { name: "experimentId", type: "text", nullable: true },
11560
+ { name: "entityType", type: "text", nullable: true },
11561
+ { name: "entityId", type: "text", nullable: true },
11562
+ { name: "entityName", type: "text", nullable: true },
11563
+ { name: "entityVersionId", type: "text", nullable: true },
11564
+ { name: "parentEntityType", type: "text", nullable: true },
11565
+ { name: "parentEntityId", type: "text", nullable: true },
11566
+ { name: "parentEntityName", type: "text", nullable: true },
11567
+ { name: "parentEntityVersionId", type: "text", nullable: true },
11568
+ { name: "rootEntityType", type: "text", nullable: true },
11569
+ { name: "rootEntityId", type: "text", nullable: true },
11570
+ { name: "rootEntityName", type: "text", nullable: true },
11571
+ { name: "rootEntityVersionId", type: "text", nullable: true },
11572
+ { name: "userId", type: "text", nullable: true },
11573
+ { name: "organizationId", type: "text", nullable: true },
11574
+ { name: "resourceId", type: "text", nullable: true },
11575
+ { name: "runId", type: "text", nullable: true },
11576
+ { name: "sessionId", type: "text", nullable: true },
11577
+ { name: "threadId", type: "text", nullable: true },
11578
+ { name: "requestId", type: "text", nullable: true },
11579
+ { name: "environment", type: "text", nullable: true },
11580
+ { name: "executionSource", type: "text", nullable: true },
11581
+ { name: "serviceName", type: "text", nullable: true }
11582
+ ];
11583
+ var SPAN_EVENT_COLUMNS = [
11584
+ CURSOR_ID_COLUMN,
11585
+ XACT_ID_COLUMN,
11586
+ { name: "traceId", type: "text" },
11587
+ { name: "spanId", type: "text" },
11588
+ { name: "parentSpanId", type: "text", nullable: true },
11589
+ { name: "experimentId", type: "text", nullable: true },
11590
+ { name: "entityType", type: "text", nullable: true },
11591
+ { name: "entityId", type: "text", nullable: true },
11592
+ { name: "entityName", type: "text", nullable: true },
11593
+ { name: "entityVersionId", type: "text", nullable: true },
11594
+ { name: "parentEntityType", type: "text", nullable: true },
11595
+ { name: "parentEntityId", type: "text", nullable: true },
11596
+ { name: "parentEntityName", type: "text", nullable: true },
11597
+ { name: "parentEntityVersionId", type: "text", nullable: true },
11598
+ { name: "rootEntityType", type: "text", nullable: true },
11599
+ { name: "rootEntityId", type: "text", nullable: true },
11600
+ { name: "rootEntityName", type: "text", nullable: true },
11601
+ { name: "rootEntityVersionId", type: "text", nullable: true },
11602
+ { name: "userId", type: "text", nullable: true },
11603
+ { name: "organizationId", type: "text", nullable: true },
11604
+ { name: "resourceId", type: "text", nullable: true },
11605
+ { name: "runId", type: "text", nullable: true },
11606
+ { name: "sessionId", type: "text", nullable: true },
11607
+ { name: "threadId", type: "text", nullable: true },
11608
+ { name: "requestId", type: "text", nullable: true },
11609
+ { name: "environment", type: "text", nullable: true },
11610
+ { name: "executionSource", type: "text", nullable: true },
11611
+ { name: "serviceName", type: "text", nullable: true },
11612
+ { name: "name", type: "text" },
11613
+ { name: "spanType", type: "text" },
11614
+ { name: "isEvent", type: "boolean", defaultSql: "false" },
11615
+ { name: "startedAt", type: "timestamptz" },
11616
+ { name: "endedAt", type: "timestamptz" },
11617
+ { name: "tags", type: "text[]", defaultSql: "'{}'" },
11618
+ { name: "metadataSearch", type: "jsonb", defaultSql: "'{}'::jsonb" },
11619
+ { name: "attributes", type: "jsonb", nullable: true },
11620
+ { name: "scope", type: "jsonb", nullable: true },
11621
+ { name: "links", type: "jsonb", nullable: true },
11622
+ { name: "input", type: "jsonb", nullable: true },
11623
+ { name: "output", type: "jsonb", nullable: true },
11624
+ { name: "error", type: "jsonb", nullable: true },
11625
+ { name: "metadataRaw", type: "jsonb", nullable: true },
11626
+ { name: "requestContext", type: "jsonb", nullable: true }
11627
+ ];
11628
+ var METRIC_EVENT_COLUMNS = [
11629
+ CURSOR_ID_COLUMN,
11630
+ XACT_ID_COLUMN,
11631
+ { name: "metricId", type: "text" },
11632
+ { name: "timestamp", type: "timestamptz" },
11633
+ { name: "name", type: "text" },
11634
+ { name: "value", type: "double precision" },
11635
+ ...COMMON_CONTEXT_COLUMNS,
11636
+ { name: "provider", type: "text", nullable: true },
11637
+ { name: "model", type: "text", nullable: true },
11638
+ { name: "estimatedCost", type: "double precision", nullable: true },
11639
+ { name: "costUnit", type: "text", nullable: true },
11640
+ { name: "tags", type: "text[]", defaultSql: "'{}'" },
11641
+ { name: "labels", type: "jsonb", defaultSql: "'{}'::jsonb" },
11642
+ { name: "costMetadata", type: "jsonb", nullable: true },
11643
+ { name: "metadata", type: "jsonb", nullable: true },
11644
+ { name: "scope", type: "jsonb", nullable: true }
11645
+ ];
11646
+ var LOG_EVENT_COLUMNS = [
11647
+ CURSOR_ID_COLUMN,
11648
+ XACT_ID_COLUMN,
11649
+ { name: "logId", type: "text" },
11650
+ { name: "timestamp", type: "timestamptz" },
11651
+ { name: "level", type: "text" },
11652
+ { name: "message", type: "text" },
11653
+ ...COMMON_CONTEXT_COLUMNS,
11654
+ { name: "tags", type: "text[]", defaultSql: "'{}'" },
11655
+ { name: "data", type: "jsonb", nullable: true },
11656
+ { name: "metadata", type: "jsonb", nullable: true },
11657
+ { name: "scope", type: "jsonb", nullable: true }
11658
+ ];
11659
+ var SCORE_EVENT_COLUMNS = [
11660
+ CURSOR_ID_COLUMN,
11661
+ XACT_ID_COLUMN,
11662
+ { name: "scoreId", type: "text" },
11663
+ { name: "timestamp", type: "timestamptz" },
11664
+ { name: "scorerId", type: "text" },
11665
+ { name: "scorerVersion", type: "text", nullable: true },
11666
+ { name: "scoreSource", type: "text", nullable: true },
11667
+ { name: "score", type: "double precision" },
11668
+ { name: "reason", type: "text", nullable: true },
11669
+ ...COMMON_CONTEXT_COLUMNS,
11670
+ { name: "scoreTraceId", type: "text", nullable: true },
11671
+ { name: "tags", type: "text[]", defaultSql: "'{}'" },
11672
+ { name: "metadata", type: "jsonb", nullable: true },
11673
+ { name: "scope", type: "jsonb", nullable: true }
11674
+ ];
11675
+ var FEEDBACK_EVENT_COLUMNS = [
11676
+ CURSOR_ID_COLUMN,
11677
+ XACT_ID_COLUMN,
11678
+ { name: "feedbackId", type: "text" },
11679
+ { name: "timestamp", type: "timestamptz" },
11680
+ { name: "feedbackSource", type: "text" },
11681
+ { name: "feedbackType", type: "text" },
11682
+ { name: "valueString", type: "text", nullable: true },
11683
+ { name: "valueNumber", type: "double precision", nullable: true },
11684
+ { name: "comment", type: "text", nullable: true },
11685
+ { name: "feedbackUserId", type: "text", nullable: true },
11686
+ { name: "sourceId", type: "text", nullable: true },
11687
+ ...COMMON_CONTEXT_COLUMNS,
11688
+ { name: "tags", type: "text[]", defaultSql: "'{}'" },
11689
+ { name: "metadata", type: "jsonb", nullable: true },
11690
+ { name: "scope", type: "jsonb", nullable: true }
11691
+ ];
11692
+ var SPAN_LIGHT_SELECT_COLUMN_NAMES = [
11693
+ "cursorId",
11694
+ "xactId",
11695
+ "traceId",
11696
+ "spanId",
11697
+ "parentSpanId",
11698
+ "name",
11699
+ "entityType",
11700
+ "entityId",
11701
+ "entityName",
11702
+ "spanType",
11703
+ "error",
11704
+ "isEvent",
11705
+ "startedAt",
11706
+ "endedAt"
11707
+ ];
11708
+ function quotedColumnName(name) {
11709
+ return `"${name}"`;
11710
+ }
11711
+ function columnDefinition(column) {
11712
+ const nullable = column.nullable ? "" : " NOT NULL";
11713
+ const defaultSql = column.defaultSql ? ` DEFAULT ${column.defaultSql}` : "";
11714
+ return ` ${quotedColumnName(column.name)} ${column.type}${nullable}${defaultSql}`;
11715
+ }
11716
+ function buildColumnDefinitions(columns) {
11717
+ return columns.map(columnDefinition).join(",\n");
11718
+ }
11719
+ function buildSelectColumns(columns) {
11720
+ return `
11721
+ ${columns.map((column) => quotedColumnName(column.name)).join(",\n ")}
11722
+ `;
11723
+ }
11724
+ function buildNamedSelectColumns(columnNames) {
11725
+ return `
11726
+ ${columnNames.map(quotedColumnName).join(",\n ")}
11727
+ `;
11728
+ }
11729
+ function columnNamesByType(columns, type) {
11730
+ return columns.filter((column) => column.type === type).map((column) => column.name);
11731
+ }
11732
+ function typedColumnNames(columns) {
11733
+ return new Set(
11734
+ columns.filter((column) => !["bigserial", "jsonb", "text[]", "xid8"].includes(column.type)).map((column) => column.name)
11735
+ );
11736
+ }
11737
+ var ALL_EVENT_COLUMNS = [
11738
+ ...SPAN_EVENT_COLUMNS,
11739
+ ...METRIC_EVENT_COLUMNS,
11740
+ ...LOG_EVENT_COLUMNS,
11741
+ ...SCORE_EVENT_COLUMNS,
11742
+ ...FEEDBACK_EVENT_COLUMNS
11743
+ ];
11744
+ var JSONB_COLUMNS = new Set(columnNamesByType(ALL_EVENT_COLUMNS, "jsonb"));
11745
+ var TEXT_ARRAY_COLUMNS = new Set(columnNamesByType(ALL_EVENT_COLUMNS, "text[]"));
11746
+ var METRIC_TYPED_COLUMNS = typedColumnNames(METRIC_EVENT_COLUMNS);
11747
+ var SCORE_TYPED_COLUMNS = typedColumnNames(SCORE_EVENT_COLUMNS);
11748
+ var FEEDBACK_TYPED_COLUMNS = typedColumnNames(FEEDBACK_EVENT_COLUMNS);
11749
+
11750
+ // src/storage/domains/observability/v-next/ddl.ts
11751
+ var TABLE_SPAN_EVENTS = "mastra_span_events";
11752
+ var TABLE_METRIC_EVENTS = "mastra_metric_events";
11753
+ var TABLE_LOG_EVENTS = "mastra_log_events";
11754
+ var TABLE_SCORE_EVENTS = "mastra_score_events";
11755
+ var TABLE_FEEDBACK_EVENTS = "mastra_feedback_events";
11756
+ var TABLE_DISCOVERY = "mastra_observability_discovery";
11757
+ var ALL_SIGNAL_TABLES = [
11758
+ TABLE_SPAN_EVENTS,
11759
+ TABLE_METRIC_EVENTS,
11760
+ TABLE_LOG_EVENTS,
11761
+ TABLE_SCORE_EVENTS,
11762
+ TABLE_FEEDBACK_EVENTS
11763
+ ];
11764
+ var SIGNAL_TIME_COLUMN = {
11765
+ [TABLE_SPAN_EVENTS]: "endedAt",
11766
+ [TABLE_METRIC_EVENTS]: "timestamp",
11767
+ [TABLE_LOG_EVENTS]: "timestamp",
11768
+ [TABLE_SCORE_EVENTS]: "timestamp",
11769
+ [TABLE_FEEDBACK_EVENTS]: "timestamp"
11770
+ };
11771
+ function qualifiedTable(schema, table) {
11772
+ const s = utils.parseSqlIdentifier(schema, "schema name");
11773
+ const t = utils.parseSqlIdentifier(table, "table name");
11774
+ return `"${s}"."${t}"`;
11775
+ }
11776
+ function qualifiedName(schema, name) {
11777
+ const s = utils.parseSqlIdentifier(schema, "schema name");
11778
+ const n = utils.parseSqlIdentifier(name, "object name");
11779
+ return `"${s}"."${n}"`;
11780
+ }
11781
+ function schemaDDL(schema) {
11782
+ const s = utils.parseSqlIdentifier(schema, "schema name");
11783
+ return `CREATE SCHEMA IF NOT EXISTS "${s}"`;
11784
+ }
11785
+ function partitionClause(mode, column) {
11786
+ return mode === "timescale" ? "" : `PARTITION BY RANGE ("${column}")`;
11787
+ }
11788
+ function spanEventsTableDDL(schema, mode) {
11789
+ return `
11790
+ CREATE TABLE IF NOT EXISTS ${qualifiedTable(schema, TABLE_SPAN_EVENTS)} (
11791
+ ${buildColumnDefinitions(SPAN_EVENT_COLUMNS)},
11792
+ PRIMARY KEY ("traceId", "spanId", "endedAt")
11793
+ )
11794
+ ${partitionClause(mode, "endedAt")}
11795
+ `.trim();
11796
+ }
11797
+ function metricEventsTableDDL(schema, mode) {
11798
+ return `
11799
+ CREATE TABLE IF NOT EXISTS ${qualifiedTable(schema, TABLE_METRIC_EVENTS)} (
11800
+ ${buildColumnDefinitions(METRIC_EVENT_COLUMNS)},
11801
+ PRIMARY KEY ("metricId", "timestamp")
11802
+ )
11803
+ ${partitionClause(mode, "timestamp")}
11804
+ `.trim();
11805
+ }
11806
+ function logEventsTableDDL(schema, mode) {
11807
+ return `
11808
+ CREATE TABLE IF NOT EXISTS ${qualifiedTable(schema, TABLE_LOG_EVENTS)} (
11809
+ ${buildColumnDefinitions(LOG_EVENT_COLUMNS)},
11810
+ PRIMARY KEY ("logId", "timestamp")
11811
+ )
11812
+ ${partitionClause(mode, "timestamp")}
11813
+ `.trim();
11814
+ }
11815
+ function scoreEventsTableDDL(schema, mode) {
11816
+ return `
11817
+ CREATE TABLE IF NOT EXISTS ${qualifiedTable(schema, TABLE_SCORE_EVENTS)} (
11818
+ ${buildColumnDefinitions(SCORE_EVENT_COLUMNS)},
11819
+ PRIMARY KEY ("scoreId", "timestamp")
11820
+ )
11821
+ ${partitionClause(mode, "timestamp")}
11822
+ `.trim();
11823
+ }
11824
+ function feedbackEventsTableDDL(schema, mode) {
11825
+ return `
11826
+ CREATE TABLE IF NOT EXISTS ${qualifiedTable(schema, TABLE_FEEDBACK_EVENTS)} (
11827
+ ${buildColumnDefinitions(FEEDBACK_EVENT_COLUMNS)},
11828
+ PRIMARY KEY ("feedbackId", "timestamp")
11829
+ )
11830
+ ${partitionClause(mode, "timestamp")}
11831
+ `.trim();
11832
+ }
11833
+ function discoveryTableDDL(schema) {
11834
+ return `
11835
+ CREATE TABLE IF NOT EXISTS ${qualifiedTable(schema, TABLE_DISCOVERY)} (
11836
+ "cacheKey" text PRIMARY KEY,
11837
+ "refreshedAt" timestamptz NOT NULL,
11838
+ "values" jsonb NOT NULL DEFAULT '[]'::jsonb
11839
+ )
11840
+ `.trim();
11841
+ }
11842
+ var ROOT_SPAN_WHERE = '"parentSpanId" IS NULL';
11843
+ function tableIndexes() {
11844
+ return [
11845
+ // span_events — full-table indexes used by getTrace / getSpan
11846
+ { name: "mastra_span_events_traceid_idx", table: TABLE_SPAN_EVENTS, columns: '("traceId", "endedAt" DESC)' },
11847
+ {
11848
+ name: "mastra_span_events_parentspan_idx",
11849
+ table: TABLE_SPAN_EVENTS,
11850
+ columns: '("parentSpanId", "endedAt" DESC)'
11851
+ },
11852
+ { name: "mastra_span_events_name_idx", table: TABLE_SPAN_EVENTS, columns: '("name")' },
11853
+ // Used by listBranches page mode (filter by spanType, order by startedAt).
11854
+ { name: "mastra_span_events_spantype_idx", table: TABLE_SPAN_EVENTS, columns: '("spanType", "startedAt" DESC)' },
11855
+ { name: "mastra_span_events_entity_idx", table: TABLE_SPAN_EVENTS, columns: '("entityType", "entityId")' },
11856
+ {
11857
+ name: "mastra_span_events_orgid_userid_idx",
11858
+ table: TABLE_SPAN_EVENTS,
11859
+ columns: '("organizationId", "userId")'
11860
+ },
11861
+ {
11862
+ name: "mastra_span_events_metadatasearch_gin",
11863
+ table: TABLE_SPAN_EVENTS,
11864
+ columns: '("metadataSearch" jsonb_path_ops)',
11865
+ using: "gin"
11866
+ },
11867
+ { name: "mastra_span_events_tags_gin", table: TABLE_SPAN_EVENTS, columns: '("tags")', using: "gin" },
11868
+ // span_events — partial indexes acting as the root-span projection. The
11869
+ // listTraces filter surface (startedAt / spanType / entityType / etc.) is
11870
+ // covered by these; rows where parentSpanId IS NOT NULL are excluded from
11871
+ // the index, so the index is the size of a separate trace_roots table.
11872
+ {
11873
+ name: "mastra_span_events_root_startedat_idx",
11874
+ table: TABLE_SPAN_EVENTS,
11875
+ columns: '("startedAt" DESC)',
11876
+ where: ROOT_SPAN_WHERE
11877
+ },
11878
+ {
11879
+ name: "mastra_span_events_root_endedat_idx",
11880
+ table: TABLE_SPAN_EVENTS,
11881
+ columns: '("endedAt" DESC)',
11882
+ where: ROOT_SPAN_WHERE
11883
+ },
11884
+ {
11885
+ name: "mastra_span_events_root_spantype_idx",
11886
+ table: TABLE_SPAN_EVENTS,
11887
+ columns: '("spanType", "startedAt" DESC)',
11888
+ where: ROOT_SPAN_WHERE
11889
+ },
11890
+ {
11891
+ name: "mastra_span_events_root_entityname_idx",
11892
+ table: TABLE_SPAN_EVENTS,
11893
+ columns: '("entityType", "entityName", "startedAt" DESC)',
11894
+ where: ROOT_SPAN_WHERE
11895
+ },
11896
+ {
11897
+ name: "mastra_span_events_root_traceid_idx",
11898
+ table: TABLE_SPAN_EVENTS,
11899
+ columns: '("traceId")',
11900
+ where: ROOT_SPAN_WHERE
11901
+ },
11902
+ // Delta polling: transaction-safe cursor ordering. Full-table coverage so the same index
11903
+ // serves both listTraces (combined with the `parentSpanId IS NULL`
11904
+ // predicate) and listBranches (combined with `spanType IN (...)`).
11905
+ {
11906
+ name: "mastra_span_events_cursor_idx",
11907
+ table: TABLE_SPAN_EVENTS,
11908
+ columns: '("xactId", "cursorId")'
11909
+ },
11910
+ // metric_events
11911
+ { name: "mastra_metric_events_name_ts_idx", table: TABLE_METRIC_EVENTS, columns: '("name", "timestamp" DESC)' },
11912
+ {
11913
+ name: "mastra_metric_events_entity_idx",
11914
+ table: TABLE_METRIC_EVENTS,
11915
+ columns: '("entityType", "entityId", "timestamp" DESC)'
11916
+ },
11917
+ { name: "mastra_metric_events_traceid_idx", table: TABLE_METRIC_EVENTS, columns: '("traceId")' },
11918
+ { name: "mastra_metric_events_labels_gin", table: TABLE_METRIC_EVENTS, columns: '("labels")', using: "gin" },
11919
+ { name: "mastra_metric_events_tags_gin", table: TABLE_METRIC_EVENTS, columns: '("tags")', using: "gin" },
11920
+ { name: "mastra_metric_events_cursor_idx", table: TABLE_METRIC_EVENTS, columns: '("xactId", "cursorId")' },
11921
+ // log_events
11922
+ { name: "mastra_log_events_ts_idx", table: TABLE_LOG_EVENTS, columns: '("timestamp" DESC)' },
11923
+ { name: "mastra_log_events_level_ts_idx", table: TABLE_LOG_EVENTS, columns: '("level", "timestamp" DESC)' },
11924
+ { name: "mastra_log_events_traceid_idx", table: TABLE_LOG_EVENTS, columns: '("traceId")' },
11925
+ {
11926
+ name: "mastra_log_events_entity_idx",
11927
+ table: TABLE_LOG_EVENTS,
11928
+ columns: '("entityType", "entityId", "timestamp" DESC)'
11929
+ },
11930
+ { name: "mastra_log_events_tags_gin", table: TABLE_LOG_EVENTS, columns: '("tags")', using: "gin" },
11931
+ { name: "mastra_log_events_cursor_idx", table: TABLE_LOG_EVENTS, columns: '("xactId", "cursorId")' },
11932
+ // score_events
11933
+ { name: "mastra_score_events_traceid_idx", table: TABLE_SCORE_EVENTS, columns: '("traceId", "timestamp" DESC)' },
11934
+ { name: "mastra_score_events_scorerid_idx", table: TABLE_SCORE_EVENTS, columns: '("scorerId", "timestamp" DESC)' },
11935
+ {
11936
+ name: "mastra_score_events_entity_idx",
11937
+ table: TABLE_SCORE_EVENTS,
11938
+ columns: '("entityType", "entityId", "timestamp" DESC)'
11939
+ },
11940
+ { name: "mastra_score_events_tags_gin", table: TABLE_SCORE_EVENTS, columns: '("tags")', using: "gin" },
11941
+ { name: "mastra_score_events_cursor_idx", table: TABLE_SCORE_EVENTS, columns: '("xactId", "cursorId")' },
11942
+ // feedback_events
11943
+ {
11944
+ name: "mastra_feedback_events_traceid_idx",
11945
+ table: TABLE_FEEDBACK_EVENTS,
11946
+ columns: '("traceId", "timestamp" DESC)'
11947
+ },
11948
+ {
11949
+ name: "mastra_feedback_events_type_idx",
11950
+ table: TABLE_FEEDBACK_EVENTS,
11951
+ columns: '("feedbackType", "timestamp" DESC)'
11952
+ },
11953
+ {
11954
+ name: "mastra_feedback_events_entity_idx",
11955
+ table: TABLE_FEEDBACK_EVENTS,
11956
+ columns: '("entityType", "entityId", "timestamp" DESC)'
11957
+ },
11958
+ { name: "mastra_feedback_events_tags_gin", table: TABLE_FEEDBACK_EVENTS, columns: '("tags")', using: "gin" },
11959
+ { name: "mastra_feedback_events_cursor_idx", table: TABLE_FEEDBACK_EVENTS, columns: '("xactId", "cursorId")' }
11960
+ ];
11961
+ }
11962
+ function indexDDL(schema, spec) {
11963
+ const idxName = utils.parseSqlIdentifier(spec.name, "index name");
11964
+ const using = spec.using ? `USING ${spec.using}` : "";
11965
+ const where = spec.where ? `WHERE ${spec.where}` : "";
11966
+ return `CREATE INDEX IF NOT EXISTS "${idxName}" ON ${qualifiedTable(schema, spec.table)} ${using} ${spec.columns} ${where}`.replace(
11967
+ /\s+/g,
11968
+ " "
11969
+ );
11970
+ }
11971
+ function allTableDDL(schema, mode) {
11972
+ return [
11973
+ spanEventsTableDDL(schema, mode),
11974
+ metricEventsTableDDL(schema, mode),
11975
+ logEventsTableDDL(schema, mode),
11976
+ scoreEventsTableDDL(schema, mode),
11977
+ feedbackEventsTableDDL(schema, mode),
11978
+ discoveryTableDDL(schema)
11979
+ ];
11980
+ }
11981
+ function allIndexDDL(schema) {
11982
+ return tableIndexes().map((spec) => indexDDL(schema, spec));
11983
+ }
11984
+ var DEFAULT_TTL_SECONDS = 5 * 60;
11985
+ var SIGNAL_TABLES_WITH_CONTEXT = [
11986
+ TABLE_SPAN_EVENTS,
11987
+ TABLE_METRIC_EVENTS,
11988
+ TABLE_LOG_EVENTS,
11989
+ TABLE_SCORE_EVENTS,
11990
+ TABLE_FEEDBACK_EVENTS
11991
+ ];
11992
+ var ENTITY_DISCOVERY_TABLES = [TABLE_SPAN_EVENTS, TABLE_METRIC_EVENTS, TABLE_LOG_EVENTS];
11993
+ var inFlightRefreshes = /* @__PURE__ */ new Map();
11994
+ function startOrJoinRefresh(dedupeKey, cacheKey, refresh, upsert, logger) {
11995
+ const existing = inFlightRefreshes.get(dedupeKey);
11996
+ if (existing) return existing;
11997
+ const promise = (async () => {
11998
+ try {
11999
+ const values = await refresh();
12000
+ await upsert(values);
12001
+ return values;
12002
+ } catch (error) {
12003
+ const message = `[observability/v-next] background refresh failed for discovery cache key "${cacheKey}"`;
12004
+ if (logger) {
12005
+ logger.warn(message, { error });
12006
+ } else {
12007
+ console.warn(message + ":", error);
11492
12008
  }
11493
- ];
11494
- }
11495
- /**
11496
- * Returns all DDL statements for this domain: tables and indexes.
11497
- * Used by exportSchemas to produce a complete, reproducible schema export.
11498
- */
11499
- static getExportDDL(schemaName) {
11500
- const statements = [];
11501
- const parsedSchema = schemaName ? utils.parseSqlIdentifier(schemaName, "schema name") : "";
11502
- const schemaPrefix = parsedSchema && parsedSchema !== "public" ? `${parsedSchema}_` : "";
11503
- for (const tableName of _PromptBlocksPG.MANAGED_TABLES) {
11504
- statements.push(
11505
- generateTableSQL({
11506
- tableName,
11507
- schema: storage.TABLE_SCHEMAS[tableName],
11508
- schemaName,
11509
- includeAllConstraints: true
11510
- })
11511
- );
12009
+ throw error;
12010
+ } finally {
12011
+ inFlightRefreshes.delete(dedupeKey);
11512
12012
  }
11513
- for (const idx of _PromptBlocksPG.getDefaultIndexDefs(schemaPrefix)) {
11514
- statements.push(generateIndexSQL(idx, schemaName));
12013
+ })();
12014
+ inFlightRefreshes.set(dedupeKey, promise);
12015
+ return promise;
12016
+ }
12017
+ async function readWithRefresh(client, schema, cacheKey, refresh, ttlSeconds, logger) {
12018
+ const table = qualifiedTable(schema, TABLE_DISCOVERY);
12019
+ const row = await client.oneOrNone(
12020
+ `SELECT "values", "refreshedAt" FROM ${table} WHERE "cacheKey" = $1`,
12021
+ [cacheKey]
12022
+ );
12023
+ const refreshedAtMs = row ? new Date(row.refreshedAt).getTime() : 0;
12024
+ const stale = !row || Date.now() - refreshedAtMs > ttlSeconds * 1e3;
12025
+ if (!stale) return row.values;
12026
+ const dedupeKey = `${schema}:${cacheKey}`;
12027
+ const refreshing = startOrJoinRefresh(
12028
+ dedupeKey,
12029
+ cacheKey,
12030
+ refresh,
12031
+ (values) => upsertCache(client, schema, cacheKey, values),
12032
+ logger
12033
+ );
12034
+ if (ttlSeconds <= 0) {
12035
+ try {
12036
+ return await refreshing;
12037
+ } catch {
12038
+ return row?.values ?? [];
11515
12039
  }
11516
- return statements;
11517
- }
11518
- getDefaultIndexDefinitions() {
11519
- const schemaPrefix = this.#schema !== "public" ? `${this.#schema}_` : "";
11520
- return _PromptBlocksPG.getDefaultIndexDefs(schemaPrefix);
11521
12040
  }
11522
- async createDefaultIndexes() {
11523
- if (this.#skipDefaultIndexes) {
11524
- return;
11525
- }
11526
- for (const indexDef of this.getDefaultIndexDefinitions()) {
11527
- try {
11528
- await this.#db.createIndex(indexDef);
11529
- } catch {
11530
- }
12041
+ if (!row) {
12042
+ try {
12043
+ return await refreshing;
12044
+ } catch {
12045
+ return [];
11531
12046
  }
11532
12047
  }
11533
- async init() {
11534
- await this.#db.createTable({ tableName: storage.TABLE_PROMPT_BLOCKS, schema: storage.TABLE_SCHEMAS[storage.TABLE_PROMPT_BLOCKS] });
11535
- await this.#db.createTable({
11536
- tableName: storage.TABLE_PROMPT_BLOCK_VERSIONS,
11537
- schema: storage.TABLE_SCHEMAS[storage.TABLE_PROMPT_BLOCK_VERSIONS]
11538
- });
11539
- await this.#db.alterTable({
11540
- tableName: storage.TABLE_PROMPT_BLOCK_VERSIONS,
11541
- schema: storage.TABLE_SCHEMAS[storage.TABLE_PROMPT_BLOCK_VERSIONS],
11542
- ifNotExists: ["requestContextSchema"]
11543
- });
11544
- await this.createDefaultIndexes();
11545
- await this.createCustomIndexes();
12048
+ refreshing.catch(() => {
12049
+ });
12050
+ return row.values;
12051
+ }
12052
+ async function upsertCache(client, schema, cacheKey, values) {
12053
+ const table = qualifiedTable(schema, TABLE_DISCOVERY);
12054
+ await client.query(
12055
+ `INSERT INTO ${table} ("cacheKey", "refreshedAt", "values")
12056
+ VALUES ($1, NOW(), $2::jsonb)
12057
+ ON CONFLICT ("cacheKey") DO UPDATE SET
12058
+ "refreshedAt" = EXCLUDED."refreshedAt",
12059
+ "values" = EXCLUDED."values"`,
12060
+ [cacheKey, JSON.stringify(values)]
12061
+ );
12062
+ }
12063
+ async function distinctAcrossTables(client, schema, column, tables, filterSql = "", filterParams = []) {
12064
+ const safeColumn = utils.parseSqlIdentifier(column, "column name");
12065
+ const unions = tables.map(
12066
+ (t) => `SELECT DISTINCT "${safeColumn}" AS v FROM ${qualifiedTable(schema, t)} WHERE "${safeColumn}" IS NOT NULL AND "${safeColumn}" <> '' ${filterSql}`
12067
+ ).join(" UNION ");
12068
+ const rows = await client.manyOrNone(`SELECT v FROM (${unions}) sub ORDER BY v`, filterParams);
12069
+ return rows.map((r) => r.v);
12070
+ }
12071
+ async function getEntityTypes(client, schema, _args, config) {
12072
+ const ttl = config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
12073
+ const values = await readWithRefresh(
12074
+ client,
12075
+ schema,
12076
+ "entity_types",
12077
+ () => distinctAcrossTables(client, schema, "entityType", ENTITY_DISCOVERY_TABLES),
12078
+ ttl,
12079
+ config.logger
12080
+ );
12081
+ return { entityTypes: values };
12082
+ }
12083
+ async function getEntityNames(client, schema, args, config) {
12084
+ const ttl = config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
12085
+ const cacheKey = args.entityType ? `entity_names:${args.entityType}` : "entity_names";
12086
+ const filterSql = args.entityType ? `AND "entityType" = $1` : "";
12087
+ const filterParams = args.entityType ? [args.entityType] : [];
12088
+ const values = await readWithRefresh(
12089
+ client,
12090
+ schema,
12091
+ cacheKey,
12092
+ () => distinctAcrossTables(client, schema, "entityName", ENTITY_DISCOVERY_TABLES, filterSql, filterParams),
12093
+ ttl,
12094
+ config.logger
12095
+ );
12096
+ return { names: values };
12097
+ }
12098
+ async function getServiceNames(client, schema, _args, config) {
12099
+ const ttl = config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
12100
+ const values = await readWithRefresh(
12101
+ client,
12102
+ schema,
12103
+ "service_names",
12104
+ () => distinctAcrossTables(client, schema, "serviceName", SIGNAL_TABLES_WITH_CONTEXT),
12105
+ ttl,
12106
+ config.logger
12107
+ );
12108
+ return { serviceNames: values };
12109
+ }
12110
+ async function getEnvironments(client, schema, _args, config) {
12111
+ const ttl = config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
12112
+ const values = await readWithRefresh(
12113
+ client,
12114
+ schema,
12115
+ "environments",
12116
+ () => distinctAcrossTables(client, schema, "environment", SIGNAL_TABLES_WITH_CONTEXT),
12117
+ ttl,
12118
+ config.logger
12119
+ );
12120
+ return { environments: values };
12121
+ }
12122
+ async function getTags(client, schema, args, config) {
12123
+ const ttl = config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
12124
+ const cacheKey = args.entityType ? `tags:${args.entityType}` : "tags";
12125
+ const refresh = async () => {
12126
+ const filter = args.entityType ? `AND "entityType" = $1` : "";
12127
+ const params = args.entityType ? [args.entityType] : [];
12128
+ const unions = ENTITY_DISCOVERY_TABLES.map(
12129
+ (t) => `SELECT DISTINCT UNNEST("tags") AS v FROM ${qualifiedTable(schema, t)} WHERE array_length("tags", 1) > 0 ${filter}`
12130
+ ).join(" UNION ");
12131
+ const rows = await client.manyOrNone(
12132
+ `SELECT v FROM (${unions}) sub WHERE v IS NOT NULL AND v <> '' ORDER BY v`,
12133
+ params
12134
+ );
12135
+ return rows.map((r) => r.v);
12136
+ };
12137
+ const values = await readWithRefresh(client, schema, cacheKey, refresh, ttl, config.logger);
12138
+ return { tags: values };
12139
+ }
12140
+ async function getMetricNames(client, schema, args, config) {
12141
+ const ttl = config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
12142
+ const values = await readWithRefresh(
12143
+ client,
12144
+ schema,
12145
+ "metric_names",
12146
+ async () => {
12147
+ const rows = await client.manyOrNone(
12148
+ `SELECT DISTINCT "name" AS v FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)}
12149
+ WHERE "name" IS NOT NULL AND "name" <> '' ORDER BY "name"`
12150
+ );
12151
+ return rows.map((r) => r.v);
12152
+ },
12153
+ ttl,
12154
+ config.logger
12155
+ );
12156
+ let filtered = values;
12157
+ if (args.prefix) filtered = filtered.filter((v) => v.startsWith(args.prefix));
12158
+ if (args.limit) filtered = filtered.slice(0, args.limit);
12159
+ return { names: filtered };
12160
+ }
12161
+ async function getMetricLabelKeys(client, schema, args, config) {
12162
+ const ttl = config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
12163
+ const cacheKey = `metric_label_keys:${args.metricName}`;
12164
+ const values = await readWithRefresh(
12165
+ client,
12166
+ schema,
12167
+ cacheKey,
12168
+ async () => {
12169
+ const rows = await client.manyOrNone(
12170
+ `SELECT DISTINCT k AS v
12171
+ FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)}, jsonb_object_keys("labels") k
12172
+ WHERE "name" = $1 ORDER BY k`,
12173
+ [args.metricName]
12174
+ );
12175
+ return rows.map((r) => r.v);
12176
+ },
12177
+ ttl,
12178
+ config.logger
12179
+ );
12180
+ return { keys: values };
12181
+ }
12182
+ async function getMetricLabelValues(client, schema, args, config) {
12183
+ const ttl = config.ttlSeconds ?? DEFAULT_TTL_SECONDS;
12184
+ const cacheKey = `metric_label_values:${args.metricName}:${args.labelKey}`;
12185
+ const values = await readWithRefresh(
12186
+ client,
12187
+ schema,
12188
+ cacheKey,
12189
+ async () => {
12190
+ const rows = await client.manyOrNone(
12191
+ `SELECT DISTINCT "labels" ->> $2 AS v
12192
+ FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)}
12193
+ WHERE "name" = $1 AND "labels" ? $2
12194
+ ORDER BY v`,
12195
+ [args.metricName, args.labelKey]
12196
+ );
12197
+ return rows.map((r) => r.v).filter((v) => v != null && v !== "");
12198
+ },
12199
+ ttl,
12200
+ config.logger
12201
+ );
12202
+ let filtered = values;
12203
+ if (args.prefix) filtered = filtered.filter((v) => v.startsWith(args.prefix));
12204
+ if (args.limit) filtered = filtered.slice(0, args.limit);
12205
+ return { values: filtered };
12206
+ }
12207
+
12208
+ // src/storage/domains/observability/v-next/filters.ts
12209
+ function newFilterAccumulator(startIndex = 1) {
12210
+ return { conditions: [], params: [], next: startIndex };
12211
+ }
12212
+ function pushEq(acc, column, value, prefix = "") {
12213
+ if (value === void 0) return;
12214
+ acc.conditions.push(`${prefix}"${column}" = $${acc.next++}`);
12215
+ acc.params.push(value);
12216
+ }
12217
+ function pushIn(acc, column, values, prefix = "") {
12218
+ if (!values.length) return;
12219
+ const placeholders = values.map(() => `$${acc.next++}`).join(", ");
12220
+ acc.conditions.push(`${prefix}"${column}" IN (${placeholders})`);
12221
+ acc.params.push(...values);
12222
+ }
12223
+ function applyCommonFilters(acc, filters, options = {}) {
12224
+ if (!filters) return;
12225
+ const tsCol = options.timestampColumn ?? "timestamp";
12226
+ const prefix = options.prefix ?? "";
12227
+ if (filters.timestamp?.start) {
12228
+ const op = filters.timestamp.startExclusive ? ">" : ">=";
12229
+ acc.conditions.push(`${prefix}"${tsCol}" ${op} $${acc.next++}`);
12230
+ acc.params.push(filters.timestamp.start.toISOString());
12231
+ }
12232
+ if (filters.timestamp?.end) {
12233
+ const op = filters.timestamp.endExclusive ? "<" : "<=";
12234
+ acc.conditions.push(`${prefix}"${tsCol}" ${op} $${acc.next++}`);
12235
+ acc.params.push(filters.timestamp.end.toISOString());
12236
+ }
12237
+ pushEq(acc, "traceId", filters.traceId, prefix);
12238
+ pushEq(acc, "spanId", filters.spanId, prefix);
12239
+ pushEq(acc, "entityType", filters.entityType, prefix);
12240
+ pushEq(acc, "entityName", filters.entityName, prefix);
12241
+ pushEq(acc, "entityVersionId", filters.entityVersionId, prefix);
12242
+ pushEq(acc, "parentEntityType", filters.parentEntityType, prefix);
12243
+ pushEq(acc, "parentEntityName", filters.parentEntityName, prefix);
12244
+ pushEq(acc, "parentEntityVersionId", filters.parentEntityVersionId, prefix);
12245
+ pushEq(acc, "rootEntityType", filters.rootEntityType, prefix);
12246
+ pushEq(acc, "rootEntityName", filters.rootEntityName, prefix);
12247
+ pushEq(acc, "rootEntityVersionId", filters.rootEntityVersionId, prefix);
12248
+ pushEq(acc, "userId", filters.userId, prefix);
12249
+ pushEq(acc, "organizationId", filters.organizationId, prefix);
12250
+ pushEq(acc, "resourceId", filters.resourceId, prefix);
12251
+ pushEq(acc, "runId", filters.runId, prefix);
12252
+ pushEq(acc, "sessionId", filters.sessionId, prefix);
12253
+ pushEq(acc, "threadId", filters.threadId, prefix);
12254
+ pushEq(acc, "requestId", filters.requestId, prefix);
12255
+ pushEq(acc, "experimentId", filters.experimentId, prefix);
12256
+ pushEq(acc, "environment", filters.environment, prefix);
12257
+ pushEq(acc, "serviceName", filters.serviceName, prefix);
12258
+ pushEq(acc, "executionSource", filters.executionSource ?? filters.source, prefix);
12259
+ if (filters.tags != null && Array.isArray(filters.tags) && filters.tags.length > 0) {
12260
+ acc.conditions.push(`${prefix}"tags" @> $${acc.next++}::text[]`);
12261
+ acc.params.push(filters.tags);
11546
12262
  }
11547
- async createCustomIndexes() {
11548
- if (!this.#indexes || this.#indexes.length === 0) {
11549
- return;
11550
- }
11551
- for (const indexDef of this.#indexes) {
11552
- try {
11553
- await this.#db.createIndex(indexDef);
11554
- } catch (error) {
11555
- this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
11556
- }
11557
- }
12263
+ }
12264
+ function applySingleOrArrayFilter(acc, column, value, prefix = "") {
12265
+ if (value === void 0) return;
12266
+ if (Array.isArray(value)) {
12267
+ pushIn(acc, column, value, prefix);
12268
+ } else {
12269
+ pushEq(acc, column, value, prefix);
11558
12270
  }
11559
- async dangerouslyClearAll() {
11560
- await this.#db.clearTable({ tableName: storage.TABLE_PROMPT_BLOCK_VERSIONS });
11561
- await this.#db.clearTable({ tableName: storage.TABLE_PROMPT_BLOCKS });
12271
+ }
12272
+ function whereOrEmpty(acc) {
12273
+ return acc.conditions.length ? `WHERE ${acc.conditions.join(" AND ")}` : "";
12274
+ }
12275
+ var PROMOTED_KEYS = /* @__PURE__ */ new Set([
12276
+ "experimentId",
12277
+ "entityType",
12278
+ "entityId",
12279
+ "entityName",
12280
+ "entityVersionId",
12281
+ "parentEntityVersionId",
12282
+ "rootEntityVersionId",
12283
+ "userId",
12284
+ "organizationId",
12285
+ "resourceId",
12286
+ "runId",
12287
+ "sessionId",
12288
+ "threadId",
12289
+ "requestId",
12290
+ "environment",
12291
+ "executionSource",
12292
+ "serviceName"
12293
+ ]);
12294
+ function nullableString(value) {
12295
+ if (typeof value === "string") return value === "" ? null : value;
12296
+ if (value == null) return null;
12297
+ return String(value);
12298
+ }
12299
+ function nullableEntityType(value) {
12300
+ const normalized = nullableString(value);
12301
+ if (!normalized) return null;
12302
+ return Object.values(storage.EntityType).includes(normalized) ? normalized : null;
12303
+ }
12304
+ function normalizeTags(tags) {
12305
+ if (!Array.isArray(tags)) return [];
12306
+ const seen = /* @__PURE__ */ new Set();
12307
+ const result = [];
12308
+ for (const t of tags) {
12309
+ if (typeof t !== "string") continue;
12310
+ const trimmed = t.trim();
12311
+ if (trimmed === "" || seen.has(trimmed)) continue;
12312
+ seen.add(trimmed);
12313
+ result.push(trimmed);
11562
12314
  }
11563
- // ==========================================================================
11564
- // Prompt Block CRUD Methods
11565
- // ==========================================================================
11566
- async getById(id) {
12315
+ return result;
12316
+ }
12317
+ function normalizeLabels(labels) {
12318
+ if (labels == null || typeof labels !== "object") return {};
12319
+ const result = {};
12320
+ for (const [k, v] of Object.entries(labels)) {
12321
+ if (typeof v !== "string") continue;
12322
+ const trimmedK = k.trim();
12323
+ const trimmedV = v.trim();
12324
+ if (trimmedK === "" || trimmedV === "") continue;
12325
+ result[trimmedK] = trimmedV;
12326
+ }
12327
+ return result;
12328
+ }
12329
+ function buildMetadataSearch(metadata) {
12330
+ if (metadata == null || typeof metadata !== "object") return {};
12331
+ const result = {};
12332
+ for (const [k, v] of Object.entries(metadata)) {
12333
+ if (PROMOTED_KEYS.has(k)) continue;
12334
+ if (typeof v !== "string") continue;
12335
+ const trimmed = v.trim();
12336
+ if (trimmed === "") continue;
12337
+ result[k] = trimmed;
12338
+ }
12339
+ return result;
12340
+ }
12341
+ function toDate(value) {
12342
+ if (value instanceof Date) return value;
12343
+ if (value == null || value === "") throw new Error(`Invalid date: ${String(value)}`);
12344
+ const d = new Date(value);
12345
+ if (isNaN(d.getTime())) throw new Error(`Invalid date: ${String(value)}`);
12346
+ return d;
12347
+ }
12348
+ function toDateOrNull(value) {
12349
+ if (value == null || value === "") return null;
12350
+ if (value instanceof Date) return value;
12351
+ const d = new Date(value);
12352
+ if (isNaN(d.getTime())) return null;
12353
+ return d;
12354
+ }
12355
+ function toIsoOrDate(value) {
12356
+ if (value instanceof Date) return value;
12357
+ if (typeof value === "number") return new Date(value);
12358
+ return value;
12359
+ }
12360
+ function jsonField(value) {
12361
+ if (value === void 0) return null;
12362
+ return value;
12363
+ }
12364
+ function parsedJson(value) {
12365
+ if (value == null) return void 0;
12366
+ if (typeof value === "string") {
11567
12367
  try {
11568
- const tableName = getTableName2({ indexName: storage.TABLE_PROMPT_BLOCKS, schemaName: getSchemaName2(this.#schema) });
12368
+ return JSON.parse(value);
12369
+ } catch {
12370
+ return void 0;
12371
+ }
12372
+ }
12373
+ return value;
12374
+ }
12375
+ function rowToCommonContext(row) {
12376
+ return {
12377
+ experimentId: nullableString(row.experimentId),
12378
+ entityType: nullableEntityType(row.entityType),
12379
+ entityId: nullableString(row.entityId),
12380
+ entityName: nullableString(row.entityName),
12381
+ entityVersionId: nullableString(row.entityVersionId),
12382
+ parentEntityType: nullableEntityType(row.parentEntityType),
12383
+ parentEntityId: nullableString(row.parentEntityId),
12384
+ parentEntityName: nullableString(row.parentEntityName),
12385
+ parentEntityVersionId: nullableString(row.parentEntityVersionId),
12386
+ rootEntityType: nullableEntityType(row.rootEntityType),
12387
+ rootEntityId: nullableString(row.rootEntityId),
12388
+ rootEntityName: nullableString(row.rootEntityName),
12389
+ rootEntityVersionId: nullableString(row.rootEntityVersionId),
12390
+ userId: nullableString(row.userId),
12391
+ organizationId: nullableString(row.organizationId),
12392
+ resourceId: nullableString(row.resourceId),
12393
+ runId: nullableString(row.runId),
12394
+ sessionId: nullableString(row.sessionId),
12395
+ threadId: nullableString(row.threadId),
12396
+ requestId: nullableString(row.requestId),
12397
+ environment: nullableString(row.environment),
12398
+ executionSource: nullableString(row.executionSource),
12399
+ serviceName: nullableString(row.serviceName)
12400
+ };
12401
+ }
12402
+ function commonContextToRow(record) {
12403
+ return {
12404
+ experimentId: record.experimentId ?? null,
12405
+ entityType: record.entityType ?? null,
12406
+ entityId: record.entityId ?? null,
12407
+ entityName: record.entityName ?? null,
12408
+ entityVersionId: record.entityVersionId ?? null,
12409
+ parentEntityType: record.parentEntityType ?? null,
12410
+ parentEntityId: record.parentEntityId ?? null,
12411
+ parentEntityName: record.parentEntityName ?? null,
12412
+ parentEntityVersionId: record.parentEntityVersionId ?? null,
12413
+ rootEntityType: record.rootEntityType ?? null,
12414
+ rootEntityId: record.rootEntityId ?? null,
12415
+ rootEntityName: record.rootEntityName ?? null,
12416
+ rootEntityVersionId: record.rootEntityVersionId ?? null,
12417
+ userId: record.userId ?? null,
12418
+ organizationId: record.organizationId ?? null,
12419
+ resourceId: record.resourceId ?? null,
12420
+ runId: record.runId ?? null,
12421
+ sessionId: record.sessionId ?? null,
12422
+ threadId: record.threadId ?? null,
12423
+ requestId: record.requestId ?? null,
12424
+ environment: record.environment ?? null,
12425
+ executionSource: record.executionSource ?? record.source ?? null,
12426
+ serviceName: record.serviceName ?? null
12427
+ };
12428
+ }
12429
+ function spanRecordToRow(span) {
12430
+ const endedAt = span.isEvent ? span.startedAt : span.endedAt ?? span.startedAt;
12431
+ const metadata = span.metadata ?? null;
12432
+ return {
12433
+ ...commonContextToRow(span),
12434
+ traceId: span.traceId,
12435
+ spanId: span.spanId,
12436
+ parentSpanId: span.parentSpanId ?? null,
12437
+ name: span.name,
12438
+ spanType: span.spanType,
12439
+ isEvent: Boolean(span.isEvent),
12440
+ startedAt: toIsoOrDate(span.startedAt),
12441
+ endedAt: toIsoOrDate(endedAt),
12442
+ tags: normalizeTags(span.tags),
12443
+ metadataSearch: buildMetadataSearch(metadata),
12444
+ metadataRaw: jsonField(metadata),
12445
+ scope: jsonField(span.scope),
12446
+ attributes: jsonField(span.attributes),
12447
+ links: jsonField(span.links),
12448
+ input: jsonField(span.input),
12449
+ output: jsonField(span.output),
12450
+ error: jsonField(span.error),
12451
+ requestContext: jsonField(span.requestContext)
12452
+ };
12453
+ }
12454
+ function rowToSpanRecord(row) {
12455
+ const startedAt = toDate(row.startedAt);
12456
+ const endedAt = row.isEvent ? startedAt : toDateOrNull(row.endedAt);
12457
+ const error = parsedJson(row.error);
12458
+ const { executionSource, ...ctx } = rowToCommonContext(row);
12459
+ return {
12460
+ ...ctx,
12461
+ source: executionSource,
12462
+ traceId: row.traceId,
12463
+ spanId: row.spanId,
12464
+ parentSpanId: nullableString(row.parentSpanId),
12465
+ name: row.name,
12466
+ spanType: row.spanType,
12467
+ isEvent: Boolean(row.isEvent),
12468
+ startedAt,
12469
+ endedAt,
12470
+ tags: normalizeTags(row.tags),
12471
+ metadata: parsedJson(row.metadataRaw) ?? void 0,
12472
+ scope: parsedJson(row.scope) ?? void 0,
12473
+ attributes: parsedJson(row.attributes) ?? void 0,
12474
+ links: parsedJson(row.links) ?? void 0,
12475
+ input: parsedJson(row.input) ?? void 0,
12476
+ output: parsedJson(row.output) ?? void 0,
12477
+ error: error ?? void 0,
12478
+ requestContext: parsedJson(row.requestContext) ?? void 0,
12479
+ createdAt: startedAt,
12480
+ updatedAt: null
12481
+ };
12482
+ }
12483
+ function rowToLightSpanRecord(row) {
12484
+ const startedAt = toDate(row.startedAt);
12485
+ const endedAt = row.isEvent ? startedAt : toDateOrNull(row.endedAt);
12486
+ return {
12487
+ traceId: row.traceId,
12488
+ spanId: row.spanId,
12489
+ parentSpanId: row.parentSpanId == null || row.parentSpanId === "" ? null : String(row.parentSpanId),
12490
+ name: row.name,
12491
+ spanType: row.spanType,
12492
+ isEvent: Boolean(row.isEvent),
12493
+ startedAt,
12494
+ endedAt,
12495
+ entityType: row.entityType == null || row.entityType === "" ? null : Object.values(storage.EntityType).includes(row.entityType) ? row.entityType : null,
12496
+ entityId: row.entityId == null || row.entityId === "" ? null : String(row.entityId),
12497
+ entityName: row.entityName == null || row.entityName === "" ? null : String(row.entityName),
12498
+ error: parsedJson(row.error) ?? void 0,
12499
+ createdAt: startedAt,
12500
+ updatedAt: null
12501
+ };
12502
+ }
12503
+ function logRecordToRow(log) {
12504
+ return {
12505
+ ...commonContextToRow(log),
12506
+ logId: log.logId,
12507
+ timestamp: toIsoOrDate(log.timestamp),
12508
+ level: log.level,
12509
+ message: log.message,
12510
+ data: jsonField(log.data),
12511
+ traceId: log.traceId ?? null,
12512
+ spanId: log.spanId ?? null,
12513
+ tags: normalizeTags(log.tags),
12514
+ metadata: jsonField(log.metadata),
12515
+ scope: jsonField(log.scope)
12516
+ };
12517
+ }
12518
+ function rowToLogRecord(row) {
12519
+ return {
12520
+ ...rowToCommonContext(row),
12521
+ logId: row.logId,
12522
+ timestamp: toDate(row.timestamp),
12523
+ level: row.level,
12524
+ message: row.message,
12525
+ data: parsedJson(row.data) ?? void 0,
12526
+ traceId: nullableString(row.traceId),
12527
+ spanId: nullableString(row.spanId),
12528
+ tags: normalizeTags(row.tags),
12529
+ metadata: parsedJson(row.metadata) ?? void 0,
12530
+ scope: parsedJson(row.scope) ?? void 0
12531
+ };
12532
+ }
12533
+ function metricRecordToRow(metric) {
12534
+ return {
12535
+ ...commonContextToRow(metric),
12536
+ metricId: metric.metricId,
12537
+ timestamp: toIsoOrDate(metric.timestamp),
12538
+ name: metric.name,
12539
+ value: metric.value,
12540
+ traceId: metric.traceId ?? null,
12541
+ spanId: metric.spanId ?? null,
12542
+ provider: metric.provider ?? null,
12543
+ model: metric.model ?? null,
12544
+ estimatedCost: metric.estimatedCost ?? null,
12545
+ costUnit: metric.costUnit ?? null,
12546
+ tags: normalizeTags(metric.tags),
12547
+ labels: normalizeLabels(metric.labels),
12548
+ costMetadata: jsonField(metric.costMetadata),
12549
+ metadata: jsonField(metric.metadata),
12550
+ scope: jsonField(metric.scope)
12551
+ };
12552
+ }
12553
+ function rowToMetricRecord(row) {
12554
+ return {
12555
+ ...rowToCommonContext(row),
12556
+ metricId: row.metricId,
12557
+ timestamp: toDate(row.timestamp),
12558
+ name: row.name,
12559
+ value: Number(row.value),
12560
+ traceId: nullableString(row.traceId),
12561
+ spanId: nullableString(row.spanId),
12562
+ provider: nullableString(row.provider),
12563
+ model: nullableString(row.model),
12564
+ estimatedCost: row.estimatedCost == null ? void 0 : Number(row.estimatedCost),
12565
+ costUnit: nullableString(row.costUnit),
12566
+ costMetadata: parsedJson(row.costMetadata) ?? void 0,
12567
+ tags: normalizeTags(row.tags),
12568
+ labels: normalizeLabels(row.labels),
12569
+ metadata: parsedJson(row.metadata) ?? void 0,
12570
+ scope: parsedJson(row.scope) ?? void 0
12571
+ };
12572
+ }
12573
+ function scoreRecordToRow(score) {
12574
+ const metadata = score.metadata ?? null;
12575
+ const scoreSource = score.scoreSource ?? score.source ?? null;
12576
+ return {
12577
+ ...commonContextToRow(score),
12578
+ scoreId: score.scoreId,
12579
+ timestamp: toIsoOrDate(score.timestamp),
12580
+ traceId: score.traceId ?? null,
12581
+ spanId: score.spanId ?? null,
12582
+ scoreTraceId: score.scoreTraceId ?? null,
12583
+ scorerId: score.scorerId,
12584
+ scorerVersion: score.scorerVersion ?? null,
12585
+ scoreSource,
12586
+ score: score.score,
12587
+ reason: score.reason ?? null,
12588
+ tags: normalizeTags(score.tags),
12589
+ metadata: jsonField(metadata),
12590
+ scope: jsonField(score.scope)
12591
+ };
12592
+ }
12593
+ function rowToScoreRecord(row) {
12594
+ return {
12595
+ ...rowToCommonContext(row),
12596
+ scoreId: row.scoreId,
12597
+ timestamp: toDate(row.timestamp),
12598
+ // Legacy schema types traceId as required string even though the column is nullable.
12599
+ traceId: nullableString(row.traceId),
12600
+ spanId: nullableString(row.spanId),
12601
+ scoreTraceId: nullableString(row.scoreTraceId),
12602
+ scorerId: row.scorerId,
12603
+ scorerVersion: nullableString(row.scorerVersion),
12604
+ scoreSource: nullableString(row.scoreSource),
12605
+ score: Number(row.score),
12606
+ reason: nullableString(row.reason),
12607
+ tags: normalizeTags(row.tags),
12608
+ metadata: parsedJson(row.metadata) ?? void 0,
12609
+ scope: parsedJson(row.scope) ?? void 0
12610
+ };
12611
+ }
12612
+ function feedbackRecordToRow(feedback) {
12613
+ const metadata = feedback.metadata ?? null;
12614
+ const feedbackSource = feedback.feedbackSource ?? feedback.source ?? "";
12615
+ return {
12616
+ ...commonContextToRow(feedback),
12617
+ feedbackId: feedback.feedbackId,
12618
+ timestamp: toIsoOrDate(feedback.timestamp),
12619
+ traceId: feedback.traceId ?? null,
12620
+ spanId: feedback.spanId ?? null,
12621
+ feedbackUserId: feedback.feedbackUserId ?? null,
12622
+ sourceId: feedback.sourceId ?? null,
12623
+ feedbackSource,
12624
+ feedbackType: feedback.feedbackType,
12625
+ valueString: typeof feedback.value === "string" ? feedback.value : null,
12626
+ valueNumber: typeof feedback.value === "number" ? feedback.value : null,
12627
+ comment: feedback.comment ?? null,
12628
+ tags: normalizeTags(feedback.tags),
12629
+ metadata: jsonField(metadata),
12630
+ scope: jsonField(feedback.scope)
12631
+ };
12632
+ }
12633
+ function rowToFeedbackRecord(row) {
12634
+ const hasNumber = row.valueNumber != null;
12635
+ const feedbackSource = nullableString(row.feedbackSource);
12636
+ return {
12637
+ ...rowToCommonContext(row),
12638
+ feedbackId: row.feedbackId,
12639
+ timestamp: toDate(row.timestamp),
12640
+ // Legacy schema types traceId as required string even though the column is nullable.
12641
+ traceId: nullableString(row.traceId),
12642
+ spanId: nullableString(row.spanId),
12643
+ feedbackUserId: nullableString(row.feedbackUserId),
12644
+ sourceId: nullableString(row.sourceId),
12645
+ feedbackSource,
12646
+ feedbackType: row.feedbackType,
12647
+ value: hasNumber ? Number(row.valueNumber) : nullableString(row.valueString) ?? "",
12648
+ comment: nullableString(row.comment),
12649
+ tags: normalizeTags(row.tags),
12650
+ metadata: parsedJson(row.metadata) ?? void 0,
12651
+ scope: parsedJson(row.scope) ?? void 0
12652
+ };
12653
+ }
12654
+ var OBSERVABILITY_DELTA_POLLING_FEATURE = "observability-delta-polling";
12655
+ function deltaPollingFeatureEnabled() {
12656
+ return features.coreFeatures.has(OBSERVABILITY_DELTA_POLLING_FEATURE);
12657
+ }
12658
+ function assertDeltaPollingEnabled() {
12659
+ if (deltaPollingFeatureEnabled()) return;
12660
+ throw new error.MastraError({
12661
+ id: "OBSERVABILITY_DELTA_POLLING_NOT_SUPPORTED",
12662
+ domain: error.ErrorDomain.MASTRA_OBSERVABILITY,
12663
+ category: error.ErrorCategory.SYSTEM,
12664
+ text: "This storage provider does not support observability delta polling"
12665
+ });
12666
+ }
12667
+ var PG_BIGINT_MAX = 9223372036854775807n;
12668
+ function invalidDeltaCursor() {
12669
+ throw new error.MastraError({
12670
+ id: "OBSERVABILITY_INVALID_DELTA_CURSOR",
12671
+ domain: error.ErrorDomain.MASTRA_OBSERVABILITY,
12672
+ category: error.ErrorCategory.USER,
12673
+ text: "Invalid observability delta cursor"
12674
+ });
12675
+ }
12676
+ function validatePgInteger(value) {
12677
+ if (!/^\d+$/.test(value)) {
12678
+ invalidDeltaCursor();
12679
+ }
12680
+ let parsed;
12681
+ try {
12682
+ parsed = BigInt(value);
12683
+ } catch {
12684
+ invalidDeltaCursor();
12685
+ }
12686
+ if (parsed < 0n || parsed > PG_BIGINT_MAX) {
12687
+ invalidDeltaCursor();
12688
+ }
12689
+ return value;
12690
+ }
12691
+ function encodeDeltaCursor(xactId, cursorId = 0) {
12692
+ return `${validatePgInteger(String(xactId ?? 0))}:${validatePgInteger(String(cursorId ?? 0))}`;
12693
+ }
12694
+ function decodeDeltaCursor(cursor) {
12695
+ const parts = cursor.split(":");
12696
+ if (parts.length !== 2) {
12697
+ invalidDeltaCursor();
12698
+ }
12699
+ return {
12700
+ xactId: validatePgInteger(parts[0]),
12701
+ cursorId: validatePgInteger(parts[1])
12702
+ };
12703
+ }
12704
+ async function readSafeXactHorizon(client) {
12705
+ const row = await client.one(`SELECT pg_snapshot_xmin(pg_current_snapshot())::text AS "xactId"`);
12706
+ return validatePgInteger(row.xactId);
12707
+ }
12708
+
12709
+ // src/storage/domains/observability/v-next/listing.ts
12710
+ function responseItems(key, items) {
12711
+ return { [key]: items };
12712
+ }
12713
+ async function readSignalStreamHeadCursor({
12714
+ client,
12715
+ table,
12716
+ filters,
12717
+ applyFilters
12718
+ }) {
12719
+ return encodeDeltaCursor(await readSafeXactHorizon(client), 0);
12720
+ }
12721
+ async function listSignalPage(config) {
12722
+ const {
12723
+ client,
12724
+ table,
12725
+ filters,
12726
+ selectColumns,
12727
+ responseKey,
12728
+ applyFilters,
12729
+ mapRow,
12730
+ page,
12731
+ perPage,
12732
+ orderField,
12733
+ orderDir
12734
+ } = config;
12735
+ const acc = newFilterAccumulator();
12736
+ applyFilters(acc, filters);
12737
+ const whereClause = whereOrEmpty(acc);
12738
+ const countRow = await client.oneOrNone(
12739
+ `SELECT COUNT(*)::text AS count FROM ${table} ${whereClause}`,
12740
+ acc.params
12741
+ );
12742
+ const total = Number(countRow?.count ?? 0);
12743
+ let items = [];
12744
+ if (total > 0) {
12745
+ const safeOrderField = utils.parseSqlIdentifier(orderField, "order field");
12746
+ const rows = await client.manyOrNone(
12747
+ `SELECT ${selectColumns}
12748
+ FROM ${table}
12749
+ ${whereClause}
12750
+ ORDER BY "${safeOrderField}" ${orderDir}, "cursorId" ${orderDir}
12751
+ LIMIT $${acc.next++} OFFSET $${acc.next++}`,
12752
+ [...acc.params, perPage, page * perPage]
12753
+ );
12754
+ items = rows.map(mapRow);
12755
+ }
12756
+ const deltaCursor = config.includeDeltaCursor ? await readSignalStreamHeadCursor({ client, table, filters, applyFilters }) : void 0;
12757
+ return {
12758
+ pagination: { total, page, perPage, hasMore: (page + 1) * perPage < total },
12759
+ ...responseItems(responseKey, items),
12760
+ ...deltaCursor !== void 0 ? { deltaCursor } : {}
12761
+ };
12762
+ }
12763
+ async function listSignalDelta(config) {
12764
+ const { client, table, filters, selectColumns, responseKey, applyFilters, mapRow, after, limit } = config;
12765
+ if (after === void 0) {
12766
+ const deltaCursor2 = await readSignalStreamHeadCursor({ client, table, filters, applyFilters });
12767
+ return { ...responseItems(responseKey, []), delta: { limit, hasMore: false }, deltaCursor: deltaCursor2 };
12768
+ }
12769
+ const afterCursor = decodeDeltaCursor(after);
12770
+ const safeHorizon = await readSafeXactHorizon(client);
12771
+ const acc = newFilterAccumulator();
12772
+ applyFilters(acc, filters);
12773
+ acc.conditions.push(`("xactId", "cursorId") > ($${acc.next++}::xid8, $${acc.next++}::bigint)`);
12774
+ acc.params.push(afterCursor.xactId, afterCursor.cursorId);
12775
+ acc.conditions.push(`"xactId" < $${acc.next++}::xid8`);
12776
+ acc.params.push(safeHorizon);
12777
+ const rows = await client.manyOrNone(
12778
+ `SELECT ${selectColumns}
12779
+ FROM ${table}
12780
+ ${whereOrEmpty(acc)}
12781
+ ORDER BY "xactId" ASC, "cursorId" ASC
12782
+ LIMIT $${acc.next++}`,
12783
+ [...acc.params, limit + 1]
12784
+ );
12785
+ const hasMore = rows.length > limit;
12786
+ const visible = rows.slice(0, limit);
12787
+ const deltaCursor = visible.length > 0 ? encodeDeltaCursor(visible[visible.length - 1].xactId, visible[visible.length - 1].cursorId) : encodeDeltaCursor(safeHorizon, 0);
12788
+ return {
12789
+ ...responseItems(responseKey, visible.map(mapRow)),
12790
+ delta: { limit, hasMore },
12791
+ deltaCursor
12792
+ };
12793
+ }
12794
+ var INTERVAL_SECONDS = {
12795
+ "1m": 60,
12796
+ "5m": 300,
12797
+ "15m": 900,
12798
+ "1h": 3600,
12799
+ "1d": 86400
12800
+ };
12801
+ function bucketSql(column, interval) {
12802
+ const seconds = INTERVAL_SECONDS[interval] ?? 3600;
12803
+ return `to_timestamp(floor(extract(epoch from ${column}) / ${seconds}) * ${seconds})`;
12804
+ }
12805
+ function resolveDistinctColumnSql(distinctColumn) {
12806
+ if (!distinctColumn) {
12807
+ throw new Error(`count_distinct aggregation requires a 'distinctColumn' argument`);
12808
+ }
12809
+ if (!storage.METRIC_DISTINCT_COLUMNS.includes(distinctColumn)) {
12810
+ throw new Error(`Invalid distinctColumn: ${distinctColumn}`);
12811
+ }
12812
+ return `"${utils.parseFieldKey(distinctColumn)}"`;
12813
+ }
12814
+ function metricAggregationSql(agg, measure, timestampColumn = "timestamp", distinctColumn) {
12815
+ if (agg === "count_distinct") {
12816
+ return `COUNT(DISTINCT ${resolveDistinctColumnSql(distinctColumn)})::double precision`;
12817
+ }
12818
+ return aggregationSql(agg, measure, timestampColumn);
12819
+ }
12820
+ function aggregationSql(agg, measure, timestampColumn = "timestamp") {
12821
+ switch (agg) {
12822
+ case "sum":
12823
+ return `SUM(${measure})`;
12824
+ case "avg":
12825
+ return `AVG(${measure})`;
12826
+ case "min":
12827
+ return `MIN(${measure})`;
12828
+ case "max":
12829
+ return `MAX(${measure})`;
12830
+ case "count":
12831
+ return `COUNT(${measure})::double precision`;
12832
+ case "last":
12833
+ return `(array_agg(${measure} ORDER BY "${timestampColumn}" DESC))[1]`;
12834
+ default:
12835
+ return `SUM(${measure})`;
12836
+ }
12837
+ }
12838
+ function resolveGroupBy(acc, groupBy, options) {
12839
+ const labelsColumn = options.labelsColumn ?? null;
12840
+ const excluded = options.excludedColumns ?? /* @__PURE__ */ new Set();
12841
+ return groupBy.map((key, index) => {
12842
+ const alias = `group_by_${index}`;
12843
+ if (options.typedColumns.has(key)) {
12844
+ const parsed = utils.parseFieldKey(key);
12845
+ if (excluded.has(parsed)) {
12846
+ throw new Error(`Invalid groupBy column(s): ${key}`);
12847
+ }
12848
+ return {
12849
+ requestedKey: key,
12850
+ alias,
12851
+ selectSql: `"${parsed}" AS ${alias}`,
12852
+ valueSql: `"${parsed}"`
12853
+ };
12854
+ }
12855
+ if (!labelsColumn) {
12856
+ throw new Error(`Invalid groupBy column(s): ${key}`);
12857
+ }
12858
+ const valueSql = `"${labelsColumn}" ->> $${acc.next++}`;
12859
+ acc.params.push(key);
12860
+ return {
12861
+ requestedKey: key,
12862
+ alias,
12863
+ selectSql: `${valueSql} AS ${alias}`,
12864
+ valueSql
12865
+ };
12866
+ });
12867
+ }
12868
+ function pushLabelExclusions(acc, resolved) {
12869
+ for (const entry of resolved) {
12870
+ if (entry.valueSql.includes("->>")) {
12871
+ acc.conditions.push(`${entry.valueSql} IS NOT NULL`);
12872
+ acc.conditions.push(`${entry.valueSql} <> ''`);
12873
+ }
12874
+ }
12875
+ }
12876
+ function dimensionsFromRow(row, resolved) {
12877
+ const out = {};
12878
+ for (const entry of resolved) {
12879
+ const v = row[entry.alias];
12880
+ out[entry.requestedKey] = v == null || v === "" ? null : String(v);
12881
+ }
12882
+ return out;
12883
+ }
12884
+ function seriesNameFromDimensions(values) {
12885
+ return values.map((v) => v == null || v === "" ? "" : String(v)).join("|");
12886
+ }
12887
+ function shiftRange(range, period) {
12888
+ if (!range.start || !range.end) return null;
12889
+ const start = range.start.getTime();
12890
+ const end = range.end.getTime();
12891
+ const duration = end - start;
12892
+ let offset;
12893
+ switch (period) {
12894
+ case "previous_day":
12895
+ offset = 864e5;
12896
+ break;
12897
+ case "previous_week":
12898
+ offset = 7 * 864e5;
12899
+ break;
12900
+ case "previous_period":
12901
+ default:
12902
+ offset = duration;
12903
+ }
12904
+ return {
12905
+ start: new Date(start - offset),
12906
+ end: new Date(end - offset),
12907
+ startExclusive: range.startExclusive,
12908
+ endExclusive: range.endExclusive
12909
+ };
12910
+ }
12911
+ function changePercent(current, previous) {
12912
+ if (current === null || previous === null || previous === 0) return null;
12913
+ return (current - previous) / Math.abs(previous) * 100;
12914
+ }
12915
+ function bucketDate(value) {
12916
+ return value instanceof Date ? value : new Date(String(value));
12917
+ }
12918
+ function validatePercentiles(percentiles) {
12919
+ if (!percentiles.length) {
12920
+ throw new Error("Percentiles must include at least one value between 0 and 1.");
12921
+ }
12922
+ for (const percentile of percentiles) {
12923
+ if (!Number.isFinite(percentile) || percentile < 0 || percentile > 1) {
12924
+ throw new Error(`Percentile value must be a finite number between 0 and 1, got ${percentile}`);
12925
+ }
12926
+ }
12927
+ }
12928
+ function percentileSelectSql(percentiles, measureSql) {
12929
+ return percentiles.map((percentile, index) => `percentile_cont(${percentile}) WITHIN GROUP (ORDER BY ${measureSql}) AS p${index}`).join(", ");
12930
+ }
12931
+ function percentileSeriesFromRows(rows, percentiles) {
12932
+ return percentiles.map((percentile, index) => ({
12933
+ percentile,
12934
+ points: rows.map((row) => ({
12935
+ timestamp: bucketDate(row.bucket),
12936
+ value: Number(row[`p${index}`] ?? 0)
12937
+ }))
12938
+ }));
12939
+ }
12940
+ function collectSeriesByDimensions(rows, resolved, createEntry, appendRow) {
12941
+ const seriesMap = /* @__PURE__ */ new Map();
12942
+ for (const row of rows) {
12943
+ const dimensionValues = resolved.map((entry2) => row[entry2.alias]);
12944
+ const seriesKey = JSON.stringify(dimensionValues);
12945
+ let entry = seriesMap.get(seriesKey);
12946
+ if (!entry) {
12947
+ entry = createEntry(dimensionValues);
12948
+ seriesMap.set(seriesKey, entry);
12949
+ }
12950
+ appendRow(entry, row, dimensionValues);
12951
+ }
12952
+ return Array.from(seriesMap.values());
12953
+ }
12954
+ var COST_SUMMARY_SELECT = `
12955
+ SUM("estimatedCost") FILTER (WHERE "estimatedCost" IS NOT NULL) AS "agg_estimatedCost",
12956
+ CASE
12957
+ WHEN COUNT(DISTINCT "costUnit") FILTER (WHERE "costUnit" IS NOT NULL) = 1
12958
+ THEN MIN("costUnit") FILTER (WHERE "costUnit" IS NOT NULL)
12959
+ ELSE NULL
12960
+ END AS "agg_costUnit"
12961
+ `;
12962
+ function costSummaryFromRow(row) {
12963
+ return {
12964
+ estimatedCost: row.agg_estimatedCost == null ? null : Number(row.agg_estimatedCost),
12965
+ costUnit: row.agg_costUnit == null || row.agg_costUnit === "" ? null : String(row.agg_costUnit)
12966
+ };
12967
+ }
12968
+ var COMPLEX_GROUP_BY_EXCLUDED = /* @__PURE__ */ new Set([
12969
+ "metadata",
12970
+ "metadataRaw",
12971
+ "metadataSearch",
12972
+ "scope",
12973
+ "attributes",
12974
+ "links",
12975
+ "input",
12976
+ "output",
12977
+ "error",
12978
+ "data",
12979
+ "labels",
12980
+ "costMetadata",
12981
+ "tags",
12982
+ "requestContext"
12983
+ ]);
12984
+ function encodeJsonb(value) {
12985
+ if (value === null || value === void 0) return null;
12986
+ return JSON.stringify(value);
12987
+ }
12988
+ function buildInsert(schema, table, records) {
12989
+ if (records.length === 0) return null;
12990
+ const columns = Object.keys(records[0]).map((c) => utils.parseSqlIdentifier(c, "column name"));
12991
+ const quotedColumns = columns.map((c) => `"${c}"`).join(", ");
12992
+ const values = [];
12993
+ const rowPlaceholders = [];
12994
+ let p = 1;
12995
+ for (const record of records) {
12996
+ const placeholders = columns.map((col) => {
12997
+ const raw = record[col];
12998
+ if (JSONB_COLUMNS.has(col)) {
12999
+ values.push(encodeJsonb(raw));
13000
+ return `$${p++}::jsonb`;
13001
+ }
13002
+ if (TEXT_ARRAY_COLUMNS.has(col)) {
13003
+ values.push(Array.isArray(raw) ? raw : []);
13004
+ return `$${p++}::text[]`;
13005
+ }
13006
+ values.push(raw === void 0 ? null : raw);
13007
+ return `$${p++}`;
13008
+ });
13009
+ rowPlaceholders.push(`(${placeholders.join(", ")})`);
13010
+ }
13011
+ const text = `INSERT INTO ${qualifiedTable(schema, table)} (${quotedColumns})
13012
+ VALUES ${rowPlaceholders.join(", ")}
13013
+ ON CONFLICT DO NOTHING`;
13014
+ return { text, values };
13015
+ }
13016
+ var SPAN_SELECT_COLUMNS = `
13017
+ ${buildSelectColumns(SPAN_EVENT_COLUMNS)}`;
13018
+ var SPAN_LIGHT_SELECT_COLUMNS = `
13019
+ ${buildNamedSelectColumns(SPAN_LIGHT_SELECT_COLUMN_NAMES)}`;
13020
+ var METRIC_SELECT_COLUMNS = `
13021
+ ${buildSelectColumns(METRIC_EVENT_COLUMNS)}`;
13022
+ var LOG_SELECT_COLUMNS = `
13023
+ ${buildSelectColumns(LOG_EVENT_COLUMNS)}`;
13024
+ var SCORE_SELECT_COLUMNS = `
13025
+ ${buildSelectColumns(SCORE_EVENT_COLUMNS)}`;
13026
+ var FEEDBACK_SELECT_COLUMNS = `
13027
+ ${buildSelectColumns(FEEDBACK_EVENT_COLUMNS)}`;
13028
+
13029
+ // src/storage/domains/observability/v-next/feedback.ts
13030
+ function applyFeedbackFilters(acc, filters) {
13031
+ applyCommonFilters(acc, filters);
13032
+ applySingleOrArrayFilter(acc, "feedbackType", filters?.feedbackType);
13033
+ if (filters?.feedbackSource ?? filters?.source) {
13034
+ acc.conditions.push(`"feedbackSource" = $${acc.next++}`);
13035
+ acc.params.push(filters.feedbackSource ?? filters.source);
13036
+ }
13037
+ if (filters?.feedbackUserId) {
13038
+ acc.conditions.push(`"feedbackUserId" = $${acc.next++}`);
13039
+ acc.params.push(filters.feedbackUserId);
13040
+ }
13041
+ }
13042
+ function pushFeedbackIdentity(acc, feedbackType, feedbackSource) {
13043
+ acc.conditions.push(`"feedbackType" = $${acc.next++}`);
13044
+ acc.params.push(feedbackType);
13045
+ if (feedbackSource !== void 0) {
13046
+ acc.conditions.push(`"feedbackSource" = $${acc.next++}`);
13047
+ acc.params.push(feedbackSource);
13048
+ }
13049
+ acc.conditions.push(`"valueNumber" IS NOT NULL`);
13050
+ }
13051
+ async function createFeedback(client, schema, args) {
13052
+ const row = feedbackRecordToRow(args.feedback);
13053
+ const insert = buildInsert(schema, TABLE_FEEDBACK_EVENTS, [row]);
13054
+ if (insert) await client.query(insert.text, insert.values);
13055
+ }
13056
+ async function batchCreateFeedback(client, schema, args) {
13057
+ if (args.feedbacks.length === 0) return;
13058
+ const rows = args.feedbacks.map(feedbackRecordToRow);
13059
+ const insert = buildInsert(schema, TABLE_FEEDBACK_EVENTS, rows);
13060
+ if (insert) await client.query(insert.text, insert.values);
13061
+ }
13062
+ async function listFeedback(client, schema, args) {
13063
+ const { mode, filters, pagination, orderBy, after, limit } = storage.listFeedbackArgsSchema.parse(args);
13064
+ const table = qualifiedTable(schema, TABLE_FEEDBACK_EVENTS);
13065
+ if (mode === "delta") {
13066
+ assertDeltaPollingEnabled();
13067
+ return listFeedbackDelta(client, table, filters, after, limit);
13068
+ }
13069
+ return listFeedbackPage(
13070
+ client,
13071
+ table,
13072
+ filters,
13073
+ pagination.page,
13074
+ pagination.perPage,
13075
+ orderBy.field,
13076
+ orderBy.direction
13077
+ );
13078
+ }
13079
+ async function listFeedbackPage(client, table, filters, page, perPage, orderField, orderDir) {
13080
+ return listSignalPage({
13081
+ client,
13082
+ table,
13083
+ filters,
13084
+ page,
13085
+ perPage,
13086
+ orderField,
13087
+ orderDir,
13088
+ includeDeltaCursor: deltaPollingFeatureEnabled(),
13089
+ selectColumns: FEEDBACK_SELECT_COLUMNS,
13090
+ responseKey: "feedback",
13091
+ applyFilters: applyFeedbackFilters,
13092
+ mapRow: rowToFeedbackRecord
13093
+ });
13094
+ }
13095
+ async function listFeedbackDelta(client, table, filters, after, limit) {
13096
+ return listSignalDelta({
13097
+ client,
13098
+ table,
13099
+ filters,
13100
+ after,
13101
+ limit,
13102
+ selectColumns: FEEDBACK_SELECT_COLUMNS,
13103
+ responseKey: "feedback",
13104
+ applyFilters: applyFeedbackFilters,
13105
+ mapRow: rowToFeedbackRecord
13106
+ });
13107
+ }
13108
+ async function runFeedbackAggregateQuery(client, schema, args, filters) {
13109
+ const acc = newFilterAccumulator();
13110
+ pushFeedbackIdentity(acc, args.feedbackType, args.feedbackSource);
13111
+ applyFeedbackFilters(acc, filters);
13112
+ const sql = `
13113
+ SELECT ${aggregationSql(args.aggregation, '"valueNumber"')} AS "value"
13114
+ FROM ${qualifiedTable(schema, TABLE_FEEDBACK_EVENTS)}
13115
+ ${whereOrEmpty(acc)}
13116
+ `;
13117
+ const row = await client.oneOrNone(sql, acc.params);
13118
+ return row?.value == null ? null : Number(row.value);
13119
+ }
13120
+ async function getFeedbackAggregate(client, schema, args) {
13121
+ const value = await runFeedbackAggregateQuery(client, schema, args, args.filters);
13122
+ if (args.comparePeriod && args.filters?.timestamp) {
13123
+ const prevRange = shiftRange(args.filters.timestamp, args.comparePeriod);
13124
+ if (prevRange) {
13125
+ const previousValue = await runFeedbackAggregateQuery(client, schema, args, {
13126
+ ...args.filters ?? {},
13127
+ timestamp: prevRange
13128
+ });
13129
+ return {
13130
+ value,
13131
+ previousValue,
13132
+ changePercent: changePercent(value, previousValue)
13133
+ };
13134
+ }
13135
+ }
13136
+ return { value };
13137
+ }
13138
+ async function getFeedbackBreakdown(client, schema, args) {
13139
+ const acc = newFilterAccumulator();
13140
+ const resolved = resolveGroupBy(acc, args.groupBy, {
13141
+ typedColumns: FEEDBACK_TYPED_COLUMNS,
13142
+ excludedColumns: COMPLEX_GROUP_BY_EXCLUDED
13143
+ });
13144
+ pushFeedbackIdentity(acc, args.feedbackType, args.feedbackSource);
13145
+ applyFeedbackFilters(acc, args.filters);
13146
+ const sql = `
13147
+ SELECT ${resolved.map((e) => e.selectSql).join(", ")},
13148
+ ${aggregationSql(args.aggregation, '"valueNumber"')} AS "value"
13149
+ FROM ${qualifiedTable(schema, TABLE_FEEDBACK_EVENTS)}
13150
+ ${whereOrEmpty(acc)}
13151
+ GROUP BY ${resolved.map((e) => e.alias).join(", ")}
13152
+ ORDER BY "value" DESC NULLS LAST
13153
+ `;
13154
+ const rows = await client.manyOrNone(sql, acc.params);
13155
+ return {
13156
+ groups: rows.map((row) => ({
13157
+ dimensions: dimensionsFromRow(row, resolved),
13158
+ value: Number(row.value ?? 0)
13159
+ }))
13160
+ };
13161
+ }
13162
+ async function getFeedbackTimeSeries(client, schema, args) {
13163
+ const bucket = bucketSql('"timestamp"', args.interval);
13164
+ if (args.groupBy && args.groupBy.length > 0) {
13165
+ const acc2 = newFilterAccumulator();
13166
+ const resolved = resolveGroupBy(acc2, args.groupBy, {
13167
+ typedColumns: FEEDBACK_TYPED_COLUMNS,
13168
+ excludedColumns: COMPLEX_GROUP_BY_EXCLUDED
13169
+ });
13170
+ pushFeedbackIdentity(acc2, args.feedbackType, args.feedbackSource);
13171
+ applyFeedbackFilters(acc2, args.filters);
13172
+ const sql2 = `
13173
+ SELECT ${bucket} AS bucket,
13174
+ ${resolved.map((e) => e.selectSql).join(", ")},
13175
+ ${aggregationSql(args.aggregation, '"valueNumber"')} AS "value"
13176
+ FROM ${qualifiedTable(schema, TABLE_FEEDBACK_EVENTS)}
13177
+ ${whereOrEmpty(acc2)}
13178
+ GROUP BY bucket, ${resolved.map((e) => e.alias).join(", ")}
13179
+ ORDER BY bucket
13180
+ `;
13181
+ const rows2 = await client.manyOrNone(sql2, acc2.params);
13182
+ return {
13183
+ series: collectSeriesByDimensions(
13184
+ rows2,
13185
+ resolved,
13186
+ (dimValues) => ({
13187
+ name: seriesNameFromDimensions(dimValues),
13188
+ points: []
13189
+ }),
13190
+ (entry, row) => {
13191
+ entry.points.push({
13192
+ timestamp: bucketDate(row.bucket),
13193
+ value: Number(row.value ?? 0)
13194
+ });
13195
+ }
13196
+ )
13197
+ };
13198
+ }
13199
+ const acc = newFilterAccumulator();
13200
+ pushFeedbackIdentity(acc, args.feedbackType, args.feedbackSource);
13201
+ applyFeedbackFilters(acc, args.filters);
13202
+ const sql = `
13203
+ SELECT ${bucket} AS bucket,
13204
+ ${aggregationSql(args.aggregation, '"valueNumber"')} AS "value"
13205
+ FROM ${qualifiedTable(schema, TABLE_FEEDBACK_EVENTS)}
13206
+ ${whereOrEmpty(acc)}
13207
+ GROUP BY bucket
13208
+ ORDER BY bucket
13209
+ `;
13210
+ const rows = await client.manyOrNone(sql, acc.params);
13211
+ const seriesName = args.feedbackSource ? `${args.feedbackType}|${args.feedbackSource}` : args.feedbackType;
13212
+ return {
13213
+ series: [
13214
+ {
13215
+ name: seriesName,
13216
+ points: rows.map((row) => ({
13217
+ timestamp: bucketDate(row.bucket),
13218
+ value: Number(row.value ?? 0)
13219
+ }))
13220
+ }
13221
+ ]
13222
+ };
13223
+ }
13224
+ async function getFeedbackPercentiles(client, schema, args) {
13225
+ validatePercentiles(args.percentiles);
13226
+ const bucket = bucketSql('"timestamp"', args.interval);
13227
+ const acc = newFilterAccumulator();
13228
+ pushFeedbackIdentity(acc, args.feedbackType, args.feedbackSource);
13229
+ applyFeedbackFilters(acc, args.filters);
13230
+ const percentileSelect = percentileSelectSql(args.percentiles, '"valueNumber"');
13231
+ const sql = `
13232
+ SELECT ${bucket} AS bucket, ${percentileSelect}
13233
+ FROM ${qualifiedTable(schema, TABLE_FEEDBACK_EVENTS)}
13234
+ ${whereOrEmpty(acc)}
13235
+ GROUP BY bucket
13236
+ ORDER BY bucket
13237
+ `;
13238
+ const rows = await client.manyOrNone(sql, acc.params);
13239
+ return { series: percentileSeriesFromRows(rows, args.percentiles) };
13240
+ }
13241
+ function applyLogFilters(acc, filters) {
13242
+ applyCommonFilters(acc, filters);
13243
+ applySingleOrArrayFilter(acc, "level", filters?.level);
13244
+ }
13245
+ async function batchCreateLogs(client, schema, args) {
13246
+ if (args.logs.length === 0) return;
13247
+ const rows = args.logs.map(logRecordToRow);
13248
+ const insert = buildInsert(schema, TABLE_LOG_EVENTS, rows);
13249
+ if (insert) await client.query(insert.text, insert.values);
13250
+ }
13251
+ async function listLogs(client, schema, args) {
13252
+ const { mode, filters, pagination, orderBy, after, limit } = storage.listLogsArgsSchema.parse(args);
13253
+ const table = qualifiedTable(schema, TABLE_LOG_EVENTS);
13254
+ if (mode === "delta") {
13255
+ assertDeltaPollingEnabled();
13256
+ return listLogsDelta(client, table, filters, after, limit);
13257
+ }
13258
+ return listLogsPage(client, table, filters, pagination.page, pagination.perPage, orderBy.field, orderBy.direction);
13259
+ }
13260
+ async function listLogsPage(client, table, filters, page, perPage, orderField, orderDir) {
13261
+ return listSignalPage({
13262
+ client,
13263
+ table,
13264
+ filters,
13265
+ page,
13266
+ perPage,
13267
+ orderField,
13268
+ orderDir,
13269
+ includeDeltaCursor: deltaPollingFeatureEnabled(),
13270
+ selectColumns: LOG_SELECT_COLUMNS,
13271
+ responseKey: "logs",
13272
+ applyFilters: applyLogFilters,
13273
+ mapRow: rowToLogRecord
13274
+ });
13275
+ }
13276
+ async function listLogsDelta(client, table, filters, after, limit) {
13277
+ return listSignalDelta({
13278
+ client,
13279
+ table,
13280
+ filters,
13281
+ after,
13282
+ limit,
13283
+ selectColumns: LOG_SELECT_COLUMNS,
13284
+ responseKey: "logs",
13285
+ applyFilters: applyLogFilters,
13286
+ mapRow: rowToLogRecord
13287
+ });
13288
+ }
13289
+ function applyMetricFilters(acc, filters) {
13290
+ applyCommonFilters(acc, filters);
13291
+ applySingleOrArrayFilter(acc, "name", filters?.name);
13292
+ applySingleOrArrayFilter(acc, "provider", filters?.provider);
13293
+ applySingleOrArrayFilter(acc, "model", filters?.model);
13294
+ applySingleOrArrayFilter(acc, "costUnit", filters?.costUnit);
13295
+ if (filters?.labels) {
13296
+ acc.conditions.push(`"labels" @> $${acc.next++}::jsonb`);
13297
+ acc.params.push(JSON.stringify(filters.labels));
13298
+ }
13299
+ }
13300
+ function pushMetricNameFilter(acc, names) {
13301
+ if (!names.length) return;
13302
+ const placeholders = names.map(() => `$${acc.next++}`).join(", ");
13303
+ acc.conditions.push(`"name" IN (${placeholders})`);
13304
+ acc.params.push(...names);
13305
+ }
13306
+ async function batchCreateMetrics(client, schema, args) {
13307
+ if (args.metrics.length === 0) return;
13308
+ const rows = args.metrics.map(metricRecordToRow);
13309
+ const insert = buildInsert(schema, TABLE_METRIC_EVENTS, rows);
13310
+ if (insert) await client.query(insert.text, insert.values);
13311
+ }
13312
+ async function listMetrics(client, schema, args) {
13313
+ const { mode, filters, pagination, orderBy, after, limit } = storage.listMetricsArgsSchema.parse(args);
13314
+ const table = qualifiedTable(schema, TABLE_METRIC_EVENTS);
13315
+ if (mode === "delta") {
13316
+ assertDeltaPollingEnabled();
13317
+ return listMetricsDelta(client, table, filters, after, limit);
13318
+ }
13319
+ return listMetricsPage(client, table, filters, pagination.page, pagination.perPage, orderBy.field, orderBy.direction);
13320
+ }
13321
+ async function listMetricsPage(client, table, filters, page, perPage, orderField, orderDir) {
13322
+ return listSignalPage({
13323
+ client,
13324
+ table,
13325
+ filters,
13326
+ page,
13327
+ perPage,
13328
+ orderField,
13329
+ orderDir,
13330
+ includeDeltaCursor: deltaPollingFeatureEnabled(),
13331
+ selectColumns: METRIC_SELECT_COLUMNS,
13332
+ responseKey: "metrics",
13333
+ applyFilters: applyMetricFilters,
13334
+ mapRow: rowToMetricRecord
13335
+ });
13336
+ }
13337
+ async function listMetricsDelta(client, table, filters, after, limit) {
13338
+ return listSignalDelta({
13339
+ client,
13340
+ table,
13341
+ filters,
13342
+ after,
13343
+ limit,
13344
+ selectColumns: METRIC_SELECT_COLUMNS,
13345
+ responseKey: "metrics",
13346
+ applyFilters: applyMetricFilters,
13347
+ mapRow: rowToMetricRecord
13348
+ });
13349
+ }
13350
+ async function runMetricAggregateQuery(client, schema, filters, names, aggregation, distinctColumn) {
13351
+ const acc = newFilterAccumulator();
13352
+ pushMetricNameFilter(acc, names);
13353
+ applyMetricFilters(acc, filters);
13354
+ const where = whereOrEmpty(acc);
13355
+ const sql = `
13356
+ SELECT ${metricAggregationSql(aggregation, '"value"', "timestamp", distinctColumn)} AS "value",
13357
+ ${COST_SUMMARY_SELECT}
13358
+ FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)}
13359
+ ${where}
13360
+ `;
13361
+ const row = await client.oneOrNone(sql, acc.params) ?? {};
13362
+ return {
13363
+ value: row.value == null ? null : Number(row.value),
13364
+ cost: costSummaryFromRow(row)
13365
+ };
13366
+ }
13367
+ async function getMetricAggregate(client, schema, args) {
13368
+ const { value, cost } = await runMetricAggregateQuery(
13369
+ client,
13370
+ schema,
13371
+ args.filters,
13372
+ args.name,
13373
+ args.aggregation,
13374
+ args.distinctColumn
13375
+ );
13376
+ if (args.comparePeriod && args.filters?.timestamp) {
13377
+ const prevRange = shiftRange(args.filters.timestamp, args.comparePeriod);
13378
+ if (prevRange) {
13379
+ const prevFilters = { ...args.filters ?? {}, timestamp: prevRange };
13380
+ const prev = await runMetricAggregateQuery(
13381
+ client,
13382
+ schema,
13383
+ prevFilters,
13384
+ args.name,
13385
+ args.aggregation,
13386
+ args.distinctColumn
13387
+ );
13388
+ return {
13389
+ value,
13390
+ estimatedCost: cost.estimatedCost,
13391
+ costUnit: cost.costUnit,
13392
+ previousValue: prev.value,
13393
+ previousEstimatedCost: prev.cost.estimatedCost,
13394
+ changePercent: changePercent(value, prev.value),
13395
+ costChangePercent: changePercent(cost.estimatedCost, prev.cost.estimatedCost)
13396
+ };
13397
+ }
13398
+ }
13399
+ return { value, estimatedCost: cost.estimatedCost, costUnit: cost.costUnit };
13400
+ }
13401
+ async function getMetricBreakdown(client, schema, args) {
13402
+ const acc = newFilterAccumulator();
13403
+ const resolved = resolveGroupBy(acc, args.groupBy, {
13404
+ typedColumns: METRIC_TYPED_COLUMNS,
13405
+ excludedColumns: COMPLEX_GROUP_BY_EXCLUDED,
13406
+ labelsColumn: "labels"
13407
+ });
13408
+ pushMetricNameFilter(acc, args.name);
13409
+ applyMetricFilters(acc, args.filters);
13410
+ pushLabelExclusions(acc, resolved);
13411
+ const orderDirection = args.orderDirection === "ASC" ? "ASC" : "DESC";
13412
+ const limitClause = args.limit == null ? "" : `LIMIT $${acc.next++}`;
13413
+ if (args.limit != null) acc.params.push(args.limit);
13414
+ const sql = `
13415
+ SELECT ${resolved.map((e) => e.selectSql).join(", ")},
13416
+ ${metricAggregationSql(args.aggregation, '"value"', "timestamp", args.distinctColumn)} AS "value",
13417
+ ${COST_SUMMARY_SELECT}
13418
+ FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)}
13419
+ ${whereOrEmpty(acc)}
13420
+ GROUP BY ${resolved.map((e) => e.alias).join(", ")}
13421
+ ORDER BY "value" ${orderDirection} NULLS LAST
13422
+ ${limitClause}
13423
+ `;
13424
+ const rows = await client.manyOrNone(sql, acc.params);
13425
+ return {
13426
+ groups: rows.map((row) => {
13427
+ const cs = costSummaryFromRow(row);
13428
+ return {
13429
+ dimensions: dimensionsFromRow(row, resolved),
13430
+ value: Number(row.value ?? 0),
13431
+ estimatedCost: cs.estimatedCost,
13432
+ costUnit: cs.costUnit
13433
+ };
13434
+ })
13435
+ };
13436
+ }
13437
+ async function getMetricTimeSeries(client, schema, args) {
13438
+ const bucket = bucketSql('"timestamp"', args.interval);
13439
+ if (args.groupBy && args.groupBy.length > 0) {
13440
+ const acc2 = newFilterAccumulator();
13441
+ const resolved = resolveGroupBy(acc2, args.groupBy, {
13442
+ typedColumns: METRIC_TYPED_COLUMNS,
13443
+ excludedColumns: COMPLEX_GROUP_BY_EXCLUDED,
13444
+ labelsColumn: "labels"
13445
+ });
13446
+ pushMetricNameFilter(acc2, args.name);
13447
+ applyMetricFilters(acc2, args.filters);
13448
+ pushLabelExclusions(acc2, resolved);
13449
+ const sql2 = `
13450
+ SELECT ${bucket} AS bucket,
13451
+ ${resolved.map((e) => e.selectSql).join(", ")},
13452
+ ${metricAggregationSql(args.aggregation, '"value"', "timestamp", args.distinctColumn)} AS "value",
13453
+ ${COST_SUMMARY_SELECT}
13454
+ FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)}
13455
+ ${whereOrEmpty(acc2)}
13456
+ GROUP BY bucket, ${resolved.map((e) => e.alias).join(", ")}
13457
+ ORDER BY bucket
13458
+ `;
13459
+ const rows2 = await client.manyOrNone(sql2, acc2.params);
13460
+ const series = collectSeriesByDimensions(
13461
+ rows2,
13462
+ resolved,
13463
+ (dimValues) => ({
13464
+ name: seriesNameFromDimensions(dimValues),
13465
+ costUnits: /* @__PURE__ */ new Set(),
13466
+ points: []
13467
+ }),
13468
+ (entry, row) => {
13469
+ const cs = costSummaryFromRow(row);
13470
+ if (cs.costUnit) entry.costUnits.add(cs.costUnit);
13471
+ entry.points.push({
13472
+ timestamp: bucketDate(row.bucket),
13473
+ value: Number(row.value ?? 0),
13474
+ estimatedCost: cs.estimatedCost
13475
+ });
13476
+ }
13477
+ ).map((s) => ({
13478
+ name: s.name,
13479
+ costUnit: s.costUnits.size === 1 ? Array.from(s.costUnits)[0] : null,
13480
+ points: s.points
13481
+ }));
13482
+ return { series };
13483
+ }
13484
+ const acc = newFilterAccumulator();
13485
+ pushMetricNameFilter(acc, args.name);
13486
+ applyMetricFilters(acc, args.filters);
13487
+ const sql = `
13488
+ SELECT ${bucket} AS bucket,
13489
+ ${metricAggregationSql(args.aggregation, '"value"', "timestamp", args.distinctColumn)} AS "value",
13490
+ ${COST_SUMMARY_SELECT}
13491
+ FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)}
13492
+ ${whereOrEmpty(acc)}
13493
+ GROUP BY bucket
13494
+ ORDER BY bucket
13495
+ `;
13496
+ const rows = await client.manyOrNone(sql, acc.params);
13497
+ const overallCostUnits = /* @__PURE__ */ new Set();
13498
+ for (const row of rows) {
13499
+ const cs = costSummaryFromRow(row);
13500
+ if (cs.costUnit) overallCostUnits.add(cs.costUnit);
13501
+ }
13502
+ return {
13503
+ series: [
13504
+ {
13505
+ name: args.name.join("|"),
13506
+ costUnit: overallCostUnits.size === 1 ? Array.from(overallCostUnits)[0] : null,
13507
+ points: rows.map((row) => {
13508
+ const cs = costSummaryFromRow(row);
13509
+ return {
13510
+ timestamp: bucketDate(row.bucket),
13511
+ value: Number(row.value ?? 0),
13512
+ estimatedCost: cs.estimatedCost
13513
+ };
13514
+ })
13515
+ }
13516
+ ]
13517
+ };
13518
+ }
13519
+ async function getMetricPercentiles(client, schema, args) {
13520
+ validatePercentiles(args.percentiles);
13521
+ const bucket = bucketSql('"timestamp"', args.interval);
13522
+ const acc = newFilterAccumulator();
13523
+ pushMetricNameFilter(acc, [args.name]);
13524
+ applyMetricFilters(acc, args.filters);
13525
+ const percentileSelect = percentileSelectSql(args.percentiles, '"value"');
13526
+ const sql = `
13527
+ SELECT ${bucket} AS bucket, ${percentileSelect}
13528
+ FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)}
13529
+ ${whereOrEmpty(acc)}
13530
+ GROUP BY bucket
13531
+ ORDER BY bucket
13532
+ `;
13533
+ const rows = await client.manyOrNone(sql, acc.params);
13534
+ return { series: percentileSeriesFromRows(rows, args.percentiles) };
13535
+ }
13536
+
13537
+ // src/storage/domains/observability/v-next/pg-errors.ts
13538
+ function asPgError(error) {
13539
+ return error ?? {};
13540
+ }
13541
+ function isDuplicateRelationError(error) {
13542
+ const { code, constraint, message = "" } = asPgError(error);
13543
+ if (code === "42P07") return true;
13544
+ if (code === "23505" && (constraint === "pg_type_typname_nsp_index" || constraint === "pg_class_relname_nsp_index")) {
13545
+ return true;
13546
+ }
13547
+ return /already exists/i.test(message);
13548
+ }
13549
+ function isDuplicateSchemaError(error) {
13550
+ const { code, constraint, message = "" } = asPgError(error);
13551
+ if (code === "42P06") return true;
13552
+ if (code === "23505" && constraint === "pg_namespace_nspname_index") return true;
13553
+ return /schema .* already exists/i.test(message);
13554
+ }
13555
+
13556
+ // src/storage/domains/observability/v-next/partitioning.ts
13557
+ var DEFAULT_FUTURE_DAYS = 14;
13558
+ async function detectTimescale(client) {
13559
+ const row = await client.oneOrNone(
13560
+ `SELECT EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'timescaledb') AS "exists"`
13561
+ );
13562
+ return Boolean(row?.exists);
13563
+ }
13564
+ async function detectPartman(client) {
13565
+ const row = await client.oneOrNone(
13566
+ `SELECT EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'pg_partman') AS "exists"`
13567
+ );
13568
+ return Boolean(row?.exists);
13569
+ }
13570
+ async function getPartmanVersion(client) {
13571
+ const row = await client.oneOrNone(
13572
+ `SELECT extversion FROM pg_extension WHERE extname = 'pg_partman'`
13573
+ );
13574
+ return row?.extversion ?? null;
13575
+ }
13576
+ function getPartmanMajor(version) {
13577
+ if (!version) return null;
13578
+ const match = /^(\d+)/.exec(version);
13579
+ return match ? Number(match[1]) : null;
13580
+ }
13581
+ async function resolveMode(client, options = {}) {
13582
+ if (options.mode && options.mode !== "auto") return options.mode;
13583
+ if (await detectTimescale(client)) return "timescale";
13584
+ if (await detectPartman(client)) return "partman";
13585
+ return "native";
13586
+ }
13587
+ function dayBounds(d) {
13588
+ const year = d.getUTCFullYear();
13589
+ const month = String(d.getUTCMonth() + 1).padStart(2, "0");
13590
+ const day = String(d.getUTCDate()).padStart(2, "0");
13591
+ const start = `${year}-${month}-${day} 00:00:00+00`;
13592
+ const next = new Date(Date.UTC(year, d.getUTCMonth(), d.getUTCDate() + 1));
13593
+ const ny = next.getUTCFullYear();
13594
+ const nm = String(next.getUTCMonth() + 1).padStart(2, "0");
13595
+ const nd = String(next.getUTCDate()).padStart(2, "0");
13596
+ const end = `${ny}-${nm}-${nd} 00:00:00+00`;
13597
+ return { start, end, suffix: `${year}${month}${day}` };
13598
+ }
13599
+ function partitionName(table, suffix) {
13600
+ return `${table}_p${suffix}`;
13601
+ }
13602
+ async function ensureNativePartitions(client, schema, options = {}) {
13603
+ const futureDays = options.futureDays ?? DEFAULT_FUTURE_DAYS;
13604
+ const includeYesterday = options.includeYesterday ?? true;
13605
+ const start = includeYesterday ? -1 : 0;
13606
+ const baseNowMs = Date.now();
13607
+ for (const table of ALL_SIGNAL_TABLES) {
13608
+ for (let i = start; i <= futureDays; i++) {
13609
+ const d = new Date(baseNowMs + i * 864e5);
13610
+ const { start: partStart, end: partEnd, suffix } = dayBounds(d);
13611
+ const childName = partitionName(table, suffix);
13612
+ const child = qualifiedName(schema, childName);
13613
+ const parent = qualifiedTable(schema, table);
13614
+ try {
13615
+ await client.none(`CREATE TABLE IF NOT EXISTS ${child} (LIKE ${parent} INCLUDING ALL)`);
13616
+ } catch (error) {
13617
+ if (!isDuplicateRelationError(error)) throw error;
13618
+ }
13619
+ try {
13620
+ await client.none(
13621
+ `ALTER TABLE ${parent} ATTACH PARTITION ${child}
13622
+ FOR VALUES FROM ('${partStart}') TO ('${partEnd}')`
13623
+ );
13624
+ } catch (error) {
13625
+ if (!isAlreadyAttachedError(error)) throw error;
13626
+ }
13627
+ }
13628
+ }
13629
+ }
13630
+ function isAlreadyAttachedError(error) {
13631
+ const code = error?.code;
13632
+ const message = error?.message ?? "";
13633
+ if (code === "42P17" || code === "42710") {
13634
+ return /is already a partition/i.test(message) || /already a partition/i.test(message);
13635
+ }
13636
+ return /is already a partition/i.test(message);
13637
+ }
13638
+ async function ensureTimescaleHypertables(client, schema) {
13639
+ for (const table of ALL_SIGNAL_TABLES) {
13640
+ const tableExpr = qualifiedTable(schema, table);
13641
+ const timeColumn = SIGNAL_TIME_COLUMN[table].replace(/'/g, "''");
13642
+ await client.none(
13643
+ `SELECT create_hypertable($1::regclass, '${timeColumn}', chunk_time_interval => INTERVAL '1 day', if_not_exists => true)`,
13644
+ [tableExpr]
13645
+ );
13646
+ }
13647
+ }
13648
+ async function ensurePartmanHypertables(client, schema) {
13649
+ const partmanMajor = getPartmanMajor(await getPartmanVersion(client));
13650
+ for (const table of ALL_SIGNAL_TABLES) {
13651
+ const exists = await client.oneOrNone(
13652
+ `SELECT EXISTS (
13653
+ SELECT 1 FROM partman.part_config
13654
+ WHERE parent_table = format('%I.%I', $1::text, $2::text)
13655
+ ) AS "exists"`,
13656
+ [schema, table]
13657
+ );
13658
+ if (exists?.exists) continue;
13659
+ for (let attempt = 0; attempt < 3; attempt++) {
13660
+ try {
13661
+ if (partmanMajor != null && partmanMajor >= 5) {
13662
+ await client.none(
13663
+ `SELECT partman.create_parent(
13664
+ p_parent_table := format('%I.%I', $1::text, $2::text),
13665
+ p_control := $3,
13666
+ p_interval := '1 day',
13667
+ p_type := 'range'
13668
+ )`,
13669
+ [schema, table, SIGNAL_TIME_COLUMN[table]]
13670
+ );
13671
+ } else {
13672
+ await client.none(
13673
+ `SELECT partman.create_parent(
13674
+ p_parent_table := format('%I.%I', $1::text, $2::text),
13675
+ p_control := $3,
13676
+ p_type := 'native',
13677
+ p_interval := '1 day'
13678
+ )`,
13679
+ [schema, table, SIGNAL_TIME_COLUMN[table]]
13680
+ );
13681
+ }
13682
+ break;
13683
+ } catch (error) {
13684
+ const message = error?.message ?? "";
13685
+ const code = error?.code;
13686
+ const isDuplicate = code === "23505" || /already managed by pg_partman/i.test(message) || /relation .* already exists/i.test(message);
13687
+ if (isDuplicate) break;
13688
+ const isDeadlock = /deadlock detected/i.test(message);
13689
+ if (!isDeadlock) throw error;
13690
+ const registered = await client.oneOrNone(
13691
+ `SELECT EXISTS (
13692
+ SELECT 1 FROM partman.part_config
13693
+ WHERE parent_table = format('%I.%I', $1::text, $2::text)
13694
+ ) AS "exists"`,
13695
+ [schema, table]
13696
+ );
13697
+ if (registered?.exists) break;
13698
+ if (attempt === 2) throw error;
13699
+ await new Promise((resolve) => setTimeout(resolve, 25));
13700
+ }
13701
+ }
13702
+ }
13703
+ }
13704
+ async function setupPartitioning(client, schema, options = {}) {
13705
+ const mode = await resolveMode(client, options);
13706
+ switch (mode) {
13707
+ case "timescale":
13708
+ await ensureTimescaleHypertables(client, schema);
13709
+ return "timescale";
13710
+ case "partman":
13711
+ await ensurePartmanHypertables(client, schema);
13712
+ return "partman";
13713
+ case "native":
13714
+ await ensureNativePartitions(client, schema, options);
13715
+ return "native";
13716
+ }
13717
+ }
13718
+ function applyScoreFilters(acc, filters) {
13719
+ applyCommonFilters(acc, filters);
13720
+ applySingleOrArrayFilter(acc, "scorerId", filters?.scorerId);
13721
+ if (filters?.scoreSource ?? filters?.source) {
13722
+ acc.conditions.push(`"scoreSource" = $${acc.next++}`);
13723
+ acc.params.push(filters.scoreSource ?? filters.source);
13724
+ }
13725
+ }
13726
+ function pushScoreIdentity(acc, scorerId, scoreSource) {
13727
+ acc.conditions.push(`"scorerId" = $${acc.next++}`);
13728
+ acc.params.push(scorerId);
13729
+ if (scoreSource !== void 0) {
13730
+ acc.conditions.push(`"scoreSource" = $${acc.next++}`);
13731
+ acc.params.push(scoreSource);
13732
+ }
13733
+ }
13734
+ async function createScore(client, schema, args) {
13735
+ const row = scoreRecordToRow(args.score);
13736
+ const insert = buildInsert(schema, TABLE_SCORE_EVENTS, [row]);
13737
+ if (insert) await client.query(insert.text, insert.values);
13738
+ }
13739
+ async function batchCreateScores(client, schema, args) {
13740
+ if (args.scores.length === 0) return;
13741
+ const rows = args.scores.map(scoreRecordToRow);
13742
+ const insert = buildInsert(schema, TABLE_SCORE_EVENTS, rows);
13743
+ if (insert) await client.query(insert.text, insert.values);
13744
+ }
13745
+ async function listScores(client, schema, args) {
13746
+ const { mode, filters, pagination, orderBy, after, limit } = storage.listScoresArgsSchema.parse(args);
13747
+ const table = qualifiedTable(schema, TABLE_SCORE_EVENTS);
13748
+ if (mode === "delta") {
13749
+ assertDeltaPollingEnabled();
13750
+ return listScoresDelta(client, table, filters, after, limit);
13751
+ }
13752
+ return listScoresPage(client, table, filters, pagination.page, pagination.perPage, orderBy.field, orderBy.direction);
13753
+ }
13754
+ async function getScoreById(client, schema, scoreId) {
13755
+ const row = await client.oneOrNone(
13756
+ `SELECT ${SCORE_SELECT_COLUMNS}
13757
+ FROM ${qualifiedTable(schema, TABLE_SCORE_EVENTS)}
13758
+ WHERE "scoreId" = $1
13759
+ ORDER BY "timestamp" DESC
13760
+ LIMIT 1`,
13761
+ [scoreId]
13762
+ );
13763
+ return row ? rowToScoreRecord(row) : null;
13764
+ }
13765
+ async function listScoresPage(client, table, filters, page, perPage, orderField, orderDir) {
13766
+ return listSignalPage({
13767
+ client,
13768
+ table,
13769
+ filters,
13770
+ page,
13771
+ perPage,
13772
+ orderField,
13773
+ orderDir,
13774
+ includeDeltaCursor: deltaPollingFeatureEnabled(),
13775
+ selectColumns: SCORE_SELECT_COLUMNS,
13776
+ responseKey: "scores",
13777
+ applyFilters: applyScoreFilters,
13778
+ mapRow: rowToScoreRecord
13779
+ });
13780
+ }
13781
+ async function listScoresDelta(client, table, filters, after, limit) {
13782
+ return listSignalDelta({
13783
+ client,
13784
+ table,
13785
+ filters,
13786
+ after,
13787
+ limit,
13788
+ selectColumns: SCORE_SELECT_COLUMNS,
13789
+ responseKey: "scores",
13790
+ applyFilters: applyScoreFilters,
13791
+ mapRow: rowToScoreRecord
13792
+ });
13793
+ }
13794
+ async function runScoreAggregateQuery(client, schema, args, filters) {
13795
+ const acc = newFilterAccumulator();
13796
+ pushScoreIdentity(acc, args.scorerId, args.scoreSource);
13797
+ applyScoreFilters(acc, filters);
13798
+ const sql = `
13799
+ SELECT ${aggregationSql(args.aggregation, '"score"')} AS "value"
13800
+ FROM ${qualifiedTable(schema, TABLE_SCORE_EVENTS)}
13801
+ ${whereOrEmpty(acc)}
13802
+ `;
13803
+ const row = await client.oneOrNone(sql, acc.params);
13804
+ return row?.value == null ? null : Number(row.value);
13805
+ }
13806
+ async function getScoreAggregate(client, schema, args) {
13807
+ const value = await runScoreAggregateQuery(client, schema, args, args.filters);
13808
+ if (args.comparePeriod && args.filters?.timestamp) {
13809
+ const prevRange = shiftRange(args.filters.timestamp, args.comparePeriod);
13810
+ if (prevRange) {
13811
+ const previousValue = await runScoreAggregateQuery(client, schema, args, {
13812
+ ...args.filters ?? {},
13813
+ timestamp: prevRange
13814
+ });
13815
+ return {
13816
+ value,
13817
+ previousValue,
13818
+ changePercent: changePercent(value, previousValue)
13819
+ };
13820
+ }
13821
+ }
13822
+ return { value };
13823
+ }
13824
+ async function getScoreBreakdown(client, schema, args) {
13825
+ const acc = newFilterAccumulator();
13826
+ const resolved = resolveGroupBy(acc, args.groupBy, {
13827
+ typedColumns: SCORE_TYPED_COLUMNS,
13828
+ excludedColumns: COMPLEX_GROUP_BY_EXCLUDED
13829
+ });
13830
+ pushScoreIdentity(acc, args.scorerId, args.scoreSource);
13831
+ applyScoreFilters(acc, args.filters);
13832
+ const sql = `
13833
+ SELECT ${resolved.map((e) => e.selectSql).join(", ")},
13834
+ ${aggregationSql(args.aggregation, '"score"')} AS "value"
13835
+ FROM ${qualifiedTable(schema, TABLE_SCORE_EVENTS)}
13836
+ ${whereOrEmpty(acc)}
13837
+ GROUP BY ${resolved.map((e) => e.alias).join(", ")}
13838
+ ORDER BY "value" DESC NULLS LAST
13839
+ `;
13840
+ const rows = await client.manyOrNone(sql, acc.params);
13841
+ return {
13842
+ groups: rows.map((row) => ({
13843
+ dimensions: dimensionsFromRow(row, resolved),
13844
+ value: Number(row.value ?? 0)
13845
+ }))
13846
+ };
13847
+ }
13848
+ async function getScoreTimeSeries(client, schema, args) {
13849
+ const bucket = bucketSql('"timestamp"', args.interval);
13850
+ if (args.groupBy && args.groupBy.length > 0) {
13851
+ const acc2 = newFilterAccumulator();
13852
+ const resolved = resolveGroupBy(acc2, args.groupBy, {
13853
+ typedColumns: SCORE_TYPED_COLUMNS,
13854
+ excludedColumns: COMPLEX_GROUP_BY_EXCLUDED
13855
+ });
13856
+ pushScoreIdentity(acc2, args.scorerId, args.scoreSource);
13857
+ applyScoreFilters(acc2, args.filters);
13858
+ const sql2 = `
13859
+ SELECT ${bucket} AS bucket,
13860
+ ${resolved.map((e) => e.selectSql).join(", ")},
13861
+ ${aggregationSql(args.aggregation, '"score"')} AS "value"
13862
+ FROM ${qualifiedTable(schema, TABLE_SCORE_EVENTS)}
13863
+ ${whereOrEmpty(acc2)}
13864
+ GROUP BY bucket, ${resolved.map((e) => e.alias).join(", ")}
13865
+ ORDER BY bucket
13866
+ `;
13867
+ const rows2 = await client.manyOrNone(sql2, acc2.params);
13868
+ return {
13869
+ series: collectSeriesByDimensions(
13870
+ rows2,
13871
+ resolved,
13872
+ (dimValues) => ({
13873
+ name: seriesNameFromDimensions(dimValues),
13874
+ points: []
13875
+ }),
13876
+ (entry, row) => {
13877
+ entry.points.push({
13878
+ timestamp: bucketDate(row.bucket),
13879
+ value: Number(row.value ?? 0)
13880
+ });
13881
+ }
13882
+ )
13883
+ };
13884
+ }
13885
+ const acc = newFilterAccumulator();
13886
+ pushScoreIdentity(acc, args.scorerId, args.scoreSource);
13887
+ applyScoreFilters(acc, args.filters);
13888
+ const sql = `
13889
+ SELECT ${bucket} AS bucket,
13890
+ ${aggregationSql(args.aggregation, '"score"')} AS "value"
13891
+ FROM ${qualifiedTable(schema, TABLE_SCORE_EVENTS)}
13892
+ ${whereOrEmpty(acc)}
13893
+ GROUP BY bucket
13894
+ ORDER BY bucket
13895
+ `;
13896
+ const rows = await client.manyOrNone(sql, acc.params);
13897
+ const seriesName = args.scoreSource ? `${args.scorerId}|${args.scoreSource}` : args.scorerId;
13898
+ return {
13899
+ series: [
13900
+ {
13901
+ name: seriesName,
13902
+ points: rows.map((row) => ({
13903
+ timestamp: bucketDate(row.bucket),
13904
+ value: Number(row.value ?? 0)
13905
+ }))
13906
+ }
13907
+ ]
13908
+ };
13909
+ }
13910
+ async function getScorePercentiles(client, schema, args) {
13911
+ validatePercentiles(args.percentiles);
13912
+ const bucket = bucketSql('"timestamp"', args.interval);
13913
+ const acc = newFilterAccumulator();
13914
+ pushScoreIdentity(acc, args.scorerId, args.scoreSource);
13915
+ applyScoreFilters(acc, args.filters);
13916
+ const percentileSelect = percentileSelectSql(args.percentiles, '"score"');
13917
+ const sql = `
13918
+ SELECT ${bucket} AS bucket, ${percentileSelect}
13919
+ FROM ${qualifiedTable(schema, TABLE_SCORE_EVENTS)}
13920
+ ${whereOrEmpty(acc)}
13921
+ GROUP BY bucket
13922
+ ORDER BY bucket
13923
+ `;
13924
+ const rows = await client.manyOrNone(sql, acc.params);
13925
+ return { series: percentileSeriesFromRows(rows, args.percentiles) };
13926
+ }
13927
+ function asIsoTimestamp(value) {
13928
+ return value instanceof Date ? value.toISOString() : new Date(value).toISOString();
13929
+ }
13930
+ async function getRootSpan(client, schema, args) {
13931
+ const table = qualifiedTable(schema, TABLE_SPAN_EVENTS);
13932
+ const row = await client.oneOrNone(
13933
+ `SELECT ${SPAN_SELECT_COLUMNS}
13934
+ FROM ${table}
13935
+ WHERE "traceId" = $1 AND "parentSpanId" IS NULL
13936
+ ORDER BY "endedAt" DESC
13937
+ LIMIT 1`,
13938
+ [args.traceId]
13939
+ );
13940
+ if (!row) return null;
13941
+ return { span: rowToSpanRecord(row) };
13942
+ }
13943
+ function buildListTracesFilters(filters, spanTable, nextParamIdx) {
13944
+ const conditions = [`r."parentSpanId" IS NULL`];
13945
+ const params = [];
13946
+ let i = nextParamIdx;
13947
+ if (!filters) {
13948
+ return { conditions, params, nextParamIdx: i };
13949
+ }
13950
+ if (filters.startedAt?.start) {
13951
+ conditions.push(`r."startedAt" ${filters.startedAt.startExclusive ? ">" : ">="} $${i++}`);
13952
+ params.push(asIsoTimestamp(filters.startedAt.start));
13953
+ }
13954
+ if (filters.startedAt?.end) {
13955
+ conditions.push(`r."startedAt" ${filters.startedAt.endExclusive ? "<" : "<="} $${i++}`);
13956
+ params.push(asIsoTimestamp(filters.startedAt.end));
13957
+ }
13958
+ if (filters.endedAt?.start) {
13959
+ conditions.push(`r."endedAt" ${filters.endedAt.startExclusive ? ">" : ">="} $${i++}`);
13960
+ params.push(asIsoTimestamp(filters.endedAt.start));
13961
+ }
13962
+ if (filters.endedAt?.end) {
13963
+ conditions.push(`r."endedAt" ${filters.endedAt.endExclusive ? "<" : "<="} $${i++}`);
13964
+ params.push(asIsoTimestamp(filters.endedAt.end));
13965
+ }
13966
+ if (filters.spanType !== void 0) {
13967
+ conditions.push(`r."spanType" = $${i++}`);
13968
+ params.push(filters.spanType);
13969
+ }
13970
+ if (filters.entityType !== void 0) {
13971
+ conditions.push(`r."entityType" = $${i++}`);
13972
+ params.push(filters.entityType);
13973
+ }
13974
+ if (filters.entityId !== void 0) {
13975
+ conditions.push(`r."entityId" = $${i++}`);
13976
+ params.push(filters.entityId);
13977
+ }
13978
+ if (filters.entityName !== void 0) {
13979
+ conditions.push(`r."entityName" = $${i++}`);
13980
+ params.push(filters.entityName);
13981
+ }
13982
+ if (filters.userId !== void 0) {
13983
+ conditions.push(`r."userId" = $${i++}`);
13984
+ params.push(filters.userId);
13985
+ }
13986
+ if (filters.organizationId !== void 0) {
13987
+ conditions.push(`r."organizationId" = $${i++}`);
13988
+ params.push(filters.organizationId);
13989
+ }
13990
+ if (filters.resourceId !== void 0) {
13991
+ conditions.push(`r."resourceId" = $${i++}`);
13992
+ params.push(filters.resourceId);
13993
+ }
13994
+ if (filters.runId !== void 0) {
13995
+ conditions.push(`r."runId" = $${i++}`);
13996
+ params.push(filters.runId);
13997
+ }
13998
+ if (filters.sessionId !== void 0) {
13999
+ conditions.push(`r."sessionId" = $${i++}`);
14000
+ params.push(filters.sessionId);
14001
+ }
14002
+ if (filters.threadId !== void 0) {
14003
+ conditions.push(`r."threadId" = $${i++}`);
14004
+ params.push(filters.threadId);
14005
+ }
14006
+ if (filters.requestId !== void 0) {
14007
+ conditions.push(`r."requestId" = $${i++}`);
14008
+ params.push(filters.requestId);
14009
+ }
14010
+ if (filters.environment !== void 0) {
14011
+ conditions.push(`r."environment" = $${i++}`);
14012
+ params.push(filters.environment);
14013
+ }
14014
+ if (filters.source !== void 0) {
14015
+ conditions.push(`r."executionSource" = $${i++}`);
14016
+ params.push(filters.source);
14017
+ }
14018
+ if (filters.serviceName !== void 0) {
14019
+ conditions.push(`r."serviceName" = $${i++}`);
14020
+ params.push(filters.serviceName);
14021
+ }
14022
+ if (filters.metadata != null) {
14023
+ conditions.push(`r."metadataSearch" @> $${i++}::jsonb`);
14024
+ params.push(JSON.stringify(filters.metadata));
14025
+ }
14026
+ if (filters.tags != null && filters.tags.length > 0) {
14027
+ conditions.push(`r."tags" @> $${i++}::text[]`);
14028
+ params.push(filters.tags);
14029
+ }
14030
+ if (filters.status !== void 0) {
14031
+ switch (filters.status) {
14032
+ case storage.TraceStatus.ERROR:
14033
+ conditions.push(`r."error" IS NOT NULL`);
14034
+ break;
14035
+ case storage.TraceStatus.RUNNING:
14036
+ conditions.push(`FALSE`);
14037
+ break;
14038
+ case storage.TraceStatus.SUCCESS:
14039
+ conditions.push(`r."error" IS NULL`);
14040
+ break;
14041
+ }
14042
+ }
14043
+ if (filters.hasChildError !== void 0) {
14044
+ const sub = `EXISTS (
14045
+ SELECT 1 FROM ${spanTable} c
14046
+ WHERE c."traceId" = r."traceId" AND c."spanId" <> r."spanId" AND c."error" IS NOT NULL
14047
+ )`;
14048
+ conditions.push(filters.hasChildError ? sub : `NOT ${sub}`);
14049
+ }
14050
+ return { conditions, params, nextParamIdx: i };
14051
+ }
14052
+ var SPAN_SELECT_COLUMNS_ALIASED = SPAN_SELECT_COLUMNS.replace(/\n/g, " ").split(",").map((c) => `r.${c.trim()}`).join(", ");
14053
+ async function listTraces(client, schema, args) {
14054
+ const { mode, filters, pagination, orderBy, after, limit } = storage.listTracesArgsSchema.parse(args);
14055
+ const span = qualifiedTable(schema, TABLE_SPAN_EVENTS);
14056
+ if (mode === "delta") {
14057
+ assertDeltaPollingEnabled();
14058
+ return listTracesDelta(client, span, filters, after, limit);
14059
+ }
14060
+ return listTracesPage(client, span, filters, pagination.page, pagination.perPage, orderBy.field, orderBy.direction);
14061
+ }
14062
+ async function listTracesPage(client, span, filters, page, perPage, orderField, orderDir) {
14063
+ const { conditions, params, nextParamIdx } = buildListTracesFilters(filters, span, 1);
14064
+ let i = nextParamIdx;
14065
+ const whereClause = `WHERE ${conditions.join(" AND ")}`;
14066
+ const orderClause = orderField === "endedAt" ? `ORDER BY r."endedAt" ${orderDir} NULLS ${orderDir === "DESC" ? "FIRST" : "LAST"}, r."cursorId" ${orderDir}` : `ORDER BY r."${orderField}" ${orderDir}, r."cursorId" ${orderDir}`;
14067
+ const countRow = await client.oneOrNone(
14068
+ `SELECT COUNT(*)::text AS count FROM ${span} r ${whereClause}`,
14069
+ params
14070
+ );
14071
+ const count = Number(countRow?.count ?? 0);
14072
+ let spans = [];
14073
+ if (count > 0) {
14074
+ const rows = await client.manyOrNone(
14075
+ `SELECT ${SPAN_SELECT_COLUMNS_ALIASED}
14076
+ FROM ${span} r
14077
+ ${whereClause}
14078
+ ${orderClause}
14079
+ LIMIT $${i++} OFFSET $${i++}`,
14080
+ [...params, perPage, page * perPage]
14081
+ );
14082
+ spans = rows.map(rowToSpanRecord);
14083
+ }
14084
+ const deltaCursor = deltaPollingFeatureEnabled() ? await readTracesStreamHeadCursor(client) : void 0;
14085
+ return {
14086
+ pagination: { total: count, page, perPage, hasMore: (page + 1) * perPage < count },
14087
+ spans: storage.toTraceSpans(spans),
14088
+ ...deltaCursor !== void 0 ? { deltaCursor } : {}
14089
+ };
14090
+ }
14091
+ async function listTracesDelta(client, span, filters, after, limit) {
14092
+ if (after === void 0) {
14093
+ const deltaCursor2 = await readTracesStreamHeadCursor(client);
14094
+ return { spans: [], delta: { limit, hasMore: false }, deltaCursor: deltaCursor2 };
14095
+ }
14096
+ const afterCursor = decodeDeltaCursor(after);
14097
+ const safeHorizon = await readSafeXactHorizon(client);
14098
+ const { conditions, params, nextParamIdx } = buildListTracesFilters(filters, span, 1);
14099
+ let i = nextParamIdx;
14100
+ conditions.push(`(r."xactId", r."cursorId") > ($${i++}::xid8, $${i++}::bigint)`);
14101
+ params.push(afterCursor.xactId, afterCursor.cursorId);
14102
+ conditions.push(`r."xactId" < $${i++}::xid8`);
14103
+ params.push(safeHorizon);
14104
+ const rows = await client.manyOrNone(
14105
+ `SELECT ${SPAN_SELECT_COLUMNS_ALIASED}
14106
+ FROM ${span} r
14107
+ WHERE ${conditions.join(" AND ")}
14108
+ ORDER BY r."xactId" ASC, r."cursorId" ASC
14109
+ LIMIT $${i++}`,
14110
+ [...params, limit + 1]
14111
+ );
14112
+ const hasMore = rows.length > limit;
14113
+ const visible = rows.slice(0, limit);
14114
+ const deltaCursor = visible.length > 0 ? encodeDeltaCursor(visible[visible.length - 1].xactId, visible[visible.length - 1].cursorId) : encodeDeltaCursor(safeHorizon, 0);
14115
+ return {
14116
+ spans: storage.toTraceSpans(visible.map(rowToSpanRecord)),
14117
+ delta: { limit, hasMore },
14118
+ deltaCursor
14119
+ };
14120
+ }
14121
+ async function readTracesStreamHeadCursor(client, span, filters) {
14122
+ return encodeDeltaCursor(await readSafeXactHorizon(client), 0);
14123
+ }
14124
+ var BRANCH_SPAN_TYPE_SET = new Set(storage.BRANCH_SPAN_TYPES);
14125
+ function buildBranchSpanTypeClause(userSpanType, params, startIdx) {
14126
+ if (userSpanType !== void 0) {
14127
+ if (!BRANCH_SPAN_TYPE_SET.has(userSpanType)) {
14128
+ return null;
14129
+ }
14130
+ params.push(userSpanType);
14131
+ return { clause: `r."spanType" = $${startIdx}`, nextIdx: startIdx + 1 };
14132
+ }
14133
+ const placeholders = [];
14134
+ for (const t of storage.BRANCH_SPAN_TYPES) {
14135
+ placeholders.push(`$${startIdx + placeholders.length}`);
14136
+ params.push(t);
14137
+ }
14138
+ return { clause: `r."spanType" IN (${placeholders.join(", ")})`, nextIdx: startIdx + placeholders.length };
14139
+ }
14140
+ function buildListBranchesFilters(filters, spanType, nextParamIdx) {
14141
+ const conditions = [];
14142
+ const params = [];
14143
+ let i = nextParamIdx;
14144
+ const spanTypeClause = buildBranchSpanTypeClause(spanType, params, i);
14145
+ if (!spanTypeClause) return null;
14146
+ conditions.push(spanTypeClause.clause);
14147
+ i = spanTypeClause.nextIdx;
14148
+ if (!filters) return { conditions, params, nextParamIdx: i };
14149
+ if (filters.startedAt?.start) {
14150
+ conditions.push(`r."startedAt" ${filters.startedAt.startExclusive ? ">" : ">="} $${i++}`);
14151
+ params.push(asIsoTimestamp(filters.startedAt.start));
14152
+ }
14153
+ if (filters.startedAt?.end) {
14154
+ conditions.push(`r."startedAt" ${filters.startedAt.endExclusive ? "<" : "<="} $${i++}`);
14155
+ params.push(asIsoTimestamp(filters.startedAt.end));
14156
+ }
14157
+ if (filters.endedAt?.start) {
14158
+ conditions.push(`r."endedAt" ${filters.endedAt.startExclusive ? ">" : ">="} $${i++}`);
14159
+ params.push(asIsoTimestamp(filters.endedAt.start));
14160
+ }
14161
+ if (filters.endedAt?.end) {
14162
+ conditions.push(`r."endedAt" ${filters.endedAt.endExclusive ? "<" : "<="} $${i++}`);
14163
+ params.push(asIsoTimestamp(filters.endedAt.end));
14164
+ }
14165
+ if (filters.traceId !== void 0) {
14166
+ conditions.push(`r."traceId" = $${i++}`);
14167
+ params.push(filters.traceId);
14168
+ }
14169
+ if (filters.entityType !== void 0) {
14170
+ conditions.push(`r."entityType" = $${i++}`);
14171
+ params.push(filters.entityType);
14172
+ }
14173
+ if (filters.entityId !== void 0) {
14174
+ conditions.push(`r."entityId" = $${i++}`);
14175
+ params.push(filters.entityId);
14176
+ }
14177
+ if (filters.entityName !== void 0) {
14178
+ conditions.push(`r."entityName" = $${i++}`);
14179
+ params.push(filters.entityName);
14180
+ }
14181
+ if (filters.entityVersionId !== void 0) {
14182
+ conditions.push(`r."entityVersionId" = $${i++}`);
14183
+ params.push(filters.entityVersionId);
14184
+ }
14185
+ if (filters.parentEntityType !== void 0) {
14186
+ conditions.push(`r."parentEntityType" = $${i++}`);
14187
+ params.push(filters.parentEntityType);
14188
+ }
14189
+ if (filters.parentEntityId !== void 0) {
14190
+ conditions.push(`r."parentEntityId" = $${i++}`);
14191
+ params.push(filters.parentEntityId);
14192
+ }
14193
+ if (filters.parentEntityName !== void 0) {
14194
+ conditions.push(`r."parentEntityName" = $${i++}`);
14195
+ params.push(filters.parentEntityName);
14196
+ }
14197
+ if (filters.parentEntityVersionId !== void 0) {
14198
+ conditions.push(`r."parentEntityVersionId" = $${i++}`);
14199
+ params.push(filters.parentEntityVersionId);
14200
+ }
14201
+ if (filters.rootEntityType !== void 0) {
14202
+ conditions.push(`r."rootEntityType" = $${i++}`);
14203
+ params.push(filters.rootEntityType);
14204
+ }
14205
+ if (filters.rootEntityId !== void 0) {
14206
+ conditions.push(`r."rootEntityId" = $${i++}`);
14207
+ params.push(filters.rootEntityId);
14208
+ }
14209
+ if (filters.rootEntityName !== void 0) {
14210
+ conditions.push(`r."rootEntityName" = $${i++}`);
14211
+ params.push(filters.rootEntityName);
14212
+ }
14213
+ if (filters.rootEntityVersionId !== void 0) {
14214
+ conditions.push(`r."rootEntityVersionId" = $${i++}`);
14215
+ params.push(filters.rootEntityVersionId);
14216
+ }
14217
+ if (filters.userId !== void 0) {
14218
+ conditions.push(`r."userId" = $${i++}`);
14219
+ params.push(filters.userId);
14220
+ }
14221
+ if (filters.organizationId !== void 0) {
14222
+ conditions.push(`r."organizationId" = $${i++}`);
14223
+ params.push(filters.organizationId);
14224
+ }
14225
+ if (filters.resourceId !== void 0) {
14226
+ conditions.push(`r."resourceId" = $${i++}`);
14227
+ params.push(filters.resourceId);
14228
+ }
14229
+ if (filters.runId !== void 0) {
14230
+ conditions.push(`r."runId" = $${i++}`);
14231
+ params.push(filters.runId);
14232
+ }
14233
+ if (filters.sessionId !== void 0) {
14234
+ conditions.push(`r."sessionId" = $${i++}`);
14235
+ params.push(filters.sessionId);
14236
+ }
14237
+ if (filters.threadId !== void 0) {
14238
+ conditions.push(`r."threadId" = $${i++}`);
14239
+ params.push(filters.threadId);
14240
+ }
14241
+ if (filters.requestId !== void 0) {
14242
+ conditions.push(`r."requestId" = $${i++}`);
14243
+ params.push(filters.requestId);
14244
+ }
14245
+ if (filters.experimentId !== void 0) {
14246
+ conditions.push(`r."experimentId" = $${i++}`);
14247
+ params.push(filters.experimentId);
14248
+ }
14249
+ if (filters.environment !== void 0) {
14250
+ conditions.push(`r."environment" = $${i++}`);
14251
+ params.push(filters.environment);
14252
+ }
14253
+ if (filters.serviceName !== void 0) {
14254
+ conditions.push(`r."serviceName" = $${i++}`);
14255
+ params.push(filters.serviceName);
14256
+ }
14257
+ if (filters.source !== void 0) {
14258
+ conditions.push(`r."executionSource" = $${i++}`);
14259
+ params.push(filters.source);
14260
+ }
14261
+ if (filters.metadata != null) {
14262
+ conditions.push(`r."metadataSearch" @> $${i++}::jsonb`);
14263
+ params.push(JSON.stringify(filters.metadata));
14264
+ }
14265
+ if (filters.tags != null && filters.tags.length > 0) {
14266
+ conditions.push(`r."tags" @> $${i++}::text[]`);
14267
+ params.push(filters.tags);
14268
+ }
14269
+ if (filters.status !== void 0) {
14270
+ switch (filters.status) {
14271
+ case storage.TraceStatus.ERROR:
14272
+ conditions.push(`r."error" IS NOT NULL`);
14273
+ break;
14274
+ case storage.TraceStatus.RUNNING:
14275
+ conditions.push(`FALSE`);
14276
+ break;
14277
+ case storage.TraceStatus.SUCCESS:
14278
+ conditions.push(`r."error" IS NULL`);
14279
+ break;
14280
+ }
14281
+ }
14282
+ return { conditions, params, nextParamIdx: i };
14283
+ }
14284
+ async function listBranches(client, schema, args) {
14285
+ const { mode, filters, pagination, orderBy, after, limit } = storage.listBranchesArgsSchema.parse(args);
14286
+ const span = qualifiedTable(schema, TABLE_SPAN_EVENTS);
14287
+ if (mode === "delta") {
14288
+ assertDeltaPollingEnabled();
14289
+ return listBranchesDelta(client, span, filters, after, limit);
14290
+ }
14291
+ return listBranchesPage(client, span, filters, pagination.page, pagination.perPage, orderBy.field, orderBy.direction);
14292
+ }
14293
+ async function listBranchesPage(client, span, filters, page, perPage, orderField, orderDir) {
14294
+ const built = buildListBranchesFilters(filters, filters?.spanType, 1);
14295
+ if (!built) {
14296
+ const deltaCursor2 = deltaPollingFeatureEnabled() ? await readBranchesStreamHeadCursor(client) : void 0;
14297
+ return {
14298
+ pagination: { total: 0, page, perPage, hasMore: false },
14299
+ branches: [],
14300
+ ...deltaCursor2 !== void 0 ? { deltaCursor: deltaCursor2 } : {}
14301
+ };
14302
+ }
14303
+ const { conditions, params, nextParamIdx } = built;
14304
+ let i = nextParamIdx;
14305
+ const whereClause = `WHERE ${conditions.join(" AND ")}`;
14306
+ const orderClause = orderField === "endedAt" ? `ORDER BY r."endedAt" ${orderDir} NULLS ${orderDir === "DESC" ? "FIRST" : "LAST"}, r."cursorId" ${orderDir}` : `ORDER BY r."${orderField}" ${orderDir}, r."cursorId" ${orderDir}`;
14307
+ const countRow = await client.oneOrNone(
14308
+ `SELECT COUNT(*)::text AS count FROM ${span} r ${whereClause}`,
14309
+ params
14310
+ );
14311
+ const count = Number(countRow?.count ?? 0);
14312
+ let spans = [];
14313
+ if (count > 0) {
14314
+ const rows = await client.manyOrNone(
14315
+ `SELECT ${SPAN_SELECT_COLUMNS_ALIASED}
14316
+ FROM ${span} r
14317
+ ${whereClause}
14318
+ ${orderClause}
14319
+ LIMIT $${i++} OFFSET $${i++}`,
14320
+ [...params, perPage, page * perPage]
14321
+ );
14322
+ spans = rows.map(rowToSpanRecord);
14323
+ }
14324
+ const deltaCursor = deltaPollingFeatureEnabled() ? await readBranchesStreamHeadCursor(client) : void 0;
14325
+ return {
14326
+ pagination: { total: count, page, perPage, hasMore: (page + 1) * perPage < count },
14327
+ branches: storage.toTraceSpans(spans),
14328
+ ...deltaCursor !== void 0 ? { deltaCursor } : {}
14329
+ };
14330
+ }
14331
+ async function listBranchesDelta(client, span, filters, after, limit) {
14332
+ if (after === void 0) {
14333
+ const deltaCursor2 = await readBranchesStreamHeadCursor(client);
14334
+ return { branches: [], delta: { limit, hasMore: false }, deltaCursor: deltaCursor2 };
14335
+ }
14336
+ const built = buildListBranchesFilters(filters, filters?.spanType, 1);
14337
+ if (!built) {
14338
+ return {
14339
+ branches: [],
14340
+ delta: { limit, hasMore: false },
14341
+ deltaCursor: await readBranchesStreamHeadCursor(client)
14342
+ };
14343
+ }
14344
+ const { conditions, params, nextParamIdx } = built;
14345
+ let i = nextParamIdx;
14346
+ const afterCursor = decodeDeltaCursor(after);
14347
+ const safeHorizon = await readSafeXactHorizon(client);
14348
+ conditions.push(`(r."xactId", r."cursorId") > ($${i++}::xid8, $${i++}::bigint)`);
14349
+ params.push(afterCursor.xactId, afterCursor.cursorId);
14350
+ conditions.push(`r."xactId" < $${i++}::xid8`);
14351
+ params.push(safeHorizon);
14352
+ const rows = await client.manyOrNone(
14353
+ `SELECT ${SPAN_SELECT_COLUMNS_ALIASED}
14354
+ FROM ${span} r
14355
+ WHERE ${conditions.join(" AND ")}
14356
+ ORDER BY r."xactId" ASC, r."cursorId" ASC
14357
+ LIMIT $${i++}`,
14358
+ [...params, limit + 1]
14359
+ );
14360
+ const hasMore = rows.length > limit;
14361
+ const visible = rows.slice(0, limit);
14362
+ const deltaCursor = visible.length > 0 ? encodeDeltaCursor(visible[visible.length - 1].xactId, visible[visible.length - 1].cursorId) : encodeDeltaCursor(safeHorizon, 0);
14363
+ return {
14364
+ branches: storage.toTraceSpans(visible.map(rowToSpanRecord)),
14365
+ delta: { limit, hasMore },
14366
+ deltaCursor
14367
+ };
14368
+ }
14369
+ async function readBranchesStreamHeadCursor(client, span, filters) {
14370
+ return encodeDeltaCursor(await readSafeXactHorizon(client), 0);
14371
+ }
14372
+
14373
+ // src/storage/domains/observability/v-next/tracing.ts
14374
+ async function createSpan(client, schema, args) {
14375
+ const row = spanRecordToRow(args.span);
14376
+ const insert = buildInsert(schema, TABLE_SPAN_EVENTS, [row]);
14377
+ if (insert) await client.query(insert.text, insert.values);
14378
+ }
14379
+ async function batchCreateSpans(client, schema, args) {
14380
+ if (args.records.length === 0) return;
14381
+ const rows = args.records.map(spanRecordToRow);
14382
+ const insert = buildInsert(schema, TABLE_SPAN_EVENTS, rows);
14383
+ if (insert) await client.query(insert.text, insert.values);
14384
+ }
14385
+ async function getSpans(client, schema, args) {
14386
+ if (args.spanIds.length === 0) {
14387
+ return { traceId: args.traceId, spans: [] };
14388
+ }
14389
+ const table = qualifiedTable(schema, TABLE_SPAN_EVENTS);
14390
+ const rows = await client.manyOrNone(
14391
+ `SELECT ${SPAN_SELECT_COLUMNS}
14392
+ FROM ${table}
14393
+ WHERE "traceId" = $1
14394
+ AND "spanId" = ANY($2::text[])
14395
+ ORDER BY "startedAt" ASC`,
14396
+ [args.traceId, args.spanIds]
14397
+ );
14398
+ return { traceId: args.traceId, spans: rows.map(rowToSpanRecord) };
14399
+ }
14400
+ async function getSpan(client, schema, args) {
14401
+ const table = qualifiedTable(schema, TABLE_SPAN_EVENTS);
14402
+ const row = await client.oneOrNone(
14403
+ `SELECT ${SPAN_SELECT_COLUMNS}
14404
+ FROM ${table}
14405
+ WHERE "traceId" = $1 AND "spanId" = $2
14406
+ ORDER BY "endedAt" DESC
14407
+ LIMIT 1`,
14408
+ [args.traceId, args.spanId]
14409
+ );
14410
+ if (!row) return null;
14411
+ return { span: rowToSpanRecord(row) };
14412
+ }
14413
+ async function getTrace(client, schema, args) {
14414
+ const table = qualifiedTable(schema, TABLE_SPAN_EVENTS);
14415
+ const rows = await client.manyOrNone(
14416
+ `SELECT ${SPAN_SELECT_COLUMNS}
14417
+ FROM ${table}
14418
+ WHERE "traceId" = $1
14419
+ ORDER BY "startedAt" ASC`,
14420
+ [args.traceId]
14421
+ );
14422
+ if (!rows.length) return null;
14423
+ return { traceId: args.traceId, spans: rows.map(rowToSpanRecord) };
14424
+ }
14425
+ async function getTraceLight(client, schema, args) {
14426
+ const table = qualifiedTable(schema, TABLE_SPAN_EVENTS);
14427
+ const rows = await client.manyOrNone(
14428
+ `SELECT ${SPAN_LIGHT_SELECT_COLUMNS}
14429
+ FROM ${table}
14430
+ WHERE "traceId" = $1
14431
+ ORDER BY "startedAt" ASC`,
14432
+ [args.traceId]
14433
+ );
14434
+ if (!rows.length) return null;
14435
+ return {
14436
+ traceId: args.traceId,
14437
+ spans: rows.map(rowToLightSpanRecord)
14438
+ };
14439
+ }
14440
+ async function batchDeleteTraces(client, schema, args) {
14441
+ if (args.traceIds.length === 0) return;
14442
+ const span = qualifiedTable(schema, TABLE_SPAN_EVENTS);
14443
+ const placeholders = args.traceIds.map((_, i) => `$${i + 1}`).join(", ");
14444
+ await client.query(`DELETE FROM ${span} WHERE "traceId" IN (${placeholders})`, args.traceIds);
14445
+ }
14446
+ async function dangerouslyClearTracing(client, schema) {
14447
+ const span = qualifiedTable(schema, TABLE_SPAN_EVENTS);
14448
+ await client.none(`TRUNCATE TABLE ${span} RESTART IDENTITY`);
14449
+ }
14450
+
14451
+ // src/storage/domains/observability/v-next/index.ts
14452
+ function wrapError(op, error$1, details) {
14453
+ if (error$1 instanceof error.MastraError) throw error$1;
14454
+ throw new error.MastraError(
14455
+ {
14456
+ id: storage.createStorageErrorId("PG", op, "FAILED"),
14457
+ domain: error.ErrorDomain.STORAGE,
14458
+ category: error.ErrorCategory.THIRD_PARTY,
14459
+ details
14460
+ },
14461
+ error$1
14462
+ );
14463
+ }
14464
+ var ObservabilityStoragePostgresVNext = class extends storage.ObservabilityStorage {
14465
+ #client;
14466
+ #schema;
14467
+ #partitioning;
14468
+ #discoveryConfig;
14469
+ #partitionMode;
14470
+ constructor(config) {
14471
+ super();
14472
+ const { client, schemaName } = resolvePgConfig(config);
14473
+ this.#client = client;
14474
+ this.#schema = schemaName ?? "public";
14475
+ this.#partitioning = config.partitioning ?? {};
14476
+ this.#discoveryConfig = config.discovery ?? {};
14477
+ }
14478
+ /**
14479
+ * Build the discovery config used at each call site, with the framework
14480
+ * logger injected so background refresh failures land in the same log
14481
+ * stream as the rest of the store. Reads `this.logger` lazily so
14482
+ * `__setLogger()` calls (e.g. when the domain is mounted under a Mastra
14483
+ * instance) propagate without rebuilding the domain.
14484
+ */
14485
+ get #discovery() {
14486
+ return { ...this.#discoveryConfig, logger: this.logger };
14487
+ }
14488
+ // -------------------------------------------------------------------------
14489
+ // Initialization
14490
+ // -------------------------------------------------------------------------
14491
+ /**
14492
+ * Create the signal tables, indexes, and (if Timescale / pg_partman is
14493
+ * present) hypertable / partman registrations.
14494
+ *
14495
+ * Not transactional: each `CREATE TABLE IF NOT EXISTS`, `CREATE INDEX IF
14496
+ * NOT EXISTS`, and `create_hypertable()` / `create_parent()` runs in its
14497
+ * own implicit transaction. Re-running `init()` after a failure is safe
14498
+ * (every statement is idempotent), but a failure partway through against
14499
+ * Timescale can leave some signal tables as hypertables and others as
14500
+ * plain tables. If that happens, fix the underlying error and call
14501
+ * `init()` again — the partially-converted state is recoverable.
14502
+ */
14503
+ async init() {
14504
+ try {
14505
+ const explicit = this.#partitioning.mode;
14506
+ let mode;
14507
+ if (explicit && explicit !== "auto") {
14508
+ mode = explicit;
14509
+ } else if (await detectTimescale(this.#client)) {
14510
+ mode = "timescale";
14511
+ } else if (await detectPartman(this.#client)) {
14512
+ mode = "partman";
14513
+ } else {
14514
+ mode = "native";
14515
+ }
14516
+ const ddlMode = mode === "timescale" ? "timescale" : "partitioned";
14517
+ try {
14518
+ await this.#client.none(schemaDDL(this.#schema));
14519
+ } catch (error) {
14520
+ if (!isDuplicateSchemaError(error)) throw error;
14521
+ }
14522
+ for (const ddl of allTableDDL(this.#schema, ddlMode)) {
14523
+ try {
14524
+ await this.#client.none(ddl);
14525
+ } catch (error) {
14526
+ if (!isDuplicateRelationError(error)) throw error;
14527
+ }
14528
+ }
14529
+ for (const ddl of allIndexDDL(this.#schema)) {
14530
+ try {
14531
+ await this.#client.none(ddl);
14532
+ } catch (error) {
14533
+ if (!isDuplicateRelationError(error)) throw error;
14534
+ }
14535
+ }
14536
+ this.#partitionMode = await setupPartitioning(this.#client, this.#schema, {
14537
+ ...this.#partitioning,
14538
+ mode
14539
+ });
14540
+ } catch (error) {
14541
+ wrapError("VNEXT_INIT", error);
14542
+ }
14543
+ }
14544
+ /** Resolved partition mode after init(). Useful for tests and diagnostics. */
14545
+ get partitionMode() {
14546
+ return this.#partitionMode;
14547
+ }
14548
+ get observabilityStrategy() {
14549
+ return { preferred: "insert-only", supported: ["insert-only"] };
14550
+ }
14551
+ getFeatures() {
14552
+ if (!deltaPollingFeatureEnabled()) return void 0;
14553
+ return ["delta-polling"];
14554
+ }
14555
+ async #run(op, fn, details) {
14556
+ try {
14557
+ return await fn();
14558
+ } catch (error) {
14559
+ wrapError(op, error, details);
14560
+ }
14561
+ }
14562
+ // -------------------------------------------------------------------------
14563
+ // Tracing — writes
14564
+ // -------------------------------------------------------------------------
14565
+ async createSpan(args) {
14566
+ await this.#run("CREATE_SPAN", () => createSpan(this.#client, this.#schema, args), {
14567
+ traceId: args.span.traceId,
14568
+ spanId: args.span.spanId
14569
+ });
14570
+ }
14571
+ async batchCreateSpans(args) {
14572
+ await this.#run("BATCH_CREATE_SPANS", () => batchCreateSpans(this.#client, this.#schema, args), {
14573
+ count: args.records.length
14574
+ });
14575
+ }
14576
+ // -------------------------------------------------------------------------
14577
+ // Tracing — reads
14578
+ // -------------------------------------------------------------------------
14579
+ async getSpan(args) {
14580
+ return this.#run("GET_SPAN", () => getSpan(this.#client, this.#schema, args), {
14581
+ traceId: args.traceId,
14582
+ spanId: args.spanId
14583
+ });
14584
+ }
14585
+ async getSpans(args) {
14586
+ return this.#run("GET_SPANS", () => getSpans(this.#client, this.#schema, args), {
14587
+ traceId: args.traceId,
14588
+ count: args.spanIds.length
14589
+ });
14590
+ }
14591
+ async getRootSpan(args) {
14592
+ return this.#run("GET_ROOT_SPAN", () => getRootSpan(this.#client, this.#schema, args), {
14593
+ traceId: args.traceId
14594
+ });
14595
+ }
14596
+ async getTrace(args) {
14597
+ return this.#run("GET_TRACE", () => getTrace(this.#client, this.#schema, args), {
14598
+ traceId: args.traceId
14599
+ });
14600
+ }
14601
+ async getTraceLight(args) {
14602
+ return this.#run("GET_TRACE_LIGHT", () => getTraceLight(this.#client, this.#schema, args), {
14603
+ traceId: args.traceId
14604
+ });
14605
+ }
14606
+ async listTraces(args) {
14607
+ return this.#run("LIST_TRACES", () => listTraces(this.#client, this.#schema, args));
14608
+ }
14609
+ async listBranches(args) {
14610
+ return this.#run("LIST_BRANCHES", () => listBranches(this.#client, this.#schema, args));
14611
+ }
14612
+ // -------------------------------------------------------------------------
14613
+ // Logs / metrics / scores / feedback — writes
14614
+ // -------------------------------------------------------------------------
14615
+ async batchCreateLogs(args) {
14616
+ await this.#run("BATCH_CREATE_LOGS", () => batchCreateLogs(this.#client, this.#schema, args), {
14617
+ count: args.logs.length
14618
+ });
14619
+ }
14620
+ async batchCreateMetrics(args) {
14621
+ await this.#run("BATCH_CREATE_METRICS", () => batchCreateMetrics(this.#client, this.#schema, args), {
14622
+ count: args.metrics.length
14623
+ });
14624
+ }
14625
+ async createScore(args) {
14626
+ await this.#run("CREATE_SCORE", () => createScore(this.#client, this.#schema, args));
14627
+ }
14628
+ async batchCreateScores(args) {
14629
+ await this.#run("BATCH_CREATE_SCORES", () => batchCreateScores(this.#client, this.#schema, args), {
14630
+ count: args.scores.length
14631
+ });
14632
+ }
14633
+ async createFeedback(args) {
14634
+ await this.#run("CREATE_FEEDBACK", () => createFeedback(this.#client, this.#schema, args));
14635
+ }
14636
+ async batchCreateFeedback(args) {
14637
+ await this.#run("BATCH_CREATE_FEEDBACK", () => batchCreateFeedback(this.#client, this.#schema, args), {
14638
+ count: args.feedbacks.length
14639
+ });
14640
+ }
14641
+ // -------------------------------------------------------------------------
14642
+ // Logs / metrics / scores / feedback — list reads
14643
+ // -------------------------------------------------------------------------
14644
+ async listLogs(args) {
14645
+ return this.#run("LIST_LOGS", () => listLogs(this.#client, this.#schema, args));
14646
+ }
14647
+ async listMetrics(args) {
14648
+ return this.#run("LIST_METRICS", () => listMetrics(this.#client, this.#schema, args));
14649
+ }
14650
+ async listScores(args) {
14651
+ return this.#run("LIST_SCORES", () => listScores(this.#client, this.#schema, args));
14652
+ }
14653
+ async getScoreById(scoreId) {
14654
+ return this.#run("GET_SCORE_BY_ID", () => getScoreById(this.#client, this.#schema, scoreId), {
14655
+ scoreId
14656
+ });
14657
+ }
14658
+ async listFeedback(args) {
14659
+ return this.#run("LIST_FEEDBACK", () => listFeedback(this.#client, this.#schema, args));
14660
+ }
14661
+ // -------------------------------------------------------------------------
14662
+ // OLAP — metrics
14663
+ // -------------------------------------------------------------------------
14664
+ async getMetricAggregate(args) {
14665
+ return this.#run("GET_METRIC_AGGREGATE", () => getMetricAggregate(this.#client, this.#schema, args));
14666
+ }
14667
+ async getMetricBreakdown(args) {
14668
+ return this.#run("GET_METRIC_BREAKDOWN", () => getMetricBreakdown(this.#client, this.#schema, args));
14669
+ }
14670
+ async getMetricTimeSeries(args) {
14671
+ return this.#run("GET_METRIC_TIME_SERIES", () => getMetricTimeSeries(this.#client, this.#schema, args));
14672
+ }
14673
+ async getMetricPercentiles(args) {
14674
+ return this.#run("GET_METRIC_PERCENTILES", () => getMetricPercentiles(this.#client, this.#schema, args));
14675
+ }
14676
+ // -------------------------------------------------------------------------
14677
+ // OLAP — scores
14678
+ // -------------------------------------------------------------------------
14679
+ async getScoreAggregate(args) {
14680
+ return this.#run("GET_SCORE_AGGREGATE", () => getScoreAggregate(this.#client, this.#schema, args));
14681
+ }
14682
+ async getScoreBreakdown(args) {
14683
+ return this.#run("GET_SCORE_BREAKDOWN", () => getScoreBreakdown(this.#client, this.#schema, args));
14684
+ }
14685
+ async getScoreTimeSeries(args) {
14686
+ return this.#run("GET_SCORE_TIME_SERIES", () => getScoreTimeSeries(this.#client, this.#schema, args));
14687
+ }
14688
+ async getScorePercentiles(args) {
14689
+ return this.#run("GET_SCORE_PERCENTILES", () => getScorePercentiles(this.#client, this.#schema, args));
14690
+ }
14691
+ // -------------------------------------------------------------------------
14692
+ // OLAP — feedback
14693
+ // -------------------------------------------------------------------------
14694
+ async getFeedbackAggregate(args) {
14695
+ return this.#run(
14696
+ "GET_FEEDBACK_AGGREGATE",
14697
+ () => getFeedbackAggregate(this.#client, this.#schema, args)
14698
+ );
14699
+ }
14700
+ async getFeedbackBreakdown(args) {
14701
+ return this.#run(
14702
+ "GET_FEEDBACK_BREAKDOWN",
14703
+ () => getFeedbackBreakdown(this.#client, this.#schema, args)
14704
+ );
14705
+ }
14706
+ async getFeedbackTimeSeries(args) {
14707
+ return this.#run(
14708
+ "GET_FEEDBACK_TIME_SERIES",
14709
+ () => getFeedbackTimeSeries(this.#client, this.#schema, args)
14710
+ );
14711
+ }
14712
+ async getFeedbackPercentiles(args) {
14713
+ return this.#run(
14714
+ "GET_FEEDBACK_PERCENTILES",
14715
+ () => getFeedbackPercentiles(this.#client, this.#schema, args)
14716
+ );
14717
+ }
14718
+ // -------------------------------------------------------------------------
14719
+ // Discovery
14720
+ // -------------------------------------------------------------------------
14721
+ async getEntityTypes(args) {
14722
+ return this.#run(
14723
+ "GET_ENTITY_TYPES",
14724
+ () => getEntityTypes(this.#client, this.#schema, args, this.#discovery)
14725
+ );
14726
+ }
14727
+ async getEntityNames(args) {
14728
+ return this.#run(
14729
+ "GET_ENTITY_NAMES",
14730
+ () => getEntityNames(this.#client, this.#schema, args, this.#discovery)
14731
+ );
14732
+ }
14733
+ async getServiceNames(args) {
14734
+ return this.#run(
14735
+ "GET_SERVICE_NAMES",
14736
+ () => getServiceNames(this.#client, this.#schema, args, this.#discovery)
14737
+ );
14738
+ }
14739
+ async getEnvironments(args) {
14740
+ return this.#run(
14741
+ "GET_ENVIRONMENTS",
14742
+ () => getEnvironments(this.#client, this.#schema, args, this.#discovery)
14743
+ );
14744
+ }
14745
+ async getTags(args) {
14746
+ return this.#run("GET_TAGS", () => getTags(this.#client, this.#schema, args, this.#discovery));
14747
+ }
14748
+ async getMetricNames(args) {
14749
+ return this.#run(
14750
+ "GET_METRIC_NAMES",
14751
+ () => getMetricNames(this.#client, this.#schema, args, this.#discovery)
14752
+ );
14753
+ }
14754
+ async getMetricLabelKeys(args) {
14755
+ return this.#run(
14756
+ "GET_METRIC_LABEL_KEYS",
14757
+ () => getMetricLabelKeys(this.#client, this.#schema, args, this.#discovery)
14758
+ );
14759
+ }
14760
+ async getMetricLabelValues(args) {
14761
+ return this.#run(
14762
+ "GET_METRIC_LABEL_VALUES",
14763
+ () => getMetricLabelValues(this.#client, this.#schema, args, this.#discovery)
14764
+ );
14765
+ }
14766
+ // -------------------------------------------------------------------------
14767
+ // Tracing — deletes / clear
14768
+ // -------------------------------------------------------------------------
14769
+ async batchDeleteTraces(args) {
14770
+ await this.#run("BATCH_DELETE_TRACES", () => batchDeleteTraces(this.#client, this.#schema, args), {
14771
+ count: args.traceIds.length
14772
+ });
14773
+ }
14774
+ async dangerouslyClearAll() {
14775
+ try {
14776
+ await dangerouslyClearTracing(this.#client, this.#schema);
14777
+ for (const t of ALL_SIGNAL_TABLES) {
14778
+ if (t === TABLE_SPAN_EVENTS) continue;
14779
+ await this.#client.none(`TRUNCATE TABLE ${qualifiedTable(this.#schema, t)} RESTART IDENTITY`);
14780
+ }
14781
+ await this.#client.none(`TRUNCATE TABLE ${qualifiedTable(this.#schema, TABLE_DISCOVERY)} RESTART IDENTITY`);
14782
+ } catch (error) {
14783
+ wrapError("DANGEROUSLY_CLEAR_ALL", error);
14784
+ }
14785
+ }
14786
+ };
14787
+ var SNAPSHOT_FIELDS3 = ["name", "description", "content", "rules", "requestContextSchema"];
14788
+ var PromptBlocksPG = class _PromptBlocksPG extends storage.PromptBlocksStorage {
14789
+ #db;
14790
+ #schema;
14791
+ #skipDefaultIndexes;
14792
+ #indexes;
14793
+ static MANAGED_TABLES = [storage.TABLE_PROMPT_BLOCKS, storage.TABLE_PROMPT_BLOCK_VERSIONS];
14794
+ constructor(config) {
14795
+ super();
14796
+ const { client, schemaName, skipDefaultIndexes, indexes } = resolvePgConfig(config);
14797
+ this.#db = new PgDB({ client, schemaName, skipDefaultIndexes });
14798
+ this.#schema = schemaName || "public";
14799
+ this.#skipDefaultIndexes = skipDefaultIndexes;
14800
+ this.#indexes = indexes?.filter((idx) => _PromptBlocksPG.MANAGED_TABLES.includes(idx.table));
14801
+ }
14802
+ /**
14803
+ * Returns default index definitions for the prompt blocks domain tables.
14804
+ * @param schemaPrefix - Prefix for index names (e.g. "my_schema_" or "")
14805
+ */
14806
+ static getDefaultIndexDefs(schemaPrefix) {
14807
+ return [
14808
+ {
14809
+ name: `${schemaPrefix}idx_prompt_block_versions_block_version`,
14810
+ table: storage.TABLE_PROMPT_BLOCK_VERSIONS,
14811
+ columns: ["blockId", "versionNumber"],
14812
+ unique: true
14813
+ }
14814
+ ];
14815
+ }
14816
+ /**
14817
+ * Returns all DDL statements for this domain: tables and indexes.
14818
+ * Used by exportSchemas to produce a complete, reproducible schema export.
14819
+ */
14820
+ static getExportDDL(schemaName) {
14821
+ const statements = [];
14822
+ const parsedSchema = schemaName ? utils.parseSqlIdentifier(schemaName, "schema name") : "";
14823
+ const schemaPrefix = parsedSchema && parsedSchema !== "public" ? `${parsedSchema}_` : "";
14824
+ for (const tableName of _PromptBlocksPG.MANAGED_TABLES) {
14825
+ statements.push(
14826
+ generateTableSQL({
14827
+ tableName,
14828
+ schema: storage.TABLE_SCHEMAS[tableName],
14829
+ schemaName,
14830
+ includeAllConstraints: true
14831
+ })
14832
+ );
14833
+ }
14834
+ for (const idx of _PromptBlocksPG.getDefaultIndexDefs(schemaPrefix)) {
14835
+ statements.push(generateIndexSQL(idx, schemaName));
14836
+ }
14837
+ return statements;
14838
+ }
14839
+ getDefaultIndexDefinitions() {
14840
+ const schemaPrefix = this.#schema !== "public" ? `${this.#schema}_` : "";
14841
+ return _PromptBlocksPG.getDefaultIndexDefs(schemaPrefix);
14842
+ }
14843
+ async createDefaultIndexes() {
14844
+ if (this.#skipDefaultIndexes) {
14845
+ return;
14846
+ }
14847
+ for (const indexDef of this.getDefaultIndexDefinitions()) {
14848
+ try {
14849
+ await this.#db.createIndex(indexDef);
14850
+ } catch {
14851
+ }
14852
+ }
14853
+ }
14854
+ async init() {
14855
+ await this.#db.createTable({ tableName: storage.TABLE_PROMPT_BLOCKS, schema: storage.TABLE_SCHEMAS[storage.TABLE_PROMPT_BLOCKS] });
14856
+ await this.#db.createTable({
14857
+ tableName: storage.TABLE_PROMPT_BLOCK_VERSIONS,
14858
+ schema: storage.TABLE_SCHEMAS[storage.TABLE_PROMPT_BLOCK_VERSIONS]
14859
+ });
14860
+ await this.#db.alterTable({
14861
+ tableName: storage.TABLE_PROMPT_BLOCK_VERSIONS,
14862
+ schema: storage.TABLE_SCHEMAS[storage.TABLE_PROMPT_BLOCK_VERSIONS],
14863
+ ifNotExists: ["requestContextSchema"]
14864
+ });
14865
+ await this.createDefaultIndexes();
14866
+ await this.createCustomIndexes();
14867
+ }
14868
+ async createCustomIndexes() {
14869
+ if (!this.#indexes || this.#indexes.length === 0) {
14870
+ return;
14871
+ }
14872
+ for (const indexDef of this.#indexes) {
14873
+ try {
14874
+ await this.#db.createIndex(indexDef);
14875
+ } catch (error) {
14876
+ this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
14877
+ }
14878
+ }
14879
+ }
14880
+ async dangerouslyClearAll() {
14881
+ await this.#db.clearTable({ tableName: storage.TABLE_PROMPT_BLOCK_VERSIONS });
14882
+ await this.#db.clearTable({ tableName: storage.TABLE_PROMPT_BLOCKS });
14883
+ }
14884
+ // ==========================================================================
14885
+ // Prompt Block CRUD Methods
14886
+ // ==========================================================================
14887
+ async getById(id) {
14888
+ try {
14889
+ const tableName = getTableName2({ indexName: storage.TABLE_PROMPT_BLOCKS, schemaName: getSchemaName2(this.#schema) });
11569
14890
  const result = await this.#db.client.oneOrNone(`SELECT * FROM ${tableName} WHERE id = $1`, [id]);
11570
14891
  if (!result) {
11571
14892
  return null;
@@ -13534,16 +16855,39 @@ var SkillsPG = class _SkillsPG extends storage.SkillsStorage {
13534
16855
  this.#skipDefaultIndexes = skipDefaultIndexes;
13535
16856
  this.#indexes = indexes?.filter((idx) => _SkillsPG.MANAGED_TABLES.includes(idx.table));
13536
16857
  }
13537
- getDefaultIndexDefinitions() {
16858
+ static getDefaultIndexDefs(schemaPrefix) {
13538
16859
  return [
13539
16860
  {
13540
- name: "idx_skill_versions_skill_version",
16861
+ name: `${schemaPrefix}idx_skill_versions_skill_version`,
13541
16862
  table: storage.TABLE_SKILL_VERSIONS,
13542
16863
  columns: ["skillId", "versionNumber"],
13543
16864
  unique: true
13544
16865
  }
13545
16866
  ];
13546
16867
  }
16868
+ static getExportDDL(schemaName) {
16869
+ const statements = [];
16870
+ const parsedSchema = schemaName ? utils.parseSqlIdentifier(schemaName, "schema name") : "";
16871
+ const schemaPrefix = parsedSchema && parsedSchema !== "public" ? `${parsedSchema}_` : "";
16872
+ for (const tableName of _SkillsPG.MANAGED_TABLES) {
16873
+ statements.push(
16874
+ generateTableSQL({
16875
+ tableName,
16876
+ schema: storage.TABLE_SCHEMAS[tableName],
16877
+ schemaName,
16878
+ includeAllConstraints: true
16879
+ })
16880
+ );
16881
+ }
16882
+ for (const idx of _SkillsPG.getDefaultIndexDefs(schemaPrefix)) {
16883
+ statements.push(generateIndexSQL(idx, schemaName));
16884
+ }
16885
+ return statements;
16886
+ }
16887
+ getDefaultIndexDefinitions() {
16888
+ const schemaPrefix = this.#schema !== "public" ? `${this.#schema}_` : "";
16889
+ return _SkillsPG.getDefaultIndexDefs(schemaPrefix);
16890
+ }
13547
16891
  async createDefaultIndexes() {
13548
16892
  if (this.#skipDefaultIndexes) {
13549
16893
  return;
@@ -14241,6 +17585,254 @@ var SkillsPG = class _SkillsPG extends storage.SkillsStorage {
14241
17585
  };
14242
17586
  }
14243
17587
  };
17588
+ function normaliseScope(raw) {
17589
+ const value = raw == null ? "per-author" : String(raw);
17590
+ if (value === "shared") return "shared";
17591
+ if (value === "caller-supplied") return "caller-supplied";
17592
+ return "per-author";
17593
+ }
17594
+ function rowToToolProviderConnection(row) {
17595
+ return {
17596
+ authorId: String(row.authorId),
17597
+ providerId: String(row.providerId),
17598
+ toolkit: String(row.toolkit),
17599
+ connectionId: String(row.connectionId),
17600
+ label: row.label == null ? null : String(row.label),
17601
+ scope: normaliseScope(row.scope),
17602
+ createdAt: new Date(String(row.createdAtZ ?? row.createdAt)),
17603
+ updatedAt: new Date(String(row.updatedAtZ ?? row.updatedAt))
17604
+ };
17605
+ }
17606
+ var ToolProviderConnectionsPG = class _ToolProviderConnectionsPG extends storage.ToolProviderConnectionsStorage {
17607
+ #db;
17608
+ #schema;
17609
+ #skipDefaultIndexes;
17610
+ #indexes;
17611
+ static MANAGED_TABLES = [storage.TABLE_TOOL_PROVIDER_CONNECTIONS];
17612
+ constructor(config) {
17613
+ super();
17614
+ const { client, schemaName, skipDefaultIndexes, indexes } = resolvePgConfig(config);
17615
+ this.#db = new PgDB({ client, schemaName, skipDefaultIndexes });
17616
+ this.#schema = schemaName || "public";
17617
+ this.#skipDefaultIndexes = skipDefaultIndexes;
17618
+ this.#indexes = indexes?.filter(
17619
+ (idx) => _ToolProviderConnectionsPG.MANAGED_TABLES.includes(idx.table)
17620
+ );
17621
+ }
17622
+ async init() {
17623
+ await this.#db.createTable({
17624
+ tableName: storage.TABLE_TOOL_PROVIDER_CONNECTIONS,
17625
+ schema: storage.TABLE_SCHEMAS[storage.TABLE_TOOL_PROVIDER_CONNECTIONS],
17626
+ compositePrimaryKey: ["authorId", "providerId", "connectionId"]
17627
+ });
17628
+ await this.createDefaultIndexes();
17629
+ await this.createCustomIndexes();
17630
+ }
17631
+ static getDefaultIndexDefs(schemaPrefix) {
17632
+ return [
17633
+ {
17634
+ name: `${schemaPrefix}idx_tool_provider_connections_author`,
17635
+ table: storage.TABLE_TOOL_PROVIDER_CONNECTIONS,
17636
+ columns: ["authorId", "providerId", "toolkit"]
17637
+ }
17638
+ ];
17639
+ }
17640
+ static getExportDDL(schemaName) {
17641
+ const statements = [];
17642
+ const parsedSchema = schemaName ? utils.parseSqlIdentifier(schemaName, "schema name") : "";
17643
+ const schemaPrefix = parsedSchema && parsedSchema !== "public" ? `${parsedSchema}_` : "";
17644
+ statements.push(
17645
+ generateTableSQL({
17646
+ tableName: storage.TABLE_TOOL_PROVIDER_CONNECTIONS,
17647
+ schema: storage.TABLE_SCHEMAS[storage.TABLE_TOOL_PROVIDER_CONNECTIONS],
17648
+ schemaName,
17649
+ compositePrimaryKey: ["authorId", "providerId", "connectionId"],
17650
+ includeAllConstraints: true
17651
+ })
17652
+ );
17653
+ for (const idx of _ToolProviderConnectionsPG.getDefaultIndexDefs(schemaPrefix)) {
17654
+ statements.push(generateIndexSQL(idx, schemaName));
17655
+ }
17656
+ return statements;
17657
+ }
17658
+ getDefaultIndexDefinitions() {
17659
+ const schemaPrefix = this.#schema !== "public" ? `${this.#schema}_` : "";
17660
+ return _ToolProviderConnectionsPG.getDefaultIndexDefs(schemaPrefix);
17661
+ }
17662
+ async createDefaultIndexes() {
17663
+ if (this.#skipDefaultIndexes) return;
17664
+ for (const indexDef of this.getDefaultIndexDefinitions()) {
17665
+ try {
17666
+ await this.#db.createIndex(indexDef);
17667
+ } catch (error) {
17668
+ this.logger?.warn?.(`Failed to create index ${indexDef.name}:`, error);
17669
+ }
17670
+ }
17671
+ }
17672
+ async createCustomIndexes() {
17673
+ if (!this.#indexes || this.#indexes.length === 0) return;
17674
+ for (const indexDef of this.#indexes) {
17675
+ try {
17676
+ await this.#db.createIndex(indexDef);
17677
+ } catch (error) {
17678
+ this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
17679
+ }
17680
+ }
17681
+ }
17682
+ async dangerouslyClearAll() {
17683
+ await this.#db.clearTable({ tableName: storage.TABLE_TOOL_PROVIDER_CONNECTIONS });
17684
+ }
17685
+ async getConnectionById({
17686
+ authorId,
17687
+ providerId,
17688
+ connectionId
17689
+ }) {
17690
+ const tableName = getTableName2({
17691
+ indexName: storage.TABLE_TOOL_PROVIDER_CONNECTIONS,
17692
+ schemaName: getSchemaName2(this.#schema)
17693
+ });
17694
+ try {
17695
+ const row = await this.#db.client.oneOrNone(
17696
+ `SELECT * FROM ${tableName} WHERE "authorId" = $1 AND "providerId" = $2 AND "connectionId" = $3 LIMIT 1`,
17697
+ [authorId, providerId, connectionId]
17698
+ );
17699
+ return row ? rowToToolProviderConnection(row) : null;
17700
+ } catch (error$1) {
17701
+ throw new error.MastraError(
17702
+ {
17703
+ id: storage.createStorageErrorId("PG", "TOOL_PROVIDER_CONNECTION_GET", "FAILED"),
17704
+ domain: error.ErrorDomain.STORAGE,
17705
+ category: error.ErrorCategory.THIRD_PARTY,
17706
+ details: { authorId, providerId, connectionId }
17707
+ },
17708
+ error$1
17709
+ );
17710
+ }
17711
+ }
17712
+ async upsertConnection(input) {
17713
+ const { authorId, providerId, toolkit, connectionId, label } = input;
17714
+ const tableName = getTableName2({
17715
+ indexName: storage.TABLE_TOOL_PROVIDER_CONNECTIONS,
17716
+ schemaName: getSchemaName2(this.#schema)
17717
+ });
17718
+ const now = /* @__PURE__ */ new Date();
17719
+ const nowIso = now.toISOString();
17720
+ const labelValue = label == null ? null : label;
17721
+ try {
17722
+ return await this.#db.client.tx(async (t) => {
17723
+ const existing = await t.oneOrNone(
17724
+ `SELECT "createdAt", "createdAtZ", scope FROM ${tableName} WHERE "authorId" = $1 AND "providerId" = $2 AND "connectionId" = $3 LIMIT 1`,
17725
+ [authorId, providerId, connectionId]
17726
+ );
17727
+ const existingCreatedAt = existing ? existing.createdAtZ ?? existing.createdAt : null;
17728
+ const createdAt = existingCreatedAt != null ? new Date(existingCreatedAt).toISOString() : nowIso;
17729
+ const existingScope = existing && existing.scope != null ? normaliseScope(existing.scope) : void 0;
17730
+ const scope = input.scope ?? existingScope ?? "per-author";
17731
+ await t.none(
17732
+ `INSERT INTO ${tableName} ("authorId", "providerId", toolkit, "connectionId", label, scope, "createdAt", "createdAtZ", "updatedAt", "updatedAtZ")
17733
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
17734
+ ON CONFLICT ("authorId", "providerId", "connectionId") DO UPDATE SET
17735
+ toolkit = EXCLUDED.toolkit,
17736
+ label = EXCLUDED.label,
17737
+ scope = EXCLUDED.scope,
17738
+ "updatedAt" = EXCLUDED."updatedAt",
17739
+ "updatedAtZ" = EXCLUDED."updatedAtZ"`,
17740
+ [authorId, providerId, toolkit, connectionId, labelValue, scope, createdAt, createdAt, nowIso, nowIso]
17741
+ );
17742
+ return {
17743
+ authorId,
17744
+ providerId,
17745
+ toolkit,
17746
+ connectionId,
17747
+ label: labelValue,
17748
+ scope,
17749
+ createdAt: new Date(createdAt),
17750
+ updatedAt: now
17751
+ };
17752
+ });
17753
+ } catch (error$1) {
17754
+ throw new error.MastraError(
17755
+ {
17756
+ id: storage.createStorageErrorId("PG", "TOOL_PROVIDER_CONNECTION_UPSERT", "FAILED"),
17757
+ domain: error.ErrorDomain.STORAGE,
17758
+ category: error.ErrorCategory.THIRD_PARTY,
17759
+ details: { authorId, providerId, connectionId }
17760
+ },
17761
+ error$1
17762
+ );
17763
+ }
17764
+ }
17765
+ async listConnectionsByAuthor({
17766
+ authorId,
17767
+ providerId,
17768
+ toolkit,
17769
+ scope
17770
+ }) {
17771
+ const tableName = getTableName2({
17772
+ indexName: storage.TABLE_TOOL_PROVIDER_CONNECTIONS,
17773
+ schemaName: getSchemaName2(this.#schema)
17774
+ });
17775
+ try {
17776
+ const clauses = [];
17777
+ const args = [];
17778
+ if (authorId !== void 0) {
17779
+ args.push(authorId);
17780
+ clauses.push(`"authorId" = $${args.length}`);
17781
+ }
17782
+ if (providerId) {
17783
+ args.push(providerId);
17784
+ clauses.push(`"providerId" = $${args.length}`);
17785
+ }
17786
+ if (toolkit) {
17787
+ args.push(toolkit);
17788
+ clauses.push(`toolkit = $${args.length}`);
17789
+ }
17790
+ if (scope) {
17791
+ args.push(scope);
17792
+ clauses.push(`scope = $${args.length}`);
17793
+ }
17794
+ const whereClause = clauses.length > 0 ? ` WHERE ${clauses.join(" AND ")}` : "";
17795
+ const rows = await this.#db.client.manyOrNone(`SELECT * FROM ${tableName}${whereClause}`, args);
17796
+ return rows.map((row) => rowToToolProviderConnection(row));
17797
+ } catch (error$1) {
17798
+ throw new error.MastraError(
17799
+ {
17800
+ id: storage.createStorageErrorId("PG", "TOOL_PROVIDER_CONNECTION_LIST", "FAILED"),
17801
+ domain: error.ErrorDomain.STORAGE,
17802
+ category: error.ErrorCategory.THIRD_PARTY,
17803
+ details: { authorId: authorId ?? "", providerId: providerId ?? "", toolkit: toolkit ?? "" }
17804
+ },
17805
+ error$1
17806
+ );
17807
+ }
17808
+ }
17809
+ async deleteConnection({
17810
+ authorId,
17811
+ providerId,
17812
+ connectionId
17813
+ }) {
17814
+ const tableName = getTableName2({
17815
+ indexName: storage.TABLE_TOOL_PROVIDER_CONNECTIONS,
17816
+ schemaName: getSchemaName2(this.#schema)
17817
+ });
17818
+ try {
17819
+ await this.#db.client.none(
17820
+ `DELETE FROM ${tableName} WHERE "authorId" = $1 AND "providerId" = $2 AND "connectionId" = $3`,
17821
+ [authorId, providerId, connectionId]
17822
+ );
17823
+ } catch (error$1) {
17824
+ throw new error.MastraError(
17825
+ {
17826
+ id: storage.createStorageErrorId("PG", "TOOL_PROVIDER_CONNECTION_DELETE", "FAILED"),
17827
+ domain: error.ErrorDomain.STORAGE,
17828
+ category: error.ErrorCategory.THIRD_PARTY,
17829
+ details: { authorId, providerId, connectionId }
17830
+ },
17831
+ error$1
17832
+ );
17833
+ }
17834
+ }
17835
+ };
14244
17836
  function getSchemaName7(schema) {
14245
17837
  return schema ? `"${schema}"` : '"public"';
14246
17838
  }
@@ -14381,8 +17973,7 @@ var WorkflowsPG = class _WorkflowsPG extends storage.WorkflowsStorage {
14381
17973
  const existingSnapshot = existingSnapshotResult.snapshot;
14382
17974
  snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
14383
17975
  }
14384
- snapshot.context[stepId] = result;
14385
- snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
17976
+ storage.mergeWorkflowStepResult({ snapshot, stepId, result, requestContext });
14386
17977
  const now = /* @__PURE__ */ new Date();
14387
17978
  const sanitizedSnapshot = sanitizeJsonForPg(JSON.stringify(snapshot));
14388
17979
  await t.none(
@@ -14574,7 +18165,7 @@ var WorkflowsPG = class _WorkflowsPG extends storage.WorkflowsStorage {
14574
18165
  async listWorkflowRuns({
14575
18166
  workflowName,
14576
18167
  fromDate,
14577
- toDate,
18168
+ toDate: toDate2,
14578
18169
  perPage,
14579
18170
  page,
14580
18171
  resourceId,
@@ -14611,9 +18202,9 @@ var WorkflowsPG = class _WorkflowsPG extends storage.WorkflowsStorage {
14611
18202
  values.push(fromDate);
14612
18203
  paramIndex++;
14613
18204
  }
14614
- if (toDate) {
18205
+ if (toDate2) {
14615
18206
  conditions.push(`"createdAt" <= $${paramIndex}`);
14616
- values.push(toDate);
18207
+ values.push(toDate2);
14617
18208
  paramIndex++;
14618
18209
  }
14619
18210
  const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
@@ -14681,16 +18272,39 @@ var WorkspacesPG = class _WorkspacesPG extends storage.WorkspacesStorage {
14681
18272
  this.#skipDefaultIndexes = skipDefaultIndexes;
14682
18273
  this.#indexes = indexes?.filter((idx) => _WorkspacesPG.MANAGED_TABLES.includes(idx.table));
14683
18274
  }
14684
- getDefaultIndexDefinitions() {
18275
+ static getDefaultIndexDefs(schemaPrefix) {
14685
18276
  return [
14686
18277
  {
14687
- name: "idx_workspace_versions_workspace_version",
18278
+ name: `${schemaPrefix}idx_workspace_versions_workspace_version`,
14688
18279
  table: storage.TABLE_WORKSPACE_VERSIONS,
14689
18280
  columns: ["workspaceId", "versionNumber"],
14690
18281
  unique: true
14691
18282
  }
14692
18283
  ];
14693
18284
  }
18285
+ static getExportDDL(schemaName) {
18286
+ const statements = [];
18287
+ const parsedSchema = schemaName ? utils.parseSqlIdentifier(schemaName, "schema name") : "";
18288
+ const schemaPrefix = parsedSchema && parsedSchema !== "public" ? `${parsedSchema}_` : "";
18289
+ for (const tableName of _WorkspacesPG.MANAGED_TABLES) {
18290
+ statements.push(
18291
+ generateTableSQL({
18292
+ tableName,
18293
+ schema: storage.TABLE_SCHEMAS[tableName],
18294
+ schemaName,
18295
+ includeAllConstraints: true
18296
+ })
18297
+ );
18298
+ }
18299
+ for (const idx of _WorkspacesPG.getDefaultIndexDefs(schemaPrefix)) {
18300
+ statements.push(generateIndexSQL(idx, schemaName));
18301
+ }
18302
+ return statements;
18303
+ }
18304
+ getDefaultIndexDefinitions() {
18305
+ const schemaPrefix = this.#schema !== "public" ? `${this.#schema}_` : "";
18306
+ return _WorkspacesPG.getDefaultIndexDefs(schemaPrefix);
18307
+ }
14694
18308
  async createDefaultIndexes() {
14695
18309
  if (this.#skipDefaultIndexes) {
14696
18310
  return;
@@ -15332,19 +18946,30 @@ var WorkspacesPG = class _WorkspacesPG extends storage.WorkspacesStorage {
15332
18946
  };
15333
18947
  }
15334
18948
  };
15335
- function buildConnectionStringPoolConfig(config, defaults) {
15336
- const parsed = pgConnectionString.parse(config.connectionString);
15337
- return {
15338
- ...parsed,
15339
- ...config.ssl !== void 0 ? { ssl: config.ssl } : {},
15340
- max: config.max ?? defaults.max,
15341
- idleTimeoutMillis: config.idleTimeoutMillis ?? defaults.idleTimeoutMillis
15342
- };
15343
- }
15344
18949
 
15345
18950
  // src/storage/index.ts
15346
18951
  var DEFAULT_MAX_CONNECTIONS = 20;
15347
18952
  var DEFAULT_IDLE_TIMEOUT_MS = 3e4;
18953
+ function createConnectionStringPool(config) {
18954
+ return new pg.Pool(
18955
+ buildConnectionStringPoolConfig(config, {
18956
+ max: DEFAULT_MAX_CONNECTIONS,
18957
+ idleTimeoutMillis: DEFAULT_IDLE_TIMEOUT_MS
18958
+ })
18959
+ );
18960
+ }
18961
+ function createHostPool(config) {
18962
+ return new pg.Pool({
18963
+ host: config.host,
18964
+ port: config.port,
18965
+ database: config.database,
18966
+ user: config.user,
18967
+ password: config.password,
18968
+ ssl: config.ssl,
18969
+ max: config.max ?? DEFAULT_MAX_CONNECTIONS,
18970
+ idleTimeoutMillis: config.idleTimeoutMillis ?? DEFAULT_IDLE_TIMEOUT_MS
18971
+ });
18972
+ }
15348
18973
  var ALL_DOMAINS = [
15349
18974
  MemoryPG,
15350
18975
  NotificationsPG,
@@ -15353,6 +18978,12 @@ var ALL_DOMAINS = [
15353
18978
  ScorerDefinitionsPG,
15354
18979
  PromptBlocksPG,
15355
18980
  AgentsPG,
18981
+ MCPClientsPG,
18982
+ MCPServersPG,
18983
+ WorkspacesPG,
18984
+ SkillsPG,
18985
+ BlobsPG,
18986
+ ToolProviderConnectionsPG,
15356
18987
  WorkflowsPG,
15357
18988
  DatasetsPG,
15358
18989
  ExperimentsPG,
@@ -15377,6 +19008,7 @@ var PostgresStore = class extends storage.MastraCompositeStore {
15377
19008
  #pool;
15378
19009
  #db;
15379
19010
  #ownsPool;
19011
+ #poolClosed = false;
15380
19012
  schema;
15381
19013
  isInitialized = false;
15382
19014
  stores;
@@ -15413,6 +19045,7 @@ var PostgresStore = class extends storage.MastraCompositeStore {
15413
19045
  workspaces: new WorkspacesPG(domainConfig),
15414
19046
  skills: new SkillsPG(domainConfig),
15415
19047
  favorites: new FavoritesPG(domainConfig),
19048
+ toolProviderConnections: new ToolProviderConnectionsPG(domainConfig),
15416
19049
  blobs: new BlobsPG(domainConfig),
15417
19050
  datasets: new DatasetsPG(domainConfig),
15418
19051
  experiments: new ExperimentsPG(domainConfig),
@@ -15433,24 +19066,10 @@ var PostgresStore = class extends storage.MastraCompositeStore {
15433
19066
  }
15434
19067
  createPool(config) {
15435
19068
  if (isConnectionStringConfig(config)) {
15436
- return new pg.Pool(
15437
- buildConnectionStringPoolConfig(config, {
15438
- max: DEFAULT_MAX_CONNECTIONS,
15439
- idleTimeoutMillis: DEFAULT_IDLE_TIMEOUT_MS
15440
- })
15441
- );
19069
+ return createConnectionStringPool(config);
15442
19070
  }
15443
19071
  if (isHostConfig(config)) {
15444
- return new pg.Pool({
15445
- host: config.host,
15446
- port: config.port,
15447
- database: config.database,
15448
- user: config.user,
15449
- password: config.password,
15450
- ssl: config.ssl,
15451
- max: config.max ?? DEFAULT_MAX_CONNECTIONS,
15452
- idleTimeoutMillis: config.idleTimeoutMillis ?? DEFAULT_IDLE_TIMEOUT_MS
15453
- });
19072
+ return createHostPool(config);
15454
19073
  }
15455
19074
  if (isCloudSqlConfig(config)) {
15456
19075
  return new pg.Pool(config);
@@ -15500,13 +19119,81 @@ var PostgresStore = class extends storage.MastraCompositeStore {
15500
19119
  /**
15501
19120
  * Closes the connection pool if it was created by this store.
15502
19121
  * If a pool was passed in via config, it will not be closed.
19122
+ * Safe to call multiple times — subsequent calls are no-ops.
15503
19123
  */
15504
19124
  async close() {
15505
- if (this.#ownsPool) {
19125
+ if (this.#ownsPool && !this.#poolClosed) {
19126
+ this.#poolClosed = true;
15506
19127
  await this.#pool.end();
15507
19128
  }
15508
19129
  }
15509
19130
  };
19131
+ function isSameConnectionTarget(primary, observability) {
19132
+ if ("pool" in primary && "pool" in observability) {
19133
+ return primary.pool === observability.pool;
19134
+ }
19135
+ if ("connectionString" in primary && "connectionString" in observability) {
19136
+ return primary.connectionString === observability.connectionString;
19137
+ }
19138
+ if ("host" in primary && "host" in observability) {
19139
+ return primary.host === observability.host && (primary.port ?? 5432) === (observability.port ?? 5432) && primary.database === observability.database;
19140
+ }
19141
+ return false;
19142
+ }
19143
+ var COLLISION_WARNING = "PostgresStoreVNext: the `observability` connection appears to point at the same Postgres instance as the primary store. For production workloads, point observability at a dedicated Postgres instance to avoid degrading your application database performance.";
19144
+ var PostgresStoreVNext = class extends PostgresStore {
19145
+ #observabilityPool;
19146
+ #ownsObservabilityPool = false;
19147
+ #observabilityPoolClosed = false;
19148
+ constructor(config) {
19149
+ super(config);
19150
+ this.name = "PostgresStoreVNext";
19151
+ const obsConfig = config.observability;
19152
+ if (isSameConnectionTarget(config, obsConfig)) {
19153
+ console.warn(COLLISION_WARNING);
19154
+ }
19155
+ const built = this.#createObservabilityClient(obsConfig);
19156
+ const observabilityClient = built.client;
19157
+ this.#observabilityPool = built.pool;
19158
+ this.#ownsObservabilityPool = built.owned;
19159
+ const observability = new ObservabilityStoragePostgresVNext({
19160
+ client: observabilityClient,
19161
+ schemaName: obsConfig.schemaName ?? config.schemaName,
19162
+ partitioning: obsConfig.partitioning,
19163
+ discovery: obsConfig.discovery
19164
+ });
19165
+ this.stores = {
19166
+ ...this.stores,
19167
+ observability
19168
+ };
19169
+ }
19170
+ #createObservabilityClient(cfg) {
19171
+ if ("pool" in cfg && cfg.pool) {
19172
+ return { client: new PoolAdapter(cfg.pool), pool: cfg.pool, owned: false };
19173
+ }
19174
+ if ("connectionString" in cfg && typeof cfg.connectionString === "string") {
19175
+ const pool2 = createConnectionStringPool(cfg);
19176
+ return { client: new PoolAdapter(pool2), pool: pool2, owned: true };
19177
+ }
19178
+ if ("host" in cfg) {
19179
+ const pool2 = createHostPool(cfg);
19180
+ return { client: new PoolAdapter(pool2), pool: pool2, owned: true };
19181
+ }
19182
+ const pool = new pg.Pool(cfg);
19183
+ return { client: new PoolAdapter(pool), pool, owned: true };
19184
+ }
19185
+ /**
19186
+ * Closes both the primary pool (when owned) and the observability pool
19187
+ * (when this store created it). Safe to call multiple times.
19188
+ */
19189
+ async close() {
19190
+ await super.close();
19191
+ if (this.#ownsObservabilityPool && this.#observabilityPool && !this.#observabilityPoolClosed) {
19192
+ this.#observabilityPoolClosed = true;
19193
+ await this.#observabilityPool.end();
19194
+ }
19195
+ }
19196
+ };
15510
19197
 
15511
19198
  // src/vector/prompt.ts
15512
19199
  var PGVECTOR_PROMPT = `When querying PG Vector, you can ONLY use the operators listed below. Any other operators will be rejected.
@@ -15619,15 +19306,18 @@ exports.MCPServersPG = MCPServersPG;
15619
19306
  exports.MemoryPG = MemoryPG;
15620
19307
  exports.NotificationsPG = NotificationsPG;
15621
19308
  exports.ObservabilityPG = ObservabilityPG;
19309
+ exports.ObservabilityStoragePostgresVNext = ObservabilityStoragePostgresVNext;
15622
19310
  exports.PGVECTOR_PROMPT = PGVECTOR_PROMPT;
15623
19311
  exports.PgVector = PgVector;
15624
19312
  exports.PoolAdapter = PoolAdapter;
15625
19313
  exports.PostgresStore = PostgresStore;
19314
+ exports.PostgresStoreVNext = PostgresStoreVNext;
15626
19315
  exports.PromptBlocksPG = PromptBlocksPG;
15627
19316
  exports.SchedulesPG = SchedulesPG;
15628
19317
  exports.ScorerDefinitionsPG = ScorerDefinitionsPG;
15629
19318
  exports.ScoresPG = ScoresPG;
15630
19319
  exports.SkillsPG = SkillsPG;
19320
+ exports.ToolProviderConnectionsPG = ToolProviderConnectionsPG;
15631
19321
  exports.WorkflowsPG = WorkflowsPG;
15632
19322
  exports.WorkspacesPG = WorkspacesPG;
15633
19323
  exports.exportSchemas = exportSchemas;