@mastra/cloudflare-d1 1.1.1-alpha.0 → 1.2.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,67 @@
1
1
  # @mastra/cloudflare-d1
2
2
 
3
+ ## 1.2.0-alpha.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Added exact metadata filtering to message history queries across Memory APIs and supported storage providers. ([#19991](https://github.com/mastra-ai/mastra/pull/19991))
8
+
9
+ ```ts
10
+ const messages = await memory.recall({
11
+ threadId: 'thread-1',
12
+ filter: {
13
+ metadata: {
14
+ status: 'done',
15
+ priority: 'high',
16
+ },
17
+ },
18
+ });
19
+ ```
20
+
21
+ Multiple fields use AND semantics. Supported values are strings, finite numbers, booleans, and `null`.
22
+
23
+ ### Patch Changes
24
+
25
+ - Updated dependencies [[`0dca9d0`](https://github.com/mastra-ai/mastra/commit/0dca9d0b1356024a53b72ea6f040db528b126caa)]:
26
+ - @mastra/core@1.54.0-alpha.0
27
+
28
+ ## 1.1.1
29
+
30
+ ### Patch Changes
31
+
32
+ - Add optional `batchId`, `datasetId`, and `datasetItemId` fields to persisted scores so saved baseline scores can be grouped as one scoring pass and joined back to the dataset items they came from. ([#18331](https://github.com/mastra-ai/mastra/pull/18331))
33
+ - `scoreTrace()` accepts top-level `batchId`, `datasetId`, and `datasetItemId` when persisting a score for a stored trace.
34
+ - `ScoreRowData` and score save payloads now include nullable `batchId`, `datasetId`, and `datasetItemId`.
35
+ - Built-in stores with explicit score schema or attribute mappings now persist these provenance fields on saved scores.
36
+ - D1, DSQL, MSSQL, and Upstash score stores now apply additive provenance migrations or deterministic score ordering for persisted score reads.
37
+
38
+ ```ts
39
+ await scoreTrace({
40
+ storage,
41
+ scorer,
42
+ target: { traceId },
43
+ batchId: 'baseline-batch-1',
44
+ datasetId,
45
+ datasetItemId,
46
+ });
47
+ ```
48
+
49
+ - Added optional `organizationId` and `projectId` fields to scores for multi-tenant isolation. Scores can now be saved with tenancy metadata and the `listScoresBy*` methods accept a `filters` option to scope results by organization and project. ([#18331](https://github.com/mastra-ai/mastra/pull/18331))
50
+
51
+ ```ts
52
+ await storage.saveScore({ ...score, organizationId: 'org-a', projectId: 'proj-1' });
53
+
54
+ const result = await storage.listScoresByScorerId({
55
+ scorerId,
56
+ filters: { organizationId: 'org-a', projectId: 'proj-1' },
57
+ });
58
+ ```
59
+
60
+ `projectId` identifies the project scope, separate from `resourceId` which continues to mean the agent memory resource.
61
+
62
+ - Updated dependencies [[`700619b`](https://github.com/mastra-ai/mastra/commit/700619b61d572e592cbaaf758121d168844ca4d2), [`0f69865`](https://github.com/mastra-ai/mastra/commit/0f69865aced225d98eac812e22699dc445ee18cb), [`9250acd`](https://github.com/mastra-ai/mastra/commit/9250acd1357f0f1f33d0dcca16f9655084c58eca), [`0c3d4bc`](https://github.com/mastra-ai/mastra/commit/0c3d4bcae13ea3699d379403e6f350d5cf4efe9f), [`cc440a3`](https://github.com/mastra-ai/mastra/commit/cc440a39400d8ce06655462b26c1666a1b3d4320), [`6a61846`](https://github.com/mastra-ai/mastra/commit/6a61846eeda29fb714549b70f1bee2bf6b141c44), [`215f9b0`](https://github.com/mastra-ai/mastra/commit/215f9b0f3f3f6fc165edad360582dd4d3d7ea748), [`17369b2`](https://github.com/mastra-ai/mastra/commit/17369b25250561e9ed994ae509be1d15bfb33bcb), [`c64c2a8`](https://github.com/mastra-ai/mastra/commit/c64c2a8503a50252f9ca6b8e8c54cadee31b92a2), [`bcae929`](https://github.com/mastra-ai/mastra/commit/bcae929945cbf265bd9f327cc715ecafa072b5b9), [`ea6327b`](https://github.com/mastra-ai/mastra/commit/ea6327ba2d63ca647804bc97b347e03a58617162), [`3439fa8`](https://github.com/mastra-ai/mastra/commit/3439fa836ecfcaa257b40c20b30ac2a8be22e9ea), [`85107f2`](https://github.com/mastra-ai/mastra/commit/85107f2758b527147fccbedff962961927c2d3b8), [`b33822e`](https://github.com/mastra-ai/mastra/commit/b33822e8d470884954b02f7b0745407ee4ef74b1), [`06e2680`](https://github.com/mastra-ai/mastra/commit/06e26806b51d2cbd858afdc66daa2b86ff3ba64a), [`06ff9e0`](https://github.com/mastra-ai/mastra/commit/06ff9e0befd1d642ab87ff749285ee4091205c7e), [`d5c11e3`](https://github.com/mastra-ai/mastra/commit/d5c11e3ba5045969caa7272a7bd1fd141c93ab6c), [`7f5e1ff`](https://github.com/mastra-ai/mastra/commit/7f5e1ff695a92f672bb3976363925d1e9136b54a), [`ff80671`](https://github.com/mastra-ai/mastra/commit/ff8067185e208b27198b4e5b71803013175c3643), [`b8375c1`](https://github.com/mastra-ai/mastra/commit/b8375c1f8fe905df8ae2ae9a893bb365f17aec4e), [`dab1257`](https://github.com/mastra-ai/mastra/commit/dab1257b64e4ed576dc5038bb7a3f7072338bc9f), [`1240f05`](https://github.com/mastra-ai/mastra/commit/1240f051c8e5371f1c014448bf37b1a1b9a05e47), [`705ff39`](https://github.com/mastra-ai/mastra/commit/705ff3969e57214ff2fdaf3815d751dd558886ed), [`e6fbd5b`](https://github.com/mastra-ai/mastra/commit/e6fbd5bfdc28e92c0c0433f29aa1bc152d3430f6), [`215f9b0`](https://github.com/mastra-ai/mastra/commit/215f9b0f3f3f6fc165edad360582dd4d3d7ea748), [`24c10d3`](https://github.com/mastra-ai/mastra/commit/24c10d333e6649ac06075903aeeee13a933db3b3), [`24c10d3`](https://github.com/mastra-ai/mastra/commit/24c10d333e6649ac06075903aeeee13a933db3b3), [`24c10d3`](https://github.com/mastra-ai/mastra/commit/24c10d333e6649ac06075903aeeee13a933db3b3), [`6f2026c`](https://github.com/mastra-ai/mastra/commit/6f2026cdf114ff1e21e49133ca774ec7d5085059), [`24c10d3`](https://github.com/mastra-ai/mastra/commit/24c10d333e6649ac06075903aeeee13a933db3b3), [`215f9b0`](https://github.com/mastra-ai/mastra/commit/215f9b0f3f3f6fc165edad360582dd4d3d7ea748), [`215f9b0`](https://github.com/mastra-ai/mastra/commit/215f9b0f3f3f6fc165edad360582dd4d3d7ea748), [`003f35d`](https://github.com/mastra-ai/mastra/commit/003f35d19e07b23b4bacc591c8bc0c59b42124ae), [`f890eda`](https://github.com/mastra-ai/mastra/commit/f890eda2c8a2ae83d9b30bc6d85842f93b6c266b), [`1340fb7`](https://github.com/mastra-ai/mastra/commit/1340fb76262a3ca062130aa71859f07257a0a5a4)]:
63
+ - @mastra/core@1.49.0
64
+
3
65
  ## 1.1.1-alpha.0
4
66
 
5
67
  ### Patch Changes
@@ -3,7 +3,7 @@ name: mastra-cloudflare-d1
3
3
  description: Documentation for @mastra/cloudflare-d1. Use when working with @mastra/cloudflare-d1 APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/cloudflare-d1"
6
- version: "1.1.1-alpha.0"
6
+ version: "1.2.0-alpha.0"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1.1-alpha.0",
2
+ "version": "1.2.0-alpha.0",
3
3
  "package": "@mastra/cloudflare-d1",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -6,7 +6,7 @@ The Cloudflare D1 storage implementation provides a serverless SQL database solu
6
6
 
7
7
  > **Observability Not Supported:** Cloudflare D1 storage **doesn't support the observability domain**. Traces from the `MastraStorageExporter` can't be persisted to D1, and [Studio's](https://mastra.ai/docs/studio/overview) observability features won't work with D1 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
- > **Row Size Limit:** Cloudflare D1 enforces a **1 MiB maximum row 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
+ > **Row Size Limit:** Cloudflare D1 enforces a **1 MiB maximum row 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
  ## Installation
12
12
 
package/dist/index.cjs CHANGED
@@ -997,6 +997,40 @@ var BackgroundTasksStorageD1 = class extends storage.BackgroundTasksStorage {
997
997
  return Number(row?.count ?? 0);
998
998
  }
999
999
  };
1000
+ function addSqliteMetadataFilter(conditions, params, metadataFilter) {
1001
+ if (!metadataFilter) return;
1002
+ for (const [key, value] of Object.entries(metadataFilter)) {
1003
+ const path = `$.metadata.${key}`;
1004
+ conditions.push(`CASE WHEN json_valid(content) THEN json_type(content, ?) IS NOT NULL ELSE 0 END`);
1005
+ params.push(path);
1006
+ addSqliteMetadataValuePredicate(conditions, params, path, value);
1007
+ }
1008
+ }
1009
+ function addSqliteMetadataValuePredicate(conditions, params, path, value) {
1010
+ if (value === null) {
1011
+ conditions.push(`CASE WHEN json_valid(content) THEN json_type(content, ?) = 'null' ELSE 0 END`);
1012
+ params.push(path);
1013
+ return;
1014
+ }
1015
+ if (typeof value === "string") {
1016
+ conditions.push(
1017
+ `CASE WHEN json_valid(content) THEN json_type(content, ?) = 'text' AND json_extract(content, ?) = ? ELSE 0 END`
1018
+ );
1019
+ params.push(path, path, value);
1020
+ return;
1021
+ }
1022
+ if (typeof value === "number") {
1023
+ conditions.push(
1024
+ `CASE WHEN json_valid(content) THEN json_type(content, ?) IN ('integer', 'real') AND json_extract(content, ?) = ? ELSE 0 END`
1025
+ );
1026
+ params.push(path, path, value);
1027
+ return;
1028
+ }
1029
+ conditions.push(
1030
+ `CASE WHEN json_valid(content) THEN json_type(content, ?) = ? AND json_extract(content, ?) = ? ELSE 0 END`
1031
+ );
1032
+ params.push(path, value ? "true" : "false", path, value ? 1 : 0);
1033
+ }
1000
1034
  var MemoryStorageD1 = class extends storage.MemoryStorage {
1001
1035
  #db;
1002
1036
  constructor(config) {
@@ -1602,6 +1636,7 @@ var MemoryStorageD1 = class extends storage.MemoryStorage {
1602
1636
  }
1603
1637
  const perPage = storage.normalizePerPage(perPageInput, 40);
1604
1638
  const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
1639
+ const metadataFilter = storage.validateStorageMetadataFilter(filter?.metadata);
1605
1640
  try {
1606
1641
  const fullTableName = this.#db.getTableName(storage.TABLE_MESSAGES);
1607
1642
  let query = `
@@ -1627,6 +1662,11 @@ var MemoryStorageD1 = class extends storage.MemoryStorage {
1627
1662
  query += ` AND createdAt ${endOp} ?`;
1628
1663
  queryParams.push(endDate);
1629
1664
  }
1665
+ const metadataConditions = [];
1666
+ addSqliteMetadataFilter(metadataConditions, queryParams, metadataFilter);
1667
+ if (metadataConditions.length > 0) {
1668
+ query += ` AND ${metadataConditions.join(" AND ")}`;
1669
+ }
1630
1670
  const { field, direction } = this.parseOrderBy(orderBy, "ASC");
1631
1671
  if (perPage === 0 && (!include || include.length === 0)) {
1632
1672
  return { messages: [], total: 0, page, perPage: perPageForResponse, hasMore: false };
@@ -1678,6 +1718,11 @@ var MemoryStorageD1 = class extends storage.MemoryStorage {
1678
1718
  countQuery += ` AND createdAt ${endOp} ?`;
1679
1719
  countParams.push(endDate);
1680
1720
  }
1721
+ const countMetadataConditions = [];
1722
+ addSqliteMetadataFilter(countMetadataConditions, countParams, metadataFilter);
1723
+ if (countMetadataConditions.length > 0) {
1724
+ countQuery += ` AND ${countMetadataConditions.join(" AND ")}`;
1725
+ }
1681
1726
  const countResult = await this.#db.executeQuery({ sql: countQuery, params: countParams });
1682
1727
  const total = Number(countResult[0]?.count ?? 0);
1683
1728
  if (total === 0 && paginatedCount === 0 && (!include || include.length === 0)) {
@@ -1706,8 +1751,7 @@ var MemoryStorageD1 = class extends storage.MemoryStorage {
1706
1751
  const list = new agent.MessageList().add(paginatedMessages, "memory");
1707
1752
  const finalMessages = this._sortMessages(list.get.all.db(), field, direction);
1708
1753
  const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
1709
- const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
1710
- const hasMore = perPageInput === false ? false : allThreadMessagesReturned ? false : offset + paginatedCount < total;
1754
+ const hasMore = perPageInput !== false && (metadataFilter || returnedThreadMessageIds.size < total) && offset + paginatedCount < total;
1711
1755
  return {
1712
1756
  messages: finalMessages,
1713
1757
  total,