@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/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
2
- import { MastraStorage, TABLE_THREADS, TABLE_MESSAGES, TABLE_WORKFLOW_SNAPSHOT, TABLE_SCORERS, StoreOperations, TABLE_TRACES, WorkflowsStorage, ensureDate, normalizePerPage, MemoryStorage, calculatePagination, serializeDate, TABLE_RESOURCES, ScoresStorage, safelyParseJSON } from '@mastra/core/storage';
2
+ import { MastraStorage, TABLE_THREADS, TABLE_MESSAGES, TABLE_WORKFLOW_SNAPSHOT, TABLE_SCORERS, StoreOperations, TABLE_TRACES, WorkflowsStorage, ensureDate, normalizePerPage, MemoryStorage, calculatePagination, serializeDate, TABLE_RESOURCES, ScoresStorage, transformScoreRow as transformScoreRow$1 } from '@mastra/core/storage';
3
3
  import Cloudflare from 'cloudflare';
4
4
  import { MessageList } from '@mastra/core/agent';
5
5
  import { saveScorePayloadSchema } from '@mastra/core/evals';
@@ -207,6 +207,17 @@ var MemoryStorageCloudflare = class extends MemoryStorage {
207
207
  );
208
208
  }
209
209
  }
210
+ /**
211
+ * Searches all threads in the KV store to find a message by its ID.
212
+ *
213
+ * **Performance Warning**: This method sequentially scans all threads to locate
214
+ * the message. For stores with many threads, this can result in significant
215
+ * latency and API calls. When possible, callers should provide the `threadId`
216
+ * directly to avoid this full scan.
217
+ *
218
+ * @param messageId - The globally unique message ID to search for
219
+ * @returns The message with its threadId if found, null otherwise
220
+ */
210
221
  async findMessageInAnyThread(messageId) {
211
222
  try {
212
223
  const prefix = this.operations.namespacePrefix ? `${this.operations.namespacePrefix}:` : "";
@@ -436,10 +447,25 @@ var MemoryStorageCloudflare = class extends MemoryStorage {
436
447
  async getFullOrder(orderKey) {
437
448
  return this.getRange(orderKey, 0, -1);
438
449
  }
439
- async getIncludedMessagesWithContext(threadId, include, messageIds) {
450
+ /**
451
+ * Retrieves messages specified in the include array along with their surrounding context.
452
+ *
453
+ * **Performance Note**: When `threadId` is not provided in an include entry, this method
454
+ * must call `findMessageInAnyThread` which sequentially scans all threads in the KV store.
455
+ * For optimal performance, callers should provide `threadId` in include entries when known.
456
+ *
457
+ * @param include - Array of message IDs to include, optionally with context windows
458
+ * @param messageIds - Set to accumulate the message IDs that should be fetched
459
+ */
460
+ async getIncludedMessagesWithContext(include, messageIds) {
440
461
  await Promise.all(
441
462
  include.map(async (item) => {
442
- const targetThreadId = item.threadId || threadId;
463
+ let targetThreadId = item.threadId;
464
+ if (!targetThreadId) {
465
+ const foundMessage = await this.findMessageInAnyThread(item.id);
466
+ if (!foundMessage) return;
467
+ targetThreadId = foundMessage.threadId;
468
+ }
443
469
  if (!targetThreadId) return;
444
470
  const threadMessagesKey = this.getThreadMessagesKey(targetThreadId);
445
471
  messageIds.add(item.id);
@@ -472,6 +498,13 @@ var MemoryStorageCloudflare = class extends MemoryStorage {
472
498
  this.logger?.debug(`No message order found for thread ${threadId}, skipping latest messages`);
473
499
  }
474
500
  }
501
+ /**
502
+ * Fetches and parses messages from one or more threads.
503
+ *
504
+ * **Performance Note**: When neither `include` entries with `threadId` nor `targetThreadId`
505
+ * are provided, this method falls back to `findMessageInAnyThread` which scans all threads.
506
+ * For optimal performance, provide `threadId` in include entries or specify `targetThreadId`.
507
+ */
475
508
  async fetchAndParseMessagesFromMultipleThreads(messageIds, include, targetThreadId) {
476
509
  const messageIdToThreadId = /* @__PURE__ */ new Map();
477
510
  if (include) {
@@ -513,6 +546,14 @@ var MemoryStorageCloudflare = class extends MemoryStorage {
513
546
  );
514
547
  return messages.filter((msg) => msg !== null);
515
548
  }
549
+ /**
550
+ * Retrieves messages by their IDs.
551
+ *
552
+ * **Performance Warning**: This method calls `findMessageInAnyThread` for each message ID,
553
+ * which scans all threads in the KV store. For large numbers of messages or threads,
554
+ * this can result in significant latency. Consider using `listMessages` with specific
555
+ * thread IDs when the thread context is known.
556
+ */
516
557
  async listMessagesById({ messageIds }) {
517
558
  if (messageIds.length === 0) return { messages: [] };
518
559
  try {
@@ -546,15 +587,17 @@ var MemoryStorageCloudflare = class extends MemoryStorage {
546
587
  }
547
588
  async listMessages(args) {
548
589
  const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
549
- if (!threadId.trim()) {
590
+ const threadIds = Array.isArray(threadId) ? threadId : [threadId];
591
+ const isValidThreadId = (id) => typeof id === "string" && id.trim().length > 0;
592
+ if (threadIds.length === 0 || threadIds.some((id) => !isValidThreadId(id))) {
550
593
  throw new MastraError(
551
594
  {
552
595
  id: "STORAGE_CLOUDFLARE_LIST_MESSAGES_INVALID_THREAD_ID",
553
596
  domain: ErrorDomain.STORAGE,
554
597
  category: ErrorCategory.THIRD_PARTY,
555
- details: { threadId }
598
+ details: { threadId: Array.isArray(threadId) ? JSON.stringify(threadId) : String(threadId) }
556
599
  },
557
- new Error("threadId must be a non-empty string")
600
+ new Error("threadId must be a non-empty string or array of non-empty strings")
558
601
  );
559
602
  }
560
603
  const perPage = normalizePerPage(perPageInput, 40);
@@ -573,16 +616,18 @@ var MemoryStorageCloudflare = class extends MemoryStorage {
573
616
  }
574
617
  const { field, direction } = this.parseOrderBy(orderBy, "ASC");
575
618
  const threadMessageIds = /* @__PURE__ */ new Set();
576
- try {
577
- const threadMessagesKey = this.getThreadMessagesKey(threadId);
578
- const allIds = await this.getFullOrder(threadMessagesKey);
579
- allIds.forEach((id) => threadMessageIds.add(id));
580
- } catch {
619
+ for (const tid of threadIds) {
620
+ try {
621
+ const threadMessagesKey = this.getThreadMessagesKey(tid);
622
+ const allIds = await this.getFullOrder(threadMessagesKey);
623
+ allIds.forEach((id) => threadMessageIds.add(id));
624
+ } catch {
625
+ }
581
626
  }
582
627
  const threadMessages = await this.fetchAndParseMessagesFromMultipleThreads(
583
628
  Array.from(threadMessageIds),
584
629
  void 0,
585
- threadId
630
+ threadIds.length === 1 ? threadIds[0] : void 0
586
631
  );
587
632
  let filteredThreadMessages = threadMessages;
588
633
  if (resourceId) {
@@ -627,7 +672,7 @@ var MemoryStorageCloudflare = class extends MemoryStorage {
627
672
  let includedMessages = [];
628
673
  if (include && include.length > 0) {
629
674
  const includedMessageIds = /* @__PURE__ */ new Set();
630
- await this.getIncludedMessagesWithContext(threadId, include, includedMessageIds);
675
+ await this.getIncludedMessagesWithContext(include, includedMessageIds);
631
676
  const paginatedIds = new Set(paginatedMessages.map((m) => m.id));
632
677
  const idsToFetch = Array.from(includedMessageIds).filter((id) => !paginatedIds.has(id));
633
678
  if (idsToFetch.length > 0) {
@@ -673,7 +718,11 @@ var MemoryStorageCloudflare = class extends MemoryStorage {
673
718
  type: message.type !== "v2" ? message.type : void 0,
674
719
  createdAt: ensureDate(message.createdAt)
675
720
  }));
676
- const list = new MessageList({ threadId, resourceId }).add(prepared, "memory");
721
+ const primaryThreadId = Array.isArray(threadId) ? threadId[0] : threadId;
722
+ const list = new MessageList({ threadId: primaryThreadId, resourceId }).add(
723
+ prepared,
724
+ "memory"
725
+ );
677
726
  let finalMessages = list.get.all.db();
678
727
  finalMessages = finalMessages.sort((a, b) => {
679
728
  const isDateField = field === "createdAt" || field === "updatedAt";
@@ -689,7 +738,10 @@ var MemoryStorageCloudflare = class extends MemoryStorage {
689
738
  const cmp = direction === "ASC" ? String(aVal).localeCompare(String(bVal)) : String(bVal).localeCompare(String(aVal));
690
739
  return cmp !== 0 ? cmp : a.id.localeCompare(b.id);
691
740
  });
692
- const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
741
+ const threadIdSet = new Set(threadIds);
742
+ const returnedThreadMessageIds = new Set(
743
+ finalMessages.filter((m) => m.threadId && threadIdSet.has(m.threadId)).map((m) => m.id)
744
+ );
693
745
  const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
694
746
  const hasMore = perPageInput !== false && !allThreadMessagesReturned && offset + paginatedCount < total;
695
747
  return {
@@ -705,9 +757,9 @@ var MemoryStorageCloudflare = class extends MemoryStorage {
705
757
  id: "CLOUDFLARE_STORAGE_LIST_MESSAGES_FAILED",
706
758
  domain: ErrorDomain.STORAGE,
707
759
  category: ErrorCategory.THIRD_PARTY,
708
- text: `Failed to list messages for thread ${threadId}: ${error instanceof Error ? error.message : String(error)}`,
760
+ text: `Failed to list messages for thread ${Array.isArray(threadId) ? threadId.join(",") : threadId}: ${error instanceof Error ? error.message : String(error)}`,
709
761
  details: {
710
- threadId,
762
+ threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
711
763
  resourceId: resourceId ?? ""
712
764
  }
713
765
  },
@@ -1459,17 +1511,7 @@ var StoreOperationsCloudflare = class extends StoreOperations {
1459
1511
  }
1460
1512
  };
1461
1513
  function transformScoreRow(row) {
1462
- const deserialized = { ...row };
1463
- deserialized.input = safelyParseJSON(row.input);
1464
- deserialized.output = safelyParseJSON(row.output);
1465
- deserialized.scorer = safelyParseJSON(row.scorer);
1466
- deserialized.preprocessStepResult = safelyParseJSON(row.preprocessStepResult);
1467
- deserialized.analyzeStepResult = safelyParseJSON(row.analyzeStepResult);
1468
- deserialized.metadata = safelyParseJSON(row.metadata);
1469
- deserialized.additionalContext = safelyParseJSON(row.additionalContext);
1470
- deserialized.requestContext = safelyParseJSON(row.requestContext);
1471
- deserialized.entity = safelyParseJSON(row.entity);
1472
- return deserialized;
1514
+ return transformScoreRow$1(row);
1473
1515
  }
1474
1516
  var ScoresStorageCloudflare = class extends ScoresStorage {
1475
1517
  operations;