@mastra/libsql 1.15.1 → 1.16.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 (28) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/docs/SKILL.md +4 -2
  3. package/dist/docs/assets/SOURCE_MAP.json +1 -1
  4. package/dist/docs/references/docs-agent-builder-overview.md +4 -3
  5. package/dist/docs/references/docs-agents-agent-approval.md +25 -2
  6. package/dist/docs/references/docs-agents-networks.md +1 -1
  7. package/dist/docs/references/docs-memory-memory-processors.md +67 -0
  8. package/dist/docs/references/docs-memory-message-history.md +56 -2
  9. package/dist/docs/references/docs-memory-overview.md +5 -3
  10. package/dist/docs/references/docs-memory-semantic-recall.md +36 -2
  11. package/dist/docs/references/docs-memory-working-memory.md +3 -3
  12. package/dist/docs/references/docs-storage-overview.md +214 -0
  13. package/dist/docs/references/docs-workflows-snapshots.md +1 -1
  14. package/dist/docs/references/reference-core-mastra-class.md +1 -1
  15. package/dist/docs/references/reference-file-based-agents-memory.md +58 -0
  16. package/dist/docs/references/reference-file-based-agents-storage.md +30 -0
  17. package/dist/docs/references/reference-memory-memory-class.md +1 -1
  18. package/dist/docs/references/reference-storage-composite.md +64 -6
  19. package/dist/docs/references/reference-storage-dynamodb.md +1 -1
  20. package/dist/docs/references/reference-storage-retention.md +74 -6
  21. package/dist/index.cjs +25 -0
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.js +25 -0
  24. package/dist/index.js.map +1 -1
  25. package/dist/vector/index.d.ts +12 -0
  26. package/dist/vector/index.d.ts.map +1 -1
  27. package/package.json +8 -8
  28. package/dist/docs/references/docs-memory-storage.md +0 -267
@@ -0,0 +1,58 @@
1
+ > Discover all available pages from the documentation index: https://mastra.ai/llms.txt
2
+
3
+ # Memory
4
+
5
+ A file-based agent gets [memory](https://mastra.ai/docs/memory/overview) from a `memory.ts` file that default-exports a [`Memory`](https://mastra.ai/reference/memory/memory-class) instance. Use this page for the file-based convention; use the memory docs for message history, semantic recall, storage, and processors.
6
+
7
+ Without `memory.ts` or `config.memory`, the agent has no memory by default. Each `generate()` or `stream()` call starts without remembered conversation state unless you pass the prior context yourself.
8
+
9
+ ## Quickstart
10
+
11
+ Create `memory.ts` next to the agent's `config.ts`:
12
+
13
+ ```typescript
14
+ import { Memory } from '@mastra/memory'
15
+
16
+ export default new Memory()
17
+ ```
18
+
19
+ The exported instance becomes the agent's `memory`. If your app configures a storage provider on the main Mastra instance, memory data is stored there. See [storage](https://mastra.ai/docs/storage/overview) for more information.
20
+
21
+ Use the same `resource` and `thread` values when calling the agent to continue a conversation:
22
+
23
+ ```typescript
24
+ const response = await weatherAgent.generate('Remember that I prefer Celsius.', {
25
+ memory: {
26
+ resource: 'user-123',
27
+ thread: 'weather-chat',
28
+ },
29
+ })
30
+ ```
31
+
32
+ ## Configure memory
33
+
34
+ Pass options to `new Memory()` when the default behavior isn't enough.
35
+
36
+ ```typescript
37
+ import { Memory } from '@mastra/memory'
38
+
39
+ export default new Memory({
40
+ options: {
41
+ lastMessages: 20,
42
+ workingMemory: {
43
+ enabled: true,
44
+ scope: 'resource',
45
+ },
46
+ },
47
+ })
48
+ ```
49
+
50
+ Visit the [`Memory` reference](https://mastra.ai/reference/memory/memory-class) for constructor options. Use these pages for related memory features:
51
+
52
+ - [Storage](https://mastra.ai/docs/storage/overview): configure persistence for memory data.
53
+ - [Semantic recall](https://mastra.ai/docs/memory/semantic-recall): retrieve relevant past messages by semantic meaning.
54
+ - [Memory processors](https://mastra.ai/docs/memory/memory-processors): filter, trim, or transform messages before memory adds them to model context.
55
+
56
+ ## Precedence with config
57
+
58
+ `config.memory` wins over `memory.ts`. If neither is present, the assembled file-based agent has no memory. See [`config.ts` precedence](https://mastra.ai/reference/file-based-agents/config) for the full merge table.
@@ -0,0 +1,30 @@
1
+ > Discover all available pages from the documentation index: https://mastra.ai/llms.txt
2
+
3
+ # Storage
4
+
5
+ Mastra sets the project's default [storage](https://mastra.ai/docs/storage/overview) from a `storage.ts` file directly under `src/mastra/`. The file default-exports a store, which replaces the built-in in-memory store used for memory, workflows, observability, and other storage domains.
6
+
7
+ Use this page for the file-based convention. For backend choice, storage domains, retention, and provider details, see [storage overview](https://mastra.ai/docs/storage/overview).
8
+
9
+ ## Quickstart
10
+
11
+ Use [`LibSQLStore`](https://mastra.ai/reference/storage/libsql) for a local file-backed store:
12
+
13
+ ```typescript
14
+ import { LibSQLStore } from '@mastra/libsql'
15
+
16
+ export default new LibSQLStore({
17
+ id: 'mastra-storage',
18
+ url: 'file:./mastra.db',
19
+ })
20
+ ```
21
+
22
+ Mastra registers the store before file-based agents and workflows, so storage-dependent primitives bind to this store instead of the default in-memory store.
23
+
24
+ ## Production backends
25
+
26
+ `storage.ts` can export any Mastra storage adapter, such as LibSQL, PostgreSQL, or MongoDB. For setup patterns, provider support, and schema details, see [storage overview](https://mastra.ai/docs/storage/overview), [observability storage](https://mastra.ai/docs/observability/storage), and the [storage reference](https://mastra.ai/reference/storage/overview).
27
+
28
+ ## Precedence with code
29
+
30
+ Code-registered storage wins over `storage.ts`. Use `storage.ts` when one project-wide store is enough; use code registration when setup depends on runtime wiring in `src/mastra/index.ts`.
@@ -37,7 +37,7 @@ export const agent = new Agent({
37
37
 
38
38
  **options** (`MemoryConfig`): Memory configuration options.
39
39
 
40
- **options.lastMessages** (`number | false`): Number of most recent messages to include in context. Set to false to disable loading conversation history into context. Use Number.MAX\_SAFE\_INTEGER to retrieve all messages with no limit. To prevent saving new messages, use the readOnly option instead.
40
+ **options.lastMessages** (`number | false`): Number of most recent messages to include in context. Set to false to disable the message history feature entirely (messages are not loaded into context or saved). Use Number.MAX\_SAFE\_INTEGER to retrieve all messages with no limit. To load messages without saving new ones, use the readOnly option.
41
41
 
42
42
  **options.readOnly** (`boolean`): When true, prevents memory from saving new messages and provides working memory as read-only context (without the updateWorkingMemory tool). Useful for read-only operations like previews, internal routing agents, or sub agents that should reference but not modify memory.
43
43
 
@@ -37,25 +37,25 @@ You'll also need to install the storage providers you want to compose:
37
37
  **npm**:
38
38
 
39
39
  ```bash
40
- npm install @mastra/pg@latest @mastra/libsql@latest
40
+ npm install @mastra/pg@latest @mastra/libsql@latest @mastra/mongodb@latest
41
41
  ```
42
42
 
43
43
  **pnpm**:
44
44
 
45
45
  ```bash
46
- pnpm add @mastra/pg@latest @mastra/libsql@latest
46
+ pnpm add @mastra/pg@latest @mastra/libsql@latest @mastra/mongodb@latest
47
47
  ```
48
48
 
49
49
  **Yarn**:
50
50
 
51
51
  ```bash
52
- yarn add @mastra/pg@latest @mastra/libsql@latest
52
+ yarn add @mastra/pg@latest @mastra/libsql@latest @mastra/mongodb@latest
53
53
  ```
54
54
 
55
55
  **Bun**:
56
56
 
57
57
  ```bash
58
- bun add @mastra/pg@latest @mastra/libsql@latest
58
+ bun add @mastra/pg@latest @mastra/libsql@latest @mastra/mongodb@latest
59
59
  ```
60
60
 
61
61
  ## Storage domains
@@ -124,6 +124,64 @@ export const mastra = new Mastra({
124
124
  })
125
125
  ```
126
126
 
127
+ ### Mixed backends
128
+
129
+ Use domain classes from each storage package to route different domains to different backends. The following example stores memory and workflow state in MongoDB, then routes observability to ClickHouse:
130
+
131
+ ```typescript
132
+ import { Mastra } from '@mastra/core'
133
+ import { MastraCompositeStore } from '@mastra/core/storage'
134
+ import { ObservabilityStorageClickhouse } from '@mastra/clickhouse'
135
+ import { MemoryStorageMongoDB, WorkflowsStorageMongoDB } from '@mastra/mongodb'
136
+
137
+ export const mastra = new Mastra({
138
+ storage: new MastraCompositeStore({
139
+ id: 'composite',
140
+ domains: {
141
+ memory: new MemoryStorageMongoDB({
142
+ uri: process.env.MONGODB_URI,
143
+ dbName: 'mastra_memory',
144
+ }),
145
+ workflows: new WorkflowsStorageMongoDB({
146
+ uri: process.env.MONGODB_URI,
147
+ dbName: 'mastra_workflows',
148
+ }),
149
+ observability: new ObservabilityStorageClickhouse({
150
+ url: process.env.CLICKHOUSE_URL,
151
+ username: process.env.CLICKHOUSE_USERNAME,
152
+ password: process.env.CLICKHOUSE_PASSWORD,
153
+ }),
154
+ },
155
+ }),
156
+ })
157
+ ```
158
+
159
+ ### Disabling a domain
160
+
161
+ Set a domain to `false` to disable it. A disabled domain doesn't fall back to `default`, so data for that domain isn't persisted:
162
+
163
+ ```typescript
164
+ import { MastraCompositeStore } from '@mastra/core/storage'
165
+ import { PostgresStore } from '@mastra/pg'
166
+ import { Mastra } from '@mastra/core'
167
+
168
+ const pgStore = new PostgresStore({
169
+ id: 'pg',
170
+ connectionString: process.env.DATABASE_URL,
171
+ })
172
+
173
+ export const mastra = new Mastra({
174
+ storage: new MastraCompositeStore({
175
+ id: 'composite',
176
+ default: pgStore,
177
+ domains: {
178
+ // don't persist traces and spans
179
+ observability: false,
180
+ },
181
+ }),
182
+ })
183
+ ```
184
+
127
185
  ## Options
128
186
 
129
187
  **id** (`string`): Unique identifier for this storage instance.
@@ -132,7 +190,7 @@ export const mastra = new Mastra({
132
190
 
133
191
  **disableInit** (`boolean`): When true, automatic initialization is disabled. You must call init() explicitly.
134
192
 
135
- **domains** (`object`): Individual domain overrides. Each domain can come from a different storage adapter. These take precedence over both editor and default storage.
193
+ **domains** (`object`): Individual domain overrides. Each domain can come from a different storage adapter. These take precedence over both editor and default storage. Set a domain to false to disable it entirely; a disabled domain does not fall back to editor or default.
136
194
 
137
195
  **domains.memory** (`MemoryStorage`): Storage for threads, messages, and resources.
138
196
 
@@ -274,6 +332,6 @@ const storage = new MastraCompositeStore({
274
332
  })
275
333
  ```
276
334
 
277
- Do not set `replication` on ClickHouse Cloud. Cloud rewrites `MergeTree` to `SharedMergeTree` server-side. See the [ClickHouse storage reference](https://mastra.ai/reference/storage/clickhouse) for the full config shape and operator notes.
335
+ Don't set `replication` on ClickHouse Cloud. Cloud rewrites `MergeTree` to `SharedMergeTree` server-side. See the [ClickHouse storage reference](https://mastra.ai/reference/storage/clickhouse) for the full config shape and operator notes.
278
336
 
279
337
  > **Info:** This approach is also required when using storage providers that don't support observability (like Convex, DynamoDB, or Cloudflare). See the [MastraStorageExporter documentation](https://mastra.ai/docs/observability/integrations/exporters/mastra-storage) for the full list of supported providers.
@@ -6,7 +6,7 @@ The DynamoDB storage implementation provides a scalable and performant NoSQL dat
6
6
 
7
7
  > **Observability Not Supported:** DynamoDB storage **doesn't support the observability domain**. Traces from the `MastraStorageExporter` can't be persisted to DynamoDB, and [Studio's](https://mastra.ai/docs/studio/overview) observability features won't work with DynamoDB as your only storage provider. To enable observability, use [composite storage](https://mastra.ai/reference/storage/composite) to route observability data to a supported provider like ClickHouse.
8
8
 
9
- > **Item Size Limit:** DynamoDB enforces a **400 KB maximum item size**. This limit can be exceeded when storing messages with base64-encoded attachments such as images. See [Handling large attachments](https://mastra.ai/docs/memory/storage) for workarounds including uploading attachments to external storage.
9
+ > **Item Size Limit:** DynamoDB enforces a **400 KB maximum item size**. This limit can be exceeded when storing messages with base64-encoded attachments such as images. See [Handling large attachments](https://mastra.ai/docs/memory/memory-processors) for workarounds including uploading attachments to external storage.
10
10
 
11
11
  ## Features
12
12
 
@@ -6,7 +6,7 @@ Storage grows without bound by default. Retention is an opt-in, age-based cleanu
6
6
 
7
7
  `prune()` deletes rows. It caps growth and is safe to run against large tables (batched, bounded, resumable, cancellable). It never reclaims disk — on SQLite/libSQL the freed pages are reused by future writes so the file stops growing, but handing disk back to the OS (for example a `VACUUM`) is left to the underlying database and the operator to manage.
8
8
 
9
- Retention covers **growth tables** only — tables that accumulate rows unbounded as a side effect of normal operation (conversation history, telemetry, job and run records, schedule fire history, event feeds). User-authored artifacts and config (agents, skills, workspaces, prompt blocks, datasets, schedule definitions, channel installations, and so on) grow with user intent and are edited or deleted explicitly, so they are not valid retention keys.
9
+ Retention covers **growth tables** only — tables that accumulate rows unbounded as a side effect of normal operation (conversation history, telemetry, job and run records, schedule fire history, event feeds). User-authored artifacts and config (agents, skills, workspaces, prompt blocks, datasets, schedule definitions, channel installations, and so on) grow with user intent and are edited or deleted explicitly, so they're not valid retention keys.
10
10
 
11
11
  The reference implementations are [libSQL](https://mastra.ai/reference/storage/libsql), [PostgreSQL](https://mastra.ai/reference/storage/postgresql), and [MongoDB](https://mastra.ai/reference/storage/mongodb). Other adapters keep rows forever until they implement retention.
12
12
 
@@ -89,8 +89,8 @@ Each domain declares which of its tables can be age-pruned and which timestamp c
89
89
  > **Note:**
90
90
  >
91
91
  > - The memory `observational_memory` table has no timestamp anchor, so it can't be age-pruned and isn't a valid retention key.
92
- > - Experiments prune as whole units: an aged experiment's result rows are deleted together with it (results cascade with their parent), so a run is never left partially deleted. There is no separate `results` key.
93
- > - For `schedules`, the growth table is the fire history (`schedule_triggers`, one row per fire) — schedule definitions are config and are not pruned.
92
+ > - Experiments prune as whole units: an aged experiment's result rows are deleted together with it (results cascade with their parent), so a run is never left partially deleted. Retention doesn't have a separate `results` key.
93
+ > - For `schedules`, the growth table is the fire history (`schedule_triggers`, one row per fire) — schedule definitions are config and aren't pruned.
94
94
  > - On PostgreSQL, timestamp anchors use the timezone-aware mirror columns (for example `createdAtZ`, `completedAtZ`).
95
95
  > - LibSQL supports all domains above; PostgreSQL and MongoDB support all except `threadState` and `harness`, which they don't implement.
96
96
  > - The v-next PostgreSQL observability domain stores signal events in day-partitioned tables (`spans`, `metrics`, `logs`, `scores`, `feedback`). For it, `prune()` drops whole day partitions (or TimescaleDB chunks) that are entirely older than the cutoff instead of deleting rows — effective granularity is one day, and a partition is only dropped once its entire day is past `maxAge`. `PruneResult.deleted` reports the number of rows in the dropped partitions.
@@ -105,6 +105,8 @@ Deletes rows older than their configured `maxAge` across every domain that has a
105
105
 
106
106
  `prune()` is designed to be safe on tables with millions of rows. It deletes in bounded, batched chunks — each batch is its own transaction — so it never takes a long lock or bloats the transaction log. It never runs a `VACUUM`.
107
107
 
108
+ Pass `options.retention` to replace the configured policies for that call only — for example to skip a domain (keep chat history) or prune more aggressively than the standing config. The store's configured `retention` is unchanged.
109
+
108
110
  Anchor-column indexes are created lazily on the first `prune()` call for each table with a policy — never at `init()` — so deployments that don't configure retention pay no extra index write or disk overhead. The first prune of an existing large table pays a one-time index build; subsequent prunes reuse the index.
109
111
 
110
112
  ```typescript
@@ -116,6 +118,13 @@ const results = await storage.prune({
116
118
  for (const r of results) {
117
119
  console.log(`${r.domain}.${r.table}: deleted ${r.deleted}, done=${r.done}`)
118
120
  }
121
+
122
+ // One-off pass with different policies (configured retention untouched):
123
+ await storage.prune({
124
+ retention: {
125
+ observability: { spans: { maxAge: '1d' } },
126
+ },
127
+ })
119
128
  ```
120
129
 
121
130
  Returns: `Promise<PruneResult[]>`
@@ -130,6 +139,8 @@ Returns: `Promise<PruneResult[]>`
130
139
 
131
140
  **signal** (`AbortSignal`): Cooperative cancellation. The batch loop checks it between batches and stops cleanly, returning partial results with done: false.
132
141
 
142
+ **retention** (`RetentionConfig`): Replaces the store's configured retention policies for this call only — e.g. to skip a domain or prune more aggressively. The configured retention is unchanged.
143
+
133
144
  ##### PruneResult
134
145
 
135
146
  Each result describes one table's progress:
@@ -145,7 +156,7 @@ interface PruneResult {
145
156
 
146
157
  ## Running prune on a schedule
147
158
 
148
- `prune()` has no built-in scheduler — you decide when it runs. Because it is bounded, a single call may not delete everything. When any result has `done: false`, eligible rows remain and you call again on the next tick. This keeps each invocation short and lets a large backlog drain over several runs.
159
+ `prune()` has no built-in scheduler — you decide when it runs. Because it's bounded, a single call may not delete everything. When any result has `done: false`, eligible rows remain and you call again on the next tick. This keeps each invocation short and lets a large backlog drain over several runs.
149
160
 
150
161
  ```typescript
151
162
  // Runs on your own cron (node-cron, a workflow schedule, an external job, etc.).
@@ -164,11 +175,68 @@ async function retentionTick() {
164
175
 
165
176
  You can also cancel a long-running prune with an `AbortSignal` — the loop stops between batches and returns partial results with `done: false`, so the next run resumes cleanly.
166
177
 
178
+ ## MongoDB TTL indexes (alternative to prune)
179
+
180
+ MongoDB offers native [TTL (Time-To-Live) indexes](https://www.mongodb.com/docs/manual/core/index-ttl/) that automatically delete expired documents without requiring manual `prune()` calls. This is a database-level feature that runs as a background thread.
181
+
182
+ > **When to use TTL vs prune():** **Use MongoDB TTL indexes when:**
183
+ >
184
+ > - You want automated, zero-maintenance deletion
185
+ > - Your retention periods are fixed (e.g., "always 30 days")
186
+ > - You prefer database-native solutions
187
+ >
188
+ > **Use `prune()` when:**
189
+ >
190
+ > - You need fine-grained control over deletion timing
191
+ > - You want to cap deletion rate during business hours
192
+ > - You need resumable, cancellable cleanup operations
193
+ > - You're using composite storage with multiple databases
194
+ >
195
+ > Both approaches are valid. TTL is simpler; `prune()` gives more control.
196
+
197
+ ### Setting up TTL indexes on MongoDB
198
+
199
+ TTL indexes work on date fields. MongoDB checks the index every 60 seconds and deletes documents where the date field + TTL duration < current time.
200
+
201
+ ```typescript
202
+ import { MongoDBStore } from '@mastra/mongodb'
203
+
204
+ const storage = new MongoDBStore({
205
+ id: 'mongodb-storage',
206
+ uri: process.env.MONGODB_URI!,
207
+ dbName: process.env.MONGODB_DB_NAME!,
208
+ indexes: [
209
+ // Messages expire after 30 days
210
+ {
211
+ collection: 'mastra_messages',
212
+ keys: { createdAt: 1 },
213
+ options: { expireAfterSeconds: 30 * 24 * 60 * 60 }, // 30 days
214
+ },
215
+ // Threads expire after 90 days
216
+ {
217
+ collection: 'mastra_threads',
218
+ keys: { createdAt: 1 },
219
+ options: { expireAfterSeconds: 90 * 24 * 60 * 60 }, // 90 days
220
+ },
221
+ // Spans expire after 7 days
222
+ {
223
+ collection: 'mastra_ai_spans',
224
+ keys: { startedAt: 1 },
225
+ options: { expireAfterSeconds: 7 * 24 * 60 * 60 }, // 7 days
226
+ },
227
+ ],
228
+ })
229
+ ```
230
+
231
+ > **Tip:** TTL indexes delete documents shortly after they expire (background thread runs every \~60 seconds), but the exact timing is not guaranteed. For precise, immediate cleanup, use `prune()` instead.
232
+
167
233
  ## Reclaiming disk
168
234
 
169
- `prune()` deletes rows but does not shrink the database file. On SQLite/libSQL the freed pages go on a freelist and are reused by future writes, so the file stops growing — for most users this alone solves the unbounded-growth problem.
235
+ `prune()` deletes rows but doesn't shrink the database file. On SQLite/libSQL the freed pages go on a freelist and are reused by future writes, so the file stops growing — for most users this alone solves the unbounded-growth problem.
236
+
237
+ Handing that free space back to the OS is a separate concern that Mastra doesn't manage. If you specifically need to shrink the file, run the underlying database's compaction (for example `VACUUM` on self-hosted libSQL) yourself, in a maintenance window — a full `VACUUM` locks the file and needs roughly twice the file size in free disk. On PostgreSQL, autovacuum reclaims dead tuples for reuse automatically; a manual `VACUUM FULL` is only needed if you must return disk to the OS.
170
238
 
171
- Handing that free space back to the OS is a separate concern that Mastra does not manage. If you specifically need to shrink the file, run the underlying database's compaction (for example `VACUUM` on self-hosted libSQL) yourself, in a maintenance window — a full `VACUUM` locks the file and needs roughly twice the file size in free disk. On PostgreSQL, autovacuum reclaims dead tuples for reuse automatically; a manual `VACUUM FULL` is only needed if you must return disk to the OS.
239
+ For MongoDB, deleted documents are reused by future insertions. To reclaim disk space, run [`db.runCommand({ compact: "collection_name" })`](https://www.mongodb.com/docs/manual/reference/command/compact/) during a maintenance window.
172
240
 
173
241
  > **LibSQL and Turso:** [Turso Cloud](https://mastra.ai/reference/storage/libsql) manages storage compaction for you, so there's nothing to reclaim manually. This applies only to self-hosted libSQL files.
174
242
 
package/dist/index.cjs CHANGED
@@ -545,6 +545,31 @@ var LibSQLVector = class extends vector.MastraVector {
545
545
  }
546
546
  this.vectorIndexes = this.isMemoryDb ? Promise.resolve(/* @__PURE__ */ new Set()) : this.discoverVectorIndexes();
547
547
  }
548
+ /**
549
+ * Closes the underlying libsql client, releasing all OS file handles.
550
+ *
551
+ * For local file databases, first runs PRAGMA wal_checkpoint(TRUNCATE) and
552
+ * switches back to journal_mode=DELETE so the -wal and -shm sidecar files
553
+ * are released promptly (mirrors LibSQLStore.close()).
554
+ *
555
+ * Remote (Turso) databases skip the WAL pragmas and just close the client.
556
+ *
557
+ * Safe to call more than once; subsequent calls are no-ops.
558
+ */
559
+ async close() {
560
+ if (this.turso.closed) {
561
+ return;
562
+ }
563
+ if (this.turso.protocol === "file" && !this.isMemoryDb) {
564
+ try {
565
+ await this.turso.execute("PRAGMA wal_checkpoint(TRUNCATE);");
566
+ await this.turso.execute("PRAGMA journal_mode=DELETE;");
567
+ } catch (err) {
568
+ this.logger.warn("LibSQLVector: Failed to checkpoint WAL before close.", err);
569
+ }
570
+ }
571
+ this.turso.close();
572
+ }
548
573
  async discoverVectorIndexes() {
549
574
  try {
550
575
  const result = await this.turso.execute({