@mastra/pg 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
2
- import { createVectorErrorId, AgentsStorage, TABLE_AGENTS, TABLE_AGENT_VERSIONS, TABLE_SCHEMAS, createStorageErrorId, normalizePerPage, calculatePagination, 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, MCPClientsStorage, TABLE_MCP_CLIENTS, TABLE_MCP_CLIENT_VERSIONS, MemoryStorage, TABLE_THREADS, TABLE_MESSAGES, TABLE_RESOURCES, ObservabilityStorage, TABLE_SPANS, listTracesArgsSchema, toTraceSpans, PromptBlocksStorage, TABLE_PROMPT_BLOCKS, TABLE_PROMPT_BLOCK_VERSIONS, ScorerDefinitionsStorage, TABLE_SCORER_DEFINITIONS, TABLE_SCORER_DEFINITION_VERSIONS, ScoresStorage, TABLE_SCORERS, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, MastraCompositeStore, TraceStatus, getDefaultValue, transformScoreRow as transformScoreRow$1, getSqlType } from '@mastra/core/storage';
2
+ import { createVectorErrorId, AgentsStorage, TABLE_AGENTS, TABLE_AGENT_VERSIONS, TABLE_SCHEMAS, createStorageErrorId, normalizePerPage, calculatePagination, BlobStore, TABLE_SKILL_BLOBS, 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, MCPClientsStorage, TABLE_MCP_CLIENTS, TABLE_MCP_CLIENT_VERSIONS, MemoryStorage, TABLE_THREADS, TABLE_MESSAGES, TABLE_RESOURCES, ObservabilityStorage, TABLE_SPANS, listTracesArgsSchema, toTraceSpans, PromptBlocksStorage, TABLE_PROMPT_BLOCKS, TABLE_PROMPT_BLOCK_VERSIONS, 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';
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';
@@ -3208,6 +3208,11 @@ var AgentsPG = class _AgentsPG extends AgentsStorage {
3208
3208
  schema: TABLE_SCHEMAS[TABLE_AGENTS],
3209
3209
  ifNotExists: ["status", "authorId"]
3210
3210
  });
3211
+ await this.#db.alterTable({
3212
+ tableName: TABLE_AGENT_VERSIONS,
3213
+ schema: TABLE_SCHEMAS[TABLE_AGENT_VERSIONS],
3214
+ ifNotExists: ["mcpClients", "requestContextSchema", "workspace", "skills", "skillsFormat"]
3215
+ });
3211
3216
  await this.#migrateToolsToJsonbFormat();
3212
3217
  await this.createDefaultIndexes();
3213
3218
  await this.createCustomIndexes();
@@ -3513,68 +3518,7 @@ var AgentsPG = class _AgentsPG extends AgentsStorage {
3513
3518
  details: { agentId: id }
3514
3519
  });
3515
3520
  }
3516
- const { authorId, activeVersionId, metadata, ...configFields } = updates;
3517
- const configFieldNames = [
3518
- "name",
3519
- "description",
3520
- "instructions",
3521
- "model",
3522
- "tools",
3523
- "defaultOptions",
3524
- "workflows",
3525
- "agents",
3526
- "integrationTools",
3527
- "inputProcessors",
3528
- "outputProcessors",
3529
- "memory",
3530
- "scorers",
3531
- "mcpClients",
3532
- "requestContextSchema"
3533
- ];
3534
- const hasConfigUpdate = configFieldNames.some((field) => field in configFields);
3535
- if (hasConfigUpdate) {
3536
- const latestVersion = await this.getLatestVersion(id);
3537
- if (!latestVersion) {
3538
- throw new MastraError({
3539
- id: createStorageErrorId("PG", "UPDATE_AGENT", "NO_VERSIONS"),
3540
- domain: ErrorDomain.STORAGE,
3541
- category: ErrorCategory.SYSTEM,
3542
- text: `No versions found for agent ${id}`,
3543
- details: { agentId: id }
3544
- });
3545
- }
3546
- const {
3547
- id: _versionId,
3548
- agentId: _agentId,
3549
- versionNumber: _versionNumber,
3550
- changedFields: _changedFields,
3551
- changeMessage: _changeMessage,
3552
- createdAt: _createdAt,
3553
- ...latestConfig
3554
- } = latestVersion;
3555
- const sanitizedConfigFields = Object.fromEntries(
3556
- Object.entries(configFields).map(([key, value]) => [key, value === null ? void 0 : value])
3557
- );
3558
- const newConfig = {
3559
- ...latestConfig,
3560
- ...sanitizedConfigFields
3561
- };
3562
- const changedFields = configFieldNames.filter(
3563
- (field) => field in configFields && JSON.stringify(configFields[field]) !== JSON.stringify(latestConfig[field])
3564
- );
3565
- if (changedFields.length > 0) {
3566
- const newVersionId = crypto.randomUUID();
3567
- const newVersionNumber = latestVersion.versionNumber + 1;
3568
- await this.createVersion({
3569
- id: newVersionId,
3570
- agentId: id,
3571
- versionNumber: newVersionNumber,
3572
- ...newConfig,
3573
- changedFields,
3574
- changeMessage: `Updated ${changedFields.join(", ")}`
3575
- });
3576
- }
3577
- }
3521
+ const { authorId, activeVersionId, metadata, status } = updates;
3578
3522
  const setClauses = [];
3579
3523
  const values = [];
3580
3524
  let paramIndex = 1;
@@ -3586,6 +3530,10 @@ var AgentsPG = class _AgentsPG extends AgentsStorage {
3586
3530
  setClauses.push(`"activeVersionId" = $${paramIndex++}`);
3587
3531
  values.push(activeVersionId);
3588
3532
  }
3533
+ if (status !== void 0) {
3534
+ setClauses.push(`status = $${paramIndex++}`);
3535
+ values.push(status);
3536
+ }
3589
3537
  if (metadata !== void 0) {
3590
3538
  setClauses.push(`metadata = $${paramIndex++}`);
3591
3539
  values.push(JSON.stringify(metadata));
@@ -3596,12 +3544,7 @@ var AgentsPG = class _AgentsPG extends AgentsStorage {
3596
3544
  setClauses.push(`"updatedAtZ" = $${paramIndex++}`);
3597
3545
  values.push(now);
3598
3546
  values.push(id);
3599
- if (setClauses.length > 2) {
3600
- await this.#db.client.none(
3601
- `UPDATE ${tableName} SET ${setClauses.join(", ")} WHERE id = $${paramIndex}`,
3602
- values
3603
- );
3604
- }
3547
+ await this.#db.client.none(`UPDATE ${tableName} SET ${setClauses.join(", ")} WHERE id = $${paramIndex}`, values);
3605
3548
  const updatedAgent = await this.getById(id);
3606
3549
  if (!updatedAgent) {
3607
3550
  throw new MastraError({
@@ -3647,7 +3590,7 @@ var AgentsPG = class _AgentsPG extends AgentsStorage {
3647
3590
  }
3648
3591
  }
3649
3592
  async list(args) {
3650
- const { page = 0, perPage: perPageInput, orderBy } = args || {};
3593
+ const { page = 0, perPage: perPageInput, orderBy, authorId, metadata, status } = args || {};
3651
3594
  const { field, direction } = this.parseOrderBy(orderBy);
3652
3595
  if (page < 0) {
3653
3596
  throw new MastraError(
@@ -3664,7 +3607,26 @@ var AgentsPG = class _AgentsPG extends AgentsStorage {
3664
3607
  const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
3665
3608
  try {
3666
3609
  const tableName = getTableName2({ indexName: TABLE_AGENTS, schemaName: getSchemaName2(this.#schema) });
3667
- const countResult = await this.#db.client.one(`SELECT COUNT(*) as count FROM ${tableName}`);
3610
+ const conditions = [];
3611
+ const queryParams = [];
3612
+ let paramIdx = 1;
3613
+ if (status) {
3614
+ conditions.push(`status = $${paramIdx++}`);
3615
+ queryParams.push(status);
3616
+ }
3617
+ if (authorId !== void 0) {
3618
+ conditions.push(`"authorId" = $${paramIdx++}`);
3619
+ queryParams.push(authorId);
3620
+ }
3621
+ if (metadata && Object.keys(metadata).length > 0) {
3622
+ conditions.push(`metadata @> $${paramIdx++}::jsonb`);
3623
+ queryParams.push(JSON.stringify(metadata));
3624
+ }
3625
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
3626
+ const countResult = await this.#db.client.one(
3627
+ `SELECT COUNT(*) as count FROM ${tableName} ${whereClause}`,
3628
+ queryParams
3629
+ );
3668
3630
  const total = parseInt(countResult.count, 10);
3669
3631
  if (total === 0) {
3670
3632
  return {
@@ -3677,8 +3639,8 @@ var AgentsPG = class _AgentsPG extends AgentsStorage {
3677
3639
  }
3678
3640
  const limitValue = perPageInput === false ? total : perPage;
3679
3641
  const dataResult = await this.#db.client.manyOrNone(
3680
- `SELECT * FROM ${tableName} ORDER BY "${field}" ${direction} LIMIT $1 OFFSET $2`,
3681
- [limitValue, offset]
3642
+ `SELECT * FROM ${tableName} ${whereClause} ORDER BY "${field}" ${direction} LIMIT $${paramIdx++} OFFSET $${paramIdx++}`,
3643
+ [...queryParams, limitValue, offset]
3682
3644
  );
3683
3645
  const agents = (dataResult || []).map((row) => this.parseRow(row));
3684
3646
  return {
@@ -3714,9 +3676,10 @@ var AgentsPG = class _AgentsPG extends AgentsStorage {
3714
3676
  name, description, instructions, model, tools,
3715
3677
  "defaultOptions", workflows, agents, "integrationTools",
3716
3678
  "inputProcessors", "outputProcessors", memory, scorers,
3717
- "mcpClients", "requestContextSchema", "changedFields", "changeMessage",
3679
+ "mcpClients", "requestContextSchema", workspace, skills, "skillsFormat",
3680
+ "changedFields", "changeMessage",
3718
3681
  "createdAt", "createdAtZ"
3719
- ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22)`,
3682
+ ) 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)`,
3720
3683
  [
3721
3684
  input.id,
3722
3685
  input.agentId,
@@ -3736,6 +3699,9 @@ var AgentsPG = class _AgentsPG extends AgentsStorage {
3736
3699
  input.scorers ? JSON.stringify(input.scorers) : null,
3737
3700
  input.mcpClients ? JSON.stringify(input.mcpClients) : null,
3738
3701
  input.requestContextSchema ? JSON.stringify(input.requestContextSchema) : null,
3702
+ input.workspace ? JSON.stringify(input.workspace) : null,
3703
+ input.skills ? JSON.stringify(input.skills) : null,
3704
+ input.skillsFormat ?? null,
3739
3705
  input.changedFields ? JSON.stringify(input.changedFields) : null,
3740
3706
  input.changeMessage ?? null,
3741
3707
  nowIso,
@@ -3975,12 +3941,92 @@ var AgentsPG = class _AgentsPG extends AgentsStorage {
3975
3941
  scorers: this.parseJson(row.scorers, "scorers"),
3976
3942
  mcpClients: this.parseJson(row.mcpClients, "mcpClients"),
3977
3943
  requestContextSchema: this.parseJson(row.requestContextSchema, "requestContextSchema"),
3944
+ workspace: this.parseJson(row.workspace, "workspace"),
3945
+ skills: this.parseJson(row.skills, "skills"),
3946
+ skillsFormat: row.skillsFormat,
3978
3947
  changedFields: this.parseJson(row.changedFields, "changedFields"),
3979
3948
  changeMessage: row.changeMessage,
3980
3949
  createdAt: row.createdAtZ || row.createdAt
3981
3950
  };
3982
3951
  }
3983
3952
  };
3953
+ var BlobsPG = class extends BlobStore {
3954
+ #db;
3955
+ #schema;
3956
+ static MANAGED_TABLES = [TABLE_SKILL_BLOBS];
3957
+ constructor(config) {
3958
+ super();
3959
+ const { client, schemaName, skipDefaultIndexes } = resolvePgConfig(config);
3960
+ this.#db = new PgDB({ client, schemaName, skipDefaultIndexes });
3961
+ this.#schema = schemaName || "public";
3962
+ }
3963
+ async init() {
3964
+ await this.#db.createTable({
3965
+ tableName: TABLE_SKILL_BLOBS,
3966
+ schema: TABLE_SCHEMAS[TABLE_SKILL_BLOBS]
3967
+ });
3968
+ }
3969
+ async put(entry) {
3970
+ const tableName = getTableName2({ indexName: TABLE_SKILL_BLOBS, schemaName: getSchemaName2(this.#schema) });
3971
+ const now = entry.createdAt ?? /* @__PURE__ */ new Date();
3972
+ const nowIso = now.toISOString();
3973
+ await this.#db.client.none(
3974
+ `INSERT INTO ${tableName} ("hash", "content", "size", "mimeType", "createdAt", "createdAtZ")
3975
+ VALUES ($1, $2, $3, $4, $5, $6)
3976
+ ON CONFLICT ("hash") DO NOTHING`,
3977
+ [entry.hash, entry.content, entry.size, entry.mimeType ?? null, nowIso, nowIso]
3978
+ );
3979
+ }
3980
+ async get(hash) {
3981
+ const tableName = getTableName2({ indexName: TABLE_SKILL_BLOBS, schemaName: getSchemaName2(this.#schema) });
3982
+ const row = await this.#db.client.oneOrNone(`SELECT * FROM ${tableName} WHERE "hash" = $1`, [hash]);
3983
+ if (!row) return null;
3984
+ return this.#parseRow(row);
3985
+ }
3986
+ async has(hash) {
3987
+ const tableName = getTableName2({ indexName: TABLE_SKILL_BLOBS, schemaName: getSchemaName2(this.#schema) });
3988
+ const row = await this.#db.client.oneOrNone(`SELECT 1 FROM ${tableName} WHERE "hash" = $1 LIMIT 1`, [hash]);
3989
+ return row !== null;
3990
+ }
3991
+ async delete(hash) {
3992
+ const tableName = getTableName2({ indexName: TABLE_SKILL_BLOBS, schemaName: getSchemaName2(this.#schema) });
3993
+ const result = await this.#db.client.query(`DELETE FROM ${tableName} WHERE "hash" = $1`, [hash]);
3994
+ return (result.rowCount ?? 0) > 0;
3995
+ }
3996
+ async putMany(entries) {
3997
+ if (entries.length === 0) return;
3998
+ for (const entry of entries) {
3999
+ await this.put(entry);
4000
+ }
4001
+ }
4002
+ async getMany(hashes) {
4003
+ const result = /* @__PURE__ */ new Map();
4004
+ if (hashes.length === 0) return result;
4005
+ const tableName = getTableName2({ indexName: TABLE_SKILL_BLOBS, schemaName: getSchemaName2(this.#schema) });
4006
+ const placeholders = hashes.map((_, i) => `$${i + 1}`).join(", ");
4007
+ const rows = await this.#db.client.manyOrNone(
4008
+ `SELECT * FROM ${tableName} WHERE "hash" IN (${placeholders})`,
4009
+ hashes
4010
+ );
4011
+ for (const row of rows) {
4012
+ const entry = this.#parseRow(row);
4013
+ result.set(entry.hash, entry);
4014
+ }
4015
+ return result;
4016
+ }
4017
+ async dangerouslyClearAll() {
4018
+ await this.#db.clearTable({ tableName: TABLE_SKILL_BLOBS });
4019
+ }
4020
+ #parseRow(row) {
4021
+ return {
4022
+ hash: row.hash,
4023
+ content: row.content,
4024
+ size: Number(row.size),
4025
+ mimeType: row.mimeType || void 0,
4026
+ createdAt: new Date(row.createdAtZ || row.createdAt)
4027
+ };
4028
+ }
4029
+ };
3984
4030
  function jsonbArg(value) {
3985
4031
  return value === void 0 || value === null ? null : JSON.stringify(value);
3986
4032
  }
@@ -4143,8 +4189,8 @@ var DatasetsPG = class _DatasetsPG extends DatasetsStorage {
4143
4189
  name: input.name,
4144
4190
  description: input.description,
4145
4191
  metadata: input.metadata,
4146
- inputSchema: input.inputSchema,
4147
- groundTruthSchema: input.groundTruthSchema,
4192
+ inputSchema: input.inputSchema ?? void 0,
4193
+ groundTruthSchema: input.groundTruthSchema ?? void 0,
4148
4194
  version: 0,
4149
4195
  createdAt: now,
4150
4196
  updatedAt: now
@@ -4222,8 +4268,8 @@ var DatasetsPG = class _DatasetsPG extends DatasetsStorage {
4222
4268
  name: args.name ?? existing.name,
4223
4269
  description: args.description ?? existing.description,
4224
4270
  metadata: args.metadata ?? existing.metadata,
4225
- inputSchema: args.inputSchema !== void 0 ? args.inputSchema : existing.inputSchema,
4226
- groundTruthSchema: args.groundTruthSchema !== void 0 ? args.groundTruthSchema : existing.groundTruthSchema,
4271
+ inputSchema: (args.inputSchema !== void 0 ? args.inputSchema : existing.inputSchema) ?? void 0,
4272
+ groundTruthSchema: (args.groundTruthSchema !== void 0 ? args.groundTruthSchema : existing.groundTruthSchema) ?? void 0,
4227
4273
  updatedAt: new Date(now)
4228
4274
  };
4229
4275
  } catch (error) {
@@ -5472,46 +5518,7 @@ var MCPClientsPG = class _MCPClientsPG extends MCPClientsStorage {
5472
5518
  details: { mcpClientId: id }
5473
5519
  });
5474
5520
  }
5475
- const { authorId, activeVersionId, metadata, status, ...configFields } = updates;
5476
- let versionCreated = false;
5477
- const hasConfigUpdate = SNAPSHOT_FIELDS.some((field) => field in configFields);
5478
- if (hasConfigUpdate) {
5479
- const latestVersion = await this.getLatestVersion(id);
5480
- if (!latestVersion) {
5481
- throw new MastraError({
5482
- id: createStorageErrorId("PG", "UPDATE_MCP_CLIENT", "NO_VERSIONS"),
5483
- domain: ErrorDomain.STORAGE,
5484
- category: ErrorCategory.SYSTEM,
5485
- text: `No versions found for MCP client ${id}`,
5486
- details: { mcpClientId: id }
5487
- });
5488
- }
5489
- const {
5490
- id: _versionId,
5491
- mcpClientId: _mcpClientId,
5492
- versionNumber: _versionNumber,
5493
- changedFields: _changedFields,
5494
- changeMessage: _changeMessage,
5495
- createdAt: _createdAt,
5496
- ...latestConfig
5497
- } = latestVersion;
5498
- const newConfig = { ...latestConfig, ...configFields };
5499
- const changedFields = SNAPSHOT_FIELDS.filter(
5500
- (field) => field in configFields && JSON.stringify(configFields[field]) !== JSON.stringify(latestConfig[field])
5501
- );
5502
- if (changedFields.length > 0) {
5503
- versionCreated = true;
5504
- const newVersionId = crypto.randomUUID();
5505
- await this.createVersion({
5506
- id: newVersionId,
5507
- mcpClientId: id,
5508
- versionNumber: latestVersion.versionNumber + 1,
5509
- ...newConfig,
5510
- changedFields: [...changedFields],
5511
- changeMessage: `Updated ${changedFields.join(", ")}`
5512
- });
5513
- }
5514
- }
5521
+ const { authorId, activeVersionId, metadata, status } = updates;
5515
5522
  const setClauses = [];
5516
5523
  const values = [];
5517
5524
  let paramIndex = 1;
@@ -5522,10 +5529,6 @@ var MCPClientsPG = class _MCPClientsPG extends MCPClientsStorage {
5522
5529
  if (activeVersionId !== void 0) {
5523
5530
  setClauses.push(`"activeVersionId" = $${paramIndex++}`);
5524
5531
  values.push(activeVersionId);
5525
- if (status === void 0) {
5526
- setClauses.push(`status = $${paramIndex++}`);
5527
- values.push("published");
5528
- }
5529
5532
  }
5530
5533
  if (status !== void 0) {
5531
5534
  setClauses.push(`status = $${paramIndex++}`);
@@ -5542,12 +5545,7 @@ var MCPClientsPG = class _MCPClientsPG extends MCPClientsStorage {
5542
5545
  setClauses.push(`"updatedAtZ" = $${paramIndex++}`);
5543
5546
  values.push(now);
5544
5547
  values.push(id);
5545
- if (setClauses.length > 2 || versionCreated) {
5546
- await this.#db.client.none(
5547
- `UPDATE ${tableName} SET ${setClauses.join(", ")} WHERE id = $${paramIndex}`,
5548
- values
5549
- );
5550
- }
5548
+ await this.#db.client.none(`UPDATE ${tableName} SET ${setClauses.join(", ")} WHERE id = $${paramIndex}`, values);
5551
5549
  const updatedClient = await this.getById(id);
5552
5550
  if (!updatedClient) {
5553
5551
  throw new MastraError({
@@ -5591,7 +5589,7 @@ var MCPClientsPG = class _MCPClientsPG extends MCPClientsStorage {
5591
5589
  }
5592
5590
  }
5593
5591
  async list(args) {
5594
- const { page = 0, perPage: perPageInput, orderBy, authorId, metadata } = args || {};
5592
+ const { page = 0, perPage: perPageInput, orderBy, authorId, metadata, status = "published" } = args || {};
5595
5593
  const { field, direction } = this.parseOrderBy(orderBy);
5596
5594
  if (page < 0) {
5597
5595
  throw new MastraError(
@@ -5611,6 +5609,8 @@ var MCPClientsPG = class _MCPClientsPG extends MCPClientsStorage {
5611
5609
  const conditions = [];
5612
5610
  const queryParams = [];
5613
5611
  let paramIdx = 1;
5612
+ conditions.push(`status = $${paramIdx++}`);
5613
+ queryParams.push(status);
5614
5614
  if (authorId !== void 0) {
5615
5615
  conditions.push(`"authorId" = $${paramIdx++}`);
5616
5616
  queryParams.push(authorId);
@@ -5619,7 +5619,7 @@ var MCPClientsPG = class _MCPClientsPG extends MCPClientsStorage {
5619
5619
  conditions.push(`metadata @> $${paramIdx++}::jsonb`);
5620
5620
  queryParams.push(JSON.stringify(metadata));
5621
5621
  }
5622
- const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
5622
+ const whereClause = `WHERE ${conditions.join(" AND ")}`;
5623
5623
  const countResult = await this.#db.client.one(
5624
5624
  `SELECT COUNT(*) as count FROM ${tableName} ${whereClause}`,
5625
5625
  queryParams
@@ -7169,7 +7169,7 @@ var MemoryPG = class _MemoryPG extends MemoryStorage {
7169
7169
  const newThread = {
7170
7170
  id: newThreadId,
7171
7171
  resourceId: resourceId || sourceThread.resourceId,
7172
- title: title || (sourceThread.title ? `Clone of ${sourceThread.title}` : void 0),
7172
+ title: title || (sourceThread.title ? `Clone of ${sourceThread.title}` : ""),
7173
7173
  metadata: {
7174
7174
  ...metadata,
7175
7175
  clone: cloneMetadata
@@ -8961,46 +8961,7 @@ var PromptBlocksPG = class _PromptBlocksPG extends PromptBlocksStorage {
8961
8961
  details: { blockId: id }
8962
8962
  });
8963
8963
  }
8964
- const { authorId, activeVersionId, metadata, status, ...configFields } = updates;
8965
- let versionCreated = false;
8966
- const hasConfigUpdate = SNAPSHOT_FIELDS2.some((field) => field in configFields);
8967
- if (hasConfigUpdate) {
8968
- const latestVersion = await this.getLatestVersion(id);
8969
- if (!latestVersion) {
8970
- throw new MastraError({
8971
- id: createStorageErrorId("PG", "UPDATE_PROMPT_BLOCK", "NO_VERSIONS"),
8972
- domain: ErrorDomain.STORAGE,
8973
- category: ErrorCategory.SYSTEM,
8974
- text: `No versions found for prompt block ${id}`,
8975
- details: { blockId: id }
8976
- });
8977
- }
8978
- const {
8979
- id: _versionId,
8980
- blockId: _blockId,
8981
- versionNumber: _versionNumber,
8982
- changedFields: _changedFields,
8983
- changeMessage: _changeMessage,
8984
- createdAt: _createdAt,
8985
- ...latestConfig
8986
- } = latestVersion;
8987
- const newConfig = { ...latestConfig, ...configFields };
8988
- const changedFields = SNAPSHOT_FIELDS2.filter(
8989
- (field) => field in configFields && JSON.stringify(configFields[field]) !== JSON.stringify(latestConfig[field])
8990
- );
8991
- if (changedFields.length > 0) {
8992
- versionCreated = true;
8993
- const newVersionId = crypto.randomUUID();
8994
- await this.createVersion({
8995
- id: newVersionId,
8996
- blockId: id,
8997
- versionNumber: latestVersion.versionNumber + 1,
8998
- ...newConfig,
8999
- changedFields: [...changedFields],
9000
- changeMessage: `Updated ${changedFields.join(", ")}`
9001
- });
9002
- }
9003
- }
8964
+ const { authorId, activeVersionId, metadata, status } = updates;
9004
8965
  const setClauses = [];
9005
8966
  const values = [];
9006
8967
  let paramIndex = 1;
@@ -9011,10 +8972,6 @@ var PromptBlocksPG = class _PromptBlocksPG extends PromptBlocksStorage {
9011
8972
  if (activeVersionId !== void 0) {
9012
8973
  setClauses.push(`"activeVersionId" = $${paramIndex++}`);
9013
8974
  values.push(activeVersionId);
9014
- if (status === void 0) {
9015
- setClauses.push(`status = $${paramIndex++}`);
9016
- values.push("published");
9017
- }
9018
8975
  }
9019
8976
  if (status !== void 0) {
9020
8977
  setClauses.push(`status = $${paramIndex++}`);
@@ -9031,12 +8988,7 @@ var PromptBlocksPG = class _PromptBlocksPG extends PromptBlocksStorage {
9031
8988
  setClauses.push(`"updatedAtZ" = $${paramIndex++}`);
9032
8989
  values.push(now);
9033
8990
  values.push(id);
9034
- if (setClauses.length > 2 || versionCreated) {
9035
- await this.#db.client.none(
9036
- `UPDATE ${tableName} SET ${setClauses.join(", ")} WHERE id = $${paramIndex}`,
9037
- values
9038
- );
9039
- }
8991
+ await this.#db.client.none(`UPDATE ${tableName} SET ${setClauses.join(", ")} WHERE id = $${paramIndex}`, values);
9040
8992
  const updatedBlock = await this.getById(id);
9041
8993
  if (!updatedBlock) {
9042
8994
  throw new MastraError({
@@ -9080,7 +9032,7 @@ var PromptBlocksPG = class _PromptBlocksPG extends PromptBlocksStorage {
9080
9032
  }
9081
9033
  }
9082
9034
  async list(args) {
9083
- const { page = 0, perPage: perPageInput, orderBy, authorId, metadata } = args || {};
9035
+ const { page = 0, perPage: perPageInput, orderBy, authorId, metadata, status = "published" } = args || {};
9084
9036
  const { field, direction } = this.parseOrderBy(orderBy);
9085
9037
  if (page < 0) {
9086
9038
  throw new MastraError(
@@ -9100,6 +9052,8 @@ var PromptBlocksPG = class _PromptBlocksPG extends PromptBlocksStorage {
9100
9052
  const conditions = [];
9101
9053
  const queryParams = [];
9102
9054
  let paramIdx = 1;
9055
+ conditions.push(`status = $${paramIdx++}`);
9056
+ queryParams.push(status);
9103
9057
  if (authorId !== void 0) {
9104
9058
  conditions.push(`"authorId" = $${paramIdx++}`);
9105
9059
  queryParams.push(authorId);
@@ -9108,7 +9062,7 @@ var PromptBlocksPG = class _PromptBlocksPG extends PromptBlocksStorage {
9108
9062
  conditions.push(`metadata @> $${paramIdx++}::jsonb`);
9109
9063
  queryParams.push(JSON.stringify(metadata));
9110
9064
  }
9111
- const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
9065
+ const whereClause = `WHERE ${conditions.join(" AND ")}`;
9112
9066
  const countResult = await this.#db.client.one(
9113
9067
  `SELECT COUNT(*) as count FROM ${tableName} ${whereClause}`,
9114
9068
  queryParams
@@ -9661,46 +9615,7 @@ var ScorerDefinitionsPG = class _ScorerDefinitionsPG extends ScorerDefinitionsSt
9661
9615
  details: { scorerDefinitionId: id }
9662
9616
  });
9663
9617
  }
9664
- const { authorId, activeVersionId, metadata, status, ...configFields } = updates;
9665
- let versionCreated = false;
9666
- const hasConfigUpdate = SNAPSHOT_FIELDS3.some((field) => field in configFields);
9667
- if (hasConfigUpdate) {
9668
- const latestVersion = await this.getLatestVersion(id);
9669
- if (!latestVersion) {
9670
- throw new MastraError({
9671
- id: createStorageErrorId("PG", "UPDATE_SCORER_DEFINITION", "NO_VERSIONS"),
9672
- domain: ErrorDomain.STORAGE,
9673
- category: ErrorCategory.SYSTEM,
9674
- text: `No versions found for scorer definition ${id}`,
9675
- details: { scorerDefinitionId: id }
9676
- });
9677
- }
9678
- const {
9679
- id: _versionId,
9680
- scorerDefinitionId: _scorerDefinitionId,
9681
- versionNumber: _versionNumber,
9682
- changedFields: _changedFields,
9683
- changeMessage: _changeMessage,
9684
- createdAt: _createdAt,
9685
- ...latestConfig
9686
- } = latestVersion;
9687
- const newConfig = { ...latestConfig, ...configFields };
9688
- const changedFields = SNAPSHOT_FIELDS3.filter(
9689
- (field) => field in configFields && JSON.stringify(configFields[field]) !== JSON.stringify(latestConfig[field])
9690
- );
9691
- if (changedFields.length > 0) {
9692
- versionCreated = true;
9693
- const newVersionId = crypto.randomUUID();
9694
- await this.createVersion({
9695
- id: newVersionId,
9696
- scorerDefinitionId: id,
9697
- versionNumber: latestVersion.versionNumber + 1,
9698
- ...newConfig,
9699
- changedFields: [...changedFields],
9700
- changeMessage: `Updated ${changedFields.join(", ")}`
9701
- });
9702
- }
9703
- }
9618
+ const { authorId, activeVersionId, metadata, status } = updates;
9704
9619
  const setClauses = [];
9705
9620
  const values = [];
9706
9621
  let paramIndex = 1;
@@ -9711,10 +9626,6 @@ var ScorerDefinitionsPG = class _ScorerDefinitionsPG extends ScorerDefinitionsSt
9711
9626
  if (activeVersionId !== void 0) {
9712
9627
  setClauses.push(`"activeVersionId" = $${paramIndex++}`);
9713
9628
  values.push(activeVersionId);
9714
- if (status === void 0) {
9715
- setClauses.push(`status = $${paramIndex++}`);
9716
- values.push("published");
9717
- }
9718
9629
  }
9719
9630
  if (status !== void 0) {
9720
9631
  setClauses.push(`status = $${paramIndex++}`);
@@ -9731,12 +9642,7 @@ var ScorerDefinitionsPG = class _ScorerDefinitionsPG extends ScorerDefinitionsSt
9731
9642
  setClauses.push(`"updatedAtZ" = $${paramIndex++}`);
9732
9643
  values.push(now);
9733
9644
  values.push(id);
9734
- if (setClauses.length > 2 || versionCreated) {
9735
- await this.#db.client.none(
9736
- `UPDATE ${tableName} SET ${setClauses.join(", ")} WHERE id = $${paramIndex}`,
9737
- values
9738
- );
9739
- }
9645
+ await this.#db.client.none(`UPDATE ${tableName} SET ${setClauses.join(", ")} WHERE id = $${paramIndex}`, values);
9740
9646
  const updatedScorer = await this.getById(id);
9741
9647
  if (!updatedScorer) {
9742
9648
  throw new MastraError({
@@ -9780,7 +9686,7 @@ var ScorerDefinitionsPG = class _ScorerDefinitionsPG extends ScorerDefinitionsSt
9780
9686
  }
9781
9687
  }
9782
9688
  async list(args) {
9783
- const { page = 0, perPage: perPageInput, orderBy, authorId, metadata } = args || {};
9689
+ const { page = 0, perPage: perPageInput, orderBy, authorId, metadata, status } = args || {};
9784
9690
  const { field, direction } = this.parseOrderBy(orderBy);
9785
9691
  if (page < 0) {
9786
9692
  throw new MastraError(
@@ -9800,6 +9706,10 @@ var ScorerDefinitionsPG = class _ScorerDefinitionsPG extends ScorerDefinitionsSt
9800
9706
  const conditions = [];
9801
9707
  const queryParams = [];
9802
9708
  let paramIdx = 1;
9709
+ if (status) {
9710
+ conditions.push(`status = $${paramIdx++}`);
9711
+ queryParams.push(status);
9712
+ }
9803
9713
  if (authorId !== void 0) {
9804
9714
  conditions.push(`"authorId" = $${paramIdx++}`);
9805
9715
  queryParams.push(authorId);
@@ -10571,94 +10481,66 @@ var ScoresPG = class _ScoresPG extends ScoresStorage {
10571
10481
  }
10572
10482
  }
10573
10483
  };
10574
- function getSchemaName5(schema) {
10575
- return schema ? `"${schema}"` : '"public"';
10576
- }
10577
- function getTableName5({ indexName, schemaName }) {
10578
- const quotedIndexName = `"${indexName}"`;
10579
- return schemaName ? `${schemaName}.${quotedIndexName}` : quotedIndexName;
10580
- }
10581
- function sanitizeJsonForPg(jsonString) {
10582
- return jsonString.replace(/\\u(0000|[Dd][89A-Fa-f][0-9A-Fa-f]{2})/g, "");
10583
- }
10584
- var WorkflowsPG = class _WorkflowsPG extends WorkflowsStorage {
10484
+ var SNAPSHOT_FIELDS4 = [
10485
+ "name",
10486
+ "description",
10487
+ "instructions",
10488
+ "license",
10489
+ "compatibility",
10490
+ "source",
10491
+ "references",
10492
+ "scripts",
10493
+ "assets",
10494
+ "metadata",
10495
+ "tree"
10496
+ ];
10497
+ var SkillsPG = class _SkillsPG extends SkillsStorage {
10585
10498
  #db;
10586
10499
  #schema;
10587
10500
  #skipDefaultIndexes;
10588
10501
  #indexes;
10589
- /** Tables managed by this domain */
10590
- static MANAGED_TABLES = [TABLE_WORKFLOW_SNAPSHOT];
10502
+ static MANAGED_TABLES = [TABLE_SKILLS, TABLE_SKILL_VERSIONS];
10591
10503
  constructor(config) {
10592
10504
  super();
10593
10505
  const { client, schemaName, skipDefaultIndexes, indexes } = resolvePgConfig(config);
10594
10506
  this.#db = new PgDB({ client, schemaName, skipDefaultIndexes });
10595
10507
  this.#schema = schemaName || "public";
10596
10508
  this.#skipDefaultIndexes = skipDefaultIndexes;
10597
- this.#indexes = indexes?.filter((idx) => _WorkflowsPG.MANAGED_TABLES.includes(idx.table));
10509
+ this.#indexes = indexes?.filter((idx) => _SkillsPG.MANAGED_TABLES.includes(idx.table));
10598
10510
  }
10599
- parseWorkflowRun(row) {
10600
- let parsedSnapshot = row.snapshot;
10601
- if (typeof parsedSnapshot === "string") {
10602
- try {
10603
- parsedSnapshot = JSON.parse(row.snapshot);
10604
- } catch (e) {
10605
- this.logger.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
10511
+ getDefaultIndexDefinitions() {
10512
+ return [
10513
+ {
10514
+ name: "idx_skill_versions_skill_version",
10515
+ table: TABLE_SKILL_VERSIONS,
10516
+ columns: ["skillId", "versionNumber"],
10517
+ unique: true
10606
10518
  }
10607
- }
10608
- return {
10609
- workflowName: row.workflow_name,
10610
- runId: row.run_id,
10611
- snapshot: parsedSnapshot,
10612
- resourceId: row.resourceId,
10613
- createdAt: new Date(row.createdAtZ || row.createdAt),
10614
- updatedAt: new Date(row.updatedAtZ || row.updatedAt)
10615
- };
10616
- }
10617
- /**
10618
- * Returns all DDL statements for this domain: table with unique constraint.
10619
- * Used by exportSchemas to produce a complete, reproducible schema export.
10620
- */
10621
- static getExportDDL(schemaName) {
10622
- const statements = [];
10623
- statements.push(
10624
- generateTableSQL({
10625
- tableName: TABLE_WORKFLOW_SNAPSHOT,
10626
- schema: TABLE_SCHEMAS[TABLE_WORKFLOW_SNAPSHOT],
10627
- schemaName,
10628
- includeAllConstraints: true
10629
- })
10630
- );
10631
- return statements;
10632
- }
10633
- /**
10634
- * Returns default index definitions for the workflows domain tables.
10635
- * Currently no default indexes are defined for workflows.
10636
- */
10637
- getDefaultIndexDefinitions() {
10638
- return [];
10519
+ ];
10639
10520
  }
10640
- /**
10641
- * Creates default indexes for optimal query performance.
10642
- * Currently no default indexes are defined for workflows.
10643
- */
10644
10521
  async createDefaultIndexes() {
10645
10522
  if (this.#skipDefaultIndexes) {
10646
10523
  return;
10647
10524
  }
10525
+ for (const indexDef of this.getDefaultIndexDefinitions()) {
10526
+ try {
10527
+ await this.#db.createIndex(indexDef);
10528
+ } catch {
10529
+ }
10530
+ }
10648
10531
  }
10649
10532
  async init() {
10650
- await this.#db.createTable({ tableName: TABLE_WORKFLOW_SNAPSHOT, schema: TABLE_SCHEMAS[TABLE_WORKFLOW_SNAPSHOT] });
10651
- await this.#db.alterTable({
10652
- tableName: TABLE_WORKFLOW_SNAPSHOT,
10653
- schema: TABLE_SCHEMAS[TABLE_WORKFLOW_SNAPSHOT],
10654
- ifNotExists: ["resourceId"]
10533
+ await this.#db.createTable({
10534
+ tableName: TABLE_SKILLS,
10535
+ schema: TABLE_SCHEMAS[TABLE_SKILLS]
10536
+ });
10537
+ await this.#db.createTable({
10538
+ tableName: TABLE_SKILL_VERSIONS,
10539
+ schema: TABLE_SCHEMAS[TABLE_SKILL_VERSIONS]
10655
10540
  });
10656
10541
  await this.createDefaultIndexes();
10657
10542
  await this.createCustomIndexes();
10658
10543
  }
10659
- /**
10660
- * Creates custom user-defined indexes for this domain's tables.
10661
- */
10662
10544
  async createCustomIndexes() {
10663
10545
  if (!this.#indexes || this.#indexes.length === 0) {
10664
10546
  return;
@@ -10672,225 +10554,1602 @@ var WorkflowsPG = class _WorkflowsPG extends WorkflowsStorage {
10672
10554
  }
10673
10555
  }
10674
10556
  async dangerouslyClearAll() {
10675
- await this.#db.clearTable({ tableName: TABLE_WORKFLOW_SNAPSHOT });
10676
- }
10677
- updateWorkflowResults({
10678
- // workflowName,
10679
- // runId,
10680
- // stepId,
10681
- // result,
10682
- // requestContext,
10683
- }) {
10684
- throw new Error("Method not implemented.");
10685
- }
10686
- updateWorkflowState({
10687
- // workflowName,
10688
- // runId,
10689
- // opts,
10690
- }) {
10691
- throw new Error("Method not implemented.");
10557
+ await this.#db.clearTable({ tableName: TABLE_SKILL_VERSIONS });
10558
+ await this.#db.clearTable({ tableName: TABLE_SKILLS });
10692
10559
  }
10693
- async persistWorkflowSnapshot({
10694
- workflowName,
10695
- runId,
10696
- resourceId,
10697
- snapshot,
10698
- createdAt,
10699
- updatedAt
10700
- }) {
10560
+ // ==========================================================================
10561
+ // Skill CRUD Methods
10562
+ // ==========================================================================
10563
+ async getById(id) {
10701
10564
  try {
10702
- const now = /* @__PURE__ */ new Date();
10703
- const createdAtValue = createdAt ? createdAt : now;
10704
- const updatedAtValue = updatedAt ? updatedAt : now;
10705
- const sanitizedSnapshot = sanitizeJsonForPg(JSON.stringify(snapshot));
10706
- await this.#db.client.none(
10707
- `INSERT INTO ${getTableName5({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName5(this.#schema) })} (workflow_name, run_id, "resourceId", snapshot, "createdAt", "updatedAt")
10708
- VALUES ($1, $2, $3, $4, $5, $6)
10709
- ON CONFLICT (workflow_name, run_id) DO UPDATE
10710
- SET "resourceId" = $3, snapshot = $4, "updatedAt" = $6`,
10711
- [workflowName, runId, resourceId, sanitizedSnapshot, createdAtValue, updatedAtValue]
10712
- );
10565
+ const tableName = getTableName2({ indexName: TABLE_SKILLS, schemaName: getSchemaName2(this.#schema) });
10566
+ const result = await this.#db.client.oneOrNone(`SELECT * FROM ${tableName} WHERE id = $1`, [id]);
10567
+ if (!result) {
10568
+ return null;
10569
+ }
10570
+ return this.parseSkillRow(result);
10713
10571
  } catch (error) {
10572
+ if (error instanceof MastraError) throw error;
10714
10573
  throw new MastraError(
10715
10574
  {
10716
- id: createStorageErrorId("PG", "PERSIST_WORKFLOW_SNAPSHOT", "FAILED"),
10575
+ id: createStorageErrorId("PG", "GET_SKILL_BY_ID", "FAILED"),
10717
10576
  domain: ErrorDomain.STORAGE,
10718
- category: ErrorCategory.THIRD_PARTY
10577
+ category: ErrorCategory.THIRD_PARTY,
10578
+ details: { skillId: id }
10719
10579
  },
10720
10580
  error
10721
10581
  );
10722
10582
  }
10723
10583
  }
10724
- async loadWorkflowSnapshot({
10725
- workflowName,
10726
- runId
10727
- }) {
10584
+ async create(input) {
10585
+ const { skill } = input;
10728
10586
  try {
10729
- const result = await this.#db.load({
10730
- tableName: TABLE_WORKFLOW_SNAPSHOT,
10731
- keys: { workflow_name: workflowName, run_id: runId }
10587
+ const tableName = getTableName2({ indexName: TABLE_SKILLS, schemaName: getSchemaName2(this.#schema) });
10588
+ const now = /* @__PURE__ */ new Date();
10589
+ const nowIso = now.toISOString();
10590
+ await this.#db.client.none(
10591
+ `INSERT INTO ${tableName} (
10592
+ id, status, "activeVersionId", "authorId",
10593
+ "createdAt", "createdAtZ", "updatedAt", "updatedAtZ"
10594
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,
10595
+ [skill.id, "draft", null, skill.authorId ?? null, nowIso, nowIso, nowIso, nowIso]
10596
+ );
10597
+ const { id: _id, authorId: _authorId, ...snapshotConfig } = skill;
10598
+ const versionId = crypto.randomUUID();
10599
+ await this.createVersion({
10600
+ id: versionId,
10601
+ skillId: skill.id,
10602
+ versionNumber: 1,
10603
+ ...snapshotConfig,
10604
+ changedFields: [...SNAPSHOT_FIELDS4],
10605
+ changeMessage: "Initial version"
10732
10606
  });
10733
- return result ? result.snapshot : null;
10607
+ return {
10608
+ id: skill.id,
10609
+ status: "draft",
10610
+ activeVersionId: void 0,
10611
+ authorId: skill.authorId,
10612
+ createdAt: now,
10613
+ updatedAt: now
10614
+ };
10734
10615
  } catch (error) {
10616
+ try {
10617
+ const tableName = getTableName2({
10618
+ indexName: TABLE_SKILLS,
10619
+ schemaName: getSchemaName2(this.#schema)
10620
+ });
10621
+ await this.#db.client.none(
10622
+ `DELETE FROM ${tableName} WHERE id = $1 AND status = 'draft' AND "activeVersionId" IS NULL`,
10623
+ [skill.id]
10624
+ );
10625
+ } catch {
10626
+ }
10627
+ if (error instanceof MastraError) throw error;
10735
10628
  throw new MastraError(
10736
10629
  {
10737
- id: createStorageErrorId("PG", "LOAD_WORKFLOW_SNAPSHOT", "FAILED"),
10630
+ id: createStorageErrorId("PG", "CREATE_SKILL", "FAILED"),
10738
10631
  domain: ErrorDomain.STORAGE,
10739
- category: ErrorCategory.THIRD_PARTY
10632
+ category: ErrorCategory.THIRD_PARTY,
10633
+ details: { skillId: skill.id }
10740
10634
  },
10741
10635
  error
10742
10636
  );
10743
10637
  }
10744
10638
  }
10745
- async getWorkflowRunById({
10746
- runId,
10747
- workflowName
10748
- }) {
10639
+ async update(input) {
10640
+ const { id, ...updates } = input;
10749
10641
  try {
10750
- const conditions = [];
10642
+ const tableName = getTableName2({ indexName: TABLE_SKILLS, schemaName: getSchemaName2(this.#schema) });
10643
+ const existingSkill = await this.getById(id);
10644
+ if (!existingSkill) {
10645
+ throw new MastraError({
10646
+ id: createStorageErrorId("PG", "UPDATE_SKILL", "NOT_FOUND"),
10647
+ domain: ErrorDomain.STORAGE,
10648
+ category: ErrorCategory.USER,
10649
+ text: `Skill ${id} not found`,
10650
+ details: { skillId: id }
10651
+ });
10652
+ }
10653
+ const { authorId, activeVersionId, status, ...configFields } = updates;
10654
+ let versionCreated = false;
10655
+ const hasConfigUpdate = SNAPSHOT_FIELDS4.some((field) => field in configFields);
10656
+ if (hasConfigUpdate) {
10657
+ const latestVersion = await this.getLatestVersion(id);
10658
+ if (!latestVersion) {
10659
+ throw new MastraError({
10660
+ id: createStorageErrorId("PG", "UPDATE_SKILL", "NO_VERSIONS"),
10661
+ domain: ErrorDomain.STORAGE,
10662
+ category: ErrorCategory.SYSTEM,
10663
+ text: `No versions found for skill ${id}`,
10664
+ details: { skillId: id }
10665
+ });
10666
+ }
10667
+ const {
10668
+ id: _versionId,
10669
+ skillId: _skillId,
10670
+ versionNumber: _versionNumber,
10671
+ changedFields: _changedFields,
10672
+ changeMessage: _changeMessage,
10673
+ createdAt: _createdAt,
10674
+ ...latestConfig
10675
+ } = latestVersion;
10676
+ const newConfig = { ...latestConfig, ...configFields };
10677
+ const changedFields = SNAPSHOT_FIELDS4.filter(
10678
+ (field) => field in configFields && JSON.stringify(configFields[field]) !== JSON.stringify(latestConfig[field])
10679
+ );
10680
+ if (changedFields.length > 0) {
10681
+ versionCreated = true;
10682
+ const newVersionId = crypto.randomUUID();
10683
+ await this.createVersion({
10684
+ id: newVersionId,
10685
+ skillId: id,
10686
+ versionNumber: latestVersion.versionNumber + 1,
10687
+ ...newConfig,
10688
+ changedFields: [...changedFields],
10689
+ changeMessage: `Updated ${changedFields.join(", ")}`
10690
+ });
10691
+ }
10692
+ }
10693
+ const setClauses = [];
10751
10694
  const values = [];
10752
10695
  let paramIndex = 1;
10753
- if (runId) {
10754
- conditions.push(`run_id = $${paramIndex}`);
10755
- values.push(runId);
10756
- paramIndex++;
10696
+ if (authorId !== void 0) {
10697
+ setClauses.push(`"authorId" = $${paramIndex++}`);
10698
+ values.push(authorId);
10757
10699
  }
10758
- if (workflowName) {
10759
- conditions.push(`workflow_name = $${paramIndex}`);
10760
- values.push(workflowName);
10761
- paramIndex++;
10700
+ if (activeVersionId !== void 0) {
10701
+ setClauses.push(`"activeVersionId" = $${paramIndex++}`);
10702
+ values.push(activeVersionId);
10703
+ if (status === void 0) {
10704
+ setClauses.push(`status = $${paramIndex++}`);
10705
+ values.push("published");
10706
+ }
10762
10707
  }
10763
- const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
10764
- const query = `
10765
- SELECT * FROM ${getTableName5({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName5(this.#schema) })}
10766
- ${whereClause}
10767
- ORDER BY "createdAt" DESC LIMIT 1
10768
- `;
10769
- const queryValues = values;
10770
- const result = await this.#db.client.oneOrNone(query, queryValues);
10771
- if (!result) {
10772
- return null;
10708
+ if (status !== void 0) {
10709
+ setClauses.push(`status = $${paramIndex++}`);
10710
+ values.push(status);
10773
10711
  }
10774
- return this.parseWorkflowRun(result);
10712
+ const now = (/* @__PURE__ */ new Date()).toISOString();
10713
+ setClauses.push(`"updatedAt" = $${paramIndex++}`);
10714
+ values.push(now);
10715
+ setClauses.push(`"updatedAtZ" = $${paramIndex++}`);
10716
+ values.push(now);
10717
+ values.push(id);
10718
+ if (setClauses.length > 2 || versionCreated) {
10719
+ await this.#db.client.none(
10720
+ `UPDATE ${tableName} SET ${setClauses.join(", ")} WHERE id = $${paramIndex}`,
10721
+ values
10722
+ );
10723
+ }
10724
+ const updatedSkill = await this.getById(id);
10725
+ if (!updatedSkill) {
10726
+ throw new MastraError({
10727
+ id: createStorageErrorId("PG", "UPDATE_SKILL", "NOT_FOUND_AFTER_UPDATE"),
10728
+ domain: ErrorDomain.STORAGE,
10729
+ category: ErrorCategory.SYSTEM,
10730
+ text: `Skill ${id} not found after update`,
10731
+ details: { skillId: id }
10732
+ });
10733
+ }
10734
+ return updatedSkill;
10775
10735
  } catch (error) {
10736
+ if (error instanceof MastraError) throw error;
10776
10737
  throw new MastraError(
10777
10738
  {
10778
- id: createStorageErrorId("PG", "GET_WORKFLOW_RUN_BY_ID", "FAILED"),
10739
+ id: createStorageErrorId("PG", "UPDATE_SKILL", "FAILED"),
10779
10740
  domain: ErrorDomain.STORAGE,
10780
10741
  category: ErrorCategory.THIRD_PARTY,
10781
- details: {
10782
- runId,
10783
- workflowName: workflowName || ""
10784
- }
10742
+ details: { skillId: id }
10785
10743
  },
10786
10744
  error
10787
10745
  );
10788
10746
  }
10789
10747
  }
10790
- async deleteWorkflowRunById({ runId, workflowName }) {
10748
+ async delete(id) {
10791
10749
  try {
10792
- await this.#db.client.none(
10793
- `DELETE FROM ${getTableName5({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName5(this.#schema) })} WHERE run_id = $1 AND workflow_name = $2`,
10794
- [runId, workflowName]
10795
- );
10750
+ const tableName = getTableName2({ indexName: TABLE_SKILLS, schemaName: getSchemaName2(this.#schema) });
10751
+ await this.deleteVersionsByParentId(id);
10752
+ await this.#db.client.none(`DELETE FROM ${tableName} WHERE id = $1`, [id]);
10796
10753
  } catch (error) {
10754
+ if (error instanceof MastraError) throw error;
10797
10755
  throw new MastraError(
10798
10756
  {
10799
- id: createStorageErrorId("PG", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
10757
+ id: createStorageErrorId("PG", "DELETE_SKILL", "FAILED"),
10800
10758
  domain: ErrorDomain.STORAGE,
10801
10759
  category: ErrorCategory.THIRD_PARTY,
10802
- details: {
10803
- runId,
10804
- workflowName
10805
- }
10760
+ details: { skillId: id }
10806
10761
  },
10807
10762
  error
10808
10763
  );
10809
10764
  }
10810
10765
  }
10811
- async listWorkflowRuns({
10812
- workflowName,
10813
- fromDate,
10814
- toDate,
10815
- perPage,
10816
- page,
10817
- resourceId,
10818
- status
10819
- } = {}) {
10766
+ async list(args) {
10767
+ const { page = 0, perPage: perPageInput, orderBy, authorId } = args || {};
10768
+ const { field, direction } = this.parseOrderBy(orderBy);
10769
+ if (page < 0) {
10770
+ throw new MastraError(
10771
+ {
10772
+ id: createStorageErrorId("PG", "LIST_SKILLS", "INVALID_PAGE"),
10773
+ domain: ErrorDomain.STORAGE,
10774
+ category: ErrorCategory.USER,
10775
+ details: { page }
10776
+ },
10777
+ new Error("page must be >= 0")
10778
+ );
10779
+ }
10780
+ const perPage = normalizePerPage(perPageInput, 100);
10781
+ const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
10820
10782
  try {
10783
+ const tableName = getTableName2({ indexName: TABLE_SKILLS, schemaName: getSchemaName2(this.#schema) });
10821
10784
  const conditions = [];
10822
- const values = [];
10823
- let paramIndex = 1;
10824
- if (workflowName) {
10825
- conditions.push(`workflow_name = $${paramIndex}`);
10826
- values.push(workflowName);
10827
- paramIndex++;
10828
- }
10829
- if (status) {
10830
- conditions.push(
10831
- `regexp_replace(snapshot::text, '\\\\u(0000|[Dd][89A-Fa-f][0-9A-Fa-f]{2})', '', 'g')::jsonb ->> 'status' = $${paramIndex}`
10832
- );
10833
- values.push(status);
10834
- paramIndex++;
10835
- }
10836
- if (resourceId) {
10837
- const hasResourceId = await this.#db.hasColumn(TABLE_WORKFLOW_SNAPSHOT, "resourceId");
10838
- if (hasResourceId) {
10839
- conditions.push(`"resourceId" = $${paramIndex}`);
10840
- values.push(resourceId);
10841
- paramIndex++;
10842
- } else {
10843
- this.logger?.warn?.(`[${TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
10844
- }
10785
+ const queryParams = [];
10786
+ let paramIdx = 1;
10787
+ if (authorId !== void 0) {
10788
+ conditions.push(`"authorId" = $${paramIdx++}`);
10789
+ queryParams.push(authorId);
10845
10790
  }
10846
- if (fromDate) {
10847
- conditions.push(`"createdAt" >= $${paramIndex}`);
10848
- values.push(fromDate);
10849
- paramIndex++;
10791
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
10792
+ const countResult = await this.#db.client.one(
10793
+ `SELECT COUNT(*) as count FROM ${tableName} ${whereClause}`,
10794
+ queryParams
10795
+ );
10796
+ const total = parseInt(countResult.count, 10);
10797
+ if (total === 0) {
10798
+ return {
10799
+ skills: [],
10800
+ total: 0,
10801
+ page,
10802
+ perPage: perPageForResponse,
10803
+ hasMore: false
10804
+ };
10850
10805
  }
10851
- if (toDate) {
10852
- conditions.push(`"createdAt" <= $${paramIndex}`);
10853
- values.push(toDate);
10854
- paramIndex++;
10806
+ const limitValue = perPageInput === false ? total : perPage;
10807
+ const dataResult = await this.#db.client.manyOrNone(
10808
+ `SELECT * FROM ${tableName} ${whereClause} ORDER BY "${field}" ${direction} LIMIT $${paramIdx++} OFFSET $${paramIdx++}`,
10809
+ [...queryParams, limitValue, offset]
10810
+ );
10811
+ const skills = (dataResult || []).map((row) => this.parseSkillRow(row));
10812
+ return {
10813
+ skills,
10814
+ total,
10815
+ page,
10816
+ perPage: perPageForResponse,
10817
+ hasMore: perPageInput === false ? false : offset + perPage < total
10818
+ };
10819
+ } catch (error) {
10820
+ if (error instanceof MastraError) throw error;
10821
+ throw new MastraError(
10822
+ {
10823
+ id: createStorageErrorId("PG", "LIST_SKILLS", "FAILED"),
10824
+ domain: ErrorDomain.STORAGE,
10825
+ category: ErrorCategory.THIRD_PARTY
10826
+ },
10827
+ error
10828
+ );
10829
+ }
10830
+ }
10831
+ // ==========================================================================
10832
+ // Skill Version Methods
10833
+ // ==========================================================================
10834
+ async createVersion(input) {
10835
+ try {
10836
+ const tableName = getTableName2({
10837
+ indexName: TABLE_SKILL_VERSIONS,
10838
+ schemaName: getSchemaName2(this.#schema)
10839
+ });
10840
+ const now = /* @__PURE__ */ new Date();
10841
+ const nowIso = now.toISOString();
10842
+ await this.#db.client.none(
10843
+ `INSERT INTO ${tableName} (
10844
+ id, "skillId", "versionNumber",
10845
+ name, description, instructions, license, compatibility,
10846
+ source, "references", scripts, assets, metadata, tree,
10847
+ "changedFields", "changeMessage",
10848
+ "createdAt", "createdAtZ"
10849
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)`,
10850
+ [
10851
+ input.id,
10852
+ input.skillId,
10853
+ input.versionNumber,
10854
+ input.name,
10855
+ input.description ?? null,
10856
+ input.instructions ?? null,
10857
+ input.license ?? null,
10858
+ input.compatibility ? JSON.stringify(input.compatibility) : null,
10859
+ input.source ? JSON.stringify(input.source) : null,
10860
+ input.references ? JSON.stringify(input.references) : null,
10861
+ input.scripts ? JSON.stringify(input.scripts) : null,
10862
+ input.assets ? JSON.stringify(input.assets) : null,
10863
+ input.metadata ? JSON.stringify(input.metadata) : null,
10864
+ input.tree ? JSON.stringify(input.tree) : null,
10865
+ input.changedFields ? JSON.stringify(input.changedFields) : null,
10866
+ input.changeMessage ?? null,
10867
+ nowIso,
10868
+ nowIso
10869
+ ]
10870
+ );
10871
+ return {
10872
+ ...input,
10873
+ createdAt: now
10874
+ };
10875
+ } catch (error) {
10876
+ if (error instanceof MastraError) throw error;
10877
+ throw new MastraError(
10878
+ {
10879
+ id: createStorageErrorId("PG", "CREATE_SKILL_VERSION", "FAILED"),
10880
+ domain: ErrorDomain.STORAGE,
10881
+ category: ErrorCategory.THIRD_PARTY,
10882
+ details: { versionId: input.id, skillId: input.skillId }
10883
+ },
10884
+ error
10885
+ );
10886
+ }
10887
+ }
10888
+ async getVersion(id) {
10889
+ try {
10890
+ const tableName = getTableName2({
10891
+ indexName: TABLE_SKILL_VERSIONS,
10892
+ schemaName: getSchemaName2(this.#schema)
10893
+ });
10894
+ const result = await this.#db.client.oneOrNone(`SELECT * FROM ${tableName} WHERE id = $1`, [id]);
10895
+ if (!result) {
10896
+ return null;
10855
10897
  }
10856
- const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
10857
- let total = 0;
10858
- const usePagination = typeof perPage === "number" && typeof page === "number";
10859
- if (usePagination) {
10860
- const countResult = await this.#db.client.one(
10861
- `SELECT COUNT(*) as count FROM ${getTableName5({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName5(this.#schema) })} ${whereClause}`,
10862
- values
10863
- );
10864
- total = Number(countResult.count);
10898
+ return this.parseVersionRow(result);
10899
+ } catch (error) {
10900
+ if (error instanceof MastraError) throw error;
10901
+ throw new MastraError(
10902
+ {
10903
+ id: createStorageErrorId("PG", "GET_SKILL_VERSION", "FAILED"),
10904
+ domain: ErrorDomain.STORAGE,
10905
+ category: ErrorCategory.THIRD_PARTY,
10906
+ details: { versionId: id }
10907
+ },
10908
+ error
10909
+ );
10910
+ }
10911
+ }
10912
+ async getVersionByNumber(skillId, versionNumber) {
10913
+ try {
10914
+ const tableName = getTableName2({
10915
+ indexName: TABLE_SKILL_VERSIONS,
10916
+ schemaName: getSchemaName2(this.#schema)
10917
+ });
10918
+ const result = await this.#db.client.oneOrNone(
10919
+ `SELECT * FROM ${tableName} WHERE "skillId" = $1 AND "versionNumber" = $2`,
10920
+ [skillId, versionNumber]
10921
+ );
10922
+ if (!result) {
10923
+ return null;
10865
10924
  }
10866
- const normalizedPerPage = usePagination ? normalizePerPage(perPage, Number.MAX_SAFE_INTEGER) : 0;
10867
- const offset = usePagination ? page * normalizedPerPage : void 0;
10868
- const query = `
10869
- SELECT * FROM ${getTableName5({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName5(this.#schema) })}
10870
- ${whereClause}
10871
- ORDER BY "createdAt" DESC
10872
- ${usePagination ? ` LIMIT $${paramIndex} OFFSET $${paramIndex + 1}` : ""}
10873
- `;
10874
- const queryValues = usePagination ? [...values, normalizedPerPage, offset] : values;
10875
- const result = await this.#db.client.manyOrNone(query, queryValues);
10876
- const runs = (result || []).map((row) => {
10877
- return this.parseWorkflowRun(row);
10925
+ return this.parseVersionRow(result);
10926
+ } catch (error) {
10927
+ if (error instanceof MastraError) throw error;
10928
+ throw new MastraError(
10929
+ {
10930
+ id: createStorageErrorId("PG", "GET_SKILL_VERSION_BY_NUMBER", "FAILED"),
10931
+ domain: ErrorDomain.STORAGE,
10932
+ category: ErrorCategory.THIRD_PARTY,
10933
+ details: { skillId, versionNumber }
10934
+ },
10935
+ error
10936
+ );
10937
+ }
10938
+ }
10939
+ async getLatestVersion(skillId) {
10940
+ try {
10941
+ const tableName = getTableName2({
10942
+ indexName: TABLE_SKILL_VERSIONS,
10943
+ schemaName: getSchemaName2(this.#schema)
10878
10944
  });
10879
- return { runs, total: total || runs.length };
10945
+ const result = await this.#db.client.oneOrNone(
10946
+ `SELECT * FROM ${tableName} WHERE "skillId" = $1 ORDER BY "versionNumber" DESC LIMIT 1`,
10947
+ [skillId]
10948
+ );
10949
+ if (!result) {
10950
+ return null;
10951
+ }
10952
+ return this.parseVersionRow(result);
10880
10953
  } catch (error) {
10954
+ if (error instanceof MastraError) throw error;
10881
10955
  throw new MastraError(
10882
10956
  {
10883
- id: createStorageErrorId("PG", "LIST_WORKFLOW_RUNS", "FAILED"),
10957
+ id: createStorageErrorId("PG", "GET_LATEST_SKILL_VERSION", "FAILED"),
10884
10958
  domain: ErrorDomain.STORAGE,
10885
10959
  category: ErrorCategory.THIRD_PARTY,
10886
- details: {
10887
- workflowName: workflowName || "all"
10888
- }
10960
+ details: { skillId }
10889
10961
  },
10890
10962
  error
10891
10963
  );
10892
10964
  }
10893
10965
  }
10966
+ async listVersions(input) {
10967
+ const { skillId, page = 0, perPage: perPageInput, orderBy } = input;
10968
+ if (page < 0) {
10969
+ throw new MastraError(
10970
+ {
10971
+ id: createStorageErrorId("PG", "LIST_SKILL_VERSIONS", "INVALID_PAGE"),
10972
+ domain: ErrorDomain.STORAGE,
10973
+ category: ErrorCategory.USER,
10974
+ details: { page }
10975
+ },
10976
+ new Error("page must be >= 0")
10977
+ );
10978
+ }
10979
+ const perPage = normalizePerPage(perPageInput, 20);
10980
+ const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
10981
+ try {
10982
+ const { field, direction } = this.parseVersionOrderBy(orderBy);
10983
+ const tableName = getTableName2({
10984
+ indexName: TABLE_SKILL_VERSIONS,
10985
+ schemaName: getSchemaName2(this.#schema)
10986
+ });
10987
+ const countResult = await this.#db.client.one(`SELECT COUNT(*) as count FROM ${tableName} WHERE "skillId" = $1`, [
10988
+ skillId
10989
+ ]);
10990
+ const total = parseInt(countResult.count, 10);
10991
+ if (total === 0) {
10992
+ return {
10993
+ versions: [],
10994
+ total: 0,
10995
+ page,
10996
+ perPage: perPageForResponse,
10997
+ hasMore: false
10998
+ };
10999
+ }
11000
+ const limitValue = perPageInput === false ? total : perPage;
11001
+ const dataResult = await this.#db.client.manyOrNone(
11002
+ `SELECT * FROM ${tableName} WHERE "skillId" = $1 ORDER BY "${field}" ${direction} LIMIT $2 OFFSET $3`,
11003
+ [skillId, limitValue, offset]
11004
+ );
11005
+ const versions = (dataResult || []).map((row) => this.parseVersionRow(row));
11006
+ return {
11007
+ versions,
11008
+ total,
11009
+ page,
11010
+ perPage: perPageForResponse,
11011
+ hasMore: perPageInput === false ? false : offset + perPage < total
11012
+ };
11013
+ } catch (error) {
11014
+ if (error instanceof MastraError) throw error;
11015
+ throw new MastraError(
11016
+ {
11017
+ id: createStorageErrorId("PG", "LIST_SKILL_VERSIONS", "FAILED"),
11018
+ domain: ErrorDomain.STORAGE,
11019
+ category: ErrorCategory.THIRD_PARTY,
11020
+ details: { skillId }
11021
+ },
11022
+ error
11023
+ );
11024
+ }
11025
+ }
11026
+ async deleteVersion(id) {
11027
+ try {
11028
+ const tableName = getTableName2({
11029
+ indexName: TABLE_SKILL_VERSIONS,
11030
+ schemaName: getSchemaName2(this.#schema)
11031
+ });
11032
+ await this.#db.client.none(`DELETE FROM ${tableName} WHERE id = $1`, [id]);
11033
+ } catch (error) {
11034
+ if (error instanceof MastraError) throw error;
11035
+ throw new MastraError(
11036
+ {
11037
+ id: createStorageErrorId("PG", "DELETE_SKILL_VERSION", "FAILED"),
11038
+ domain: ErrorDomain.STORAGE,
11039
+ category: ErrorCategory.THIRD_PARTY,
11040
+ details: { versionId: id }
11041
+ },
11042
+ error
11043
+ );
11044
+ }
11045
+ }
11046
+ async deleteVersionsByParentId(entityId) {
11047
+ try {
11048
+ const tableName = getTableName2({
11049
+ indexName: TABLE_SKILL_VERSIONS,
11050
+ schemaName: getSchemaName2(this.#schema)
11051
+ });
11052
+ await this.#db.client.none(`DELETE FROM ${tableName} WHERE "skillId" = $1`, [entityId]);
11053
+ } catch (error) {
11054
+ if (error instanceof MastraError) throw error;
11055
+ throw new MastraError(
11056
+ {
11057
+ id: createStorageErrorId("PG", "DELETE_SKILL_VERSIONS_BY_SKILL_ID", "FAILED"),
11058
+ domain: ErrorDomain.STORAGE,
11059
+ category: ErrorCategory.THIRD_PARTY,
11060
+ details: { skillId: entityId }
11061
+ },
11062
+ error
11063
+ );
11064
+ }
11065
+ }
11066
+ async countVersions(skillId) {
11067
+ try {
11068
+ const tableName = getTableName2({
11069
+ indexName: TABLE_SKILL_VERSIONS,
11070
+ schemaName: getSchemaName2(this.#schema)
11071
+ });
11072
+ const result = await this.#db.client.one(`SELECT COUNT(*) as count FROM ${tableName} WHERE "skillId" = $1`, [
11073
+ skillId
11074
+ ]);
11075
+ return parseInt(result.count, 10);
11076
+ } catch (error) {
11077
+ if (error instanceof MastraError) throw error;
11078
+ throw new MastraError(
11079
+ {
11080
+ id: createStorageErrorId("PG", "COUNT_SKILL_VERSIONS", "FAILED"),
11081
+ domain: ErrorDomain.STORAGE,
11082
+ category: ErrorCategory.THIRD_PARTY,
11083
+ details: { skillId }
11084
+ },
11085
+ error
11086
+ );
11087
+ }
11088
+ }
11089
+ // ==========================================================================
11090
+ // Private Helper Methods
11091
+ // ==========================================================================
11092
+ parseJson(value, fieldName) {
11093
+ if (!value) return void 0;
11094
+ if (typeof value !== "string") return value;
11095
+ try {
11096
+ return JSON.parse(value);
11097
+ } catch (error) {
11098
+ if (error instanceof MastraError) throw error;
11099
+ const details = {
11100
+ value: value.length > 100 ? value.substring(0, 100) + "..." : value
11101
+ };
11102
+ if (fieldName) {
11103
+ details.field = fieldName;
11104
+ }
11105
+ throw new MastraError(
11106
+ {
11107
+ id: createStorageErrorId("PG", "PARSE_JSON", "INVALID_JSON"),
11108
+ domain: ErrorDomain.STORAGE,
11109
+ category: ErrorCategory.SYSTEM,
11110
+ text: `Failed to parse JSON${fieldName ? ` for field "${fieldName}"` : ""}: ${error instanceof Error ? error.message : "Unknown error"}`,
11111
+ details
11112
+ },
11113
+ error
11114
+ );
11115
+ }
11116
+ }
11117
+ parseSkillRow(row) {
11118
+ return {
11119
+ id: row.id,
11120
+ status: row.status,
11121
+ activeVersionId: row.activeVersionId,
11122
+ authorId: row.authorId,
11123
+ createdAt: new Date(row.createdAtZ || row.createdAt),
11124
+ updatedAt: new Date(row.updatedAtZ || row.updatedAt)
11125
+ };
11126
+ }
11127
+ parseVersionRow(row) {
11128
+ return {
11129
+ id: row.id,
11130
+ skillId: row.skillId,
11131
+ versionNumber: row.versionNumber,
11132
+ name: row.name,
11133
+ description: row.description,
11134
+ instructions: row.instructions,
11135
+ license: row.license,
11136
+ compatibility: this.parseJson(row.compatibility, "compatibility"),
11137
+ source: this.parseJson(row.source, "source"),
11138
+ references: this.parseJson(row.references, "references"),
11139
+ scripts: this.parseJson(row.scripts, "scripts"),
11140
+ assets: this.parseJson(row.assets, "assets"),
11141
+ metadata: this.parseJson(row.metadata, "metadata"),
11142
+ tree: this.parseJson(row.tree, "tree"),
11143
+ changedFields: this.parseJson(row.changedFields, "changedFields"),
11144
+ changeMessage: row.changeMessage,
11145
+ createdAt: new Date(row.createdAtZ || row.createdAt)
11146
+ };
11147
+ }
11148
+ };
11149
+ function getSchemaName5(schema) {
11150
+ return schema ? `"${schema}"` : '"public"';
11151
+ }
11152
+ function getTableName5({ indexName, schemaName }) {
11153
+ const quotedIndexName = `"${indexName}"`;
11154
+ return schemaName ? `${schemaName}.${quotedIndexName}` : quotedIndexName;
11155
+ }
11156
+ function sanitizeJsonForPg(jsonString) {
11157
+ return jsonString.replace(/\\u(0000|[Dd][89A-Fa-f][0-9A-Fa-f]{2})/g, "");
11158
+ }
11159
+ var WorkflowsPG = class _WorkflowsPG extends WorkflowsStorage {
11160
+ #db;
11161
+ #schema;
11162
+ #skipDefaultIndexes;
11163
+ #indexes;
11164
+ /** Tables managed by this domain */
11165
+ static MANAGED_TABLES = [TABLE_WORKFLOW_SNAPSHOT];
11166
+ constructor(config) {
11167
+ super();
11168
+ const { client, schemaName, skipDefaultIndexes, indexes } = resolvePgConfig(config);
11169
+ this.#db = new PgDB({ client, schemaName, skipDefaultIndexes });
11170
+ this.#schema = schemaName || "public";
11171
+ this.#skipDefaultIndexes = skipDefaultIndexes;
11172
+ this.#indexes = indexes?.filter((idx) => _WorkflowsPG.MANAGED_TABLES.includes(idx.table));
11173
+ }
11174
+ parseWorkflowRun(row) {
11175
+ let parsedSnapshot = row.snapshot;
11176
+ if (typeof parsedSnapshot === "string") {
11177
+ try {
11178
+ parsedSnapshot = JSON.parse(row.snapshot);
11179
+ } catch (e) {
11180
+ this.logger.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
11181
+ }
11182
+ }
11183
+ return {
11184
+ workflowName: row.workflow_name,
11185
+ runId: row.run_id,
11186
+ snapshot: parsedSnapshot,
11187
+ resourceId: row.resourceId,
11188
+ createdAt: new Date(row.createdAtZ || row.createdAt),
11189
+ updatedAt: new Date(row.updatedAtZ || row.updatedAt)
11190
+ };
11191
+ }
11192
+ /**
11193
+ * Returns all DDL statements for this domain: table with unique constraint.
11194
+ * Used by exportSchemas to produce a complete, reproducible schema export.
11195
+ */
11196
+ static getExportDDL(schemaName) {
11197
+ const statements = [];
11198
+ statements.push(
11199
+ generateTableSQL({
11200
+ tableName: TABLE_WORKFLOW_SNAPSHOT,
11201
+ schema: TABLE_SCHEMAS[TABLE_WORKFLOW_SNAPSHOT],
11202
+ schemaName,
11203
+ includeAllConstraints: true
11204
+ })
11205
+ );
11206
+ return statements;
11207
+ }
11208
+ /**
11209
+ * Returns default index definitions for the workflows domain tables.
11210
+ * Currently no default indexes are defined for workflows.
11211
+ */
11212
+ getDefaultIndexDefinitions() {
11213
+ return [];
11214
+ }
11215
+ /**
11216
+ * Creates default indexes for optimal query performance.
11217
+ * Currently no default indexes are defined for workflows.
11218
+ */
11219
+ async createDefaultIndexes() {
11220
+ if (this.#skipDefaultIndexes) {
11221
+ return;
11222
+ }
11223
+ }
11224
+ async init() {
11225
+ await this.#db.createTable({ tableName: TABLE_WORKFLOW_SNAPSHOT, schema: TABLE_SCHEMAS[TABLE_WORKFLOW_SNAPSHOT] });
11226
+ await this.#db.alterTable({
11227
+ tableName: TABLE_WORKFLOW_SNAPSHOT,
11228
+ schema: TABLE_SCHEMAS[TABLE_WORKFLOW_SNAPSHOT],
11229
+ ifNotExists: ["resourceId"]
11230
+ });
11231
+ await this.createDefaultIndexes();
11232
+ await this.createCustomIndexes();
11233
+ }
11234
+ /**
11235
+ * Creates custom user-defined indexes for this domain's tables.
11236
+ */
11237
+ async createCustomIndexes() {
11238
+ if (!this.#indexes || this.#indexes.length === 0) {
11239
+ return;
11240
+ }
11241
+ for (const indexDef of this.#indexes) {
11242
+ try {
11243
+ await this.#db.createIndex(indexDef);
11244
+ } catch (error) {
11245
+ this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
11246
+ }
11247
+ }
11248
+ }
11249
+ async dangerouslyClearAll() {
11250
+ await this.#db.clearTable({ tableName: TABLE_WORKFLOW_SNAPSHOT });
11251
+ }
11252
+ updateWorkflowResults({
11253
+ // workflowName,
11254
+ // runId,
11255
+ // stepId,
11256
+ // result,
11257
+ // requestContext,
11258
+ }) {
11259
+ throw new Error("Method not implemented.");
11260
+ }
11261
+ updateWorkflowState({
11262
+ // workflowName,
11263
+ // runId,
11264
+ // opts,
11265
+ }) {
11266
+ throw new Error("Method not implemented.");
11267
+ }
11268
+ async persistWorkflowSnapshot({
11269
+ workflowName,
11270
+ runId,
11271
+ resourceId,
11272
+ snapshot,
11273
+ createdAt,
11274
+ updatedAt
11275
+ }) {
11276
+ try {
11277
+ const now = /* @__PURE__ */ new Date();
11278
+ const createdAtValue = createdAt ? createdAt : now;
11279
+ const updatedAtValue = updatedAt ? updatedAt : now;
11280
+ const sanitizedSnapshot = sanitizeJsonForPg(JSON.stringify(snapshot));
11281
+ await this.#db.client.none(
11282
+ `INSERT INTO ${getTableName5({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName5(this.#schema) })} (workflow_name, run_id, "resourceId", snapshot, "createdAt", "updatedAt")
11283
+ VALUES ($1, $2, $3, $4, $5, $6)
11284
+ ON CONFLICT (workflow_name, run_id) DO UPDATE
11285
+ SET "resourceId" = $3, snapshot = $4, "updatedAt" = $6`,
11286
+ [workflowName, runId, resourceId, sanitizedSnapshot, createdAtValue, updatedAtValue]
11287
+ );
11288
+ } catch (error) {
11289
+ throw new MastraError(
11290
+ {
11291
+ id: createStorageErrorId("PG", "PERSIST_WORKFLOW_SNAPSHOT", "FAILED"),
11292
+ domain: ErrorDomain.STORAGE,
11293
+ category: ErrorCategory.THIRD_PARTY
11294
+ },
11295
+ error
11296
+ );
11297
+ }
11298
+ }
11299
+ async loadWorkflowSnapshot({
11300
+ workflowName,
11301
+ runId
11302
+ }) {
11303
+ try {
11304
+ const result = await this.#db.load({
11305
+ tableName: TABLE_WORKFLOW_SNAPSHOT,
11306
+ keys: { workflow_name: workflowName, run_id: runId }
11307
+ });
11308
+ return result ? result.snapshot : null;
11309
+ } catch (error) {
11310
+ throw new MastraError(
11311
+ {
11312
+ id: createStorageErrorId("PG", "LOAD_WORKFLOW_SNAPSHOT", "FAILED"),
11313
+ domain: ErrorDomain.STORAGE,
11314
+ category: ErrorCategory.THIRD_PARTY
11315
+ },
11316
+ error
11317
+ );
11318
+ }
11319
+ }
11320
+ async getWorkflowRunById({
11321
+ runId,
11322
+ workflowName
11323
+ }) {
11324
+ try {
11325
+ const conditions = [];
11326
+ const values = [];
11327
+ let paramIndex = 1;
11328
+ if (runId) {
11329
+ conditions.push(`run_id = $${paramIndex}`);
11330
+ values.push(runId);
11331
+ paramIndex++;
11332
+ }
11333
+ if (workflowName) {
11334
+ conditions.push(`workflow_name = $${paramIndex}`);
11335
+ values.push(workflowName);
11336
+ paramIndex++;
11337
+ }
11338
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
11339
+ const query = `
11340
+ SELECT * FROM ${getTableName5({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName5(this.#schema) })}
11341
+ ${whereClause}
11342
+ ORDER BY "createdAt" DESC LIMIT 1
11343
+ `;
11344
+ const queryValues = values;
11345
+ const result = await this.#db.client.oneOrNone(query, queryValues);
11346
+ if (!result) {
11347
+ return null;
11348
+ }
11349
+ return this.parseWorkflowRun(result);
11350
+ } catch (error) {
11351
+ throw new MastraError(
11352
+ {
11353
+ id: createStorageErrorId("PG", "GET_WORKFLOW_RUN_BY_ID", "FAILED"),
11354
+ domain: ErrorDomain.STORAGE,
11355
+ category: ErrorCategory.THIRD_PARTY,
11356
+ details: {
11357
+ runId,
11358
+ workflowName: workflowName || ""
11359
+ }
11360
+ },
11361
+ error
11362
+ );
11363
+ }
11364
+ }
11365
+ async deleteWorkflowRunById({ runId, workflowName }) {
11366
+ try {
11367
+ await this.#db.client.none(
11368
+ `DELETE FROM ${getTableName5({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName5(this.#schema) })} WHERE run_id = $1 AND workflow_name = $2`,
11369
+ [runId, workflowName]
11370
+ );
11371
+ } catch (error) {
11372
+ throw new MastraError(
11373
+ {
11374
+ id: createStorageErrorId("PG", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
11375
+ domain: ErrorDomain.STORAGE,
11376
+ category: ErrorCategory.THIRD_PARTY,
11377
+ details: {
11378
+ runId,
11379
+ workflowName
11380
+ }
11381
+ },
11382
+ error
11383
+ );
11384
+ }
11385
+ }
11386
+ async listWorkflowRuns({
11387
+ workflowName,
11388
+ fromDate,
11389
+ toDate,
11390
+ perPage,
11391
+ page,
11392
+ resourceId,
11393
+ status
11394
+ } = {}) {
11395
+ try {
11396
+ const conditions = [];
11397
+ const values = [];
11398
+ let paramIndex = 1;
11399
+ if (workflowName) {
11400
+ conditions.push(`workflow_name = $${paramIndex}`);
11401
+ values.push(workflowName);
11402
+ paramIndex++;
11403
+ }
11404
+ if (status) {
11405
+ conditions.push(
11406
+ `regexp_replace(snapshot::text, '\\\\u(0000|[Dd][89A-Fa-f][0-9A-Fa-f]{2})', '', 'g')::jsonb ->> 'status' = $${paramIndex}`
11407
+ );
11408
+ values.push(status);
11409
+ paramIndex++;
11410
+ }
11411
+ if (resourceId) {
11412
+ const hasResourceId = await this.#db.hasColumn(TABLE_WORKFLOW_SNAPSHOT, "resourceId");
11413
+ if (hasResourceId) {
11414
+ conditions.push(`"resourceId" = $${paramIndex}`);
11415
+ values.push(resourceId);
11416
+ paramIndex++;
11417
+ } else {
11418
+ this.logger?.warn?.(`[${TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
11419
+ }
11420
+ }
11421
+ if (fromDate) {
11422
+ conditions.push(`"createdAt" >= $${paramIndex}`);
11423
+ values.push(fromDate);
11424
+ paramIndex++;
11425
+ }
11426
+ if (toDate) {
11427
+ conditions.push(`"createdAt" <= $${paramIndex}`);
11428
+ values.push(toDate);
11429
+ paramIndex++;
11430
+ }
11431
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
11432
+ let total = 0;
11433
+ const usePagination = typeof perPage === "number" && typeof page === "number";
11434
+ if (usePagination) {
11435
+ const countResult = await this.#db.client.one(
11436
+ `SELECT COUNT(*) as count FROM ${getTableName5({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName5(this.#schema) })} ${whereClause}`,
11437
+ values
11438
+ );
11439
+ total = Number(countResult.count);
11440
+ }
11441
+ const normalizedPerPage = usePagination ? normalizePerPage(perPage, Number.MAX_SAFE_INTEGER) : 0;
11442
+ const offset = usePagination ? page * normalizedPerPage : void 0;
11443
+ const query = `
11444
+ SELECT * FROM ${getTableName5({ indexName: TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName5(this.#schema) })}
11445
+ ${whereClause}
11446
+ ORDER BY "createdAt" DESC
11447
+ ${usePagination ? ` LIMIT $${paramIndex} OFFSET $${paramIndex + 1}` : ""}
11448
+ `;
11449
+ const queryValues = usePagination ? [...values, normalizedPerPage, offset] : values;
11450
+ const result = await this.#db.client.manyOrNone(query, queryValues);
11451
+ const runs = (result || []).map((row) => {
11452
+ return this.parseWorkflowRun(row);
11453
+ });
11454
+ return { runs, total: total || runs.length };
11455
+ } catch (error) {
11456
+ throw new MastraError(
11457
+ {
11458
+ id: createStorageErrorId("PG", "LIST_WORKFLOW_RUNS", "FAILED"),
11459
+ domain: ErrorDomain.STORAGE,
11460
+ category: ErrorCategory.THIRD_PARTY,
11461
+ details: {
11462
+ workflowName: workflowName || "all"
11463
+ }
11464
+ },
11465
+ error
11466
+ );
11467
+ }
11468
+ }
11469
+ };
11470
+ var SNAPSHOT_FIELDS5 = [
11471
+ "name",
11472
+ "description",
11473
+ "filesystem",
11474
+ "sandbox",
11475
+ "mounts",
11476
+ "search",
11477
+ "skills",
11478
+ "tools",
11479
+ "autoSync",
11480
+ "operationTimeout"
11481
+ ];
11482
+ var WorkspacesPG = class _WorkspacesPG extends WorkspacesStorage {
11483
+ #db;
11484
+ #schema;
11485
+ #skipDefaultIndexes;
11486
+ #indexes;
11487
+ static MANAGED_TABLES = [TABLE_WORKSPACES, TABLE_WORKSPACE_VERSIONS];
11488
+ constructor(config) {
11489
+ super();
11490
+ const { client, schemaName, skipDefaultIndexes, indexes } = resolvePgConfig(config);
11491
+ this.#db = new PgDB({ client, schemaName, skipDefaultIndexes });
11492
+ this.#schema = schemaName || "public";
11493
+ this.#skipDefaultIndexes = skipDefaultIndexes;
11494
+ this.#indexes = indexes?.filter((idx) => _WorkspacesPG.MANAGED_TABLES.includes(idx.table));
11495
+ }
11496
+ getDefaultIndexDefinitions() {
11497
+ return [
11498
+ {
11499
+ name: "idx_workspace_versions_workspace_version",
11500
+ table: TABLE_WORKSPACE_VERSIONS,
11501
+ columns: ["workspaceId", "versionNumber"],
11502
+ unique: true
11503
+ }
11504
+ ];
11505
+ }
11506
+ async createDefaultIndexes() {
11507
+ if (this.#skipDefaultIndexes) {
11508
+ return;
11509
+ }
11510
+ for (const indexDef of this.getDefaultIndexDefinitions()) {
11511
+ try {
11512
+ await this.#db.createIndex(indexDef);
11513
+ } catch {
11514
+ }
11515
+ }
11516
+ }
11517
+ async init() {
11518
+ await this.#db.createTable({
11519
+ tableName: TABLE_WORKSPACES,
11520
+ schema: TABLE_SCHEMAS[TABLE_WORKSPACES]
11521
+ });
11522
+ await this.#db.createTable({
11523
+ tableName: TABLE_WORKSPACE_VERSIONS,
11524
+ schema: TABLE_SCHEMAS[TABLE_WORKSPACE_VERSIONS]
11525
+ });
11526
+ await this.createDefaultIndexes();
11527
+ await this.createCustomIndexes();
11528
+ }
11529
+ async createCustomIndexes() {
11530
+ if (!this.#indexes || this.#indexes.length === 0) {
11531
+ return;
11532
+ }
11533
+ for (const indexDef of this.#indexes) {
11534
+ try {
11535
+ await this.#db.createIndex(indexDef);
11536
+ } catch (error) {
11537
+ this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
11538
+ }
11539
+ }
11540
+ }
11541
+ async dangerouslyClearAll() {
11542
+ await this.#db.clearTable({ tableName: TABLE_WORKSPACE_VERSIONS });
11543
+ await this.#db.clearTable({ tableName: TABLE_WORKSPACES });
11544
+ }
11545
+ // ==========================================================================
11546
+ // Workspace CRUD Methods
11547
+ // ==========================================================================
11548
+ async getById(id) {
11549
+ try {
11550
+ const tableName = getTableName2({ indexName: TABLE_WORKSPACES, schemaName: getSchemaName2(this.#schema) });
11551
+ const result = await this.#db.client.oneOrNone(`SELECT * FROM ${tableName} WHERE id = $1`, [id]);
11552
+ if (!result) {
11553
+ return null;
11554
+ }
11555
+ return this.parseWorkspaceRow(result);
11556
+ } catch (error) {
11557
+ if (error instanceof MastraError) throw error;
11558
+ throw new MastraError(
11559
+ {
11560
+ id: createStorageErrorId("PG", "GET_WORKSPACE_BY_ID", "FAILED"),
11561
+ domain: ErrorDomain.STORAGE,
11562
+ category: ErrorCategory.THIRD_PARTY,
11563
+ details: { workspaceId: id }
11564
+ },
11565
+ error
11566
+ );
11567
+ }
11568
+ }
11569
+ async create(input) {
11570
+ const { workspace } = input;
11571
+ try {
11572
+ const tableName = getTableName2({ indexName: TABLE_WORKSPACES, schemaName: getSchemaName2(this.#schema) });
11573
+ const now = /* @__PURE__ */ new Date();
11574
+ const nowIso = now.toISOString();
11575
+ await this.#db.client.none(
11576
+ `INSERT INTO ${tableName} (
11577
+ id, status, "activeVersionId", "authorId", metadata,
11578
+ "createdAt", "createdAtZ", "updatedAt", "updatedAtZ"
11579
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
11580
+ [
11581
+ workspace.id,
11582
+ "draft",
11583
+ null,
11584
+ workspace.authorId ?? null,
11585
+ workspace.metadata ? JSON.stringify(workspace.metadata) : null,
11586
+ nowIso,
11587
+ nowIso,
11588
+ nowIso,
11589
+ nowIso
11590
+ ]
11591
+ );
11592
+ const { id: _id, authorId: _authorId, metadata: _metadata, ...snapshotConfig } = workspace;
11593
+ const versionId = crypto.randomUUID();
11594
+ await this.createVersion({
11595
+ id: versionId,
11596
+ workspaceId: workspace.id,
11597
+ versionNumber: 1,
11598
+ ...snapshotConfig,
11599
+ changedFields: [...SNAPSHOT_FIELDS5],
11600
+ changeMessage: "Initial version"
11601
+ });
11602
+ return {
11603
+ id: workspace.id,
11604
+ status: "draft",
11605
+ activeVersionId: void 0,
11606
+ authorId: workspace.authorId,
11607
+ metadata: workspace.metadata,
11608
+ createdAt: now,
11609
+ updatedAt: now
11610
+ };
11611
+ } catch (error) {
11612
+ try {
11613
+ const tableName = getTableName2({
11614
+ indexName: TABLE_WORKSPACES,
11615
+ schemaName: getSchemaName2(this.#schema)
11616
+ });
11617
+ await this.#db.client.none(
11618
+ `DELETE FROM ${tableName} WHERE id = $1 AND status = 'draft' AND "activeVersionId" IS NULL`,
11619
+ [workspace.id]
11620
+ );
11621
+ } catch {
11622
+ }
11623
+ if (error instanceof MastraError) throw error;
11624
+ throw new MastraError(
11625
+ {
11626
+ id: createStorageErrorId("PG", "CREATE_WORKSPACE", "FAILED"),
11627
+ domain: ErrorDomain.STORAGE,
11628
+ category: ErrorCategory.THIRD_PARTY,
11629
+ details: { workspaceId: workspace.id }
11630
+ },
11631
+ error
11632
+ );
11633
+ }
11634
+ }
11635
+ async update(input) {
11636
+ const { id, ...updates } = input;
11637
+ try {
11638
+ const tableName = getTableName2({ indexName: TABLE_WORKSPACES, schemaName: getSchemaName2(this.#schema) });
11639
+ const existingWorkspace = await this.getById(id);
11640
+ if (!existingWorkspace) {
11641
+ throw new MastraError({
11642
+ id: createStorageErrorId("PG", "UPDATE_WORKSPACE", "NOT_FOUND"),
11643
+ domain: ErrorDomain.STORAGE,
11644
+ category: ErrorCategory.USER,
11645
+ text: `Workspace ${id} not found`,
11646
+ details: { workspaceId: id }
11647
+ });
11648
+ }
11649
+ const { authorId, activeVersionId, metadata, status, ...configFields } = updates;
11650
+ let versionCreated = false;
11651
+ const hasConfigUpdate = SNAPSHOT_FIELDS5.some((field) => field in configFields);
11652
+ if (hasConfigUpdate) {
11653
+ const latestVersion = await this.getLatestVersion(id);
11654
+ if (!latestVersion) {
11655
+ throw new MastraError({
11656
+ id: createStorageErrorId("PG", "UPDATE_WORKSPACE", "NO_VERSIONS"),
11657
+ domain: ErrorDomain.STORAGE,
11658
+ category: ErrorCategory.SYSTEM,
11659
+ text: `No versions found for workspace ${id}`,
11660
+ details: { workspaceId: id }
11661
+ });
11662
+ }
11663
+ const {
11664
+ id: _versionId,
11665
+ workspaceId: _workspaceId,
11666
+ versionNumber: _versionNumber,
11667
+ changedFields: _changedFields,
11668
+ changeMessage: _changeMessage,
11669
+ createdAt: _createdAt,
11670
+ ...latestConfig
11671
+ } = latestVersion;
11672
+ const newConfig = { ...latestConfig, ...configFields };
11673
+ const changedFields = SNAPSHOT_FIELDS5.filter(
11674
+ (field) => field in configFields && JSON.stringify(configFields[field]) !== JSON.stringify(latestConfig[field])
11675
+ );
11676
+ if (changedFields.length > 0) {
11677
+ versionCreated = true;
11678
+ const newVersionId = crypto.randomUUID();
11679
+ await this.createVersion({
11680
+ id: newVersionId,
11681
+ workspaceId: id,
11682
+ versionNumber: latestVersion.versionNumber + 1,
11683
+ ...newConfig,
11684
+ changedFields: [...changedFields],
11685
+ changeMessage: `Updated ${changedFields.join(", ")}`
11686
+ });
11687
+ }
11688
+ }
11689
+ const setClauses = [];
11690
+ const values = [];
11691
+ let paramIndex = 1;
11692
+ if (authorId !== void 0) {
11693
+ setClauses.push(`"authorId" = $${paramIndex++}`);
11694
+ values.push(authorId);
11695
+ }
11696
+ if (activeVersionId !== void 0) {
11697
+ setClauses.push(`"activeVersionId" = $${paramIndex++}`);
11698
+ values.push(activeVersionId);
11699
+ if (status === void 0) {
11700
+ setClauses.push(`status = $${paramIndex++}`);
11701
+ values.push("published");
11702
+ }
11703
+ }
11704
+ if (status !== void 0) {
11705
+ setClauses.push(`status = $${paramIndex++}`);
11706
+ values.push(status);
11707
+ }
11708
+ if (metadata !== void 0) {
11709
+ const mergedMetadata = { ...existingWorkspace.metadata || {}, ...metadata };
11710
+ setClauses.push(`metadata = $${paramIndex++}`);
11711
+ values.push(JSON.stringify(mergedMetadata));
11712
+ }
11713
+ const now = (/* @__PURE__ */ new Date()).toISOString();
11714
+ setClauses.push(`"updatedAt" = $${paramIndex++}`);
11715
+ values.push(now);
11716
+ setClauses.push(`"updatedAtZ" = $${paramIndex++}`);
11717
+ values.push(now);
11718
+ values.push(id);
11719
+ if (setClauses.length > 2 || versionCreated) {
11720
+ await this.#db.client.none(
11721
+ `UPDATE ${tableName} SET ${setClauses.join(", ")} WHERE id = $${paramIndex}`,
11722
+ values
11723
+ );
11724
+ }
11725
+ const updatedWorkspace = await this.getById(id);
11726
+ if (!updatedWorkspace) {
11727
+ throw new MastraError({
11728
+ id: createStorageErrorId("PG", "UPDATE_WORKSPACE", "NOT_FOUND_AFTER_UPDATE"),
11729
+ domain: ErrorDomain.STORAGE,
11730
+ category: ErrorCategory.SYSTEM,
11731
+ text: `Workspace ${id} not found after update`,
11732
+ details: { workspaceId: id }
11733
+ });
11734
+ }
11735
+ return updatedWorkspace;
11736
+ } catch (error) {
11737
+ if (error instanceof MastraError) throw error;
11738
+ throw new MastraError(
11739
+ {
11740
+ id: createStorageErrorId("PG", "UPDATE_WORKSPACE", "FAILED"),
11741
+ domain: ErrorDomain.STORAGE,
11742
+ category: ErrorCategory.THIRD_PARTY,
11743
+ details: { workspaceId: id }
11744
+ },
11745
+ error
11746
+ );
11747
+ }
11748
+ }
11749
+ async delete(id) {
11750
+ try {
11751
+ const tableName = getTableName2({ indexName: TABLE_WORKSPACES, schemaName: getSchemaName2(this.#schema) });
11752
+ await this.deleteVersionsByParentId(id);
11753
+ await this.#db.client.none(`DELETE FROM ${tableName} WHERE id = $1`, [id]);
11754
+ } catch (error) {
11755
+ if (error instanceof MastraError) throw error;
11756
+ throw new MastraError(
11757
+ {
11758
+ id: createStorageErrorId("PG", "DELETE_WORKSPACE", "FAILED"),
11759
+ domain: ErrorDomain.STORAGE,
11760
+ category: ErrorCategory.THIRD_PARTY,
11761
+ details: { workspaceId: id }
11762
+ },
11763
+ error
11764
+ );
11765
+ }
11766
+ }
11767
+ async list(args) {
11768
+ const { page = 0, perPage: perPageInput, orderBy, authorId, metadata } = args || {};
11769
+ const { field, direction } = this.parseOrderBy(orderBy);
11770
+ if (page < 0) {
11771
+ throw new MastraError(
11772
+ {
11773
+ id: createStorageErrorId("PG", "LIST_WORKSPACES", "INVALID_PAGE"),
11774
+ domain: ErrorDomain.STORAGE,
11775
+ category: ErrorCategory.USER,
11776
+ details: { page }
11777
+ },
11778
+ new Error("page must be >= 0")
11779
+ );
11780
+ }
11781
+ const perPage = normalizePerPage(perPageInput, 100);
11782
+ const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
11783
+ try {
11784
+ const tableName = getTableName2({ indexName: TABLE_WORKSPACES, schemaName: getSchemaName2(this.#schema) });
11785
+ const conditions = [];
11786
+ const queryParams = [];
11787
+ let paramIdx = 1;
11788
+ if (authorId !== void 0) {
11789
+ conditions.push(`"authorId" = $${paramIdx++}`);
11790
+ queryParams.push(authorId);
11791
+ }
11792
+ if (metadata && Object.keys(metadata).length > 0) {
11793
+ conditions.push(`metadata @> $${paramIdx++}::jsonb`);
11794
+ queryParams.push(JSON.stringify(metadata));
11795
+ }
11796
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
11797
+ const countResult = await this.#db.client.one(
11798
+ `SELECT COUNT(*) as count FROM ${tableName} ${whereClause}`,
11799
+ queryParams
11800
+ );
11801
+ const total = parseInt(countResult.count, 10);
11802
+ if (total === 0) {
11803
+ return {
11804
+ workspaces: [],
11805
+ total: 0,
11806
+ page,
11807
+ perPage: perPageForResponse,
11808
+ hasMore: false
11809
+ };
11810
+ }
11811
+ const limitValue = perPageInput === false ? total : perPage;
11812
+ const dataResult = await this.#db.client.manyOrNone(
11813
+ `SELECT * FROM ${tableName} ${whereClause} ORDER BY "${field}" ${direction} LIMIT $${paramIdx++} OFFSET $${paramIdx++}`,
11814
+ [...queryParams, limitValue, offset]
11815
+ );
11816
+ const workspaces = (dataResult || []).map((row) => this.parseWorkspaceRow(row));
11817
+ return {
11818
+ workspaces,
11819
+ total,
11820
+ page,
11821
+ perPage: perPageForResponse,
11822
+ hasMore: perPageInput === false ? false : offset + perPage < total
11823
+ };
11824
+ } catch (error) {
11825
+ if (error instanceof MastraError) throw error;
11826
+ throw new MastraError(
11827
+ {
11828
+ id: createStorageErrorId("PG", "LIST_WORKSPACES", "FAILED"),
11829
+ domain: ErrorDomain.STORAGE,
11830
+ category: ErrorCategory.THIRD_PARTY
11831
+ },
11832
+ error
11833
+ );
11834
+ }
11835
+ }
11836
+ // ==========================================================================
11837
+ // Workspace Version Methods
11838
+ // ==========================================================================
11839
+ async createVersion(input) {
11840
+ try {
11841
+ const tableName = getTableName2({
11842
+ indexName: TABLE_WORKSPACE_VERSIONS,
11843
+ schemaName: getSchemaName2(this.#schema)
11844
+ });
11845
+ const now = /* @__PURE__ */ new Date();
11846
+ const nowIso = now.toISOString();
11847
+ await this.#db.client.none(
11848
+ `INSERT INTO ${tableName} (
11849
+ id, "workspaceId", "versionNumber",
11850
+ name, description, filesystem, sandbox, mounts, search, skills, tools,
11851
+ "autoSync", "operationTimeout",
11852
+ "changedFields", "changeMessage",
11853
+ "createdAt", "createdAtZ"
11854
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)`,
11855
+ [
11856
+ input.id,
11857
+ input.workspaceId,
11858
+ input.versionNumber,
11859
+ input.name,
11860
+ input.description ?? null,
11861
+ input.filesystem ? JSON.stringify(input.filesystem) : null,
11862
+ input.sandbox ? JSON.stringify(input.sandbox) : null,
11863
+ input.mounts ? JSON.stringify(input.mounts) : null,
11864
+ input.search ? JSON.stringify(input.search) : null,
11865
+ input.skills ? JSON.stringify(input.skills) : null,
11866
+ input.tools ? JSON.stringify(input.tools) : null,
11867
+ input.autoSync ?? false,
11868
+ input.operationTimeout ?? null,
11869
+ input.changedFields ? JSON.stringify(input.changedFields) : null,
11870
+ input.changeMessage ?? null,
11871
+ nowIso,
11872
+ nowIso
11873
+ ]
11874
+ );
11875
+ return {
11876
+ ...input,
11877
+ createdAt: now
11878
+ };
11879
+ } catch (error) {
11880
+ if (error instanceof MastraError) throw error;
11881
+ throw new MastraError(
11882
+ {
11883
+ id: createStorageErrorId("PG", "CREATE_WORKSPACE_VERSION", "FAILED"),
11884
+ domain: ErrorDomain.STORAGE,
11885
+ category: ErrorCategory.THIRD_PARTY,
11886
+ details: { versionId: input.id, workspaceId: input.workspaceId }
11887
+ },
11888
+ error
11889
+ );
11890
+ }
11891
+ }
11892
+ async getVersion(id) {
11893
+ try {
11894
+ const tableName = getTableName2({
11895
+ indexName: TABLE_WORKSPACE_VERSIONS,
11896
+ schemaName: getSchemaName2(this.#schema)
11897
+ });
11898
+ const result = await this.#db.client.oneOrNone(`SELECT * FROM ${tableName} WHERE id = $1`, [id]);
11899
+ if (!result) {
11900
+ return null;
11901
+ }
11902
+ return this.parseVersionRow(result);
11903
+ } catch (error) {
11904
+ if (error instanceof MastraError) throw error;
11905
+ throw new MastraError(
11906
+ {
11907
+ id: createStorageErrorId("PG", "GET_WORKSPACE_VERSION", "FAILED"),
11908
+ domain: ErrorDomain.STORAGE,
11909
+ category: ErrorCategory.THIRD_PARTY,
11910
+ details: { versionId: id }
11911
+ },
11912
+ error
11913
+ );
11914
+ }
11915
+ }
11916
+ async getVersionByNumber(workspaceId, versionNumber) {
11917
+ try {
11918
+ const tableName = getTableName2({
11919
+ indexName: TABLE_WORKSPACE_VERSIONS,
11920
+ schemaName: getSchemaName2(this.#schema)
11921
+ });
11922
+ const result = await this.#db.client.oneOrNone(
11923
+ `SELECT * FROM ${tableName} WHERE "workspaceId" = $1 AND "versionNumber" = $2`,
11924
+ [workspaceId, versionNumber]
11925
+ );
11926
+ if (!result) {
11927
+ return null;
11928
+ }
11929
+ return this.parseVersionRow(result);
11930
+ } catch (error) {
11931
+ if (error instanceof MastraError) throw error;
11932
+ throw new MastraError(
11933
+ {
11934
+ id: createStorageErrorId("PG", "GET_WORKSPACE_VERSION_BY_NUMBER", "FAILED"),
11935
+ domain: ErrorDomain.STORAGE,
11936
+ category: ErrorCategory.THIRD_PARTY,
11937
+ details: { workspaceId, versionNumber }
11938
+ },
11939
+ error
11940
+ );
11941
+ }
11942
+ }
11943
+ async getLatestVersion(workspaceId) {
11944
+ try {
11945
+ const tableName = getTableName2({
11946
+ indexName: TABLE_WORKSPACE_VERSIONS,
11947
+ schemaName: getSchemaName2(this.#schema)
11948
+ });
11949
+ const result = await this.#db.client.oneOrNone(
11950
+ `SELECT * FROM ${tableName} WHERE "workspaceId" = $1 ORDER BY "versionNumber" DESC LIMIT 1`,
11951
+ [workspaceId]
11952
+ );
11953
+ if (!result) {
11954
+ return null;
11955
+ }
11956
+ return this.parseVersionRow(result);
11957
+ } catch (error) {
11958
+ if (error instanceof MastraError) throw error;
11959
+ throw new MastraError(
11960
+ {
11961
+ id: createStorageErrorId("PG", "GET_LATEST_WORKSPACE_VERSION", "FAILED"),
11962
+ domain: ErrorDomain.STORAGE,
11963
+ category: ErrorCategory.THIRD_PARTY,
11964
+ details: { workspaceId }
11965
+ },
11966
+ error
11967
+ );
11968
+ }
11969
+ }
11970
+ async listVersions(input) {
11971
+ const { workspaceId, page = 0, perPage: perPageInput, orderBy } = input;
11972
+ if (page < 0) {
11973
+ throw new MastraError(
11974
+ {
11975
+ id: createStorageErrorId("PG", "LIST_WORKSPACE_VERSIONS", "INVALID_PAGE"),
11976
+ domain: ErrorDomain.STORAGE,
11977
+ category: ErrorCategory.USER,
11978
+ details: { page }
11979
+ },
11980
+ new Error("page must be >= 0")
11981
+ );
11982
+ }
11983
+ const perPage = normalizePerPage(perPageInput, 20);
11984
+ const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
11985
+ try {
11986
+ const { field, direction } = this.parseVersionOrderBy(orderBy);
11987
+ const tableName = getTableName2({
11988
+ indexName: TABLE_WORKSPACE_VERSIONS,
11989
+ schemaName: getSchemaName2(this.#schema)
11990
+ });
11991
+ const countResult = await this.#db.client.one(
11992
+ `SELECT COUNT(*) as count FROM ${tableName} WHERE "workspaceId" = $1`,
11993
+ [workspaceId]
11994
+ );
11995
+ const total = parseInt(countResult.count, 10);
11996
+ if (total === 0) {
11997
+ return {
11998
+ versions: [],
11999
+ total: 0,
12000
+ page,
12001
+ perPage: perPageForResponse,
12002
+ hasMore: false
12003
+ };
12004
+ }
12005
+ const limitValue = perPageInput === false ? total : perPage;
12006
+ const dataResult = await this.#db.client.manyOrNone(
12007
+ `SELECT * FROM ${tableName} WHERE "workspaceId" = $1 ORDER BY "${field}" ${direction} LIMIT $2 OFFSET $3`,
12008
+ [workspaceId, limitValue, offset]
12009
+ );
12010
+ const versions = (dataResult || []).map((row) => this.parseVersionRow(row));
12011
+ return {
12012
+ versions,
12013
+ total,
12014
+ page,
12015
+ perPage: perPageForResponse,
12016
+ hasMore: perPageInput === false ? false : offset + perPage < total
12017
+ };
12018
+ } catch (error) {
12019
+ if (error instanceof MastraError) throw error;
12020
+ throw new MastraError(
12021
+ {
12022
+ id: createStorageErrorId("PG", "LIST_WORKSPACE_VERSIONS", "FAILED"),
12023
+ domain: ErrorDomain.STORAGE,
12024
+ category: ErrorCategory.THIRD_PARTY,
12025
+ details: { workspaceId }
12026
+ },
12027
+ error
12028
+ );
12029
+ }
12030
+ }
12031
+ async deleteVersion(id) {
12032
+ try {
12033
+ const tableName = getTableName2({
12034
+ indexName: TABLE_WORKSPACE_VERSIONS,
12035
+ schemaName: getSchemaName2(this.#schema)
12036
+ });
12037
+ await this.#db.client.none(`DELETE FROM ${tableName} WHERE id = $1`, [id]);
12038
+ } catch (error) {
12039
+ if (error instanceof MastraError) throw error;
12040
+ throw new MastraError(
12041
+ {
12042
+ id: createStorageErrorId("PG", "DELETE_WORKSPACE_VERSION", "FAILED"),
12043
+ domain: ErrorDomain.STORAGE,
12044
+ category: ErrorCategory.THIRD_PARTY,
12045
+ details: { versionId: id }
12046
+ },
12047
+ error
12048
+ );
12049
+ }
12050
+ }
12051
+ async deleteVersionsByParentId(entityId) {
12052
+ try {
12053
+ const tableName = getTableName2({
12054
+ indexName: TABLE_WORKSPACE_VERSIONS,
12055
+ schemaName: getSchemaName2(this.#schema)
12056
+ });
12057
+ await this.#db.client.none(`DELETE FROM ${tableName} WHERE "workspaceId" = $1`, [entityId]);
12058
+ } catch (error) {
12059
+ if (error instanceof MastraError) throw error;
12060
+ throw new MastraError(
12061
+ {
12062
+ id: createStorageErrorId("PG", "DELETE_WORKSPACE_VERSIONS_BY_WORKSPACE_ID", "FAILED"),
12063
+ domain: ErrorDomain.STORAGE,
12064
+ category: ErrorCategory.THIRD_PARTY,
12065
+ details: { workspaceId: entityId }
12066
+ },
12067
+ error
12068
+ );
12069
+ }
12070
+ }
12071
+ async countVersions(workspaceId) {
12072
+ try {
12073
+ const tableName = getTableName2({
12074
+ indexName: TABLE_WORKSPACE_VERSIONS,
12075
+ schemaName: getSchemaName2(this.#schema)
12076
+ });
12077
+ const result = await this.#db.client.one(`SELECT COUNT(*) as count FROM ${tableName} WHERE "workspaceId" = $1`, [
12078
+ workspaceId
12079
+ ]);
12080
+ return parseInt(result.count, 10);
12081
+ } catch (error) {
12082
+ if (error instanceof MastraError) throw error;
12083
+ throw new MastraError(
12084
+ {
12085
+ id: createStorageErrorId("PG", "COUNT_WORKSPACE_VERSIONS", "FAILED"),
12086
+ domain: ErrorDomain.STORAGE,
12087
+ category: ErrorCategory.THIRD_PARTY,
12088
+ details: { workspaceId }
12089
+ },
12090
+ error
12091
+ );
12092
+ }
12093
+ }
12094
+ // ==========================================================================
12095
+ // Private Helper Methods
12096
+ // ==========================================================================
12097
+ parseJson(value, fieldName) {
12098
+ if (!value) return void 0;
12099
+ if (typeof value !== "string") return value;
12100
+ try {
12101
+ return JSON.parse(value);
12102
+ } catch (error) {
12103
+ if (error instanceof MastraError) throw error;
12104
+ const details = {
12105
+ value: value.length > 100 ? value.substring(0, 100) + "..." : value
12106
+ };
12107
+ if (fieldName) {
12108
+ details.field = fieldName;
12109
+ }
12110
+ throw new MastraError(
12111
+ {
12112
+ id: createStorageErrorId("PG", "PARSE_JSON", "INVALID_JSON"),
12113
+ domain: ErrorDomain.STORAGE,
12114
+ category: ErrorCategory.SYSTEM,
12115
+ text: `Failed to parse JSON${fieldName ? ` for field "${fieldName}"` : ""}: ${error instanceof Error ? error.message : "Unknown error"}`,
12116
+ details
12117
+ },
12118
+ error
12119
+ );
12120
+ }
12121
+ }
12122
+ parseWorkspaceRow(row) {
12123
+ return {
12124
+ id: row.id,
12125
+ status: row.status,
12126
+ activeVersionId: row.activeVersionId,
12127
+ authorId: row.authorId,
12128
+ metadata: this.parseJson(row.metadata, "metadata"),
12129
+ createdAt: new Date(row.createdAtZ || row.createdAt),
12130
+ updatedAt: new Date(row.updatedAtZ || row.updatedAt)
12131
+ };
12132
+ }
12133
+ parseVersionRow(row) {
12134
+ return {
12135
+ id: row.id,
12136
+ workspaceId: row.workspaceId,
12137
+ versionNumber: row.versionNumber,
12138
+ name: row.name,
12139
+ description: row.description,
12140
+ filesystem: this.parseJson(row.filesystem, "filesystem"),
12141
+ sandbox: this.parseJson(row.sandbox, "sandbox"),
12142
+ mounts: this.parseJson(row.mounts, "mounts"),
12143
+ search: this.parseJson(row.search, "search"),
12144
+ skills: this.parseJson(row.skills, "skills"),
12145
+ tools: this.parseJson(row.tools, "tools"),
12146
+ autoSync: Boolean(row.autoSync),
12147
+ operationTimeout: row.operationTimeout != null ? Number(row.operationTimeout) : void 0,
12148
+ changedFields: this.parseJson(row.changedFields, "changedFields"),
12149
+ changeMessage: row.changeMessage,
12150
+ createdAt: new Date(row.createdAtZ || row.createdAt)
12151
+ };
12152
+ }
10894
12153
  };
10895
12154
 
10896
12155
  // src/storage/index.ts
@@ -10954,6 +12213,9 @@ var PostgresStore = class extends MastraCompositeStore {
10954
12213
  promptBlocks: new PromptBlocksPG(domainConfig),
10955
12214
  scorerDefinitions: new ScorerDefinitionsPG(domainConfig),
10956
12215
  mcpClients: new MCPClientsPG(domainConfig),
12216
+ workspaces: new WorkspacesPG(domainConfig),
12217
+ skills: new SkillsPG(domainConfig),
12218
+ blobs: new BlobsPG(domainConfig),
10957
12219
  datasets: new DatasetsPG(domainConfig),
10958
12220
  experiments: new ExperimentsPG(domainConfig)
10959
12221
  };
@@ -11144,6 +12406,6 @@ Example Complex Query:
11144
12406
  ]
11145
12407
  }`;
11146
12408
 
11147
- export { AgentsPG, DatasetsPG, ExperimentsPG, MCPClientsPG, MemoryPG, ObservabilityPG, PGVECTOR_PROMPT, PgVector, PoolAdapter, PostgresStore, PromptBlocksPG, ScorerDefinitionsPG, ScoresPG, WorkflowsPG, exportSchemas };
12409
+ export { AgentsPG, BlobsPG, DatasetsPG, ExperimentsPG, MCPClientsPG, MemoryPG, ObservabilityPG, PGVECTOR_PROMPT, PgVector, PoolAdapter, PostgresStore, PromptBlocksPG, ScorerDefinitionsPG, ScoresPG, SkillsPG, WorkflowsPG, WorkspacesPG, exportSchemas };
11148
12410
  //# sourceMappingURL=index.js.map
11149
12411
  //# sourceMappingURL=index.js.map