@mastra/libsql 1.10.1 → 1.11.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { createClient } from '@libsql/client';
2
2
  import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
3
- import { createVectorErrorId, AgentsStorage, AGENTS_SCHEMA, TABLE_AGENTS, AGENT_VERSIONS_SCHEMA, TABLE_AGENT_VERSIONS, createStorageErrorId, normalizePerPage, calculatePagination, BackgroundTasksStorage, TABLE_SCHEMAS, TABLE_BACKGROUND_TASKS, BlobStore, TABLE_SKILL_BLOBS, SKILL_BLOBS_SCHEMA, ChannelsStorage, TABLE_CHANNEL_INSTALLATIONS, TABLE_CHANNEL_CONFIG, DatasetsStorage, DATASETS_SCHEMA, TABLE_DATASETS, DATASET_ITEMS_SCHEMA, TABLE_DATASET_ITEMS, DATASET_VERSIONS_SCHEMA, TABLE_DATASET_VERSIONS, ensureDate, safelyParseJSON, TABLE_EXPERIMENT_RESULTS, TABLE_EXPERIMENTS, ExperimentsStorage, EXPERIMENTS_SCHEMA, EXPERIMENT_RESULTS_SCHEMA, MCPClientsStorage, MCP_CLIENTS_SCHEMA, TABLE_MCP_CLIENTS, MCP_CLIENT_VERSIONS_SCHEMA, TABLE_MCP_CLIENT_VERSIONS, MCPServersStorage, MCP_SERVERS_SCHEMA, TABLE_MCP_SERVERS, MCP_SERVER_VERSIONS_SCHEMA, TABLE_MCP_SERVER_VERSIONS, MemoryStorage, TABLE_THREADS, TABLE_MESSAGES, TABLE_RESOURCES, ObservabilityStorage, SPAN_SCHEMA, TABLE_SPANS, listTracesArgsSchema, toTraceSpans, PromptBlocksStorage, PROMPT_BLOCKS_SCHEMA, TABLE_PROMPT_BLOCKS, PROMPT_BLOCK_VERSIONS_SCHEMA, TABLE_PROMPT_BLOCK_VERSIONS, SchedulesStorage, TABLE_SCHEDULES, TABLE_SCHEDULE_TRIGGERS, ScorerDefinitionsStorage, SCORER_DEFINITIONS_SCHEMA, TABLE_SCORER_DEFINITIONS, SCORER_DEFINITION_VERSIONS_SCHEMA, TABLE_SCORER_DEFINITION_VERSIONS, ScoresStorage, SCORERS_SCHEMA, TABLE_SCORERS, transformScoreRow, SkillsStorage, SKILLS_SCHEMA, TABLE_SKILLS, SKILL_VERSIONS_SCHEMA, TABLE_SKILL_VERSIONS, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, WorkspacesStorage, WORKSPACES_SCHEMA, TABLE_WORKSPACES, WORKSPACE_VERSIONS_SCHEMA, TABLE_WORKSPACE_VERSIONS, MastraCompositeStore, getSqlType, TraceStatus } from '@mastra/core/storage';
3
+ import { createVectorErrorId, AgentsStorage, AGENTS_SCHEMA, TABLE_AGENTS, AGENT_VERSIONS_SCHEMA, TABLE_AGENT_VERSIONS, createStorageErrorId, normalizePerPage, calculatePagination, BackgroundTasksStorage, TABLE_SCHEMAS, TABLE_BACKGROUND_TASKS, BlobStore, TABLE_SKILL_BLOBS, SKILL_BLOBS_SCHEMA, ChannelsStorage, TABLE_CHANNEL_INSTALLATIONS, TABLE_CHANNEL_CONFIG, DatasetsStorage, DATASETS_SCHEMA, TABLE_DATASETS, DATASET_ITEMS_SCHEMA, TABLE_DATASET_ITEMS, DATASET_VERSIONS_SCHEMA, TABLE_DATASET_VERSIONS, ensureDate, safelyParseJSON, TABLE_EXPERIMENT_RESULTS, TABLE_EXPERIMENTS, ExperimentsStorage, EXPERIMENTS_SCHEMA, EXPERIMENT_RESULTS_SCHEMA, FavoritesStorage, FAVORITES_SCHEMA, TABLE_FAVORITES, TABLE_SKILLS, MCPClientsStorage, MCP_CLIENTS_SCHEMA, TABLE_MCP_CLIENTS, MCP_CLIENT_VERSIONS_SCHEMA, TABLE_MCP_CLIENT_VERSIONS, MCPServersStorage, MCP_SERVERS_SCHEMA, TABLE_MCP_SERVERS, MCP_SERVER_VERSIONS_SCHEMA, TABLE_MCP_SERVER_VERSIONS, MemoryStorage, TABLE_THREADS, TABLE_MESSAGES, TABLE_RESOURCES, ObservabilityStorage, SPAN_SCHEMA, TABLE_SPANS, listTracesArgsSchema, toTraceSpans, PromptBlocksStorage, PROMPT_BLOCKS_SCHEMA, TABLE_PROMPT_BLOCKS, PROMPT_BLOCK_VERSIONS_SCHEMA, TABLE_PROMPT_BLOCK_VERSIONS, SchedulesStorage, TABLE_SCHEDULES, TABLE_SCHEDULE_TRIGGERS, ScorerDefinitionsStorage, SCORER_DEFINITIONS_SCHEMA, TABLE_SCORER_DEFINITIONS, SCORER_DEFINITION_VERSIONS_SCHEMA, TABLE_SCORER_DEFINITION_VERSIONS, ScoresStorage, SCORERS_SCHEMA, TABLE_SCORERS, transformScoreRow, SkillsStorage, SKILLS_SCHEMA, SKILL_VERSIONS_SCHEMA, TABLE_SKILL_VERSIONS, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, WorkspacesStorage, WORKSPACES_SCHEMA, TABLE_WORKSPACES, WORKSPACE_VERSIONS_SCHEMA, TABLE_WORKSPACE_VERSIONS, MastraCompositeStore, getSqlType, TraceStatus } from '@mastra/core/storage';
4
4
  import { parseSqlIdentifier, parseFieldKey } from '@mastra/core/utils';
5
5
  import { MastraVector, validateTopK, validateUpsertInput } from '@mastra/core/vector';
6
6
  import { BaseFilterTranslator } from '@mastra/core/vector/filter';
@@ -1209,6 +1209,15 @@ function buildSelectColumns(tableName) {
1209
1209
  return colDef?.type === "jsonb" ? `json("${parsedCol}") as "${parsedCol}"` : `"${parsedCol}"`;
1210
1210
  }).join(", ");
1211
1211
  }
1212
+ function buildSelectColumnsWithAlias(tableName, alias) {
1213
+ const parsedAlias = parseSqlIdentifier(alias, "table alias");
1214
+ const schema = TABLE_SCHEMAS[tableName];
1215
+ return Object.keys(schema).map((col) => {
1216
+ const colDef = schema[col];
1217
+ const parsedCol = parseSqlIdentifier(col, "column name");
1218
+ return colDef?.type === "jsonb" ? `json(${parsedAlias}."${parsedCol}") as "${parsedCol}"` : `${parsedAlias}."${parsedCol}"`;
1219
+ }).join(", ");
1220
+ }
1212
1221
  function isLockError(error) {
1213
1222
  return error.code === "SQLITE_BUSY" || error.code === "SQLITE_LOCKED" || error.message?.toLowerCase().includes("database is locked") || error.message?.toLowerCase().includes("database table is locked") || error.message?.toLowerCase().includes("table is locked") || error.constructor.name === "SqliteError" && error.message?.toLowerCase().includes("locked");
1214
1223
  }
@@ -2259,12 +2268,12 @@ var AgentsLibSQL = class extends AgentsStorage {
2259
2268
  await this.#db.alterTable({
2260
2269
  tableName: TABLE_AGENTS,
2261
2270
  schema: AGENTS_SCHEMA,
2262
- ifNotExists: ["status", "authorId"]
2271
+ ifNotExists: ["status", "authorId", "visibility", "favoriteCount"]
2263
2272
  });
2264
2273
  await this.#db.alterTable({
2265
2274
  tableName: TABLE_AGENT_VERSIONS,
2266
2275
  schema: AGENT_VERSIONS_SCHEMA,
2267
- ifNotExists: ["mcpClients", "requestContextSchema", "workspace", "skills", "skillsFormat"]
2276
+ ifNotExists: ["mcpClients", "requestContextSchema", "workspace", "skills", "skillsFormat", "browser"]
2268
2277
  });
2269
2278
  await this.#migrateToolsToJsonbFormat();
2270
2279
  await this.#cleanupStaleDrafts();
@@ -2355,14 +2364,23 @@ var AgentsLibSQL = class extends AgentsStorage {
2355
2364
  });
2356
2365
  }
2357
2366
  /**
2358
- * Removes stale draft agent records that have no activeVersionId.
2367
+ * Removes stale draft agent records that have no versions at all.
2359
2368
  * These are left behind when createAgent partially fails (inserts thin record
2360
2369
  * but fails to create the version due to schema mismatch).
2370
+ *
2371
+ * A legitimate draft (never published) will have rows in the versions table,
2372
+ * so we must only delete records with zero associated versions.
2361
2373
  */
2362
2374
  async #cleanupStaleDrafts() {
2363
2375
  try {
2364
2376
  await this.#client.execute({
2365
- sql: `DELETE FROM "${TABLE_AGENTS}" WHERE status = 'draft' AND activeVersionId IS NULL`
2377
+ sql: `DELETE FROM "${TABLE_AGENTS}"
2378
+ WHERE status = 'draft'
2379
+ AND activeVersionId IS NULL
2380
+ AND NOT EXISTS (
2381
+ SELECT 1 FROM "${TABLE_AGENT_VERSIONS}"
2382
+ WHERE "${TABLE_AGENT_VERSIONS}".agentId = "${TABLE_AGENTS}".id
2383
+ )`
2366
2384
  });
2367
2385
  } catch {
2368
2386
  }
@@ -2457,7 +2475,9 @@ var AgentsLibSQL = class extends AgentsStorage {
2457
2475
  status: row.status,
2458
2476
  activeVersionId: row.activeVersionId,
2459
2477
  authorId: row.authorId,
2478
+ visibility: row.visibility ?? void 0,
2460
2479
  metadata: this.parseJson(row.metadata, "metadata"),
2480
+ favoriteCount: row.favoriteCount === null || row.favoriteCount === void 0 ? 0 : Number(row.favoriteCount),
2461
2481
  createdAt: new Date(row.createdAt),
2462
2482
  updatedAt: new Date(row.updatedAt)
2463
2483
  };
@@ -2486,6 +2506,7 @@ var AgentsLibSQL = class extends AgentsStorage {
2486
2506
  const { agent } = input;
2487
2507
  try {
2488
2508
  const now = /* @__PURE__ */ new Date();
2509
+ const visibility = agent.visibility ?? (agent.authorId ? "private" : null);
2489
2510
  await this.#db.insert({
2490
2511
  tableName: TABLE_AGENTS,
2491
2512
  record: {
@@ -2493,12 +2514,14 @@ var AgentsLibSQL = class extends AgentsStorage {
2493
2514
  status: "draft",
2494
2515
  activeVersionId: null,
2495
2516
  authorId: agent.authorId ?? null,
2517
+ visibility,
2496
2518
  metadata: agent.metadata ?? null,
2519
+ favoriteCount: 0,
2497
2520
  createdAt: now,
2498
2521
  updatedAt: now
2499
2522
  }
2500
2523
  });
2501
- const { id: _id, authorId: _authorId, metadata: _metadata, ...snapshotConfig } = agent;
2524
+ const { id: _id, authorId: _authorId, visibility: _visibility, metadata: _metadata, ...snapshotConfig } = agent;
2502
2525
  const versionId = crypto.randomUUID();
2503
2526
  await this.createVersion({
2504
2527
  id: versionId,
@@ -2547,13 +2570,14 @@ var AgentsLibSQL = class extends AgentsStorage {
2547
2570
  details: { agentId: id }
2548
2571
  });
2549
2572
  }
2550
- const { authorId, activeVersionId, metadata, status } = updates;
2573
+ const { authorId, activeVersionId, metadata, status, visibility } = updates;
2551
2574
  const updateData = {
2552
2575
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2553
2576
  };
2554
2577
  if (authorId !== void 0) updateData.authorId = authorId;
2555
2578
  if (activeVersionId !== void 0) updateData.activeVersionId = activeVersionId;
2556
2579
  if (status !== void 0) updateData.status = status;
2580
+ if (visibility !== void 0) updateData.visibility = visibility;
2557
2581
  if (metadata !== void 0) {
2558
2582
  updateData.metadata = { ...existing.metadata, ...metadata };
2559
2583
  }
@@ -2609,7 +2633,18 @@ var AgentsLibSQL = class extends AgentsStorage {
2609
2633
  }
2610
2634
  }
2611
2635
  async list(args) {
2612
- const { page = 0, perPage: perPageInput, orderBy, authorId, metadata, status } = args || {};
2636
+ const {
2637
+ page = 0,
2638
+ perPage: perPageInput,
2639
+ orderBy,
2640
+ authorId,
2641
+ metadata,
2642
+ status,
2643
+ visibility,
2644
+ entityIds,
2645
+ pinFavoritedFor,
2646
+ favoritedOnly
2647
+ } = args || {};
2613
2648
  const { field, direction } = this.parseOrderBy(orderBy);
2614
2649
  if (page < 0) {
2615
2650
  throw new MastraError(
@@ -2625,16 +2660,29 @@ var AgentsLibSQL = class extends AgentsStorage {
2625
2660
  const perPage = normalizePerPage(perPageInput, 100);
2626
2661
  const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
2627
2662
  try {
2663
+ if (entityIds && entityIds.length === 0) {
2664
+ return {
2665
+ agents: [],
2666
+ total: 0,
2667
+ page,
2668
+ perPage: perPageForResponse,
2669
+ hasMore: false
2670
+ };
2671
+ }
2628
2672
  const conditions = [];
2629
2673
  const queryParams = [];
2630
2674
  if (status) {
2631
- conditions.push("status = ?");
2675
+ conditions.push("a.status = ?");
2632
2676
  queryParams.push(status);
2633
2677
  }
2634
2678
  if (authorId !== void 0) {
2635
- conditions.push("authorId = ?");
2679
+ conditions.push("a.authorId = ?");
2636
2680
  queryParams.push(authorId);
2637
2681
  }
2682
+ if (visibility !== void 0) {
2683
+ conditions.push("a.visibility = ?");
2684
+ queryParams.push(visibility);
2685
+ }
2638
2686
  if (metadata && Object.keys(metadata).length > 0) {
2639
2687
  for (const [key, value] of Object.entries(metadata)) {
2640
2688
  if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) {
@@ -2646,14 +2694,32 @@ var AgentsLibSQL = class extends AgentsStorage {
2646
2694
  details: { key }
2647
2695
  });
2648
2696
  }
2649
- conditions.push(`json_extract(metadata, '$.${key}') = ?`);
2697
+ conditions.push(`json_extract(a.metadata, '$.${key}') = ?`);
2650
2698
  queryParams.push(typeof value === "string" ? value : JSON.stringify(value));
2651
2699
  }
2652
2700
  }
2701
+ if (entityIds && entityIds.length > 0) {
2702
+ const placeholders = entityIds.map(() => "?").join(", ");
2703
+ conditions.push(`a.id IN (${placeholders})`);
2704
+ queryParams.push(...entityIds);
2705
+ }
2706
+ const joinUserId = pinFavoritedFor;
2707
+ const useJoin = Boolean(joinUserId);
2708
+ let joinClause = "";
2709
+ const joinParams = [];
2710
+ if (useJoin && joinUserId) {
2711
+ joinClause = `LEFT JOIN "${TABLE_FAVORITES}" s ON s."entityType" = 'agent' AND s."entityId" = a.id AND s."userId" = ?`;
2712
+ joinParams.push(joinUserId);
2713
+ if (favoritedOnly) {
2714
+ conditions.push('s."userId" IS NOT NULL');
2715
+ }
2716
+ } else if (favoritedOnly) {
2717
+ conditions.push("1=0");
2718
+ }
2653
2719
  const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
2654
2720
  const countResult = await this.#client.execute({
2655
- sql: `SELECT COUNT(*) as count FROM "${TABLE_AGENTS}" ${whereClause}`,
2656
- args: queryParams
2721
+ sql: `SELECT COUNT(*) as count FROM "${TABLE_AGENTS}" a ${joinClause} ${whereClause}`,
2722
+ args: [...joinParams, ...queryParams]
2657
2723
  });
2658
2724
  const total = Number(countResult.rows?.[0]?.count ?? 0);
2659
2725
  if (total === 0) {
@@ -2665,10 +2731,18 @@ var AgentsLibSQL = class extends AgentsStorage {
2665
2731
  hasMore: false
2666
2732
  };
2667
2733
  }
2734
+ const orderByParts = [];
2735
+ if (useJoin && joinUserId) {
2736
+ orderByParts.push(`(s."userId" IS NOT NULL) DESC`);
2737
+ }
2738
+ orderByParts.push(`a."${field}" ${direction}`);
2739
+ orderByParts.push(`a."id" ASC`);
2740
+ const orderByClause = `ORDER BY ${orderByParts.join(", ")}`;
2668
2741
  const limitValue = perPageInput === false ? total : perPage;
2742
+ const selectCols = buildSelectColumnsWithAlias(TABLE_AGENTS, "a");
2669
2743
  const result = await this.#client.execute({
2670
- sql: `SELECT ${buildSelectColumns(TABLE_AGENTS)} FROM "${TABLE_AGENTS}" ${whereClause} ORDER BY "${field}" ${direction} LIMIT ? OFFSET ?`,
2671
- args: [...queryParams, limitValue, offset]
2744
+ sql: `SELECT ${selectCols} FROM "${TABLE_AGENTS}" a ${joinClause} ${whereClause} ${orderByClause} LIMIT ? OFFSET ?`,
2745
+ args: [...joinParams, ...queryParams, limitValue, offset]
2672
2746
  });
2673
2747
  const rows = result.rows ?? [];
2674
2748
  const agents = rows.map((row) => this.parseRow(row));
@@ -2721,6 +2795,7 @@ var AgentsLibSQL = class extends AgentsStorage {
2721
2795
  workspace: input.workspace ?? null,
2722
2796
  skills: input.skills ?? null,
2723
2797
  skillsFormat: input.skillsFormat ?? null,
2798
+ browser: input.browser ?? null,
2724
2799
  changedFields: input.changedFields ?? null,
2725
2800
  changeMessage: input.changeMessage ?? null,
2726
2801
  createdAt: now
@@ -2994,6 +3069,7 @@ var AgentsLibSQL = class extends AgentsStorage {
2994
3069
  workspace: this.parseJson(row.workspace, "workspace"),
2995
3070
  skills: this.parseJson(row.skills, "skills"),
2996
3071
  skillsFormat: row.skillsFormat,
3072
+ browser: this.parseJson(row.browser, "browser"),
2997
3073
  changedFields: this.parseJson(row.changedFields, "changedFields"),
2998
3074
  changeMessage: row.changeMessage,
2999
3075
  createdAt: new Date(row.createdAt)
@@ -4975,6 +5051,255 @@ var ExperimentsLibSQL = class extends ExperimentsStorage {
4975
5051
  }
4976
5052
  }
4977
5053
  };
5054
+ var ENTITY_TABLE = {
5055
+ agent: TABLE_AGENTS,
5056
+ skill: TABLE_SKILLS
5057
+ };
5058
+ var FavoritesLibSQL = class extends FavoritesStorage {
5059
+ #db;
5060
+ #client;
5061
+ constructor(config) {
5062
+ super();
5063
+ const client = resolveClient(config);
5064
+ this.#client = client;
5065
+ this.#db = new LibSQLDB({ client, maxRetries: config.maxRetries, initialBackoffMs: config.initialBackoffMs });
5066
+ }
5067
+ async init() {
5068
+ await this.#db.createTable({
5069
+ tableName: TABLE_FAVORITES,
5070
+ schema: FAVORITES_SCHEMA,
5071
+ compositePrimaryKey: ["userId", "entityType", "entityId"]
5072
+ });
5073
+ await this.#client.execute(
5074
+ `CREATE INDEX IF NOT EXISTS idx_favorites_entity ON "${TABLE_FAVORITES}" ("entityType", "entityId")`
5075
+ );
5076
+ }
5077
+ async dangerouslyClearAll() {
5078
+ const tx = await this.#client.transaction("write");
5079
+ try {
5080
+ await tx.execute(`DELETE FROM "${TABLE_FAVORITES}"`);
5081
+ await tx.execute(`UPDATE "${TABLE_AGENTS}" SET "favoriteCount" = 0 WHERE "favoriteCount" > 0`);
5082
+ await tx.execute(`UPDATE "${TABLE_SKILLS}" SET "favoriteCount" = 0 WHERE "favoriteCount" > 0`);
5083
+ await tx.commit();
5084
+ } catch (error) {
5085
+ if (!tx.closed) {
5086
+ await tx.rollback();
5087
+ }
5088
+ throw error;
5089
+ }
5090
+ }
5091
+ async favorite(input) {
5092
+ const { userId, entityType, entityId } = input;
5093
+ const entityTable = ENTITY_TABLE[entityType];
5094
+ try {
5095
+ const tx = await this.#client.transaction("write");
5096
+ try {
5097
+ const entityRow = await tx.execute({
5098
+ sql: `SELECT "favoriteCount" FROM "${entityTable}" WHERE id = ?`,
5099
+ args: [entityId]
5100
+ });
5101
+ if (!entityRow.rows?.[0]) {
5102
+ throw new MastraError({
5103
+ id: createStorageErrorId("LIBSQL", "FAVORITE", "ENTITY_NOT_FOUND"),
5104
+ domain: ErrorDomain.STORAGE,
5105
+ category: ErrorCategory.USER,
5106
+ text: `${entityType} ${entityId} not found`,
5107
+ details: { entityType, entityId }
5108
+ });
5109
+ }
5110
+ const inserted = await tx.execute({
5111
+ sql: `INSERT OR IGNORE INTO "${TABLE_FAVORITES}" ("userId", "entityType", "entityId", "createdAt") VALUES (?, ?, ?, ?)`,
5112
+ args: [userId, entityType, entityId, (/* @__PURE__ */ new Date()).toISOString()]
5113
+ });
5114
+ if ((inserted.rowsAffected ?? 0) > 0) {
5115
+ await tx.execute({
5116
+ sql: `UPDATE "${entityTable}" SET "favoriteCount" = COALESCE("favoriteCount", 0) + 1 WHERE id = ?`,
5117
+ args: [entityId]
5118
+ });
5119
+ }
5120
+ const after = await tx.execute({
5121
+ sql: `SELECT "favoriteCount" FROM "${entityTable}" WHERE id = ?`,
5122
+ args: [entityId]
5123
+ });
5124
+ const favoriteCount = Number(after.rows?.[0]?.favoriteCount ?? 0);
5125
+ await tx.commit();
5126
+ return { favorited: true, favoriteCount };
5127
+ } catch (error) {
5128
+ if (!tx.closed) {
5129
+ await tx.rollback();
5130
+ }
5131
+ throw error;
5132
+ }
5133
+ } catch (error) {
5134
+ if (error instanceof MastraError) throw error;
5135
+ throw new MastraError(
5136
+ {
5137
+ id: createStorageErrorId("LIBSQL", "FAVORITE", "FAILED"),
5138
+ domain: ErrorDomain.STORAGE,
5139
+ category: ErrorCategory.THIRD_PARTY,
5140
+ details: { entityType, entityId }
5141
+ },
5142
+ error
5143
+ );
5144
+ }
5145
+ }
5146
+ async unfavorite(input) {
5147
+ const { userId, entityType, entityId } = input;
5148
+ const entityTable = ENTITY_TABLE[entityType];
5149
+ try {
5150
+ const tx = await this.#client.transaction("write");
5151
+ try {
5152
+ const entityRow = await tx.execute({
5153
+ sql: `SELECT "favoriteCount" FROM "${entityTable}" WHERE id = ?`,
5154
+ args: [entityId]
5155
+ });
5156
+ if (!entityRow.rows?.[0]) {
5157
+ throw new MastraError({
5158
+ id: createStorageErrorId("LIBSQL", "UNFAVORITE", "ENTITY_NOT_FOUND"),
5159
+ domain: ErrorDomain.STORAGE,
5160
+ category: ErrorCategory.USER,
5161
+ text: `${entityType} ${entityId} not found`,
5162
+ details: { entityType, entityId }
5163
+ });
5164
+ }
5165
+ const deleted = await tx.execute({
5166
+ sql: `DELETE FROM "${TABLE_FAVORITES}" WHERE "userId" = ? AND "entityType" = ? AND "entityId" = ?`,
5167
+ args: [userId, entityType, entityId]
5168
+ });
5169
+ if ((deleted.rowsAffected ?? 0) > 0) {
5170
+ await tx.execute({
5171
+ sql: `UPDATE "${entityTable}" SET "favoriteCount" = MAX(COALESCE("favoriteCount", 0) - 1, 0) WHERE id = ?`,
5172
+ args: [entityId]
5173
+ });
5174
+ }
5175
+ const after = await tx.execute({
5176
+ sql: `SELECT "favoriteCount" FROM "${entityTable}" WHERE id = ?`,
5177
+ args: [entityId]
5178
+ });
5179
+ const favoriteCount = Number(after.rows?.[0]?.favoriteCount ?? 0);
5180
+ await tx.commit();
5181
+ return { favorited: false, favoriteCount };
5182
+ } catch (error) {
5183
+ if (!tx.closed) {
5184
+ await tx.rollback();
5185
+ }
5186
+ throw error;
5187
+ }
5188
+ } catch (error) {
5189
+ if (error instanceof MastraError) throw error;
5190
+ throw new MastraError(
5191
+ {
5192
+ id: createStorageErrorId("LIBSQL", "UNFAVORITE", "FAILED"),
5193
+ domain: ErrorDomain.STORAGE,
5194
+ category: ErrorCategory.THIRD_PARTY,
5195
+ details: { entityType, entityId }
5196
+ },
5197
+ error
5198
+ );
5199
+ }
5200
+ }
5201
+ async isFavorited(input) {
5202
+ try {
5203
+ const result = await this.#client.execute({
5204
+ sql: `SELECT 1 FROM "${TABLE_FAVORITES}" WHERE "userId" = ? AND "entityType" = ? AND "entityId" = ? LIMIT 1`,
5205
+ args: [input.userId, input.entityType, input.entityId]
5206
+ });
5207
+ return (result.rows?.length ?? 0) > 0;
5208
+ } catch (error) {
5209
+ if (error instanceof MastraError) throw error;
5210
+ throw new MastraError(
5211
+ {
5212
+ id: createStorageErrorId("LIBSQL", "IS_FAVORITED", "FAILED"),
5213
+ domain: ErrorDomain.STORAGE,
5214
+ category: ErrorCategory.THIRD_PARTY
5215
+ },
5216
+ error
5217
+ );
5218
+ }
5219
+ }
5220
+ async isFavoritedBatch(input) {
5221
+ const { userId, entityType, entityIds } = input;
5222
+ if (entityIds.length === 0) {
5223
+ return /* @__PURE__ */ new Set();
5224
+ }
5225
+ try {
5226
+ const placeholders = entityIds.map(() => "?").join(", ");
5227
+ const args = [userId, entityType, ...entityIds];
5228
+ const result = await this.#client.execute({
5229
+ sql: `SELECT "entityId" FROM "${TABLE_FAVORITES}" WHERE "userId" = ? AND "entityType" = ? AND "entityId" IN (${placeholders})`,
5230
+ args
5231
+ });
5232
+ const set = /* @__PURE__ */ new Set();
5233
+ for (const row of result.rows ?? []) {
5234
+ set.add(row.entityId);
5235
+ }
5236
+ return set;
5237
+ } catch (error) {
5238
+ if (error instanceof MastraError) throw error;
5239
+ throw new MastraError(
5240
+ {
5241
+ id: createStorageErrorId("LIBSQL", "IS_FAVORITED_BATCH", "FAILED"),
5242
+ domain: ErrorDomain.STORAGE,
5243
+ category: ErrorCategory.THIRD_PARTY
5244
+ },
5245
+ error
5246
+ );
5247
+ }
5248
+ }
5249
+ async listFavoritedIds(input) {
5250
+ try {
5251
+ const result = await this.#client.execute({
5252
+ sql: `SELECT "entityId" FROM "${TABLE_FAVORITES}" WHERE "userId" = ? AND "entityType" = ? ORDER BY "createdAt" DESC, "entityId" ASC`,
5253
+ args: [input.userId, input.entityType]
5254
+ });
5255
+ return (result.rows ?? []).map((row) => row.entityId);
5256
+ } catch (error) {
5257
+ if (error instanceof MastraError) throw error;
5258
+ throw new MastraError(
5259
+ {
5260
+ id: createStorageErrorId("LIBSQL", "LIST_FAVORITED_IDS", "FAILED"),
5261
+ domain: ErrorDomain.STORAGE,
5262
+ category: ErrorCategory.THIRD_PARTY
5263
+ },
5264
+ error
5265
+ );
5266
+ }
5267
+ }
5268
+ async deleteFavoritesForEntity(input) {
5269
+ const entityTable = ENTITY_TABLE[input.entityType];
5270
+ try {
5271
+ const tx = await this.#client.transaction("write");
5272
+ try {
5273
+ const result = await tx.execute({
5274
+ sql: `DELETE FROM "${TABLE_FAVORITES}" WHERE "entityType" = ? AND "entityId" = ?`,
5275
+ args: [input.entityType, input.entityId]
5276
+ });
5277
+ await tx.execute({
5278
+ sql: `UPDATE "${entityTable}" SET "favoriteCount" = 0 WHERE id = ?`,
5279
+ args: [input.entityId]
5280
+ });
5281
+ await tx.commit();
5282
+ return Number(result.rowsAffected ?? 0);
5283
+ } catch (txError) {
5284
+ if (!tx.closed) {
5285
+ await tx.rollback();
5286
+ }
5287
+ throw txError;
5288
+ }
5289
+ } catch (error) {
5290
+ if (error instanceof MastraError) throw error;
5291
+ throw new MastraError(
5292
+ {
5293
+ id: createStorageErrorId("LIBSQL", "DELETE_FAVORITES_FOR_ENTITY", "FAILED"),
5294
+ domain: ErrorDomain.STORAGE,
5295
+ category: ErrorCategory.THIRD_PARTY,
5296
+ details: { entityType: input.entityType, entityId: input.entityId }
5297
+ },
5298
+ error
5299
+ );
5300
+ }
5301
+ }
5302
+ };
4978
5303
  var MCPClientsLibSQL = class extends MCPClientsStorage {
4979
5304
  #db;
4980
5305
  #client;
@@ -10046,6 +10371,7 @@ var SNAPSHOT_FIELDS = [
10046
10371
  "references",
10047
10372
  "scripts",
10048
10373
  "assets",
10374
+ "files",
10049
10375
  "metadata",
10050
10376
  "tree"
10051
10377
  ];
@@ -10064,6 +10390,16 @@ var SkillsLibSQL = class extends SkillsStorage {
10064
10390
  tableName: TABLE_SKILL_VERSIONS,
10065
10391
  schema: SKILL_VERSIONS_SCHEMA
10066
10392
  });
10393
+ await this.#db.alterTable({
10394
+ tableName: TABLE_SKILLS,
10395
+ schema: SKILLS_SCHEMA,
10396
+ ifNotExists: ["visibility", "favoriteCount"]
10397
+ });
10398
+ await this.#db.alterTable({
10399
+ tableName: TABLE_SKILL_VERSIONS,
10400
+ schema: SKILL_VERSIONS_SCHEMA,
10401
+ ifNotExists: ["files"]
10402
+ });
10067
10403
  await this.#client.execute(
10068
10404
  `CREATE UNIQUE INDEX IF NOT EXISTS idx_skill_versions_skill_version ON "${TABLE_SKILL_VERSIONS}" ("skillId", "versionNumber")`
10069
10405
  );
@@ -10099,6 +10435,7 @@ var SkillsLibSQL = class extends SkillsStorage {
10099
10435
  const { skill } = input;
10100
10436
  try {
10101
10437
  const now = /* @__PURE__ */ new Date();
10438
+ const visibility = skill.visibility ?? (skill.authorId ? "private" : void 0);
10102
10439
  await this.#db.insert({
10103
10440
  tableName: TABLE_SKILLS,
10104
10441
  record: {
@@ -10106,11 +10443,13 @@ var SkillsLibSQL = class extends SkillsStorage {
10106
10443
  status: "draft",
10107
10444
  activeVersionId: null,
10108
10445
  authorId: skill.authorId ?? null,
10446
+ visibility: visibility ?? null,
10447
+ favoriteCount: 0,
10109
10448
  createdAt: now.toISOString(),
10110
10449
  updatedAt: now.toISOString()
10111
10450
  }
10112
10451
  });
10113
- const { id: _id, authorId: _authorId, ...snapshotConfig } = skill;
10452
+ const { id: _id, authorId: _authorId, visibility: _visibility, ...snapshotConfig } = skill;
10114
10453
  const versionId = crypto.randomUUID();
10115
10454
  try {
10116
10455
  await this.createVersion({
@@ -10158,13 +10497,18 @@ var SkillsLibSQL = class extends SkillsStorage {
10158
10497
  details: { skillId: id }
10159
10498
  });
10160
10499
  }
10161
- const { authorId, activeVersionId, status, ...configFields } = updates;
10500
+ const { authorId, visibility, activeVersionId, status, ...rawConfigFields } = updates;
10501
+ const configFields = {};
10502
+ for (const [key, value] of Object.entries(rawConfigFields)) {
10503
+ if (value !== void 0) configFields[key] = value;
10504
+ }
10162
10505
  const configFieldNames = SNAPSHOT_FIELDS;
10163
10506
  const hasConfigUpdate = configFieldNames.some((field) => field in configFields);
10164
10507
  const updateData = {
10165
10508
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
10166
10509
  };
10167
10510
  if (authorId !== void 0) updateData.authorId = authorId;
10511
+ if (visibility !== void 0) updateData.visibility = visibility;
10168
10512
  if (activeVersionId !== void 0) {
10169
10513
  updateData.activeVersionId = activeVersionId;
10170
10514
  if (status === void 0) {
@@ -10257,18 +10601,63 @@ var SkillsLibSQL = class extends SkillsStorage {
10257
10601
  }
10258
10602
  async list(args) {
10259
10603
  try {
10260
- const { page = 0, perPage: perPageInput, orderBy, authorId } = args || {};
10604
+ const {
10605
+ page = 0,
10606
+ perPage: perPageInput,
10607
+ orderBy,
10608
+ authorId,
10609
+ visibility,
10610
+ status,
10611
+ entityIds,
10612
+ pinFavoritedFor,
10613
+ favoritedOnly
10614
+ } = args || {};
10261
10615
  const { field, direction } = this.parseOrderBy(orderBy);
10616
+ if (entityIds && entityIds.length === 0) {
10617
+ return {
10618
+ skills: [],
10619
+ total: 0,
10620
+ page,
10621
+ perPage: perPageInput ?? 100,
10622
+ hasMore: false
10623
+ };
10624
+ }
10262
10625
  const conditions = [];
10263
10626
  const queryParams = [];
10264
10627
  if (authorId !== void 0) {
10265
- conditions.push("authorId = ?");
10628
+ conditions.push("s_e.authorId = ?");
10266
10629
  queryParams.push(authorId);
10267
10630
  }
10631
+ if (visibility !== void 0) {
10632
+ conditions.push("s_e.visibility = ?");
10633
+ queryParams.push(visibility);
10634
+ }
10635
+ if (status !== void 0) {
10636
+ conditions.push("s_e.status = ?");
10637
+ queryParams.push(status);
10638
+ }
10639
+ if (entityIds && entityIds.length > 0) {
10640
+ const placeholders = entityIds.map(() => "?").join(", ");
10641
+ conditions.push(`s_e.id IN (${placeholders})`);
10642
+ queryParams.push(...entityIds);
10643
+ }
10644
+ const joinUserId = pinFavoritedFor;
10645
+ const useJoin = Boolean(joinUserId);
10646
+ let joinClause = "";
10647
+ const joinParams = [];
10648
+ if (useJoin && joinUserId) {
10649
+ joinClause = `LEFT JOIN "${TABLE_FAVORITES}" st ON st."entityType" = 'skill' AND st."entityId" = s_e.id AND st."userId" = ?`;
10650
+ joinParams.push(joinUserId);
10651
+ if (favoritedOnly) {
10652
+ conditions.push('st."userId" IS NOT NULL');
10653
+ }
10654
+ } else if (favoritedOnly) {
10655
+ conditions.push("1=0");
10656
+ }
10268
10657
  const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
10269
10658
  const countResult = await this.#client.execute({
10270
- sql: `SELECT COUNT(*) as count FROM "${TABLE_SKILLS}" ${whereClause}`,
10271
- args: queryParams
10659
+ sql: `SELECT COUNT(*) as count FROM "${TABLE_SKILLS}" s_e ${joinClause} ${whereClause}`,
10660
+ args: [...joinParams, ...queryParams]
10272
10661
  });
10273
10662
  const total = Number(countResult.rows?.[0]?.count ?? 0);
10274
10663
  if (total === 0) {
@@ -10284,9 +10673,17 @@ var SkillsLibSQL = class extends SkillsStorage {
10284
10673
  const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
10285
10674
  const limitValue = perPageInput === false ? total : perPage;
10286
10675
  const end = perPageInput === false ? total : start + perPage;
10676
+ const orderByParts = [];
10677
+ if (useJoin && joinUserId) {
10678
+ orderByParts.push(`(st."userId" IS NOT NULL) DESC`);
10679
+ }
10680
+ orderByParts.push(`s_e."${field}" ${direction}`);
10681
+ orderByParts.push(`s_e."id" ASC`);
10682
+ const orderByClause = `ORDER BY ${orderByParts.join(", ")}`;
10683
+ const selectCols = buildSelectColumnsWithAlias(TABLE_SKILLS, "s_e");
10287
10684
  const result = await this.#client.execute({
10288
- sql: `SELECT ${buildSelectColumns(TABLE_SKILLS)} FROM "${TABLE_SKILLS}" ${whereClause} ORDER BY ${field} ${direction} LIMIT ? OFFSET ?`,
10289
- args: [...queryParams, limitValue, start]
10685
+ sql: `SELECT ${selectCols} FROM "${TABLE_SKILLS}" s_e ${joinClause} ${whereClause} ${orderByClause} LIMIT ? OFFSET ?`,
10686
+ args: [...joinParams, ...queryParams, limitValue, start]
10290
10687
  });
10291
10688
  const skills = result.rows?.map((row) => this.#parseSkillRow(row)) ?? [];
10292
10689
  return {
@@ -10318,9 +10715,9 @@ var SkillsLibSQL = class extends SkillsStorage {
10318
10715
  sql: `INSERT INTO "${TABLE_SKILL_VERSIONS}" (
10319
10716
  id, "skillId", "versionNumber",
10320
10717
  name, description, instructions, license, compatibility,
10321
- source, "references", scripts, assets, metadata, tree,
10718
+ source, "references", scripts, assets, files, metadata, tree,
10322
10719
  "changedFields", "changeMessage", "createdAt"
10323
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
10720
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
10324
10721
  args: [
10325
10722
  input.id,
10326
10723
  input.skillId,
@@ -10334,6 +10731,7 @@ var SkillsLibSQL = class extends SkillsStorage {
10334
10731
  input.references ? JSON.stringify(input.references) : null,
10335
10732
  input.scripts ? JSON.stringify(input.scripts) : null,
10336
10733
  input.assets ? JSON.stringify(input.assets) : null,
10734
+ input.files ? JSON.stringify(input.files) : null,
10337
10735
  input.metadata ? JSON.stringify(input.metadata) : null,
10338
10736
  input.tree ? JSON.stringify(input.tree) : null,
10339
10737
  input.changedFields ? JSON.stringify(input.changedFields) : null,
@@ -10527,6 +10925,8 @@ var SkillsLibSQL = class extends SkillsStorage {
10527
10925
  status: row.status ?? "draft",
10528
10926
  activeVersionId: row.activeVersionId ?? void 0,
10529
10927
  authorId: row.authorId ?? void 0,
10928
+ visibility: row.visibility ?? void 0,
10929
+ favoriteCount: row.favoriteCount === null || row.favoriteCount === void 0 ? 0 : Number(row.favoriteCount),
10530
10930
  createdAt: new Date(row.createdAt),
10531
10931
  updatedAt: new Date(row.updatedAt)
10532
10932
  };
@@ -10556,6 +10956,7 @@ var SkillsLibSQL = class extends SkillsStorage {
10556
10956
  references: safeParseJSON(row.references),
10557
10957
  scripts: safeParseJSON(row.scripts),
10558
10958
  assets: safeParseJSON(row.assets),
10959
+ files: safeParseJSON(row.files),
10559
10960
  metadata: safeParseJSON(row.metadata),
10560
10961
  tree: safeParseJSON(row.tree),
10561
10962
  changedFields: safeParseJSON(row.changedFields),
@@ -11007,7 +11408,11 @@ var WorkspacesLibSQL = class extends WorkspacesStorage {
11007
11408
  details: { workspaceId: id }
11008
11409
  });
11009
11410
  }
11010
- const { authorId, activeVersionId, metadata, status, ...configFields } = updates;
11411
+ const { authorId, activeVersionId, metadata, status, ...rawConfigFields } = updates;
11412
+ const configFields = {};
11413
+ for (const [key, value] of Object.entries(rawConfigFields)) {
11414
+ if (value !== void 0) configFields[key] = value;
11415
+ }
11011
11416
  const configFieldNames = SNAPSHOT_FIELDS2;
11012
11417
  const hasConfigUpdate = configFieldNames.some((field) => field in configFields);
11013
11418
  const updateData = {
@@ -11492,6 +11897,7 @@ var LibSQLStore = class extends MastraCompositeStore {
11492
11897
  const mcpServers = new MCPServersLibSQL(domainConfig);
11493
11898
  const workspaces = new WorkspacesLibSQL(domainConfig);
11494
11899
  const skills = new SkillsLibSQL(domainConfig);
11900
+ const favorites = new FavoritesLibSQL(domainConfig);
11495
11901
  const blobs = new BlobsLibSQL(domainConfig);
11496
11902
  const backgroundTasks = new BackgroundTasksLibSQL(domainConfig);
11497
11903
  const schedules = new SchedulesLibSQL(domainConfig);
@@ -11510,6 +11916,7 @@ var LibSQLStore = class extends MastraCompositeStore {
11510
11916
  mcpServers,
11511
11917
  workspaces,
11512
11918
  skills,
11919
+ favorites,
11513
11920
  blobs,
11514
11921
  backgroundTasks,
11515
11922
  schedules
@@ -11673,6 +12080,6 @@ Example Complex Query:
11673
12080
  ]
11674
12081
  }`;
11675
12082
 
11676
- export { AgentsLibSQL, BackgroundTasksLibSQL, BlobsLibSQL, ChannelsLibSQL, DatasetsLibSQL, LibSQLStore as DefaultStorage, ExperimentsLibSQL, LIBSQL_PROMPT, LibSQLStore, LibSQLVector, MCPClientsLibSQL, MCPServersLibSQL, MemoryLibSQL, ObservabilityLibSQL, PromptBlocksLibSQL, SchedulesLibSQL, ScorerDefinitionsLibSQL, ScoresLibSQL, SkillsLibSQL, WorkflowsLibSQL, WorkspacesLibSQL };
12083
+ export { AgentsLibSQL, BackgroundTasksLibSQL, BlobsLibSQL, ChannelsLibSQL, DatasetsLibSQL, LibSQLStore as DefaultStorage, ExperimentsLibSQL, FavoritesLibSQL, LIBSQL_PROMPT, LibSQLStore, LibSQLVector, MCPClientsLibSQL, MCPServersLibSQL, MemoryLibSQL, ObservabilityLibSQL, PromptBlocksLibSQL, SchedulesLibSQL, ScorerDefinitionsLibSQL, ScoresLibSQL, SkillsLibSQL, WorkflowsLibSQL, WorkspacesLibSQL };
11677
12084
  //# sourceMappingURL=index.js.map
11678
12085
  //# sourceMappingURL=index.js.map