@mastra/duckdb 1.2.0 → 1.3.0-alpha.1

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,61 @@
1
1
  # @mastra/duckdb
2
2
 
3
+ ## 1.3.0-alpha.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Improved performance of `listTraces` and `listBranches` on DuckDB. The Traces and Branches lists in the observability UI now load noticeably faster, especially on large span tables, because filtering and pagination happen up front and the store only assembles full span data for the rows on the page being viewed. ([#16165](https://github.com/mastra-ai/mastra/pull/16165))
8
+
9
+ No API or behavior changes — return shapes and filter semantics are unchanged, and no migration is required.
10
+
11
+ - Updated dependencies [[`ca28c23`](https://github.com/mastra-ai/mastra/commit/ca28c232a2f18801a6cf20fe053479237b4d4fb0)]:
12
+ - @mastra/core@1.32.0-alpha.3
13
+
14
+ ## 1.3.0-alpha.0
15
+
16
+ ### Minor Changes
17
+
18
+ - - **Added** `listBranches` and `getSpans` implementations. ([#16154](https://github.com/mastra-ai/mastra/pull/16154))
19
+ - Historical span data is queryable immediately; no migration required.
20
+
21
+ - Added `count_distinct` aggregation and server-side TopK to the metrics storage API so dashboards built on high-cardinality fields (like `threadId` or `resourceId`) stay fast and bounded. ([#16137](https://github.com/mastra-ai/mastra/pull/16137))
22
+
23
+ **New aggregation**
24
+
25
+ `getMetricAggregate`, `getMetricBreakdown`, and `getMetricTimeSeries` accept `aggregation: 'count_distinct'` with a `distinctColumn`. Backends pick the most efficient native implementation — `uniq` on ClickHouse, `approx_count_distinct` on DuckDB.
26
+
27
+ `distinctColumn` is restricted to a low/medium-cardinality categorical allowlist (`entityType`, `entityName`, `parentEntityType`, `parentEntityName`, `rootEntityType`, `rootEntityName`, `name`, `provider`, `model`, `environment`, `executionSource`, `serviceName`). ID columns are not allowed — distinct counts over near-unique values converge to the row count and are rarely useful.
28
+
29
+ ```ts
30
+ await store.getMetricAggregate({
31
+ name: ['mastra_llm_tokens_total'],
32
+ aggregation: 'count_distinct',
33
+ distinctColumn: 'model',
34
+ filters: { timestamp: { start, end } },
35
+ });
36
+ ```
37
+
38
+ **Server-side TopK**
39
+
40
+ `getMetricBreakdown` accepts `limit` and `orderDirection`, so breakdowns never return the full cardinality of a column from the database. Ordering is always by the aggregated `value`; `orderDirection` flips between top-N (`DESC`, default) and bottom-N (`ASC`).
41
+
42
+ ```ts
43
+ await store.getMetricBreakdown({
44
+ name: ['mastra_agent_duration_ms'],
45
+ aggregation: 'sum',
46
+ groupBy: ['threadId'],
47
+ limit: 20,
48
+ orderDirection: 'DESC',
49
+ });
50
+ ```
51
+
52
+ ### Patch Changes
53
+
54
+ - Added direct score lookup support to observability storage so score records can be fetched by `scoreId` without scanning paginated score lists, including DuckDB and ClickHouse vNext observability stores. ([#16162](https://github.com/mastra-ai/mastra/pull/16162))
55
+
56
+ - Updated dependencies [[`86c0298`](https://github.com/mastra-ai/mastra/commit/86c0298e647306423c842f9d5ac827bd616bd13d), [`7fce309`](https://github.com/mastra-ai/mastra/commit/7fce30912b14170bfc41f0ac736cca0f39fe0cd4), [`7997c2e`](https://github.com/mastra-ai/mastra/commit/7997c2e55ddd121562a4098cd8d2b89c68433bf1), [`e97ccb9`](https://github.com/mastra-ai/mastra/commit/e97ccb900f8b7a390ce82c9f8eb8d6eb2c5e3777), [`c5daf48`](https://github.com/mastra-ai/mastra/commit/c5daf48556e98c46ae06caf00f92c249912007e9), [`cd96779`](https://github.com/mastra-ai/mastra/commit/cd9677937f113b2856dc8b9f3d4bdabcee58bb2e)]:
57
+ - @mastra/core@1.32.0-alpha.2
58
+
3
59
  ## 1.2.0
4
60
 
5
61
  ### Minor Changes
@@ -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.2.0"
6
+ version: "1.3.0-alpha.1"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -16,6 +16,7 @@ Read the individual reference documents for detailed explanations and code examp
16
16
 
17
17
  ### Reference
18
18
 
19
+ - [Reference: DuckDB storage](references/reference-storage-duckdb.md) - Documentation for the DuckDB storage implementation in Mastra, an embedded analytical backend for local observability development.
19
20
  - [Reference: DuckDB vector store](references/reference-vectors-duckdb.md) - Documentation for the DuckDBVector class in Mastra, which provides embedded high-performance vector search using DuckDB with HNSW indexing.
20
21
 
21
22
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.2.0",
2
+ "version": "1.3.0-alpha.1",
3
3
  "package": "@mastra/duckdb",
4
4
  "exports": {
5
5
  "DuckDBConnection": {
@@ -0,0 +1,150 @@
1
+ # DuckDB storage
2
+
3
+ [DuckDB](https://duckdb.org/) is an embedded, in-process analytical database. The `@mastra/duckdb` package provides an OLAP-backed observability store for local development, suitable for traces, logs, metrics, scores, and feedback without running an external service.
4
+
5
+ For vector search, see the [DuckDB vector store reference](https://mastra.ai/reference/vectors/duckdb), which is a separate API in the same package.
6
+
7
+ ## When to use DuckDB
8
+
9
+ Local development of observability features. DuckDB is embedded and file-based, so it does not require a server and starts instantly. It supports the same observability signals as ClickHouse, which makes it useful for testing dashboards and trace exploration before deploying to a production backend.
10
+
11
+ DuckDB currently implements only the `observability` domain. Pair it with another storage adapter (such as [LibSQL](https://mastra.ai/reference/storage/libsql)) for `memory` and `workflows` in a [composite storage](https://mastra.ai/reference/storage/composite) setup.
12
+
13
+ > **Warning:** DuckDB is for development and not recommended for production. It runs in-process, persists to a single local file, and does not work on platforms with ephemeral filesystems (such as Railway, Fly.io, Render, Heroku, or serverless containers). For production observability, use [ClickHouse](https://mastra.ai/reference/storage/clickhouse).
14
+
15
+ ## Installation
16
+
17
+ **npm**:
18
+
19
+ ```bash
20
+ npm install @mastra/duckdb@latest
21
+ ```
22
+
23
+ **pnpm**:
24
+
25
+ ```bash
26
+ pnpm add @mastra/duckdb@latest
27
+ ```
28
+
29
+ **Yarn**:
30
+
31
+ ```bash
32
+ yarn add @mastra/duckdb@latest
33
+ ```
34
+
35
+ **Bun**:
36
+
37
+ ```bash
38
+ bun add @mastra/duckdb@latest
39
+ ```
40
+
41
+ ## Usage
42
+
43
+ ### As the observability domain in a composite store
44
+
45
+ This is the standard local-development setup. LibSQL handles the other domains, and DuckDB handles observability.
46
+
47
+ ```typescript
48
+ import { Mastra } from '@mastra/core'
49
+ import { MastraCompositeStore } from '@mastra/core/storage'
50
+ import { LibSQLStore } from '@mastra/libsql'
51
+ import { DuckDBStore } from '@mastra/duckdb'
52
+ import { Observability, DefaultExporter } from '@mastra/observability'
53
+
54
+ export const mastra = new Mastra({
55
+ storage: new MastraCompositeStore({
56
+ id: 'composite-storage',
57
+ default: new LibSQLStore({
58
+ id: 'mastra-storage',
59
+ url: 'file:./mastra.db',
60
+ }),
61
+ domains: {
62
+ observability: new DuckDBStore().observability,
63
+ },
64
+ }),
65
+ observability: new Observability({
66
+ configs: {
67
+ default: {
68
+ serviceName: 'mastra',
69
+ exporters: [new DefaultExporter()],
70
+ },
71
+ },
72
+ }),
73
+ })
74
+ ```
75
+
76
+ The `.observability` accessor returns the observability domain store directly. The equivalent generic form uses `getStore()`, which works for any composite-style storage adapter:
77
+
78
+ ```typescript
79
+ const observability = await new DuckDBStore().getStore('observability')
80
+ ```
81
+
82
+ ### Standalone
83
+
84
+ When you need only observability storage outside the `Mastra` composite, instantiate `DuckDBStore` directly and access the observability domain:
85
+
86
+ ```typescript
87
+ import { DuckDBStore } from '@mastra/duckdb'
88
+
89
+ const duckdb = new DuckDBStore({ path: './traces.duckdb' })
90
+ const observability = duckdb.observability
91
+
92
+ await observability.init()
93
+ ```
94
+
95
+ ### In-memory database
96
+
97
+ Pass `:memory:` to use an ephemeral DuckDB instance. Data is lost when the process exits, which is appropriate for unit tests and short-lived scripts.
98
+
99
+ ```typescript
100
+ const duckdb = new DuckDBStore({ path: ':memory:' })
101
+ ```
102
+
103
+ ## Configuration
104
+
105
+ ### `DuckDBStore` options
106
+
107
+ **id** (`string`): Unique identifier for this storage instance. (Default: `'duckdb'`)
108
+
109
+ **path** (`string`): Path to the DuckDB database file. Use \`:memory:\` for an ephemeral in-memory database. (Default: `'mastra.duckdb'`)
110
+
111
+ ### Lower-level types
112
+
113
+ `@mastra/duckdb` also exports `DuckDBConnection` for sharing a single underlying database across multiple Mastra storage instances, and the corresponding `DuckDBStorageConfig` type. Most applications will not need these directly.
114
+
115
+ ## Supported domains
116
+
117
+ DuckDB currently implements one storage domain:
118
+
119
+ | Domain | Supported |
120
+ | --------------- | --------- |
121
+ | `observability` | Yes |
122
+ | `memory` | No |
123
+ | `workflows` | No |
124
+ | `scores` | No |
125
+ | `agents` | No |
126
+
127
+ For a full storage solution, compose `DuckDBStore` with an adapter that covers the missing domains (most commonly [LibSQL](https://mastra.ai/reference/storage/libsql) for local development).
128
+
129
+ ## Initialization
130
+
131
+ When passed to `Mastra` through `MastraCompositeStore`, the observability domain initializes itself on first use. To run initialization explicitly outside of `Mastra`, call `init()` on the observability store:
132
+
133
+ ```typescript
134
+ import { DuckDBStore } from '@mastra/duckdb'
135
+
136
+ const duckdb = new DuckDBStore({ path: './traces.duckdb' })
137
+ await duckdb.observability.init()
138
+ ```
139
+
140
+ ## Observability strategy
141
+
142
+ DuckDB supports the `event-sourced` strategy used by `DefaultExporter`, which buffers spans in memory and writes completed events in batches. This is appropriate for development-scale traffic. For high-volume production workloads, see [`DefaultExporter` storage provider support](https://mastra.ai/docs/observability/tracing/exporters/default).
143
+
144
+ ## Related
145
+
146
+ - [Storage overview](https://mastra.ai/reference/storage/overview)
147
+ - [Composite storage](https://mastra.ai/reference/storage/composite)
148
+ - [ClickHouse storage](https://mastra.ai/reference/storage/clickhouse): Production observability backend
149
+ - [DuckDB vector store](https://mastra.ai/reference/vectors/duckdb): Vector search using the same package
150
+ - [Observability overview](https://mastra.ai/docs/observability/overview)
package/dist/index.cjs CHANGED
@@ -583,7 +583,7 @@ var ObservabilityStorageDuckDB = class extends storage.ObservabilityStorage {
583
583
  return null;
584
584
  }
585
585
  if (!this.loadPromise) {
586
- this.loadPromise = import('./observability-AILZGFQT.cjs').then(({ ObservabilityStorageDuckDB: ObservabilityStorageDuckDB2 }) => {
586
+ this.loadPromise = import('./observability-2PJ44OVC.cjs').then(({ ObservabilityStorageDuckDB: ObservabilityStorageDuckDB2 }) => {
587
587
  const delegate = new ObservabilityStorageDuckDB2({ db: this.db });
588
588
  this.delegate = delegate;
589
589
  return delegate;
@@ -640,6 +640,10 @@ var ObservabilityStorageDuckDB = class extends storage.ObservabilityStorage {
640
640
  const delegate = await this.requireDelegate();
641
641
  return delegate.getSpan(...args);
642
642
  }
643
+ async getSpans(...args) {
644
+ const delegate = await this.requireDelegate();
645
+ return delegate.getSpans(...args);
646
+ }
643
647
  async getRootSpan(...args) {
644
648
  const delegate = await this.requireDelegate();
645
649
  return delegate.getRootSpan(...args);
@@ -656,6 +660,10 @@ var ObservabilityStorageDuckDB = class extends storage.ObservabilityStorage {
656
660
  const delegate = await this.requireDelegate();
657
661
  return delegate.listTraces(...args);
658
662
  }
663
+ async listBranches(...args) {
664
+ const delegate = await this.requireDelegate();
665
+ return delegate.listBranches(...args);
666
+ }
659
667
  async batchCreateSpans(...args) {
660
668
  const delegate = await this.requireDelegate();
661
669
  return delegate.batchCreateSpans(...args);
@@ -744,6 +752,10 @@ var ObservabilityStorageDuckDB = class extends storage.ObservabilityStorage {
744
752
  const delegate = await this.requireDelegate();
745
753
  return delegate.listScores(...args);
746
754
  }
755
+ async getScoreById(...args) {
756
+ const delegate = await this.requireDelegate();
757
+ return delegate.getScoreById(...args);
758
+ }
747
759
  async getScoreAggregate(...args) {
748
760
  const delegate = await this.requireDelegate();
749
761
  return delegate.getScoreAggregate(...args);