@mastra/factory 0.17.3-alpha.5 → 0.18.0-alpha.10

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 (178) hide show
  1. package/dist/auth.d.ts.map +1 -1
  2. package/dist/auth.js +15 -4
  3. package/dist/auth.js.map +1 -1
  4. package/dist/boards/review.d.ts +2 -0
  5. package/dist/boards/review.d.ts.map +1 -1
  6. package/dist/boards/review.js +16 -6
  7. package/dist/boards/review.js.map +1 -1
  8. package/dist/boards/transition-policy.d.ts +3 -3
  9. package/dist/boards/transition-policy.d.ts.map +1 -1
  10. package/dist/boards/transition-policy.js.map +1 -1
  11. package/dist/boards/work-transition-policy.d.ts.map +1 -1
  12. package/dist/boards/work-transition-policy.js +13 -3
  13. package/dist/boards/work-transition-policy.js.map +1 -1
  14. package/dist/capabilities/intake.d.ts +2 -0
  15. package/dist/capabilities/intake.d.ts.map +1 -1
  16. package/dist/factory.d.ts.map +1 -1
  17. package/dist/factory.js +14 -3
  18. package/dist/factory.js.map +1 -1
  19. package/dist/integrations/github/default-rules.d.ts +17 -1
  20. package/dist/integrations/github/default-rules.d.ts.map +1 -1
  21. package/dist/integrations/github/default-rules.js +30 -6
  22. package/dist/integrations/github/default-rules.js.map +1 -1
  23. package/dist/integrations/github/reconcile-worker.d.ts.map +1 -1
  24. package/dist/integrations/github/reconcile-worker.js.map +1 -1
  25. package/dist/integrations/github/routes.d.ts.map +1 -1
  26. package/dist/integrations/github/routes.js +1 -0
  27. package/dist/integrations/github/routes.js.map +1 -1
  28. package/dist/integrations/github/rules.d.ts.map +1 -1
  29. package/dist/integrations/github/rules.js +48 -2
  30. package/dist/integrations/github/rules.js.map +1 -1
  31. package/dist/integrations/github/sandbox.d.ts.map +1 -1
  32. package/dist/integrations/github/sandbox.js.map +1 -1
  33. package/dist/integrations/gitlab/api.d.ts.map +1 -1
  34. package/dist/integrations/gitlab/api.js.map +1 -1
  35. package/dist/integrations/gitlab/default-rules.d.ts.map +1 -1
  36. package/dist/integrations/gitlab/default-rules.js +1 -0
  37. package/dist/integrations/gitlab/default-rules.js.map +1 -1
  38. package/dist/integrations/gitlab/reconciler.d.ts.map +1 -1
  39. package/dist/integrations/gitlab/reconciler.js.map +1 -1
  40. package/dist/integrations/gitlab/reconciliation-config.d.ts.map +1 -1
  41. package/dist/integrations/gitlab/reconciliation-config.js.map +1 -1
  42. package/dist/integrations/gitlab/routes.d.ts.map +1 -1
  43. package/dist/integrations/gitlab/routes.js +1 -0
  44. package/dist/integrations/gitlab/routes.js.map +1 -1
  45. package/dist/integrations/gitlab/rules.d.ts.map +1 -1
  46. package/dist/integrations/gitlab/rules.js +66 -0
  47. package/dist/integrations/gitlab/rules.js.map +1 -1
  48. package/dist/integrations/gitlab/version-control.d.ts.map +1 -1
  49. package/dist/integrations/gitlab/version-control.js.map +1 -1
  50. package/dist/integrations/incidentio/api.d.ts.map +1 -1
  51. package/dist/integrations/incidentio/api.js.map +1 -1
  52. package/dist/integrations/incidentio/intake.d.ts.map +1 -1
  53. package/dist/integrations/incidentio/intake.js.map +1 -1
  54. package/dist/integrations/issue-reconcile-worker.d.ts.map +1 -1
  55. package/dist/integrations/issue-reconcile-worker.js.map +1 -1
  56. package/dist/integrations/linear/default-rules.d.ts +2 -1
  57. package/dist/integrations/linear/default-rules.d.ts.map +1 -1
  58. package/dist/integrations/linear/default-rules.js +1 -0
  59. package/dist/integrations/linear/default-rules.js.map +1 -1
  60. package/dist/integrations/linear/integration.d.ts.map +1 -1
  61. package/dist/integrations/linear/integration.js +2 -0
  62. package/dist/integrations/linear/integration.js.map +1 -1
  63. package/dist/integrations/linear/issue-reconciler.d.ts.map +1 -1
  64. package/dist/integrations/linear/issue-reconciler.js +3 -0
  65. package/dist/integrations/linear/issue-reconciler.js.map +1 -1
  66. package/dist/integrations/linear/routes.d.ts.map +1 -1
  67. package/dist/integrations/linear/routes.js +2 -1
  68. package/dist/integrations/linear/routes.js.map +1 -1
  69. package/dist/integrations/linear/rules.d.ts +1 -0
  70. package/dist/integrations/linear/rules.d.ts.map +1 -1
  71. package/dist/integrations/linear/rules.js.map +1 -1
  72. package/dist/integrations/platform/linear/event-worker.js.map +1 -1
  73. package/dist/integrations/slack/emoji-shortcodes.generated.js.map +1 -1
  74. package/dist/integrations/slack/feed-publisher.d.ts.map +1 -1
  75. package/dist/integrations/slack/feed-publisher.js.map +1 -1
  76. package/dist/integrations/slack/slack.d.ts +7 -7
  77. package/dist/integrations/slack/slack.d.ts.map +1 -1
  78. package/dist/integrations/slack/slack.js +157 -23
  79. package/dist/integrations/slack/slack.js.map +1 -1
  80. package/dist/integrations/subscription-session.d.ts +3 -1
  81. package/dist/integrations/subscription-session.d.ts.map +1 -1
  82. package/dist/integrations/subscription-session.js +4 -2
  83. package/dist/integrations/subscription-session.js.map +1 -1
  84. package/dist/platform-auth-host.d.ts +4 -0
  85. package/dist/platform-auth-host.d.ts.map +1 -0
  86. package/dist/platform-auth-host.js +18 -0
  87. package/dist/platform-auth-host.js.map +1 -0
  88. package/dist/routes/contracts.d.ts +23 -0
  89. package/dist/routes/contracts.d.ts.map +1 -1
  90. package/dist/routes/contracts.js +21 -0
  91. package/dist/routes/contracts.js.map +1 -1
  92. package/dist/routes/intake.d.ts.map +1 -1
  93. package/dist/routes/intake.js +15 -1
  94. package/dist/routes/intake.js.map +1 -1
  95. package/dist/routes/projects.d.ts +22 -2
  96. package/dist/routes/projects.d.ts.map +1 -1
  97. package/dist/routes/projects.js +101 -0
  98. package/dist/routes/projects.js.map +1 -1
  99. package/dist/routes/surface.d.ts +1 -1
  100. package/dist/routes/surface.d.ts.map +1 -1
  101. package/dist/routes/surface.js +47 -6
  102. package/dist/routes/surface.js.map +1 -1
  103. package/dist/routes/work-items.d.ts.map +1 -1
  104. package/dist/routes/work-items.js +6 -1
  105. package/dist/routes/work-items.js.map +1 -1
  106. package/dist/rules/dispatch-errors.d.ts.map +1 -1
  107. package/dist/rules/dispatch-errors.js +4 -0
  108. package/dist/rules/dispatch-errors.js.map +1 -1
  109. package/dist/rules/dispatcher.d.ts.map +1 -1
  110. package/dist/rules/dispatcher.js +14 -6
  111. package/dist/rules/dispatcher.js.map +1 -1
  112. package/dist/rules/processor.d.ts.map +1 -1
  113. package/dist/rules/processor.js +9 -1
  114. package/dist/rules/processor.js.map +1 -1
  115. package/dist/rules/review-source-tool.d.ts +103 -0
  116. package/dist/rules/review-source-tool.d.ts.map +1 -0
  117. package/dist/rules/review-source-tool.js +109 -0
  118. package/dist/rules/review-source-tool.js.map +1 -0
  119. package/dist/rules/start-coordinator.d.ts +7 -1
  120. package/dist/rules/start-coordinator.d.ts.map +1 -1
  121. package/dist/rules/start-coordinator.js +56 -2
  122. package/dist/rules/start-coordinator.js.map +1 -1
  123. package/dist/rules/tools.d.ts +1 -0
  124. package/dist/rules/tools.d.ts.map +1 -1
  125. package/dist/rules/tools.js +107 -32
  126. package/dist/rules/tools.js.map +1 -1
  127. package/dist/rules/transition-service.d.ts +4 -4
  128. package/dist/rules/transition-service.d.ts.map +1 -1
  129. package/dist/rules/transition-service.js +3 -2
  130. package/dist/rules/transition-service.js.map +1 -1
  131. package/dist/rules/types.d.ts +2 -0
  132. package/dist/rules/types.d.ts.map +1 -1
  133. package/dist/rules/types.js.map +1 -1
  134. package/dist/sandbox/materialization.d.ts +5 -1
  135. package/dist/sandbox/materialization.d.ts.map +1 -1
  136. package/dist/sandbox/materialization.js.map +1 -1
  137. package/dist/sandbox/session-sandbox.d.ts +13 -1
  138. package/dist/sandbox/session-sandbox.d.ts.map +1 -1
  139. package/dist/sandbox/session-sandbox.js.map +1 -1
  140. package/dist/session/factory-session.d.ts +14 -4
  141. package/dist/session/factory-session.d.ts.map +1 -1
  142. package/dist/session/factory-session.js +32 -11
  143. package/dist/session/factory-session.js.map +1 -1
  144. package/dist/session/work-item-repository.d.ts +21 -0
  145. package/dist/session/work-item-repository.d.ts.map +1 -0
  146. package/dist/session/work-item-repository.js +91 -0
  147. package/dist/session/work-item-repository.js.map +1 -0
  148. package/dist/skills/service.d.ts.map +1 -1
  149. package/dist/skills/service.js +16 -6
  150. package/dist/skills/service.js.map +1 -1
  151. package/dist/storage/domains/intake/base.d.ts +1 -0
  152. package/dist/storage/domains/intake/base.d.ts.map +1 -1
  153. package/dist/storage/domains/intake/base.js.map +1 -1
  154. package/dist/storage/domains/integrations/base.d.ts.map +1 -1
  155. package/dist/storage/domains/integrations/base.js.map +1 -1
  156. package/dist/storage/domains/work-items/base.d.ts +15 -2
  157. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  158. package/dist/storage/domains/work-items/base.js +31 -1
  159. package/dist/storage/domains/work-items/base.js.map +1 -1
  160. package/dist/supervisor/session-messaging.d.ts +4 -1
  161. package/dist/supervisor/session-messaging.d.ts.map +1 -1
  162. package/dist/supervisor/session-messaging.js +8 -2
  163. package/dist/supervisor/session-messaging.js.map +1 -1
  164. package/dist/supervisor/write-tools.d.ts +2 -1
  165. package/dist/supervisor/write-tools.d.ts.map +1 -1
  166. package/dist/supervisor/write-tools.js +9 -2
  167. package/dist/supervisor/write-tools.js.map +1 -1
  168. package/dist/workspace.d.ts +7 -1
  169. package/dist/workspace.d.ts.map +1 -1
  170. package/dist/workspace.js +53 -14
  171. package/dist/workspace.js.map +1 -1
  172. package/factory-skills/factory-complete-issue/SKILL.md +4 -2
  173. package/factory-skills/factory-gitlab-rereview/SKILL.md +3 -2
  174. package/factory-skills/factory-gitlab-review/SKILL.md +19 -3
  175. package/factory-skills/factory-plan/SKILL.md +11 -0
  176. package/factory-skills/factory-rereview/SKILL.md +37 -12
  177. package/factory-skills/factory-review/SKILL.md +37 -12
  178. package/package.json +8 -8
@@ -1 +1 @@
1
- {"version":3,"file":"subscription-session.d.ts","sourceRoot":"","sources":["../../src/integrations/subscription-session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAI9D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AAEvF,oEAAoE;AACpE,MAAM,MAAM,mBAAmB,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpE,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE;QAAE,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAA;KAAE,CAAC;CACtF;AAED;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG,uBAAuB,CAAC;IAC3D,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC,CAAC,CAAC;AAEH;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,YAAY,EAAE,sBAAsB,EACpC,aAAa,EAAE,yBAAyB,GAAG,SAAS,GACnD,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAyBrC;AAED;;;;;;;;GAQG;AACH,wBAAsB,wBAAwB,CAC5C,cAAc,EAAE,cAAc,EAC9B,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,yBAAyB,GACvC,OAAO,CAAC,IAAI,CAAC,CAKf;AAED,wBAAsB,0BAA0B,CAC9C,UAAU,EAAE,iBAAiB,CAAC,YAAY,CAAC,EAC3C,YAAY,EAAE,sBAAsB,EACpC,OAAO,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,yBAAyB,CAAA;CAAE,kHA+EtE"}
1
+ {"version":3,"file":"subscription-session.d.ts","sourceRoot":"","sources":["../../src/integrations/subscription-session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAI9D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AAEvF,oEAAoE;AACpE,MAAM,MAAM,mBAAmB,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpE,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE;QAAE,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAA;KAAE,CAAC;CACtF;AAED;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG,uBAAuB,CAAC;IAC3D,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC,CAAC,CAAC;AAEH;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,YAAY,EAAE,sBAAsB,EACpC,aAAa,EAAE,yBAAyB,GAAG,SAAS,GACnD,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAyBrC;AAED;;;;;;;;GAQG;AACH,wBAAsB,wBAAwB,CAC5C,cAAc,EAAE,cAAc,EAC9B,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,yBAAyB,EACxC,OAAO,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GACnC,OAAO,CAAC,UAAU,GAAG,aAAa,GAAG,uBAAuB,CAAC,CAS/D;AAED,wBAAsB,0BAA0B,CAC9C,UAAU,EAAE,iBAAiB,CAAC,YAAY,CAAC,EAC3C,YAAY,EAAE,sBAAsB,EACpC,OAAO,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,yBAAyB,CAAA;CAAE,kHA+EtE"}
@@ -41,14 +41,16 @@ async function subscriptionRunContext(subscription, sourceControl) {
41
41
  * Factory session or its org is unresolved, so credential resolution fails
42
42
  * closed.
43
43
  */
44
- async function prepareSessionRunContext(requestContext, sessionId, sourceControl) {
44
+ async function prepareSessionRunContext(requestContext, sessionId, sourceControl, options) {
45
45
  const sessionRow = await sourceControl.sessions.getBySessionId(sessionId);
46
- if (!sessionRow || !hasResolvedOrg(sessionRow.orgId)) return;
46
+ if (!sessionRow || !hasResolvedOrg(sessionRow.orgId)) return "unavailable";
47
+ if (options?.expectedOrgId !== void 0 && sessionRow.orgId !== options.expectedOrgId) return "organization-mismatch";
47
48
  requestContext.set("user", {
48
49
  workosId: sessionRow.userId,
49
50
  organizationId: sessionRow.orgId
50
51
  });
51
52
  await primeTenantCredentialsForRequestContext(requestContext);
53
+ return "prepared";
52
54
  }
53
55
  async function resolveSubscriptionSession(controller, subscription, options) {
54
56
  const { label } = options;
@@ -1 +1 @@
1
- {"version":3,"file":"subscription-session.js","names":[],"sources":["../../src/integrations/subscription-session.ts"],"sourcesContent":["import type { MountedMastraCode } from '@mastra/code-sdk';\nimport { RequestContext } from '@mastra/core/request-context';\n\nimport { primeTenantCredentialsForRequestContext } from '../routes/tenant-credentials.js';\nimport { hasResolvedOrg, seedSessionOrg } from '../session/org-seed.js';\nimport type { IntegrationSubscription } from '../storage/domains/integrations/base.js';\n\n/** The Factory session row fields a woken session has to run as. */\nexport type FactorySessionOwner = { userId: string; orgId: string };\n\nexport interface SubscriptionSessionLookup {\n sessions: { getBySessionId(sessionId: string): Promise<FactorySessionOwner | null> };\n}\n\n/**\n * Bring the session that owns a subscribed thread online so a provider event\n * can be delivered to it. Provider-neutral: GitHub and GitLab subscriptions\n * carry the same session binding and differ only in their target data.\n */\nexport type SubscriptionSessionRow = IntegrationSubscription<{\n projectRepositoryId: string;\n subscribedByUserId?: string | null;\n}>;\n\n/**\n * The request context a provider-triggered run executes under: the user who\n * subscribed the thread, in the subscription's organization. A webhook carries\n * no signed-in user and tenant credential resolution fails closed without one,\n * so a woken run would otherwise stop before it could persist or answer the\n * notification. The subscription row already names that user, so delivery\n * costs no extra read; an older row without one falls back to the Factory\n * session's owner, the identity used when a session is recreated for delivery.\n */\nexport async function subscriptionRunContext(\n subscription: SubscriptionSessionRow,\n sourceControl: SubscriptionSessionLookup | undefined,\n): Promise<RequestContext | undefined> {\n let userId = subscription.data.subscribedByUserId ?? undefined;\n let orgId: string | undefined = subscription.orgId;\n if (!userId && subscription.sessionId && sourceControl) {\n const sessionRow = await sourceControl.sessions.getBySessionId(subscription.sessionId);\n userId = sessionRow?.userId;\n orgId = sessionRow?.orgId ?? orgId;\n }\n if (!userId || !hasResolvedOrg(orgId)) return undefined;\n const requestContext = new RequestContext();\n requestContext.set('user', { workosId: userId, organizationId: orgId });\n // The web auth middleware primes credential snapshots per request; a\n // webhook-triggered run has no request, so prime here or the model resolves\n // against an empty snapshot and the run fails closed before persisting. A\n // priming failure propagates: handing back an unprimed context would let the\n // caller accept the delivery, and retire a terminal subscription, for a run\n // that then fails without its credentials and cannot be redelivered.\n try {\n await primeTenantCredentialsForRequestContext(requestContext);\n } catch (error) {\n throw new Error(`Unable to prime tenant credentials for subscription ${subscription.id}; not delivered.`, {\n cause: error,\n });\n }\n return requestContext;\n}\n\n/**\n * Attach the Factory session's owner, in its organization, to the request\n * context of a run that has no inbound request (a notification or peer-signal\n * wake), and prime that tenant's credentials. The live session's `ownerId`\n * isn't used: sessions opened from the browser or Slack are owned by the\n * controller id, not a user. Leaves the context alone when `sessionId` names no\n * Factory session or its org is unresolved, so credential resolution fails\n * closed.\n */\nexport async function prepareSessionRunContext(\n requestContext: RequestContext,\n sessionId: string,\n sourceControl: SubscriptionSessionLookup,\n): Promise<void> {\n const sessionRow = await sourceControl.sessions.getBySessionId(sessionId);\n if (!sessionRow || !hasResolvedOrg(sessionRow.orgId)) return;\n requestContext.set('user', { workosId: sessionRow.userId, organizationId: sessionRow.orgId });\n await primeTenantCredentialsForRequestContext(requestContext);\n}\n\nexport async function resolveSubscriptionSession(\n controller: MountedMastraCode['controller'],\n subscription: SubscriptionSessionRow,\n options: { label: string; sourceControl?: SubscriptionSessionLookup },\n) {\n const { label } = options;\n const { sessionId, resourceId, threadId } = subscription;\n if (!sessionId || !resourceId || !threadId) {\n throw new Error(`${label} subscription ${subscription.id} is missing its session binding.`);\n }\n // Read the thread straight from storage before touching sessions. This answers\n // two questions at once, and `queryThreadById` does it without constructing a\n // session (so no workspace or sandbox is provisioned just to make the check).\n //\n // First: do we even have this thread? A change request's events can reach a\n // deployment that never owned the subscribed thread, and delivery must not\n // fabricate a session for a thread that lives somewhere else.\n //\n // Second: which resource owns it? The subscription records the Factory project\n // as its `resourceId`, but an unscoped session is registered under its own id,\n // so the stored value routinely names a resource that does not own the thread.\n // The thread row is the authoritative answer; the stored id is only a fallback.\n const thread = await controller.queryThreadById({ threadId });\n if (!thread) return undefined;\n const ownerResourceId = thread.resourceId || resourceId;\n const scope = subscription.sessionScope || undefined;\n let session = await controller.getSessionByResource(ownerResourceId, scope);\n if (!session) {\n const tags = {\n factoryProjectId: resourceId,\n projectRepositoryId: subscription.data.projectRepositoryId,\n };\n // Creating the session resolves its workspace, which authorizes the caller\n // against the Factory session row — no signed-in user, so run as its owner.\n // The session is created under the resource that owns the thread, so the\n // thread switch below resolves; the persisted Factory session is keyed by\n // the subscription's session ID.\n const sessionRow = await options.sourceControl?.sessions.getBySessionId(sessionId);\n if (!sessionRow) {\n throw new Error(`${label} subscription ${subscription.id} has no Factory session ${sessionId} to run as.`);\n }\n const requestContext = new RequestContext();\n requestContext.set('user', { workosId: sessionRow.userId, organizationId: sessionRow.orgId });\n session = await controller.createSession({\n id: sessionId,\n ownerId: sessionRow.userId,\n resourceId: ownerResourceId,\n scope,\n tags,\n requestContext,\n });\n await seedSessionOrg(session, sessionRow.orgId);\n } else if (!hasResolvedOrg(session.state?.get()?.factoryOrgId)) {\n // A session created before the org seed existed carries the project tag and\n // no org, so capture would refuse for the rest of its life even though the\n // org is recoverable. Heal it — but only here, and only when it is missing:\n // hoisting the row fetch above would make an existing-session delivery throw\n // on a missing row where it previously succeeded, and fetching it every time\n // would add a storage read to every delivery. A row that is missing or a\n // lookup that throws leaves the session marked unresolved, and delivery\n // continues either way.\n try {\n const sessionRow = await options.sourceControl?.sessions.getBySessionId(sessionId);\n await seedSessionOrg(session, sessionRow?.orgId);\n } catch (error) {\n console.warn(`[${label} webhook] Unable to resolve the session organization.`, error);\n await seedSessionOrg(session, undefined);\n }\n } else if (session.state?.get()?.factoryOrgUnresolved) {\n // The org is present, so an earlier failed resolution left a stale marker\n // behind. Clear it without a storage read — nothing else re-seeds a session\n // once the start hook has run, so the marker would otherwise outlive its\n // cause.\n await seedSessionOrg(session, session.state.get()?.factoryOrgId);\n }\n if (session.thread.getId() !== threadId) {\n await session.thread.switch({ threadId, emitEvent: false });\n }\n if (session.thread.getId() !== threadId) {\n throw new Error(`Session ${sessionId} did not bind thread ${threadId}.`);\n }\n return session;\n}\n"],"mappings":";;;;;;;;;;;;;AAiCA,eAAsB,uBACpB,cACA,eACqC;CACrC,IAAI,SAAS,aAAa,KAAK,sBAAsB,KAAA;CACrD,IAAI,QAA4B,aAAa;CAC7C,IAAI,CAAC,UAAU,aAAa,aAAa,eAAe;EACtD,MAAM,aAAa,MAAM,cAAc,SAAS,eAAe,aAAa,SAAS;EACrF,SAAS,YAAY;EACrB,QAAQ,YAAY,SAAS;CAC/B;CACA,IAAI,CAAC,UAAU,CAAC,eAAe,KAAK,GAAG,OAAO,KAAA;CAC9C,MAAM,iBAAiB,IAAI,eAAe;CAC1C,eAAe,IAAI,QAAQ;EAAE,UAAU;EAAQ,gBAAgB;CAAM,CAAC;CAOtE,IAAI;EACF,MAAM,wCAAwC,cAAc;CAC9D,SAAS,OAAO;EACd,MAAM,IAAI,MAAM,uDAAuD,aAAa,GAAG,mBAAmB,EACxG,OAAO,MACT,CAAC;CACH;CACA,OAAO;AACT;;;;;;;;;;AAWA,eAAsB,yBACpB,gBACA,WACA,eACe;CACf,MAAM,aAAa,MAAM,cAAc,SAAS,eAAe,SAAS;CACxE,IAAI,CAAC,cAAc,CAAC,eAAe,WAAW,KAAK,GAAG;CACtD,eAAe,IAAI,QAAQ;EAAE,UAAU,WAAW;EAAQ,gBAAgB,WAAW;CAAM,CAAC;CAC5F,MAAM,wCAAwC,cAAc;AAC9D;AAEA,eAAsB,2BACpB,YACA,cACA,SACA;CACA,MAAM,EAAE,UAAU;CAClB,MAAM,EAAE,WAAW,YAAY,aAAa;CAC5C,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,UAChC,MAAM,IAAI,MAAM,GAAG,MAAM,gBAAgB,aAAa,GAAG,iCAAiC;CAc5F,MAAM,SAAS,MAAM,WAAW,gBAAgB,EAAE,SAAS,CAAC;CAC5D,IAAI,CAAC,QAAQ,OAAO,KAAA;CACpB,MAAM,kBAAkB,OAAO,cAAc;CAC7C,MAAM,QAAQ,aAAa,gBAAgB,KAAA;CAC3C,IAAI,UAAU,MAAM,WAAW,qBAAqB,iBAAiB,KAAK;CAC1E,IAAI,CAAC,SAAS;EACZ,MAAM,OAAO;GACX,kBAAkB;GAClB,qBAAqB,aAAa,KAAK;EACzC;EAMA,MAAM,aAAa,MAAM,QAAQ,eAAe,SAAS,eAAe,SAAS;EACjF,IAAI,CAAC,YACH,MAAM,IAAI,MAAM,GAAG,MAAM,gBAAgB,aAAa,GAAG,0BAA0B,UAAU,YAAY;EAE3G,MAAM,iBAAiB,IAAI,eAAe;EAC1C,eAAe,IAAI,QAAQ;GAAE,UAAU,WAAW;GAAQ,gBAAgB,WAAW;EAAM,CAAC;EAC5F,UAAU,MAAM,WAAW,cAAc;GACvC,IAAI;GACJ,SAAS,WAAW;GACpB,YAAY;GACZ;GACA;GACA;EACF,CAAC;EACD,MAAM,eAAe,SAAS,WAAW,KAAK;CAChD,OAAO,IAAI,CAAC,eAAe,QAAQ,OAAO,IAAI,CAAC,EAAE,YAAY,GAS3D,IAAI;EACF,MAAM,aAAa,MAAM,QAAQ,eAAe,SAAS,eAAe,SAAS;EACjF,MAAM,eAAe,SAAS,YAAY,KAAK;CACjD,SAAS,OAAO;EACd,QAAQ,KAAK,IAAI,MAAM,wDAAwD,KAAK;EACpF,MAAM,eAAe,SAAS,KAAA,CAAS;CACzC;MACK,IAAI,QAAQ,OAAO,IAAI,CAAC,EAAE,sBAK/B,MAAM,eAAe,SAAS,QAAQ,MAAM,IAAI,CAAC,EAAE,YAAY;CAEjE,IAAI,QAAQ,OAAO,MAAM,MAAM,UAC7B,MAAM,QAAQ,OAAO,OAAO;EAAE;EAAU,WAAW;CAAM,CAAC;CAE5D,IAAI,QAAQ,OAAO,MAAM,MAAM,UAC7B,MAAM,IAAI,MAAM,WAAW,UAAU,uBAAuB,SAAS,EAAE;CAEzE,OAAO;AACT"}
1
+ {"version":3,"file":"subscription-session.js","names":[],"sources":["../../src/integrations/subscription-session.ts"],"sourcesContent":["import type { MountedMastraCode } from '@mastra/code-sdk';\nimport { RequestContext } from '@mastra/core/request-context';\n\nimport { primeTenantCredentialsForRequestContext } from '../routes/tenant-credentials.js';\nimport { hasResolvedOrg, seedSessionOrg } from '../session/org-seed.js';\nimport type { IntegrationSubscription } from '../storage/domains/integrations/base.js';\n\n/** The Factory session row fields a woken session has to run as. */\nexport type FactorySessionOwner = { userId: string; orgId: string };\n\nexport interface SubscriptionSessionLookup {\n sessions: { getBySessionId(sessionId: string): Promise<FactorySessionOwner | null> };\n}\n\n/**\n * Bring the session that owns a subscribed thread online so a provider event\n * can be delivered to it. Provider-neutral: GitHub and GitLab subscriptions\n * carry the same session binding and differ only in their target data.\n */\nexport type SubscriptionSessionRow = IntegrationSubscription<{\n projectRepositoryId: string;\n subscribedByUserId?: string | null;\n}>;\n\n/**\n * The request context a provider-triggered run executes under: the user who\n * subscribed the thread, in the subscription's organization. A webhook carries\n * no signed-in user and tenant credential resolution fails closed without one,\n * so a woken run would otherwise stop before it could persist or answer the\n * notification. The subscription row already names that user, so delivery\n * costs no extra read; an older row without one falls back to the Factory\n * session's owner, the identity used when a session is recreated for delivery.\n */\nexport async function subscriptionRunContext(\n subscription: SubscriptionSessionRow,\n sourceControl: SubscriptionSessionLookup | undefined,\n): Promise<RequestContext | undefined> {\n let userId = subscription.data.subscribedByUserId ?? undefined;\n let orgId: string | undefined = subscription.orgId;\n if (!userId && subscription.sessionId && sourceControl) {\n const sessionRow = await sourceControl.sessions.getBySessionId(subscription.sessionId);\n userId = sessionRow?.userId;\n orgId = sessionRow?.orgId ?? orgId;\n }\n if (!userId || !hasResolvedOrg(orgId)) return undefined;\n const requestContext = new RequestContext();\n requestContext.set('user', { workosId: userId, organizationId: orgId });\n // The web auth middleware primes credential snapshots per request; a\n // webhook-triggered run has no request, so prime here or the model resolves\n // against an empty snapshot and the run fails closed before persisting. A\n // priming failure propagates: handing back an unprimed context would let the\n // caller accept the delivery, and retire a terminal subscription, for a run\n // that then fails without its credentials and cannot be redelivered.\n try {\n await primeTenantCredentialsForRequestContext(requestContext);\n } catch (error) {\n throw new Error(`Unable to prime tenant credentials for subscription ${subscription.id}; not delivered.`, {\n cause: error,\n });\n }\n return requestContext;\n}\n\n/**\n * Attach the Factory session's owner, in its organization, to the request\n * context of a run that has no inbound request (a notification or peer-signal\n * wake), and prime that tenant's credentials. The live session's `ownerId`\n * isn't used: sessions opened from the browser or Slack are owned by the\n * controller id, not a user. Leaves the context alone when `sessionId` names no\n * Factory session or its org is unresolved, so credential resolution fails\n * closed.\n */\nexport async function prepareSessionRunContext(\n requestContext: RequestContext,\n sessionId: string,\n sourceControl: SubscriptionSessionLookup,\n options?: { expectedOrgId?: string },\n): Promise<'prepared' | 'unavailable' | 'organization-mismatch'> {\n const sessionRow = await sourceControl.sessions.getBySessionId(sessionId);\n if (!sessionRow || !hasResolvedOrg(sessionRow.orgId)) return 'unavailable';\n if (options?.expectedOrgId !== undefined && sessionRow.orgId !== options.expectedOrgId) {\n return 'organization-mismatch';\n }\n requestContext.set('user', { workosId: sessionRow.userId, organizationId: sessionRow.orgId });\n await primeTenantCredentialsForRequestContext(requestContext);\n return 'prepared';\n}\n\nexport async function resolveSubscriptionSession(\n controller: MountedMastraCode['controller'],\n subscription: SubscriptionSessionRow,\n options: { label: string; sourceControl?: SubscriptionSessionLookup },\n) {\n const { label } = options;\n const { sessionId, resourceId, threadId } = subscription;\n if (!sessionId || !resourceId || !threadId) {\n throw new Error(`${label} subscription ${subscription.id} is missing its session binding.`);\n }\n // Read the thread straight from storage before touching sessions. This answers\n // two questions at once, and `queryThreadById` does it without constructing a\n // session (so no workspace or sandbox is provisioned just to make the check).\n //\n // First: do we even have this thread? A change request's events can reach a\n // deployment that never owned the subscribed thread, and delivery must not\n // fabricate a session for a thread that lives somewhere else.\n //\n // Second: which resource owns it? The subscription records the Factory project\n // as its `resourceId`, but an unscoped session is registered under its own id,\n // so the stored value routinely names a resource that does not own the thread.\n // The thread row is the authoritative answer; the stored id is only a fallback.\n const thread = await controller.queryThreadById({ threadId });\n if (!thread) return undefined;\n const ownerResourceId = thread.resourceId || resourceId;\n const scope = subscription.sessionScope || undefined;\n let session = await controller.getSessionByResource(ownerResourceId, scope);\n if (!session) {\n const tags = {\n factoryProjectId: resourceId,\n projectRepositoryId: subscription.data.projectRepositoryId,\n };\n // Creating the session resolves its workspace, which authorizes the caller\n // against the Factory session row — no signed-in user, so run as its owner.\n // The session is created under the resource that owns the thread, so the\n // thread switch below resolves; the persisted Factory session is keyed by\n // the subscription's session ID.\n const sessionRow = await options.sourceControl?.sessions.getBySessionId(sessionId);\n if (!sessionRow) {\n throw new Error(`${label} subscription ${subscription.id} has no Factory session ${sessionId} to run as.`);\n }\n const requestContext = new RequestContext();\n requestContext.set('user', { workosId: sessionRow.userId, organizationId: sessionRow.orgId });\n session = await controller.createSession({\n id: sessionId,\n ownerId: sessionRow.userId,\n resourceId: ownerResourceId,\n scope,\n tags,\n requestContext,\n });\n await seedSessionOrg(session, sessionRow.orgId);\n } else if (!hasResolvedOrg(session.state?.get()?.factoryOrgId)) {\n // A session created before the org seed existed carries the project tag and\n // no org, so capture would refuse for the rest of its life even though the\n // org is recoverable. Heal it — but only here, and only when it is missing:\n // hoisting the row fetch above would make an existing-session delivery throw\n // on a missing row where it previously succeeded, and fetching it every time\n // would add a storage read to every delivery. A row that is missing or a\n // lookup that throws leaves the session marked unresolved, and delivery\n // continues either way.\n try {\n const sessionRow = await options.sourceControl?.sessions.getBySessionId(sessionId);\n await seedSessionOrg(session, sessionRow?.orgId);\n } catch (error) {\n console.warn(`[${label} webhook] Unable to resolve the session organization.`, error);\n await seedSessionOrg(session, undefined);\n }\n } else if (session.state?.get()?.factoryOrgUnresolved) {\n // The org is present, so an earlier failed resolution left a stale marker\n // behind. Clear it without a storage read — nothing else re-seeds a session\n // once the start hook has run, so the marker would otherwise outlive its\n // cause.\n await seedSessionOrg(session, session.state.get()?.factoryOrgId);\n }\n if (session.thread.getId() !== threadId) {\n await session.thread.switch({ threadId, emitEvent: false });\n }\n if (session.thread.getId() !== threadId) {\n throw new Error(`Session ${sessionId} did not bind thread ${threadId}.`);\n }\n return session;\n}\n"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare const PLATFORM_AUTH_PROVIDER = "mastra-studio";
2
+ export declare const CUSTOM_DOMAIN_UNSUPPORTED_ERROR = "custom_domain_unsupported";
3
+ export declare function isPlatformAuthSupportedHost(hostname: string): boolean;
4
+ //# sourceMappingURL=platform-auth-host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-auth-host.d.ts","sourceRoot":"","sources":["../src/platform-auth-host.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,kBAAkB,CAAC;AACtD,eAAO,MAAM,+BAA+B,8BAA8B,CAAC;AAK3E,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAMrE"}
@@ -0,0 +1,18 @@
1
+ //#region src/platform-auth-host.ts
2
+ const PLATFORM_AUTH_PROVIDER = "mastra-studio";
3
+ const CUSTOM_DOMAIN_UNSUPPORTED_ERROR = "custom_domain_unsupported";
4
+ const PLATFORM_AUTH_DOMAINS = ["mastra.cloud", "mastra.ai"];
5
+ const LOOPBACK_HOSTS = /* @__PURE__ */ new Set([
6
+ "localhost",
7
+ "127.0.0.1",
8
+ "[::1]"
9
+ ]);
10
+ function isPlatformAuthSupportedHost(hostname) {
11
+ const normalizedHostname = hostname.toLowerCase();
12
+ if (LOOPBACK_HOSTS.has(normalizedHostname)) return true;
13
+ return PLATFORM_AUTH_DOMAINS.some((domain) => normalizedHostname === domain || normalizedHostname.endsWith(`.${domain}`));
14
+ }
15
+ //#endregion
16
+ export { CUSTOM_DOMAIN_UNSUPPORTED_ERROR, PLATFORM_AUTH_PROVIDER, isPlatformAuthSupportedHost };
17
+
18
+ //# sourceMappingURL=platform-auth-host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-auth-host.js","names":[],"sources":["../src/platform-auth-host.ts"],"sourcesContent":["export const PLATFORM_AUTH_PROVIDER = 'mastra-studio';\nexport const CUSTOM_DOMAIN_UNSUPPORTED_ERROR = 'custom_domain_unsupported';\n\nconst PLATFORM_AUTH_DOMAINS = ['mastra.cloud', 'mastra.ai'] as const;\nconst LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '[::1]']);\n\nexport function isPlatformAuthSupportedHost(hostname: string): boolean {\n const normalizedHostname = hostname.toLowerCase();\n if (LOOPBACK_HOSTS.has(normalizedHostname)) return true;\n return PLATFORM_AUTH_DOMAINS.some(\n domain => normalizedHostname === domain || normalizedHostname.endsWith(`.${domain}`),\n );\n}\n"],"mappings":";AAAA,MAAa,yBAAyB;AACtC,MAAa,kCAAkC;AAE/C,MAAM,wBAAwB,CAAC,gBAAgB,WAAW;AAC1D,MAAM,iCAAiB,IAAI,IAAI;CAAC;CAAa;CAAa;AAAO,CAAC;AAElE,SAAgB,4BAA4B,UAA2B;CACrE,MAAM,qBAAqB,SAAS,YAAY;CAChD,IAAI,eAAe,IAAI,kBAAkB,GAAG,OAAO;CACnD,OAAO,sBAAsB,MAC3B,WAAU,uBAAuB,UAAU,mBAAmB,SAAS,IAAI,QAAQ,CACrF;AACF"}
@@ -204,6 +204,29 @@ export declare const FACTORY_ROUTE_CONTRACTS: {
204
204
  project: z.ZodRecord<z.ZodString, z.ZodUnknown>;
205
205
  }, z.core.$strip>;
206
206
  };
207
+ readonly projectApplyDefaultModel: {
208
+ readonly method: "POST";
209
+ readonly path: "/web/factory/projects/:id/apply-default-model";
210
+ readonly description: "Apply the Factory default model to running work and review threads";
211
+ readonly pathSchema: z.ZodObject<{
212
+ id: z.ZodString;
213
+ }, z.core.$strip>;
214
+ readonly responseSchema: z.ZodObject<{
215
+ modelId: z.ZodString;
216
+ applied: z.ZodArray<z.ZodString>;
217
+ skipped: z.ZodArray<z.ZodObject<{
218
+ threadId: z.ZodString;
219
+ reason: z.ZodEnum<{
220
+ "not-running": "not-running";
221
+ "work-item-missing": "work-item-missing";
222
+ "stage-inactive": "stage-inactive";
223
+ "thread-missing": "thread-missing";
224
+ "mode-unknown": "mode-unknown";
225
+ "apply-failed": "apply-failed";
226
+ }>;
227
+ }, z.core.$strip>>;
228
+ }, z.core.$strip>;
229
+ };
207
230
  readonly projectDelete: {
208
231
  readonly method: "DELETE";
209
232
  readonly path: "/web/factory/projects/:id";
@@ -1 +1 @@
1
- {"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../../src/routes/contracts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;IACxB,UAAU,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;IACvB,cAAc,EAAE,CAAC,CAAC,OAAO,CAAC;CAC3B,CAAC;AAEF,eAAO,MAAM,YAAY,kFAAkF,CAAC;AA8B5G,eAAO,MAAM,uBAAuB;;;iBAGlC,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;;;iBASoE,CAAC;AAiDzG,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;iBAQnC,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;iBAUqE,CAAC;AAE3G,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;GAgB5B,CAAC;AAEN,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBASlC,CAAC;AAEH,eAAO,MAAM,4BAA4B;;;;;;;;kBAQ9B,CAAC;AAEZ,eAAO,MAAM,kBAAkB;;;iBAG7B,CAAC;AA8CH,eAAO,MAAM,mBAAmB;;;;;;;iBAa9B,CAAC;AAWH,KAAK,uBAAuB,GAAG;IAAE,UAAU,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AA6ChE,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;iBAS/B,CAAC;AAyBH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqOqB,CAAC;AAE1D,MAAM,MAAM,uBAAuB,GAAG,MAAM,OAAO,uBAAuB,CAAC"}
1
+ {"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../../src/routes/contracts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;IACxB,UAAU,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;IACvB,cAAc,EAAE,CAAC,CAAC,OAAO,CAAC;CAC3B,CAAC;AAEF,eAAO,MAAM,YAAY,kFAAkF,CAAC;AA8B5G,eAAO,MAAM,uBAAuB;;;iBAGlC,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;;;iBASoE,CAAC;AAiDzG,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;iBAQnC,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;iBAUqE,CAAC;AAE3G,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;GAgB5B,CAAC;AAEN,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBASlC,CAAC;AAEH,eAAO,MAAM,4BAA4B;;;;;;;;kBAQ9B,CAAC;AAEZ,eAAO,MAAM,kBAAkB;;;iBAG7B,CAAC;AA8CH,eAAO,MAAM,mBAAmB;;;;;;;iBAa9B,CAAC;AAWH,KAAK,uBAAuB,GAAG;IAAE,UAAU,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AA6ChE,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;iBAS/B,CAAC;AAyBH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4PqB,CAAC;AAE1D,MAAM,MAAM,uBAAuB,GAAG,MAAM,OAAO,uBAAuB,CAAC"}
@@ -265,6 +265,27 @@ const FACTORY_ROUTE_CONTRACTS = {
265
265
  bodySchema: updateProjectBodySchema,
266
266
  responseSchema: projectResponseSchema
267
267
  },
268
+ projectApplyDefaultModel: {
269
+ method: "POST",
270
+ path: "/web/factory/projects/:id/apply-default-model",
271
+ description: "Apply the Factory default model to running work and review threads",
272
+ pathSchema: projectPathSchema,
273
+ responseSchema: z.object({
274
+ modelId: z.string(),
275
+ applied: z.array(z.string()),
276
+ skipped: z.array(z.object({
277
+ threadId: z.string(),
278
+ reason: z.enum([
279
+ "not-running",
280
+ "work-item-missing",
281
+ "stage-inactive",
282
+ "thread-missing",
283
+ "mode-unknown",
284
+ "apply-failed"
285
+ ])
286
+ }))
287
+ })
288
+ },
268
289
  projectDelete: {
269
290
  method: "DELETE",
270
291
  path: "/web/factory/projects/:id",
@@ -1 +1 @@
1
- {"version":3,"file":"contracts.js","names":[],"sources":["../../src/routes/contracts.ts"],"sourcesContent":["import { z } from 'zod';\n\nimport { FACTORY_ROLE_STAGES } from '../rules/types.js';\nimport { BOARD_IDENTIFIER_RE, MAX_BOARD_IDENTIFIER_LENGTH } from '../rules/validation.js';\n\nconst FACTORY_ROLE_VALUES = Object.keys(FACTORY_ROLE_STAGES) as [string, ...string[]];\n\nexport type FactoryRouteContract = {\n method: 'GET' | 'POST' | 'PATCH' | 'DELETE';\n path: string;\n description: string;\n pathSchema?: z.ZodType;\n querySchema?: z.ZodType;\n bodySchema?: z.ZodType;\n responseSchema: z.ZodType;\n};\n\nexport const UUID_PATTERN = '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$';\nconst uuidSchema = z.string().regex(new RegExp(UUID_PATTERN));\nconst entitySchema = z.record(z.string(), z.unknown());\nconst nonEmptyTrimmed = (max: number) => z.string().trim().min(1).max(max);\nconst rawBoundedTrimmed = (max: number) =>\n z\n .string()\n .max(max)\n .transform(value => value.trim())\n .pipe(z.string().min(1));\nconst trimmedUuidSchema = z.string().trim().regex(new RegExp(UUID_PATTERN));\nconst nullableTrimmed = (max: number) =>\n z.union([\n z\n .string()\n .trim()\n .max(max)\n .transform(value => value || null),\n z.null(),\n ]);\nconst projectPathSchema = z.object({ id: uuidSchema });\nconst projectDecisionPathSchema = z.object({ id: uuidSchema, decisionId: uuidSchema });\nconst workItemPathSchema = z.object({ id: uuidSchema });\nconst transitionPathSchema = z.object({ id: uuidSchema, workItemId: uuidSchema });\n\nconst projectSchema = entitySchema;\nconst projectResponseSchema = z.object({ project: projectSchema });\nconst workItemResponseSchema = z.object({ workItem: entitySchema });\nconst decisionResponseSchema = z.object({ decision: entitySchema });\n\nexport const createProjectBodySchema = z.object({\n name: nonEmptyTrimmed(200),\n description: nullableTrimmed(2_000).optional().default(null),\n});\n\nexport const updateProjectBodySchema = z\n .object({\n name: nonEmptyTrimmed(200).optional(),\n description: nullableTrimmed(2_000).optional(),\n defaultModelId: nullableTrimmed(200).optional(),\n slackWorkItemsEnabled: z.boolean().optional(),\n autoRunEnabled: z.boolean().optional(),\n autoApprovePlans: z.boolean().optional(),\n })\n .refine(input => Object.keys(input).length > 0, { message: 'At least one project field is required' });\n\nconst stagesSchema = z\n .array(\n z\n .string()\n .max(64)\n .regex(/^[a-z0-9][a-z0-9_-]*$/i),\n )\n .min(1)\n .max(16)\n .refine(stages => new Set(stages).size === stages.length, { message: 'Stages must be unique' });\n\nconst externalSourceSchema = z\n .object({\n integrationId: z.string().min(1).max(128),\n type: z.string().min(1).max(128),\n externalId: z.string().min(1).max(512),\n url: z.string().max(2_048).optional(),\n })\n .nullable();\n\nconst sessionSchema = z.object({\n sessionId: z.string().min(1).max(512),\n branch: z.string().min(1).max(512),\n threadId: z.string().min(1).max(512),\n});\n\nconst sessionsSchema = z.record(z.string().min(1).max(64), sessionSchema);\nconst metadataSchema = z\n .union([z.record(z.string(), z.unknown()), z.null()])\n .refine(value => {\n try {\n return JSON.stringify(value).length <= 16 * 1024;\n } catch {\n return false;\n }\n }, 'Metadata exceeds 16 KiB')\n .transform(value => {\n if (value === null) return null;\n const {\n factoryRuleMaterializationKey: _materialization,\n factoryPullRequestReconciliation: _reconciliation,\n externalSourceMissingAt: _externalSourceMissingAt,\n ...metadata\n } = value;\n return metadata;\n });\n\nexport const createWorkItemBodySchema = z.object({\n title: rawBoundedTrimmed(500),\n board: z.string().min(1).max(128).optional(),\n externalSource: externalSourceSchema.optional(),\n parentWorkItemId: uuidSchema.nullable().optional(),\n stages: stagesSchema.optional(),\n sessions: sessionsSchema.optional(),\n metadata: metadataSchema.optional(),\n});\n\nexport const updateWorkItemBodySchema = z\n .object({\n title: rawBoundedTrimmed(500).optional(),\n board: z.string().min(1).max(128).optional(),\n parentWorkItemId: uuidSchema.nullable().optional(),\n stages: stagesSchema.optional(),\n sessions: sessionsSchema.optional(),\n metadata: metadataSchema.optional(),\n plansPreapproved: z.literal(true).optional(),\n })\n .refine(input => Object.keys(input).length > 0, { message: 'At least one work-item field is required' });\n\nexport const transitionBodySchema = z\n .object({\n board: z.string().max(MAX_BOARD_IDENTIFIER_LENGTH).regex(BOARD_IDENTIFIER_RE),\n stage: z.string().max(MAX_BOARD_IDENTIFIER_LENGTH).regex(BOARD_IDENTIFIER_RE),\n expectedRevision: z.number().int().min(1),\n requestId: trimmedUuidSchema,\n cause: nonEmptyTrimmed(256),\n reenter: z.unknown().optional(),\n })\n .transform(input => ({\n board: input.board,\n stage: input.stage,\n expectedRevision: input.expectedRevision,\n ingress: { type: 'human' as const, identity: input.requestId },\n cause: input.cause,\n ...(input.reenter === true ? { reenter: true } : {}),\n }));\n\nexport const startWorkItemBodySchema = z.object({\n sessionId: trimmedUuidSchema,\n threadTitle: nonEmptyTrimmed(512),\n kickoffKey: trimmedUuidSchema,\n workItem: z.object({\n id: trimmedUuidSchema,\n role: nonEmptyTrimmed(32),\n input: createWorkItemBodySchema,\n }),\n});\n\nexport const automationRunStartBodySchema = z\n .object({\n requestId: trimmedUuidSchema,\n expectedRevision: z.number().int().min(1),\n role: z.enum(FACTORY_ROLE_VALUES),\n skillName: nonEmptyTrimmed(128),\n arguments: nonEmptyTrimmed(4_096).optional(),\n })\n .strict();\n\nexport const metricsQuerySchema = z.object({\n from: z.string().optional(),\n to: z.string().optional(),\n});\n\nconst decisionStatusSchema = z.enum([\n 'pending',\n 'proposed',\n 'dismissed',\n 'superseded',\n 'leased',\n 'retry',\n 'succeeded',\n 'failed',\n]);\nconst boundedLimitSchema = (defaultValue: number, max: number) =>\n z\n .string()\n .optional()\n .transform(value => {\n const parsed = value ? Number.parseInt(value, 10) : defaultValue;\n return Number.isFinite(parsed) ? Math.max(1, Math.min(max, parsed)) : defaultValue;\n });\nconst decisionCursorSchema = z\n .string()\n .optional()\n .transform((value, context) => {\n if (!value) return undefined;\n try {\n const decoded = JSON.parse(Buffer.from(value, 'base64url').toString('utf8')) as unknown;\n if (\n !Array.isArray(decoded) ||\n decoded.length !== 2 ||\n typeof decoded[0] !== 'string' ||\n typeof decoded[1] !== 'string'\n ) {\n throw new Error('invalid cursor');\n }\n const createdAt = new Date(decoded[0]);\n if (Number.isNaN(createdAt.getTime()) || !new RegExp(UUID_PATTERN).test(decoded[1])) {\n throw new Error('invalid cursor');\n }\n return { createdAt, id: decoded[1] };\n } catch {\n context.addIssue({ code: 'custom', message: 'Invalid cursor' });\n return z.NEVER;\n }\n });\n\nexport const decisionQuerySchema = z.object({\n statuses: z\n .string()\n .optional()\n .transform(value => {\n if (!value) return undefined;\n const statuses = [...new Set(value.split(',').map(status => status.trim()))].filter(\n status => decisionStatusSchema.safeParse(status).success,\n ) as Array<z.infer<typeof decisionStatusSchema>>;\n return statuses.length > 0 ? statuses : undefined;\n }),\n before: decisionCursorSchema,\n limit: boundedLimitSchema(25, 50),\n});\n\nconst attentionKindSchema = z.enum([\n 'automation-failed',\n 'automation-proposed',\n 'mention',\n 'activity',\n 'supervisor-finding',\n 'agent-waiting',\n]);\ntype AttentionKind = z.infer<typeof attentionKindSchema>;\ntype AttentionStreamPosition = { occurredAt: Date; id: string };\ntype AttentionCursorMap = Map<AttentionKind, AttentionStreamPosition | undefined>;\n\nfunction parseAttentionStreamPosition(value: unknown): AttentionStreamPosition | undefined {\n if (!Array.isArray(value) || value.length !== 2 || typeof value[0] !== 'string' || typeof value[1] !== 'string') {\n return undefined;\n }\n const occurredAt = new Date(value[0]);\n if (Number.isNaN(occurredAt.getTime()) || !new RegExp(UUID_PATTERN).test(value[1])) return undefined;\n return { occurredAt, id: value[1] };\n}\n\nconst attentionCursorSchema = z\n .string()\n .optional()\n .transform((value, context) => {\n if (!value) return undefined;\n try {\n const decoded: unknown = JSON.parse(Buffer.from(value, 'base64url').toString('utf8'));\n if (Array.isArray(decoded)) {\n const legacy = parseAttentionStreamPosition(decoded);\n if (!legacy) throw new Error('invalid cursor');\n return new Map<AttentionKind, AttentionStreamPosition | undefined>([['automation-failed', legacy]]);\n }\n if (!decoded || typeof decoded !== 'object') throw new Error('invalid cursor');\n const cursors: AttentionCursorMap = new Map();\n for (const [kind, positionValue] of Object.entries(decoded)) {\n const parsedKind = attentionKindSchema.safeParse(kind);\n if (!parsedKind.success) throw new Error('invalid cursor');\n if (positionValue === null) {\n cursors.set(parsedKind.data, undefined);\n continue;\n }\n const position = parseAttentionStreamPosition(positionValue);\n if (!position) throw new Error('invalid cursor');\n cursors.set(parsedKind.data, position);\n }\n if (cursors.size === 0) throw new Error('invalid cursor');\n return cursors;\n } catch {\n context.addIssue({ code: 'custom', message: 'Invalid cursor' });\n return z.NEVER;\n }\n });\n\nexport const attentionQuerySchema = z.object({\n view: z.enum(['open', 'unread', 'archived']).optional().default('open'),\n kind: z.array(attentionKindSchema).optional(),\n before: attentionCursorSchema,\n limit: boundedLimitSchema(25, 50),\n search: z\n .string()\n .optional()\n .transform(value => value?.trim().toLowerCase().slice(0, 200) || undefined),\n});\n\nconst attentionActionPathSchema = z\n .object({\n id: uuidSchema,\n kind: attentionKindSchema,\n sourceId: z.string().min(1).max(256),\n occurrence: z\n .string()\n .regex(/^(0|[1-9]\\d*)$/)\n .transform((value, context) => {\n const occurrence = Number(value);\n if (Number.isSafeInteger(occurrence)) return occurrence;\n context.addIssue({ code: 'custom', message: 'Invalid occurrence' });\n return z.NEVER;\n }),\n })\n .refine(\n input =>\n input.kind === 'supervisor-finding'\n ? /^[a-z0-9:_-]{1,256}$/i.test(input.sourceId)\n : new RegExp(UUID_PATTERN).test(input.sourceId),\n { message: 'Invalid attention source id', path: ['sourceId'] },\n );\n\nexport const FACTORY_ROUTE_CONTRACTS = {\n projectList: {\n method: 'GET',\n path: '/web/factory/projects',\n description: 'List Factory projects for the current organization',\n responseSchema: z.object({ projects: z.array(projectSchema) }),\n },\n projectCreate: {\n method: 'POST',\n path: '/web/factory/projects',\n description: 'Create a Factory project',\n bodySchema: createProjectBodySchema,\n responseSchema: projectResponseSchema,\n },\n projectGet: {\n method: 'GET',\n path: '/web/factory/projects/:id',\n description: 'Get a Factory project',\n pathSchema: projectPathSchema,\n responseSchema: projectResponseSchema,\n },\n projectUpdate: {\n method: 'PATCH',\n path: '/web/factory/projects/:id',\n description: 'Update a Factory project',\n pathSchema: projectPathSchema,\n bodySchema: updateProjectBodySchema,\n responseSchema: projectResponseSchema,\n },\n projectDelete: {\n method: 'DELETE',\n path: '/web/factory/projects/:id',\n description: 'Delete a Factory project',\n pathSchema: projectPathSchema,\n responseSchema: z.null(),\n },\n metricsGet: {\n method: 'GET',\n path: '/web/factory/projects/:id/metrics',\n description: 'Get Factory project metrics',\n pathSchema: projectPathSchema,\n querySchema: metricsQuerySchema,\n responseSchema: z.object({ metrics: entitySchema }),\n },\n healthThresholdsGet: {\n method: 'GET',\n path: '/web/factory/projects/:id/health/thresholds',\n description: 'Get queue-health thresholds',\n pathSchema: projectPathSchema,\n responseSchema: z.object({ thresholds: z.array(z.number().finite()) }),\n },\n boardCatalog: {\n method: 'GET',\n path: '/web/factory/projects/:id/boards',\n description: 'List installed Factory boards',\n pathSchema: projectPathSchema,\n responseSchema: z.object({\n boards: z.array(\n z.object({\n id: z.string(),\n title: z.string(),\n initialPhase: z.string(),\n phases: z.array(\n z.object({\n id: z.string(),\n title: z.string(),\n kind: z.enum(['resting', 'working', 'terminal']),\n role: z.string().optional(),\n transitions: z.array(z.object({ outcome: z.string().nullable(), to: z.string() })),\n }),\n ),\n }),\n ),\n }),\n },\n workItemList: {\n method: 'GET',\n path: '/web/factory/projects/:id/work-items',\n description: 'List Factory work items and running sessions',\n pathSchema: projectPathSchema,\n responseSchema: z.object({\n workItems: z.array(entitySchema),\n runningSessionIds: z.array(z.string()),\n parkedSessionIds: z.array(z.string()),\n }),\n },\n workItemCreate: {\n method: 'POST',\n path: '/web/factory/projects/:id/work-items',\n description: 'Create a work item in Intake',\n pathSchema: projectPathSchema,\n bodySchema: createWorkItemBodySchema,\n responseSchema: workItemResponseSchema,\n },\n workItemUpdate: {\n method: 'PATCH',\n path: '/web/factory/work-items/:id',\n description: 'Update non-stage work-item fields',\n pathSchema: workItemPathSchema,\n bodySchema: updateWorkItemBodySchema,\n responseSchema: workItemResponseSchema,\n },\n workItemDelete: {\n method: 'DELETE',\n path: '/web/factory/work-items/:id',\n description: 'Delete a Factory work item',\n pathSchema: workItemPathSchema,\n responseSchema: z.object({ ok: z.literal(true) }),\n },\n workItemTransition: {\n method: 'POST',\n path: '/web/factory/projects/:id/work-items/:workItemId/transition',\n description: 'Transition a work item with its expected revision',\n pathSchema: transitionPathSchema,\n bodySchema: transitionBodySchema,\n responseSchema: entitySchema,\n },\n workItemStart: {\n method: 'POST',\n path: '/web/factory/projects/:id/runs/start',\n description: 'Explicitly start a Factory work-item run',\n pathSchema: projectPathSchema,\n bodySchema: startWorkItemBodySchema,\n responseSchema: entitySchema,\n },\n workItemAutomationRun: {\n method: 'POST',\n path: '/web/factory/projects/:id/work-items/:workItemId/automation-runs',\n description: 'Enqueue an idempotent deferred skill dispatch for a trusted external orchestrator',\n pathSchema: transitionPathSchema,\n bodySchema: automationRunStartBodySchema,\n responseSchema: entitySchema,\n },\n decisionList: {\n method: 'GET',\n path: '/web/factory/projects/:id/decisions',\n description: 'List Factory decisions',\n pathSchema: projectPathSchema,\n querySchema: decisionQuerySchema,\n responseSchema: z.object({ decisions: z.array(entitySchema), nextCursor: z.string().optional() }),\n },\n decisionApprove: {\n method: 'POST',\n path: '/web/factory/projects/:id/decisions/:decisionId/approve',\n description: 'Approve a proposed Factory decision',\n pathSchema: projectDecisionPathSchema,\n responseSchema: decisionResponseSchema,\n },\n decisionDismiss: {\n method: 'POST',\n path: '/web/factory/projects/:id/decisions/:decisionId/dismiss',\n description: 'Dismiss a proposed Factory decision',\n pathSchema: projectDecisionPathSchema,\n responseSchema: decisionResponseSchema,\n },\n decisionRetry: {\n method: 'POST',\n path: '/web/factory/projects/:id/decisions/:decisionId/retry',\n description: 'Retry a failed retryable Factory decision',\n pathSchema: projectDecisionPathSchema,\n responseSchema: decisionResponseSchema,\n },\n attentionList: {\n method: 'GET',\n path: '/web/factory/projects/:id/attention',\n description: 'List the Factory attention inbox',\n pathSchema: projectPathSchema,\n querySchema: attentionQuerySchema,\n responseSchema: z.object({\n items: z.array(entitySchema),\n kinds: z.record(\n attentionKindSchema,\n z.object({\n open: z.number(),\n unread: z.number(),\n latest: z.object({ key: z.string(), at: z.string(), unread: z.boolean() }).nullable(),\n }),\n ),\n hasMore: z.boolean(),\n nextCursor: z.string().optional(),\n }),\n },\n attentionReadAll: {\n method: 'POST',\n path: '/web/factory/projects/:id/attention/read-all',\n description: 'Mark all Factory attention as read',\n pathSchema: projectPathSchema,\n querySchema: z.object({ before: attentionCursorSchema }),\n responseSchema: z.object({ ok: z.literal(true), hasMore: z.boolean(), nextCursor: z.string().optional() }),\n },\n attentionRead: {\n method: 'POST',\n path: '/web/factory/projects/:id/attention/:kind/:sourceId/:occurrence/read',\n description: 'Mark a Factory attention receipt as read',\n pathSchema: attentionActionPathSchema,\n responseSchema: z.object({ receipt: entitySchema }),\n },\n attentionArchive: {\n method: 'POST',\n path: '/web/factory/projects/:id/attention/:kind/:sourceId/:occurrence/archive',\n description: 'Archive a Factory attention receipt',\n pathSchema: attentionActionPathSchema,\n responseSchema: z.object({ receipt: entitySchema }),\n },\n attentionRestore: {\n method: 'POST',\n path: '/web/factory/projects/:id/attention/:kind/:sourceId/:occurrence/restore',\n description: 'Restore an archived Factory attention receipt',\n pathSchema: attentionActionPathSchema,\n responseSchema: z.object({ receipt: entitySchema }),\n },\n supervisorSession: {\n method: 'POST',\n path: '/web/factory/projects/:id/supervisor/session',\n description: 'Get the deterministic Factory supervisor session address',\n pathSchema: projectPathSchema,\n responseSchema: z.object({ sessionId: z.string(), threadId: z.string(), factoryProjectId: uuidSchema }),\n },\n supervisorHealth: {\n method: 'GET',\n path: '/web/factory/projects/:id/supervisor/health',\n description: 'Run the deterministic Factory supervisor health check',\n pathSchema: projectPathSchema,\n responseSchema: z.object({\n checkedAt: z.string(),\n findings: z.array(entitySchema),\n counts: z.record(z.string(), z.number().int().nonnegative()),\n }),\n },\n} as const satisfies Record<string, FactoryRouteContract>;\n\nexport type FactoryRouteContractKey = keyof typeof FACTORY_ROUTE_CONTRACTS;\n"],"mappings":"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"}
1
+ {"version":3,"file":"contracts.js","names":[],"sources":["../../src/routes/contracts.ts"],"sourcesContent":["import { z } from 'zod';\n\nimport { FACTORY_ROLE_STAGES } from '../rules/types.js';\nimport { BOARD_IDENTIFIER_RE, MAX_BOARD_IDENTIFIER_LENGTH } from '../rules/validation.js';\n\nconst FACTORY_ROLE_VALUES = Object.keys(FACTORY_ROLE_STAGES) as [string, ...string[]];\n\nexport type FactoryRouteContract = {\n method: 'GET' | 'POST' | 'PATCH' | 'DELETE';\n path: string;\n description: string;\n pathSchema?: z.ZodType;\n querySchema?: z.ZodType;\n bodySchema?: z.ZodType;\n responseSchema: z.ZodType;\n};\n\nexport const UUID_PATTERN = '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$';\nconst uuidSchema = z.string().regex(new RegExp(UUID_PATTERN));\nconst entitySchema = z.record(z.string(), z.unknown());\nconst nonEmptyTrimmed = (max: number) => z.string().trim().min(1).max(max);\nconst rawBoundedTrimmed = (max: number) =>\n z\n .string()\n .max(max)\n .transform(value => value.trim())\n .pipe(z.string().min(1));\nconst trimmedUuidSchema = z.string().trim().regex(new RegExp(UUID_PATTERN));\nconst nullableTrimmed = (max: number) =>\n z.union([\n z\n .string()\n .trim()\n .max(max)\n .transform(value => value || null),\n z.null(),\n ]);\nconst projectPathSchema = z.object({ id: uuidSchema });\nconst projectDecisionPathSchema = z.object({ id: uuidSchema, decisionId: uuidSchema });\nconst workItemPathSchema = z.object({ id: uuidSchema });\nconst transitionPathSchema = z.object({ id: uuidSchema, workItemId: uuidSchema });\n\nconst projectSchema = entitySchema;\nconst projectResponseSchema = z.object({ project: projectSchema });\nconst workItemResponseSchema = z.object({ workItem: entitySchema });\nconst decisionResponseSchema = z.object({ decision: entitySchema });\n\nexport const createProjectBodySchema = z.object({\n name: nonEmptyTrimmed(200),\n description: nullableTrimmed(2_000).optional().default(null),\n});\n\nexport const updateProjectBodySchema = z\n .object({\n name: nonEmptyTrimmed(200).optional(),\n description: nullableTrimmed(2_000).optional(),\n defaultModelId: nullableTrimmed(200).optional(),\n slackWorkItemsEnabled: z.boolean().optional(),\n autoRunEnabled: z.boolean().optional(),\n autoApprovePlans: z.boolean().optional(),\n })\n .refine(input => Object.keys(input).length > 0, { message: 'At least one project field is required' });\n\nconst stagesSchema = z\n .array(\n z\n .string()\n .max(64)\n .regex(/^[a-z0-9][a-z0-9_-]*$/i),\n )\n .min(1)\n .max(16)\n .refine(stages => new Set(stages).size === stages.length, { message: 'Stages must be unique' });\n\nconst externalSourceSchema = z\n .object({\n integrationId: z.string().min(1).max(128),\n type: z.string().min(1).max(128),\n externalId: z.string().min(1).max(512),\n url: z.string().max(2_048).optional(),\n })\n .nullable();\n\nconst sessionSchema = z.object({\n sessionId: z.string().min(1).max(512),\n branch: z.string().min(1).max(512),\n threadId: z.string().min(1).max(512),\n});\n\nconst sessionsSchema = z.record(z.string().min(1).max(64), sessionSchema);\nconst metadataSchema = z\n .union([z.record(z.string(), z.unknown()), z.null()])\n .refine(value => {\n try {\n return JSON.stringify(value).length <= 16 * 1024;\n } catch {\n return false;\n }\n }, 'Metadata exceeds 16 KiB')\n .transform(value => {\n if (value === null) return null;\n const {\n factoryRuleMaterializationKey: _materialization,\n factoryPullRequestReconciliation: _reconciliation,\n externalSourceMissingAt: _externalSourceMissingAt,\n ...metadata\n } = value;\n return metadata;\n });\n\nexport const createWorkItemBodySchema = z.object({\n title: rawBoundedTrimmed(500),\n board: z.string().min(1).max(128).optional(),\n externalSource: externalSourceSchema.optional(),\n parentWorkItemId: uuidSchema.nullable().optional(),\n stages: stagesSchema.optional(),\n sessions: sessionsSchema.optional(),\n metadata: metadataSchema.optional(),\n});\n\nexport const updateWorkItemBodySchema = z\n .object({\n title: rawBoundedTrimmed(500).optional(),\n board: z.string().min(1).max(128).optional(),\n parentWorkItemId: uuidSchema.nullable().optional(),\n stages: stagesSchema.optional(),\n sessions: sessionsSchema.optional(),\n metadata: metadataSchema.optional(),\n plansPreapproved: z.literal(true).optional(),\n })\n .refine(input => Object.keys(input).length > 0, { message: 'At least one work-item field is required' });\n\nexport const transitionBodySchema = z\n .object({\n board: z.string().max(MAX_BOARD_IDENTIFIER_LENGTH).regex(BOARD_IDENTIFIER_RE),\n stage: z.string().max(MAX_BOARD_IDENTIFIER_LENGTH).regex(BOARD_IDENTIFIER_RE),\n expectedRevision: z.number().int().min(1),\n requestId: trimmedUuidSchema,\n cause: nonEmptyTrimmed(256),\n reenter: z.unknown().optional(),\n })\n .transform(input => ({\n board: input.board,\n stage: input.stage,\n expectedRevision: input.expectedRevision,\n ingress: { type: 'human' as const, identity: input.requestId },\n cause: input.cause,\n ...(input.reenter === true ? { reenter: true } : {}),\n }));\n\nexport const startWorkItemBodySchema = z.object({\n sessionId: trimmedUuidSchema,\n threadTitle: nonEmptyTrimmed(512),\n kickoffKey: trimmedUuidSchema,\n workItem: z.object({\n id: trimmedUuidSchema,\n role: nonEmptyTrimmed(32),\n input: createWorkItemBodySchema,\n }),\n});\n\nexport const automationRunStartBodySchema = z\n .object({\n requestId: trimmedUuidSchema,\n expectedRevision: z.number().int().min(1),\n role: z.enum(FACTORY_ROLE_VALUES),\n skillName: nonEmptyTrimmed(128),\n arguments: nonEmptyTrimmed(4_096).optional(),\n })\n .strict();\n\nexport const metricsQuerySchema = z.object({\n from: z.string().optional(),\n to: z.string().optional(),\n});\n\nconst decisionStatusSchema = z.enum([\n 'pending',\n 'proposed',\n 'dismissed',\n 'superseded',\n 'leased',\n 'retry',\n 'succeeded',\n 'failed',\n]);\nconst boundedLimitSchema = (defaultValue: number, max: number) =>\n z\n .string()\n .optional()\n .transform(value => {\n const parsed = value ? Number.parseInt(value, 10) : defaultValue;\n return Number.isFinite(parsed) ? Math.max(1, Math.min(max, parsed)) : defaultValue;\n });\nconst decisionCursorSchema = z\n .string()\n .optional()\n .transform((value, context) => {\n if (!value) return undefined;\n try {\n const decoded = JSON.parse(Buffer.from(value, 'base64url').toString('utf8')) as unknown;\n if (\n !Array.isArray(decoded) ||\n decoded.length !== 2 ||\n typeof decoded[0] !== 'string' ||\n typeof decoded[1] !== 'string'\n ) {\n throw new Error('invalid cursor');\n }\n const createdAt = new Date(decoded[0]);\n if (Number.isNaN(createdAt.getTime()) || !new RegExp(UUID_PATTERN).test(decoded[1])) {\n throw new Error('invalid cursor');\n }\n return { createdAt, id: decoded[1] };\n } catch {\n context.addIssue({ code: 'custom', message: 'Invalid cursor' });\n return z.NEVER;\n }\n });\n\nexport const decisionQuerySchema = z.object({\n statuses: z\n .string()\n .optional()\n .transform(value => {\n if (!value) return undefined;\n const statuses = [...new Set(value.split(',').map(status => status.trim()))].filter(\n status => decisionStatusSchema.safeParse(status).success,\n ) as Array<z.infer<typeof decisionStatusSchema>>;\n return statuses.length > 0 ? statuses : undefined;\n }),\n before: decisionCursorSchema,\n limit: boundedLimitSchema(25, 50),\n});\n\nconst attentionKindSchema = z.enum([\n 'automation-failed',\n 'automation-proposed',\n 'mention',\n 'activity',\n 'supervisor-finding',\n 'agent-waiting',\n]);\ntype AttentionKind = z.infer<typeof attentionKindSchema>;\ntype AttentionStreamPosition = { occurredAt: Date; id: string };\ntype AttentionCursorMap = Map<AttentionKind, AttentionStreamPosition | undefined>;\n\nfunction parseAttentionStreamPosition(value: unknown): AttentionStreamPosition | undefined {\n if (!Array.isArray(value) || value.length !== 2 || typeof value[0] !== 'string' || typeof value[1] !== 'string') {\n return undefined;\n }\n const occurredAt = new Date(value[0]);\n if (Number.isNaN(occurredAt.getTime()) || !new RegExp(UUID_PATTERN).test(value[1])) return undefined;\n return { occurredAt, id: value[1] };\n}\n\nconst attentionCursorSchema = z\n .string()\n .optional()\n .transform((value, context) => {\n if (!value) return undefined;\n try {\n const decoded: unknown = JSON.parse(Buffer.from(value, 'base64url').toString('utf8'));\n if (Array.isArray(decoded)) {\n const legacy = parseAttentionStreamPosition(decoded);\n if (!legacy) throw new Error('invalid cursor');\n return new Map<AttentionKind, AttentionStreamPosition | undefined>([['automation-failed', legacy]]);\n }\n if (!decoded || typeof decoded !== 'object') throw new Error('invalid cursor');\n const cursors: AttentionCursorMap = new Map();\n for (const [kind, positionValue] of Object.entries(decoded)) {\n const parsedKind = attentionKindSchema.safeParse(kind);\n if (!parsedKind.success) throw new Error('invalid cursor');\n if (positionValue === null) {\n cursors.set(parsedKind.data, undefined);\n continue;\n }\n const position = parseAttentionStreamPosition(positionValue);\n if (!position) throw new Error('invalid cursor');\n cursors.set(parsedKind.data, position);\n }\n if (cursors.size === 0) throw new Error('invalid cursor');\n return cursors;\n } catch {\n context.addIssue({ code: 'custom', message: 'Invalid cursor' });\n return z.NEVER;\n }\n });\n\nexport const attentionQuerySchema = z.object({\n view: z.enum(['open', 'unread', 'archived']).optional().default('open'),\n kind: z.array(attentionKindSchema).optional(),\n before: attentionCursorSchema,\n limit: boundedLimitSchema(25, 50),\n search: z\n .string()\n .optional()\n .transform(value => value?.trim().toLowerCase().slice(0, 200) || undefined),\n});\n\nconst attentionActionPathSchema = z\n .object({\n id: uuidSchema,\n kind: attentionKindSchema,\n sourceId: z.string().min(1).max(256),\n occurrence: z\n .string()\n .regex(/^(0|[1-9]\\d*)$/)\n .transform((value, context) => {\n const occurrence = Number(value);\n if (Number.isSafeInteger(occurrence)) return occurrence;\n context.addIssue({ code: 'custom', message: 'Invalid occurrence' });\n return z.NEVER;\n }),\n })\n .refine(\n input =>\n input.kind === 'supervisor-finding'\n ? /^[a-z0-9:_-]{1,256}$/i.test(input.sourceId)\n : new RegExp(UUID_PATTERN).test(input.sourceId),\n { message: 'Invalid attention source id', path: ['sourceId'] },\n );\n\nexport const FACTORY_ROUTE_CONTRACTS = {\n projectList: {\n method: 'GET',\n path: '/web/factory/projects',\n description: 'List Factory projects for the current organization',\n responseSchema: z.object({ projects: z.array(projectSchema) }),\n },\n projectCreate: {\n method: 'POST',\n path: '/web/factory/projects',\n description: 'Create a Factory project',\n bodySchema: createProjectBodySchema,\n responseSchema: projectResponseSchema,\n },\n projectGet: {\n method: 'GET',\n path: '/web/factory/projects/:id',\n description: 'Get a Factory project',\n pathSchema: projectPathSchema,\n responseSchema: projectResponseSchema,\n },\n projectUpdate: {\n method: 'PATCH',\n path: '/web/factory/projects/:id',\n description: 'Update a Factory project',\n pathSchema: projectPathSchema,\n bodySchema: updateProjectBodySchema,\n responseSchema: projectResponseSchema,\n },\n projectApplyDefaultModel: {\n method: 'POST',\n path: '/web/factory/projects/:id/apply-default-model',\n description: 'Apply the Factory default model to running work and review threads',\n pathSchema: projectPathSchema,\n responseSchema: z.object({\n modelId: z.string(),\n applied: z.array(z.string()),\n skipped: z.array(\n z.object({\n threadId: z.string(),\n reason: z.enum([\n 'not-running',\n 'work-item-missing',\n 'stage-inactive',\n 'thread-missing',\n 'mode-unknown',\n 'apply-failed',\n ]),\n }),\n ),\n }),\n },\n projectDelete: {\n method: 'DELETE',\n path: '/web/factory/projects/:id',\n description: 'Delete a Factory project',\n pathSchema: projectPathSchema,\n responseSchema: z.null(),\n },\n metricsGet: {\n method: 'GET',\n path: '/web/factory/projects/:id/metrics',\n description: 'Get Factory project metrics',\n pathSchema: projectPathSchema,\n querySchema: metricsQuerySchema,\n responseSchema: z.object({ metrics: entitySchema }),\n },\n healthThresholdsGet: {\n method: 'GET',\n path: '/web/factory/projects/:id/health/thresholds',\n description: 'Get queue-health thresholds',\n pathSchema: projectPathSchema,\n responseSchema: z.object({ thresholds: z.array(z.number().finite()) }),\n },\n boardCatalog: {\n method: 'GET',\n path: '/web/factory/projects/:id/boards',\n description: 'List installed Factory boards',\n pathSchema: projectPathSchema,\n responseSchema: z.object({\n boards: z.array(\n z.object({\n id: z.string(),\n title: z.string(),\n initialPhase: z.string(),\n phases: z.array(\n z.object({\n id: z.string(),\n title: z.string(),\n kind: z.enum(['resting', 'working', 'terminal']),\n role: z.string().optional(),\n transitions: z.array(z.object({ outcome: z.string().nullable(), to: z.string() })),\n }),\n ),\n }),\n ),\n }),\n },\n workItemList: {\n method: 'GET',\n path: '/web/factory/projects/:id/work-items',\n description: 'List Factory work items and running sessions',\n pathSchema: projectPathSchema,\n responseSchema: z.object({\n workItems: z.array(entitySchema),\n runningSessionIds: z.array(z.string()),\n parkedSessionIds: z.array(z.string()),\n }),\n },\n workItemCreate: {\n method: 'POST',\n path: '/web/factory/projects/:id/work-items',\n description: 'Create a work item in Intake',\n pathSchema: projectPathSchema,\n bodySchema: createWorkItemBodySchema,\n responseSchema: workItemResponseSchema,\n },\n workItemUpdate: {\n method: 'PATCH',\n path: '/web/factory/work-items/:id',\n description: 'Update non-stage work-item fields',\n pathSchema: workItemPathSchema,\n bodySchema: updateWorkItemBodySchema,\n responseSchema: workItemResponseSchema,\n },\n workItemDelete: {\n method: 'DELETE',\n path: '/web/factory/work-items/:id',\n description: 'Delete a Factory work item',\n pathSchema: workItemPathSchema,\n responseSchema: z.object({ ok: z.literal(true) }),\n },\n workItemTransition: {\n method: 'POST',\n path: '/web/factory/projects/:id/work-items/:workItemId/transition',\n description: 'Transition a work item with its expected revision',\n pathSchema: transitionPathSchema,\n bodySchema: transitionBodySchema,\n responseSchema: entitySchema,\n },\n workItemStart: {\n method: 'POST',\n path: '/web/factory/projects/:id/runs/start',\n description: 'Explicitly start a Factory work-item run',\n pathSchema: projectPathSchema,\n bodySchema: startWorkItemBodySchema,\n responseSchema: entitySchema,\n },\n workItemAutomationRun: {\n method: 'POST',\n path: '/web/factory/projects/:id/work-items/:workItemId/automation-runs',\n description: 'Enqueue an idempotent deferred skill dispatch for a trusted external orchestrator',\n pathSchema: transitionPathSchema,\n bodySchema: automationRunStartBodySchema,\n responseSchema: entitySchema,\n },\n decisionList: {\n method: 'GET',\n path: '/web/factory/projects/:id/decisions',\n description: 'List Factory decisions',\n pathSchema: projectPathSchema,\n querySchema: decisionQuerySchema,\n responseSchema: z.object({ decisions: z.array(entitySchema), nextCursor: z.string().optional() }),\n },\n decisionApprove: {\n method: 'POST',\n path: '/web/factory/projects/:id/decisions/:decisionId/approve',\n description: 'Approve a proposed Factory decision',\n pathSchema: projectDecisionPathSchema,\n responseSchema: decisionResponseSchema,\n },\n decisionDismiss: {\n method: 'POST',\n path: '/web/factory/projects/:id/decisions/:decisionId/dismiss',\n description: 'Dismiss a proposed Factory decision',\n pathSchema: projectDecisionPathSchema,\n responseSchema: decisionResponseSchema,\n },\n decisionRetry: {\n method: 'POST',\n path: '/web/factory/projects/:id/decisions/:decisionId/retry',\n description: 'Retry a failed retryable Factory decision',\n pathSchema: projectDecisionPathSchema,\n responseSchema: decisionResponseSchema,\n },\n attentionList: {\n method: 'GET',\n path: '/web/factory/projects/:id/attention',\n description: 'List the Factory attention inbox',\n pathSchema: projectPathSchema,\n querySchema: attentionQuerySchema,\n responseSchema: z.object({\n items: z.array(entitySchema),\n kinds: z.record(\n attentionKindSchema,\n z.object({\n open: z.number(),\n unread: z.number(),\n latest: z.object({ key: z.string(), at: z.string(), unread: z.boolean() }).nullable(),\n }),\n ),\n hasMore: z.boolean(),\n nextCursor: z.string().optional(),\n }),\n },\n attentionReadAll: {\n method: 'POST',\n path: '/web/factory/projects/:id/attention/read-all',\n description: 'Mark all Factory attention as read',\n pathSchema: projectPathSchema,\n querySchema: z.object({ before: attentionCursorSchema }),\n responseSchema: z.object({ ok: z.literal(true), hasMore: z.boolean(), nextCursor: z.string().optional() }),\n },\n attentionRead: {\n method: 'POST',\n path: '/web/factory/projects/:id/attention/:kind/:sourceId/:occurrence/read',\n description: 'Mark a Factory attention receipt as read',\n pathSchema: attentionActionPathSchema,\n responseSchema: z.object({ receipt: entitySchema }),\n },\n attentionArchive: {\n method: 'POST',\n path: '/web/factory/projects/:id/attention/:kind/:sourceId/:occurrence/archive',\n description: 'Archive a Factory attention receipt',\n pathSchema: attentionActionPathSchema,\n responseSchema: z.object({ receipt: entitySchema }),\n },\n attentionRestore: {\n method: 'POST',\n path: '/web/factory/projects/:id/attention/:kind/:sourceId/:occurrence/restore',\n description: 'Restore an archived Factory attention receipt',\n pathSchema: attentionActionPathSchema,\n responseSchema: z.object({ receipt: entitySchema }),\n },\n supervisorSession: {\n method: 'POST',\n path: '/web/factory/projects/:id/supervisor/session',\n description: 'Get the deterministic Factory supervisor session address',\n pathSchema: projectPathSchema,\n responseSchema: z.object({ sessionId: z.string(), threadId: z.string(), factoryProjectId: uuidSchema }),\n },\n supervisorHealth: {\n method: 'GET',\n path: '/web/factory/projects/:id/supervisor/health',\n description: 'Run the deterministic Factory supervisor health check',\n pathSchema: projectPathSchema,\n responseSchema: z.object({\n checkedAt: z.string(),\n findings: z.array(entitySchema),\n counts: z.record(z.string(), z.number().int().nonnegative()),\n }),\n },\n} as const satisfies Record<string, FactoryRouteContract>;\n\nexport type FactoryRouteContractKey = keyof typeof FACTORY_ROUTE_CONTRACTS;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"intake.d.ts","sourceRoot":"","sources":["../../src/routes/intake.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGpD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,KAAK,EAAE,MAAM,EAAc,MAAM,2BAA2B,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAEvE,OAAO,KAAK,EAAE,YAAY,EAAoB,aAAa,EAAE,MAAM,mCAAmC,CAAC;AACvG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,aAAa,GAAG,WAAW,CAAC,CAAC;CACnD;AAYD,MAAM,WAAW,gBAAiB,SAAQ,iBAAiB;IACzD,KAAK,EAAE,YAAY,CAAC;IACpB,sCAAsC;IACtC,MAAM,EAAE,aAAa,CAAC;IACtB,uEAAuE;IACvE,QAAQ,CAAC,EAAE;QAAE,GAAG,CAAC,KAAK,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,EAAE,EAAE,MAAM,CAAA;SAAE,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAA;KAAE,CAAC;IAClF,YAAY,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACnC,wGAAwG;IACxG,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,2GAA2G;IAC3G,SAAS,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,MAAM,GAAG,QAAQ,GAAG,+BAA+B,CAAC,CAAC;CACzF;AAiID,+EAA+E;AAC/E,MAAM,WAAW,wBAAwB;IACvC,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAoDD,UAAU,aAAa;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,+EAA+E;IAC/E,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,iEAAiE;AACjE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,GAAG,aAAa,GAAG,IAAI,CAetE;AAGD,QAAA,MAAM,oBAAoB;;;;;iBAUxB,CAAC;AACH,KAAK,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAE9D,qEAAqE;AACrE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,gBAAgB,GAAG,IAAI,CAG5E;AAeD,+EAA+E;AAC/E,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CAyBpE;AAmBD,qBAAa,YAAa,SAAQ,KAAK,CAAC,gBAAgB,CAAC;;IAgBvD,MAAM,IAAI,QAAQ,EAAE;CA+UrB"}
1
+ {"version":3,"file":"intake.d.ts","sourceRoot":"","sources":["../../src/routes/intake.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGpD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,KAAK,EAAE,MAAM,EAAc,MAAM,2BAA2B,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAEvE,OAAO,KAAK,EAAE,YAAY,EAAoB,aAAa,EAAE,MAAM,mCAAmC,CAAC;AACvG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,aAAa,GAAG,WAAW,CAAC,CAAC;CACnD;AAYD,MAAM,WAAW,gBAAiB,SAAQ,iBAAiB;IACzD,KAAK,EAAE,YAAY,CAAC;IACpB,sCAAsC;IACtC,MAAM,EAAE,aAAa,CAAC;IACtB,uEAAuE;IACvE,QAAQ,CAAC,EAAE;QAAE,GAAG,CAAC,KAAK,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,EAAE,EAAE,MAAM,CAAA;SAAE,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAA;KAAE,CAAC;IAClF,YAAY,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACnC,wGAAwG;IACxG,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,2GAA2G;IAC3G,SAAS,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,MAAM,GAAG,QAAQ,GAAG,+BAA+B,CAAC,CAAC;CACzF;AAiID,+EAA+E;AAC/E,MAAM,WAAW,wBAAwB;IACvC,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAoDD,UAAU,aAAa;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,+EAA+E;IAC/E,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,iEAAiE;AACjE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,GAAG,aAAa,GAAG,IAAI,CAetE;AAGD,QAAA,MAAM,oBAAoB;;;;;iBAUxB,CAAC;AACH,KAAK,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAE9D,qEAAqE;AACrE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,gBAAgB,GAAG,IAAI,CAG5E;AAmCD,+EAA+E;AAC/E,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CAqCpE;AAmBD,qBAAa,YAAa,SAAQ,KAAK,CAAC,gBAAgB,CAAC;;IAgBvD,MAAM,IAAI,QAAQ,EAAE;CA+UrB"}
@@ -185,6 +185,17 @@ function sanitizeIdList(value) {
185
185
  const ids = value.filter((item) => typeof item === "string" && item.length > 0 && item.length <= MAX_INTAKE_SOURCE_ID_LENGTH);
186
186
  return ids.length === value.length && new Set(ids).size === ids.length ? ids : void 0;
187
187
  }
188
+ function sanitizeLinearRepositoryMap(value) {
189
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
190
+ const entries = Object.entries(value);
191
+ if (entries.length > 200) return void 0;
192
+ const mapping = Object.create(null);
193
+ for (const [projectId, slug] of entries) {
194
+ if (!projectId || projectId.length > MAX_INTAKE_SOURCE_ID_LENGTH || typeof slug !== "string" || !slug.trim() || slug.length > 512) return;
195
+ mapping[projectId] = slug;
196
+ }
197
+ return mapping;
198
+ }
188
199
  /** Validate a request body into an intake config, rejecting unknown shapes. */
189
200
  function parseIntakeConfig(body) {
190
201
  if (typeof body !== "object" || body === null || Array.isArray(body)) return null;
@@ -197,9 +208,12 @@ function parseIntakeConfig(body) {
197
208
  if (typeof selection.enabled !== "boolean") return null;
198
209
  const sourceIds = sanitizeIdList(selection.sourceIds ?? null);
199
210
  if (sourceIds === void 0) return null;
211
+ const repositoryByLinearProject = integrationId === "linear" ? sanitizeLinearRepositoryMap(selection.repositoryByLinearProject) : void 0;
212
+ if (integrationId === "linear" && selection.repositoryByLinearProject !== void 0 && repositoryByLinearProject === void 0) return null;
200
213
  config[integrationId] = {
201
214
  enabled: selection.enabled,
202
- sourceIds
215
+ sourceIds,
216
+ ...repositoryByLinearProject ? { repositoryByLinearProject } : {}
203
217
  };
204
218
  }
205
219
  return config;
@@ -1 +1 @@
1
- {"version":3,"file":"intake.js","names":["#resolveTenant"],"sources":["../../src/routes/intake.ts"],"sourcesContent":["import type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { Context } from 'hono';\nimport { z } from 'zod';\n\nimport type { BoardRegistry } from '../boards/index.js';\nimport { cardLabels, moveCardToBoard } from '../boards/relocate.js';\nimport type { Intake, IntakeItem } from '../capabilities/intake.js';\nimport type { AuditEmitter } from '../storage/domains/audit/domain.js';\nimport { normalizeIntakeLabel, resolveIntakeLabelRoute } from '../storage/domains/intake/base.js';\nimport type { IntakeConfig, IntakeLabelRoute, IntakeStorage } from '../storage/domains/intake/base.js';\nimport type { WorkItemsStorage } from '../storage/domains/work-items/base.js';\nimport type { RouteDependencies } from './route.js';\nimport { Route } from './route.js';\n\nexport interface IntakeIntegration {\n id: string;\n intake: Pick<Intake, 'listSources' | 'listItems'>;\n}\n\ninterface AggregatedIntakeItem extends Omit<IntakeItem, 'source'> {\n integrationId: string;\n externalSource: {\n integrationId: string;\n type: string;\n externalId: string;\n url?: string;\n };\n}\n\nexport interface IntakeRoutesDeps extends RouteDependencies {\n audit: AuditEmitter;\n /** Intake selection domain handle. */\n intake: IntakeStorage;\n /** Factory project domain handle, used to validate binding targets. */\n projects?: { get(input: { orgId: string; id: string }): Promise<unknown | null> };\n integrations?: IntakeIntegration[];\n /** Installed boards, used to validate binding targets. Absent means only legacy routing is accepted. */\n boardRegistry?: BoardRegistry;\n /** Work items domain handle; when present, rebinding a source to another board moves its resting cards. */\n workItems?: Pick<WorkItemsStorage, 'list' | 'update' | 'supersedeDecisionsForWorkItem'>;\n}\n\n/** Upper bound on source pages read while relocating cards, so a huge source cannot stall the request. */\nconst REBIND_MAX_PAGES = 20;\n/**\n * One deadline for the whole rebind read, not one per page: the binding is already saved when we\n * get here, so the caller is only waiting on relocation and a slow provider must not hold the\n * response for pages × timeout.\n */\nconst REBIND_READ_BUDGET_MS = 30_000;\n\n/**\n * Keys under which an intake item may be persisted as a work item. Providers key items by their\n * own id, while materialization uses the human identifier (`linear:MAS-44`), so both are accepted.\n */\nfunction intakeItemSourceKeys(integrationId: string, item: IntakeItem): string[] {\n const identifier = item.metadata?.identifier;\n return typeof identifier === 'string' && identifier.length > 0\n ? [item.source.externalId, `${integrationId}:${identifier}`]\n : [item.source.externalId];\n}\n\n/**\n * Move the cards that came from a rebound source onto its new board's initial phase. Terminal cards\n * stay put (they are history that belongs where it finished), as do cards with a session attached to\n * a current stage (a run owns them). Everything else moves, including cards parked in a working\n * phase that never started a run — auto-ingested issues sit in Work › Triage that way.\n */\nasync function relocateSourceCards({\n workItems,\n integration,\n boardRegistry,\n orgId,\n userId,\n factoryProjectId,\n sourceId,\n targetBoard,\n attributionSourceIds,\n}: {\n workItems: Pick<WorkItemsStorage, 'list' | 'update' | 'supersedeDecisionsForWorkItem'>;\n integration: IntakeIntegration;\n boardRegistry: BoardRegistry;\n orgId: string;\n userId: string;\n factoryProjectId: string;\n sourceId: string;\n targetBoard: string;\n attributionSourceIds: string[];\n}): Promise<{ moved: number; skipped: number }> {\n if (!boardRegistry.has(targetBoard)) return { moved: 0, skipped: 0 };\n\n const sourceKeys = new Set<string>();\n let cursor: string | undefined;\n const deadline = Date.now() + REBIND_READ_BUDGET_MS;\n for (let page = 0; page < REBIND_MAX_PAGES; page += 1) {\n const result = await withTimeout(\n integration.id,\n () =>\n integration.intake.listItems({\n orgId,\n userId,\n sourceIds: [sourceId],\n attributionSourceIds,\n cursor,\n }),\n deadline - Date.now(),\n );\n for (const item of result.items) {\n if (item.sourceId !== sourceId) continue;\n for (const key of intakeItemSourceKeys(integration.id, item)) sourceKeys.add(key);\n }\n if (!result.nextCursor) break;\n cursor = result.nextCursor;\n }\n if (sourceKeys.size === 0) return { moved: 0, skipped: 0 };\n\n let moved = 0;\n let skipped = 0;\n const items = await workItems.list({ orgId, factoryProjectId });\n for (const item of items) {\n const source = item.externalSource;\n if (!source || source.integrationId !== integration.id || !sourceKeys.has(source.externalId)) continue;\n const outcome = await moveCardToBoard({ workItems, boardRegistry, userId, item, targetBoard });\n if (outcome === 'moved') moved += 1;\n else if (outcome === 'skipped') skipped += 1;\n }\n return { moved, skipped };\n}\n\n/**\n * After a label route changes, every issue card in the project that carries `label` is re-routed\n * under the project's current routes: to the board its labels now select, or back to Work when none\n * of them is routed any more.\n */\nasync function relocateLabeledCards({\n workItems,\n boardRegistry,\n orgId,\n userId,\n factoryProjectId,\n integrationId,\n label,\n routes,\n}: {\n workItems: Pick<WorkItemsStorage, 'list' | 'update' | 'supersedeDecisionsForWorkItem'>;\n boardRegistry: BoardRegistry;\n orgId: string;\n userId: string;\n factoryProjectId: string;\n integrationId: string;\n label: string;\n routes: readonly IntakeLabelRoute[];\n}): Promise<{ moved: number; skipped: number }> {\n const changed = normalizeIntakeLabel(label);\n let moved = 0;\n let skipped = 0;\n for (const item of await workItems.list({ orgId, factoryProjectId })) {\n const source = item.externalSource;\n if (!source || source.integrationId !== integrationId || source.type !== 'issue') continue;\n const labels = cardLabels(item);\n if (!labels.some(candidate => normalizeIntakeLabel(candidate) === changed)) continue;\n const targetBoard = resolveIntakeLabelRoute(routes, labels)?.board ?? 'work';\n const outcome = await moveCardToBoard({ workItems, boardRegistry, userId, item, targetBoard });\n if (outcome === 'moved') moved += 1;\n else if (outcome === 'skipped') skipped += 1;\n }\n return { moved, skipped };\n}\n\n/** One integration that failed while the rest of the aggregation succeeded. */\nexport interface IntakeIntegrationFailure {\n integrationId: string;\n message: string;\n}\n\ntype SettledIntegration<T> = { integrationId: string; value: T } | IntakeIntegrationFailure;\n\nconst PROVIDER_READ_TIMEOUT_MS = 15_000;\n\n/** The Intake contract takes no abort signal, so a slow read is abandoned, not cancelled. */\nfunction withTimeout<T>(\n integrationId: string,\n read: () => Promise<T>,\n timeoutMs: number = PROVIDER_READ_TIMEOUT_MS,\n): Promise<T> {\n return new Promise((resolve, reject) => {\n const budget = Math.max(0, timeoutMs);\n const timer = setTimeout(\n () => reject(new Error(`${integrationId} did not answer within ${Math.round(budget / 1000)}s`)),\n budget,\n );\n read()\n .then(resolve, reject)\n .finally(() => clearTimeout(timer));\n });\n}\n\n/**\n * Read every integration concurrently and isolate the ones that throw or hang, so a single\n * unreachable provider degrades to a per-source error instead of failing the listing.\n */\nasync function settleByIntegration<T>(\n requests: Array<{ integrationId: string; read: () => Promise<T> }>,\n): Promise<{ pages: Array<{ integrationId: string; value: T }>; failures: IntakeIntegrationFailure[] }> {\n const settled = await Promise.all(\n requests.map(async ({ integrationId, read }): Promise<SettledIntegration<T>> => {\n try {\n return { integrationId, value: await withTimeout(integrationId, read) };\n } catch (error) {\n console.error(`[factory] intake integration ${integrationId} is unavailable:`, error);\n return { integrationId, message: error instanceof Error ? error.message : String(error) };\n }\n }),\n );\n const pages: Array<{ integrationId: string; value: T }> = [];\n const failures: IntakeIntegrationFailure[] = [];\n for (const entry of settled) {\n if ('value' in entry) pages.push(entry);\n else failures.push(entry);\n }\n return { pages, failures };\n}\n\nconst MAX_INTAKE_SOURCE_ID_LENGTH = 1024;\n\ninterface ParsedBinding {\n integrationId: string;\n sourceId: string;\n factoryProjectId: string | null;\n /** Installed board target; `null`/omitted keeps legacy source-type routing. */\n board: string | null;\n}\n\n/** Validate a binding request body, rejecting unknown shapes. */\nexport function parseIntakeBinding(body: unknown): ParsedBinding | null {\n if (typeof body !== 'object' || body === null || Array.isArray(body)) return null;\n const { integrationId, sourceId, factoryProjectId, board } = body as Record<string, unknown>;\n const isId = (value: unknown) => typeof value === 'string' && value.length > 0 && value.length <= 256;\n const isSourceId = (value: unknown) =>\n typeof value === 'string' && value.length > 0 && value.length <= MAX_INTAKE_SOURCE_ID_LENGTH;\n if (!isId(integrationId) || !isSourceId(sourceId)) return null;\n if (factoryProjectId !== null && !isId(factoryProjectId)) return null;\n if (board !== undefined && board !== null && !isId(board)) return null;\n return {\n integrationId: integrationId as string,\n sourceId: sourceId as string,\n factoryProjectId: factoryProjectId as string | null,\n board: (board as string | null | undefined) ?? null,\n };\n}\n\nconst identifier = z.string().min(1).max(256);\nconst labelRouteBodySchema = z.object({\n factoryProjectId: identifier,\n integrationId: identifier,\n label: z\n .string()\n .max(256)\n .transform(normalizeIntakeLabel)\n .refine(label => label.length > 0, 'label must not be blank'),\n /** Installed board target; `null` removes the route so the label falls back to Work. */\n board: identifier.nullish().transform(board => board ?? null),\n});\ntype ParsedLabelRoute = z.output<typeof labelRouteBodySchema>;\n\n/** Validate a label-route request body, rejecting unknown shapes. */\nexport function parseIntakeLabelRoute(body: unknown): ParsedLabelRoute | null {\n const parsed = labelRouteBodySchema.safeParse(body);\n return parsed.success ? parsed.data : null;\n}\n\nfunction loose(c: unknown): Context {\n return c as Context;\n}\n\nfunction sanitizeIdList(value: unknown): string[] | null | undefined {\n if (value === null) return null;\n if (!Array.isArray(value) || value.length > 200) return undefined;\n const ids = value.filter(\n (item): item is string => typeof item === 'string' && item.length > 0 && item.length <= MAX_INTAKE_SOURCE_ID_LENGTH,\n );\n return ids.length === value.length && new Set(ids).size === ids.length ? ids : undefined;\n}\n\n/** Validate a request body into an intake config, rejecting unknown shapes. */\nexport function parseIntakeConfig(body: unknown): IntakeConfig | null {\n if (typeof body !== 'object' || body === null || Array.isArray(body)) return null;\n const entries = Object.entries(body);\n if (entries.length > 50) return null;\n\n // Null-prototype so an `__proto__` key lands as a real entry instead of silently\n // reassigning the prototype and disappearing from the validation below.\n const config: IntakeConfig = Object.create(null);\n for (const [integrationId, value] of entries) {\n if (\n !integrationId ||\n integrationId.length > 128 ||\n typeof value !== 'object' ||\n value === null ||\n Array.isArray(value)\n ) {\n return null;\n }\n const selection = value as { enabled?: unknown; sourceIds?: unknown };\n if (typeof selection.enabled !== 'boolean') return null;\n const sourceIds = sanitizeIdList(selection.sourceIds ?? null);\n if (sourceIds === undefined) return null;\n config[integrationId] = { enabled: selection.enabled, sourceIds };\n }\n return config;\n}\n\nfunction encodeCursor(cursors: Record<string, string>): string | null {\n return Object.keys(cursors).length > 0 ? Buffer.from(JSON.stringify(cursors)).toString('base64url') : null;\n}\n\nfunction decodeCursor(value: string | undefined): Record<string, string> | null {\n if (!value) return {};\n try {\n const parsed = JSON.parse(Buffer.from(value, 'base64url').toString('utf8')) as unknown;\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) return null;\n const entries = Object.entries(parsed);\n if (entries.some(([key, cursor]) => !key || typeof cursor !== 'string')) return null;\n return Object.fromEntries(entries) as Record<string, string>;\n } catch {\n return null;\n }\n}\n\nexport class IntakeRoutes extends Route<IntakeRoutesDeps> {\n async #resolveTenant(c: Context): Promise<{ orgId: string; userId: string } | { response: Response }> {\n await this.deps.auth.ensureUser(c);\n const tenant = this.deps.auth.tenant(c);\n if (!tenant) return { response: c.json({ error: 'unauthorized' }, 401) };\n if (!tenant.orgId) {\n return {\n response: c.json(\n { error: 'organization_required', message: 'Intake configuration requires an organization.' },\n 403,\n ),\n };\n }\n return { orgId: tenant.orgId, userId: tenant.userId };\n }\n\n routes(): ApiRoute[] {\n const { audit, intake, projects, integrations = [], boardRegistry, workItems } = this.deps;\n const integrationIds = integrations.map(integration => integration.id);\n\n return [\n registerApiRoute('/web/intake/config', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n await intake.ensureReady();\n const config = await intake.getConfig({ orgId: tenant.orgId, integrationIds });\n return c.json({ config });\n },\n }),\n registerApiRoute('/web/intake/config', {\n method: 'PUT',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const config = parseIntakeConfig(body);\n if (!config) {\n return c.json({ error: 'invalid_config' }, 400);\n }\n\n const registeredConfig: IntakeConfig = Object.create(null);\n for (const [integrationId, selection] of Object.entries(config)) {\n if (integrationIds.includes(integrationId)) {\n registeredConfig[integrationId] = selection;\n continue;\n }\n if (selection.enabled || selection.sourceIds?.length) {\n return c.json({ error: 'invalid_config' }, 400);\n }\n }\n\n await intake.ensureReady();\n await intake.saveConfig({ orgId: tenant.orgId, config: registeredConfig });\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.intake.config_updated',\n targets: [{ type: 'intake_config', id: tenant.orgId }],\n metadata: Object.fromEntries(\n Object.entries(registeredConfig).map(([integrationId, selection]) => [\n integrationId,\n { enabled: selection.enabled, sources: selection.sourceIds?.length ?? null },\n ]),\n ),\n },\n });\n return c.json({ config: registeredConfig });\n },\n }),\n registerApiRoute('/web/intake/bindings', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n await intake.ensureReady();\n return c.json({ bindings: await intake.listBindings({ orgId: tenant.orgId }) });\n },\n }),\n registerApiRoute('/web/intake/bindings', {\n method: 'PUT',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const binding = parseIntakeBinding(body);\n if (!binding || !integrationIds.includes(binding.integrationId)) {\n return c.json({ error: 'invalid_binding' }, 400);\n }\n if (binding.factoryProjectId && projects) {\n const project = await projects.get({ orgId: tenant.orgId, id: binding.factoryProjectId });\n if (!project) return c.json({ error: 'factory_project_not_found' }, 404);\n }\n if (binding.board !== null && !boardRegistry?.has(binding.board)) {\n return c.json({ error: 'invalid_board', message: `Board '${binding.board}' is not installed.` }, 422);\n }\n\n await intake.ensureReady();\n let auditFactoryProjectId = binding.factoryProjectId;\n let relocated: { moved: number; skipped: number } | null = null;\n if (binding.factoryProjectId === null) {\n const previousBinding = await intake.clearBinding({\n orgId: tenant.orgId,\n integrationId: binding.integrationId,\n sourceId: binding.sourceId,\n });\n auditFactoryProjectId = previousBinding?.factoryProjectId ?? null;\n } else {\n const previousBinding = await intake.getBinding({\n orgId: tenant.orgId,\n integrationId: binding.integrationId,\n sourceId: binding.sourceId,\n });\n await intake.setBinding({\n orgId: tenant.orgId,\n userId: tenant.userId,\n integrationId: binding.integrationId,\n sourceId: binding.sourceId,\n factoryProjectId: binding.factoryProjectId,\n board: binding.board,\n });\n // A source that stays in the same project but is pointed at a different board\n // takes its resting cards along. Bindings that predate persisted boards have a\n // null board yet still fed Work/Review, so relocation compares each card's\n // effective board rather than trusting the previous binding value.\n const nextBoard = binding.board;\n const integration = integrations.find(candidate => candidate.id === binding.integrationId);\n if (\n workItems &&\n boardRegistry &&\n integration &&\n previousBinding?.factoryProjectId === binding.factoryProjectId &&\n nextBoard !== null &&\n previousBinding.board !== nextBoard\n ) {\n try {\n const config = await intake.getConfig({\n orgId: tenant.orgId,\n integrationIds: [binding.integrationId],\n });\n const configuredSourceIds = config[binding.integrationId]?.sourceIds ?? [];\n const attributionSourceIds = configuredSourceIds.includes(binding.sourceId)\n ? configuredSourceIds\n : [...configuredSourceIds, binding.sourceId];\n relocated = await relocateSourceCards({\n workItems,\n integration,\n boardRegistry,\n orgId: tenant.orgId,\n userId: tenant.userId,\n factoryProjectId: binding.factoryProjectId,\n sourceId: binding.sourceId,\n attributionSourceIds,\n targetBoard: nextBoard,\n });\n } catch (error) {\n // The binding is saved; the cards can be moved by hand if the provider was unreachable.\n console.error(`[factory] intake rebind could not relocate ${binding.integrationId} cards:`, error);\n }\n }\n }\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.intake.binding_updated',\n ...(auditFactoryProjectId ? { factoryProjectId: auditFactoryProjectId } : {}),\n targets: [{ type: 'intake_source', id: `${binding.integrationId}:${binding.sourceId}` }],\n metadata: {\n factoryProjectId: binding.factoryProjectId,\n board: binding.board,\n ...(relocated ? { relocated } : {}),\n },\n },\n });\n return c.json({\n bindings: await intake.listBindings({ orgId: tenant.orgId }),\n ...(relocated ? { relocated } : {}),\n });\n },\n }),\n registerApiRoute('/web/intake/label-routes', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n const factoryProjectId = c.req.query('factoryProjectId');\n await intake.ensureReady();\n return c.json({\n routes: await intake.listLabelRoutes({\n orgId: tenant.orgId,\n ...(factoryProjectId ? { factoryProjectId } : {}),\n }),\n });\n },\n }),\n registerApiRoute('/web/intake/label-routes', {\n method: 'PUT',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const route = parseIntakeLabelRoute(body);\n if (!route || !integrationIds.includes(route.integrationId)) {\n return c.json({ error: 'invalid_label_route' }, 400);\n }\n if (projects) {\n const project = await projects.get({ orgId: tenant.orgId, id: route.factoryProjectId });\n if (!project) return c.json({ error: 'factory_project_not_found' }, 404);\n }\n if (route.board !== null && !boardRegistry?.has(route.board)) {\n return c.json({ error: 'invalid_board', message: `Board '${route.board}' is not installed.` }, 422);\n }\n\n await intake.ensureReady();\n const scope = {\n orgId: tenant.orgId,\n factoryProjectId: route.factoryProjectId,\n integrationId: route.integrationId,\n };\n const previous = (await intake.listLabelRoutes(scope)).find(existing => existing.label === route.label);\n if (route.board === null) {\n await intake.clearLabelRoute({ ...scope, label: route.label });\n } else {\n await intake.setLabelRoute({ ...scope, label: route.label, board: route.board, userId: tenant.userId });\n }\n\n // Cards already carrying the label follow the route: onto the new board, or back to\n // Work when the label is no longer routed anywhere.\n let relocated: { moved: number; skipped: number } | null = null;\n if (workItems && boardRegistry && (previous?.board ?? null) !== route.board) {\n try {\n relocated = await relocateLabeledCards({\n workItems,\n boardRegistry,\n orgId: tenant.orgId,\n userId: tenant.userId,\n factoryProjectId: route.factoryProjectId,\n integrationId: route.integrationId,\n label: route.label,\n routes: await intake.listLabelRoutes(scope),\n });\n } catch (error) {\n // The route is saved; the cards can be moved by hand.\n console.error(`[factory] intake label route could not relocate ${route.integrationId} cards:`, error);\n }\n }\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.intake.label_route_updated',\n factoryProjectId: route.factoryProjectId,\n targets: [{ type: 'intake_label_route', id: `${route.integrationId}:${route.label}` }],\n metadata: { board: route.board, ...(relocated ? { relocated } : {}) },\n },\n });\n return c.json({\n routes: await intake.listLabelRoutes({ orgId: tenant.orgId, factoryProjectId: route.factoryProjectId }),\n ...(relocated ? { relocated } : {}),\n });\n },\n }),\n registerApiRoute('/web/intake/sources', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n const { pages, failures } = await settleByIntegration(\n integrations.map(integration => ({\n integrationId: integration.id,\n read: () => integration.intake.listSources(tenant),\n })),\n );\n return c.json({\n sources: pages.flatMap(({ integrationId, value }) => value.map(source => ({ integrationId, ...source }))),\n failures,\n });\n },\n }),\n registerApiRoute('/web/intake/items', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n const cursors = decodeCursor(c.req.query('cursor'));\n if (!cursors) return c.json({ error: 'invalid_cursor' }, 400);\n\n await intake.ensureReady();\n const config = await intake.getConfig({ orgId: tenant.orgId, integrationIds });\n const { pages, failures } = await settleByIntegration(\n integrations.flatMap(integration => {\n const selection = config[integration.id];\n if (!selection?.enabled || !selection.sourceIds?.length) return [];\n const sourceIds = selection.sourceIds;\n const cursor = cursors[integration.id];\n return [\n {\n integrationId: integration.id,\n read: () => integration.intake.listItems({ ...tenant, sourceIds, ...(cursor ? { cursor } : {}) }),\n },\n ];\n }),\n );\n\n const items: AggregatedIntakeItem[] = [];\n const nextCursors: Record<string, string> = {};\n for (const { integrationId, value } of pages) {\n items.push(\n ...value.items.map(item => {\n const { source, ...candidate } = item;\n return { ...candidate, integrationId, externalSource: { integrationId, ...source } };\n }),\n );\n if (value.nextCursor) nextCursors[integrationId] = value.nextCursor;\n }\n // Keep the cursor an unavailable integration came in with, so the next page resumes there instead of replaying it.\n for (const { integrationId } of failures) {\n const cursor = cursors[integrationId];\n if (cursor) nextCursors[integrationId] = cursor;\n }\n return c.json({ items, nextCursor: encodeCursor(nextCursors), failures });\n },\n }),\n ];\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"intake.js","names":["#resolveTenant"],"sources":["../../src/routes/intake.ts"],"sourcesContent":["import type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { Context } from 'hono';\nimport { z } from 'zod';\n\nimport type { BoardRegistry } from '../boards/index.js';\nimport { cardLabels, moveCardToBoard } from '../boards/relocate.js';\nimport type { Intake, IntakeItem } from '../capabilities/intake.js';\nimport type { AuditEmitter } from '../storage/domains/audit/domain.js';\nimport { normalizeIntakeLabel, resolveIntakeLabelRoute } from '../storage/domains/intake/base.js';\nimport type { IntakeConfig, IntakeLabelRoute, IntakeStorage } from '../storage/domains/intake/base.js';\nimport type { WorkItemsStorage } from '../storage/domains/work-items/base.js';\nimport type { RouteDependencies } from './route.js';\nimport { Route } from './route.js';\n\nexport interface IntakeIntegration {\n id: string;\n intake: Pick<Intake, 'listSources' | 'listItems'>;\n}\n\ninterface AggregatedIntakeItem extends Omit<IntakeItem, 'source'> {\n integrationId: string;\n externalSource: {\n integrationId: string;\n type: string;\n externalId: string;\n url?: string;\n };\n}\n\nexport interface IntakeRoutesDeps extends RouteDependencies {\n audit: AuditEmitter;\n /** Intake selection domain handle. */\n intake: IntakeStorage;\n /** Factory project domain handle, used to validate binding targets. */\n projects?: { get(input: { orgId: string; id: string }): Promise<unknown | null> };\n integrations?: IntakeIntegration[];\n /** Installed boards, used to validate binding targets. Absent means only legacy routing is accepted. */\n boardRegistry?: BoardRegistry;\n /** Work items domain handle; when present, rebinding a source to another board moves its resting cards. */\n workItems?: Pick<WorkItemsStorage, 'list' | 'update' | 'supersedeDecisionsForWorkItem'>;\n}\n\n/** Upper bound on source pages read while relocating cards, so a huge source cannot stall the request. */\nconst REBIND_MAX_PAGES = 20;\n/**\n * One deadline for the whole rebind read, not one per page: the binding is already saved when we\n * get here, so the caller is only waiting on relocation and a slow provider must not hold the\n * response for pages × timeout.\n */\nconst REBIND_READ_BUDGET_MS = 30_000;\n\n/**\n * Keys under which an intake item may be persisted as a work item. Providers key items by their\n * own id, while materialization uses the human identifier (`linear:MAS-44`), so both are accepted.\n */\nfunction intakeItemSourceKeys(integrationId: string, item: IntakeItem): string[] {\n const identifier = item.metadata?.identifier;\n return typeof identifier === 'string' && identifier.length > 0\n ? [item.source.externalId, `${integrationId}:${identifier}`]\n : [item.source.externalId];\n}\n\n/**\n * Move the cards that came from a rebound source onto its new board's initial phase. Terminal cards\n * stay put (they are history that belongs where it finished), as do cards with a session attached to\n * a current stage (a run owns them). Everything else moves, including cards parked in a working\n * phase that never started a run — auto-ingested issues sit in Work › Triage that way.\n */\nasync function relocateSourceCards({\n workItems,\n integration,\n boardRegistry,\n orgId,\n userId,\n factoryProjectId,\n sourceId,\n targetBoard,\n attributionSourceIds,\n}: {\n workItems: Pick<WorkItemsStorage, 'list' | 'update' | 'supersedeDecisionsForWorkItem'>;\n integration: IntakeIntegration;\n boardRegistry: BoardRegistry;\n orgId: string;\n userId: string;\n factoryProjectId: string;\n sourceId: string;\n targetBoard: string;\n attributionSourceIds: string[];\n}): Promise<{ moved: number; skipped: number }> {\n if (!boardRegistry.has(targetBoard)) return { moved: 0, skipped: 0 };\n\n const sourceKeys = new Set<string>();\n let cursor: string | undefined;\n const deadline = Date.now() + REBIND_READ_BUDGET_MS;\n for (let page = 0; page < REBIND_MAX_PAGES; page += 1) {\n const result = await withTimeout(\n integration.id,\n () =>\n integration.intake.listItems({\n orgId,\n userId,\n sourceIds: [sourceId],\n attributionSourceIds,\n cursor,\n }),\n deadline - Date.now(),\n );\n for (const item of result.items) {\n if (item.sourceId !== sourceId) continue;\n for (const key of intakeItemSourceKeys(integration.id, item)) sourceKeys.add(key);\n }\n if (!result.nextCursor) break;\n cursor = result.nextCursor;\n }\n if (sourceKeys.size === 0) return { moved: 0, skipped: 0 };\n\n let moved = 0;\n let skipped = 0;\n const items = await workItems.list({ orgId, factoryProjectId });\n for (const item of items) {\n const source = item.externalSource;\n if (!source || source.integrationId !== integration.id || !sourceKeys.has(source.externalId)) continue;\n const outcome = await moveCardToBoard({ workItems, boardRegistry, userId, item, targetBoard });\n if (outcome === 'moved') moved += 1;\n else if (outcome === 'skipped') skipped += 1;\n }\n return { moved, skipped };\n}\n\n/**\n * After a label route changes, every issue card in the project that carries `label` is re-routed\n * under the project's current routes: to the board its labels now select, or back to Work when none\n * of them is routed any more.\n */\nasync function relocateLabeledCards({\n workItems,\n boardRegistry,\n orgId,\n userId,\n factoryProjectId,\n integrationId,\n label,\n routes,\n}: {\n workItems: Pick<WorkItemsStorage, 'list' | 'update' | 'supersedeDecisionsForWorkItem'>;\n boardRegistry: BoardRegistry;\n orgId: string;\n userId: string;\n factoryProjectId: string;\n integrationId: string;\n label: string;\n routes: readonly IntakeLabelRoute[];\n}): Promise<{ moved: number; skipped: number }> {\n const changed = normalizeIntakeLabel(label);\n let moved = 0;\n let skipped = 0;\n for (const item of await workItems.list({ orgId, factoryProjectId })) {\n const source = item.externalSource;\n if (!source || source.integrationId !== integrationId || source.type !== 'issue') continue;\n const labels = cardLabels(item);\n if (!labels.some(candidate => normalizeIntakeLabel(candidate) === changed)) continue;\n const targetBoard = resolveIntakeLabelRoute(routes, labels)?.board ?? 'work';\n const outcome = await moveCardToBoard({ workItems, boardRegistry, userId, item, targetBoard });\n if (outcome === 'moved') moved += 1;\n else if (outcome === 'skipped') skipped += 1;\n }\n return { moved, skipped };\n}\n\n/** One integration that failed while the rest of the aggregation succeeded. */\nexport interface IntakeIntegrationFailure {\n integrationId: string;\n message: string;\n}\n\ntype SettledIntegration<T> = { integrationId: string; value: T } | IntakeIntegrationFailure;\n\nconst PROVIDER_READ_TIMEOUT_MS = 15_000;\n\n/** The Intake contract takes no abort signal, so a slow read is abandoned, not cancelled. */\nfunction withTimeout<T>(\n integrationId: string,\n read: () => Promise<T>,\n timeoutMs: number = PROVIDER_READ_TIMEOUT_MS,\n): Promise<T> {\n return new Promise((resolve, reject) => {\n const budget = Math.max(0, timeoutMs);\n const timer = setTimeout(\n () => reject(new Error(`${integrationId} did not answer within ${Math.round(budget / 1000)}s`)),\n budget,\n );\n read()\n .then(resolve, reject)\n .finally(() => clearTimeout(timer));\n });\n}\n\n/**\n * Read every integration concurrently and isolate the ones that throw or hang, so a single\n * unreachable provider degrades to a per-source error instead of failing the listing.\n */\nasync function settleByIntegration<T>(\n requests: Array<{ integrationId: string; read: () => Promise<T> }>,\n): Promise<{ pages: Array<{ integrationId: string; value: T }>; failures: IntakeIntegrationFailure[] }> {\n const settled = await Promise.all(\n requests.map(async ({ integrationId, read }): Promise<SettledIntegration<T>> => {\n try {\n return { integrationId, value: await withTimeout(integrationId, read) };\n } catch (error) {\n console.error(`[factory] intake integration ${integrationId} is unavailable:`, error);\n return { integrationId, message: error instanceof Error ? error.message : String(error) };\n }\n }),\n );\n const pages: Array<{ integrationId: string; value: T }> = [];\n const failures: IntakeIntegrationFailure[] = [];\n for (const entry of settled) {\n if ('value' in entry) pages.push(entry);\n else failures.push(entry);\n }\n return { pages, failures };\n}\n\nconst MAX_INTAKE_SOURCE_ID_LENGTH = 1024;\n\ninterface ParsedBinding {\n integrationId: string;\n sourceId: string;\n factoryProjectId: string | null;\n /** Installed board target; `null`/omitted keeps legacy source-type routing. */\n board: string | null;\n}\n\n/** Validate a binding request body, rejecting unknown shapes. */\nexport function parseIntakeBinding(body: unknown): ParsedBinding | null {\n if (typeof body !== 'object' || body === null || Array.isArray(body)) return null;\n const { integrationId, sourceId, factoryProjectId, board } = body as Record<string, unknown>;\n const isId = (value: unknown) => typeof value === 'string' && value.length > 0 && value.length <= 256;\n const isSourceId = (value: unknown) =>\n typeof value === 'string' && value.length > 0 && value.length <= MAX_INTAKE_SOURCE_ID_LENGTH;\n if (!isId(integrationId) || !isSourceId(sourceId)) return null;\n if (factoryProjectId !== null && !isId(factoryProjectId)) return null;\n if (board !== undefined && board !== null && !isId(board)) return null;\n return {\n integrationId: integrationId as string,\n sourceId: sourceId as string,\n factoryProjectId: factoryProjectId as string | null,\n board: (board as string | null | undefined) ?? null,\n };\n}\n\nconst identifier = z.string().min(1).max(256);\nconst labelRouteBodySchema = z.object({\n factoryProjectId: identifier,\n integrationId: identifier,\n label: z\n .string()\n .max(256)\n .transform(normalizeIntakeLabel)\n .refine(label => label.length > 0, 'label must not be blank'),\n /** Installed board target; `null` removes the route so the label falls back to Work. */\n board: identifier.nullish().transform(board => board ?? null),\n});\ntype ParsedLabelRoute = z.output<typeof labelRouteBodySchema>;\n\n/** Validate a label-route request body, rejecting unknown shapes. */\nexport function parseIntakeLabelRoute(body: unknown): ParsedLabelRoute | null {\n const parsed = labelRouteBodySchema.safeParse(body);\n return parsed.success ? parsed.data : null;\n}\n\nfunction loose(c: unknown): Context {\n return c as Context;\n}\n\nfunction sanitizeIdList(value: unknown): string[] | null | undefined {\n if (value === null) return null;\n if (!Array.isArray(value) || value.length > 200) return undefined;\n const ids = value.filter(\n (item): item is string => typeof item === 'string' && item.length > 0 && item.length <= MAX_INTAKE_SOURCE_ID_LENGTH,\n );\n return ids.length === value.length && new Set(ids).size === ids.length ? ids : undefined;\n}\n\nfunction sanitizeLinearRepositoryMap(value: unknown): Record<string, string> | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined;\n const entries = Object.entries(value);\n if (entries.length > 200) return undefined;\n const mapping: Record<string, string> = Object.create(null);\n for (const [projectId, slug] of entries) {\n if (\n !projectId ||\n projectId.length > MAX_INTAKE_SOURCE_ID_LENGTH ||\n typeof slug !== 'string' ||\n !slug.trim() ||\n slug.length > 512\n ) {\n return undefined;\n }\n mapping[projectId] = slug;\n }\n return mapping;\n}\n\n/** Validate a request body into an intake config, rejecting unknown shapes. */\nexport function parseIntakeConfig(body: unknown): IntakeConfig | null {\n if (typeof body !== 'object' || body === null || Array.isArray(body)) return null;\n const entries = Object.entries(body);\n if (entries.length > 50) return null;\n\n // Null-prototype so an `__proto__` key lands as a real entry instead of silently\n // reassigning the prototype and disappearing from the validation below.\n const config: IntakeConfig = Object.create(null);\n for (const [integrationId, value] of entries) {\n if (\n !integrationId ||\n integrationId.length > 128 ||\n typeof value !== 'object' ||\n value === null ||\n Array.isArray(value)\n ) {\n return null;\n }\n const selection = value as { enabled?: unknown; sourceIds?: unknown; repositoryByLinearProject?: unknown };\n if (typeof selection.enabled !== 'boolean') return null;\n const sourceIds = sanitizeIdList(selection.sourceIds ?? null);\n if (sourceIds === undefined) return null;\n const repositoryByLinearProject =\n integrationId === 'linear' ? sanitizeLinearRepositoryMap(selection.repositoryByLinearProject) : undefined;\n if (\n integrationId === 'linear' &&\n selection.repositoryByLinearProject !== undefined &&\n repositoryByLinearProject === undefined\n )\n return null;\n config[integrationId] = {\n enabled: selection.enabled,\n sourceIds,\n ...(repositoryByLinearProject ? { repositoryByLinearProject } : {}),\n };\n }\n return config;\n}\n\nfunction encodeCursor(cursors: Record<string, string>): string | null {\n return Object.keys(cursors).length > 0 ? Buffer.from(JSON.stringify(cursors)).toString('base64url') : null;\n}\n\nfunction decodeCursor(value: string | undefined): Record<string, string> | null {\n if (!value) return {};\n try {\n const parsed = JSON.parse(Buffer.from(value, 'base64url').toString('utf8')) as unknown;\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) return null;\n const entries = Object.entries(parsed);\n if (entries.some(([key, cursor]) => !key || typeof cursor !== 'string')) return null;\n return Object.fromEntries(entries) as Record<string, string>;\n } catch {\n return null;\n }\n}\n\nexport class IntakeRoutes extends Route<IntakeRoutesDeps> {\n async #resolveTenant(c: Context): Promise<{ orgId: string; userId: string } | { response: Response }> {\n await this.deps.auth.ensureUser(c);\n const tenant = this.deps.auth.tenant(c);\n if (!tenant) return { response: c.json({ error: 'unauthorized' }, 401) };\n if (!tenant.orgId) {\n return {\n response: c.json(\n { error: 'organization_required', message: 'Intake configuration requires an organization.' },\n 403,\n ),\n };\n }\n return { orgId: tenant.orgId, userId: tenant.userId };\n }\n\n routes(): ApiRoute[] {\n const { audit, intake, projects, integrations = [], boardRegistry, workItems } = this.deps;\n const integrationIds = integrations.map(integration => integration.id);\n\n return [\n registerApiRoute('/web/intake/config', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n await intake.ensureReady();\n const config = await intake.getConfig({ orgId: tenant.orgId, integrationIds });\n return c.json({ config });\n },\n }),\n registerApiRoute('/web/intake/config', {\n method: 'PUT',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const config = parseIntakeConfig(body);\n if (!config) {\n return c.json({ error: 'invalid_config' }, 400);\n }\n\n const registeredConfig: IntakeConfig = Object.create(null);\n for (const [integrationId, selection] of Object.entries(config)) {\n if (integrationIds.includes(integrationId)) {\n registeredConfig[integrationId] = selection;\n continue;\n }\n if (selection.enabled || selection.sourceIds?.length) {\n return c.json({ error: 'invalid_config' }, 400);\n }\n }\n\n await intake.ensureReady();\n await intake.saveConfig({ orgId: tenant.orgId, config: registeredConfig });\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.intake.config_updated',\n targets: [{ type: 'intake_config', id: tenant.orgId }],\n metadata: Object.fromEntries(\n Object.entries(registeredConfig).map(([integrationId, selection]) => [\n integrationId,\n { enabled: selection.enabled, sources: selection.sourceIds?.length ?? null },\n ]),\n ),\n },\n });\n return c.json({ config: registeredConfig });\n },\n }),\n registerApiRoute('/web/intake/bindings', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n await intake.ensureReady();\n return c.json({ bindings: await intake.listBindings({ orgId: tenant.orgId }) });\n },\n }),\n registerApiRoute('/web/intake/bindings', {\n method: 'PUT',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const binding = parseIntakeBinding(body);\n if (!binding || !integrationIds.includes(binding.integrationId)) {\n return c.json({ error: 'invalid_binding' }, 400);\n }\n if (binding.factoryProjectId && projects) {\n const project = await projects.get({ orgId: tenant.orgId, id: binding.factoryProjectId });\n if (!project) return c.json({ error: 'factory_project_not_found' }, 404);\n }\n if (binding.board !== null && !boardRegistry?.has(binding.board)) {\n return c.json({ error: 'invalid_board', message: `Board '${binding.board}' is not installed.` }, 422);\n }\n\n await intake.ensureReady();\n let auditFactoryProjectId = binding.factoryProjectId;\n let relocated: { moved: number; skipped: number } | null = null;\n if (binding.factoryProjectId === null) {\n const previousBinding = await intake.clearBinding({\n orgId: tenant.orgId,\n integrationId: binding.integrationId,\n sourceId: binding.sourceId,\n });\n auditFactoryProjectId = previousBinding?.factoryProjectId ?? null;\n } else {\n const previousBinding = await intake.getBinding({\n orgId: tenant.orgId,\n integrationId: binding.integrationId,\n sourceId: binding.sourceId,\n });\n await intake.setBinding({\n orgId: tenant.orgId,\n userId: tenant.userId,\n integrationId: binding.integrationId,\n sourceId: binding.sourceId,\n factoryProjectId: binding.factoryProjectId,\n board: binding.board,\n });\n // A source that stays in the same project but is pointed at a different board\n // takes its resting cards along. Bindings that predate persisted boards have a\n // null board yet still fed Work/Review, so relocation compares each card's\n // effective board rather than trusting the previous binding value.\n const nextBoard = binding.board;\n const integration = integrations.find(candidate => candidate.id === binding.integrationId);\n if (\n workItems &&\n boardRegistry &&\n integration &&\n previousBinding?.factoryProjectId === binding.factoryProjectId &&\n nextBoard !== null &&\n previousBinding.board !== nextBoard\n ) {\n try {\n const config = await intake.getConfig({\n orgId: tenant.orgId,\n integrationIds: [binding.integrationId],\n });\n const configuredSourceIds = config[binding.integrationId]?.sourceIds ?? [];\n const attributionSourceIds = configuredSourceIds.includes(binding.sourceId)\n ? configuredSourceIds\n : [...configuredSourceIds, binding.sourceId];\n relocated = await relocateSourceCards({\n workItems,\n integration,\n boardRegistry,\n orgId: tenant.orgId,\n userId: tenant.userId,\n factoryProjectId: binding.factoryProjectId,\n sourceId: binding.sourceId,\n attributionSourceIds,\n targetBoard: nextBoard,\n });\n } catch (error) {\n // The binding is saved; the cards can be moved by hand if the provider was unreachable.\n console.error(`[factory] intake rebind could not relocate ${binding.integrationId} cards:`, error);\n }\n }\n }\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.intake.binding_updated',\n ...(auditFactoryProjectId ? { factoryProjectId: auditFactoryProjectId } : {}),\n targets: [{ type: 'intake_source', id: `${binding.integrationId}:${binding.sourceId}` }],\n metadata: {\n factoryProjectId: binding.factoryProjectId,\n board: binding.board,\n ...(relocated ? { relocated } : {}),\n },\n },\n });\n return c.json({\n bindings: await intake.listBindings({ orgId: tenant.orgId }),\n ...(relocated ? { relocated } : {}),\n });\n },\n }),\n registerApiRoute('/web/intake/label-routes', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n const factoryProjectId = c.req.query('factoryProjectId');\n await intake.ensureReady();\n return c.json({\n routes: await intake.listLabelRoutes({\n orgId: tenant.orgId,\n ...(factoryProjectId ? { factoryProjectId } : {}),\n }),\n });\n },\n }),\n registerApiRoute('/web/intake/label-routes', {\n method: 'PUT',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const route = parseIntakeLabelRoute(body);\n if (!route || !integrationIds.includes(route.integrationId)) {\n return c.json({ error: 'invalid_label_route' }, 400);\n }\n if (projects) {\n const project = await projects.get({ orgId: tenant.orgId, id: route.factoryProjectId });\n if (!project) return c.json({ error: 'factory_project_not_found' }, 404);\n }\n if (route.board !== null && !boardRegistry?.has(route.board)) {\n return c.json({ error: 'invalid_board', message: `Board '${route.board}' is not installed.` }, 422);\n }\n\n await intake.ensureReady();\n const scope = {\n orgId: tenant.orgId,\n factoryProjectId: route.factoryProjectId,\n integrationId: route.integrationId,\n };\n const previous = (await intake.listLabelRoutes(scope)).find(existing => existing.label === route.label);\n if (route.board === null) {\n await intake.clearLabelRoute({ ...scope, label: route.label });\n } else {\n await intake.setLabelRoute({ ...scope, label: route.label, board: route.board, userId: tenant.userId });\n }\n\n // Cards already carrying the label follow the route: onto the new board, or back to\n // Work when the label is no longer routed anywhere.\n let relocated: { moved: number; skipped: number } | null = null;\n if (workItems && boardRegistry && (previous?.board ?? null) !== route.board) {\n try {\n relocated = await relocateLabeledCards({\n workItems,\n boardRegistry,\n orgId: tenant.orgId,\n userId: tenant.userId,\n factoryProjectId: route.factoryProjectId,\n integrationId: route.integrationId,\n label: route.label,\n routes: await intake.listLabelRoutes(scope),\n });\n } catch (error) {\n // The route is saved; the cards can be moved by hand.\n console.error(`[factory] intake label route could not relocate ${route.integrationId} cards:`, error);\n }\n }\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.intake.label_route_updated',\n factoryProjectId: route.factoryProjectId,\n targets: [{ type: 'intake_label_route', id: `${route.integrationId}:${route.label}` }],\n metadata: { board: route.board, ...(relocated ? { relocated } : {}) },\n },\n });\n return c.json({\n routes: await intake.listLabelRoutes({ orgId: tenant.orgId, factoryProjectId: route.factoryProjectId }),\n ...(relocated ? { relocated } : {}),\n });\n },\n }),\n registerApiRoute('/web/intake/sources', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n const { pages, failures } = await settleByIntegration(\n integrations.map(integration => ({\n integrationId: integration.id,\n read: () => integration.intake.listSources(tenant),\n })),\n );\n return c.json({\n sources: pages.flatMap(({ integrationId, value }) => value.map(source => ({ integrationId, ...source }))),\n failures,\n });\n },\n }),\n registerApiRoute('/web/intake/items', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n const cursors = decodeCursor(c.req.query('cursor'));\n if (!cursors) return c.json({ error: 'invalid_cursor' }, 400);\n\n await intake.ensureReady();\n const config = await intake.getConfig({ orgId: tenant.orgId, integrationIds });\n const { pages, failures } = await settleByIntegration(\n integrations.flatMap(integration => {\n const selection = config[integration.id];\n if (!selection?.enabled || !selection.sourceIds?.length) return [];\n const sourceIds = selection.sourceIds;\n const cursor = cursors[integration.id];\n return [\n {\n integrationId: integration.id,\n read: () => integration.intake.listItems({ ...tenant, sourceIds, ...(cursor ? { cursor } : {}) }),\n },\n ];\n }),\n );\n\n const items: AggregatedIntakeItem[] = [];\n const nextCursors: Record<string, string> = {};\n for (const { integrationId, value } of pages) {\n items.push(\n ...value.items.map(item => {\n const { source, ...candidate } = item;\n return { ...candidate, integrationId, externalSource: { integrationId, ...source } };\n }),\n );\n if (value.nextCursor) nextCursors[integrationId] = value.nextCursor;\n }\n // Keep the cursor an unavailable integration came in with, so the next page resumes there instead of replaying it.\n for (const { integrationId } of failures) {\n const cursor = cursors[integrationId];\n if (cursor) nextCursors[integrationId] = cursor;\n }\n return c.json({ items, nextCursor: encodeCursor(nextCursors), failures });\n },\n }),\n ];\n }\n}\n"],"mappings":"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"}