@mastra/duckdb 1.5.1 → 1.5.2-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/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @mastra/duckdb
2
2
 
3
+ ## 1.5.2-alpha.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Fixed severe CPU and memory spikes when listing traces from large DuckDB databases. ([#20175](https://github.com/mastra-ai/mastra/pull/20175))
8
+
9
+ Opening the traces page in Studio (or calling the list traces / list branches APIs) against a multi-GB trace database previously decompressed the entire span_events table for every page load, poll, and scroll — pinning all CPU cores and ballooning memory by several GB per query. On multi-GB databases, trace list queries now use roughly 5x less CPU and stay within a bounded memory budget:
10
+
11
+ - Page queries now scan only the time range containing the requested spans instead of the whole table
12
+ - Filtered and custom-ordered queries (status, hasChildError, order by endedAt) now paginate on a narrow column set before reconstructing full span payloads
13
+ - Delta polls now short-circuit when there is no new data
14
+
15
+ Also added `memoryLimit` and `threads` options to `DuckDBStore`. DuckDB previously used its default memory budget of 80% of system RAM, which could push application servers into swap; it now defaults to 2GB. File-backed databases spill larger-than-memory operations to disk. Note that `:memory:` databases cannot spill, so if you run very large queries against an in-memory database, raise `memoryLimit`.
16
+
17
+ ```typescript
18
+ const store = new DuckDBStore({
19
+ path: 'mastra.duckdb',
20
+ memoryLimit: '4GB', // default '2GB'
21
+ threads: 2, // default: one per CPU core
22
+ });
23
+ ```
24
+
25
+ - Updated dependencies [[`ce93a3c`](https://github.com/mastra-ai/mastra/commit/ce93a3c114ea1cbfbd576f3db41d7c26c9844f5b), [`5718a22`](https://github.com/mastra-ai/mastra/commit/5718a229281dcfd36bcd1f42a242e3717e510a33), [`5807d3a`](https://github.com/mastra-ai/mastra/commit/5807d3ae1d259b8b7d6df7e5bf2b485c694af9c8), [`57661af`](https://github.com/mastra-ai/mastra/commit/57661afeca52ff9af4e72675ede2134fa503d5a5), [`57661af`](https://github.com/mastra-ai/mastra/commit/57661afeca52ff9af4e72675ede2134fa503d5a5), [`57661af`](https://github.com/mastra-ai/mastra/commit/57661afeca52ff9af4e72675ede2134fa503d5a5), [`5718a22`](https://github.com/mastra-ai/mastra/commit/5718a229281dcfd36bcd1f42a242e3717e510a33), [`57661af`](https://github.com/mastra-ai/mastra/commit/57661afeca52ff9af4e72675ede2134fa503d5a5), [`d1b7e3a`](https://github.com/mastra-ai/mastra/commit/d1b7e3a978a309a5653eeaa490d2d6c7c53bd093), [`c093146`](https://github.com/mastra-ai/mastra/commit/c0931466404d3c521308ea119cb165bb7e695155)]:
26
+ - @mastra/core@1.54.0-alpha.1
27
+
3
28
  ## 1.5.1
4
29
 
5
30
  ### Patch Changes
@@ -380,9 +405,7 @@
380
405
  });
381
406
 
382
407
  export const mastra = new Mastra({
383
- agents: {
384
- /* your agents here */
385
- },
408
+ agents: {/* your agents here */},
386
409
  observability: new Observability({
387
410
  configs: {
388
411
  default: {
@@ -466,9 +489,7 @@
466
489
  });
467
490
 
468
491
  export const mastra = new Mastra({
469
- agents: {
470
- /* your agents here */
471
- },
492
+ agents: {/* your agents here */},
472
493
  observability: new Observability({
473
494
  configs: {
474
495
  default: {
@@ -515,9 +536,7 @@
515
536
  });
516
537
 
517
538
  export const mastra = new Mastra({
518
- agents: {
519
- /* your agents here */
520
- },
539
+ agents: {/* your agents here */},
521
540
  observability: new Observability({
522
541
  configs: {
523
542
  default: {
@@ -39,14 +39,20 @@ function toJsValue(val) {
39
39
  }
40
40
  return val;
41
41
  }
42
+ var DEFAULT_MEMORY_LIMIT = "2GB";
42
43
  var DuckDBConnection = class extends base.MastraBase {
43
44
  instance = null;
44
45
  initialized = false;
45
46
  initPromise = null;
46
47
  path;
48
+ instanceOptions;
47
49
  constructor(config = {}) {
48
50
  super({ component: "STORAGE", name: "DUCKDB" });
49
51
  this.path = config.path ?? "mastra.duckdb";
52
+ this.instanceOptions = {
53
+ max_memory: config.memoryLimit ?? DEFAULT_MEMORY_LIMIT,
54
+ ...config.threads !== void 0 ? { threads: String(config.threads) } : {}
55
+ };
50
56
  }
51
57
  async initialize() {
52
58
  if (this.initialized && this.instance) return;
@@ -58,7 +64,7 @@ var DuckDBConnection = class extends base.MastraBase {
58
64
  }
59
65
  this.initPromise = (async () => {
60
66
  try {
61
- this.instance = await nodeApi.DuckDBInstance.create(this.path);
67
+ this.instance = await nodeApi.DuckDBInstance.create(this.path, this.instanceOptions);
62
68
  this.initialized = true;
63
69
  } catch (error) {
64
70
  this.instance = null;
@@ -215,5 +221,5 @@ ${statement}`).join("\n;\n") + "\n;";
215
221
 
216
222
  exports.DuckDBConnection = DuckDBConnection;
217
223
  exports.bindParam = bindParam;
218
- //# sourceMappingURL=chunk-SMRZJTCI.cjs.map
219
- //# sourceMappingURL=chunk-SMRZJTCI.cjs.map
224
+ //# sourceMappingURL=chunk-2OYGUAH5.cjs.map
225
+ //# sourceMappingURL=chunk-2OYGUAH5.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/storage/db/index.ts"],"names":["DuckDBTimestampValue","DuckDBTimestampTZValue","MastraBase","DuckDBInstance","result","rows","columns"],"mappings":"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","file":"chunk-2OYGUAH5.cjs","sourcesContent":["import { DuckDBInstance, DuckDBTimestampValue, DuckDBTimestampTZValue } from '@duckdb/node-api';\nimport type { DuckDBPreparedStatement } from '@duckdb/node-api';\nimport { MastraBase } from '@mastra/core/base';\n\n/**\n * Bind a single parameter to a prepared statement using explicit typed methods.\n * This avoids the \"Cannot create values of type ANY\" error that occurs when\n * DuckDB cannot infer parameter types from SQL context (e.g. json_extract_string).\n */\nexport function bindParam(stmt: DuckDBPreparedStatement, index: number, value: unknown): void {\n if (value === null || value === undefined) {\n stmt.bindNull(index);\n } else if (typeof value === 'string') {\n stmt.bindVarchar(index, value);\n } else if (typeof value === 'number') {\n if (Number.isInteger(value) && value >= -2147483648 && value <= 2147483647) {\n stmt.bindInteger(index, value);\n } else {\n stmt.bindDouble(index, value);\n }\n } else if (typeof value === 'boolean') {\n stmt.bindBoolean(index, value);\n } else if (typeof value === 'bigint') {\n stmt.bindBigInt(index, value);\n } else if (value instanceof Date) {\n stmt.bindTimestamp(index, new DuckDBTimestampValue(BigInt(value.getTime()) * 1000n));\n } else if (value instanceof DuckDBTimestampValue) {\n stmt.bindTimestamp(index, value);\n } else if (value instanceof DuckDBTimestampTZValue) {\n stmt.bindTimestampTZ(index, value);\n } else {\n // Fallback: serialize to JSON string\n stmt.bindVarchar(index, JSON.stringify(value));\n }\n}\n\n/** Convert DuckDB-specific return types to plain JS types */\nfunction toJsValue(val: unknown): unknown {\n if (val === null || val === undefined) return val;\n // DuckDBTimestampValue → Date (micros since epoch)\n if (val instanceof DuckDBTimestampValue) {\n return new Date(Number(val.micros / 1000n));\n }\n // BigInt → Number (safe for values we care about)\n if (typeof val === 'bigint') {\n return Number(val);\n }\n return val;\n}\n\n/** Configuration for the DuckDB database connection. */\nexport interface DuckDBStorageConfig {\n /** Path to the DuckDB file. Defaults to 'mastra.duckdb'. Use ':memory:' for ephemeral. */\n path?: string;\n /**\n * Maximum memory DuckDB may use (e.g. '2GB', '512MB').\n * @default '2GB'\n * DuckDB's own default is 80% of system RAM, which is far too aggressive for\n * a store embedded in an application server — a single query against a large\n * database can balloon the process by several GB and push the host into\n * swap. Larger-than-memory operations spill to disk for file-backed\n * databases. Raise this for dedicated analytical workloads.\n */\n memoryLimit?: string;\n /**\n * Number of threads DuckDB may use. Defaults to DuckDB's default (one per\n * CPU core). Lower this to keep queries from monopolizing all cores of a\n * shared application server.\n */\n threads?: number;\n}\n\nconst DEFAULT_MEMORY_LIMIT = '2GB';\n\n/**\n * Shared DuckDB connection management for Mastra storage.\n * Defaults to a local file (`mastra.duckdb`) when no path is provided.\n * Pass `path: ':memory:'` for an ephemeral in-memory database.\n */\nexport class DuckDBConnection extends MastraBase {\n private instance: DuckDBInstance | null = null;\n private initialized = false;\n private initPromise: Promise<void> | null = null;\n private path: string;\n private instanceOptions: Record<string, string>;\n\n constructor(config: DuckDBStorageConfig = {}) {\n super({ component: 'STORAGE', name: 'DUCKDB' });\n this.path = config.path ?? 'mastra.duckdb';\n this.instanceOptions = {\n max_memory: config.memoryLimit ?? DEFAULT_MEMORY_LIMIT,\n ...(config.threads !== undefined ? { threads: String(config.threads) } : {}),\n };\n }\n\n private async initialize(): Promise<void> {\n if (this.initialized && this.instance) return;\n\n if (this.initPromise) {\n await this.initPromise;\n if (this.instance) return;\n this.initPromise = null;\n this.initialized = false;\n }\n\n this.initPromise = (async () => {\n try {\n this.instance = await DuckDBInstance.create(this.path, this.instanceOptions);\n this.initialized = true;\n } catch (error) {\n this.instance = null;\n this.initialized = false;\n this.initPromise = null;\n throw error;\n }\n })();\n\n return this.initPromise;\n }\n\n /** Create a new connection to the DuckDB instance, initializing if needed. */\n async getConnection() {\n await this.initialize();\n if (!this.instance) {\n throw new Error('DuckDB instance not initialized');\n }\n return this.instance.connect();\n }\n\n private closeConnection(connection: unknown): void {\n const conn = connection as {\n closeSync?: () => void;\n disconnectSync?: () => void;\n close?: () => void;\n disconnect?: () => void;\n };\n try {\n if (typeof conn?.closeSync === 'function') {\n conn.closeSync();\n return;\n }\n if (typeof conn?.disconnectSync === 'function') {\n conn.disconnectSync();\n return;\n }\n if (typeof conn?.close === 'function') {\n conn.close();\n return;\n }\n if (typeof conn?.disconnect === 'function') {\n conn.disconnect();\n }\n } catch {\n // Ignore close failures to avoid masking query/execute errors.\n }\n }\n\n /**\n * Execute a SQL query and return results as objects.\n */\n async query<T = Record<string, unknown>>(sql: string, params: unknown[] = []): Promise<T[]> {\n const connection = await this.getConnection();\n try {\n if (params.length === 0) {\n const result = await connection.run(sql);\n const rows = await result.getRows();\n const columns = result.columnNames();\n return rows.map(row => {\n const obj: Record<string, unknown> = {};\n columns.forEach((col, i) => {\n obj[col] = toJsValue(row[i]);\n });\n return obj as T;\n });\n }\n\n let paramIndex = 0;\n const preparedSql = sql.replace(/\\?/g, () => `$${++paramIndex}`);\n const stmt = await connection.prepare(preparedSql);\n for (let i = 0; i < params.length; i++) {\n bindParam(stmt, i + 1, params[i]);\n }\n const result = await stmt.run();\n const rows = await result.getRows();\n const columns = result.columnNames();\n return rows.map(row => {\n const obj: Record<string, unknown> = {};\n columns.forEach((col, i) => {\n obj[col] = toJsValue(row[i]);\n });\n return obj as T;\n });\n } finally {\n this.closeConnection(connection);\n }\n }\n\n /**\n * Execute a SQL statement without returning results.\n */\n async execute(sql: string, params: unknown[] = []): Promise<void> {\n const connection = await this.getConnection();\n try {\n if (params.length === 0) {\n await connection.run(sql);\n return;\n }\n let paramIndex = 0;\n const preparedSql = sql.replace(/\\?/g, () => `$${++paramIndex}`);\n const stmt = await connection.prepare(preparedSql);\n for (let i = 0; i < params.length; i++) {\n bindParam(stmt, i + 1, params[i]);\n }\n await stmt.run();\n } finally {\n this.closeConnection(connection);\n }\n }\n\n /**\n * Execute multiple SQL statements in order using a single DuckDB connection.\n *\n * This is intended for schema setup/migrations where statements have no\n * parameters and must remain ordered, but opening a connection per statement\n * would dominate initialization cost. Blank statements are skipped. Like\n * calling execute() repeatedly, this does not wrap statements in a transaction,\n * so prior statements can remain applied if a later statement fails.\n */\n async executeBatch(sqlStatements: readonly string[]): Promise<void> {\n const statements = sqlStatements.map(statement => statement.trim()).filter(Boolean);\n if (statements.length === 0) return;\n\n const connection = await this.getConnection();\n try {\n const sql =\n statements.map((statement, i) => `-- executeBatch statement ${i + 1}\\n${statement}`).join('\\n;\\n') + '\\n;';\n await connection.run(sql);\n } finally {\n this.closeConnection(connection);\n }\n }\n\n /**\n * Escape a value for safe inline SQL use.\n * DuckDB prepared statements can't handle NULL for parameters typed as ANY,\n * so for complex INSERT/UPDATE operations we inline values safely.\n */\n static sqlValue(value: unknown): string {\n if (value === null || value === undefined) return 'NULL';\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) return 'NULL';\n return String(value);\n }\n if (typeof value === 'boolean') return value ? 'TRUE' : 'FALSE';\n if (value instanceof Date) return `'${value.toISOString()}'::TIMESTAMP`;\n if (typeof value === 'string') return `'${value.replace(/'/g, \"''\")}'`;\n // Objects/arrays → JSON string\n return `'${JSON.stringify(value).replace(/'/g, \"''\")}'`;\n }\n\n /** Release the DuckDB instance, allowing garbage collection. */\n async close(): Promise<void> {\n if (this.instance) {\n try {\n const instance = this.instance as unknown as { closeSync?: () => void; close?: () => void };\n if (typeof instance.closeSync === 'function') {\n instance.closeSync();\n } else if (typeof instance.close === 'function') {\n instance.close();\n }\n } catch {\n // Ignore close failures to allow cleanup of references.\n }\n this.instance = null;\n this.initialized = false;\n this.initPromise = null;\n }\n }\n}\n"]}
@@ -37,14 +37,20 @@ function toJsValue(val) {
37
37
  }
38
38
  return val;
39
39
  }
40
+ var DEFAULT_MEMORY_LIMIT = "2GB";
40
41
  var DuckDBConnection = class extends MastraBase {
41
42
  instance = null;
42
43
  initialized = false;
43
44
  initPromise = null;
44
45
  path;
46
+ instanceOptions;
45
47
  constructor(config = {}) {
46
48
  super({ component: "STORAGE", name: "DUCKDB" });
47
49
  this.path = config.path ?? "mastra.duckdb";
50
+ this.instanceOptions = {
51
+ max_memory: config.memoryLimit ?? DEFAULT_MEMORY_LIMIT,
52
+ ...config.threads !== void 0 ? { threads: String(config.threads) } : {}
53
+ };
48
54
  }
49
55
  async initialize() {
50
56
  if (this.initialized && this.instance) return;
@@ -56,7 +62,7 @@ var DuckDBConnection = class extends MastraBase {
56
62
  }
57
63
  this.initPromise = (async () => {
58
64
  try {
59
- this.instance = await DuckDBInstance.create(this.path);
65
+ this.instance = await DuckDBInstance.create(this.path, this.instanceOptions);
60
66
  this.initialized = true;
61
67
  } catch (error) {
62
68
  this.instance = null;
@@ -212,5 +218,5 @@ ${statement}`).join("\n;\n") + "\n;";
212
218
  };
213
219
 
214
220
  export { DuckDBConnection, bindParam };
215
- //# sourceMappingURL=chunk-4LIZE4MC.js.map
216
- //# sourceMappingURL=chunk-4LIZE4MC.js.map
221
+ //# sourceMappingURL=chunk-SBS7DUKU.js.map
222
+ //# sourceMappingURL=chunk-SBS7DUKU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/storage/db/index.ts"],"names":["result","rows","columns"],"mappings":"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","file":"chunk-SBS7DUKU.js","sourcesContent":["import { DuckDBInstance, DuckDBTimestampValue, DuckDBTimestampTZValue } from '@duckdb/node-api';\nimport type { DuckDBPreparedStatement } from '@duckdb/node-api';\nimport { MastraBase } from '@mastra/core/base';\n\n/**\n * Bind a single parameter to a prepared statement using explicit typed methods.\n * This avoids the \"Cannot create values of type ANY\" error that occurs when\n * DuckDB cannot infer parameter types from SQL context (e.g. json_extract_string).\n */\nexport function bindParam(stmt: DuckDBPreparedStatement, index: number, value: unknown): void {\n if (value === null || value === undefined) {\n stmt.bindNull(index);\n } else if (typeof value === 'string') {\n stmt.bindVarchar(index, value);\n } else if (typeof value === 'number') {\n if (Number.isInteger(value) && value >= -2147483648 && value <= 2147483647) {\n stmt.bindInteger(index, value);\n } else {\n stmt.bindDouble(index, value);\n }\n } else if (typeof value === 'boolean') {\n stmt.bindBoolean(index, value);\n } else if (typeof value === 'bigint') {\n stmt.bindBigInt(index, value);\n } else if (value instanceof Date) {\n stmt.bindTimestamp(index, new DuckDBTimestampValue(BigInt(value.getTime()) * 1000n));\n } else if (value instanceof DuckDBTimestampValue) {\n stmt.bindTimestamp(index, value);\n } else if (value instanceof DuckDBTimestampTZValue) {\n stmt.bindTimestampTZ(index, value);\n } else {\n // Fallback: serialize to JSON string\n stmt.bindVarchar(index, JSON.stringify(value));\n }\n}\n\n/** Convert DuckDB-specific return types to plain JS types */\nfunction toJsValue(val: unknown): unknown {\n if (val === null || val === undefined) return val;\n // DuckDBTimestampValue → Date (micros since epoch)\n if (val instanceof DuckDBTimestampValue) {\n return new Date(Number(val.micros / 1000n));\n }\n // BigInt → Number (safe for values we care about)\n if (typeof val === 'bigint') {\n return Number(val);\n }\n return val;\n}\n\n/** Configuration for the DuckDB database connection. */\nexport interface DuckDBStorageConfig {\n /** Path to the DuckDB file. Defaults to 'mastra.duckdb'. Use ':memory:' for ephemeral. */\n path?: string;\n /**\n * Maximum memory DuckDB may use (e.g. '2GB', '512MB').\n * @default '2GB'\n * DuckDB's own default is 80% of system RAM, which is far too aggressive for\n * a store embedded in an application server — a single query against a large\n * database can balloon the process by several GB and push the host into\n * swap. Larger-than-memory operations spill to disk for file-backed\n * databases. Raise this for dedicated analytical workloads.\n */\n memoryLimit?: string;\n /**\n * Number of threads DuckDB may use. Defaults to DuckDB's default (one per\n * CPU core). Lower this to keep queries from monopolizing all cores of a\n * shared application server.\n */\n threads?: number;\n}\n\nconst DEFAULT_MEMORY_LIMIT = '2GB';\n\n/**\n * Shared DuckDB connection management for Mastra storage.\n * Defaults to a local file (`mastra.duckdb`) when no path is provided.\n * Pass `path: ':memory:'` for an ephemeral in-memory database.\n */\nexport class DuckDBConnection extends MastraBase {\n private instance: DuckDBInstance | null = null;\n private initialized = false;\n private initPromise: Promise<void> | null = null;\n private path: string;\n private instanceOptions: Record<string, string>;\n\n constructor(config: DuckDBStorageConfig = {}) {\n super({ component: 'STORAGE', name: 'DUCKDB' });\n this.path = config.path ?? 'mastra.duckdb';\n this.instanceOptions = {\n max_memory: config.memoryLimit ?? DEFAULT_MEMORY_LIMIT,\n ...(config.threads !== undefined ? { threads: String(config.threads) } : {}),\n };\n }\n\n private async initialize(): Promise<void> {\n if (this.initialized && this.instance) return;\n\n if (this.initPromise) {\n await this.initPromise;\n if (this.instance) return;\n this.initPromise = null;\n this.initialized = false;\n }\n\n this.initPromise = (async () => {\n try {\n this.instance = await DuckDBInstance.create(this.path, this.instanceOptions);\n this.initialized = true;\n } catch (error) {\n this.instance = null;\n this.initialized = false;\n this.initPromise = null;\n throw error;\n }\n })();\n\n return this.initPromise;\n }\n\n /** Create a new connection to the DuckDB instance, initializing if needed. */\n async getConnection() {\n await this.initialize();\n if (!this.instance) {\n throw new Error('DuckDB instance not initialized');\n }\n return this.instance.connect();\n }\n\n private closeConnection(connection: unknown): void {\n const conn = connection as {\n closeSync?: () => void;\n disconnectSync?: () => void;\n close?: () => void;\n disconnect?: () => void;\n };\n try {\n if (typeof conn?.closeSync === 'function') {\n conn.closeSync();\n return;\n }\n if (typeof conn?.disconnectSync === 'function') {\n conn.disconnectSync();\n return;\n }\n if (typeof conn?.close === 'function') {\n conn.close();\n return;\n }\n if (typeof conn?.disconnect === 'function') {\n conn.disconnect();\n }\n } catch {\n // Ignore close failures to avoid masking query/execute errors.\n }\n }\n\n /**\n * Execute a SQL query and return results as objects.\n */\n async query<T = Record<string, unknown>>(sql: string, params: unknown[] = []): Promise<T[]> {\n const connection = await this.getConnection();\n try {\n if (params.length === 0) {\n const result = await connection.run(sql);\n const rows = await result.getRows();\n const columns = result.columnNames();\n return rows.map(row => {\n const obj: Record<string, unknown> = {};\n columns.forEach((col, i) => {\n obj[col] = toJsValue(row[i]);\n });\n return obj as T;\n });\n }\n\n let paramIndex = 0;\n const preparedSql = sql.replace(/\\?/g, () => `$${++paramIndex}`);\n const stmt = await connection.prepare(preparedSql);\n for (let i = 0; i < params.length; i++) {\n bindParam(stmt, i + 1, params[i]);\n }\n const result = await stmt.run();\n const rows = await result.getRows();\n const columns = result.columnNames();\n return rows.map(row => {\n const obj: Record<string, unknown> = {};\n columns.forEach((col, i) => {\n obj[col] = toJsValue(row[i]);\n });\n return obj as T;\n });\n } finally {\n this.closeConnection(connection);\n }\n }\n\n /**\n * Execute a SQL statement without returning results.\n */\n async execute(sql: string, params: unknown[] = []): Promise<void> {\n const connection = await this.getConnection();\n try {\n if (params.length === 0) {\n await connection.run(sql);\n return;\n }\n let paramIndex = 0;\n const preparedSql = sql.replace(/\\?/g, () => `$${++paramIndex}`);\n const stmt = await connection.prepare(preparedSql);\n for (let i = 0; i < params.length; i++) {\n bindParam(stmt, i + 1, params[i]);\n }\n await stmt.run();\n } finally {\n this.closeConnection(connection);\n }\n }\n\n /**\n * Execute multiple SQL statements in order using a single DuckDB connection.\n *\n * This is intended for schema setup/migrations where statements have no\n * parameters and must remain ordered, but opening a connection per statement\n * would dominate initialization cost. Blank statements are skipped. Like\n * calling execute() repeatedly, this does not wrap statements in a transaction,\n * so prior statements can remain applied if a later statement fails.\n */\n async executeBatch(sqlStatements: readonly string[]): Promise<void> {\n const statements = sqlStatements.map(statement => statement.trim()).filter(Boolean);\n if (statements.length === 0) return;\n\n const connection = await this.getConnection();\n try {\n const sql =\n statements.map((statement, i) => `-- executeBatch statement ${i + 1}\\n${statement}`).join('\\n;\\n') + '\\n;';\n await connection.run(sql);\n } finally {\n this.closeConnection(connection);\n }\n }\n\n /**\n * Escape a value for safe inline SQL use.\n * DuckDB prepared statements can't handle NULL for parameters typed as ANY,\n * so for complex INSERT/UPDATE operations we inline values safely.\n */\n static sqlValue(value: unknown): string {\n if (value === null || value === undefined) return 'NULL';\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) return 'NULL';\n return String(value);\n }\n if (typeof value === 'boolean') return value ? 'TRUE' : 'FALSE';\n if (value instanceof Date) return `'${value.toISOString()}'::TIMESTAMP`;\n if (typeof value === 'string') return `'${value.replace(/'/g, \"''\")}'`;\n // Objects/arrays → JSON string\n return `'${JSON.stringify(value).replace(/'/g, \"''\")}'`;\n }\n\n /** Release the DuckDB instance, allowing garbage collection. */\n async close(): Promise<void> {\n if (this.instance) {\n try {\n const instance = this.instance as unknown as { closeSync?: () => void; close?: () => void };\n if (typeof instance.closeSync === 'function') {\n instance.closeSync();\n } else if (typeof instance.close === 'function') {\n instance.close();\n }\n } catch {\n // Ignore close failures to allow cleanup of references.\n }\n this.instance = null;\n this.initialized = false;\n this.initPromise = null;\n }\n }\n}\n"]}
@@ -3,7 +3,7 @@ name: mastra-duckdb
3
3
  description: Documentation for @mastra/duckdb. Use when working with @mastra/duckdb APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/duckdb"
6
- version: "1.5.1"
6
+ version: "1.5.2-alpha.0"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,11 +1,11 @@
1
1
  {
2
- "version": "1.5.1",
2
+ "version": "1.5.2-alpha.0",
3
3
  "package": "@mastra/duckdb",
4
4
  "exports": {
5
5
  "DuckDBConnection": {
6
6
  "types": "dist/index.d.ts",
7
- "implementation": "dist/chunk-4LIZE4MC.js",
8
- "line": 40
7
+ "implementation": "dist/chunk-SBS7DUKU.js",
8
+ "line": 41
9
9
  }
10
10
  },
11
11
  "modules": {}
@@ -110,6 +110,10 @@ const duckdb = new DuckDBStore({ path: ':memory:' })
110
110
 
111
111
  **path** (`string`): Path to the DuckDB database file. Use :memory: for an ephemeral in-memory database. (Default: `'mastra.duckdb'`)
112
112
 
113
+ **memoryLimit** (`string`): Maximum memory DuckDB may use, such as '2GB' or '512MB'. Larger-than-memory operations spill to disk for file-backed databases. Raise this for dedicated analytical workloads. (Default: `'2GB'`)
114
+
115
+ **threads** (`number`): Number of threads DuckDB may use. Lower this to keep queries from monopolizing all cores of a shared application server. (Default: `one per CPU core`)
116
+
113
117
  ### Lower-level types
114
118
 
115
119
  `@mastra/duckdb` also exports `DuckDBConnection` for sharing a single underlying database across multiple Mastra storage instances, and the corresponding `DuckDBStorageConfig` type. Most applications won't need these directly.
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkSMRZJTCI_cjs = require('./chunk-SMRZJTCI.cjs');
3
+ var chunk2OYGUAH5_cjs = require('./chunk-2OYGUAH5.cjs');
4
4
  var nodeApi = require('@duckdb/node-api');
5
5
  var error = require('@mastra/core/error');
6
6
  var storage = require('@mastra/core/storage');
@@ -254,7 +254,7 @@ var DuckDBVector = class extends vector.MastraVector {
254
254
  const preparedSql = sql.replace(/\?/g, () => `$${++paramIndex}`);
255
255
  const stmt = await connection.prepare(preparedSql);
256
256
  for (let i = 0; i < params.length; i++) {
257
- chunkSMRZJTCI_cjs.bindParam(stmt, i + 1, params[i]);
257
+ chunk2OYGUAH5_cjs.bindParam(stmt, i + 1, params[i]);
258
258
  }
259
259
  const result = await stmt.run();
260
260
  const rows = await result.getRows();
@@ -282,7 +282,7 @@ var DuckDBVector = class extends vector.MastraVector {
282
282
  const preparedSql = sql.replace(/\?/g, () => `$${++paramIndex}`);
283
283
  const stmt = await connection.prepare(preparedSql);
284
284
  for (let i = 0; i < params.length; i++) {
285
- chunkSMRZJTCI_cjs.bindParam(stmt, i + 1, params[i]);
285
+ chunk2OYGUAH5_cjs.bindParam(stmt, i + 1, params[i]);
286
286
  }
287
287
  await stmt.run();
288
288
  }
@@ -586,7 +586,7 @@ var ObservabilityStorageDuckDB = class extends storage.ObservabilityStorage {
586
586
  return null;
587
587
  }
588
588
  if (!this.loadPromise) {
589
- this.loadPromise = import('./observability-V2KYD7UF.cjs').then(({ ObservabilityStorageDuckDB: ObservabilityStorageDuckDB2 }) => {
589
+ this.loadPromise = import('./observability-YNPIOM43.cjs').then(({ ObservabilityStorageDuckDB: ObservabilityStorageDuckDB2 }) => {
590
590
  const delegate = new ObservabilityStorageDuckDB2({ db: this.db });
591
591
  this.delegate = delegate;
592
592
  return delegate;
@@ -821,7 +821,7 @@ var DuckDBStore = class extends storage.MastraCompositeStore {
821
821
  constructor(config = {}) {
822
822
  const id = config.id ?? "duckdb";
823
823
  super({ id, name: "DuckDBStore" });
824
- this.db = new chunkSMRZJTCI_cjs.DuckDBConnection({ path: config.path });
824
+ this.db = new chunk2OYGUAH5_cjs.DuckDBConnection({ path: config.path, memoryLimit: config.memoryLimit, threads: config.threads });
825
825
  this.observabilityStore = new ObservabilityStorageDuckDB({ db: this.db });
826
826
  this.stores = {
827
827
  observability: this.observabilityStore
@@ -845,7 +845,7 @@ var DuckDBStore = class extends storage.MastraCompositeStore {
845
845
 
846
846
  Object.defineProperty(exports, "DuckDBConnection", {
847
847
  enumerable: true,
848
- get: function () { return chunkSMRZJTCI_cjs.DuckDBConnection; }
848
+ get: function () { return chunk2OYGUAH5_cjs.DuckDBConnection; }
849
849
  });
850
850
  exports.DuckDBStore = DuckDBStore;
851
851
  exports.DuckDBVector = DuckDBVector;