@mastra/cloudflare 1.0.0-beta.2 → 1.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @mastra/cloudflare
2
2
 
3
+ ## 1.0.0-beta.3
4
+
5
+ ### Patch Changes
6
+
7
+ - feat(storage): support querying messages from multiple threads ([#10663](https://github.com/mastra-ai/mastra/pull/10663))
8
+ - Fixed TypeScript errors where `threadId: string | string[]` was being passed to places expecting `Scalar` type
9
+ - Added proper multi-thread support for `listMessages` across all adapters when `threadId` is an array
10
+ - Updated `_getIncludedMessages` to look up message threadId by ID (since message IDs are globally unique)
11
+ - **upstash**: Added `msg-idx:{messageId}` index for O(1) message lookups (backwards compatible with fallback to scan for old messages, with automatic backfill)
12
+
13
+ - fix: ensure score responses match saved payloads for Mastra Stores. ([#10557](https://github.com/mastra-ai/mastra/pull/10557))
14
+
15
+ - Unify transformScoreRow functions across storage adapters ([#10648](https://github.com/mastra-ai/mastra/pull/10648))
16
+
17
+ Added a unified `transformScoreRow` function in `@mastra/core/storage` that provides schema-driven row transformation for score data. This eliminates code duplication across 10 storage adapters while maintaining store-specific behavior through configurable options:
18
+ - `preferredTimestampFields`: Preferred source fields for timestamps (PostgreSQL, Cloudflare D1)
19
+ - `convertTimestamps`: Convert timestamp strings to Date objects (MSSQL, MongoDB, ClickHouse)
20
+ - `nullValuePattern`: Skip values matching pattern (ClickHouse's `'_null_'`)
21
+ - `fieldMappings`: Map source column names to schema fields (LibSQL's `additionalLLMContext`)
22
+
23
+ Each store adapter now uses the unified function with appropriate options, reducing ~200 lines of duplicate transformation logic while ensuring consistent behavior across all storage backends.
24
+
25
+ - Updated dependencies [[`ac0d2f4`](https://github.com/mastra-ai/mastra/commit/ac0d2f4ff8831f72c1c66c2be809706d17f65789), [`1a0d3fc`](https://github.com/mastra-ai/mastra/commit/1a0d3fc811482c9c376cdf79ee615c23bae9b2d6), [`85a628b`](https://github.com/mastra-ai/mastra/commit/85a628b1224a8f64cd82ea7f033774bf22df7a7e), [`c237233`](https://github.com/mastra-ai/mastra/commit/c23723399ccedf7f5744b3f40997b79246bfbe64), [`15f9e21`](https://github.com/mastra-ai/mastra/commit/15f9e216177201ea6e3f6d0bfb063fcc0953444f), [`ff94dea`](https://github.com/mastra-ai/mastra/commit/ff94dea935f4e34545c63bcb6c29804732698809), [`5b2ff46`](https://github.com/mastra-ai/mastra/commit/5b2ff4651df70c146523a7fca773f8eb0a2272f8), [`db41688`](https://github.com/mastra-ai/mastra/commit/db4168806d007417e2e60b4f68656dca4e5f40c9), [`5ca599d`](https://github.com/mastra-ai/mastra/commit/5ca599d0bb59a1595f19f58473fcd67cc71cef58), [`bff1145`](https://github.com/mastra-ai/mastra/commit/bff114556b3cbadad9b2768488708f8ad0e91475), [`5c8ca24`](https://github.com/mastra-ai/mastra/commit/5c8ca247094e0cc2cdbd7137822fb47241f86e77), [`e191844`](https://github.com/mastra-ai/mastra/commit/e1918444ca3f80e82feef1dad506cd4ec6e2875f), [`22553f1`](https://github.com/mastra-ai/mastra/commit/22553f11c63ee5e966a9c034a349822249584691), [`7237163`](https://github.com/mastra-ai/mastra/commit/72371635dbf96a87df4b073cc48fc655afbdce3d), [`2500740`](https://github.com/mastra-ai/mastra/commit/2500740ea23da067d6e50ec71c625ab3ce275e64), [`873ecbb`](https://github.com/mastra-ai/mastra/commit/873ecbb517586aa17d2f1e99283755b3ebb2863f), [`4f9bbe5`](https://github.com/mastra-ai/mastra/commit/4f9bbe5968f42c86f4930b8193de3c3c17e5bd36), [`02e51fe`](https://github.com/mastra-ai/mastra/commit/02e51feddb3d4155cfbcc42624fd0d0970d032c0), [`8f3fa3a`](https://github.com/mastra-ai/mastra/commit/8f3fa3a652bb77da092f913ec51ae46e3a7e27dc), [`cd29ad2`](https://github.com/mastra-ai/mastra/commit/cd29ad23a255534e8191f249593849ed29160886), [`bdf4d8c`](https://github.com/mastra-ai/mastra/commit/bdf4d8cdc656d8a2c21d81834bfa3bfa70f56c16), [`854e3da`](https://github.com/mastra-ai/mastra/commit/854e3dad5daac17a91a20986399d3a51f54bf68b), [`ce18d38`](https://github.com/mastra-ai/mastra/commit/ce18d38678c65870350d123955014a8432075fd9), [`cccf9c8`](https://github.com/mastra-ai/mastra/commit/cccf9c8b2d2dfc1a5e63919395b83d78c89682a0), [`61a5705`](https://github.com/mastra-ai/mastra/commit/61a570551278b6743e64243b3ce7d73de915ca8a), [`db70a48`](https://github.com/mastra-ai/mastra/commit/db70a48aeeeeb8e5f92007e8ede52c364ce15287), [`f0fdc14`](https://github.com/mastra-ai/mastra/commit/f0fdc14ee233d619266b3d2bbdeea7d25cfc6d13), [`db18bc9`](https://github.com/mastra-ai/mastra/commit/db18bc9c3825e2c1a0ad9a183cc9935f6691bfa1), [`9b37b56`](https://github.com/mastra-ai/mastra/commit/9b37b565e1f2a76c24f728945cc740c2b09be9da), [`41a23c3`](https://github.com/mastra-ai/mastra/commit/41a23c32f9877d71810f37e24930515df2ff7a0f), [`5d171ad`](https://github.com/mastra-ai/mastra/commit/5d171ad9ef340387276b77c2bb3e83e83332d729), [`f03ae60`](https://github.com/mastra-ai/mastra/commit/f03ae60500fe350c9d828621006cdafe1975fdd8), [`d1e74a0`](https://github.com/mastra-ai/mastra/commit/d1e74a0a293866dece31022047f5dbab65a304d0), [`39e7869`](https://github.com/mastra-ai/mastra/commit/39e7869bc7d0ee391077ce291474d8a84eedccff), [`5761926`](https://github.com/mastra-ai/mastra/commit/57619260c4a2cdd598763abbacd90de594c6bc76), [`c900fdd`](https://github.com/mastra-ai/mastra/commit/c900fdd504c41348efdffb205cfe80d48c38fa33), [`604a79f`](https://github.com/mastra-ai/mastra/commit/604a79fecf276e26a54a3fe01bb94e65315d2e0e), [`887f0b4`](https://github.com/mastra-ai/mastra/commit/887f0b4746cdbd7cb7d6b17ac9f82aeb58037ea5), [`2562143`](https://github.com/mastra-ai/mastra/commit/256214336b4faa78646c9c1776612393790d8784), [`ef11a61`](https://github.com/mastra-ai/mastra/commit/ef11a61920fa0ed08a5b7ceedd192875af119749)]:
26
+ - @mastra/core@1.0.0-beta.6
27
+
3
28
  ## 1.0.0-beta.2
4
29
 
5
30
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -213,6 +213,17 @@ var MemoryStorageCloudflare = class extends storage.MemoryStorage {
213
213
  );
214
214
  }
215
215
  }
216
+ /**
217
+ * Searches all threads in the KV store to find a message by its ID.
218
+ *
219
+ * **Performance Warning**: This method sequentially scans all threads to locate
220
+ * the message. For stores with many threads, this can result in significant
221
+ * latency and API calls. When possible, callers should provide the `threadId`
222
+ * directly to avoid this full scan.
223
+ *
224
+ * @param messageId - The globally unique message ID to search for
225
+ * @returns The message with its threadId if found, null otherwise
226
+ */
216
227
  async findMessageInAnyThread(messageId) {
217
228
  try {
218
229
  const prefix = this.operations.namespacePrefix ? `${this.operations.namespacePrefix}:` : "";
@@ -442,10 +453,25 @@ var MemoryStorageCloudflare = class extends storage.MemoryStorage {
442
453
  async getFullOrder(orderKey) {
443
454
  return this.getRange(orderKey, 0, -1);
444
455
  }
445
- async getIncludedMessagesWithContext(threadId, include, messageIds) {
456
+ /**
457
+ * Retrieves messages specified in the include array along with their surrounding context.
458
+ *
459
+ * **Performance Note**: When `threadId` is not provided in an include entry, this method
460
+ * must call `findMessageInAnyThread` which sequentially scans all threads in the KV store.
461
+ * For optimal performance, callers should provide `threadId` in include entries when known.
462
+ *
463
+ * @param include - Array of message IDs to include, optionally with context windows
464
+ * @param messageIds - Set to accumulate the message IDs that should be fetched
465
+ */
466
+ async getIncludedMessagesWithContext(include, messageIds) {
446
467
  await Promise.all(
447
468
  include.map(async (item) => {
448
- const targetThreadId = item.threadId || threadId;
469
+ let targetThreadId = item.threadId;
470
+ if (!targetThreadId) {
471
+ const foundMessage = await this.findMessageInAnyThread(item.id);
472
+ if (!foundMessage) return;
473
+ targetThreadId = foundMessage.threadId;
474
+ }
449
475
  if (!targetThreadId) return;
450
476
  const threadMessagesKey = this.getThreadMessagesKey(targetThreadId);
451
477
  messageIds.add(item.id);
@@ -478,6 +504,13 @@ var MemoryStorageCloudflare = class extends storage.MemoryStorage {
478
504
  this.logger?.debug(`No message order found for thread ${threadId}, skipping latest messages`);
479
505
  }
480
506
  }
507
+ /**
508
+ * Fetches and parses messages from one or more threads.
509
+ *
510
+ * **Performance Note**: When neither `include` entries with `threadId` nor `targetThreadId`
511
+ * are provided, this method falls back to `findMessageInAnyThread` which scans all threads.
512
+ * For optimal performance, provide `threadId` in include entries or specify `targetThreadId`.
513
+ */
481
514
  async fetchAndParseMessagesFromMultipleThreads(messageIds, include, targetThreadId) {
482
515
  const messageIdToThreadId = /* @__PURE__ */ new Map();
483
516
  if (include) {
@@ -519,6 +552,14 @@ var MemoryStorageCloudflare = class extends storage.MemoryStorage {
519
552
  );
520
553
  return messages.filter((msg) => msg !== null);
521
554
  }
555
+ /**
556
+ * Retrieves messages by their IDs.
557
+ *
558
+ * **Performance Warning**: This method calls `findMessageInAnyThread` for each message ID,
559
+ * which scans all threads in the KV store. For large numbers of messages or threads,
560
+ * this can result in significant latency. Consider using `listMessages` with specific
561
+ * thread IDs when the thread context is known.
562
+ */
522
563
  async listMessagesById({ messageIds }) {
523
564
  if (messageIds.length === 0) return { messages: [] };
524
565
  try {
@@ -552,15 +593,17 @@ var MemoryStorageCloudflare = class extends storage.MemoryStorage {
552
593
  }
553
594
  async listMessages(args) {
554
595
  const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
555
- if (!threadId.trim()) {
596
+ const threadIds = Array.isArray(threadId) ? threadId : [threadId];
597
+ const isValidThreadId = (id) => typeof id === "string" && id.trim().length > 0;
598
+ if (threadIds.length === 0 || threadIds.some((id) => !isValidThreadId(id))) {
556
599
  throw new error.MastraError(
557
600
  {
558
601
  id: "STORAGE_CLOUDFLARE_LIST_MESSAGES_INVALID_THREAD_ID",
559
602
  domain: error.ErrorDomain.STORAGE,
560
603
  category: error.ErrorCategory.THIRD_PARTY,
561
- details: { threadId }
604
+ details: { threadId: Array.isArray(threadId) ? JSON.stringify(threadId) : String(threadId) }
562
605
  },
563
- new Error("threadId must be a non-empty string")
606
+ new Error("threadId must be a non-empty string or array of non-empty strings")
564
607
  );
565
608
  }
566
609
  const perPage = storage.normalizePerPage(perPageInput, 40);
@@ -579,16 +622,18 @@ var MemoryStorageCloudflare = class extends storage.MemoryStorage {
579
622
  }
580
623
  const { field, direction } = this.parseOrderBy(orderBy, "ASC");
581
624
  const threadMessageIds = /* @__PURE__ */ new Set();
582
- try {
583
- const threadMessagesKey = this.getThreadMessagesKey(threadId);
584
- const allIds = await this.getFullOrder(threadMessagesKey);
585
- allIds.forEach((id) => threadMessageIds.add(id));
586
- } catch {
625
+ for (const tid of threadIds) {
626
+ try {
627
+ const threadMessagesKey = this.getThreadMessagesKey(tid);
628
+ const allIds = await this.getFullOrder(threadMessagesKey);
629
+ allIds.forEach((id) => threadMessageIds.add(id));
630
+ } catch {
631
+ }
587
632
  }
588
633
  const threadMessages = await this.fetchAndParseMessagesFromMultipleThreads(
589
634
  Array.from(threadMessageIds),
590
635
  void 0,
591
- threadId
636
+ threadIds.length === 1 ? threadIds[0] : void 0
592
637
  );
593
638
  let filteredThreadMessages = threadMessages;
594
639
  if (resourceId) {
@@ -633,7 +678,7 @@ var MemoryStorageCloudflare = class extends storage.MemoryStorage {
633
678
  let includedMessages = [];
634
679
  if (include && include.length > 0) {
635
680
  const includedMessageIds = /* @__PURE__ */ new Set();
636
- await this.getIncludedMessagesWithContext(threadId, include, includedMessageIds);
681
+ await this.getIncludedMessagesWithContext(include, includedMessageIds);
637
682
  const paginatedIds = new Set(paginatedMessages.map((m) => m.id));
638
683
  const idsToFetch = Array.from(includedMessageIds).filter((id) => !paginatedIds.has(id));
639
684
  if (idsToFetch.length > 0) {
@@ -679,7 +724,11 @@ var MemoryStorageCloudflare = class extends storage.MemoryStorage {
679
724
  type: message.type !== "v2" ? message.type : void 0,
680
725
  createdAt: storage.ensureDate(message.createdAt)
681
726
  }));
682
- const list = new agent.MessageList({ threadId, resourceId }).add(prepared, "memory");
727
+ const primaryThreadId = Array.isArray(threadId) ? threadId[0] : threadId;
728
+ const list = new agent.MessageList({ threadId: primaryThreadId, resourceId }).add(
729
+ prepared,
730
+ "memory"
731
+ );
683
732
  let finalMessages = list.get.all.db();
684
733
  finalMessages = finalMessages.sort((a, b) => {
685
734
  const isDateField = field === "createdAt" || field === "updatedAt";
@@ -695,7 +744,10 @@ var MemoryStorageCloudflare = class extends storage.MemoryStorage {
695
744
  const cmp = direction === "ASC" ? String(aVal).localeCompare(String(bVal)) : String(bVal).localeCompare(String(aVal));
696
745
  return cmp !== 0 ? cmp : a.id.localeCompare(b.id);
697
746
  });
698
- const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
747
+ const threadIdSet = new Set(threadIds);
748
+ const returnedThreadMessageIds = new Set(
749
+ finalMessages.filter((m) => m.threadId && threadIdSet.has(m.threadId)).map((m) => m.id)
750
+ );
699
751
  const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
700
752
  const hasMore = perPageInput !== false && !allThreadMessagesReturned && offset + paginatedCount < total;
701
753
  return {
@@ -711,9 +763,9 @@ var MemoryStorageCloudflare = class extends storage.MemoryStorage {
711
763
  id: "CLOUDFLARE_STORAGE_LIST_MESSAGES_FAILED",
712
764
  domain: error.ErrorDomain.STORAGE,
713
765
  category: error.ErrorCategory.THIRD_PARTY,
714
- text: `Failed to list messages for thread ${threadId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
766
+ text: `Failed to list messages for thread ${Array.isArray(threadId) ? threadId.join(",") : threadId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
715
767
  details: {
716
- threadId,
768
+ threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
717
769
  resourceId: resourceId ?? ""
718
770
  }
719
771
  },
@@ -1465,17 +1517,7 @@ var StoreOperationsCloudflare = class extends storage.StoreOperations {
1465
1517
  }
1466
1518
  };
1467
1519
  function transformScoreRow(row) {
1468
- const deserialized = { ...row };
1469
- deserialized.input = storage.safelyParseJSON(row.input);
1470
- deserialized.output = storage.safelyParseJSON(row.output);
1471
- deserialized.scorer = storage.safelyParseJSON(row.scorer);
1472
- deserialized.preprocessStepResult = storage.safelyParseJSON(row.preprocessStepResult);
1473
- deserialized.analyzeStepResult = storage.safelyParseJSON(row.analyzeStepResult);
1474
- deserialized.metadata = storage.safelyParseJSON(row.metadata);
1475
- deserialized.additionalContext = storage.safelyParseJSON(row.additionalContext);
1476
- deserialized.requestContext = storage.safelyParseJSON(row.requestContext);
1477
- deserialized.entity = storage.safelyParseJSON(row.entity);
1478
- return deserialized;
1520
+ return storage.transformScoreRow(row);
1479
1521
  }
1480
1522
  var ScoresStorageCloudflare = class extends storage.ScoresStorage {
1481
1523
  operations;