@mastra/factory 0.25.0-alpha.4 → 0.25.0-alpha.5

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 (301) hide show
  1. package/dist/auth.js +1 -2
  2. package/dist/boards/define-board.js +1 -2
  3. package/dist/boards/index.js +1 -2
  4. package/dist/boards/registry.js +1 -2
  5. package/dist/boards/relocate.js +1 -2
  6. package/dist/boards/review.js +1 -2
  7. package/dist/boards/semantics.js +1 -2
  8. package/dist/boards/transition-policy.js +1 -2
  9. package/dist/boards/work-tool-rules.js +1 -2
  10. package/dist/boards/work-transition-policy.js +1 -2
  11. package/dist/boards/work.js +1 -2
  12. package/dist/environment/build-runner.js +1 -2
  13. package/dist/environment/build-schedule.js +1 -2
  14. package/dist/environment/build-workflow.js +1 -2
  15. package/dist/environment/build.js +1 -2
  16. package/dist/environment/heads.js +1 -2
  17. package/dist/factory.d.ts +4 -2
  18. package/dist/factory.d.ts.map +1 -1
  19. package/dist/factory.js +43 -16
  20. package/dist/factory.js.map +1 -1
  21. package/dist/feed-events.js +1 -2
  22. package/dist/index.js +2 -2
  23. package/dist/integrations/channel-thread-announcements.d.ts +8 -0
  24. package/dist/integrations/channel-thread-announcements.d.ts.map +1 -0
  25. package/dist/integrations/channel-thread-announcements.js +16 -0
  26. package/dist/integrations/channel-thread-announcements.js.map +1 -0
  27. package/dist/integrations/github/acceptance-labels.js +1 -2
  28. package/dist/integrations/github/app-identity.js +1 -2
  29. package/dist/integrations/github/commits.js +1 -2
  30. package/dist/integrations/github/config.js +1 -2
  31. package/dist/integrations/github/default-rules.js +2 -3
  32. package/dist/integrations/github/integration.js +3 -4
  33. package/dist/integrations/github/issue-reconciler.js +1 -2
  34. package/dist/integrations/github/pat.js +1 -2
  35. package/dist/integrations/github/provenance.d.ts.map +1 -1
  36. package/dist/integrations/github/provenance.js +2 -5
  37. package/dist/integrations/github/provenance.js.map +1 -1
  38. package/dist/integrations/github/reconcile-worker.js +1 -2
  39. package/dist/integrations/github/reconciliation-config.js +1 -2
  40. package/dist/integrations/github/routes.js +4 -5
  41. package/dist/integrations/github/rules.d.ts.map +1 -1
  42. package/dist/integrations/github/rules.js +14 -3
  43. package/dist/integrations/github/rules.js.map +1 -1
  44. package/dist/integrations/github/sandbox-release.js +1 -2
  45. package/dist/integrations/github/sandbox.js +1 -2
  46. package/dist/integrations/github/session-subscriptions.js +1 -2
  47. package/dist/integrations/github/settle-or-abort.js +1 -2
  48. package/dist/integrations/github/stale-reviews.js +1 -2
  49. package/dist/integrations/github/subscriptions.js +1 -2
  50. package/dist/integrations/github/token-refresh.js +1 -2
  51. package/dist/integrations/github/webhook.d.ts.map +1 -1
  52. package/dist/integrations/github/webhook.js +17 -3
  53. package/dist/integrations/github/webhook.js.map +1 -1
  54. package/dist/integrations/gitlab/agent-tools.js +1 -2
  55. package/dist/integrations/gitlab/api.js +1 -2
  56. package/dist/integrations/gitlab/default-rules.js +1 -2
  57. package/dist/integrations/gitlab/integration.js +2 -3
  58. package/dist/integrations/gitlab/issue-reconciler.js +1 -2
  59. package/dist/integrations/gitlab/merge-request-reconciler.js +1 -2
  60. package/dist/integrations/gitlab/reconciler.js +1 -2
  61. package/dist/integrations/gitlab/reconciliation-config.js +1 -2
  62. package/dist/integrations/gitlab/routes.js +1 -2
  63. package/dist/integrations/gitlab/rules.js +1 -2
  64. package/dist/integrations/gitlab/session-subscriptions.js +1 -2
  65. package/dist/integrations/gitlab/subscriptions.js +1 -2
  66. package/dist/integrations/gitlab/version-control.js +1 -2
  67. package/dist/integrations/gitlab/webhook-dispatch.js +1 -2
  68. package/dist/integrations/gitlab/webhook.js +1 -2
  69. package/dist/integrations/incidentio/agent-tools.js +1 -2
  70. package/dist/integrations/incidentio/api.js +1 -2
  71. package/dist/integrations/incidentio/claim.js +1 -2
  72. package/dist/integrations/incidentio/default-rules.js +1 -2
  73. package/dist/integrations/incidentio/intake.js +1 -2
  74. package/dist/integrations/incidentio/integration.js +1 -2
  75. package/dist/integrations/incidentio/issue-reconciler.js +1 -2
  76. package/dist/integrations/incidentio/reconciliation-config.js +1 -2
  77. package/dist/integrations/incidentio/routes.js +1 -2
  78. package/dist/integrations/incidentio/rules.js +1 -2
  79. package/dist/integrations/issue-reconcile-worker.js +1 -2
  80. package/dist/integrations/issue-reconciler.js +1 -2
  81. package/dist/integrations/jira/adf.js +1 -2
  82. package/dist/integrations/jira/agent-tools.js +1 -2
  83. package/dist/integrations/jira/api.js +1 -2
  84. package/dist/integrations/jira/claim.js +1 -2
  85. package/dist/integrations/jira/default-rules.js +1 -2
  86. package/dist/integrations/jira/integration.js +1 -2
  87. package/dist/integrations/jira/issue-reconciler.js +1 -2
  88. package/dist/integrations/jira/reconciliation-config.js +1 -2
  89. package/dist/integrations/jira/routes.js +1 -2
  90. package/dist/integrations/jira/rules.js +1 -2
  91. package/dist/integrations/linear/agent-tools.d.ts +1 -1
  92. package/dist/integrations/linear/agent-tools.d.ts.map +1 -1
  93. package/dist/integrations/linear/agent-tools.js +5 -5
  94. package/dist/integrations/linear/agent-tools.js.map +1 -1
  95. package/dist/integrations/linear/claim.js +1 -2
  96. package/dist/integrations/linear/default-rules.js +1 -2
  97. package/dist/integrations/linear/integration.d.ts +2 -0
  98. package/dist/integrations/linear/integration.d.ts.map +1 -1
  99. package/dist/integrations/linear/integration.js +2 -2
  100. package/dist/integrations/linear/integration.js.map +1 -1
  101. package/dist/integrations/linear/issue-reconciler.js +1 -2
  102. package/dist/integrations/linear/reconciliation-config.js +1 -2
  103. package/dist/integrations/linear/routes.js +1 -2
  104. package/dist/integrations/linear/rules.js +1 -2
  105. package/dist/integrations/platform/api-client.js +1 -2
  106. package/dist/integrations/platform/connect/routes.js +1 -2
  107. package/dist/integrations/platform/github/event-worker.js +6 -2
  108. package/dist/integrations/platform/github/event-worker.js.map +1 -1
  109. package/dist/integrations/platform/github/integration.js +1 -2
  110. package/dist/integrations/platform/gitlab/event-worker.js +1 -2
  111. package/dist/integrations/platform/gitlab/integration.js +1 -2
  112. package/dist/integrations/platform/incidentio/integration.js +1 -2
  113. package/dist/integrations/platform/jira/agent-tools.js +1 -2
  114. package/dist/integrations/platform/jira/integration.js +1 -2
  115. package/dist/integrations/platform/jira/routes.js +1 -2
  116. package/dist/integrations/platform/linear/event-worker.js +1 -2
  117. package/dist/integrations/platform/linear/integration.d.ts.map +1 -1
  118. package/dist/integrations/platform/linear/integration.js +2 -2
  119. package/dist/integrations/platform/linear/integration.js.map +1 -1
  120. package/dist/integrations/pull-request-head.js +1 -2
  121. package/dist/integrations/reconciliation-config.js +1 -2
  122. package/dist/integrations/slack/channel-reply-processor.d.ts.map +1 -1
  123. package/dist/integrations/slack/channel-reply-processor.js +11 -5
  124. package/dist/integrations/slack/channel-reply-processor.js.map +1 -1
  125. package/dist/integrations/slack/channel-session-link-processor.js +1 -2
  126. package/dist/integrations/slack/connect-route.js +1 -2
  127. package/dist/integrations/slack/emoji-shortcodes.generated.js +1 -2
  128. package/dist/integrations/slack/emoji.js +1 -2
  129. package/dist/integrations/slack/feed-publisher.js +1 -2
  130. package/dist/integrations/slack/integration.d.ts +5 -0
  131. package/dist/integrations/slack/integration.d.ts.map +1 -1
  132. package/dist/integrations/slack/integration.js +13 -2
  133. package/dist/integrations/slack/integration.js.map +1 -1
  134. package/dist/integrations/slack/reply-reminder-processor.js +1 -2
  135. package/dist/integrations/slack/reply-tool.js +1 -2
  136. package/dist/integrations/slack/share-file-tool.js +1 -2
  137. package/dist/integrations/slack/slack.js +2 -3
  138. package/dist/integrations/subscription-session.js +1 -2
  139. package/dist/integrations/workos/integration.js +1 -2
  140. package/dist/mcp/disconnect.js +1 -2
  141. package/dist/mcp/events.js +2 -3
  142. package/dist/mcp/routes.js +1 -2
  143. package/dist/packages/_internals/workspace/dist/index.js +1 -2
  144. package/dist/packages/_internals/workspace/dist/index.js.map +1 -1
  145. package/dist/platform-auth-host.js +1 -2
  146. package/dist/provider-display-name.js +1 -2
  147. package/dist/review-verdict.d.ts +1 -0
  148. package/dist/review-verdict.d.ts.map +1 -1
  149. package/dist/review-verdict.js +9 -3
  150. package/dist/review-verdict.js.map +1 -1
  151. package/dist/routes/attention-activity.js +1 -2
  152. package/dist/routes/attention-parked.js +1 -2
  153. package/dist/routes/attention-proposed.js +1 -2
  154. package/dist/routes/attention-providers.js +1 -2
  155. package/dist/routes/attention.js +1 -2
  156. package/dist/routes/automation-runs.js +1 -2
  157. package/dist/routes/config.d.ts +4 -0
  158. package/dist/routes/config.d.ts.map +1 -1
  159. package/dist/routes/config.js +7 -2
  160. package/dist/routes/config.js.map +1 -1
  161. package/dist/routes/contracts.js +1 -2
  162. package/dist/routes/custom-provider-source.js +1 -2
  163. package/dist/routes/fs.js +1 -2
  164. package/dist/routes/intake.js +1 -2
  165. package/dist/routes/knowledge.js +1 -2
  166. package/dist/routes/oauth.js +1 -2
  167. package/dist/routes/projects.js +1 -2
  168. package/dist/routes/provider-credentials.js +1 -2
  169. package/dist/routes/route.js +1 -2
  170. package/dist/routes/session-access.js +1 -2
  171. package/dist/routes/skills.js +1 -2
  172. package/dist/routes/source-control-sessions.js +5 -6
  173. package/dist/routes/source-control-settings.js +1 -2
  174. package/dist/routes/surface.js +2 -3
  175. package/dist/routes/telemetry.js +1 -2
  176. package/dist/routes/tenant-credentials.js +1 -2
  177. package/dist/routes/work-items.js +2 -3
  178. package/dist/rules/binding-context.js +1 -2
  179. package/dist/rules/decision-applicability.js +1 -2
  180. package/dist/rules/dispatch-errors.js +1 -2
  181. package/dist/rules/dispatcher.js +1 -2
  182. package/dist/rules/event-rules.js +1 -2
  183. package/dist/rules/processor.js +1 -2
  184. package/dist/rules/resolve.js +1 -2
  185. package/dist/rules/review-source-tool.js +1 -2
  186. package/dist/rules/start-coordinator.js +1 -2
  187. package/dist/rules/terminal-cleanup.js +1 -2
  188. package/dist/rules/tools.js +1 -2
  189. package/dist/rules/transition-service.js +1 -2
  190. package/dist/rules/types.d.ts +4 -1
  191. package/dist/rules/types.d.ts.map +1 -1
  192. package/dist/rules/types.js +1 -2
  193. package/dist/rules/types.js.map +1 -1
  194. package/dist/rules/validation.js +1 -2
  195. package/dist/sandbox/callback-factory-sandbox.js +1 -2
  196. package/dist/sandbox/git-ref.js +1 -2
  197. package/dist/sandbox/local-factory-sandbox.d.ts +12 -4
  198. package/dist/sandbox/local-factory-sandbox.d.ts.map +1 -1
  199. package/dist/sandbox/local-factory-sandbox.js +32 -7
  200. package/dist/sandbox/local-factory-sandbox.js.map +1 -1
  201. package/dist/sandbox/materialization.js +1 -2
  202. package/dist/sandbox/session-retirement.js +1 -2
  203. package/dist/sandbox/session-sandbox.js +1 -2
  204. package/dist/sandbox/workdir.js +1 -2
  205. package/dist/secret-encryption.js +1 -2
  206. package/dist/server-error.js +1 -2
  207. package/dist/session/credential-policy.js +1 -2
  208. package/dist/session/default-model-hydration.js +1 -2
  209. package/dist/session/environment-repositories.js +1 -2
  210. package/dist/session/environment-state-processor.d.ts +0 -1
  211. package/dist/session/environment-state-processor.d.ts.map +1 -1
  212. package/dist/session/environment-state-processor.js +2 -3
  213. package/dist/session/environment-state-processor.js.map +1 -1
  214. package/dist/session/factory-session.js +1 -2
  215. package/dist/session/filesystem-capture.js +2 -3
  216. package/dist/session/filesystem-capture.js.map +1 -1
  217. package/dist/session/first-exec-capture.js +2 -3
  218. package/dist/session/first-exec-capture.js.map +1 -1
  219. package/dist/session/first-message-capture.js +1 -2
  220. package/dist/session/live-sessions.js +1 -2
  221. package/dist/session/memory-settings-hydration.js +1 -2
  222. package/dist/session/org-seed.js +1 -2
  223. package/dist/session/reply-credential-processor.js +1 -2
  224. package/dist/session/resource-migration.js +1 -2
  225. package/dist/session/run-audit.js +1 -2
  226. package/dist/session/session-threads.js +1 -2
  227. package/dist/session/session-title.js +1 -2
  228. package/dist/session/shell-commands.js +1 -2
  229. package/dist/session/source-control-tools.js +2 -3
  230. package/dist/session/thinking-default.js +1 -2
  231. package/dist/session/thread-session-stamp.js +1 -2
  232. package/dist/session/thread-title-mirror.js +1 -2
  233. package/dist/session/thread-title-mirror.js.map +1 -1
  234. package/dist/session/work-item-repository.js +1 -2
  235. package/dist/session-owner-signal.js +1 -2
  236. package/dist/skills/catalog.js +1 -2
  237. package/dist/skills/service.js +1 -2
  238. package/dist/spa-static.js +1 -2
  239. package/dist/state-signing.js +1 -2
  240. package/dist/storage/domains/audit/actions.js +1 -2
  241. package/dist/storage/domains/audit/actors.js +1 -2
  242. package/dist/storage/domains/audit/agent-audit.js +1 -2
  243. package/dist/storage/domains/audit/base.js +1 -2
  244. package/dist/storage/domains/audit/domain.js +1 -2
  245. package/dist/storage/domains/audit/wire.js +1 -2
  246. package/dist/storage/domains/channel-identity/base.js +1 -2
  247. package/dist/storage/domains/comments/activity.js +1 -2
  248. package/dist/storage/domains/comments/actor.js +1 -2
  249. package/dist/storage/domains/comments/base.js +1 -2
  250. package/dist/storage/domains/comments/domain.js +1 -2
  251. package/dist/storage/domains/comments/feed-context.js +1 -2
  252. package/dist/storage/domains/comments/parse.js +1 -2
  253. package/dist/storage/domains/comments/routes.js +1 -2
  254. package/dist/storage/domains/comments/schema.js +1 -2
  255. package/dist/storage/domains/comments/wire.js +1 -2
  256. package/dist/storage/domains/credentials/base.d.ts +4 -1
  257. package/dist/storage/domains/credentials/base.d.ts.map +1 -1
  258. package/dist/storage/domains/credentials/base.js +40 -44
  259. package/dist/storage/domains/credentials/base.js.map +1 -1
  260. package/dist/storage/domains/custom-providers/base.js +1 -2
  261. package/dist/storage/domains/filesystem/base.js +1 -2
  262. package/dist/storage/domains/intake/base.js +1 -2
  263. package/dist/storage/domains/integrations/base.js +1 -2
  264. package/dist/storage/domains/memory-settings/base.js +1 -2
  265. package/dist/storage/domains/model-defaults/base.js +1 -2
  266. package/dist/storage/domains/projects/base.js +1 -2
  267. package/dist/storage/domains/queue-health/base.js +1 -2
  268. package/dist/storage/domains/source-control/base.js +1 -2
  269. package/dist/storage/domains/source-control/inmemory.js +1 -2
  270. package/dist/storage/domains/work-items/base.js +1 -2
  271. package/dist/storage/domains/work-items/board-version.js +1 -2
  272. package/dist/storage/domains/work-items/metrics.js +1 -2
  273. package/dist/telemetry-types.js +1 -2
  274. package/dist/telemetry.js +1 -2
  275. package/dist/timing.js +1 -2
  276. package/dist/tools/annotations.js +1 -2
  277. package/dist/tools/approval-tools.js +1 -2
  278. package/dist/tools/deliver.js +2 -3
  279. package/dist/tools/index.js +1 -2
  280. package/dist/tools/messaging-tools.js +1 -2
  281. package/dist/tools/permissions.js +1 -2
  282. package/dist/tools/read-tools.js +1 -2
  283. package/dist/tools/reports.js +1 -2
  284. package/dist/tools/run-watch.js +1 -2
  285. package/dist/tools/sandbox-tools.js +1 -2
  286. package/dist/tools/scope.js +2 -3
  287. package/dist/tools/session-tools.js +1 -2
  288. package/dist/tools/sessions-state-processor.js +1 -2
  289. package/dist/tools/side-sessions.js +1 -2
  290. package/dist/tools/work-item-tools.js +1 -2
  291. package/dist/work-item-branch.js +1 -2
  292. package/dist/work-item-branch.js.map +1 -1
  293. package/dist/work-items/create-work-item.js +1 -2
  294. package/dist/work-items/decision-actions.js +1 -2
  295. package/dist/workspace.d.ts.map +1 -1
  296. package/dist/workspace.js +1 -3
  297. package/dist/workspace.js.map +1 -1
  298. package/factory-skills/factory-rereview/SKILL.md +12 -2
  299. package/factory-skills/factory-review/SKILL.md +12 -2
  300. package/factory-skills/factory-triage/SKILL.md +7 -7
  301. package/package.json +19 -17
@@ -1,4 +1,4 @@
1
- //#region src/storage/domains/comments/actor.ts
1
+ // src/storage/domains/comments/actor.ts
2
2
  function isMentionableActorId(id) {
3
3
  return id.length > 0 && !id.includes(":");
4
4
  }
@@ -32,7 +32,6 @@ function actorFromChannelAuthor(external, link) {
32
32
  external
33
33
  };
34
34
  }
35
- //#endregion
36
35
  export { actorFromAgentBinding, actorFromAuthUser, actorFromChannelAuthor, isMentionableActorId };
37
36
 
38
37
  //# sourceMappingURL=actor.js.map
@@ -3,7 +3,7 @@ import { FACTORY_BOARD_VERSIONS_SCHEMA, bumpBoardVersions, trackBoardWrites } fr
3
3
  import { externalSourceKey } from "../work-items/base.js";
4
4
  import { fanOutWorkItemActivity, listActivityForUser } from "./activity.js";
5
5
  import { FactoryStorageDomain, UniqueViolationError } from "@mastra/core/storage";
6
- //#region src/storage/domains/comments/base.ts
6
+ // src/storage/domains/comments/base.ts
7
7
  /**
8
8
  * Work-item comments domain — one message list per work item, materialized
9
9
  * from every source. Local creates and platform mirrors (Slack, Linear,
@@ -527,7 +527,6 @@ var WorkItemCommentsStorage = class extends FactoryStorageDomain {
527
527
  }
528
528
  }
529
529
  };
530
- //#endregion
531
530
  export { CommentTokenConflictError, MAX_COMMENT_BODY_LENGTH, MAX_COMMENT_MENTIONS, MAX_COMMENT_QUOTE_LENGTH, WORK_ITEM_ACTIVITY_SCHEMA, WORK_ITEM_COMMENTS_SCHEMA, WORK_ITEM_COMMENT_MENTIONS_SCHEMA, WorkItemCommentsStorage, clampCommentLimit, commentBodyError, commentSourceKey, decodeCommentCursor, encodeCommentCursor, supersedesFeedActivity };
532
531
 
533
532
  //# sourceMappingURL=base.js.map
@@ -4,7 +4,7 @@ import { factoryMentionAttentionIdentity } from "../work-items/base.js";
4
4
  import { CommentTokenConflictError, commentBodyError } from "./base.js";
5
5
  import { toWireComment } from "./wire.js";
6
6
  import { buildCommentRoutes } from "./routes.js";
7
- //#region src/storage/domains/comments/domain.ts
7
+ // src/storage/domains/comments/domain.ts
8
8
  const MAX_ROSTER_SIZE = 100;
9
9
  const ROSTER_CACHE_TTL_MS = 6e4;
10
10
  var CommentsDomain = class {
@@ -279,7 +279,6 @@ var CommentsDomain = class {
279
279
  });
280
280
  }
281
281
  };
282
- //#endregion
283
282
  export { CommentsDomain, toWireComment };
284
283
 
285
284
  //# sourceMappingURL=domain.js.map
@@ -1,4 +1,4 @@
1
- //#region src/storage/domains/comments/feed-context.ts
1
+ // src/storage/domains/comments/feed-context.ts
2
2
  /** The one block that may trail a skill envelope in a kickoff; both transcript renderers allow only it. */
3
3
  const WORK_ITEM_FEED_TAG = "work-item-feed";
4
4
  const MAX_FEED_COMMENTS = 20;
@@ -83,7 +83,6 @@ async function withWorkItemFeed(reader, scope, message) {
83
83
  workItemId
84
84
  }));
85
85
  }
86
- //#endregion
87
86
  export { FactoryFeedReader, WORK_ITEM_FEED_TAG, withFeedContext, withWorkItemFeed };
88
87
 
89
88
  //# sourceMappingURL=feed-context.js.map
@@ -1,6 +1,6 @@
1
1
  import { isMentionableActorId } from "./actor.js";
2
2
  import { commentBodyError } from "./base.js";
3
- //#region src/storage/domains/comments/parse.ts
3
+ // src/storage/domains/comments/parse.ts
4
4
  const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
5
5
  const CLIENT_TOKEN_RE = /^[A-Za-z0-9-]{8,64}$/;
6
6
  function isRecord(value) {
@@ -84,7 +84,6 @@ function parseEditCommentBody(raw) {
84
84
  ...expectedRevision !== void 0 ? { expectedRevision } : {}
85
85
  };
86
86
  }
87
- //#endregion
88
87
  export { UUID_RE, isRecord, parseCreateCommentBody, parseEditCommentBody, readJson };
89
88
 
90
89
  //# sourceMappingURL=parse.js.map
@@ -7,7 +7,7 @@ import { toWireComment } from "./wire.js";
7
7
  import { registerApiRoute } from "@mastra/core/server";
8
8
  import { withAck } from "@mastra/core/events";
9
9
  import { streamSSE } from "hono/streaming";
10
- //#region src/storage/domains/comments/routes.ts
10
+ // src/storage/domains/comments/routes.ts
11
11
  /**
12
12
  * HTTP for the item feed. Every handler is the same shape: resolve the tenant,
13
13
  * validate the path ids, delegate to a `CommentsDomain` service method, map its
@@ -296,7 +296,6 @@ function buildCommentRoutes(dependencies) {
296
296
  })
297
297
  ];
298
298
  }
299
- //#endregion
300
299
  export { buildCommentRoutes };
301
300
 
302
301
  //# sourceMappingURL=routes.js.map
@@ -1,4 +1,4 @@
1
- //#region src/storage/domains/comments/schema.ts
1
+ // src/storage/domains/comments/schema.ts
2
2
  const WORK_ITEM_COMMENTS_SCHEMA = {
3
3
  name: "work_item_comments",
4
4
  columns: {
@@ -173,7 +173,6 @@ const WORK_ITEM_ACTIVITY_SCHEMA = {
173
173
  ]
174
174
  }]
175
175
  };
176
- //#endregion
177
176
  export { WORK_ITEM_ACTIVITY_SCHEMA, WORK_ITEM_COMMENTS_SCHEMA, WORK_ITEM_COMMENT_MENTIONS_SCHEMA };
178
177
 
179
178
  //# sourceMappingURL=schema.js.map
@@ -1,4 +1,4 @@
1
- //#region src/storage/domains/comments/wire.ts
1
+ // src/storage/domains/comments/wire.ts
2
2
  const LOCAL_SOURCE_KEY_PREFIX = "local:comment:";
3
3
  function toWireAuthor({ kind, id, displayName, avatarUrl }) {
4
4
  return {
@@ -31,7 +31,6 @@ function toWireComment(comment, viewerId) {
31
31
  ...comment.deletedAt ? { deletedAt: comment.deletedAt.toISOString() } : {}
32
32
  };
33
33
  }
34
- //#endregion
35
34
  export { toWireComment };
36
35
 
37
36
  //# sourceMappingURL=wire.js.map
@@ -39,6 +39,8 @@ export interface CredentialRecord {
39
39
  scope: CredentialScope;
40
40
  credential: AuthCredential;
41
41
  updatedAt: Date;
42
+ /** When the last OAuth token refresh failed; cleared by the next successful refresh or a new sign-in. */
43
+ refreshFailedAt?: Date;
42
44
  }
43
45
  /** Result of per-caller resolution: the winning credential and its scope. */
44
46
  export interface ResolvedCredential {
@@ -109,7 +111,8 @@ export declare class ModelCredentialsStorage extends FactoryStorageDomain {
109
111
  * rotating refresh tokens. The expiry is re-checked under the lock —
110
112
  * another replica may have refreshed already, in which case `refreshFn` is
111
113
  * skipped and the fresh credential is returned. Returns `undefined` when no
112
- * OAuth row exists for the tenant.
114
+ * OAuth row exists for the tenant. A failed `refreshFn` is recorded on the
115
+ * row (surfaced as `CredentialRecord.refreshFailedAt`) and rethrown.
113
116
  */
114
117
  refreshOAuth(tenant: CredentialTenant, provider: string, refreshFn: (current: OAuthCredential) => Promise<OAuthCredential>): Promise<OAuthCredential | undefined>;
115
118
  /** Persist a pending login flow started by a web route. */
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../src/storage/domains/credentials/base.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../src/storage/domains/credentials/base.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { createPlaintextFactorySecretEncryption } from "../../../secret-encryption.js";
2
2
  import { FactoryStorageDomain, UniqueViolationError } from "@mastra/core/storage";
3
- //#region src/storage/domains/credentials/base.ts
3
+ // src/storage/domains/credentials/base.ts
4
4
  /** Mirror of `AuthStorage.getApiKey()`'s expiry check. */
5
5
  function isOAuthCredentialExpired(credential, now = Date.now()) {
6
6
  return now >= credential.expires;
@@ -18,7 +18,11 @@ const MODEL_CREDENTIALS_SCHEMA = {
18
18
  type: { type: "text" },
19
19
  data: { type: "json" },
20
20
  created_at: { type: "timestamp" },
21
- updated_at: { type: "timestamp" }
21
+ updated_at: { type: "timestamp" },
22
+ refresh_failed_at: {
23
+ type: "timestamp",
24
+ nullable: true
25
+ }
22
26
  },
23
27
  uniqueIndexes: [{
24
28
  name: "model_provider_credentials_user_unique",
@@ -107,6 +111,15 @@ var ModelCredentialsStorage = class extends FactoryStorageDomain {
107
111
  async #decryptCredential(value) {
108
112
  return (await this.encryption.decrypt(value)).value;
109
113
  }
114
+ async #toRecord(row, scope) {
115
+ return {
116
+ provider: row.provider,
117
+ scope,
118
+ credential: await this.#decryptCredential(row.data),
119
+ updatedAt: row.updated_at,
120
+ refreshFailedAt: row.refresh_failed_at ?? void 0
121
+ };
122
+ }
110
123
  async #migrateCredential(id) {
111
124
  await this.#db.updateAtomic("model_provider_credentials", { id }, async (row) => {
112
125
  const decrypted = await this.encryption.decrypt(row.data);
@@ -126,7 +139,8 @@ var ModelCredentialsStorage = class extends FactoryStorageDomain {
126
139
  const update = async () => this.#db.updateMany("model_provider_credentials", where, {
127
140
  type: credential.type,
128
141
  data: encrypted,
129
- updated_at: /* @__PURE__ */ new Date()
142
+ updated_at: /* @__PURE__ */ new Date(),
143
+ refresh_failed_at: null
130
144
  });
131
145
  let lastError;
132
146
  for (let attempt = 0; attempt < 2; attempt++) {
@@ -163,45 +177,20 @@ var ModelCredentialsStorage = class extends FactoryStorageDomain {
163
177
  org_id: orgId,
164
178
  user_id: null
165
179
  })]);
166
- return Promise.all([...userRows.map(async (row) => ({
167
- provider: row.provider,
168
- scope: "user",
169
- credential: await this.#decryptCredential(row.data),
170
- updatedAt: row.updated_at
171
- })), ...orgRows.map(async (row) => ({
172
- provider: row.provider,
173
- scope: "org",
174
- credential: await this.#decryptCredential(row.data),
175
- updatedAt: row.updated_at
176
- }))]);
180
+ return Promise.all([...userRows.map((row) => this.#toRecord(row, "user")), ...orgRows.map((row) => this.#toRecord(row, "org"))]);
177
181
  }
178
182
  /** Resolve a provider credential from exactly one tenancy scope. */
179
183
  async resolveCredential(orgId, userId, provider, scope) {
180
- const readUser = async () => {
181
- const row = await this.#db.findOne("model_provider_credentials", {
182
- org_id: orgId,
183
- provider,
184
- user_id: userId
185
- });
186
- return row ? {
187
- provider: row.provider,
188
- scope: "user",
189
- credential: await this.#decryptCredential(row.data)
190
- } : void 0;
184
+ const tenant = scope === "org" ? { orgId } : {
185
+ orgId,
186
+ userId
191
187
  };
192
- const readOrg = async () => {
193
- const row = await this.#db.findOne("model_provider_credentials", {
194
- org_id: orgId,
195
- provider,
196
- user_id: null
197
- });
198
- return row ? {
199
- provider: row.provider,
200
- scope: "org",
201
- credential: await this.#decryptCredential(row.data)
202
- } : void 0;
203
- };
204
- return scope === "org" ? readOrg() : readUser();
188
+ const row = await this.#db.findOne("model_provider_credentials", tenantWhere(tenant, provider));
189
+ return row ? {
190
+ provider: row.provider,
191
+ scope,
192
+ credential: await this.#decryptCredential(row.data)
193
+ } : void 0;
205
194
  }
206
195
  /**
207
196
  * Refresh the tenant's OAuth credential under the backend's atomic
@@ -209,10 +198,12 @@ var ModelCredentialsStorage = class extends FactoryStorageDomain {
209
198
  * rotating refresh tokens. The expiry is re-checked under the lock —
210
199
  * another replica may have refreshed already, in which case `refreshFn` is
211
200
  * skipped and the fresh credential is returned. Returns `undefined` when no
212
- * OAuth row exists for the tenant.
201
+ * OAuth row exists for the tenant. A failed `refreshFn` is recorded on the
202
+ * row (surfaced as `CredentialRecord.refreshFailedAt`) and rethrown.
213
203
  */
214
204
  async refreshOAuth(tenant, provider, refreshFn) {
215
205
  let result;
206
+ let failure;
216
207
  await this.#db.updateAtomic("model_provider_credentials", tenantWhere(tenant, provider), async (row) => {
217
208
  const decrypted = await this.encryption.decrypt(row.data);
218
209
  if (decrypted.value.type !== "oauth") return null;
@@ -221,13 +212,19 @@ var ModelCredentialsStorage = class extends FactoryStorageDomain {
221
212
  result = current;
222
213
  return decrypted.needsReencryption ? { data: await this.encryption.encrypt(current) } : null;
223
214
  }
224
- const next = await refreshFn(current);
225
- result = next;
215
+ try {
216
+ result = await refreshFn(current);
217
+ } catch (error) {
218
+ failure = { error };
219
+ return { refresh_failed_at: /* @__PURE__ */ new Date() };
220
+ }
226
221
  return {
227
- data: await this.encryption.encrypt(next),
228
- updated_at: /* @__PURE__ */ new Date()
222
+ data: await this.encryption.encrypt(result),
223
+ updated_at: /* @__PURE__ */ new Date(),
224
+ refresh_failed_at: null
229
225
  };
230
226
  });
227
+ if (failure) throw failure.error;
231
228
  return result;
232
229
  }
233
230
  /** Persist a pending login flow started by a web route. */
@@ -288,7 +285,6 @@ var ModelCredentialsStorage = class extends FactoryStorageDomain {
288
285
  await this.#db.deleteMany("oauth_login_sessions", { session_id: sessionId });
289
286
  }
290
287
  };
291
- //#endregion
292
288
  export { MODEL_CREDENTIALS_SCHEMA, ModelCredentialsStorage, OAUTH_LOGIN_SESSIONS_SCHEMA, isOAuthCredentialExpired };
293
289
 
294
290
  //# sourceMappingURL=base.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"base.js","names":[],"sources":["../../../../src/storage/domains/credentials/base.ts"],"sourcesContent":["/**\n * Model provider credentials domain — tenant-scoped OAuth tokens and API keys\n * for model providers (Anthropic/Claude Max, OpenAI Codex, GitHub Copilot,\n * xAI, plus plain API-key providers).\n *\n * Tenancy is two-level:\n * - **user-scoped** rows (`userId` present): personal plan OAuth tokens and\n * personal API keys. OAuth plan tokens are ONLY ever user-scoped — they are\n * personal subscriptions, and sharing one would bill/rate-limit a single\n * account for the whole org.\n * - **org-scoped** rows (`userId` absent): shared API keys set by an org\n * admin, inherited by every member.\n *\n * Model calls resolve exactly one scope: user or org. Deployed tenant stores\n * never fall back to the other scope or implicitly borrow server environment keys.\n *\n * Secrets posture: credentials are stored server-side only and never returned\n * to the client (same as `linear_connections.access_token`). Encryption at\n * rest is out of scope, matching the existing posture.\n *\n * The domain also owns `oauth_login_sessions`: pending web login flows\n * (paste-code PKCE verifiers, device-code poll state) persisted server-side so\n * any replica can complete or poll a flow started on another.\n */\n\nimport type { AuthCredential, OAuthCredential } from '@mastra/code-sdk/auth/types';\nimport { FactoryStorageDomain, UniqueViolationError } from '@mastra/core/storage';\nimport type { CollectionSchema, CollectionWhere, FactoryStorageOps } from '@mastra/core/storage';\nimport { createPlaintextFactorySecretEncryption } from '../../../secret-encryption.js';\nimport type { FactorySecretEncryption } from '../../../secret-encryption.js';\n\n/** Owning tenant of a credential row. `userId` absent = org-scoped row. */\nexport interface CredentialTenant {\n orgId: string;\n userId?: string;\n}\n\n/** Which tenancy level a credential row lives at. */\nexport type CredentialScope = 'user' | 'org';\n\n/** One stored credential, annotated with its scope. */\nexport interface CredentialRecord {\n provider: string;\n scope: CredentialScope;\n credential: AuthCredential;\n updatedAt: Date;\n}\n\n/** Result of per-caller resolution: the winning credential and its scope. */\nexport interface ResolvedCredential {\n provider: string;\n scope: CredentialScope;\n credential: AuthCredential;\n}\n\n/** Kind of pending web login flow a session row tracks. */\nexport type LoginSessionKind = 'paste-code' | 'device-code';\n\n/** Scope the completed credential should be written to. */\nexport type LoginCredentialScope = 'user' | 'org';\n\n/** One pending OAuth login flow, persisted so any replica can continue it. */\nexport interface LoginSessionRow {\n sessionId: string;\n orgId: string;\n userId: string;\n provider: string;\n kind: LoginSessionKind;\n /** Where the completed credential lands; absent rows default to `'user'`. */\n credentialScope?: LoginCredentialScope;\n /** Serialized flow state (PKCE verifier, device-code pending state, ...). */\n pending: Record<string, unknown>;\n expiresAt: Date;\n /** Earliest time the next upstream poll is allowed (device-code flows). */\n nextPollAt: Date | null;\n createdAt: Date;\n}\n\nexport interface CreateLoginSessionInput {\n sessionId: string;\n orgId: string;\n userId: string;\n provider: string;\n kind: LoginSessionKind;\n credentialScope?: LoginCredentialScope;\n pending: Record<string, unknown>;\n expiresAt: Date;\n nextPollAt?: Date | null;\n}\n\n/** Mirror of `AuthStorage.getApiKey()`'s expiry check. */\nexport function isOAuthCredentialExpired(credential: OAuthCredential, now = Date.now()): boolean {\n return now >= credential.expires;\n}\n\nexport const MODEL_CREDENTIALS_SCHEMA: CollectionSchema = {\n name: 'model_provider_credentials',\n columns: {\n id: { type: 'uuid-pk' },\n org_id: { type: 'text' },\n user_id: { type: 'text', nullable: true },\n provider: { type: 'text' },\n type: { type: 'text' },\n data: { type: 'json' },\n created_at: { type: 'timestamp' },\n updated_at: { type: 'timestamp' },\n },\n uniqueIndexes: [\n // Scope is encoded in `user_id` nullability (NULL = org-scoped shared\n // row), enforced by two partial unique indexes.\n {\n name: 'model_provider_credentials_user_unique',\n columns: ['org_id', 'user_id', 'provider'],\n whereNotNull: 'user_id',\n },\n { name: 'model_provider_credentials_org_unique', columns: ['org_id', 'provider'], whereNull: 'user_id' },\n ],\n};\n\nexport const OAUTH_LOGIN_SESSIONS_SCHEMA: CollectionSchema = {\n name: 'oauth_login_sessions',\n columns: {\n session_id: { type: 'text', primaryKey: true },\n org_id: { type: 'text' },\n user_id: { type: 'text' },\n provider: { type: 'text' },\n kind: { type: 'text' },\n credential_scope: { type: 'text', nullable: true },\n pending: { type: 'json' },\n expires_at: { type: 'timestamp' },\n next_poll_at: { type: 'timestamp', nullable: true },\n created_at: { type: 'timestamp' },\n },\n};\n\n/** Column shape of one `model_provider_credentials` row as returned by ops. */\ninterface CredentialDbRow extends Record<string, unknown> {\n id: string;\n provider: string;\n user_id: string | null;\n data: unknown;\n updated_at: Date;\n}\n\n/** Column shape of one `oauth_login_sessions` row as returned by ops. */\ninterface LoginSessionDbRow extends Record<string, unknown> {\n session_id: string;\n org_id: string;\n user_id: string;\n provider: string;\n kind: LoginSessionKind;\n credential_scope: LoginCredentialScope | null;\n pending: Record<string, unknown>;\n expires_at: Date;\n next_poll_at: Date | null;\n created_at: Date;\n}\n\nfunction toSessionRow(db: LoginSessionDbRow): LoginSessionRow {\n return {\n sessionId: db.session_id,\n orgId: db.org_id,\n userId: db.user_id,\n provider: db.provider,\n kind: db.kind,\n ...(db.credential_scope ? { credentialScope: db.credential_scope } : {}),\n pending: db.pending,\n expiresAt: db.expires_at,\n nextPollAt: db.next_poll_at,\n createdAt: db.created_at,\n };\n}\n\n/** Filter selecting exactly the tenant's row for a provider (`null` = org row). */\nfunction tenantWhere(tenant: CredentialTenant, provider: string): CollectionWhere {\n return { org_id: tenant.orgId, provider, user_id: tenant.userId ?? null };\n}\n\n/**\n * Model-credentials storage, written once against the generic\n * `FactoryStorageOps` surface. `refreshOAuth()` and `claimLoginSession()`\n * ride `updateAtomic` so concurrent replicas serialize instead of\n * invalidating each other's rotating tokens / double-claiming a flow.\n */\nexport class ModelCredentialsStorage extends FactoryStorageDomain {\n constructor(private readonly encryption: FactorySecretEncryption = createPlaintextFactorySecretEncryption()) {\n super('model-credentials');\n }\n\n async init(): Promise<void> {\n await this.ensureCollections([MODEL_CREDENTIALS_SCHEMA, OAUTH_LOGIN_SESSIONS_SCHEMA]);\n const rows = await this.ops.findMany<CredentialDbRow>('model_provider_credentials', {});\n await Promise.all(rows.map(row => this.#migrateCredential(row.id)));\n }\n\n async dangerouslyClearAll(): Promise<void> {\n await this.ops.deleteMany('oauth_login_sessions', {});\n await this.ops.deleteMany('model_provider_credentials', {});\n }\n\n get #db(): FactoryStorageOps {\n return this.ops;\n }\n\n async #decryptCredential(value: unknown): Promise<AuthCredential> {\n return (await this.encryption.decrypt<AuthCredential>(value)).value;\n }\n\n async #migrateCredential(id: string): Promise<void> {\n await this.#db.updateAtomic<CredentialDbRow>('model_provider_credentials', { id }, async row => {\n const decrypted = await this.encryption.decrypt<AuthCredential>(row.data);\n if (!decrypted.needsReencryption) return null;\n return { data: await this.encryption.encrypt(decrypted.value) };\n });\n }\n\n /** Read the tenant's credential for a provider at exactly that scope. */\n async getCredential(tenant: CredentialTenant, provider: string): Promise<AuthCredential | undefined> {\n const row = await this.#db.findOne<CredentialDbRow>('model_provider_credentials', tenantWhere(tenant, provider));\n return row ? this.#decryptCredential(row.data) : undefined;\n }\n\n /** Upsert the tenant's credential (`created_at` is preserved on update). */\n async setCredential(tenant: CredentialTenant, provider: string, credential: AuthCredential): Promise<void> {\n const where = tenantWhere(tenant, provider);\n const encrypted = await this.encryption.encrypt(credential);\n const update = async () =>\n this.#db.updateMany('model_provider_credentials', where, {\n type: credential.type,\n data: encrypted,\n updated_at: new Date(),\n });\n\n let lastError: unknown;\n for (let attempt = 0; attempt < 2; attempt++) {\n if ((await update()) > 0) return;\n\n const now = new Date();\n try {\n await this.#db.insertOne<CredentialDbRow>('model_provider_credentials', {\n org_id: tenant.orgId,\n user_id: tenant.userId ?? null,\n provider,\n type: credential.type,\n data: encrypted,\n created_at: now,\n updated_at: now,\n });\n return;\n } catch (error) {\n if (!(error instanceof UniqueViolationError)) throw error;\n lastError = error;\n }\n }\n throw lastError;\n }\n\n /** Delete the tenant's credential at exactly that scope. True when a row was removed. */\n async removeCredential(tenant: CredentialTenant, provider: string): Promise<boolean> {\n const deleted = await this.#db.deleteMany('model_provider_credentials', tenantWhere(tenant, provider));\n return deleted > 0;\n }\n\n /** All credentials visible to a user: their own rows plus the org's shared rows. */\n async listCredentials(orgId: string, userId: string): Promise<CredentialRecord[]> {\n // SQL `IN` never matches NULL, so the org rows need their own query.\n const [userRows, orgRows] = await Promise.all([\n this.#db.findMany<CredentialDbRow>('model_provider_credentials', { org_id: orgId, user_id: userId }),\n this.#db.findMany<CredentialDbRow>('model_provider_credentials', { org_id: orgId, user_id: null }),\n ]);\n return Promise.all([\n ...userRows.map(async row => ({\n provider: row.provider,\n scope: 'user' as const,\n credential: await this.#decryptCredential(row.data),\n updatedAt: row.updated_at,\n })),\n ...orgRows.map(async row => ({\n provider: row.provider,\n scope: 'org' as const,\n credential: await this.#decryptCredential(row.data),\n updatedAt: row.updated_at,\n })),\n ]);\n }\n\n /** Resolve a provider credential from exactly one tenancy scope. */\n async resolveCredential(\n orgId: string,\n userId: string,\n provider: string,\n scope: CredentialScope,\n ): Promise<ResolvedCredential | undefined> {\n const readUser = async (): Promise<ResolvedCredential | undefined> => {\n const row = await this.#db.findOne<CredentialDbRow>('model_provider_credentials', {\n org_id: orgId,\n provider,\n user_id: userId,\n });\n return row\n ? { provider: row.provider, scope: 'user', credential: await this.#decryptCredential(row.data) }\n : undefined;\n };\n const readOrg = async (): Promise<ResolvedCredential | undefined> => {\n const row = await this.#db.findOne<CredentialDbRow>('model_provider_credentials', {\n org_id: orgId,\n provider,\n user_id: null,\n });\n return row\n ? { provider: row.provider, scope: 'org', credential: await this.#decryptCredential(row.data) }\n : undefined;\n };\n return scope === 'org' ? readOrg() : readUser();\n }\n\n /**\n * Refresh the tenant's OAuth credential under the backend's atomic\n * read-modify-write so concurrent replicas don't invalidate each other's\n * rotating refresh tokens. The expiry is re-checked under the lock —\n * another replica may have refreshed already, in which case `refreshFn` is\n * skipped and the fresh credential is returned. Returns `undefined` when no\n * OAuth row exists for the tenant.\n */\n async refreshOAuth(\n tenant: CredentialTenant,\n provider: string,\n refreshFn: (current: OAuthCredential) => Promise<OAuthCredential>,\n ): Promise<OAuthCredential | undefined> {\n let result: OAuthCredential | undefined;\n await this.#db.updateAtomic<CredentialDbRow>(\n 'model_provider_credentials',\n tenantWhere(tenant, provider),\n async row => {\n const decrypted = await this.encryption.decrypt<AuthCredential>(row.data);\n if (decrypted.value.type !== 'oauth') return null;\n const current = decrypted.value;\n // Re-check under the lock: another replica may have refreshed while we waited.\n if (!isOAuthCredentialExpired(current)) {\n result = current;\n return decrypted.needsReencryption ? { data: await this.encryption.encrypt(current) } : null;\n }\n const next = await refreshFn(current);\n result = next;\n return { data: await this.encryption.encrypt(next), updated_at: new Date() };\n },\n );\n return result;\n }\n\n /** Persist a pending login flow started by a web route. */\n async createLoginSession(input: CreateLoginSessionInput): Promise<LoginSessionRow> {\n const inserted = await this.#db.insertOne<LoginSessionDbRow>('oauth_login_sessions', {\n session_id: input.sessionId,\n org_id: input.orgId,\n user_id: input.userId,\n provider: input.provider,\n kind: input.kind,\n credential_scope: input.credentialScope ?? null,\n pending: input.pending,\n expires_at: input.expiresAt,\n next_poll_at: input.nextPollAt ?? null,\n created_at: new Date(),\n });\n return toSessionRow(inserted);\n }\n\n /**\n * Read a pending login flow. An expired session is deleted on read (TTL\n * cleanup) and reported as absent.\n */\n async getLoginSession(sessionId: string): Promise<LoginSessionRow | undefined> {\n const row = await this.#db.findOne<LoginSessionDbRow>('oauth_login_sessions', { session_id: sessionId });\n if (!row) return undefined;\n if (row.expires_at.getTime() <= Date.now()) {\n await this.#db.deleteMany('oauth_login_sessions', { session_id: sessionId });\n return undefined;\n }\n return toSessionRow(row);\n }\n\n /**\n * Atomically claim a due login session for one upstream completion/poll attempt.\n * Returns undefined when the session is missing, expired, owned by another\n * tenant/provider, or already claimed by a concurrent request.\n */\n async claimLoginSession(\n sessionId: string,\n owner: Pick<LoginSessionRow, 'orgId' | 'userId' | 'provider' | 'kind'>,\n ): Promise<LoginSessionRow | undefined> {\n const now = Date.now();\n let claimed = false;\n const updated = await this.#db.updateAtomic<LoginSessionDbRow>(\n 'oauth_login_sessions',\n { session_id: sessionId },\n row => {\n if (\n row.org_id !== owner.orgId ||\n row.user_id !== owner.userId ||\n row.provider !== owner.provider ||\n row.kind !== owner.kind\n ) {\n return null;\n }\n if (row.expires_at.getTime() <= now) return null;\n if (row.next_poll_at && row.next_poll_at.getTime() > now) return null;\n claimed = true;\n // Park the next poll at expiry so a concurrent claim loses until the\n // claimer either touches the session forward or deletes it.\n return { next_poll_at: row.expires_at };\n },\n );\n return claimed && updated ? toSessionRow(updated) : undefined;\n }\n\n /** Update a pending flow's serialized state and/or next allowed poll time. */\n async touchLoginSession(\n sessionId: string,\n updates: { pending?: Record<string, unknown>; nextPollAt?: Date | null },\n ): Promise<void> {\n const set: Record<string, unknown> = {};\n if (updates.pending !== undefined) set.pending = updates.pending;\n if (updates.nextPollAt !== undefined) set.next_poll_at = updates.nextPollAt;\n if (Object.keys(set).length === 0) return;\n await this.#db.updateMany('oauth_login_sessions', { session_id: sessionId }, set);\n }\n\n /** Remove a pending login flow (completed, cancelled, or failed). */\n async deleteLoginSession(sessionId: string): Promise<void> {\n await this.#db.deleteMany('oauth_login_sessions', { session_id: sessionId });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"base.js","names":[],"sources":["../../../../src/storage/domains/credentials/base.ts"],"sourcesContent":["/**\n * Model provider credentials domain — tenant-scoped OAuth tokens and API keys\n * for model providers (Anthropic/Claude Max, OpenAI Codex, GitHub Copilot,\n * xAI, plus plain API-key providers).\n *\n * Tenancy is two-level:\n * - **user-scoped** rows (`userId` present): personal plan OAuth tokens and\n * personal API keys. OAuth plan tokens are ONLY ever user-scoped — they are\n * personal subscriptions, and sharing one would bill/rate-limit a single\n * account for the whole org.\n * - **org-scoped** rows (`userId` absent): shared API keys set by an org\n * admin, inherited by every member.\n *\n * Model calls resolve exactly one scope: user or org. Deployed tenant stores\n * never fall back to the other scope or implicitly borrow server environment keys.\n *\n * Secrets posture: credentials are stored server-side only and never returned\n * to the client (same as `linear_connections.access_token`). Encryption at\n * rest is out of scope, matching the existing posture.\n *\n * The domain also owns `oauth_login_sessions`: pending web login flows\n * (paste-code PKCE verifiers, device-code poll state) persisted server-side so\n * any replica can complete or poll a flow started on another.\n */\n\nimport type { AuthCredential, OAuthCredential } from '@mastra/code-sdk/auth/types';\nimport { FactoryStorageDomain, UniqueViolationError } from '@mastra/core/storage';\nimport type { CollectionSchema, CollectionWhere, FactoryStorageOps } from '@mastra/core/storage';\nimport { createPlaintextFactorySecretEncryption } from '../../../secret-encryption.js';\nimport type { FactorySecretEncryption } from '../../../secret-encryption.js';\n\n/** Owning tenant of a credential row. `userId` absent = org-scoped row. */\nexport interface CredentialTenant {\n orgId: string;\n userId?: string;\n}\n\n/** Which tenancy level a credential row lives at. */\nexport type CredentialScope = 'user' | 'org';\n\n/** One stored credential, annotated with its scope. */\nexport interface CredentialRecord {\n provider: string;\n scope: CredentialScope;\n credential: AuthCredential;\n updatedAt: Date;\n /** When the last OAuth token refresh failed; cleared by the next successful refresh or a new sign-in. */\n refreshFailedAt?: Date;\n}\n\n/** Result of per-caller resolution: the winning credential and its scope. */\nexport interface ResolvedCredential {\n provider: string;\n scope: CredentialScope;\n credential: AuthCredential;\n}\n\n/** Kind of pending web login flow a session row tracks. */\nexport type LoginSessionKind = 'paste-code' | 'device-code';\n\n/** Scope the completed credential should be written to. */\nexport type LoginCredentialScope = 'user' | 'org';\n\n/** One pending OAuth login flow, persisted so any replica can continue it. */\nexport interface LoginSessionRow {\n sessionId: string;\n orgId: string;\n userId: string;\n provider: string;\n kind: LoginSessionKind;\n /** Where the completed credential lands; absent rows default to `'user'`. */\n credentialScope?: LoginCredentialScope;\n /** Serialized flow state (PKCE verifier, device-code pending state, ...). */\n pending: Record<string, unknown>;\n expiresAt: Date;\n /** Earliest time the next upstream poll is allowed (device-code flows). */\n nextPollAt: Date | null;\n createdAt: Date;\n}\n\nexport interface CreateLoginSessionInput {\n sessionId: string;\n orgId: string;\n userId: string;\n provider: string;\n kind: LoginSessionKind;\n credentialScope?: LoginCredentialScope;\n pending: Record<string, unknown>;\n expiresAt: Date;\n nextPollAt?: Date | null;\n}\n\n/** Mirror of `AuthStorage.getApiKey()`'s expiry check. */\nexport function isOAuthCredentialExpired(credential: OAuthCredential, now = Date.now()): boolean {\n return now >= credential.expires;\n}\n\nexport const MODEL_CREDENTIALS_SCHEMA: CollectionSchema = {\n name: 'model_provider_credentials',\n columns: {\n id: { type: 'uuid-pk' },\n org_id: { type: 'text' },\n user_id: { type: 'text', nullable: true },\n provider: { type: 'text' },\n type: { type: 'text' },\n data: { type: 'json' },\n created_at: { type: 'timestamp' },\n updated_at: { type: 'timestamp' },\n refresh_failed_at: { type: 'timestamp', nullable: true },\n },\n uniqueIndexes: [\n // Scope is encoded in `user_id` nullability (NULL = org-scoped shared\n // row), enforced by two partial unique indexes.\n {\n name: 'model_provider_credentials_user_unique',\n columns: ['org_id', 'user_id', 'provider'],\n whereNotNull: 'user_id',\n },\n { name: 'model_provider_credentials_org_unique', columns: ['org_id', 'provider'], whereNull: 'user_id' },\n ],\n};\n\nexport const OAUTH_LOGIN_SESSIONS_SCHEMA: CollectionSchema = {\n name: 'oauth_login_sessions',\n columns: {\n session_id: { type: 'text', primaryKey: true },\n org_id: { type: 'text' },\n user_id: { type: 'text' },\n provider: { type: 'text' },\n kind: { type: 'text' },\n credential_scope: { type: 'text', nullable: true },\n pending: { type: 'json' },\n expires_at: { type: 'timestamp' },\n next_poll_at: { type: 'timestamp', nullable: true },\n created_at: { type: 'timestamp' },\n },\n};\n\n/** Column shape of one `model_provider_credentials` row as returned by ops. */\ninterface CredentialDbRow extends Record<string, unknown> {\n id: string;\n provider: string;\n user_id: string | null;\n data: unknown;\n updated_at: Date;\n refresh_failed_at: Date | null;\n}\n\n/** Column shape of one `oauth_login_sessions` row as returned by ops. */\ninterface LoginSessionDbRow extends Record<string, unknown> {\n session_id: string;\n org_id: string;\n user_id: string;\n provider: string;\n kind: LoginSessionKind;\n credential_scope: LoginCredentialScope | null;\n pending: Record<string, unknown>;\n expires_at: Date;\n next_poll_at: Date | null;\n created_at: Date;\n}\n\nfunction toSessionRow(db: LoginSessionDbRow): LoginSessionRow {\n return {\n sessionId: db.session_id,\n orgId: db.org_id,\n userId: db.user_id,\n provider: db.provider,\n kind: db.kind,\n ...(db.credential_scope ? { credentialScope: db.credential_scope } : {}),\n pending: db.pending,\n expiresAt: db.expires_at,\n nextPollAt: db.next_poll_at,\n createdAt: db.created_at,\n };\n}\n\n/** Filter selecting exactly the tenant's row for a provider (`null` = org row). */\nfunction tenantWhere(tenant: CredentialTenant, provider: string): CollectionWhere {\n return { org_id: tenant.orgId, provider, user_id: tenant.userId ?? null };\n}\n\n/**\n * Model-credentials storage, written once against the generic\n * `FactoryStorageOps` surface. `refreshOAuth()` and `claimLoginSession()`\n * ride `updateAtomic` so concurrent replicas serialize instead of\n * invalidating each other's rotating tokens / double-claiming a flow.\n */\nexport class ModelCredentialsStorage extends FactoryStorageDomain {\n constructor(private readonly encryption: FactorySecretEncryption = createPlaintextFactorySecretEncryption()) {\n super('model-credentials');\n }\n\n async init(): Promise<void> {\n await this.ensureCollections([MODEL_CREDENTIALS_SCHEMA, OAUTH_LOGIN_SESSIONS_SCHEMA]);\n const rows = await this.ops.findMany<CredentialDbRow>('model_provider_credentials', {});\n await Promise.all(rows.map(row => this.#migrateCredential(row.id)));\n }\n\n async dangerouslyClearAll(): Promise<void> {\n await this.ops.deleteMany('oauth_login_sessions', {});\n await this.ops.deleteMany('model_provider_credentials', {});\n }\n\n get #db(): FactoryStorageOps {\n return this.ops;\n }\n\n async #decryptCredential(value: unknown): Promise<AuthCredential> {\n return (await this.encryption.decrypt<AuthCredential>(value)).value;\n }\n\n async #toRecord(row: CredentialDbRow, scope: CredentialScope): Promise<CredentialRecord> {\n return {\n provider: row.provider,\n scope,\n credential: await this.#decryptCredential(row.data),\n updatedAt: row.updated_at,\n refreshFailedAt: row.refresh_failed_at ?? undefined,\n };\n }\n\n async #migrateCredential(id: string): Promise<void> {\n await this.#db.updateAtomic<CredentialDbRow>('model_provider_credentials', { id }, async row => {\n const decrypted = await this.encryption.decrypt<AuthCredential>(row.data);\n if (!decrypted.needsReencryption) return null;\n return { data: await this.encryption.encrypt(decrypted.value) };\n });\n }\n\n /** Read the tenant's credential for a provider at exactly that scope. */\n async getCredential(tenant: CredentialTenant, provider: string): Promise<AuthCredential | undefined> {\n const row = await this.#db.findOne<CredentialDbRow>('model_provider_credentials', tenantWhere(tenant, provider));\n return row ? this.#decryptCredential(row.data) : undefined;\n }\n\n /** Upsert the tenant's credential (`created_at` is preserved on update). */\n async setCredential(tenant: CredentialTenant, provider: string, credential: AuthCredential): Promise<void> {\n const where = tenantWhere(tenant, provider);\n const encrypted = await this.encryption.encrypt(credential);\n const update = async () =>\n this.#db.updateMany('model_provider_credentials', where, {\n type: credential.type,\n data: encrypted,\n updated_at: new Date(),\n refresh_failed_at: null,\n });\n\n let lastError: unknown;\n for (let attempt = 0; attempt < 2; attempt++) {\n if ((await update()) > 0) return;\n\n const now = new Date();\n try {\n await this.#db.insertOne<CredentialDbRow>('model_provider_credentials', {\n org_id: tenant.orgId,\n user_id: tenant.userId ?? null,\n provider,\n type: credential.type,\n data: encrypted,\n created_at: now,\n updated_at: now,\n });\n return;\n } catch (error) {\n if (!(error instanceof UniqueViolationError)) throw error;\n lastError = error;\n }\n }\n throw lastError;\n }\n\n /** Delete the tenant's credential at exactly that scope. True when a row was removed. */\n async removeCredential(tenant: CredentialTenant, provider: string): Promise<boolean> {\n const deleted = await this.#db.deleteMany('model_provider_credentials', tenantWhere(tenant, provider));\n return deleted > 0;\n }\n\n /** All credentials visible to a user: their own rows plus the org's shared rows. */\n async listCredentials(orgId: string, userId: string): Promise<CredentialRecord[]> {\n // SQL `IN` never matches NULL, so the org rows need their own query.\n const [userRows, orgRows] = await Promise.all([\n this.#db.findMany<CredentialDbRow>('model_provider_credentials', { org_id: orgId, user_id: userId }),\n this.#db.findMany<CredentialDbRow>('model_provider_credentials', { org_id: orgId, user_id: null }),\n ]);\n return Promise.all([\n ...userRows.map(row => this.#toRecord(row, 'user')),\n ...orgRows.map(row => this.#toRecord(row, 'org')),\n ]);\n }\n\n /** Resolve a provider credential from exactly one tenancy scope. */\n async resolveCredential(\n orgId: string,\n userId: string,\n provider: string,\n scope: CredentialScope,\n ): Promise<ResolvedCredential | undefined> {\n const tenant = scope === 'org' ? { orgId } : { orgId, userId };\n const row = await this.#db.findOne<CredentialDbRow>('model_provider_credentials', tenantWhere(tenant, provider));\n return row ? { provider: row.provider, scope, credential: await this.#decryptCredential(row.data) } : undefined;\n }\n\n /**\n * Refresh the tenant's OAuth credential under the backend's atomic\n * read-modify-write so concurrent replicas don't invalidate each other's\n * rotating refresh tokens. The expiry is re-checked under the lock —\n * another replica may have refreshed already, in which case `refreshFn` is\n * skipped and the fresh credential is returned. Returns `undefined` when no\n * OAuth row exists for the tenant. A failed `refreshFn` is recorded on the\n * row (surfaced as `CredentialRecord.refreshFailedAt`) and rethrown.\n */\n async refreshOAuth(\n tenant: CredentialTenant,\n provider: string,\n refreshFn: (current: OAuthCredential) => Promise<OAuthCredential>,\n ): Promise<OAuthCredential | undefined> {\n let result: OAuthCredential | undefined;\n let failure: { error: unknown } | undefined;\n await this.#db.updateAtomic<CredentialDbRow>(\n 'model_provider_credentials',\n tenantWhere(tenant, provider),\n async row => {\n const decrypted = await this.encryption.decrypt<AuthCredential>(row.data);\n if (decrypted.value.type !== 'oauth') return null;\n const current = decrypted.value;\n // Re-check under the lock: another replica may have refreshed while we waited.\n if (!isOAuthCredentialExpired(current)) {\n result = current;\n return decrypted.needsReencryption ? { data: await this.encryption.encrypt(current) } : null;\n }\n try {\n result = await refreshFn(current);\n } catch (error) {\n failure = { error };\n return { refresh_failed_at: new Date() };\n }\n return { data: await this.encryption.encrypt(result), updated_at: new Date(), refresh_failed_at: null };\n },\n );\n if (failure) throw failure.error;\n return result;\n }\n\n /** Persist a pending login flow started by a web route. */\n async createLoginSession(input: CreateLoginSessionInput): Promise<LoginSessionRow> {\n const inserted = await this.#db.insertOne<LoginSessionDbRow>('oauth_login_sessions', {\n session_id: input.sessionId,\n org_id: input.orgId,\n user_id: input.userId,\n provider: input.provider,\n kind: input.kind,\n credential_scope: input.credentialScope ?? null,\n pending: input.pending,\n expires_at: input.expiresAt,\n next_poll_at: input.nextPollAt ?? null,\n created_at: new Date(),\n });\n return toSessionRow(inserted);\n }\n\n /**\n * Read a pending login flow. An expired session is deleted on read (TTL\n * cleanup) and reported as absent.\n */\n async getLoginSession(sessionId: string): Promise<LoginSessionRow | undefined> {\n const row = await this.#db.findOne<LoginSessionDbRow>('oauth_login_sessions', { session_id: sessionId });\n if (!row) return undefined;\n if (row.expires_at.getTime() <= Date.now()) {\n await this.#db.deleteMany('oauth_login_sessions', { session_id: sessionId });\n return undefined;\n }\n return toSessionRow(row);\n }\n\n /**\n * Atomically claim a due login session for one upstream completion/poll attempt.\n * Returns undefined when the session is missing, expired, owned by another\n * tenant/provider, or already claimed by a concurrent request.\n */\n async claimLoginSession(\n sessionId: string,\n owner: Pick<LoginSessionRow, 'orgId' | 'userId' | 'provider' | 'kind'>,\n ): Promise<LoginSessionRow | undefined> {\n const now = Date.now();\n let claimed = false;\n const updated = await this.#db.updateAtomic<LoginSessionDbRow>(\n 'oauth_login_sessions',\n { session_id: sessionId },\n row => {\n if (\n row.org_id !== owner.orgId ||\n row.user_id !== owner.userId ||\n row.provider !== owner.provider ||\n row.kind !== owner.kind\n ) {\n return null;\n }\n if (row.expires_at.getTime() <= now) return null;\n if (row.next_poll_at && row.next_poll_at.getTime() > now) return null;\n claimed = true;\n // Park the next poll at expiry so a concurrent claim loses until the\n // claimer either touches the session forward or deletes it.\n return { next_poll_at: row.expires_at };\n },\n );\n return claimed && updated ? toSessionRow(updated) : undefined;\n }\n\n /** Update a pending flow's serialized state and/or next allowed poll time. */\n async touchLoginSession(\n sessionId: string,\n updates: { pending?: Record<string, unknown>; nextPollAt?: Date | null },\n ): Promise<void> {\n const set: Record<string, unknown> = {};\n if (updates.pending !== undefined) set.pending = updates.pending;\n if (updates.nextPollAt !== undefined) set.next_poll_at = updates.nextPollAt;\n if (Object.keys(set).length === 0) return;\n await this.#db.updateMany('oauth_login_sessions', { session_id: sessionId }, set);\n }\n\n /** Remove a pending login flow (completed, cancelled, or failed). */\n async deleteLoginSession(sessionId: string): Promise<void> {\n await this.#db.deleteMany('oauth_login_sessions', { session_id: sessionId });\n }\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { createPlaintextFactorySecretEncryption } from "../../../secret-encryption.js";
2
2
  import { FactoryStorageDomain, UniqueViolationError } from "@mastra/core/storage";
3
- //#region src/storage/domains/custom-providers/base.ts
3
+ // src/storage/domains/custom-providers/base.ts
4
4
  const CUSTOM_PROVIDERS_SCHEMA = {
5
5
  name: "custom_providers",
6
6
  columns: {
@@ -170,7 +170,6 @@ var CustomProvidersStorage = class extends FactoryStorageDomain {
170
170
  }) > 0;
171
171
  }
172
172
  };
173
- //#endregion
174
173
  export { CUSTOM_PROVIDERS_SCHEMA, CustomProvidersStorage };
175
174
 
176
175
  //# sourceMappingURL=base.js.map
@@ -1,5 +1,5 @@
1
1
  import { FactoryStorageDomain } from "@mastra/core/storage";
2
- //#region src/storage/domains/filesystem/base.ts
2
+ // src/storage/domains/filesystem/base.ts
3
3
  const SNAPSHOTS = "filesystem_snapshots";
4
4
  const FILESYSTEM_SCHEMAS = [{
5
5
  name: SNAPSHOTS,
@@ -73,7 +73,6 @@ var FilesystemStorage = class extends FactoryStorageDomain {
73
73
  return this.ops.deleteMany(SNAPSHOTS, { resource_id: args.resourceId });
74
74
  }
75
75
  };
76
- //#endregion
77
76
  export { FILESYSTEM_SCHEMAS, FilesystemStorage };
78
77
 
79
78
  //# sourceMappingURL=base.js.map
@@ -1,5 +1,5 @@
1
1
  import { FactoryStorageDomain, UniqueViolationError } from "@mastra/core/storage";
2
- //#region src/storage/domains/intake/base.ts
2
+ // src/storage/domains/intake/base.ts
3
3
  /**
4
4
  * Org-wide intake selections for every configured intake integration.
5
5
  *
@@ -425,7 +425,6 @@ var IntakeStorage = class extends FactoryStorageDomain {
425
425
  }, { isolationLevel: "serializable" });
426
426
  }
427
427
  };
428
- //#endregion
429
428
  export { DEFAULT_INTAKE_CONFIG, INTAKE_LABEL_ROUTES_SCHEMA, INTAKE_ORG_SETTINGS_SCHEMA, INTAKE_SOURCE_BINDINGS_SCHEMA, IntakeStorage, LEGACY_INTAKE_USER_SETTINGS_SCHEMA, mergeIntakeSelections, normalizeIntakeLabel, resolveIntakeLabelRoute };
430
429
 
431
430
  //# sourceMappingURL=base.js.map
@@ -1,6 +1,6 @@
1
1
  import { createPlaintextFactorySecretEncryption } from "../../../secret-encryption.js";
2
2
  import { FactoryStorageDomain, UniqueViolationError } from "@mastra/core/storage";
3
- //#region src/storage/domains/integrations/base.ts
3
+ // src/storage/domains/integrations/base.ts
4
4
  /**
5
5
  * Generic integration storage — the default persistence surface for
6
6
  * `FactoryIntegration`s.
@@ -334,7 +334,6 @@ var IntegrationStorage = class extends FactoryStorageDomain {
334
334
  };
335
335
  }
336
336
  };
337
- //#endregion
338
337
  export { INTEGRATION_CONNECTIONS_SCHEMA, INTEGRATION_SETTINGS_SCHEMA, INTEGRATION_SUBSCRIPTIONS_SCHEMA, IntegrationStorage };
339
338
 
340
339
  //# sourceMappingURL=base.js.map
@@ -1,5 +1,5 @@
1
1
  import { FactoryStorageDomain, UniqueViolationError } from "@mastra/core/storage";
2
- //#region src/storage/domains/memory-settings/base.ts
2
+ // src/storage/domains/memory-settings/base.ts
3
3
  /**
4
4
  * Sentinel `user_id` for a factory project's shared memory settings. Factory
5
5
  * runs are org-shared, so their OM configuration lives on the project — this
@@ -123,7 +123,6 @@ var MemorySettingsStorage = class extends FactoryStorageDomain {
123
123
  }
124
124
  }
125
125
  };
126
- //#endregion
127
126
  export { MEMORY_SETTINGS_SCHEMA, MemorySettingsStorage, factoryMemorySettingsUserId };
128
127
 
129
128
  //# sourceMappingURL=base.js.map
@@ -1,6 +1,6 @@
1
1
  import { FactoryStorageDomain, UniqueViolationError } from "@mastra/core/storage";
2
2
  import { isThinkingLevelSetting } from "@mastra/code-sdk/thinking";
3
- //#region src/storage/domains/model-defaults/base.ts
3
+ // src/storage/domains/model-defaults/base.ts
4
4
  const USER_DEFAULT_MODELS_SCHEMA = {
5
5
  name: "user_default_models",
6
6
  columns: {
@@ -91,7 +91,6 @@ var ModelDefaultsStorage = class extends FactoryStorageDomain {
91
91
  }) > 0;
92
92
  }
93
93
  };
94
- //#endregion
95
94
  export { ModelDefaultsStorage, USER_DEFAULT_MODELS_SCHEMA };
96
95
 
97
96
  //# sourceMappingURL=base.js.map
@@ -1,6 +1,6 @@
1
1
  import { FactoryStorageDomain } from "@mastra/core/storage";
2
2
  import { isThinkingLevelSetting } from "@mastra/code-sdk/thinking";
3
- //#region src/storage/domains/projects/base.ts
3
+ // src/storage/domains/projects/base.ts
4
4
  const DEFAULT_BUILD_PUSH_DEBOUNCE_MINUTES = 10;
5
5
  const DEFAULT_FACTORY_THINKING_LEVEL = "medium";
6
6
  const FACTORY_MODEL_SCOPES = [
@@ -366,7 +366,6 @@ var FactoryProjectsStorage = class extends FactoryStorageDomain {
366
366
  }) > 0 ? project : null;
367
367
  }
368
368
  };
369
- //#endregion
370
369
  export { DEFAULT_BUILD_PUSH_DEBOUNCE_MINUTES, DEFAULT_FACTORY_THINKING_LEVEL, FACTORY_MODEL_SCOPES, FACTORY_PROJECTS_SCHEMA, FactoryProjectsStorage, effectiveModelScope };
371
370
 
372
371
  //# sourceMappingURL=base.js.map
@@ -1,5 +1,5 @@
1
1
  import { FactoryStorageDomain, UniqueViolationError } from "@mastra/core/storage";
2
- //#region src/storage/domains/queue-health/base.ts
2
+ // src/storage/domains/queue-health/base.ts
3
3
  /**
4
4
  * Queue-health threshold configuration domain: per-project age buckets for the
5
5
  * Factory Overview queue-health chart.
@@ -116,7 +116,6 @@ var QueueHealthStorage = class extends FactoryStorageDomain {
116
116
  }
117
117
  }
118
118
  };
119
- //#endregion
120
119
  export { DEFAULT_QUEUE_HEALTH_CONFIG, QUEUE_HEALTH_SETTINGS_SCHEMA, QueueHealthStorage, assertValidThresholds, parseQueueHealthConfig, thresholdsOrDefault };
121
120
 
122
121
  //# sourceMappingURL=base.js.map
@@ -1,6 +1,6 @@
1
1
  import { FACTORY_PROJECTS_SCHEMA } from "../projects/base.js";
2
2
  import { FactoryStorageDomain, UniqueViolationError } from "@mastra/core/storage";
3
- //#region src/storage/domains/source-control/base.ts
3
+ // src/storage/domains/source-control/base.ts
4
4
  const FACTORY_PROJECTS = "factory_projects";
5
5
  const INSTALLATIONS = "source_control_installations";
6
6
  const REPOSITORIES = "source_control_repositories";
@@ -1249,7 +1249,6 @@ var SourceControlStorage = class extends FactoryStorageDomain {
1249
1249
  };
1250
1250
  }
1251
1251
  };
1252
- //#endregion
1253
1252
  export { SOURCE_CONTROL_SCHEMAS, SessionBranchHeldError, SessionOwnershipMismatchError, SourceControlConnectionNotFoundError, SourceControlStorage };
1254
1253
 
1255
1254
  //# sourceMappingURL=base.js.map
@@ -1,5 +1,5 @@
1
1
  import { UniqueViolationError } from "@mastra/core/storage";
2
- //#region src/storage/domains/source-control/inmemory.ts
2
+ // src/storage/domains/source-control/inmemory.ts
3
3
  /** In-memory provider-scoped source-control handle for route tests. */
4
4
  var SourceControlStorageInMemory = class {
5
5
  integrationId;
@@ -457,7 +457,6 @@ var SourceControlStorageInMemory = class {
457
457
  listBySession: async ({ sessionId }) => this.sessionRepositoriesRows.filter((row) => row.sessionId === sessionId)
458
458
  };
459
459
  };
460
- //#endregion
461
460
  export { SourceControlStorageInMemory };
462
461
 
463
462
  //# sourceMappingURL=inmemory.js.map
@@ -4,7 +4,7 @@ import { WORK_ITEM_ACTIVITY_SCHEMA, WORK_ITEM_COMMENTS_SCHEMA, WORK_ITEM_COMMENT
4
4
  import { BoardScopes, FACTORY_BOARD_VERSIONS_SCHEMA, bumpBoardVersions, readBoardVersion, trackBoardWrites } from "./board-version.js";
5
5
  import { createHash } from "crypto";
6
6
  import { FactoryStorageDomain, UniqueViolationError } from "@mastra/core/storage";
7
- //#region src/storage/domains/work-items/base.ts
7
+ // src/storage/domains/work-items/base.ts
8
8
  /**
9
9
  * Factory work-items storage domain.
10
10
  *
@@ -2742,7 +2742,6 @@ var WorkItemsStorage = class extends FactoryStorageDomain {
2742
2742
  return removed;
2743
2743
  }
2744
2744
  };
2745
- //#endregion
2746
2745
  export { ACTIVE_RUN_BINDING_STAGES, FACTORY_PULL_REQUEST_RECONCILIATION_KEY, FACTORY_RULE_MATERIALIZATION_KEY, FACTORY_WORK_ITEM_SUBSCRIPTIONS_SCHEMA, WORK_ITEMS_SCHEMA, WorkItemClaimConflictError, WorkItemRelationError, WorkItemUpdateConflictError, WorkItemsStorage, applyStageTransition, externalSourceKey, factoryActivityAttentionIdentity, factoryAgentWaitingAttentionIdentity, factoryAttentionKey, factoryDecisionAttentionIdentity, factoryDecisionHash, factoryMentionAttentionIdentity, factoryProposalAttentionIdentity, isAgentActor, stampSessions, validateParentRelation };
2747
2746
 
2748
2747
  //# sourceMappingURL=base.js.map
@@ -1,5 +1,5 @@
1
1
  import { randomUUID } from "crypto";
2
- //#region src/storage/domains/work-items/board-version.ts
2
+ // src/storage/domains/work-items/board-version.ts
3
3
  /**
4
4
  * One row per project whose `version` is replaced after every committed write to that project's
5
5
  * `work_items`. Readers of the full card list compare it against the version their snapshot was
@@ -104,7 +104,6 @@ async function readBoardVersion(ops, orgId, factoryProjectId) {
104
104
  factory_project_id: factoryProjectId
105
105
  }))?.version;
106
106
  }
107
- //#endregion
108
107
  export { BoardScopes, FACTORY_BOARD_VERSIONS_SCHEMA, bumpBoardVersions, readBoardVersion, trackBoardWrites };
109
108
 
110
109
  //# sourceMappingURL=board-version.js.map
@@ -1,5 +1,5 @@
1
1
  import { isAgentActor } from "./base.js";
2
- //#region src/storage/domains/work-items/metrics.ts
2
+ // src/storage/domains/work-items/metrics.ts
3
3
  /**
4
4
  * Aggregation math for the Factory Overview page.
5
5
  *
@@ -220,7 +220,6 @@ function computeFactoryMetrics(boardItems, window) {
220
220
  agentCoverage: agentCoverage(items, window)
221
221
  };
222
222
  }
223
- //#endregion
224
223
  export { DEFAULT_METRICS_WINDOW, MAX_METRICS_WINDOW, computeFactoryMetrics, parseMetricsRange };
225
224
 
226
225
  //# sourceMappingURL=metrics.js.map