@mastra/duckdb 1.16.0-alpha.2 → 1.17.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.
Files changed (37) hide show
  1. package/dist/docs/SKILL.md +1 -1
  2. package/dist/docs/assets/SOURCE_MAP.json +1 -1
  3. package/dist/{features-DH60yLCA.cjs → features-CMkGwt1J.cjs} +70 -7
  4. package/dist/features-CMkGwt1J.cjs.map +1 -0
  5. package/dist/{features-B8gl38Ue.js → features-dc98I6Rx.js} +61 -4
  6. package/dist/features-dc98I6Rx.js.map +1 -0
  7. package/dist/index.cjs +23 -8
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.js +23 -8
  10. package/dist/index.js.map +1 -1
  11. package/dist/{observability-BWSYzhM2.js → observability-DlRTQlrI.js} +110 -15
  12. package/dist/observability-DlRTQlrI.js.map +1 -0
  13. package/dist/{observability-B-Vnz-ZL.cjs → observability-Dr89aflR.cjs} +109 -14
  14. package/dist/observability-Dr89aflR.cjs.map +1 -0
  15. package/dist/storage/db/index.d.ts +5 -0
  16. package/dist/storage/db/index.d.ts.map +1 -1
  17. package/dist/storage/domains/observability/ddl.d.ts +1 -1
  18. package/dist/storage/domains/observability/ddl.d.ts.map +1 -1
  19. package/dist/storage/domains/observability/index.d.ts +1 -1
  20. package/dist/storage/domains/observability/index.d.ts.map +1 -1
  21. package/dist/storage/domains/observability/preview-compat.d.ts +1 -0
  22. package/dist/storage/domains/observability/preview-compat.d.ts.map +1 -1
  23. package/dist/storage/domains/observability/span-query.d.ts +1 -0
  24. package/dist/storage/domains/observability/span-query.d.ts.map +1 -1
  25. package/dist/storage/domains/observability/thread-query.d.ts +1 -0
  26. package/dist/storage/domains/observability/thread-query.d.ts.map +1 -1
  27. package/dist/storage/domains/observability/trace-query.d.ts.map +1 -1
  28. package/dist/storage/domains/observability/tracing.d.ts.map +1 -1
  29. package/dist/storage/features.d.ts +3 -1
  30. package/dist/storage/features.d.ts.map +1 -1
  31. package/dist/storage/index.d.ts +3 -0
  32. package/dist/storage/index.d.ts.map +1 -1
  33. package/package.json +5 -5
  34. package/dist/features-B8gl38Ue.js.map +0 -1
  35. package/dist/features-DH60yLCA.cjs.map +0 -1
  36. package/dist/observability-B-Vnz-ZL.cjs.map +0 -1
  37. package/dist/observability-BWSYzhM2.js.map +0 -1
@@ -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.16.0-alpha.2"
6
+ version: "1.17.0-alpha.0"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.16.0-alpha.2",
2
+ "version": "1.17.0-alpha.0",
3
3
  "package": "@mastra/duckdb",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -66,6 +66,10 @@ var DuckDBConnection = class extends _mastra_core_base.MastraBase {
66
66
  instance = null;
67
67
  initialized = false;
68
68
  initPromise = null;
69
+ closed = false;
70
+ activeConnections = 0;
71
+ drainPromise = null;
72
+ finishDrain = null;
69
73
  path;
70
74
  instanceOptions;
71
75
  constructor(config = {}) {
@@ -80,6 +84,7 @@ var DuckDBConnection = class extends _mastra_core_base.MastraBase {
80
84
  };
81
85
  }
82
86
  async initialize() {
87
+ if (this.closed) throw new Error("DuckDB connection is closed");
83
88
  if (this.initialized && this.instance) return;
84
89
  if (this.initPromise) {
85
90
  await this.initPromise;
@@ -103,8 +108,46 @@ var DuckDBConnection = class extends _mastra_core_base.MastraBase {
103
108
  /** Create a new connection to the DuckDB instance, initializing if needed. */
104
109
  async getConnection() {
105
110
  await this.initialize();
111
+ if (this.closed) throw new Error("DuckDB connection is closed");
106
112
  if (!this.instance) throw new Error("DuckDB instance not initialized");
107
- return this.instance.connect();
113
+ this.activeConnections++;
114
+ try {
115
+ const connection = await this.instance.connect();
116
+ let released = false;
117
+ const release = () => {
118
+ if (!released) {
119
+ released = true;
120
+ this.releaseConnection();
121
+ }
122
+ };
123
+ return new Proxy(connection, { get(target, key) {
124
+ const value = Reflect.get(target, key, target);
125
+ if (typeof value !== "function") return value;
126
+ if (key === "closeSync" || key === "disconnectSync" || key === "close" || key === "disconnect") return (...args) => {
127
+ try {
128
+ const result = value.apply(target, args);
129
+ if (result instanceof Promise) return result.finally(release);
130
+ release();
131
+ return result;
132
+ } catch (error) {
133
+ release();
134
+ throw error;
135
+ }
136
+ };
137
+ return value.bind(target);
138
+ } });
139
+ } catch (error) {
140
+ this.releaseConnection();
141
+ throw error;
142
+ }
143
+ }
144
+ releaseConnection() {
145
+ this.activeConnections--;
146
+ if (this.activeConnections === 0) {
147
+ this.finishDrain?.();
148
+ this.finishDrain = null;
149
+ this.drainPromise = null;
150
+ }
108
151
  }
109
152
  closeConnection(connection) {
110
153
  const conn = connection;
@@ -265,6 +308,12 @@ var DuckDBConnection = class extends _mastra_core_base.MastraBase {
265
308
  }
266
309
  /** Release the DuckDB instance, allowing garbage collection. */
267
310
  async close() {
311
+ this.closed = true;
312
+ await this.initPromise?.catch(() => void 0);
313
+ if (this.activeConnections > 0) {
314
+ this.drainPromise ??= new Promise((resolve) => this.finishDrain = resolve);
315
+ await this.drainPromise;
316
+ }
268
317
  if (this.instance) {
269
318
  try {
270
319
  const instance = this.instance;
@@ -285,7 +334,15 @@ const spanAggregateFeatures = typeof _mastra_core_storage.planSpanAggregate ===
285
334
  const timeToFirstChunkSupported = "timeToFirstChunkMs" in _mastra_core_storage.TRACE_QUERY_FIELD_REGISTRY.trace;
286
335
  /** Core before the sort rejects `orderBy` on the field, so the sort is only declared when core plans it. */
287
336
  const timeToFirstChunkSortSupported = _mastra_core_storage.TRACE_QUERY_ORDER_FIELDS?.includes("timeToFirstChunkMs") === true;
288
- const timeToFirstChunkFeatures = [...timeToFirstChunkSupported ? ["trace-query-time-to-first-chunk"] : [], ...timeToFirstChunkSortSupported ? ["trace-query-time-to-first-chunk-sort"] : []];
337
+ /** Same rule for time to first token: returned and sorted only when core knows the field. */
338
+ const timeToFirstTokenSupported = "timeToFirstTokenMs" in _mastra_core_storage.TRACE_QUERY_FIELD_REGISTRY.trace;
339
+ const timeToFirstTokenSortSupported = _mastra_core_storage.TRACE_QUERY_ORDER_FIELDS?.includes("timeToFirstTokenMs") === true;
340
+ const timingFeatures = [
341
+ ...timeToFirstChunkSupported ? ["trace-query-time-to-first-chunk"] : [],
342
+ ...timeToFirstChunkSortSupported ? ["trace-query-time-to-first-chunk-sort"] : [],
343
+ ...timeToFirstTokenSupported ? ["trace-query-time-to-first-token"] : [],
344
+ ...timeToFirstTokenSortSupported ? ["trace-query-time-to-first-token-sort"] : []
345
+ ];
289
346
  Object.defineProperty(exports, "DuckDBConnection", {
290
347
  enumerable: true,
291
348
  get: function() {
@@ -328,17 +385,23 @@ Object.defineProperty(exports, "threadQueryFeatures", {
328
385
  return threadQueryFeatures;
329
386
  }
330
387
  });
331
- Object.defineProperty(exports, "timeToFirstChunkFeatures", {
388
+ Object.defineProperty(exports, "timeToFirstChunkSupported", {
332
389
  enumerable: true,
333
390
  get: function() {
334
- return timeToFirstChunkFeatures;
391
+ return timeToFirstChunkSupported;
335
392
  }
336
393
  });
337
- Object.defineProperty(exports, "timeToFirstChunkSupported", {
394
+ Object.defineProperty(exports, "timeToFirstTokenSupported", {
338
395
  enumerable: true,
339
396
  get: function() {
340
- return timeToFirstChunkSupported;
397
+ return timeToFirstTokenSupported;
398
+ }
399
+ });
400
+ Object.defineProperty(exports, "timingFeatures", {
401
+ enumerable: true,
402
+ get: function() {
403
+ return timingFeatures;
341
404
  }
342
405
  });
343
406
 
344
- //# sourceMappingURL=features-DH60yLCA.cjs.map
407
+ //# sourceMappingURL=features-CMkGwt1J.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features-CMkGwt1J.cjs","names":["DuckDBTimestampValue","DuckDBTimestampTZValue","MastraBase","DuckDBInstance","coreStorage"],"sources":["../src/storage/db/index.ts","../src/storage/features.ts"],"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/** A query interrupted at its caller-supplied deadline. */\nexport class DuckDBQueryTimeoutError extends Error {\n constructor() {\n super('DuckDB query exceeded its deadline');\n this.name = 'DuckDBQueryTimeoutError';\n }\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 closed = false;\n private activeConnections = 0;\n private drainPromise: Promise<void> | null = null;\n private finishDrain: (() => 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.closed) throw new Error('DuckDB connection is closed');\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.closed) throw new Error('DuckDB connection is closed');\n if (!this.instance) {\n throw new Error('DuckDB instance not initialized');\n }\n this.activeConnections++;\n try {\n const connection = await this.instance.connect();\n let released = false;\n const release = () => {\n if (!released) {\n released = true;\n this.releaseConnection();\n }\n };\n return new Proxy(connection, {\n get(target, key) {\n const value = Reflect.get(target, key, target);\n if (typeof value !== 'function') return value;\n if (key === 'closeSync' || key === 'disconnectSync' || key === 'close' || key === 'disconnect') {\n return (...args: unknown[]) => {\n try {\n const result = value.apply(target, args);\n if (result instanceof Promise) return result.finally(release);\n release();\n return result;\n } catch (error) {\n release();\n throw error;\n }\n };\n }\n return value.bind(target);\n },\n });\n } catch (error) {\n this.releaseConnection();\n throw error;\n }\n }\n\n private releaseConnection(): void {\n this.activeConnections--;\n if (this.activeConnections === 0) {\n this.finishDrain?.();\n this.finishDrain = null;\n this.drainPromise = null;\n }\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[] = [], timeoutMs?: number): Promise<T[]> {\n const connection = await this.getConnection();\n let timedOut = false;\n const timer =\n timeoutMs === undefined\n ? undefined\n : setTimeout(() => {\n timedOut = true;\n connection.interrupt();\n }, timeoutMs);\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 } catch (error) {\n if (timedOut) throw new DuckDBQueryTimeoutError();\n throw error;\n } finally {\n if (timer !== undefined) clearTimeout(timer);\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 /** Delete one bounded retention batch and return the number of rows removed. */\n async pruneBatch({\n tableName,\n column,\n cutoff,\n limit,\n }: {\n tableName: string;\n column: string;\n cutoff: Date;\n limit: number;\n }): Promise<number> {\n const identifier = /^[A-Za-z_][A-Za-z0-9_]*$/;\n if (!identifier.test(tableName) || !identifier.test(column)) {\n throw new Error(`Invalid retention identifier: ${tableName}.${column}`);\n }\n\n const rows = await this.query(\n `DELETE FROM ${tableName}\n WHERE rowid IN (\n SELECT rowid FROM ${tableName}\n WHERE ${column} < ?\n ORDER BY ${column}\n LIMIT ?\n )\n RETURNING 1 AS deleted`,\n [cutoff, limit],\n );\n return rows.length;\n }\n\n /** Execute parameterized statements atomically using a single DuckDB connection. */\n async executeTransaction(statements: readonly { sql: string; params?: readonly unknown[] }[]): Promise<void> {\n if (statements.length === 0) return;\n\n const connection = await this.getConnection();\n try {\n await connection.run('BEGIN TRANSACTION');\n for (const statement of statements) {\n const params = statement.params ?? [];\n if (params.length === 0) {\n await connection.run(statement.sql);\n continue;\n }\n let paramIndex = 0;\n const preparedSql = statement.sql.replace(/\\?/g, () => `$${++paramIndex}`);\n const prepared = await connection.prepare(preparedSql);\n for (let i = 0; i < params.length; i++) {\n bindParam(prepared, i + 1, params[i]);\n }\n await prepared.run();\n }\n await connection.run('COMMIT');\n } catch (error) {\n await connection.run('ROLLBACK').catch(() => undefined);\n throw error;\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 this.closed = true;\n await this.initPromise?.catch(() => undefined);\n if (this.activeConnections > 0) {\n this.drainPromise ??= new Promise<void>(resolve => (this.finishDrain = resolve));\n await this.drainPromise;\n }\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","import * as coreStorage from '@mastra/core/storage';\n\nexport const threadQueryFeatures =\n typeof coreStorage.planThreadRowsQuery === 'function' ? (['thread-query-rows'] as const) : ([] as const);\n\nexport const spanQueryFeatures =\n typeof coreStorage.planSpanQuery === 'function'\n ? (['span-query', 'span-query-context-fields'] as const)\n : ([] as const);\n\nexport const spanAggregateFeatures =\n typeof coreStorage.planSpanAggregate === 'function' ? (['span-aggregate'] as const) : ([] as const);\n\n/** Core versions without the field reject it in trace query results, so it is only returned when core knows it. */\nexport const timeToFirstChunkSupported = 'timeToFirstChunkMs' in coreStorage.TRACE_QUERY_FIELD_REGISTRY.trace;\n\n/** Core before the sort rejects `orderBy` on the field, so the sort is only declared when core plans it. */\nconst timeToFirstChunkSortSupported = coreStorage.TRACE_QUERY_ORDER_FIELDS?.includes('timeToFirstChunkMs') === true;\n\n/** Same rule for time to first token: returned and sorted only when core knows the field. */\nexport const timeToFirstTokenSupported = 'timeToFirstTokenMs' in coreStorage.TRACE_QUERY_FIELD_REGISTRY.trace;\nconst timeToFirstTokenSortSupported = coreStorage.TRACE_QUERY_ORDER_FIELDS?.includes('timeToFirstTokenMs') === true;\n\nexport const timingFeatures = [\n ...(timeToFirstChunkSupported ? (['trace-query-time-to-first-chunk'] as const) : []),\n ...(timeToFirstChunkSortSupported ? (['trace-query-time-to-first-chunk-sort'] as const) : []),\n ...(timeToFirstTokenSupported ? (['trace-query-time-to-first-token'] as const) : []),\n ...(timeToFirstTokenSortSupported ? (['trace-query-time-to-first-token-sort'] as const) : []),\n] as const;\n"],"mappings":"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"}
@@ -44,6 +44,10 @@ var DuckDBConnection = class extends MastraBase {
44
44
  instance = null;
45
45
  initialized = false;
46
46
  initPromise = null;
47
+ closed = false;
48
+ activeConnections = 0;
49
+ drainPromise = null;
50
+ finishDrain = null;
47
51
  path;
48
52
  instanceOptions;
49
53
  constructor(config = {}) {
@@ -58,6 +62,7 @@ var DuckDBConnection = class extends MastraBase {
58
62
  };
59
63
  }
60
64
  async initialize() {
65
+ if (this.closed) throw new Error("DuckDB connection is closed");
61
66
  if (this.initialized && this.instance) return;
62
67
  if (this.initPromise) {
63
68
  await this.initPromise;
@@ -81,8 +86,46 @@ var DuckDBConnection = class extends MastraBase {
81
86
  /** Create a new connection to the DuckDB instance, initializing if needed. */
82
87
  async getConnection() {
83
88
  await this.initialize();
89
+ if (this.closed) throw new Error("DuckDB connection is closed");
84
90
  if (!this.instance) throw new Error("DuckDB instance not initialized");
85
- return this.instance.connect();
91
+ this.activeConnections++;
92
+ try {
93
+ const connection = await this.instance.connect();
94
+ let released = false;
95
+ const release = () => {
96
+ if (!released) {
97
+ released = true;
98
+ this.releaseConnection();
99
+ }
100
+ };
101
+ return new Proxy(connection, { get(target, key) {
102
+ const value = Reflect.get(target, key, target);
103
+ if (typeof value !== "function") return value;
104
+ if (key === "closeSync" || key === "disconnectSync" || key === "close" || key === "disconnect") return (...args) => {
105
+ try {
106
+ const result = value.apply(target, args);
107
+ if (result instanceof Promise) return result.finally(release);
108
+ release();
109
+ return result;
110
+ } catch (error) {
111
+ release();
112
+ throw error;
113
+ }
114
+ };
115
+ return value.bind(target);
116
+ } });
117
+ } catch (error) {
118
+ this.releaseConnection();
119
+ throw error;
120
+ }
121
+ }
122
+ releaseConnection() {
123
+ this.activeConnections--;
124
+ if (this.activeConnections === 0) {
125
+ this.finishDrain?.();
126
+ this.finishDrain = null;
127
+ this.drainPromise = null;
128
+ }
86
129
  }
87
130
  closeConnection(connection) {
88
131
  const conn = connection;
@@ -243,6 +286,12 @@ var DuckDBConnection = class extends MastraBase {
243
286
  }
244
287
  /** Release the DuckDB instance, allowing garbage collection. */
245
288
  async close() {
289
+ this.closed = true;
290
+ await this.initPromise?.catch(() => void 0);
291
+ if (this.activeConnections > 0) {
292
+ this.drainPromise ??= new Promise((resolve) => this.finishDrain = resolve);
293
+ await this.drainPromise;
294
+ }
246
295
  if (this.instance) {
247
296
  try {
248
297
  const instance = this.instance;
@@ -263,7 +312,15 @@ const spanAggregateFeatures = typeof coreStorage.planSpanAggregate === "function
263
312
  const timeToFirstChunkSupported = "timeToFirstChunkMs" in coreStorage.TRACE_QUERY_FIELD_REGISTRY.trace;
264
313
  /** Core before the sort rejects `orderBy` on the field, so the sort is only declared when core plans it. */
265
314
  const timeToFirstChunkSortSupported = coreStorage.TRACE_QUERY_ORDER_FIELDS?.includes("timeToFirstChunkMs") === true;
266
- const timeToFirstChunkFeatures = [...timeToFirstChunkSupported ? ["trace-query-time-to-first-chunk"] : [], ...timeToFirstChunkSortSupported ? ["trace-query-time-to-first-chunk-sort"] : []];
267
- export { timeToFirstChunkSupported as a, bindParam as c, timeToFirstChunkFeatures as i, spanQueryFeatures as n, DuckDBConnection as o, threadQueryFeatures as r, DuckDBQueryTimeoutError as s, spanAggregateFeatures as t };
315
+ /** Same rule for time to first token: returned and sorted only when core knows the field. */
316
+ const timeToFirstTokenSupported = "timeToFirstTokenMs" in coreStorage.TRACE_QUERY_FIELD_REGISTRY.trace;
317
+ const timeToFirstTokenSortSupported = coreStorage.TRACE_QUERY_ORDER_FIELDS?.includes("timeToFirstTokenMs") === true;
318
+ const timingFeatures = [
319
+ ...timeToFirstChunkSupported ? ["trace-query-time-to-first-chunk"] : [],
320
+ ...timeToFirstChunkSortSupported ? ["trace-query-time-to-first-chunk-sort"] : [],
321
+ ...timeToFirstTokenSupported ? ["trace-query-time-to-first-token"] : [],
322
+ ...timeToFirstTokenSortSupported ? ["trace-query-time-to-first-token-sort"] : []
323
+ ];
324
+ export { timeToFirstTokenSupported as a, DuckDBQueryTimeoutError as c, timeToFirstChunkSupported as i, bindParam as l, spanQueryFeatures as n, timingFeatures as o, threadQueryFeatures as r, DuckDBConnection as s, spanAggregateFeatures as t };
268
325
 
269
- //# sourceMappingURL=features-B8gl38Ue.js.map
326
+ //# sourceMappingURL=features-dc98I6Rx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features-dc98I6Rx.js","names":[],"sources":["../src/storage/db/index.ts","../src/storage/features.ts"],"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/** A query interrupted at its caller-supplied deadline. */\nexport class DuckDBQueryTimeoutError extends Error {\n constructor() {\n super('DuckDB query exceeded its deadline');\n this.name = 'DuckDBQueryTimeoutError';\n }\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 closed = false;\n private activeConnections = 0;\n private drainPromise: Promise<void> | null = null;\n private finishDrain: (() => 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.closed) throw new Error('DuckDB connection is closed');\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.closed) throw new Error('DuckDB connection is closed');\n if (!this.instance) {\n throw new Error('DuckDB instance not initialized');\n }\n this.activeConnections++;\n try {\n const connection = await this.instance.connect();\n let released = false;\n const release = () => {\n if (!released) {\n released = true;\n this.releaseConnection();\n }\n };\n return new Proxy(connection, {\n get(target, key) {\n const value = Reflect.get(target, key, target);\n if (typeof value !== 'function') return value;\n if (key === 'closeSync' || key === 'disconnectSync' || key === 'close' || key === 'disconnect') {\n return (...args: unknown[]) => {\n try {\n const result = value.apply(target, args);\n if (result instanceof Promise) return result.finally(release);\n release();\n return result;\n } catch (error) {\n release();\n throw error;\n }\n };\n }\n return value.bind(target);\n },\n });\n } catch (error) {\n this.releaseConnection();\n throw error;\n }\n }\n\n private releaseConnection(): void {\n this.activeConnections--;\n if (this.activeConnections === 0) {\n this.finishDrain?.();\n this.finishDrain = null;\n this.drainPromise = null;\n }\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[] = [], timeoutMs?: number): Promise<T[]> {\n const connection = await this.getConnection();\n let timedOut = false;\n const timer =\n timeoutMs === undefined\n ? undefined\n : setTimeout(() => {\n timedOut = true;\n connection.interrupt();\n }, timeoutMs);\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 } catch (error) {\n if (timedOut) throw new DuckDBQueryTimeoutError();\n throw error;\n } finally {\n if (timer !== undefined) clearTimeout(timer);\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 /** Delete one bounded retention batch and return the number of rows removed. */\n async pruneBatch({\n tableName,\n column,\n cutoff,\n limit,\n }: {\n tableName: string;\n column: string;\n cutoff: Date;\n limit: number;\n }): Promise<number> {\n const identifier = /^[A-Za-z_][A-Za-z0-9_]*$/;\n if (!identifier.test(tableName) || !identifier.test(column)) {\n throw new Error(`Invalid retention identifier: ${tableName}.${column}`);\n }\n\n const rows = await this.query(\n `DELETE FROM ${tableName}\n WHERE rowid IN (\n SELECT rowid FROM ${tableName}\n WHERE ${column} < ?\n ORDER BY ${column}\n LIMIT ?\n )\n RETURNING 1 AS deleted`,\n [cutoff, limit],\n );\n return rows.length;\n }\n\n /** Execute parameterized statements atomically using a single DuckDB connection. */\n async executeTransaction(statements: readonly { sql: string; params?: readonly unknown[] }[]): Promise<void> {\n if (statements.length === 0) return;\n\n const connection = await this.getConnection();\n try {\n await connection.run('BEGIN TRANSACTION');\n for (const statement of statements) {\n const params = statement.params ?? [];\n if (params.length === 0) {\n await connection.run(statement.sql);\n continue;\n }\n let paramIndex = 0;\n const preparedSql = statement.sql.replace(/\\?/g, () => `$${++paramIndex}`);\n const prepared = await connection.prepare(preparedSql);\n for (let i = 0; i < params.length; i++) {\n bindParam(prepared, i + 1, params[i]);\n }\n await prepared.run();\n }\n await connection.run('COMMIT');\n } catch (error) {\n await connection.run('ROLLBACK').catch(() => undefined);\n throw error;\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 this.closed = true;\n await this.initPromise?.catch(() => undefined);\n if (this.activeConnections > 0) {\n this.drainPromise ??= new Promise<void>(resolve => (this.finishDrain = resolve));\n await this.drainPromise;\n }\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","import * as coreStorage from '@mastra/core/storage';\n\nexport const threadQueryFeatures =\n typeof coreStorage.planThreadRowsQuery === 'function' ? (['thread-query-rows'] as const) : ([] as const);\n\nexport const spanQueryFeatures =\n typeof coreStorage.planSpanQuery === 'function'\n ? (['span-query', 'span-query-context-fields'] as const)\n : ([] as const);\n\nexport const spanAggregateFeatures =\n typeof coreStorage.planSpanAggregate === 'function' ? (['span-aggregate'] as const) : ([] as const);\n\n/** Core versions without the field reject it in trace query results, so it is only returned when core knows it. */\nexport const timeToFirstChunkSupported = 'timeToFirstChunkMs' in coreStorage.TRACE_QUERY_FIELD_REGISTRY.trace;\n\n/** Core before the sort rejects `orderBy` on the field, so the sort is only declared when core plans it. */\nconst timeToFirstChunkSortSupported = coreStorage.TRACE_QUERY_ORDER_FIELDS?.includes('timeToFirstChunkMs') === true;\n\n/** Same rule for time to first token: returned and sorted only when core knows the field. */\nexport const timeToFirstTokenSupported = 'timeToFirstTokenMs' in coreStorage.TRACE_QUERY_FIELD_REGISTRY.trace;\nconst timeToFirstTokenSortSupported = coreStorage.TRACE_QUERY_ORDER_FIELDS?.includes('timeToFirstTokenMs') === true;\n\nexport const timingFeatures = [\n ...(timeToFirstChunkSupported ? (['trace-query-time-to-first-chunk'] as const) : []),\n ...(timeToFirstChunkSortSupported ? (['trace-query-time-to-first-chunk-sort'] as const) : []),\n ...(timeToFirstTokenSupported ? (['trace-query-time-to-first-token'] as const) : []),\n ...(timeToFirstTokenSortSupported ? (['trace-query-time-to-first-token-sort'] as const) : []),\n] as const;\n"],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_features = require("./features-DH60yLCA.cjs");
2
+ const require_features = require("./features-CMkGwt1J.cjs");
3
3
  let _duckdb_node_api = require("@duckdb/node-api");
4
4
  let _mastra_core_error = require("@mastra/core/error");
5
5
  let _mastra_core_storage = require("@mastra/core/storage");
@@ -505,7 +505,7 @@ const DUCKDB_OBSERVABILITY_FEATURES = [
505
505
  "trace-query-tenant-scope",
506
506
  "feedback",
507
507
  "trace-query-context-ids",
508
- ...require_features.timeToFirstChunkFeatures,
508
+ ...require_features.timingFeatures,
509
509
  "trace-query-root-span-fields",
510
510
  "trace-query-root-entity-id"
511
511
  ];
@@ -530,7 +530,7 @@ const DUCKDB_OBSERVABILITY_DELTA_FEATURES = [
530
530
  "trace-query-tenant-scope",
531
531
  "feedback",
532
532
  "trace-query-context-ids",
533
- ...require_features.timeToFirstChunkFeatures,
533
+ ...require_features.timingFeatures,
534
534
  "trace-query-root-span-fields",
535
535
  "trace-query-root-entity-id"
536
536
  ];
@@ -549,6 +549,8 @@ var ObservabilityStorageDuckDB = class extends _mastra_core_storage.Observabilit
549
549
  delegate = null;
550
550
  loadPromise = null;
551
551
  unavailableError = null;
552
+ pendingInits = /* @__PURE__ */ new Set();
553
+ closed = false;
552
554
  constructor(config) {
553
555
  super();
554
556
  this.db = config.db;
@@ -564,7 +566,7 @@ var ObservabilityStorageDuckDB = class extends _mastra_core_storage.Observabilit
564
566
  async loadDelegate() {
565
567
  if (this.delegate) return this.delegate;
566
568
  if (this.unavailableError) return null;
567
- if (!this.loadPromise) this.loadPromise = Promise.resolve().then(() => require("./observability-B-Vnz-ZL.cjs")).then(({ ObservabilityStorageDuckDB }) => {
569
+ if (!this.loadPromise) this.loadPromise = Promise.resolve().then(() => require("./observability-Dr89aflR.cjs")).then(({ ObservabilityStorageDuckDB }) => {
568
570
  const delegate = new ObservabilityStorageDuckDB({ db: this.db });
569
571
  this.delegate = delegate;
570
572
  return delegate;
@@ -596,9 +598,22 @@ var ObservabilityStorageDuckDB = class extends _mastra_core_storage.Observabilit
596
598
  return DUCKDB_OBSERVABILITY_DELTA_FEATURES;
597
599
  }
598
600
  async init(...args) {
599
- const delegate = await this.loadDelegate();
600
- if (!delegate) return;
601
- return delegate.init(...args);
601
+ if (this.closed) throw new Error("DuckDB observability storage is closed");
602
+ const init = (async () => {
603
+ const delegate = await this.loadDelegate();
604
+ if (delegate && !this.closed) await delegate.init(...args);
605
+ })();
606
+ this.pendingInits.add(init);
607
+ try {
608
+ await init;
609
+ } finally {
610
+ this.pendingInits.delete(init);
611
+ }
612
+ }
613
+ async close() {
614
+ this.closed = true;
615
+ await Promise.allSettled(this.pendingInits);
616
+ await this.db.close();
602
617
  }
603
618
  async migrateSpans(...args) {
604
619
  return (await this.requireDelegate()).migrateSpans(...args);
@@ -825,7 +840,7 @@ var DuckDBStore = class extends _mastra_core_storage.MastraCompositeStore {
825
840
  * Safe to call more than once; subsequent calls are no-ops.
826
841
  */
827
842
  async close() {
828
- await this.db.close();
843
+ await this.observabilityStore.close();
829
844
  }
830
845
  };
831
846
  exports.DuckDBConnection = require_features.DuckDBConnection;