@mastra/pg 1.12.1 → 1.13.0-alpha.1

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