@mastra/duckdb 1.5.1 → 1.5.2

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.cjs CHANGED
@@ -1,339 +1,311 @@
1
- 'use strict';
2
-
3
- var chunkSMRZJTCI_cjs = require('./chunk-SMRZJTCI.cjs');
4
- var nodeApi = require('@duckdb/node-api');
5
- var error = require('@mastra/core/error');
6
- var storage = require('@mastra/core/storage');
7
- var vector = require('@mastra/core/vector');
8
- var features = require('@mastra/core/features');
9
-
10
- // src/vector/filter-builder.ts
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_db = require("./db-TBEcMD49.cjs");
3
+ let _duckdb_node_api = require("@duckdb/node-api");
4
+ let _mastra_core_error = require("@mastra/core/error");
5
+ let _mastra_core_storage = require("@mastra/core/storage");
6
+ let _mastra_core_vector = require("@mastra/core/vector");
7
+ let _mastra_core_features = require("@mastra/core/features");
8
+ //#region src/vector/filter-builder.ts
9
+ /**
10
+ * Escape a string for safe use in SQL.
11
+ */
11
12
  function escapeString(value) {
12
- return value.replace(/'/g, "''");
13
+ return value.replace(/'/g, "''");
13
14
  }
15
+ /**
16
+ * Convert a value to a SQL literal for comparison with JSON-extracted values.
17
+ * DuckDB's ->> operator returns the raw value without JSON quoting.
18
+ */
14
19
  function toSqlLiteral(value) {
15
- if (value === null || value === void 0) {
16
- return "NULL";
17
- }
18
- if (typeof value === "string") {
19
- return `'${escapeString(value)}'`;
20
- }
21
- if (typeof value === "number") {
22
- return String(value);
23
- }
24
- if (typeof value === "boolean") {
25
- return value ? "true" : "false";
26
- }
27
- return `'${escapeString(JSON.stringify(value))}'`;
20
+ if (value === null || value === void 0) return "NULL";
21
+ if (typeof value === "string") return `'${escapeString(value)}'`;
22
+ if (typeof value === "number") return String(value);
23
+ if (typeof value === "boolean") return value ? "true" : "false";
24
+ return `'${escapeString(JSON.stringify(value))}'`;
28
25
  }
26
+ /**
27
+ * Build a SQL WHERE clause from a filter object.
28
+ * Supports MongoDB-style query operators.
29
+ */
29
30
  function buildFilterClause(filter) {
30
- if (!filter || Object.keys(filter).length === 0) {
31
- return { clause: "1=1", params: [] };
32
- }
33
- const conditions = [];
34
- for (const [key, value] of Object.entries(filter)) {
35
- if (key === "$and") {
36
- if (Array.isArray(value) && value.length > 0) {
37
- const subConditions = value.map((subFilter) => buildFilterClause(subFilter));
38
- const andClause = subConditions.map((sc) => `(${sc.clause})`).join(" AND ");
39
- conditions.push(`(${andClause})`);
40
- }
41
- continue;
42
- }
43
- if (key === "$or") {
44
- if (Array.isArray(value) && value.length > 0) {
45
- const subConditions = value.map((subFilter) => buildFilterClause(subFilter));
46
- const orClause = subConditions.map((sc) => `(${sc.clause})`).join(" OR ");
47
- conditions.push(`(${orClause})`);
48
- }
49
- continue;
50
- }
51
- if (key === "$not") {
52
- if (typeof value === "object" && value !== null) {
53
- const subResult = buildFilterClause(value);
54
- conditions.push(`NOT (${subResult.clause})`);
55
- }
56
- continue;
57
- }
58
- if (key === "$nor") {
59
- if (Array.isArray(value) && value.length > 0) {
60
- const subConditions = value.map((subFilter) => buildFilterClause(subFilter));
61
- const norClause = subConditions.map((sc) => `(${sc.clause})`).join(" OR ");
62
- conditions.push(`NOT (${norClause})`);
63
- }
64
- continue;
65
- }
66
- const fieldPath = buildJsonPath(key);
67
- if (value === null) {
68
- conditions.push(`${fieldPath} IS NULL`);
69
- } else if (typeof value === "object" && !Array.isArray(value)) {
70
- const operatorResult = buildOperatorCondition(key, value);
71
- if (operatorResult) {
72
- conditions.push(operatorResult);
73
- }
74
- } else {
75
- conditions.push(`${fieldPath} = ${toSqlLiteral(value)}`);
76
- }
77
- }
78
- if (conditions.length === 0) {
79
- return { clause: "1=1", params: [] };
80
- }
81
- return { clause: conditions.join(" AND "), params: [] };
31
+ if (!filter || Object.keys(filter).length === 0) return {
32
+ clause: "1=1",
33
+ params: []
34
+ };
35
+ const conditions = [];
36
+ for (const [key, value] of Object.entries(filter)) {
37
+ if (key === "$and") {
38
+ if (Array.isArray(value) && value.length > 0) {
39
+ const andClause = value.map((subFilter) => buildFilterClause(subFilter)).map((sc) => `(${sc.clause})`).join(" AND ");
40
+ conditions.push(`(${andClause})`);
41
+ }
42
+ continue;
43
+ }
44
+ if (key === "$or") {
45
+ if (Array.isArray(value) && value.length > 0) {
46
+ const orClause = value.map((subFilter) => buildFilterClause(subFilter)).map((sc) => `(${sc.clause})`).join(" OR ");
47
+ conditions.push(`(${orClause})`);
48
+ }
49
+ continue;
50
+ }
51
+ if (key === "$not") {
52
+ if (typeof value === "object" && value !== null) {
53
+ const subResult = buildFilterClause(value);
54
+ conditions.push(`NOT (${subResult.clause})`);
55
+ }
56
+ continue;
57
+ }
58
+ if (key === "$nor") {
59
+ if (Array.isArray(value) && value.length > 0) {
60
+ const norClause = value.map((subFilter) => buildFilterClause(subFilter)).map((sc) => `(${sc.clause})`).join(" OR ");
61
+ conditions.push(`NOT (${norClause})`);
62
+ }
63
+ continue;
64
+ }
65
+ const fieldPath = buildJsonPath(key);
66
+ if (value === null) conditions.push(`${fieldPath} IS NULL`);
67
+ else if (typeof value === "object" && !Array.isArray(value)) {
68
+ const operatorResult = buildOperatorCondition(key, value);
69
+ if (operatorResult) conditions.push(operatorResult);
70
+ } else conditions.push(`${fieldPath} = ${toSqlLiteral(value)}`);
71
+ }
72
+ if (conditions.length === 0) return {
73
+ clause: "1=1",
74
+ params: []
75
+ };
76
+ return {
77
+ clause: conditions.join(" AND "),
78
+ params: []
79
+ };
82
80
  }
81
+ /**
82
+ * Build a JSON path expression for accessing nested fields in metadata.
83
+ * DuckDB uses json_extract_string for extracting string values from JSON.
84
+ */
83
85
  function buildJsonPath(field) {
84
- const parts = field.split(".");
85
- const jsonPath = "$." + parts.map((p) => escapeString(p)).join(".");
86
- return `json_extract_string(metadata, '${jsonPath}')`;
86
+ return `json_extract_string(metadata, '${"$." + field.split(".").map((p) => escapeString(p)).join(".")}')`;
87
87
  }
88
+ /**
89
+ * Build a condition from an operator object.
90
+ */
88
91
  function buildOperatorCondition(field, operators) {
89
- const conditions = [];
90
- const fieldPath = buildJsonPath(field);
91
- for (const [op, value] of Object.entries(operators)) {
92
- switch (op) {
93
- case "$eq":
94
- if (value === null) {
95
- conditions.push(`${fieldPath} IS NULL`);
96
- } else {
97
- conditions.push(`${fieldPath} = ${toSqlLiteral(value)}`);
98
- }
99
- break;
100
- case "$ne":
101
- if (value === null) {
102
- conditions.push(`${fieldPath} IS NOT NULL`);
103
- } else {
104
- conditions.push(`${fieldPath} != ${toSqlLiteral(value)}`);
105
- }
106
- break;
107
- case "$gt":
108
- conditions.push(`CAST(${fieldPath} AS DOUBLE) > ${toSqlLiteral(value)}`);
109
- break;
110
- case "$gte":
111
- conditions.push(`CAST(${fieldPath} AS DOUBLE) >= ${toSqlLiteral(value)}`);
112
- break;
113
- case "$lt":
114
- conditions.push(`CAST(${fieldPath} AS DOUBLE) < ${toSqlLiteral(value)}`);
115
- break;
116
- case "$lte":
117
- conditions.push(`CAST(${fieldPath} AS DOUBLE) <= ${toSqlLiteral(value)}`);
118
- break;
119
- case "$in":
120
- if (Array.isArray(value) && value.length > 0) {
121
- const jsonPath = `json_extract(metadata, '$.${escapeString(field)}')`;
122
- const literals = value.map((v) => toSqlLiteral(v)).join(", ");
123
- const stringLiterals = value.map((v) => toSqlLiteral(String(v))).join(", ");
124
- conditions.push(
125
- `(list_has_any(TRY_CAST(${jsonPath} AS VARCHAR[]), [${stringLiterals}]) OR ${fieldPath} IN (${literals}))`
126
- );
127
- } else {
128
- conditions.push("1=0");
129
- }
130
- break;
131
- case "$nin":
132
- if (Array.isArray(value) && value.length > 0) {
133
- const literals = value.map((v) => toSqlLiteral(v)).join(", ");
134
- conditions.push(`${fieldPath} NOT IN (${literals})`);
135
- }
136
- break;
137
- case "$exists":
138
- if (value) {
139
- conditions.push(`${fieldPath} IS NOT NULL`);
140
- } else {
141
- conditions.push(`${fieldPath} IS NULL`);
142
- }
143
- break;
144
- case "$contains":
145
- if (typeof value === "string") {
146
- conditions.push(`${fieldPath} LIKE '%${escapeString(value)}%'`);
147
- } else if (Array.isArray(value)) {
148
- const jsonPath = `json_extract(metadata, '$.${escapeString(field)}')`;
149
- const arrayConditions = value.map((v) => {
150
- return `list_contains(TRY_CAST(${jsonPath} AS VARCHAR[]), ${toSqlLiteral(v)})`;
151
- });
152
- conditions.push(`(${arrayConditions.join(" AND ")})`);
153
- } else {
154
- conditions.push(`${fieldPath} = ${toSqlLiteral(value)}`);
155
- }
156
- break;
157
- case "$all":
158
- if (Array.isArray(value) && value.length > 0) {
159
- const jsonPath = `json_extract(metadata, '$.${escapeString(field)}')`;
160
- const arrayConditions = value.map((v) => {
161
- return `list_contains(TRY_CAST(${jsonPath} AS VARCHAR[]), ${toSqlLiteral(v)})`;
162
- });
163
- conditions.push(`(${arrayConditions.join(" AND ")})`);
164
- }
165
- break;
166
- case "$not":
167
- if (typeof value === "object" && value !== null) {
168
- const subResult = buildOperatorCondition(field, value);
169
- if (subResult) {
170
- conditions.push(`NOT (${subResult})`);
171
- }
172
- }
173
- break;
174
- default:
175
- throw new Error(`Unsupported operator: ${op}`);
176
- }
177
- }
178
- if (conditions.length === 0) {
179
- return null;
180
- }
181
- return conditions.join(" AND ");
92
+ const conditions = [];
93
+ const fieldPath = buildJsonPath(field);
94
+ for (const [op, value] of Object.entries(operators)) switch (op) {
95
+ case "$eq":
96
+ if (value === null) conditions.push(`${fieldPath} IS NULL`);
97
+ else conditions.push(`${fieldPath} = ${toSqlLiteral(value)}`);
98
+ break;
99
+ case "$ne":
100
+ if (value === null) conditions.push(`${fieldPath} IS NOT NULL`);
101
+ else conditions.push(`${fieldPath} != ${toSqlLiteral(value)}`);
102
+ break;
103
+ case "$gt":
104
+ conditions.push(`CAST(${fieldPath} AS DOUBLE) > ${toSqlLiteral(value)}`);
105
+ break;
106
+ case "$gte":
107
+ conditions.push(`CAST(${fieldPath} AS DOUBLE) >= ${toSqlLiteral(value)}`);
108
+ break;
109
+ case "$lt":
110
+ conditions.push(`CAST(${fieldPath} AS DOUBLE) < ${toSqlLiteral(value)}`);
111
+ break;
112
+ case "$lte":
113
+ conditions.push(`CAST(${fieldPath} AS DOUBLE) <= ${toSqlLiteral(value)}`);
114
+ break;
115
+ case "$in":
116
+ if (Array.isArray(value) && value.length > 0) {
117
+ const jsonPath = `json_extract(metadata, '$.${escapeString(field)}')`;
118
+ const literals = value.map((v) => toSqlLiteral(v)).join(", ");
119
+ const stringLiterals = value.map((v) => toSqlLiteral(String(v))).join(", ");
120
+ conditions.push(`(list_has_any(TRY_CAST(${jsonPath} AS VARCHAR[]), [${stringLiterals}]) OR ${fieldPath} IN (${literals}))`);
121
+ } else conditions.push("1=0");
122
+ break;
123
+ case "$nin":
124
+ if (Array.isArray(value) && value.length > 0) {
125
+ const literals = value.map((v) => toSqlLiteral(v)).join(", ");
126
+ conditions.push(`${fieldPath} NOT IN (${literals})`);
127
+ }
128
+ break;
129
+ case "$exists":
130
+ if (value) conditions.push(`${fieldPath} IS NOT NULL`);
131
+ else conditions.push(`${fieldPath} IS NULL`);
132
+ break;
133
+ case "$contains":
134
+ if (typeof value === "string") conditions.push(`${fieldPath} LIKE '%${escapeString(value)}%'`);
135
+ else if (Array.isArray(value)) {
136
+ const jsonPath = `json_extract(metadata, '$.${escapeString(field)}')`;
137
+ const arrayConditions = value.map((v) => {
138
+ return `list_contains(TRY_CAST(${jsonPath} AS VARCHAR[]), ${toSqlLiteral(v)})`;
139
+ });
140
+ conditions.push(`(${arrayConditions.join(" AND ")})`);
141
+ } else conditions.push(`${fieldPath} = ${toSqlLiteral(value)}`);
142
+ break;
143
+ case "$all":
144
+ if (Array.isArray(value) && value.length > 0) {
145
+ const jsonPath = `json_extract(metadata, '$.${escapeString(field)}')`;
146
+ const arrayConditions = value.map((v) => {
147
+ return `list_contains(TRY_CAST(${jsonPath} AS VARCHAR[]), ${toSqlLiteral(v)})`;
148
+ });
149
+ conditions.push(`(${arrayConditions.join(" AND ")})`);
150
+ }
151
+ break;
152
+ case "$not":
153
+ if (typeof value === "object" && value !== null) {
154
+ const subResult = buildOperatorCondition(field, value);
155
+ if (subResult) conditions.push(`NOT (${subResult})`);
156
+ }
157
+ break;
158
+ default: throw new Error(`Unsupported operator: ${op}`);
159
+ }
160
+ if (conditions.length === 0) return null;
161
+ return conditions.join(" AND ");
182
162
  }
183
-
184
- // src/vector/index.ts
185
- var DuckDBVector = class extends vector.MastraVector {
186
- config;
187
- instance = null;
188
- initialized = false;
189
- initPromise = null;
190
- constructor(config) {
191
- super({ id: config.id });
192
- this.config = {
193
- path: ":memory:",
194
- dimensions: 1536,
195
- metric: "cosine",
196
- ...config
197
- };
198
- }
199
- /**
200
- * Initialize the database connection and load required extensions.
201
- */
202
- async initialize() {
203
- if (this.initialized && this.instance) return;
204
- if (this.initPromise) {
205
- await this.initPromise;
206
- if (!this.instance) {
207
- this.initPromise = null;
208
- this.initialized = false;
209
- } else {
210
- return;
211
- }
212
- }
213
- this.initPromise = (async () => {
214
- try {
215
- this.instance = await nodeApi.DuckDBInstance.create(this.config.path);
216
- const connection = await this.instance.connect();
217
- try {
218
- await connection.run("INSTALL vss;");
219
- await connection.run("LOAD vss;");
220
- } catch {
221
- try {
222
- await connection.run("LOAD vss;");
223
- } catch {
224
- this.logger.warn("VSS extension not available, using basic array operations");
225
- }
226
- }
227
- this.initialized = true;
228
- } catch (error) {
229
- this.instance = null;
230
- this.initialized = false;
231
- this.initPromise = null;
232
- throw error;
233
- }
234
- })();
235
- return this.initPromise;
236
- }
237
- /**
238
- * Get a database connection.
239
- */
240
- async getConnection() {
241
- await this.initialize();
242
- if (!this.instance) {
243
- throw new Error("DuckDB instance not initialized");
244
- }
245
- return this.instance.connect();
246
- }
247
- /**
248
- * Execute a SQL query and return results.
249
- */
250
- async runQuery(sql, params = []) {
251
- const connection = await this.getConnection();
252
- try {
253
- let paramIndex = 0;
254
- const preparedSql = sql.replace(/\?/g, () => `$${++paramIndex}`);
255
- const stmt = await connection.prepare(preparedSql);
256
- for (let i = 0; i < params.length; i++) {
257
- chunkSMRZJTCI_cjs.bindParam(stmt, i + 1, params[i]);
258
- }
259
- const result = await stmt.run();
260
- const rows = await result.getRows();
261
- const columns = result.columnNames();
262
- return rows.map((row) => {
263
- const obj = {};
264
- columns.forEach((col, i) => {
265
- obj[col] = row[i];
266
- });
267
- return obj;
268
- });
269
- } finally {
270
- }
271
- }
272
- /**
273
- * Execute a SQL statement without returning results.
274
- */
275
- async runStatement(sql, params = []) {
276
- const connection = await this.getConnection();
277
- try {
278
- if (params.length === 0) {
279
- await connection.run(sql);
280
- } else {
281
- let paramIndex = 0;
282
- const preparedSql = sql.replace(/\?/g, () => `$${++paramIndex}`);
283
- const stmt = await connection.prepare(preparedSql);
284
- for (let i = 0; i < params.length; i++) {
285
- chunkSMRZJTCI_cjs.bindParam(stmt, i + 1, params[i]);
286
- }
287
- await stmt.run();
288
- }
289
- } finally {
290
- }
291
- }
292
- /**
293
- * Validate and escape a SQL identifier (table name, column name).
294
- */
295
- escapeIdentifier(name) {
296
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
297
- throw new Error(`Invalid identifier: ${name}. Only alphanumeric characters and underscores are allowed.`);
298
- }
299
- return `"${name}"`;
300
- }
301
- /**
302
- * Get the distance function for the configured metric.
303
- */
304
- getDistanceFunction() {
305
- switch (this.config.metric) {
306
- case "cosine":
307
- return "array_cosine_distance";
308
- case "euclidean":
309
- return "array_distance";
310
- case "dotproduct":
311
- return "array_inner_product";
312
- default:
313
- return "array_cosine_distance";
314
- }
315
- }
316
- /** Perform a vector similarity search with optional metadata filtering. */
317
- async query(params) {
318
- await this.initialize();
319
- const { indexName, queryVector, topK = 10, filter, includeVector = false } = params;
320
- if (!queryVector) {
321
- throw new error.MastraError({
322
- id: storage.createVectorErrorId("DUCKDB", "QUERY", "MISSING_VECTOR"),
323
- text: "queryVector is required for DuckDB queries. Metadata-only queries are not supported by this vector store.",
324
- domain: error.ErrorDomain.STORAGE,
325
- category: error.ErrorCategory.USER,
326
- details: { indexName }
327
- });
328
- }
329
- vector.validateTopK("DUCKDB", topK);
330
- const tableName = this.escapeIdentifier(indexName);
331
- const distanceFunc = this.getDistanceFunction();
332
- const vectorLiteral = `[${queryVector.join(", ")}]::FLOAT[${queryVector.length}]`;
333
- const { clause: filterClause } = filter ? buildFilterClause(filter) : { clause: "" };
334
- const selectCols = includeVector ? "id, vector, metadata, distance" : "id, metadata, distance";
335
- const sql = `
336
- SELECT ${selectCols}
163
+ //#endregion
164
+ //#region src/vector/index.ts
165
+ /**
166
+ * DuckDB vector store implementation for Mastra.
167
+ *
168
+ * Provides embedded high-performance vector storage with HNSW indexing
169
+ * using the DuckDB VSS extension for vector similarity search.
170
+ *
171
+ * Key features:
172
+ * - Embedded database (no server required)
173
+ * - HNSW indexing for fast similarity search
174
+ * - SQL interface for metadata filtering
175
+ * - Native Parquet support
176
+ */
177
+ var DuckDBVector = class extends _mastra_core_vector.MastraVector {
178
+ config;
179
+ instance = null;
180
+ initialized = false;
181
+ initPromise = null;
182
+ constructor(config) {
183
+ super({ id: config.id });
184
+ this.config = {
185
+ path: ":memory:",
186
+ dimensions: 1536,
187
+ metric: "cosine",
188
+ ...config
189
+ };
190
+ }
191
+ /**
192
+ * Initialize the database connection and load required extensions.
193
+ */
194
+ async initialize() {
195
+ if (this.initialized && this.instance) return;
196
+ if (this.initPromise) {
197
+ await this.initPromise;
198
+ if (!this.instance) {
199
+ this.initPromise = null;
200
+ this.initialized = false;
201
+ } else return;
202
+ }
203
+ this.initPromise = (async () => {
204
+ try {
205
+ this.instance = await _duckdb_node_api.DuckDBInstance.create(this.config.path);
206
+ const connection = await this.instance.connect();
207
+ try {
208
+ await connection.run("INSTALL vss;");
209
+ await connection.run("LOAD vss;");
210
+ } catch {
211
+ try {
212
+ await connection.run("LOAD vss;");
213
+ } catch {
214
+ this.logger.warn("VSS extension not available, using basic array operations");
215
+ }
216
+ }
217
+ this.initialized = true;
218
+ } catch (error) {
219
+ this.instance = null;
220
+ this.initialized = false;
221
+ this.initPromise = null;
222
+ throw error;
223
+ }
224
+ })();
225
+ return this.initPromise;
226
+ }
227
+ /**
228
+ * Get a database connection.
229
+ */
230
+ async getConnection() {
231
+ await this.initialize();
232
+ if (!this.instance) throw new Error("DuckDB instance not initialized");
233
+ return this.instance.connect();
234
+ }
235
+ /**
236
+ * Execute a SQL query and return results.
237
+ */
238
+ async runQuery(sql, params = []) {
239
+ const connection = await this.getConnection();
240
+ try {
241
+ let paramIndex = 0;
242
+ const preparedSql = sql.replace(/\?/g, () => `$${++paramIndex}`);
243
+ const stmt = await connection.prepare(preparedSql);
244
+ for (let i = 0; i < params.length; i++) require_db.bindParam(stmt, i + 1, params[i]);
245
+ const result = await stmt.run();
246
+ const rows = await result.getRows();
247
+ const columns = result.columnNames();
248
+ return rows.map((row) => {
249
+ const obj = {};
250
+ columns.forEach((col, i) => {
251
+ obj[col] = row[i];
252
+ });
253
+ return obj;
254
+ });
255
+ } finally {}
256
+ }
257
+ /**
258
+ * Execute a SQL statement without returning results.
259
+ */
260
+ async runStatement(sql, params = []) {
261
+ const connection = await this.getConnection();
262
+ try {
263
+ if (params.length === 0) await connection.run(sql);
264
+ else {
265
+ let paramIndex = 0;
266
+ const preparedSql = sql.replace(/\?/g, () => `$${++paramIndex}`);
267
+ const stmt = await connection.prepare(preparedSql);
268
+ for (let i = 0; i < params.length; i++) require_db.bindParam(stmt, i + 1, params[i]);
269
+ await stmt.run();
270
+ }
271
+ } finally {}
272
+ }
273
+ /**
274
+ * Validate and escape a SQL identifier (table name, column name).
275
+ */
276
+ escapeIdentifier(name) {
277
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) throw new Error(`Invalid identifier: ${name}. Only alphanumeric characters and underscores are allowed.`);
278
+ return `"${name}"`;
279
+ }
280
+ /**
281
+ * Get the distance function for the configured metric.
282
+ */
283
+ getDistanceFunction() {
284
+ switch (this.config.metric) {
285
+ case "cosine": return "array_cosine_distance";
286
+ case "euclidean": return "array_distance";
287
+ case "dotproduct": return "array_inner_product";
288
+ default: return "array_cosine_distance";
289
+ }
290
+ }
291
+ /** Perform a vector similarity search with optional metadata filtering. */
292
+ async query(params) {
293
+ await this.initialize();
294
+ const { indexName, queryVector, topK = 10, filter, includeVector = false } = params;
295
+ if (!queryVector) throw new _mastra_core_error.MastraError({
296
+ id: (0, _mastra_core_storage.createVectorErrorId)("DUCKDB", "QUERY", "MISSING_VECTOR"),
297
+ text: "queryVector is required for DuckDB queries. Metadata-only queries are not supported by this vector store.",
298
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
299
+ category: _mastra_core_error.ErrorCategory.USER,
300
+ details: { indexName }
301
+ });
302
+ (0, _mastra_core_vector.validateTopK)("DUCKDB", topK);
303
+ const tableName = this.escapeIdentifier(indexName);
304
+ const distanceFunc = this.getDistanceFunction();
305
+ const vectorLiteral = `[${queryVector.join(", ")}]::FLOAT[${queryVector.length}]`;
306
+ const { clause: filterClause } = filter ? buildFilterClause(filter) : { clause: "" };
307
+ const sql = `
308
+ SELECT ${includeVector ? "id, vector, metadata, distance" : "id, metadata, distance"}
337
309
  FROM (
338
310
  SELECT
339
311
  id,
@@ -346,509 +318,440 @@ var DuckDBVector = class extends vector.MastraVector {
346
318
  ORDER BY distance ${this.config.metric === "dotproduct" ? "DESC" : "ASC"}
347
319
  LIMIT ${topK}
348
320
  `;
349
- const connection = await this.getConnection();
350
- const result = await connection.run(sql);
351
- const rows = await result.getRows();
352
- const columns = result.columnNames();
353
- return rows.map((row) => {
354
- const rowObj = {};
355
- columns.forEach((col, i) => {
356
- rowObj[col] = row[i];
357
- });
358
- const distance = rowObj.distance;
359
- const score = this.config.metric === "cosine" ? 1 - distance : this.config.metric === "euclidean" ? 1 / (1 + distance) : distance;
360
- const metadata = typeof rowObj.metadata === "string" ? JSON.parse(rowObj.metadata) : rowObj.metadata;
361
- const queryResult = {
362
- id: rowObj.id,
363
- score,
364
- metadata
365
- };
366
- if (includeVector && rowObj.vector) {
367
- queryResult.vector = Array.isArray(rowObj.vector) ? rowObj.vector : JSON.parse(rowObj.vector);
368
- }
369
- return queryResult;
370
- });
371
- }
372
- /** Insert or replace vectors with metadata. Returns the vector IDs. */
373
- async upsert(params) {
374
- await this.initialize();
375
- const { indexName, vectors, metadata, ids } = params;
376
- vector.validateUpsertInput("DUCKDB", vectors, metadata, ids);
377
- const tableName = this.escapeIdentifier(indexName);
378
- const vectorIds = ids || vectors.map(() => crypto.randomUUID());
379
- for (let i = 0; i < vectors.length; i++) {
380
- const id = vectorIds[i];
381
- const vector = vectors[i];
382
- const meta = metadata?.[i] || {};
383
- const vectorLiteral = `[${vector.join(", ")}]::FLOAT[${vector.length}]`;
384
- const metadataJson = JSON.stringify(meta);
385
- const sql = `
321
+ const result = await (await this.getConnection()).run(sql);
322
+ const rows = await result.getRows();
323
+ const columns = result.columnNames();
324
+ return rows.map((row) => {
325
+ const rowObj = {};
326
+ columns.forEach((col, i) => {
327
+ rowObj[col] = row[i];
328
+ });
329
+ const distance = rowObj.distance;
330
+ const score = this.config.metric === "cosine" ? 1 - distance : this.config.metric === "euclidean" ? 1 / (1 + distance) : distance;
331
+ const metadata = typeof rowObj.metadata === "string" ? JSON.parse(rowObj.metadata) : rowObj.metadata;
332
+ const queryResult = {
333
+ id: rowObj.id,
334
+ score,
335
+ metadata
336
+ };
337
+ if (includeVector && rowObj.vector) queryResult.vector = Array.isArray(rowObj.vector) ? rowObj.vector : JSON.parse(rowObj.vector);
338
+ return queryResult;
339
+ });
340
+ }
341
+ /** Insert or replace vectors with metadata. Returns the vector IDs. */
342
+ async upsert(params) {
343
+ await this.initialize();
344
+ const { indexName, vectors, metadata, ids } = params;
345
+ (0, _mastra_core_vector.validateUpsertInput)("DUCKDB", vectors, metadata, ids);
346
+ const tableName = this.escapeIdentifier(indexName);
347
+ const vectorIds = ids || vectors.map(() => crypto.randomUUID());
348
+ for (let i = 0; i < vectors.length; i++) {
349
+ const id = vectorIds[i];
350
+ const vector = vectors[i];
351
+ const meta = metadata?.[i] || {};
352
+ const sql = `
386
353
  INSERT OR REPLACE INTO ${tableName} (id, vector, metadata)
387
- VALUES (?, ${vectorLiteral}, '${metadataJson.replace(/'/g, "''")}')
354
+ VALUES (?, ${`[${vector.join(", ")}]::FLOAT[${vector.length}]`}, '${JSON.stringify(meta).replace(/'/g, "''")}')
388
355
  `;
389
- await this.runStatement(sql, [id]);
390
- }
391
- return vectorIds;
392
- }
393
- /** Create a vector table with HNSW index for similarity search. */
394
- async createIndex(params) {
395
- await this.initialize();
396
- const { indexName, dimension, metric } = params;
397
- const tableName = this.escapeIdentifier(indexName);
398
- if (metric) {
399
- this.config.metric = metric;
400
- }
401
- const connection = await this.getConnection();
402
- const createTableSql = `
356
+ await this.runStatement(sql, [id]);
357
+ }
358
+ return vectorIds;
359
+ }
360
+ /** Create a vector table with HNSW index for similarity search. */
361
+ async createIndex(params) {
362
+ await this.initialize();
363
+ const { indexName, dimension, metric } = params;
364
+ const tableName = this.escapeIdentifier(indexName);
365
+ if (metric) this.config.metric = metric;
366
+ const connection = await this.getConnection();
367
+ const createTableSql = `
403
368
  CREATE TABLE IF NOT EXISTS ${tableName} (
404
369
  id VARCHAR PRIMARY KEY,
405
370
  vector FLOAT[${dimension}],
406
371
  metadata JSON
407
372
  )
408
373
  `;
409
- await connection.run(createTableSql);
410
- try {
411
- const indexNameStr = `${indexName}_hnsw_idx`;
412
- const createIndexSql = `
413
- CREATE INDEX IF NOT EXISTS "${indexNameStr}"
374
+ await connection.run(createTableSql);
375
+ try {
376
+ const createIndexSql = `
377
+ CREATE INDEX IF NOT EXISTS "${`${indexName}_hnsw_idx`}"
414
378
  ON ${tableName}
415
379
  USING HNSW (vector)
416
380
  `;
417
- await connection.run(createIndexSql);
418
- } catch {
419
- this.logger.warn(`Could not create HNSW index for ${indexName}, falling back to linear scan`);
420
- }
421
- }
422
- /** List all vector table names in the database. */
423
- async listIndexes() {
424
- await this.initialize();
425
- const connection = await this.getConnection();
426
- const result = await connection.run(`
381
+ await connection.run(createIndexSql);
382
+ } catch {
383
+ this.logger.warn(`Could not create HNSW index for ${indexName}, falling back to linear scan`);
384
+ }
385
+ }
386
+ /** List all vector table names in the database. */
387
+ async listIndexes() {
388
+ await this.initialize();
389
+ return (await (await (await this.getConnection()).run(`
427
390
  SELECT table_name
428
391
  FROM information_schema.tables
429
392
  WHERE table_schema = 'main'
430
393
  AND table_type = 'BASE TABLE'
431
- `);
432
- const rows = await result.getRows();
433
- return rows.map((row) => row[0]);
434
- }
435
- /** Return dimension, row count, and metric for a vector index. */
436
- async describeIndex(params) {
437
- await this.initialize();
438
- const { indexName } = params;
439
- const tableName = this.escapeIdentifier(indexName);
440
- const connection = await this.getConnection();
441
- const schemaResult = await connection.run(`
394
+ `)).getRows()).map((row) => row[0]);
395
+ }
396
+ /** Return dimension, row count, and metric for a vector index. */
397
+ async describeIndex(params) {
398
+ await this.initialize();
399
+ const { indexName } = params;
400
+ const tableName = this.escapeIdentifier(indexName);
401
+ const connection = await this.getConnection();
402
+ const schemaRows = await (await connection.run(`
442
403
  SELECT data_type
443
404
  FROM information_schema.columns
444
405
  WHERE table_name = '${indexName}' AND column_name = 'vector'
445
- `);
446
- const schemaRows = await schemaResult.getRows();
447
- if (schemaRows.length === 0) {
448
- throw new Error(`Index "${indexName}" not found`);
449
- }
450
- const dataType = schemaRows[0][0];
451
- const dimensionMatch = dataType.match(/\[(\d+)\]/);
452
- const dimension = dimensionMatch ? parseInt(dimensionMatch[1], 10) : 0;
453
- const countResult = await connection.run(`SELECT COUNT(*) as count FROM ${tableName}`);
454
- const countRows = await countResult.getRows();
455
- const count = Number(countRows[0]?.[0] || 0);
456
- return {
457
- dimension,
458
- count,
459
- metric: this.config.metric || "cosine"
460
- };
461
- }
462
- /** Drop a vector table and its HNSW index. */
463
- async deleteIndex(params) {
464
- await this.initialize();
465
- const { indexName } = params;
466
- const tableName = this.escapeIdentifier(indexName);
467
- const connection = await this.getConnection();
468
- await connection.run(`DROP TABLE IF EXISTS ${tableName}`);
469
- }
470
- /** Update a vector's embedding and/or metadata by ID or filter. */
471
- async updateVector(params) {
472
- await this.initialize();
473
- const { indexName, update } = params;
474
- const tableName = this.escapeIdentifier(indexName);
475
- if (!update.vector && !update.metadata) {
476
- throw new Error("No updates provided");
477
- }
478
- const hasId = "id" in params && params.id;
479
- const hasFilter = "filter" in params && params.filter;
480
- if (hasId && hasFilter) {
481
- throw new Error("id and filter are mutually exclusive - provide only one");
482
- }
483
- if (!hasId && !hasFilter) {
484
- throw new Error("Either id or filter must be provided");
485
- }
486
- const updates = [];
487
- if (update.vector) {
488
- updates.push(`vector = [${update.vector.join(", ")}]::FLOAT[${update.vector.length}]`);
489
- }
490
- if (update.metadata) {
491
- const metadataJson = JSON.stringify(update.metadata).replace(/'/g, "''");
492
- updates.push(`metadata = '${metadataJson}'`);
493
- }
494
- if (hasId) {
495
- const sql = `UPDATE ${tableName} SET ${updates.join(", ")} WHERE id = ?`;
496
- await this.runStatement(sql, [params.id]);
497
- } else if (hasFilter) {
498
- const filter = params.filter;
499
- if (Object.keys(filter).length === 0) {
500
- throw new Error("Cannot update with empty filter");
501
- }
502
- const { clause } = buildFilterClause(filter);
503
- await this.runStatement(`UPDATE ${tableName} SET ${updates.join(", ")} WHERE ${clause}`);
504
- }
505
- }
506
- /** Delete a single vector by ID. */
507
- async deleteVector(params) {
508
- await this.initialize();
509
- const { indexName, id } = params;
510
- const tableName = this.escapeIdentifier(indexName);
511
- const sql = `DELETE FROM ${tableName} WHERE id = ?`;
512
- await this.runStatement(sql, [id]);
513
- }
514
- /** Delete multiple vectors by IDs or metadata filter (mutually exclusive). */
515
- async deleteVectors(params) {
516
- await this.initialize();
517
- const { indexName, ids, filter } = params;
518
- const tableName = this.escapeIdentifier(indexName);
519
- if (!ids && !filter) {
520
- throw new Error("Either filter or ids must be provided");
521
- }
522
- if (ids && filter) {
523
- throw new Error("ids and filter are mutually exclusive - provide only one");
524
- }
525
- if (ids) {
526
- if (ids.length === 0) {
527
- throw new Error("Cannot delete with empty ids array");
528
- }
529
- const placeholders = ids.map(() => "?").join(", ");
530
- const sql = `DELETE FROM ${tableName} WHERE id IN (${placeholders})`;
531
- await this.runStatement(sql, ids);
532
- } else if (filter) {
533
- if (Object.keys(filter).length === 0) {
534
- throw new Error("Cannot delete with empty filter");
535
- }
536
- const { clause } = buildFilterClause(filter);
537
- await this.runStatement(`DELETE FROM ${tableName} WHERE ${clause}`);
538
- }
539
- }
540
- /**
541
- * Close the database connection.
542
- * After closing, the vector store can be reused by calling methods that require initialization.
543
- */
544
- async close() {
545
- if (this.instance) {
546
- this.instance = null;
547
- this.initialized = false;
548
- this.initPromise = null;
549
- }
550
- }
406
+ `)).getRows();
407
+ if (schemaRows.length === 0) throw new Error(`Index "${indexName}" not found`);
408
+ const dimensionMatch = schemaRows[0][0].match(/\[(\d+)\]/);
409
+ const dimension = dimensionMatch ? parseInt(dimensionMatch[1], 10) : 0;
410
+ const countRows = await (await connection.run(`SELECT COUNT(*) as count FROM ${tableName}`)).getRows();
411
+ return {
412
+ dimension,
413
+ count: Number(countRows[0]?.[0] || 0),
414
+ metric: this.config.metric || "cosine"
415
+ };
416
+ }
417
+ /** Drop a vector table and its HNSW index. */
418
+ async deleteIndex(params) {
419
+ await this.initialize();
420
+ const { indexName } = params;
421
+ const tableName = this.escapeIdentifier(indexName);
422
+ await (await this.getConnection()).run(`DROP TABLE IF EXISTS ${tableName}`);
423
+ }
424
+ /** Update a vector's embedding and/or metadata by ID or filter. */
425
+ async updateVector(params) {
426
+ await this.initialize();
427
+ const { indexName, update } = params;
428
+ const tableName = this.escapeIdentifier(indexName);
429
+ if (!update.vector && !update.metadata) throw new Error("No updates provided");
430
+ const hasId = "id" in params && params.id;
431
+ const hasFilter = "filter" in params && params.filter;
432
+ if (hasId && hasFilter) throw new Error("id and filter are mutually exclusive - provide only one");
433
+ if (!hasId && !hasFilter) throw new Error("Either id or filter must be provided");
434
+ const updates = [];
435
+ if (update.vector) updates.push(`vector = [${update.vector.join(", ")}]::FLOAT[${update.vector.length}]`);
436
+ if (update.metadata) {
437
+ const metadataJson = JSON.stringify(update.metadata).replace(/'/g, "''");
438
+ updates.push(`metadata = '${metadataJson}'`);
439
+ }
440
+ if (hasId) {
441
+ const sql = `UPDATE ${tableName} SET ${updates.join(", ")} WHERE id = ?`;
442
+ await this.runStatement(sql, [params.id]);
443
+ } else if (hasFilter) {
444
+ const filter = params.filter;
445
+ if (Object.keys(filter).length === 0) throw new Error("Cannot update with empty filter");
446
+ const { clause } = buildFilterClause(filter);
447
+ await this.runStatement(`UPDATE ${tableName} SET ${updates.join(", ")} WHERE ${clause}`);
448
+ }
449
+ }
450
+ /** Delete a single vector by ID. */
451
+ async deleteVector(params) {
452
+ await this.initialize();
453
+ const { indexName, id } = params;
454
+ const sql = `DELETE FROM ${this.escapeIdentifier(indexName)} WHERE id = ?`;
455
+ await this.runStatement(sql, [id]);
456
+ }
457
+ /** Delete multiple vectors by IDs or metadata filter (mutually exclusive). */
458
+ async deleteVectors(params) {
459
+ await this.initialize();
460
+ const { indexName, ids, filter } = params;
461
+ const tableName = this.escapeIdentifier(indexName);
462
+ if (!ids && !filter) throw new Error("Either filter or ids must be provided");
463
+ if (ids && filter) throw new Error("ids and filter are mutually exclusive - provide only one");
464
+ if (ids) {
465
+ if (ids.length === 0) throw new Error("Cannot delete with empty ids array");
466
+ const sql = `DELETE FROM ${tableName} WHERE id IN (${ids.map(() => "?").join(", ")})`;
467
+ await this.runStatement(sql, ids);
468
+ } else if (filter) {
469
+ if (Object.keys(filter).length === 0) throw new Error("Cannot delete with empty filter");
470
+ const { clause } = buildFilterClause(filter);
471
+ await this.runStatement(`DELETE FROM ${tableName} WHERE ${clause}`);
472
+ }
473
+ }
474
+ /**
475
+ * Close the database connection.
476
+ * After closing, the vector store can be reused by calling methods that require initialization.
477
+ */
478
+ async close() {
479
+ if (this.instance) {
480
+ this.instance = null;
481
+ this.initialized = false;
482
+ this.initPromise = null;
483
+ }
484
+ }
551
485
  };
552
- var OBSERVABILITY_UPGRADE_MESSAGE = "DuckDB observability storage requires `@mastra/core` with observability storage support. Upgrade `@mastra/core` to use this store.";
553
- var OBSERVABILITY_DELTA_POLLING_FEATURE = "observability-delta-polling";
554
- var DUCKDB_OBSERVABILITY_FEATURES = ["delta-polling"];
486
+ //#endregion
487
+ //#region src/storage/index.ts
488
+ const OBSERVABILITY_UPGRADE_MESSAGE = "DuckDB observability storage requires `@mastra/core` with observability storage support. Upgrade `@mastra/core` to use this store.";
489
+ const OBSERVABILITY_DELTA_POLLING_FEATURE = "observability-delta-polling";
490
+ const DUCKDB_OBSERVABILITY_FEATURES = ["delta-polling"];
555
491
  function isObservabilityCompatibilityError(error) {
556
- if (!(error instanceof Error)) {
557
- return false;
558
- }
559
- return error.message.includes("@mastra/core") && (error.message.includes("does not provide an export named") || error.message.includes("No matching export") || error.message.includes("Cannot find module") || error.message.includes("Cannot find package"));
492
+ if (!(error instanceof Error)) return false;
493
+ return error.message.includes("@mastra/core") && (error.message.includes("does not provide an export named") || error.message.includes("No matching export") || error.message.includes("Cannot find module") || error.message.includes("Cannot find package"));
560
494
  }
561
- var ObservabilityStorageDuckDB = class extends storage.ObservabilityStorage {
562
- db;
563
- delegate = null;
564
- loadPromise = null;
565
- unavailableError = null;
566
- constructor(config) {
567
- super();
568
- this.db = config.db;
569
- }
570
- createUnavailableError(cause) {
571
- return new error.MastraError(
572
- {
573
- id: "OBSERVABILITY_STORAGE_DUCKDB_CORE_UPGRADE_NOT_IMPLEMENTED",
574
- domain: error.ErrorDomain.MASTRA_OBSERVABILITY,
575
- category: error.ErrorCategory.SYSTEM,
576
- text: OBSERVABILITY_UPGRADE_MESSAGE
577
- },
578
- cause
579
- );
580
- }
581
- async loadDelegate() {
582
- if (this.delegate) {
583
- return this.delegate;
584
- }
585
- if (this.unavailableError) {
586
- return null;
587
- }
588
- if (!this.loadPromise) {
589
- this.loadPromise = import('./observability-V2KYD7UF.cjs').then(({ ObservabilityStorageDuckDB: ObservabilityStorageDuckDB2 }) => {
590
- const delegate = new ObservabilityStorageDuckDB2({ db: this.db });
591
- this.delegate = delegate;
592
- return delegate;
593
- }).catch((error) => {
594
- if (isObservabilityCompatibilityError(error)) {
595
- this.unavailableError = this.createUnavailableError(error);
596
- return null;
597
- }
598
- throw error;
599
- });
600
- }
601
- return this.loadPromise;
602
- }
603
- async requireDelegate() {
604
- const delegate = await this.loadDelegate();
605
- if (!delegate) {
606
- throw this.unavailableError ?? this.createUnavailableError();
607
- }
608
- return delegate;
609
- }
610
- get observabilityStrategy() {
611
- return this.delegate?.observabilityStrategy ?? {
612
- preferred: "event-sourced",
613
- supported: ["event-sourced"]
614
- };
615
- }
616
- get tracingStrategy() {
617
- return this.delegate?.tracingStrategy ?? this.observabilityStrategy;
618
- }
619
- getFeatures() {
620
- if (!features.coreFeatures.has(OBSERVABILITY_DELTA_POLLING_FEATURE)) {
621
- return void 0;
622
- }
623
- return DUCKDB_OBSERVABILITY_FEATURES;
624
- }
625
- async init(...args) {
626
- const delegate = await this.loadDelegate();
627
- if (!delegate) {
628
- return;
629
- }
630
- return delegate.init(...args);
631
- }
632
- async migrateSpans(...args) {
633
- const delegate = await this.requireDelegate();
634
- return delegate.migrateSpans(...args);
635
- }
636
- async dangerouslyClearAll(...args) {
637
- const delegate = await this.requireDelegate();
638
- return delegate.dangerouslyClearAll(...args);
639
- }
640
- async createSpan(...args) {
641
- const delegate = await this.requireDelegate();
642
- return delegate.createSpan(...args);
643
- }
644
- async updateSpan(...args) {
645
- const delegate = await this.requireDelegate();
646
- return delegate.updateSpan(...args);
647
- }
648
- async getSpan(...args) {
649
- const delegate = await this.requireDelegate();
650
- return delegate.getSpan(...args);
651
- }
652
- async getSpans(...args) {
653
- const delegate = await this.requireDelegate();
654
- return delegate.getSpans(...args);
655
- }
656
- async getRootSpan(...args) {
657
- const delegate = await this.requireDelegate();
658
- return delegate.getRootSpan(...args);
659
- }
660
- async getTrace(...args) {
661
- const delegate = await this.requireDelegate();
662
- return delegate.getTrace(...args);
663
- }
664
- async getTraceLight(...args) {
665
- const delegate = await this.requireDelegate();
666
- return delegate.getTraceLight(...args);
667
- }
668
- async listTraces(...args) {
669
- const delegate = await this.requireDelegate();
670
- return delegate.listTraces(...args);
671
- }
672
- async listTracesLight(...args) {
673
- const delegate = await this.requireDelegate();
674
- return delegate.listTracesLight(...args);
675
- }
676
- async listBranches(...args) {
677
- const delegate = await this.requireDelegate();
678
- return delegate.listBranches(...args);
679
- }
680
- async batchCreateSpans(...args) {
681
- const delegate = await this.requireDelegate();
682
- return delegate.batchCreateSpans(...args);
683
- }
684
- async batchUpdateSpans(...args) {
685
- const delegate = await this.requireDelegate();
686
- return delegate.batchUpdateSpans(...args);
687
- }
688
- async batchDeleteTraces(...args) {
689
- const delegate = await this.requireDelegate();
690
- return delegate.batchDeleteTraces(...args);
691
- }
692
- async batchCreateLogs(...args) {
693
- const delegate = await this.requireDelegate();
694
- return delegate.batchCreateLogs(...args);
695
- }
696
- async listLogs(...args) {
697
- const delegate = await this.requireDelegate();
698
- return delegate.listLogs(...args);
699
- }
700
- async batchCreateMetrics(...args) {
701
- const delegate = await this.requireDelegate();
702
- return delegate.batchCreateMetrics(...args);
703
- }
704
- async listMetrics(...args) {
705
- const delegate = await this.requireDelegate();
706
- return delegate.listMetrics(...args);
707
- }
708
- async getMetricAggregate(...args) {
709
- const delegate = await this.requireDelegate();
710
- return delegate.getMetricAggregate(...args);
711
- }
712
- async getMetricBreakdown(...args) {
713
- const delegate = await this.requireDelegate();
714
- return delegate.getMetricBreakdown(...args);
715
- }
716
- async getMetricTimeSeries(...args) {
717
- const delegate = await this.requireDelegate();
718
- return delegate.getMetricTimeSeries(...args);
719
- }
720
- async getMetricPercentiles(...args) {
721
- const delegate = await this.requireDelegate();
722
- return delegate.getMetricPercentiles(...args);
723
- }
724
- async getMetricNames(...args) {
725
- const delegate = await this.requireDelegate();
726
- return delegate.getMetricNames(...args);
727
- }
728
- async getMetricLabelKeys(...args) {
729
- const delegate = await this.requireDelegate();
730
- return delegate.getMetricLabelKeys(...args);
731
- }
732
- async getMetricLabelValues(...args) {
733
- const delegate = await this.requireDelegate();
734
- return delegate.getMetricLabelValues(...args);
735
- }
736
- async getEntityTypes(...args) {
737
- const delegate = await this.requireDelegate();
738
- return delegate.getEntityTypes(...args);
739
- }
740
- async getEntityNames(...args) {
741
- const delegate = await this.requireDelegate();
742
- return delegate.getEntityNames(...args);
743
- }
744
- async getServiceNames(...args) {
745
- const delegate = await this.requireDelegate();
746
- return delegate.getServiceNames(...args);
747
- }
748
- async getEnvironments(...args) {
749
- const delegate = await this.requireDelegate();
750
- return delegate.getEnvironments(...args);
751
- }
752
- async getTags(...args) {
753
- const delegate = await this.requireDelegate();
754
- return delegate.getTags(...args);
755
- }
756
- async createScore(...args) {
757
- const delegate = await this.requireDelegate();
758
- return delegate.createScore(...args);
759
- }
760
- async batchCreateScores(...args) {
761
- const delegate = await this.requireDelegate();
762
- return delegate.batchCreateScores(...args);
763
- }
764
- async listScores(...args) {
765
- const delegate = await this.requireDelegate();
766
- return delegate.listScores(...args);
767
- }
768
- async getScoreById(...args) {
769
- const delegate = await this.requireDelegate();
770
- return delegate.getScoreById(...args);
771
- }
772
- async getScoreAggregate(...args) {
773
- const delegate = await this.requireDelegate();
774
- return delegate.getScoreAggregate(...args);
775
- }
776
- async getScoreBreakdown(...args) {
777
- const delegate = await this.requireDelegate();
778
- return delegate.getScoreBreakdown(...args);
779
- }
780
- async getScoreTimeSeries(...args) {
781
- const delegate = await this.requireDelegate();
782
- return delegate.getScoreTimeSeries(...args);
783
- }
784
- async getScorePercentiles(...args) {
785
- const delegate = await this.requireDelegate();
786
- return delegate.getScorePercentiles(...args);
787
- }
788
- async createFeedback(...args) {
789
- const delegate = await this.requireDelegate();
790
- return delegate.createFeedback(...args);
791
- }
792
- async batchCreateFeedback(...args) {
793
- const delegate = await this.requireDelegate();
794
- return delegate.batchCreateFeedback(...args);
795
- }
796
- async listFeedback(...args) {
797
- const delegate = await this.requireDelegate();
798
- return delegate.listFeedback(...args);
799
- }
800
- async getFeedbackAggregate(...args) {
801
- const delegate = await this.requireDelegate();
802
- return delegate.getFeedbackAggregate(...args);
803
- }
804
- async getFeedbackBreakdown(...args) {
805
- const delegate = await this.requireDelegate();
806
- return delegate.getFeedbackBreakdown(...args);
807
- }
808
- async getFeedbackTimeSeries(...args) {
809
- const delegate = await this.requireDelegate();
810
- return delegate.getFeedbackTimeSeries(...args);
811
- }
812
- async getFeedbackPercentiles(...args) {
813
- const delegate = await this.requireDelegate();
814
- return delegate.getFeedbackPercentiles(...args);
815
- }
495
+ /**
496
+ * Lazy DuckDB observability facade.
497
+ *
498
+ * This avoids loading the concrete observability implementation until init or first use,
499
+ * which lets DuckDBStore degrade cleanly when paired with an older @mastra/core runtime.
500
+ */
501
+ var ObservabilityStorageDuckDB = class extends _mastra_core_storage.ObservabilityStorage {
502
+ db;
503
+ delegate = null;
504
+ loadPromise = null;
505
+ unavailableError = null;
506
+ constructor(config) {
507
+ super();
508
+ this.db = config.db;
509
+ }
510
+ createUnavailableError(cause) {
511
+ return new _mastra_core_error.MastraError({
512
+ id: "OBSERVABILITY_STORAGE_DUCKDB_CORE_UPGRADE_NOT_IMPLEMENTED",
513
+ domain: _mastra_core_error.ErrorDomain.MASTRA_OBSERVABILITY,
514
+ category: _mastra_core_error.ErrorCategory.SYSTEM,
515
+ text: OBSERVABILITY_UPGRADE_MESSAGE
516
+ }, cause);
517
+ }
518
+ async loadDelegate() {
519
+ if (this.delegate) return this.delegate;
520
+ if (this.unavailableError) return null;
521
+ if (!this.loadPromise) this.loadPromise = Promise.resolve().then(() => require("./observability-Dc-V68UX.cjs")).then(({ ObservabilityStorageDuckDB }) => {
522
+ const delegate = new ObservabilityStorageDuckDB({ db: this.db });
523
+ this.delegate = delegate;
524
+ return delegate;
525
+ }).catch((error) => {
526
+ if (isObservabilityCompatibilityError(error)) {
527
+ this.unavailableError = this.createUnavailableError(error);
528
+ return null;
529
+ }
530
+ throw error;
531
+ });
532
+ return this.loadPromise;
533
+ }
534
+ async requireDelegate() {
535
+ const delegate = await this.loadDelegate();
536
+ if (!delegate) throw this.unavailableError ?? this.createUnavailableError();
537
+ return delegate;
538
+ }
539
+ get observabilityStrategy() {
540
+ return this.delegate?.observabilityStrategy ?? {
541
+ preferred: "event-sourced",
542
+ supported: ["event-sourced"]
543
+ };
544
+ }
545
+ get tracingStrategy() {
546
+ return this.delegate?.tracingStrategy ?? this.observabilityStrategy;
547
+ }
548
+ getFeatures() {
549
+ if (!_mastra_core_features.coreFeatures.has(OBSERVABILITY_DELTA_POLLING_FEATURE)) return;
550
+ return DUCKDB_OBSERVABILITY_FEATURES;
551
+ }
552
+ async init(...args) {
553
+ const delegate = await this.loadDelegate();
554
+ if (!delegate) return;
555
+ return delegate.init(...args);
556
+ }
557
+ async migrateSpans(...args) {
558
+ return (await this.requireDelegate()).migrateSpans(...args);
559
+ }
560
+ async dangerouslyClearAll(...args) {
561
+ return (await this.requireDelegate()).dangerouslyClearAll(...args);
562
+ }
563
+ async createSpan(...args) {
564
+ return (await this.requireDelegate()).createSpan(...args);
565
+ }
566
+ async updateSpan(...args) {
567
+ return (await this.requireDelegate()).updateSpan(...args);
568
+ }
569
+ async getSpan(...args) {
570
+ return (await this.requireDelegate()).getSpan(...args);
571
+ }
572
+ async getSpans(...args) {
573
+ return (await this.requireDelegate()).getSpans(...args);
574
+ }
575
+ async getRootSpan(...args) {
576
+ return (await this.requireDelegate()).getRootSpan(...args);
577
+ }
578
+ async getTrace(...args) {
579
+ return (await this.requireDelegate()).getTrace(...args);
580
+ }
581
+ async getTraceLight(...args) {
582
+ return (await this.requireDelegate()).getTraceLight(...args);
583
+ }
584
+ async listTraces(...args) {
585
+ return (await this.requireDelegate()).listTraces(...args);
586
+ }
587
+ async listTracesLight(...args) {
588
+ return (await this.requireDelegate()).listTracesLight(...args);
589
+ }
590
+ async listBranches(...args) {
591
+ return (await this.requireDelegate()).listBranches(...args);
592
+ }
593
+ async batchCreateSpans(...args) {
594
+ return (await this.requireDelegate()).batchCreateSpans(...args);
595
+ }
596
+ async batchUpdateSpans(...args) {
597
+ return (await this.requireDelegate()).batchUpdateSpans(...args);
598
+ }
599
+ async batchDeleteTraces(...args) {
600
+ return (await this.requireDelegate()).batchDeleteTraces(...args);
601
+ }
602
+ async batchCreateLogs(...args) {
603
+ return (await this.requireDelegate()).batchCreateLogs(...args);
604
+ }
605
+ async listLogs(...args) {
606
+ return (await this.requireDelegate()).listLogs(...args);
607
+ }
608
+ async batchCreateMetrics(...args) {
609
+ return (await this.requireDelegate()).batchCreateMetrics(...args);
610
+ }
611
+ async listMetrics(...args) {
612
+ return (await this.requireDelegate()).listMetrics(...args);
613
+ }
614
+ async getMetricAggregate(...args) {
615
+ return (await this.requireDelegate()).getMetricAggregate(...args);
616
+ }
617
+ async getMetricBreakdown(...args) {
618
+ return (await this.requireDelegate()).getMetricBreakdown(...args);
619
+ }
620
+ async getMetricTimeSeries(...args) {
621
+ return (await this.requireDelegate()).getMetricTimeSeries(...args);
622
+ }
623
+ async getMetricPercentiles(...args) {
624
+ return (await this.requireDelegate()).getMetricPercentiles(...args);
625
+ }
626
+ async getMetricNames(...args) {
627
+ return (await this.requireDelegate()).getMetricNames(...args);
628
+ }
629
+ async getMetricLabelKeys(...args) {
630
+ return (await this.requireDelegate()).getMetricLabelKeys(...args);
631
+ }
632
+ async getMetricLabelValues(...args) {
633
+ return (await this.requireDelegate()).getMetricLabelValues(...args);
634
+ }
635
+ async getEntityTypes(...args) {
636
+ return (await this.requireDelegate()).getEntityTypes(...args);
637
+ }
638
+ async getEntityNames(...args) {
639
+ return (await this.requireDelegate()).getEntityNames(...args);
640
+ }
641
+ async getServiceNames(...args) {
642
+ return (await this.requireDelegate()).getServiceNames(...args);
643
+ }
644
+ async getEnvironments(...args) {
645
+ return (await this.requireDelegate()).getEnvironments(...args);
646
+ }
647
+ async getTags(...args) {
648
+ return (await this.requireDelegate()).getTags(...args);
649
+ }
650
+ async createScore(...args) {
651
+ return (await this.requireDelegate()).createScore(...args);
652
+ }
653
+ async batchCreateScores(...args) {
654
+ return (await this.requireDelegate()).batchCreateScores(...args);
655
+ }
656
+ async listScores(...args) {
657
+ return (await this.requireDelegate()).listScores(...args);
658
+ }
659
+ async getScoreById(...args) {
660
+ return (await this.requireDelegate()).getScoreById(...args);
661
+ }
662
+ async getScoreAggregate(...args) {
663
+ return (await this.requireDelegate()).getScoreAggregate(...args);
664
+ }
665
+ async getScoreBreakdown(...args) {
666
+ return (await this.requireDelegate()).getScoreBreakdown(...args);
667
+ }
668
+ async getScoreTimeSeries(...args) {
669
+ return (await this.requireDelegate()).getScoreTimeSeries(...args);
670
+ }
671
+ async getScorePercentiles(...args) {
672
+ return (await this.requireDelegate()).getScorePercentiles(...args);
673
+ }
674
+ async createFeedback(...args) {
675
+ return (await this.requireDelegate()).createFeedback(...args);
676
+ }
677
+ async batchCreateFeedback(...args) {
678
+ return (await this.requireDelegate()).batchCreateFeedback(...args);
679
+ }
680
+ async listFeedback(...args) {
681
+ return (await this.requireDelegate()).listFeedback(...args);
682
+ }
683
+ async getFeedbackAggregate(...args) {
684
+ return (await this.requireDelegate()).getFeedbackAggregate(...args);
685
+ }
686
+ async getFeedbackBreakdown(...args) {
687
+ return (await this.requireDelegate()).getFeedbackBreakdown(...args);
688
+ }
689
+ async getFeedbackTimeSeries(...args) {
690
+ return (await this.requireDelegate()).getFeedbackTimeSeries(...args);
691
+ }
692
+ async getFeedbackPercentiles(...args) {
693
+ return (await this.requireDelegate()).getFeedbackPercentiles(...args);
694
+ }
816
695
  };
817
- var DuckDBStore = class extends storage.MastraCompositeStore {
818
- db;
819
- observabilityStore;
820
- stores;
821
- constructor(config = {}) {
822
- const id = config.id ?? "duckdb";
823
- super({ id, name: "DuckDBStore" });
824
- this.db = new chunkSMRZJTCI_cjs.DuckDBConnection({ path: config.path });
825
- this.observabilityStore = new ObservabilityStorageDuckDB({ db: this.db });
826
- this.stores = {
827
- observability: this.observabilityStore
828
- };
829
- }
830
- /** Convenience accessor for the observability domain. */
831
- get observability() {
832
- return this.observabilityStore;
833
- }
834
- /**
835
- * Release the underlying DuckDB instance so the file lock is freed.
836
- * Called automatically by Mastra.shutdown(). Without this, the DuckDB
837
- * native write lock persists past process exit during dev hot reloads,
838
- * causing "Conflicting lock is held" errors on the next start.
839
- * Safe to call more than once; subsequent calls are no-ops.
840
- */
841
- async close() {
842
- await this.db.close();
843
- }
696
+ /**
697
+ * DuckDB storage adapter for Mastra.
698
+ *
699
+ * Currently provides observability storage (traces, metrics, logs, scores, feedback).
700
+ * Use via composition with another store for domains DuckDB doesn't yet cover.
701
+ *
702
+ * @example
703
+ * ```typescript
704
+ * // As the observability backend in a composed store
705
+ * const storage = new MastraCompositeStore({
706
+ * id: 'my-store',
707
+ * default: new LibSQLStore({ id: 'my-store', url: 'file:./dev.db' }),
708
+ * domains: {
709
+ * observability: new DuckDBStore().observability,
710
+ * },
711
+ * });
712
+ *
713
+ * // Or standalone (only observability domain available)
714
+ * const duckdb = new DuckDBStore();
715
+ * const obs = await duckdb.getStore('observability');
716
+ * ```
717
+ */
718
+ var DuckDBStore = class extends _mastra_core_storage.MastraCompositeStore {
719
+ db;
720
+ observabilityStore;
721
+ stores;
722
+ constructor(config = {}) {
723
+ const id = config.id ?? "duckdb";
724
+ super({
725
+ id,
726
+ name: "DuckDBStore"
727
+ });
728
+ this.db = new require_db.DuckDBConnection({
729
+ path: config.path,
730
+ memoryLimit: config.memoryLimit,
731
+ threads: config.threads
732
+ });
733
+ this.observabilityStore = new ObservabilityStorageDuckDB({ db: this.db });
734
+ this.stores = { observability: this.observabilityStore };
735
+ }
736
+ /** Convenience accessor for the observability domain. */
737
+ get observability() {
738
+ return this.observabilityStore;
739
+ }
740
+ /**
741
+ * Release the underlying DuckDB instance so the file lock is freed.
742
+ * Called automatically by Mastra.shutdown(). Without this, the DuckDB
743
+ * native write lock persists past process exit during dev hot reloads,
744
+ * causing "Conflicting lock is held" errors on the next start.
745
+ * Safe to call more than once; subsequent calls are no-ops.
746
+ */
747
+ async close() {
748
+ await this.db.close();
749
+ }
844
750
  };
845
-
846
- Object.defineProperty(exports, "DuckDBConnection", {
847
- enumerable: true,
848
- get: function () { return chunkSMRZJTCI_cjs.DuckDBConnection; }
849
- });
751
+ //#endregion
752
+ exports.DuckDBConnection = require_db.DuckDBConnection;
850
753
  exports.DuckDBStore = DuckDBStore;
851
754
  exports.DuckDBVector = DuckDBVector;
852
755
  exports.ObservabilityStorageDuckDB = ObservabilityStorageDuckDB;
853
- //# sourceMappingURL=index.cjs.map
756
+
854
757
  //# sourceMappingURL=index.cjs.map