@mastra/pg 1.12.1-alpha.0 → 1.13.0-alpha.0

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