@mastra/convex 1.1.0-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.
Files changed (42) hide show
  1. package/CHANGELOG.md +129 -0
  2. package/README.md +31 -13
  3. package/dist/{chunk-FZDLZ4S3.js → chunk-AJFME2ZF.js} +323 -16
  4. package/dist/chunk-AJFME2ZF.js.map +1 -0
  5. package/dist/{chunk-JPWDG4L3.js → chunk-MC75WADX.js} +79 -4
  6. package/dist/chunk-MC75WADX.js.map +1 -0
  7. package/dist/{chunk-EEELVBWO.cjs → chunk-ORSDZTO4.cjs} +322 -15
  8. package/dist/chunk-ORSDZTO4.cjs.map +1 -0
  9. package/dist/{chunk-CV23JOCS.cjs → chunk-SFRHJGSM.cjs} +102 -2
  10. package/dist/chunk-SFRHJGSM.cjs.map +1 -0
  11. package/dist/docs/SKILL.md +1 -1
  12. package/dist/docs/assets/SOURCE_MAP.json +63 -23
  13. package/dist/index.cjs +634 -69
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.js +574 -49
  16. package/dist/index.js.map +1 -1
  17. package/dist/schema.cjs +60 -20
  18. package/dist/schema.d.ts +192 -2
  19. package/dist/schema.d.ts.map +1 -1
  20. package/dist/schema.js +1 -1
  21. package/dist/server/index-map.d.ts.map +1 -1
  22. package/dist/server/index.cjs +63 -23
  23. package/dist/server/index.d.ts +1 -1
  24. package/dist/server/index.d.ts.map +1 -1
  25. package/dist/server/index.js +2 -2
  26. package/dist/server/storage.d.ts.map +1 -1
  27. package/dist/storage/db/index.d.ts +28 -1
  28. package/dist/storage/db/index.d.ts.map +1 -1
  29. package/dist/storage/domains/background-tasks/index.d.ts.map +1 -1
  30. package/dist/storage/domains/channels/index.d.ts +19 -0
  31. package/dist/storage/domains/channels/index.d.ts.map +1 -0
  32. package/dist/storage/domains/schedules/index.d.ts +19 -0
  33. package/dist/storage/domains/schedules/index.d.ts.map +1 -0
  34. package/dist/storage/index.d.ts +3 -1
  35. package/dist/storage/index.d.ts.map +1 -1
  36. package/dist/storage/types.d.ts +42 -0
  37. package/dist/storage/types.d.ts.map +1 -1
  38. package/package.json +5 -5
  39. package/dist/chunk-CV23JOCS.cjs.map +0 -1
  40. package/dist/chunk-EEELVBWO.cjs.map +0 -1
  41. package/dist/chunk-FZDLZ4S3.js.map +0 -1
  42. package/dist/chunk-JPWDG4L3.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- export { mastraCache, mastraNativeVectorAction, mastraNativeVectorMutation, mastraNativeVectorQuery, mastraStorage } from './chunk-FZDLZ4S3.js';
2
- export { TABLE_MESSAGES, TABLE_RESOURCES, TABLE_SCORERS, TABLE_THREADS, TABLE_WORKFLOW_SNAPSHOT, defineMastraNativeVectorTable, mastraCacheListItemsTable, mastraCacheTable, mastraDocumentsTable, mastraMessagesTable, mastraResourcesTable, mastraScoresTable, mastraThreadsTable, mastraVectorIndexesTable, mastraVectorsTable, mastraWorkflowSnapshotsTable } from './chunk-JPWDG4L3.js';
1
+ export { mastraCache, mastraNativeVectorAction, mastraNativeVectorMutation, mastraNativeVectorQuery, mastraStorage } from './chunk-AJFME2ZF.js';
2
+ export { TABLE_BACKGROUND_TASKS, TABLE_CHANNEL_CONFIG, TABLE_CHANNEL_INSTALLATIONS, TABLE_MESSAGES, TABLE_RESOURCES, TABLE_SCHEDULES, TABLE_SCHEDULE_TRIGGERS, TABLE_SCORERS, TABLE_THREADS, TABLE_WORKFLOW_SNAPSHOT, defineMastraNativeVectorTable, mastraBackgroundTasksTable, mastraCacheListItemsTable, mastraCacheTable, mastraChannelConfigTable, mastraChannelInstallationsTable, mastraDocumentsTable, mastraMessagesTable, mastraResourcesTable, mastraScheduleTriggersTable, mastraSchedulesTable, mastraScoresTable, mastraThreadsTable, mastraVectorIndexesTable, mastraVectorsTable, mastraWorkflowSnapshotsTable } from './chunk-MC75WADX.js';
3
3
  import { MastraServerCache } from '@mastra/core/cache';
4
- import { MastraCompositeStore, createVectorErrorId, MemoryStorage, TABLE_THREADS, TABLE_MESSAGES, TABLE_RESOURCES, createStorageErrorId, normalizePerPage, calculatePagination, filterByDateRange, safelyParseJSON, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, ScoresStorage, TABLE_SCORERS, BackgroundTasksStorage, TABLE_BACKGROUND_TASKS } from '@mastra/core/storage';
4
+ import { MastraCompositeStore, createVectorErrorId, MemoryStorage, TABLE_THREADS, TABLE_MESSAGES, TABLE_RESOURCES, createStorageErrorId, normalizePerPage, calculatePagination, filterByDateRange, safelyParseJSON, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, ScoresStorage, TABLE_SCORERS, ChannelsStorage, TABLE_CHANNEL_INSTALLATIONS, TABLE_CHANNEL_CONFIG, SchedulesStorage, TABLE_SCHEDULE_TRIGGERS, TABLE_SCHEDULES, BackgroundTasksStorage, TABLE_BACKGROUND_TASKS } from '@mastra/core/storage';
5
5
  import crypto from 'crypto';
6
6
  import { MastraBase } from '@mastra/core/base';
7
7
  import { MessageList } from '@mastra/core/agent';
@@ -337,6 +337,18 @@ var ConvexDB = class extends MastraBase {
337
337
  records: records.map((record) => this.normalizeRecord(tableName, record))
338
338
  });
339
339
  }
340
+ async patch({
341
+ tableName,
342
+ id,
343
+ record
344
+ }) {
345
+ return this.client.callStorage({
346
+ op: "patch",
347
+ tableName,
348
+ id,
349
+ record: this.normalizePatch(record)
350
+ });
351
+ }
340
352
  async load({ tableName, keys }) {
341
353
  const result = await this.client.callStorage({
342
354
  op: "load",
@@ -345,12 +357,13 @@ var ConvexDB = class extends MastraBase {
345
357
  });
346
358
  return result;
347
359
  }
348
- async queryTable(tableName, filters, indexHint) {
360
+ async queryTable(tableName, filters, indexHint, limit) {
349
361
  return this.client.callStorage({
350
362
  op: "queryTable",
351
363
  tableName,
352
364
  filters,
353
- indexHint
365
+ indexHint,
366
+ limit
354
367
  });
355
368
  }
356
369
  async deleteMany(tableName, ids) {
@@ -361,6 +374,85 @@ var ConvexDB = class extends MastraBase {
361
374
  ids
362
375
  });
363
376
  }
377
+ async createSchedule(record) {
378
+ if (!record.id) {
379
+ throw new Error(`Schedule is missing an id`);
380
+ }
381
+ await this.client.callStorage({
382
+ op: "createSchedule",
383
+ tableName: TABLE_SCHEDULES,
384
+ record: this.normalizeRecord(TABLE_SCHEDULES, record)
385
+ });
386
+ }
387
+ async recordScheduleTrigger(record) {
388
+ if (!record.id) {
389
+ throw new Error(`Schedule trigger is missing an id`);
390
+ }
391
+ await this.client.callStorage({
392
+ op: "recordScheduleTrigger",
393
+ tableName: TABLE_SCHEDULE_TRIGGERS,
394
+ record: this.normalizeRecord(TABLE_SCHEDULE_TRIGGERS, record)
395
+ });
396
+ }
397
+ async listDueSchedules(now, limit) {
398
+ return this.client.callStorage({
399
+ op: "listDueSchedules",
400
+ tableName: TABLE_SCHEDULES,
401
+ now,
402
+ limit
403
+ });
404
+ }
405
+ async updateScheduleNextFire({
406
+ id,
407
+ expectedNextFireAt,
408
+ newNextFireAt,
409
+ lastFireAt,
410
+ lastRunId
411
+ }) {
412
+ return this.client.callStorage({
413
+ op: "updateScheduleNextFire",
414
+ tableName: TABLE_SCHEDULES,
415
+ id,
416
+ expectedNextFireAt,
417
+ newNextFireAt,
418
+ lastFireAt,
419
+ lastRunId
420
+ });
421
+ }
422
+ async updateSchedule({ id, patch }) {
423
+ return this.client.callStorage({
424
+ op: "updateSchedule",
425
+ tableName: TABLE_SCHEDULES,
426
+ id,
427
+ patch
428
+ });
429
+ }
430
+ async listScheduleTriggers({
431
+ scheduleId,
432
+ fromActualFireAt,
433
+ toActualFireAt,
434
+ limit
435
+ }) {
436
+ return this.client.callStorage({
437
+ op: "listScheduleTriggers",
438
+ tableName: TABLE_SCHEDULE_TRIGGERS,
439
+ scheduleId,
440
+ fromActualFireAt,
441
+ toActualFireAt,
442
+ limit
443
+ });
444
+ }
445
+ async deleteScheduleTriggers(scheduleId) {
446
+ let hasMore = true;
447
+ while (hasMore) {
448
+ const response = await this.client.callStorageRaw({
449
+ op: "deleteScheduleTriggers",
450
+ tableName: TABLE_SCHEDULE_TRIGGERS,
451
+ scheduleId
452
+ });
453
+ hasMore = response.hasMore ?? false;
454
+ }
455
+ }
364
456
  normalizeRecord(tableName, record) {
365
457
  const normalized = { ...record };
366
458
  if (tableName === TABLE_WORKFLOW_SNAPSHOT && !normalized.id) {
@@ -378,29 +470,69 @@ var ConvexDB = class extends MastraBase {
378
470
  }
379
471
  return normalized;
380
472
  }
473
+ normalizePatch(record) {
474
+ const normalized = { ...record };
475
+ for (const [key, value] of Object.entries(normalized)) {
476
+ if (value instanceof Date) {
477
+ normalized[key] = value.toISOString();
478
+ }
479
+ }
480
+ return normalized;
481
+ }
381
482
  };
382
483
 
383
484
  // src/storage/domains/background-tasks/index.ts
384
485
  function serializeJson(v) {
385
- if (typeof v === "object" && v != null) return JSON.stringify(v);
386
- return v ?? void 0;
486
+ if (v === void 0 || v === null) return null;
487
+ return JSON.stringify(v);
488
+ }
489
+ function serializeRequiredJson(v) {
490
+ return JSON.stringify(v ?? {});
387
491
  }
388
492
  function toStored(task) {
389
493
  return {
390
- ...task,
391
- args: serializeJson(task.args),
494
+ id: task.id,
495
+ status: task.status,
496
+ tool_call_id: task.toolCallId,
497
+ tool_name: task.toolName,
498
+ agent_id: task.agentId,
499
+ run_id: task.runId,
500
+ thread_id: task.threadId ?? null,
501
+ resource_id: task.resourceId ?? null,
502
+ args: serializeRequiredJson(task.args),
392
503
  result: serializeJson(task.result),
393
504
  error: serializeJson(task.error),
394
- suspendPayload: serializeJson(task.suspendPayload),
505
+ suspend_payload: serializeJson(task.suspendPayload),
506
+ retry_count: task.retryCount,
507
+ max_retries: task.maxRetries,
508
+ timeout_ms: task.timeoutMs,
395
509
  createdAt: task.createdAt.toISOString(),
396
- startedAt: task.startedAt?.toISOString(),
397
- suspendedAt: task.suspendedAt?.toISOString(),
398
- completedAt: task.completedAt?.toISOString()
510
+ startedAt: task.startedAt?.toISOString() ?? null,
511
+ suspendedAt: task.suspendedAt?.toISOString() ?? null,
512
+ completedAt: task.completedAt?.toISOString() ?? null
399
513
  };
400
514
  }
515
+ function toStoredPatch(update) {
516
+ const patch = {};
517
+ if (update.status !== void 0) patch.status = update.status;
518
+ if ("result" in update) patch.result = serializeJson(update.result);
519
+ if ("error" in update) patch.error = serializeJson(update.error);
520
+ if ("suspendPayload" in update) patch.suspend_payload = serializeJson(update.suspendPayload);
521
+ if (update.retryCount !== void 0) patch.retry_count = update.retryCount;
522
+ if (update.maxRetries !== void 0) patch.max_retries = update.maxRetries;
523
+ if (update.timeoutMs !== void 0) patch.timeout_ms = update.timeoutMs;
524
+ if ("startedAt" in update) patch.startedAt = update.startedAt?.toISOString() ?? null;
525
+ if ("suspendedAt" in update) patch.suspendedAt = update.suspendedAt?.toISOString() ?? null;
526
+ if ("completedAt" in update) patch.completedAt = update.completedAt?.toISOString() ?? null;
527
+ return patch;
528
+ }
529
+ function legacyOrCurrent(stored, currentKey, legacyKey) {
530
+ return currentKey in stored ? stored[currentKey] : stored[legacyKey];
531
+ }
401
532
  function fromStored(stored) {
402
- const parseJson = (val) => {
403
- if (!val) return void 0;
533
+ const record = stored;
534
+ const parseJson3 = (val) => {
535
+ if (val == null) return void 0;
404
536
  try {
405
537
  return JSON.parse(val);
406
538
  } catch {
@@ -408,27 +540,32 @@ function fromStored(stored) {
408
540
  }
409
541
  };
410
542
  return {
411
- id: stored.id,
412
- status: stored.status,
413
- toolName: stored.toolName,
414
- toolCallId: stored.toolCallId,
415
- args: parseJson(stored.args) ?? {},
416
- agentId: stored.agentId,
417
- threadId: stored.threadId,
418
- resourceId: stored.resourceId,
419
- runId: stored.runId,
420
- result: parseJson(stored.result),
421
- error: parseJson(stored.error),
422
- suspendPayload: parseJson(stored.suspendPayload),
423
- retryCount: stored.retryCount,
424
- maxRetries: stored.maxRetries,
425
- timeoutMs: stored.timeoutMs,
426
- createdAt: new Date(stored.createdAt),
427
- startedAt: stored.startedAt ? new Date(stored.startedAt) : void 0,
428
- suspendedAt: stored.suspendedAt ? new Date(stored.suspendedAt) : void 0,
429
- completedAt: stored.completedAt ? new Date(stored.completedAt) : void 0
543
+ id: record.id,
544
+ status: record.status,
545
+ toolName: legacyOrCurrent(record, "tool_name", "toolName"),
546
+ toolCallId: legacyOrCurrent(record, "tool_call_id", "toolCallId"),
547
+ args: parseJson3(record.args) ?? {},
548
+ agentId: legacyOrCurrent(record, "agent_id", "agentId"),
549
+ threadId: legacyOrCurrent(record, "thread_id", "threadId") ?? void 0,
550
+ resourceId: legacyOrCurrent(record, "resource_id", "resourceId") ?? void 0,
551
+ runId: legacyOrCurrent(record, "run_id", "runId"),
552
+ result: parseJson3(record.result),
553
+ error: parseJson3(record.error),
554
+ suspendPayload: parseJson3(legacyOrCurrent(record, "suspend_payload", "suspendPayload")),
555
+ retryCount: legacyOrCurrent(record, "retry_count", "retryCount"),
556
+ maxRetries: legacyOrCurrent(record, "max_retries", "maxRetries"),
557
+ timeoutMs: legacyOrCurrent(record, "timeout_ms", "timeoutMs"),
558
+ createdAt: new Date(record.createdAt),
559
+ startedAt: record.startedAt ? new Date(record.startedAt) : void 0,
560
+ suspendedAt: record.suspendedAt ? new Date(record.suspendedAt) : void 0,
561
+ completedAt: record.completedAt ? new Date(record.completedAt) : void 0
430
562
  };
431
563
  }
564
+ function hasDeleteFilter(filter) {
565
+ return Boolean(
566
+ (Array.isArray(filter.status) ? filter.status.length > 0 : filter.status) || filter.agentId || filter.threadId || filter.resourceId || filter.toolName || filter.toolCallId || filter.runId || filter.fromDate || filter.toDate
567
+ );
568
+ }
432
569
  var BackgroundTasksConvex = class extends BackgroundTasksStorage {
433
570
  #db;
434
571
  constructor(config) {
@@ -443,26 +580,34 @@ var BackgroundTasksConvex = class extends BackgroundTasksStorage {
443
580
  await this.#db.insert({ tableName: TABLE_BACKGROUND_TASKS, record: toStored(task) });
444
581
  }
445
582
  async updateTask(taskId, update) {
446
- const existing = await this.getTask(taskId);
447
- if (!existing) return;
448
- const merged = { ...existing };
449
- if ("status" in update) merged.status = update.status;
450
- if ("result" in update) merged.result = update.result;
451
- if ("error" in update) merged.error = update.error;
452
- if ("suspendPayload" in update) merged.suspendPayload = update.suspendPayload;
453
- if ("retryCount" in update) merged.retryCount = update.retryCount;
454
- if ("startedAt" in update) merged.startedAt = update.startedAt;
455
- if ("suspendedAt" in update) merged.suspendedAt = update.suspendedAt;
456
- if ("completedAt" in update) merged.completedAt = update.completedAt;
457
- await this.#db.deleteMany(TABLE_BACKGROUND_TASKS, [taskId]);
458
- await this.#db.insert({ tableName: TABLE_BACKGROUND_TASKS, record: toStored(merged) });
583
+ const patch = toStoredPatch(update);
584
+ if (Object.keys(patch).length === 0) return;
585
+ await this.#db.patch({
586
+ tableName: TABLE_BACKGROUND_TASKS,
587
+ id: taskId,
588
+ record: patch
589
+ });
459
590
  }
460
591
  async getTask(taskId) {
461
592
  const data = await this.#db.load({ tableName: TABLE_BACKGROUND_TASKS, keys: { id: taskId } });
462
593
  return data ? fromStored(data) : null;
463
594
  }
464
595
  async listTasks(filter) {
465
- const all = await this.#db.queryTable(TABLE_BACKGROUND_TASKS);
596
+ const queryFilters = [];
597
+ if (typeof filter.status === "string") queryFilters.push({ field: "status", value: filter.status });
598
+ if (Array.isArray(filter.status) && filter.status.length === 1) {
599
+ queryFilters.push({ field: "status", value: filter.status[0] });
600
+ }
601
+ if (filter.agentId) queryFilters.push({ field: "agent_id", value: filter.agentId });
602
+ if (filter.threadId) queryFilters.push({ field: "thread_id", value: filter.threadId });
603
+ if (filter.resourceId) queryFilters.push({ field: "resource_id", value: filter.resourceId });
604
+ if (filter.toolName) queryFilters.push({ field: "tool_name", value: filter.toolName });
605
+ if (filter.toolCallId) queryFilters.push({ field: "tool_call_id", value: filter.toolCallId });
606
+ if (filter.runId) queryFilters.push({ field: "run_id", value: filter.runId });
607
+ const all = await this.#db.queryTable(
608
+ TABLE_BACKGROUND_TASKS,
609
+ queryFilters.length > 0 ? queryFilters : void 0
610
+ );
466
611
  let tasks = all.map(fromStored);
467
612
  if (filter.status) {
468
613
  const s = Array.isArray(filter.status) ? filter.status : [filter.status];
@@ -470,6 +615,7 @@ var BackgroundTasksConvex = class extends BackgroundTasksStorage {
470
615
  }
471
616
  if (filter.agentId) tasks = tasks.filter((t) => t.agentId === filter.agentId);
472
617
  if (filter.threadId) tasks = tasks.filter((t) => t.threadId === filter.threadId);
618
+ if (filter.resourceId) tasks = tasks.filter((t) => t.resourceId === filter.resourceId);
473
619
  if (filter.toolName) tasks = tasks.filter((t) => t.toolName === filter.toolName);
474
620
  if (filter.toolCallId) tasks = tasks.filter((t) => t.toolCallId === filter.toolCallId);
475
621
  if (filter.runId) tasks = tasks.filter((t) => t.runId === filter.runId);
@@ -502,6 +648,7 @@ var BackgroundTasksConvex = class extends BackgroundTasksStorage {
502
648
  await this.#db.deleteMany(TABLE_BACKGROUND_TASKS, [taskId]);
503
649
  }
504
650
  async deleteTasks(filter) {
651
+ if (!hasDeleteFilter(filter)) return;
505
652
  const { tasks } = await this.listTasks(filter);
506
653
  const taskIds = tasks.map((t) => t.id);
507
654
  await this.#db.deleteMany(TABLE_BACKGROUND_TASKS, taskIds);
@@ -515,6 +662,141 @@ var BackgroundTasksConvex = class extends BackgroundTasksStorage {
515
662
  return total;
516
663
  }
517
664
  };
665
+ var statusPriority = {
666
+ active: 0,
667
+ pending: 1,
668
+ error: 2
669
+ };
670
+ function stringifyJson(value) {
671
+ return JSON.stringify(value);
672
+ }
673
+ function parseJson(value, context) {
674
+ try {
675
+ return JSON.parse(value);
676
+ } catch (error) {
677
+ throw new Error(`Invalid channel data JSON for ${context}`, { cause: error });
678
+ }
679
+ }
680
+ function installationToRecord(installation, existingRecord) {
681
+ const now = (/* @__PURE__ */ new Date()).toISOString();
682
+ return {
683
+ id: installation.id,
684
+ platform: installation.platform,
685
+ agentId: installation.agentId,
686
+ status: installation.status,
687
+ webhookId: installation.webhookId ?? null,
688
+ data: stringifyJson(installation.data),
689
+ configHash: installation.configHash ?? null,
690
+ error: installation.error ?? null,
691
+ createdAt: existingRecord?.createdAt ?? installation.createdAt?.toISOString() ?? now,
692
+ updatedAt: now
693
+ };
694
+ }
695
+ function recordToInstallation(record) {
696
+ return {
697
+ id: record.id,
698
+ platform: record.platform,
699
+ agentId: record.agentId,
700
+ status: record.status,
701
+ webhookId: record.webhookId ?? void 0,
702
+ data: parseJson(record.data, `installation ${record.id}`),
703
+ configHash: record.configHash ?? void 0,
704
+ error: record.error ?? void 0,
705
+ createdAt: new Date(record.createdAt),
706
+ updatedAt: new Date(record.updatedAt)
707
+ };
708
+ }
709
+ function configToRecord(config) {
710
+ return {
711
+ id: config.platform,
712
+ platform: config.platform,
713
+ data: stringifyJson(config.data),
714
+ updatedAt: config.updatedAt.toISOString()
715
+ };
716
+ }
717
+ function recordToConfig(record) {
718
+ return {
719
+ platform: record.platform,
720
+ data: parseJson(record.data, `config ${record.platform}`),
721
+ updatedAt: new Date(record.updatedAt)
722
+ };
723
+ }
724
+ function sortInstallationsForAgent(a, b) {
725
+ const statusDiff = statusPriority[a.status] - statusPriority[b.status];
726
+ if (statusDiff !== 0) return statusDiff;
727
+ return b.updatedAt.getTime() - a.updatedAt.getTime();
728
+ }
729
+ var ChannelsConvex = class extends ChannelsStorage {
730
+ #db;
731
+ constructor(config) {
732
+ super();
733
+ const client = resolveConvexConfig(config);
734
+ this.#db = new ConvexDB(client);
735
+ }
736
+ async init() {
737
+ }
738
+ async dangerouslyClearAll() {
739
+ await this.#db.clearTable({ tableName: TABLE_CHANNEL_INSTALLATIONS });
740
+ await this.#db.clearTable({ tableName: TABLE_CHANNEL_CONFIG });
741
+ }
742
+ async saveInstallation(installation) {
743
+ const existingRecord = await this.#db.load({
744
+ tableName: TABLE_CHANNEL_INSTALLATIONS,
745
+ keys: { id: installation.id }
746
+ });
747
+ await this.#db.insert({
748
+ tableName: TABLE_CHANNEL_INSTALLATIONS,
749
+ record: installationToRecord(installation, existingRecord)
750
+ });
751
+ }
752
+ async getInstallation(id) {
753
+ const record = await this.#db.load({
754
+ tableName: TABLE_CHANNEL_INSTALLATIONS,
755
+ keys: { id }
756
+ });
757
+ return record ? recordToInstallation(record) : null;
758
+ }
759
+ async getInstallationByAgent(platform, agentId) {
760
+ const records = await this.#db.queryTable(TABLE_CHANNEL_INSTALLATIONS, [
761
+ { field: "platform", value: platform },
762
+ { field: "agentId", value: agentId }
763
+ ]);
764
+ const [installation] = records.map(recordToInstallation).sort(sortInstallationsForAgent);
765
+ return installation ?? null;
766
+ }
767
+ async getInstallationByWebhookId(webhookId) {
768
+ const records = await this.#db.queryTable(TABLE_CHANNEL_INSTALLATIONS, [
769
+ { field: "webhookId", value: webhookId }
770
+ ]);
771
+ const [installation] = records.map(recordToInstallation).sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());
772
+ return installation ?? null;
773
+ }
774
+ async listInstallations(platform) {
775
+ const records = await this.#db.queryTable(TABLE_CHANNEL_INSTALLATIONS, [
776
+ { field: "platform", value: platform }
777
+ ]);
778
+ return records.map(recordToInstallation).sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
779
+ }
780
+ async deleteInstallation(id) {
781
+ await this.#db.deleteMany(TABLE_CHANNEL_INSTALLATIONS, [id]);
782
+ }
783
+ async saveConfig(config) {
784
+ await this.#db.insert({
785
+ tableName: TABLE_CHANNEL_CONFIG,
786
+ record: configToRecord(config)
787
+ });
788
+ }
789
+ async getConfig(platform) {
790
+ const record = await this.#db.load({
791
+ tableName: TABLE_CHANNEL_CONFIG,
792
+ keys: { id: platform }
793
+ });
794
+ return record ? recordToConfig(record) : null;
795
+ }
796
+ async deleteConfig(platform) {
797
+ await this.#db.deleteMany(TABLE_CHANNEL_CONFIG, [platform]);
798
+ }
799
+ };
518
800
  var MemoryConvex = class extends MemoryStorage {
519
801
  #db;
520
802
  constructor(config) {
@@ -1000,6 +1282,247 @@ var MemoryConvex = class extends MemoryStorage {
1000
1282
  }
1001
1283
  }
1002
1284
  };
1285
+ var SCHEDULE_LIST_LIMIT = 8e3;
1286
+ function serializeJson2(value) {
1287
+ return JSON.stringify(value);
1288
+ }
1289
+ function parseJson2(value) {
1290
+ if (value == null) return void 0;
1291
+ if (typeof value === "string") {
1292
+ try {
1293
+ return JSON.parse(value);
1294
+ } catch {
1295
+ return value;
1296
+ }
1297
+ }
1298
+ return value;
1299
+ }
1300
+ function isMissingSchedulesSchemaError(error) {
1301
+ const message = error instanceof Error ? error.message : String(error);
1302
+ return /(?:Table|table)\s+(?:["'`])?(?:mastra_schedules|mastra_schedule_triggers)(?:["'`])?\s+(?:is\s+)?(?:not\s+in\s+the\s+schema|not\s+found\s+in\s+schema|not\s+found|does\s+not\s+exist)/i.test(
1303
+ message
1304
+ );
1305
+ }
1306
+ function scheduleToRecord(schedule) {
1307
+ return {
1308
+ id: schedule.id,
1309
+ target: serializeJson2(schedule.target),
1310
+ cron: schedule.cron,
1311
+ timezone: schedule.timezone ?? null,
1312
+ status: schedule.status,
1313
+ next_fire_at: schedule.nextFireAt,
1314
+ last_fire_at: schedule.lastFireAt ?? null,
1315
+ last_run_id: schedule.lastRunId ?? null,
1316
+ created_at: schedule.createdAt,
1317
+ updated_at: schedule.updatedAt,
1318
+ metadata: schedule.metadata == null ? null : serializeJson2(schedule.metadata),
1319
+ owner_type: schedule.ownerType ?? null,
1320
+ owner_id: schedule.ownerId ?? null,
1321
+ workflow_id: schedule.target.type === "workflow" ? schedule.target.workflowId : null
1322
+ };
1323
+ }
1324
+ function recordToSchedule(record) {
1325
+ const target = parseJson2(record.target);
1326
+ if (!target || typeof target !== "object" || typeof target.type !== "string") {
1327
+ throw new Error(`Schedule ${record.id} has invalid target`);
1328
+ }
1329
+ const schedule = {
1330
+ id: String(record.id),
1331
+ target,
1332
+ cron: String(record.cron),
1333
+ status: String(record.status),
1334
+ nextFireAt: Number(record.next_fire_at),
1335
+ createdAt: Number(record.created_at),
1336
+ updatedAt: Number(record.updated_at)
1337
+ };
1338
+ if (record.timezone != null) schedule.timezone = String(record.timezone);
1339
+ if (record.last_fire_at != null) schedule.lastFireAt = Number(record.last_fire_at);
1340
+ if (record.last_run_id != null) schedule.lastRunId = String(record.last_run_id);
1341
+ const metadata = parseJson2(record.metadata);
1342
+ if (metadata != null) schedule.metadata = metadata;
1343
+ if (record.owner_type != null) schedule.ownerType = String(record.owner_type);
1344
+ if (record.owner_id != null) schedule.ownerId = String(record.owner_id);
1345
+ return schedule;
1346
+ }
1347
+ function triggerToRecord(trigger) {
1348
+ return {
1349
+ id: trigger.id ?? crypto.randomUUID(),
1350
+ schedule_id: trigger.scheduleId,
1351
+ run_id: trigger.runId,
1352
+ scheduled_fire_at: trigger.scheduledFireAt,
1353
+ actual_fire_at: trigger.actualFireAt,
1354
+ outcome: trigger.outcome,
1355
+ error: trigger.error ?? null,
1356
+ trigger_kind: trigger.triggerKind ?? "schedule-fire",
1357
+ parent_trigger_id: trigger.parentTriggerId ?? null,
1358
+ metadata: trigger.metadata == null ? null : serializeJson2(trigger.metadata)
1359
+ };
1360
+ }
1361
+ function recordToTrigger(record) {
1362
+ const trigger = {
1363
+ id: record.id != null ? String(record.id) : void 0,
1364
+ scheduleId: String(record.schedule_id),
1365
+ runId: record.run_id != null ? String(record.run_id) : null,
1366
+ scheduledFireAt: Number(record.scheduled_fire_at),
1367
+ actualFireAt: Number(record.actual_fire_at),
1368
+ outcome: String(record.outcome),
1369
+ triggerKind: record.trigger_kind != null ? String(record.trigger_kind) : "schedule-fire"
1370
+ };
1371
+ if (record.error != null) trigger.error = String(record.error);
1372
+ if (record.parent_trigger_id != null) trigger.parentTriggerId = String(record.parent_trigger_id);
1373
+ const metadata = parseJson2(record.metadata);
1374
+ if (metadata != null) trigger.metadata = metadata;
1375
+ return trigger;
1376
+ }
1377
+ var SchedulesConvex = class extends SchedulesStorage {
1378
+ #db;
1379
+ constructor(config) {
1380
+ super();
1381
+ const client = resolveConvexConfig(config);
1382
+ this.#db = new ConvexDB(client);
1383
+ }
1384
+ async init() {
1385
+ }
1386
+ async dangerouslyClearAll() {
1387
+ await this.#db.clearTable({ tableName: TABLE_SCHEDULE_TRIGGERS });
1388
+ await this.#db.clearTable({ tableName: TABLE_SCHEDULES });
1389
+ }
1390
+ async createSchedule(schedule) {
1391
+ await this.#db.createSchedule(scheduleToRecord(schedule));
1392
+ return schedule;
1393
+ }
1394
+ async getSchedule(id) {
1395
+ const record = await this.#db.load({ tableName: TABLE_SCHEDULES, keys: { id } });
1396
+ return record ? recordToSchedule(record) : null;
1397
+ }
1398
+ async listSchedules(filter) {
1399
+ const queryFilters = [];
1400
+ if (filter?.status) queryFilters.push({ field: "status", value: filter.status });
1401
+ if (filter?.ownerType !== void 0 && filter.ownerType !== null) {
1402
+ queryFilters.push({ field: "owner_type", value: filter.ownerType });
1403
+ }
1404
+ if (filter?.ownerType === null) {
1405
+ queryFilters.push({ field: "owner_type", value: null });
1406
+ }
1407
+ if (filter?.ownerId !== void 0 && filter.ownerId !== null) {
1408
+ queryFilters.push({ field: "owner_id", value: filter.ownerId });
1409
+ }
1410
+ if (filter?.ownerId === null) {
1411
+ queryFilters.push({ field: "owner_id", value: null });
1412
+ }
1413
+ if (filter?.workflowId) queryFilters.push({ field: "workflow_id", value: filter.workflowId });
1414
+ let records;
1415
+ try {
1416
+ records = await this.#db.queryTable(
1417
+ TABLE_SCHEDULES,
1418
+ queryFilters.length ? queryFilters : void 0,
1419
+ void 0,
1420
+ SCHEDULE_LIST_LIMIT
1421
+ );
1422
+ } catch (error) {
1423
+ if (isMissingSchedulesSchemaError(error)) {
1424
+ this.logger.warn("Convex schedules schema is not available; returning no schedules", { error });
1425
+ return [];
1426
+ }
1427
+ throw error;
1428
+ }
1429
+ if (records.length >= SCHEDULE_LIST_LIMIT) {
1430
+ this.logger.warn("Convex schedules list reached the adapter limit; results may be truncated", {
1431
+ limit: SCHEDULE_LIST_LIMIT
1432
+ });
1433
+ }
1434
+ let schedules = records.map(recordToSchedule);
1435
+ if (filter?.workflowId) {
1436
+ schedules = schedules.filter(
1437
+ (schedule) => schedule.target.type === "workflow" && schedule.target.workflowId === filter.workflowId
1438
+ );
1439
+ }
1440
+ if (filter?.ownerType === null) {
1441
+ schedules = schedules.filter((schedule) => (schedule.ownerType ?? null) === null);
1442
+ }
1443
+ if (filter?.ownerId === null) {
1444
+ schedules = schedules.filter((schedule) => (schedule.ownerId ?? null) === null);
1445
+ }
1446
+ schedules.sort((a, b) => a.createdAt - b.createdAt);
1447
+ return schedules;
1448
+ }
1449
+ async listDueSchedules(now, limit) {
1450
+ let records;
1451
+ try {
1452
+ records = await this.#db.listDueSchedules(now, limit);
1453
+ } catch (error) {
1454
+ if (isMissingSchedulesSchemaError(error)) {
1455
+ this.logger.warn("Convex schedules schema is not available; returning no due schedules", { error });
1456
+ return [];
1457
+ }
1458
+ throw error;
1459
+ }
1460
+ return records.map(recordToSchedule);
1461
+ }
1462
+ async updateSchedule(id, patch) {
1463
+ const updates = {};
1464
+ if ("cron" in patch && patch.cron !== void 0) {
1465
+ updates.cron = patch.cron;
1466
+ }
1467
+ if ("timezone" in patch) {
1468
+ updates.timezone = patch.timezone ?? null;
1469
+ }
1470
+ if ("status" in patch && patch.status !== void 0) {
1471
+ updates.status = patch.status;
1472
+ }
1473
+ if ("nextFireAt" in patch && patch.nextFireAt !== void 0) {
1474
+ updates.next_fire_at = patch.nextFireAt;
1475
+ }
1476
+ if ("target" in patch && patch.target !== void 0) {
1477
+ updates.target = serializeJson2(patch.target);
1478
+ updates.workflow_id = patch.target.type === "workflow" ? patch.target.workflowId : null;
1479
+ }
1480
+ if ("metadata" in patch) {
1481
+ updates.metadata = patch.metadata == null ? null : serializeJson2(patch.metadata);
1482
+ }
1483
+ if ("ownerType" in patch) {
1484
+ updates.owner_type = patch.ownerType ?? null;
1485
+ }
1486
+ if ("ownerId" in patch) {
1487
+ updates.owner_id = patch.ownerId ?? null;
1488
+ }
1489
+ if (Object.keys(updates).length === 0) {
1490
+ const existing = await this.getSchedule(id);
1491
+ if (!existing) {
1492
+ throw new Error(`Schedule ${id} not found`);
1493
+ }
1494
+ return existing;
1495
+ }
1496
+ updates.updated_at = Date.now();
1497
+ const updated = await this.#db.updateSchedule({ id, patch: updates });
1498
+ return recordToSchedule(updated);
1499
+ }
1500
+ async updateScheduleNextFire(id, expectedNextFireAt, newNextFireAt, lastFireAt, lastRunId) {
1501
+ return this.#db.updateScheduleNextFire({
1502
+ id,
1503
+ expectedNextFireAt,
1504
+ newNextFireAt,
1505
+ lastFireAt,
1506
+ lastRunId
1507
+ });
1508
+ }
1509
+ async deleteSchedule(id) {
1510
+ await this.#db.deleteScheduleTriggers(id);
1511
+ await this.#db.deleteMany(TABLE_SCHEDULES, [id]);
1512
+ }
1513
+ async recordTrigger(trigger) {
1514
+ await this.#db.recordScheduleTrigger(triggerToRecord(trigger));
1515
+ }
1516
+ async listTriggers(scheduleId, opts) {
1517
+ const triggers = await this.#db.listScheduleTriggers({
1518
+ scheduleId,
1519
+ fromActualFireAt: opts?.fromActualFireAt,
1520
+ toActualFireAt: opts?.toActualFireAt,
1521
+ limit: opts?.limit
1522
+ });
1523
+ return triggers.map(recordToTrigger);
1524
+ }
1525
+ };
1003
1526
  var ScoresConvex = class extends ScoresStorage {
1004
1527
  #db;
1005
1528
  constructor(config) {
@@ -1280,7 +1803,9 @@ var ConvexStore = class extends MastraCompositeStore {
1280
1803
  memory,
1281
1804
  workflows,
1282
1805
  scores,
1283
- backgroundTasks: new BackgroundTasksConvex(domainConfig)
1806
+ backgroundTasks: new BackgroundTasksConvex(domainConfig),
1807
+ schedules: new SchedulesConvex(domainConfig),
1808
+ channels: new ChannelsConvex(domainConfig)
1284
1809
  };
1285
1810
  }
1286
1811
  };