@mastra/factory 0.15.0 → 0.16.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 (212) hide show
  1. package/README.md +4 -3
  2. package/dist/boards/index.d.ts +1 -1
  3. package/dist/boards/index.d.ts.map +1 -1
  4. package/dist/boards/index.js +2 -2
  5. package/dist/boards/index.js.map +1 -1
  6. package/dist/boards/review.d.ts.map +1 -1
  7. package/dist/boards/review.js +4 -1
  8. package/dist/boards/review.js.map +1 -1
  9. package/dist/boards/semantics.d.ts +7 -0
  10. package/dist/boards/semantics.d.ts.map +1 -1
  11. package/dist/boards/semantics.js +15 -1
  12. package/dist/boards/semantics.js.map +1 -1
  13. package/dist/boards/transition-policy.d.ts +4 -0
  14. package/dist/boards/transition-policy.d.ts.map +1 -1
  15. package/dist/boards/transition-policy.js.map +1 -1
  16. package/dist/boards/work-transition-policy.d.ts.map +1 -1
  17. package/dist/boards/work-transition-policy.js +6 -1
  18. package/dist/boards/work-transition-policy.js.map +1 -1
  19. package/dist/boards/work.d.ts.map +1 -1
  20. package/dist/boards/work.js +37 -3
  21. package/dist/boards/work.js.map +1 -1
  22. package/dist/capabilities/intake.d.ts +4 -0
  23. package/dist/capabilities/intake.d.ts.map +1 -1
  24. package/dist/factory.d.ts +6 -3
  25. package/dist/factory.d.ts.map +1 -1
  26. package/dist/factory.js +66 -18
  27. package/dist/factory.js.map +1 -1
  28. package/dist/integrations/base.d.ts +6 -2
  29. package/dist/integrations/base.d.ts.map +1 -1
  30. package/dist/integrations/incidentio/agent-tools.d.ts +49 -0
  31. package/dist/integrations/incidentio/agent-tools.d.ts.map +1 -0
  32. package/dist/integrations/incidentio/agent-tools.js +90 -0
  33. package/dist/integrations/incidentio/agent-tools.js.map +1 -0
  34. package/dist/integrations/incidentio/claim.d.ts +8 -0
  35. package/dist/integrations/incidentio/claim.d.ts.map +1 -0
  36. package/dist/integrations/incidentio/claim.js +14 -0
  37. package/dist/integrations/incidentio/claim.js.map +1 -0
  38. package/dist/integrations/incidentio/default-rules.d.ts +46 -0
  39. package/dist/integrations/incidentio/default-rules.d.ts.map +1 -0
  40. package/dist/integrations/incidentio/default-rules.js +66 -0
  41. package/dist/integrations/incidentio/default-rules.js.map +1 -0
  42. package/dist/integrations/incidentio/integration.d.ts +48 -2
  43. package/dist/integrations/incidentio/integration.d.ts.map +1 -1
  44. package/dist/integrations/incidentio/integration.js +88 -2
  45. package/dist/integrations/incidentio/integration.js.map +1 -1
  46. package/dist/integrations/incidentio/issue-reconciler.d.ts +2 -0
  47. package/dist/integrations/incidentio/issue-reconciler.d.ts.map +1 -1
  48. package/dist/integrations/incidentio/issue-reconciler.js +38 -2
  49. package/dist/integrations/incidentio/issue-reconciler.js.map +1 -1
  50. package/dist/integrations/incidentio/routes.d.ts +71 -0
  51. package/dist/integrations/incidentio/routes.d.ts.map +1 -0
  52. package/dist/integrations/incidentio/routes.js +245 -0
  53. package/dist/integrations/incidentio/routes.js.map +1 -0
  54. package/dist/integrations/incidentio/rules.d.ts +55 -0
  55. package/dist/integrations/incidentio/rules.d.ts.map +1 -0
  56. package/dist/integrations/incidentio/rules.js +175 -0
  57. package/dist/integrations/incidentio/rules.js.map +1 -0
  58. package/dist/integrations/jira/adf.d.ts +26 -0
  59. package/dist/integrations/jira/adf.d.ts.map +1 -0
  60. package/dist/integrations/jira/adf.js +73 -0
  61. package/dist/integrations/jira/adf.js.map +1 -0
  62. package/dist/integrations/jira/agent-tools.d.ts +45 -0
  63. package/dist/integrations/jira/agent-tools.d.ts.map +1 -0
  64. package/dist/integrations/jira/agent-tools.js +87 -0
  65. package/dist/integrations/jira/agent-tools.js.map +1 -0
  66. package/dist/integrations/jira/api.d.ts +157 -0
  67. package/dist/integrations/jira/api.d.ts.map +1 -0
  68. package/dist/integrations/jira/api.js +141 -0
  69. package/dist/integrations/jira/api.js.map +1 -0
  70. package/dist/integrations/jira/claim.d.ts +9 -0
  71. package/dist/integrations/jira/claim.d.ts.map +1 -0
  72. package/dist/integrations/jira/claim.js +15 -0
  73. package/dist/integrations/jira/claim.js.map +1 -0
  74. package/dist/integrations/jira/default-rules.d.ts +47 -0
  75. package/dist/integrations/jira/default-rules.d.ts.map +1 -0
  76. package/dist/integrations/jira/default-rules.js +67 -0
  77. package/dist/integrations/jira/default-rules.js.map +1 -0
  78. package/dist/integrations/jira/integration.d.ts +114 -0
  79. package/dist/integrations/jira/integration.d.ts.map +1 -0
  80. package/dist/integrations/jira/integration.js +401 -0
  81. package/dist/integrations/jira/integration.js.map +1 -0
  82. package/dist/integrations/jira/issue-reconciler.d.ts +10 -0
  83. package/dist/integrations/jira/issue-reconciler.d.ts.map +1 -0
  84. package/dist/integrations/jira/issue-reconciler.js +70 -0
  85. package/dist/integrations/jira/issue-reconciler.js.map +1 -0
  86. package/dist/integrations/jira/reconciliation-config.d.ts +3 -0
  87. package/dist/integrations/jira/reconciliation-config.d.ts.map +1 -0
  88. package/dist/integrations/jira/reconciliation-config.js +17 -0
  89. package/dist/integrations/jira/reconciliation-config.js.map +1 -0
  90. package/dist/integrations/jira/routes.d.ts +54 -0
  91. package/dist/integrations/jira/routes.d.ts.map +1 -0
  92. package/dist/integrations/jira/routes.js +260 -0
  93. package/dist/integrations/jira/routes.js.map +1 -0
  94. package/dist/integrations/jira/rules.d.ts +57 -0
  95. package/dist/integrations/jira/rules.d.ts.map +1 -0
  96. package/dist/integrations/jira/rules.js +175 -0
  97. package/dist/integrations/jira/rules.js.map +1 -0
  98. package/dist/integrations/linear/claim.d.ts +8 -0
  99. package/dist/integrations/linear/claim.d.ts.map +1 -0
  100. package/dist/integrations/linear/claim.js +14 -0
  101. package/dist/integrations/linear/claim.js.map +1 -0
  102. package/dist/integrations/linear/default-rules.d.ts +1 -0
  103. package/dist/integrations/linear/default-rules.d.ts.map +1 -1
  104. package/dist/integrations/linear/default-rules.js +2 -0
  105. package/dist/integrations/linear/default-rules.js.map +1 -1
  106. package/dist/integrations/linear/integration.d.ts +24 -6
  107. package/dist/integrations/linear/integration.d.ts.map +1 -1
  108. package/dist/integrations/linear/integration.js +257 -37
  109. package/dist/integrations/linear/integration.js.map +1 -1
  110. package/dist/integrations/linear/routes.d.ts +10 -0
  111. package/dist/integrations/linear/routes.d.ts.map +1 -1
  112. package/dist/integrations/linear/routes.js +74 -12
  113. package/dist/integrations/linear/routes.js.map +1 -1
  114. package/dist/integrations/linear/rules.d.ts +1 -1
  115. package/dist/integrations/linear/rules.d.ts.map +1 -1
  116. package/dist/integrations/linear/rules.js +27 -2
  117. package/dist/integrations/linear/rules.js.map +1 -1
  118. package/dist/integrations/platform/connect/routes.d.ts +39 -0
  119. package/dist/integrations/platform/connect/routes.d.ts.map +1 -0
  120. package/dist/integrations/platform/connect/routes.js +129 -0
  121. package/dist/integrations/platform/connect/routes.js.map +1 -0
  122. package/dist/integrations/platform/github/event-worker.js +1 -1
  123. package/dist/integrations/platform/github/integration.js +1 -1
  124. package/dist/integrations/platform/incidentio/integration.d.ts +61 -4
  125. package/dist/integrations/platform/incidentio/integration.d.ts.map +1 -1
  126. package/dist/integrations/platform/incidentio/integration.js +371 -22
  127. package/dist/integrations/platform/incidentio/integration.js.map +1 -1
  128. package/dist/integrations/platform/jira/agent-tools.d.ts +36 -0
  129. package/dist/integrations/platform/jira/agent-tools.d.ts.map +1 -0
  130. package/dist/integrations/platform/jira/agent-tools.js +85 -0
  131. package/dist/integrations/platform/jira/agent-tools.js.map +1 -0
  132. package/dist/integrations/platform/jira/integration.d.ts +65 -0
  133. package/dist/integrations/platform/jira/integration.d.ts.map +1 -0
  134. package/dist/integrations/platform/jira/integration.js +540 -0
  135. package/dist/integrations/platform/jira/integration.js.map +1 -0
  136. package/dist/integrations/platform/jira/routes.d.ts +55 -0
  137. package/dist/integrations/platform/jira/routes.d.ts.map +1 -0
  138. package/dist/integrations/platform/jira/routes.js +274 -0
  139. package/dist/integrations/platform/jira/routes.js.map +1 -0
  140. package/dist/integrations/platform/linear/integration.d.ts +34 -1
  141. package/dist/integrations/platform/linear/integration.d.ts.map +1 -1
  142. package/dist/integrations/platform/linear/integration.js +271 -48
  143. package/dist/integrations/platform/linear/integration.js.map +1 -1
  144. package/dist/routes/intake.d.ts.map +1 -1
  145. package/dist/routes/intake.js +15 -5
  146. package/dist/routes/intake.js.map +1 -1
  147. package/dist/routes/oauth.js +2 -5
  148. package/dist/routes/oauth.js.map +1 -1
  149. package/dist/routes/surface.d.ts.map +1 -1
  150. package/dist/routes/surface.js +24 -4
  151. package/dist/routes/surface.js.map +1 -1
  152. package/dist/rules/dispatch-errors.d.ts.map +1 -1
  153. package/dist/rules/dispatch-errors.js +8 -0
  154. package/dist/rules/dispatch-errors.js.map +1 -1
  155. package/dist/rules/dispatcher.d.ts +1 -0
  156. package/dist/rules/dispatcher.d.ts.map +1 -1
  157. package/dist/rules/dispatcher.js +180 -106
  158. package/dist/rules/dispatcher.js.map +1 -1
  159. package/dist/rules/index.d.ts +2 -2
  160. package/dist/rules/index.d.ts.map +1 -1
  161. package/dist/rules/index.js +2 -2
  162. package/dist/rules/start-coordinator.d.ts.map +1 -1
  163. package/dist/rules/start-coordinator.js +4 -1
  164. package/dist/rules/start-coordinator.js.map +1 -1
  165. package/dist/rules/terminal-cleanup.d.ts +14 -1
  166. package/dist/rules/terminal-cleanup.d.ts.map +1 -1
  167. package/dist/rules/terminal-cleanup.js +20 -0
  168. package/dist/rules/terminal-cleanup.js.map +1 -1
  169. package/dist/rules/tools.d.ts +2 -0
  170. package/dist/rules/tools.d.ts.map +1 -1
  171. package/dist/rules/tools.js +30 -2
  172. package/dist/rules/tools.js.map +1 -1
  173. package/dist/rules/transition-service.d.ts +13 -0
  174. package/dist/rules/transition-service.d.ts.map +1 -1
  175. package/dist/rules/transition-service.js +11 -2
  176. package/dist/rules/transition-service.js.map +1 -1
  177. package/dist/rules/types.d.ts +72 -3
  178. package/dist/rules/types.d.ts.map +1 -1
  179. package/dist/rules/types.js +9 -1
  180. package/dist/rules/types.js.map +1 -1
  181. package/dist/rules/validation.d.ts.map +1 -1
  182. package/dist/rules/validation.js +13 -2
  183. package/dist/rules/validation.js.map +1 -1
  184. package/dist/session/run-audit.d.ts +9 -0
  185. package/dist/session/run-audit.d.ts.map +1 -1
  186. package/dist/session/run-audit.js +37 -6
  187. package/dist/session/run-audit.js.map +1 -1
  188. package/dist/skills/service.d.ts +12 -0
  189. package/dist/skills/service.d.ts.map +1 -1
  190. package/dist/skills/service.js +27 -1
  191. package/dist/skills/service.js.map +1 -1
  192. package/dist/storage/domains/intake/base.d.ts +11 -8
  193. package/dist/storage/domains/intake/base.d.ts.map +1 -1
  194. package/dist/storage/domains/intake/base.js +69 -24
  195. package/dist/storage/domains/intake/base.js.map +1 -1
  196. package/dist/storage/domains/work-items/base.d.ts +41 -2
  197. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  198. package/dist/storage/domains/work-items/base.js +159 -12
  199. package/dist/storage/domains/work-items/base.js.map +1 -1
  200. package/dist/supervisor/session-messaging.d.ts +23 -0
  201. package/dist/supervisor/session-messaging.d.ts.map +1 -0
  202. package/dist/supervisor/session-messaging.js +15 -0
  203. package/dist/supervisor/session-messaging.js.map +1 -0
  204. package/dist/supervisor/write-tools.d.ts +2 -1
  205. package/dist/supervisor/write-tools.d.ts.map +1 -1
  206. package/dist/supervisor/write-tools.js +11 -7
  207. package/dist/supervisor/write-tools.js.map +1 -1
  208. package/dist/work-item-branch.d.ts +1 -1
  209. package/dist/work-item-branch.d.ts.map +1 -1
  210. package/dist/work-item-branch.js +4 -2
  211. package/dist/work-item-branch.js.map +1 -1
  212. package/package.json +11 -11
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration.js","names":["#clientConfig","#platformClient","#endpointHost","#cloudIdByConnectionId","#siteUrlByConnectionId","#orgIdByResourceId","#rules","#projects","#auth","#activeConnections","#resolveIntakeDispatch","#listSources","#listItems","#listIssues","#getIssue","#createComment","#updateIssue","#connectionContext","#connectionContextById","#toIntakeIssue","#findIssue","#listAllComments","#resolveRequest","#cloudId"],"sources":["../../../../src/integrations/platform/jira/integration.ts"],"sourcesContent":["import type { RequestContext } from '@mastra/core/request-context';\nimport type { ApiRoute } from '@mastra/core/server';\nimport type { MastraWorker } from '@mastra/core/worker';\n\nimport type { IntegrationConnection } from '../../../capabilities/connection.js';\nimport type {\n CreateIntakeCommentInput,\n CreatedIntakeComment,\n GetIntakeIssueInput,\n Intake,\n IntakeIssue,\n IntakeIssueDetail,\n IntakeItemPage,\n IntakeSource,\n ListIntakeIssuesInput,\n ListIntakeItemsInput,\n ResolveIntakeDispatchInput,\n ResolvedIntakeDispatch,\n UpdateIntakeIssueInput,\n} from '../../../capabilities/intake.js';\nimport type { RouteAuth } from '../../../routes/route.js';\nimport type { FactoryProjectsStorage } from '../../../storage/domains/projects/base.js';\nimport type { FactoryIntegration, IntegrationContext, IntegrationTools } from '../../base.js';\nimport { IssueReconcileWorker } from '../../issue-reconcile-worker.js';\nimport { adfToText } from '../../jira/adf.js';\nimport type { JiraComment, JiraIssue, JiraTransition } from '../../jira/api.js';\nimport { JiraApiClient, JiraApiError } from '../../jira/api.js';\nimport type { JiraEventRules, JiraRuleOverrides } from '../../jira/default-rules.js';\nimport { resolveJiraRules } from '../../jira/default-rules.js';\nimport { attachJiraIssueReconciler } from '../../jira/issue-reconciler.js';\nimport { jiraReconciliationEnabled, jiraReconciliationInterval } from '../../jira/reconciliation-config.js';\nimport { attachJiraRules } from '../../jira/rules.js';\nimport {\n logPlatformInfo,\n PlatformApiClient,\n platformApiClientConfigFromEnv,\n type PlatformApiClientConfig,\n} from '../api-client.js';\nimport { buildPlatformJiraAgentTools } from './agent-tools.js';\nimport { buildPlatformJiraRoutes } from './routes.js';\n\ninterface PlatformIntegrationConnection {\n id: string;\n integrationId: string;\n status: 'active' | 'needs_reauth';\n accountLabel: string | null;\n}\n\ninterface JiraConnectionContext {\n connection: PlatformIntegrationConnection;\n api: JiraApiClient;\n siteUrl: string;\n}\n\ninterface PlatformConnectionContextResponse {\n connection_config: Record<string, unknown> | null;\n metadata: Record<string, unknown> | null;\n}\n\ninterface JiraIssueReference {\n connectionId: string;\n issueId: string;\n projectId?: string;\n}\n\ninterface JiraPageCursor {\n group: number;\n jira?: string;\n}\n\nconst ISSUE_COMMENTS_MAX_PAGES = 20;\n\n/** Hard stop for project pagination so a misbehaving `isLast` can't loop forever. */\nconst PROJECT_SEARCH_MAX_PAGES = 50;\nconst ISSUE_KEY_PATTERN = /^[A-Za-z][A-Za-z0-9_]*-\\d+$/;\nconst PLATFORM_JIRA_PROVIDER_CONFIG_KEY = 'jira';\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nconst JIRA_CONNECTION_TOKEN_PREFIX = 'jira-connection:';\nconst JIRA_ISSUE_REF_PREFIX = 'jira-issue:';\nconst JIRA_SOURCE_PREFIX = 'jira-project:';\n\nconst STATE_TYPE_TO_CATEGORY: Record<'unstarted' | 'started' | 'completed', string> = {\n unstarted: 'new',\n started: 'indeterminate',\n completed: 'done',\n};\n\nfunction stateTypeFromCategory(key: string | undefined): string | null {\n switch (key) {\n case 'new':\n return 'unstarted';\n case 'indeterminate':\n return 'started';\n case 'done':\n return 'completed';\n default:\n return null;\n }\n}\n\nexport interface PlatformJiraIntegrationConfig {\n clientConfig?: PlatformApiClientConfig;\n /** Per-event replacements; omitted events retain defaults, null disables. */\n rules?: JiraRuleOverrides;\n}\n\nexport class PlatformJiraIntegration implements FactoryIntegration {\n readonly id = 'jira';\n readonly #clientConfig: PlatformApiClientConfig;\n readonly #platformClient: PlatformApiClient;\n readonly #endpointHost: string;\n readonly #cloudIdByConnectionId = new Map<string, string>();\n readonly #siteUrlByConnectionId = new Map<string, string>();\n #projects: FactoryProjectsStorage | undefined;\n #auth: RouteAuth | undefined;\n readonly #orgIdByResourceId = new Map<string, string | null>();\n\n readonly #rules: JiraEventRules;\n\n get rules(): JiraEventRules {\n return this.#rules;\n }\n\n constructor(config: PlatformJiraIntegrationConfig = {}) {\n this.#rules = resolveJiraRules(config.rules);\n this.#clientConfig = config.clientConfig ?? platformApiClientConfigFromEnv();\n this.#platformClient = new PlatformApiClient(this.#clientConfig);\n this.#endpointHost = new URL(this.#clientConfig.baseUrl).host;\n }\n\n initialize({ projects, auth }: { projects: FactoryProjectsStorage; auth: RouteAuth }): void {\n this.#projects = projects;\n this.#auth = auth;\n logPlatformInfo('Platform Jira integration initialized', { endpointHost: this.#endpointHost });\n }\n\n get projects(): FactoryProjectsStorage {\n if (!this.#projects)\n throw new Error('PlatformJiraIntegration is not initialized — the factory binds storage during prepare().');\n return this.#projects;\n }\n\n get authEnabled(): boolean {\n return this.#auth?.enabled() ?? false;\n }\n\n async resolveOrgId(resourceId: string): Promise<string | null> {\n const cached = this.#orgIdByResourceId.get(resourceId);\n if (cached !== undefined) return cached;\n if (!UUID_PATTERN.test(resourceId)) {\n this.#orgIdByResourceId.set(resourceId, null);\n return null;\n }\n try {\n await this.projects.ensureReady();\n const project = await this.projects.getById({ id: resourceId });\n const orgId = project?.orgId ?? null;\n this.#orgIdByResourceId.set(resourceId, orgId);\n return orgId;\n } catch {\n return null;\n }\n }\n\n clearCaches(): void {\n this.#orgIdByResourceId.clear();\n this.#cloudIdByConnectionId.clear();\n this.#siteUrlByConnectionId.clear();\n }\n\n async listConnections(): Promise<PlatformIntegrationConnection[]> {\n const providerKey = encodeURIComponent(PLATFORM_JIRA_PROVIDER_CONFIG_KEY);\n const result = await this.#platformClient.request<{ connections: PlatformIntegrationConnection[] }>(\n 'GET',\n `/v2/connections?providerKey=${providerKey}`,\n );\n return result.connections;\n }\n\n async hasActiveConnections(): Promise<boolean> {\n return (await this.#activeConnections()).length > 0;\n }\n\n readonly intake: Intake = {\n resolveIntakeDispatch: input => this.#resolveIntakeDispatch(input),\n listSources: () => this.#listSources(),\n listItems: input => this.#listItems(input),\n listIssues: input => this.#listIssues(input),\n getIssue: input => this.#getIssue(input),\n createComment: input => this.#createComment(input),\n updateIssue: input => this.#updateIssue(input),\n };\n\n async #resolveIntakeDispatch({ externalSource }: ResolveIntakeDispatchInput): Promise<ResolvedIntakeDispatch | null> {\n if (externalSource.type !== 'issue') return null;\n const reference = decodeIssueReference(externalSource.externalId);\n if (!reference) return null;\n return {\n connection: jiraConnection(reference.connectionId),\n ...(reference.projectId ? { sourceId: encodeSourceId(reference.connectionId, reference.projectId) } : {}),\n issueId: reference.issueId,\n };\n }\n\n async #listSources(): Promise<IntakeSource[]> {\n const sources: IntakeSource[] = [];\n for (const connection of await this.#activeConnections()) {\n const context = await this.#connectionContext(connection);\n let startAt = 0;\n for (let pageCount = 0; pageCount < PROJECT_SEARCH_MAX_PAGES; pageCount++) {\n const page = await context.api.listProjects({ startAt });\n for (const project of page.values) {\n sources.push({\n id: encodeSourceId(connection.id, project.id),\n name: project.name,\n type: 'project',\n metadata: {\n key: project.key,\n connectionId: connection.id,\n site: new URL(context.siteUrl).host,\n },\n });\n }\n if (page.isLast || page.values.length === 0) break;\n startAt += page.values.length;\n }\n }\n return sources;\n }\n\n async #listItems({ sourceIds, cursor }: ListIntakeItemsInput): Promise<IntakeItemPage> {\n if (sourceIds.length === 0) return { items: [], nextCursor: null };\n const page = await this.listActiveIssues(cursor, sourceIds);\n return {\n items: page.issues.map(issue => ({\n source: { type: 'issue', externalId: issue.externalId, url: issue.url },\n sourceId: issue.sourceId,\n title: `${issue.identifier}: ${issue.title}`,\n status: issue.state ?? undefined,\n labels: issue.labels,\n assignee: issue.assignee,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n metadata: {\n identifier: issue.identifier,\n issueRef: issue.externalId,\n state: issue.state,\n stateType: issue.stateType,\n priority: issue.priority,\n project: issue.source,\n site: issue.site,\n assignee: issue.assignee,\n assignees: issue.assignees ?? [],\n creator: issue.author,\n author: issue.author,\n labels: issue.labels,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n },\n })),\n nextCursor: page.nextCursor,\n };\n }\n\n async #listIssues(input: ListIntakeIssuesInput): Promise<{ issues: IntakeIssue[]; nextCursor: string | null }> {\n const page = await this.listActiveIssues(input.cursor, input.sourceIds, input.labels);\n return { issues: page.issues, nextCursor: page.nextCursor };\n }\n\n async listActiveIssues(\n cursor?: string,\n sourceIds: string[] = [],\n labels?: string[],\n ): Promise<{\n issues: Array<IntakeIssue & { sourceId: string; externalId: string; site: string }>;\n nextCursor: string | null;\n }> {\n const grouped = groupSources(sourceIds);\n if (grouped.length === 0) return { issues: [], nextCursor: null };\n const decodedCursor = decodePageCursor(cursor);\n if (decodedCursor.group >= grouped.length) return { issues: [], nextCursor: null };\n\n for (let groupIndex = decodedCursor.group; groupIndex < grouped.length; groupIndex++) {\n const group = grouped[groupIndex]!;\n const context = await this.#connectionContextById(group.connectionId);\n const jql = buildIntakeJql(group.projectIds, labels);\n if (jql === null) continue;\n const page = await context.api.searchIssues({\n jql,\n ...(groupIndex === decodedCursor.group && decodedCursor.jira ? { nextPageToken: decodedCursor.jira } : {}),\n });\n const nextCursor = page.nextPageToken\n ? encodePageCursor({ group: groupIndex, jira: page.nextPageToken })\n : groupIndex + 1 < grouped.length\n ? encodePageCursor({ group: groupIndex + 1 })\n : null;\n return {\n issues: page.issues.map(issue => {\n const projectId = issue.fields.project?.id ?? group.projectIds[0] ?? '';\n return {\n ...this.#toIntakeIssue(issue, context.siteUrl),\n sourceId: encodeSourceId(group.connectionId, projectId),\n externalId: encodeIssueReference({ connectionId: group.connectionId, issueId: issue.key, projectId }),\n site: new URL(context.siteUrl).host,\n };\n }),\n nextCursor,\n };\n }\n return { issues: [], nextCursor: null };\n }\n\n async #getIssue(input: GetIntakeIssueInput): Promise<IntakeIssueDetail | null> {\n const { context, issue } = (await this.#findIssue(input)) ?? {};\n if (!context || !issue) return null;\n const { comments, total } = await this.#listAllComments(context.api, issue.key);\n return {\n ...this.#toIntakeIssue(issue, context.siteUrl),\n commentCount: total,\n description: issue.fields.description ? adfToText(issue.fields.description) || null : null,\n comments: comments.map(comment => ({\n author: comment.author?.displayName ?? null,\n body: adfToText(comment.body),\n createdAt: comment.created,\n })),\n };\n }\n\n async #listAllComments(api: JiraApiClient, keyOrId: string): Promise<{ comments: JiraComment[]; total: number }> {\n const comments: JiraComment[] = [];\n let total = 0;\n for (let page = 0; page < ISSUE_COMMENTS_MAX_PAGES; page++) {\n const result = await api.listComments(keyOrId, { startAt: comments.length });\n comments.push(...result.comments);\n total = result.total;\n if (result.comments.length === 0 || comments.length >= total) break;\n }\n return { comments, total };\n }\n\n async #createComment(input: CreateIntakeCommentInput): Promise<CreatedIntakeComment | null> {\n const resolved = await this.#resolveRequest(input);\n let key = resolved.issueId;\n if (!ISSUE_KEY_PATTERN.test(key)) {\n try {\n key = (await resolved.context.api.getIssue(key)).key;\n } catch (error) {\n if (error instanceof JiraApiError && error.status === 404) return null;\n throw error;\n }\n }\n const comment = await resolved.context.api.createComment(key, input.body);\n return {\n id: comment.id,\n url: `${resolved.context.siteUrl}/browse/${key}?focusedCommentId=${comment.id}`,\n };\n }\n\n async #updateIssue(input: UpdateIntakeIssueInput): Promise<IntakeIssue | null> {\n const resolved = await this.#resolveRequest(input);\n let issue: JiraIssue;\n try {\n issue = await resolved.context.api.getIssue(resolved.issueId);\n } catch (error) {\n if (error instanceof JiraApiError && error.status === 404) return null;\n throw error;\n }\n if (currentStatusMatches(issue, input.state)) return this.#toIntakeIssue(issue, resolved.context.siteUrl);\n const transitions = await resolved.context.api.listTransitions(issue.key);\n const transition = resolveTransition(transitions, input.state);\n if (!transition) return null;\n await resolved.context.api.applyTransition(issue.key, transition.id);\n return this.#toIntakeIssue(await resolved.context.api.getIssue(issue.key), resolved.context.siteUrl);\n }\n\n async #resolveRequest(input: GetIntakeIssueInput): Promise<{ context: JiraConnectionContext; issueId: string }> {\n const issueReference = decodeIssueReference(input.issueId);\n const source = input.sourceId ? decodeSourceId(input.sourceId) : null;\n const connectionId =\n issueReference?.connectionId ?? source?.connectionId ?? connectionIdFromConnection(input.connection);\n const issueId = issueReference?.issueId ?? input.issueId;\n if (connectionId) return { context: await this.#connectionContextById(connectionId), issueId };\n const active = await this.#activeConnections();\n if (active.length !== 1) {\n throw new JiraApiError('Jira issue reference must identify a connection when multiple sites are connected.', 400);\n }\n return { context: await this.#connectionContext(active[0]!), issueId };\n }\n\n /**\n * Locate an issue for a read. A connection-scoped reference resolves\n * directly; a plain issue key (the agent tool's normal input) is looked up\n * across every active connection so multi-site organizations can still\n * fetch by key — the first site that knows the key wins, which is safe\n * because Jira project-key prefixes make cross-site collisions unlikely and\n * the tool is read-only.\n */\n async #findIssue(input: GetIntakeIssueInput): Promise<{ context: JiraConnectionContext; issue: JiraIssue } | null> {\n const issueReference = decodeIssueReference(input.issueId);\n const source = input.sourceId ? decodeSourceId(input.sourceId) : null;\n const connectionId =\n issueReference?.connectionId ?? source?.connectionId ?? connectionIdFromConnection(input.connection);\n const issueId = issueReference?.issueId ?? input.issueId;\n\n const candidates: JiraConnectionContext[] = [];\n if (connectionId) {\n candidates.push(await this.#connectionContextById(connectionId));\n } else {\n const active = await this.#activeConnections();\n if (active.length === 0) {\n throw new JiraApiError('Jira connection is unavailable or requires reauthentication.', 401);\n }\n for (const connection of active) candidates.push(await this.#connectionContext(connection));\n }\n\n let firstError: unknown;\n for (const context of candidates) {\n try {\n return { context, issue: await context.api.getIssue(issueId) };\n } catch (error) {\n if (error instanceof JiraApiError && error.status === 404) continue;\n firstError ??= error;\n }\n }\n // Not found anywhere. If a site failed for a non-404 reason, surface that\n // failure instead of a silent \"not found\".\n if (firstError !== undefined) throw firstError;\n return null;\n }\n\n #toIntakeIssue(issue: JiraIssue, siteUrl: string): IntakeIssue {\n const { fields } = issue;\n return {\n id: issue.id,\n identifier: issue.key,\n title: fields.summary ?? issue.key,\n url: `${siteUrl}/browse/${issue.key}`,\n author: fields.reporter?.displayName ?? null,\n state: fields.status?.name ?? null,\n stateType: stateTypeFromCategory(fields.status?.statusCategory?.key),\n priority: fields.priority?.name ?? null,\n assignee: fields.assignee?.displayName ?? null,\n source: fields.project?.key ?? null,\n labels: fields.labels ?? [],\n commentCount: null,\n createdAt: fields.created ?? '',\n updatedAt: fields.updated ?? '',\n };\n }\n\n async #activeConnections(): Promise<PlatformIntegrationConnection[]> {\n return (await this.listConnections()).filter(connection => connection.status === 'active');\n }\n\n async #connectionContextById(connectionId: string): Promise<JiraConnectionContext> {\n const connection = (await this.#activeConnections()).find(candidate => candidate.id === connectionId);\n if (!connection) {\n throw new JiraApiError('Jira connection is unavailable or requires reauthentication.', 401);\n }\n return this.#connectionContext(connection);\n }\n\n async #cloudId(connectionId: string): Promise<string> {\n const cached = this.#cloudIdByConnectionId.get(connectionId);\n if (cached) return cached;\n\n const context = await this.#platformClient.request<PlatformConnectionContextResponse>(\n 'GET',\n `/v2/connections/${encodeURIComponent(connectionId)}/context`,\n );\n const cloudId = context.connection_config?.cloudId;\n if (typeof cloudId !== 'string' || !UUID_PATTERN.test(cloudId)) {\n throw new JiraApiError('Platform Jira connection context is missing a valid cloudId.', 502);\n }\n this.#cloudIdByConnectionId.set(connectionId, cloudId);\n return cloudId;\n }\n\n async #connectionContext(connection: PlatformIntegrationConnection): Promise<JiraConnectionContext> {\n const proxyBaseUrl = `${this.#clientConfig.baseUrl.replace(/\\/+$/, '')}/v2/connections/${encodeURIComponent(\n connection.id,\n )}/proxy`;\n const cloudId = await this.#cloudId(connection.id);\n const api = new JiraApiClient({\n baseUrl: `${proxyBaseUrl}/ex/jira/${encodeURIComponent(cloudId)}`,\n accessToken: this.#clientConfig.accessToken,\n ...(this.#clientConfig.fetchImpl ? { fetchImpl: this.#clientConfig.fetchImpl } : {}),\n });\n let siteUrl = this.#siteUrlByConnectionId.get(connection.id);\n if (!siteUrl) {\n siteUrl = connection.accountLabel\n ? normalizeSiteUrl(connection.accountLabel)\n : normalizeSiteUrl((await api.getServerInfo()).baseUrl);\n this.#siteUrlByConnectionId.set(connection.id, siteUrl);\n }\n return { connection, api, siteUrl };\n }\n\n workers(ctx: IntegrationContext): MastraWorker[] {\n if (!jiraReconciliationEnabled()) return [];\n const reconcile = attachJiraIssueReconciler(this, ctx);\n if (!reconcile) return [];\n const intervalMs = jiraReconciliationInterval();\n return [\n new IssueReconcileWorker({\n integrationId: this.id,\n reconcile,\n ...(intervalMs ? { intervalMs } : {}),\n }),\n ];\n }\n\n routes(ctx: IntegrationContext): ApiRoute[] {\n return buildPlatformJiraRoutes({\n jira: this,\n auth: ctx.auth,\n intake: ctx.storage.intake,\n appDbConfigured: Boolean(ctx.factoryStorage),\n ingestFactoryIssues: attachJiraRules(this, ctx),\n });\n }\n\n async agentTools(args: { requestContext: RequestContext }): Promise<IntegrationTools> {\n return buildPlatformJiraAgentTools({ requestContext: args.requestContext, jira: this });\n }\n\n diagnostics(): Record<string, unknown> {\n return { configured: true, mode: 'platform', endpointHost: this.#endpointHost };\n }\n}\n\nfunction jiraConnection(connectionId: string): IntegrationConnection {\n return { type: 'oauth', accessToken: `${JIRA_CONNECTION_TOKEN_PREFIX}${connectionId}` };\n}\n\nfunction connectionIdFromConnection(connection: IntegrationConnection): string | null {\n if (connection.type !== 'oauth' || !connection.accessToken.startsWith(JIRA_CONNECTION_TOKEN_PREFIX)) return null;\n return connection.accessToken.slice(JIRA_CONNECTION_TOKEN_PREFIX.length) || null;\n}\n\nexport function encodeSourceId(connectionId: string, projectId: string): string {\n return `${JIRA_SOURCE_PREFIX}${Buffer.from(JSON.stringify({ connectionId, projectId })).toString('base64url')}`;\n}\n\nexport function decodeSourceId(sourceId: string): { connectionId: string; projectId: string } | null {\n if (!sourceId.startsWith(JIRA_SOURCE_PREFIX)) return null;\n try {\n const parsed = JSON.parse(\n Buffer.from(sourceId.slice(JIRA_SOURCE_PREFIX.length), 'base64url').toString('utf8'),\n ) as Record<string, unknown>;\n return typeof parsed.connectionId === 'string' && typeof parsed.projectId === 'string'\n ? { connectionId: parsed.connectionId, projectId: parsed.projectId }\n : null;\n } catch {\n return null;\n }\n}\n\nexport function encodeIssueReference(reference: JiraIssueReference): string {\n return `${JIRA_ISSUE_REF_PREFIX}${Buffer.from(JSON.stringify(reference)).toString('base64url')}`;\n}\n\nexport function decodeIssueReference(value: string): JiraIssueReference | null {\n if (!value.startsWith(JIRA_ISSUE_REF_PREFIX)) return null;\n try {\n const parsed = JSON.parse(\n Buffer.from(value.slice(JIRA_ISSUE_REF_PREFIX.length), 'base64url').toString('utf8'),\n ) as Record<string, unknown>;\n if (typeof parsed.connectionId !== 'string' || typeof parsed.issueId !== 'string') return null;\n return {\n connectionId: parsed.connectionId,\n issueId: parsed.issueId,\n ...(typeof parsed.projectId === 'string' ? { projectId: parsed.projectId } : {}),\n };\n } catch {\n return null;\n }\n}\n\nfunction groupSources(sourceIds: string[]): Array<{ connectionId: string; projectIds: string[] }> {\n const groups = new Map<string, Set<string>>();\n for (const sourceId of sourceIds) {\n const source = decodeSourceId(sourceId);\n if (!source) continue;\n const projectIds = groups.get(source.connectionId) ?? new Set<string>();\n projectIds.add(source.projectId);\n groups.set(source.connectionId, projectIds);\n }\n return [...groups.entries()]\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([connectionId, projectIds]) => ({ connectionId, projectIds: [...projectIds].sort() }));\n}\n\nfunction encodePageCursor(cursor: JiraPageCursor): string {\n return Buffer.from(JSON.stringify(cursor)).toString('base64url');\n}\n\nfunction decodePageCursor(cursor: string | undefined): JiraPageCursor {\n if (!cursor) return { group: 0 };\n try {\n const parsed = JSON.parse(Buffer.from(cursor, 'base64url').toString('utf8')) as Record<string, unknown>;\n if (!Number.isInteger(parsed.group) || (parsed.group as number) < 0) throw new Error();\n return {\n group: parsed.group as number,\n ...(typeof parsed.jira === 'string' ? { jira: parsed.jira } : {}),\n };\n } catch {\n throw new JiraApiError('Jira pagination cursor is invalid.', 400);\n }\n}\n\nfunction normalizeSiteUrl(value: string): string {\n const candidate = /^https?:\\/\\//i.test(value) ? value : `https://${value}`;\n // `accountLabel` is free-form Platform data — an unparsable value must\n // surface as the classified 502 the routes already handle, not a raw\n // TypeError escaping the connection context.\n let url: URL;\n try {\n url = new URL(candidate);\n } catch {\n throw new JiraApiError('Jira site URL is invalid.', 502);\n }\n if (url.protocol !== 'http:' && url.protocol !== 'https:') throw new JiraApiError('Jira site URL is invalid.', 502);\n return url.origin;\n}\n\nfunction buildIntakeJql(projectIds?: string[], labels?: string[]): string | null {\n const clauses: string[] = [];\n const safeProjects = (projectIds ?? [])\n .map(id => id.trim())\n .filter(id => /^[A-Za-z0-9_]+$/.test(id))\n .map(id => (/^\\d+$/.test(id) ? id : `\"${id}\"`));\n if (projectIds && safeProjects.length === 0) return null;\n if (safeProjects.length > 0) clauses.push(`project IN (${safeProjects.join(', ')})`);\n clauses.push('statusCategory != Done');\n const safeLabels = [...new Set((labels ?? []).map(label => label.trim().replace(/[\"\\\\]/g, '')).filter(Boolean))];\n if (safeLabels.length > 0) clauses.push(`labels IN (${safeLabels.map(label => `\"${label}\"`).join(', ')})`);\n return `${clauses.join(' AND ')} ORDER BY updated DESC`;\n}\n\nfunction currentStatusMatches(issue: JiraIssue, target: UpdateIntakeIssueInput['state']): boolean {\n const status = issue.fields.status;\n if (!status) return false;\n if (target.kind === 'byName') return status.name.toLowerCase() === target.name.toLowerCase();\n if (target.stateType === 'canceled') return status.statusCategory?.key === 'done' && /cancel/i.test(status.name);\n return status.statusCategory?.key === STATE_TYPE_TO_CATEGORY[target.stateType];\n}\n\nfunction resolveTransition(\n transitions: JiraTransition[],\n target: UpdateIntakeIssueInput['state'],\n): JiraTransition | null {\n if (target.kind === 'byName') {\n const wanted = target.name.toLowerCase();\n return transitions.find(transition => transition.to?.name.toLowerCase() === wanted) ?? null;\n }\n if (target.stateType === 'canceled') {\n return (\n transitions.find(\n transition => transition.to?.statusCategory?.key === 'done' && /cancel/i.test(transition.to.name),\n ) ?? null\n );\n }\n const category = STATE_TYPE_TO_CATEGORY[target.stateType];\n return transitions.find(transition => transition.to?.statusCategory?.key === category) ?? null;\n}\n"],"mappings":";;;;;;;;;;;AAsEA,MAAM,2BAA2B;;AAGjC,MAAM,2BAA2B;AACjC,MAAM,oBAAoB;AAC1B,MAAM,oCAAoC;AAC1C,MAAM,eAAe;AACrB,MAAM,+BAA+B;AACrC,MAAM,wBAAwB;AAC9B,MAAM,qBAAqB;AAE3B,MAAM,yBAAgF;CACpF,WAAW;CACX,SAAS;CACT,WAAW;AACb;AAEA,SAAS,sBAAsB,KAAwC;CACrE,QAAQ,KAAR;EACE,KAAK,OACH,OAAO;EACT,KAAK,iBACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,SACE,OAAO;CACX;AACF;AAQA,IAAa,0BAAb,MAAmE;CACjE,KAAc;CACd;CACA;CACA;CACA,yCAAkC,IAAI,IAAoB;CAC1D,yCAAkC,IAAI,IAAoB;CAC1D;CACA;CACA,qCAA8B,IAAI,IAA2B;CAE7D;CAEA,IAAI,QAAwB;EAC1B,OAAO,KAAKM;CACd;CAEA,YAAY,SAAwC,CAAC,GAAG;EACtD,KAAKA,SAAS,iBAAiB,OAAO,KAAK;EAC3C,KAAKN,gBAAgB,OAAO,gBAAgB,+BAA+B;EAC3E,KAAKC,kBAAkB,IAAI,kBAAkB,KAAKD,aAAa;EAC/D,KAAKE,gBAAgB,IAAI,IAAI,KAAKF,cAAc,OAAO,CAAC,CAAC;CAC3D;CAEA,WAAW,EAAE,UAAU,QAAqE;EAC1F,KAAKO,YAAY;EACjB,KAAKC,QAAQ;EACb,gBAAgB,yCAAyC,EAAE,cAAc,KAAKN,cAAc,CAAC;CAC/F;CAEA,IAAI,WAAmC;EACrC,IAAI,CAAC,KAAKK,WACR,MAAM,IAAI,MAAM,0FAA0F;EAC5G,OAAO,KAAKA;CACd;CAEA,IAAI,cAAuB;EACzB,OAAO,KAAKC,OAAO,QAAQ,KAAK;CAClC;CAEA,MAAM,aAAa,YAA4C;EAC7D,MAAM,SAAS,KAAKH,mBAAmB,IAAI,UAAU;EACrD,IAAI,WAAW,KAAA,GAAW,OAAO;EACjC,IAAI,CAAC,aAAa,KAAK,UAAU,GAAG;GAClC,KAAKA,mBAAmB,IAAI,YAAY,IAAI;GAC5C,OAAO;EACT;EACA,IAAI;GACF,MAAM,KAAK,SAAS,YAAY;GAEhC,MAAM,SAAQ,MADQ,KAAK,SAAS,QAAQ,EAAE,IAAI,WAAW,CAAC,EAAA,EACvC,SAAS;GAChC,KAAKA,mBAAmB,IAAI,YAAY,KAAK;GAC7C,OAAO;EACT,QAAQ;GACN,OAAO;EACT;CACF;CAEA,cAAoB;EAClB,KAAKA,mBAAmB,MAAM;EAC9B,KAAKF,uBAAuB,MAAM;EAClC,KAAKC,uBAAuB,MAAM;CACpC;CAEA,MAAM,kBAA4D;EAChE,MAAM,cAAc,mBAAmB,iCAAiC;EAKxE,QAAO,MAJc,KAAKH,gBAAgB,QACxC,OACA,+BAA+B,aACjC,EAAA,CACc;CAChB;CAEA,MAAM,uBAAyC;EAC7C,QAAQ,MAAM,KAAKQ,mBAAmB,EAAA,CAAG,SAAS;CACpD;CAEA,SAA0B;EACxB,wBAAuB,UAAS,KAAKC,uBAAuB,KAAK;EACjE,mBAAmB,KAAKC,aAAa;EACrC,YAAW,UAAS,KAAKC,WAAW,KAAK;EACzC,aAAY,UAAS,KAAKC,YAAY,KAAK;EAC3C,WAAU,UAAS,KAAKC,UAAU,KAAK;EACvC,gBAAe,UAAS,KAAKC,eAAe,KAAK;EACjD,cAAa,UAAS,KAAKC,aAAa,KAAK;CAC/C;CAEA,MAAMN,uBAAuB,EAAE,kBAAsF;EACnH,IAAI,eAAe,SAAS,SAAS,OAAO;EAC5C,MAAM,YAAY,qBAAqB,eAAe,UAAU;EAChE,IAAI,CAAC,WAAW,OAAO;EACvB,OAAO;GACL,YAAY,eAAe,UAAU,YAAY;GACjD,GAAI,UAAU,YAAY,EAAE,UAAU,eAAe,UAAU,cAAc,UAAU,SAAS,EAAE,IAAI,CAAC;GACvG,SAAS,UAAU;EACrB;CACF;CAEA,MAAMC,eAAwC;EAC5C,MAAM,UAA0B,CAAC;EACjC,KAAK,MAAM,cAAc,MAAM,KAAKF,mBAAmB,GAAG;GACxD,MAAM,UAAU,MAAM,KAAKQ,mBAAmB,UAAU;GACxD,IAAI,UAAU;GACd,KAAK,IAAI,YAAY,GAAG,YAAY,0BAA0B,aAAa;IACzE,MAAM,OAAO,MAAM,QAAQ,IAAI,aAAa,EAAE,QAAQ,CAAC;IACvD,KAAK,MAAM,WAAW,KAAK,QACzB,QAAQ,KAAK;KACX,IAAI,eAAe,WAAW,IAAI,QAAQ,EAAE;KAC5C,MAAM,QAAQ;KACd,MAAM;KACN,UAAU;MACR,KAAK,QAAQ;MACb,cAAc,WAAW;MACzB,MAAM,IAAI,IAAI,QAAQ,OAAO,CAAC,CAAC;KACjC;IACF,CAAC;IAEH,IAAI,KAAK,UAAU,KAAK,OAAO,WAAW,GAAG;IAC7C,WAAW,KAAK,OAAO;GACzB;EACF;EACA,OAAO;CACT;CAEA,MAAML,WAAW,EAAE,WAAW,UAAyD;EACrF,IAAI,UAAU,WAAW,GAAG,OAAO;GAAE,OAAO,CAAC;GAAG,YAAY;EAAK;EACjE,MAAM,OAAO,MAAM,KAAK,iBAAiB,QAAQ,SAAS;EAC1D,OAAO;GACL,OAAO,KAAK,OAAO,KAAI,WAAU;IAC/B,QAAQ;KAAE,MAAM;KAAS,YAAY,MAAM;KAAY,KAAK,MAAM;IAAI;IACtE,UAAU,MAAM;IAChB,OAAO,GAAG,MAAM,WAAW,IAAI,MAAM;IACrC,QAAQ,MAAM,SAAS,KAAA;IACvB,QAAQ,MAAM;IACd,UAAU,MAAM;IAChB,WAAW,MAAM;IACjB,WAAW,MAAM;IACjB,UAAU;KACR,YAAY,MAAM;KAClB,UAAU,MAAM;KAChB,OAAO,MAAM;KACb,WAAW,MAAM;KACjB,UAAU,MAAM;KAChB,SAAS,MAAM;KACf,MAAM,MAAM;KACZ,UAAU,MAAM;KAChB,WAAW,MAAM,aAAa,CAAC;KAC/B,SAAS,MAAM;KACf,QAAQ,MAAM;KACd,QAAQ,MAAM;KACd,WAAW,MAAM;KACjB,WAAW,MAAM;IACnB;GACF,EAAE;GACF,YAAY,KAAK;EACnB;CACF;CAEA,MAAMC,YAAY,OAA6F;EAC7G,MAAM,OAAO,MAAM,KAAK,iBAAiB,MAAM,QAAQ,MAAM,WAAW,MAAM,MAAM;EACpF,OAAO;GAAE,QAAQ,KAAK;GAAQ,YAAY,KAAK;EAAW;CAC5D;CAEA,MAAM,iBACJ,QACA,YAAsB,CAAC,GACvB,QAIC;EACD,MAAM,UAAU,aAAa,SAAS;EACtC,IAAI,QAAQ,WAAW,GAAG,OAAO;GAAE,QAAQ,CAAC;GAAG,YAAY;EAAK;EAChE,MAAM,gBAAgB,iBAAiB,MAAM;EAC7C,IAAI,cAAc,SAAS,QAAQ,QAAQ,OAAO;GAAE,QAAQ,CAAC;GAAG,YAAY;EAAK;EAEjF,KAAK,IAAI,aAAa,cAAc,OAAO,aAAa,QAAQ,QAAQ,cAAc;GACpF,MAAM,QAAQ,QAAQ;GACtB,MAAM,UAAU,MAAM,KAAKK,uBAAuB,MAAM,YAAY;GACpE,MAAM,MAAM,eAAe,MAAM,YAAY,MAAM;GACnD,IAAI,QAAQ,MAAM;GAClB,MAAM,OAAO,MAAM,QAAQ,IAAI,aAAa;IAC1C;IACA,GAAI,eAAe,cAAc,SAAS,cAAc,OAAO,EAAE,eAAe,cAAc,KAAK,IAAI,CAAC;GAC1G,CAAC;GACD,MAAM,aAAa,KAAK,gBACpB,iBAAiB;IAAE,OAAO;IAAY,MAAM,KAAK;GAAc,CAAC,IAChE,aAAa,IAAI,QAAQ,SACvB,iBAAiB,EAAE,OAAO,aAAa,EAAE,CAAC,IAC1C;GACN,OAAO;IACL,QAAQ,KAAK,OAAO,KAAI,UAAS;KAC/B,MAAM,YAAY,MAAM,OAAO,SAAS,MAAM,MAAM,WAAW,MAAM;KACrE,OAAO;MACL,GAAG,KAAKC,eAAe,OAAO,QAAQ,OAAO;MAC7C,UAAU,eAAe,MAAM,cAAc,SAAS;MACtD,YAAY,qBAAqB;OAAE,cAAc,MAAM;OAAc,SAAS,MAAM;OAAK;MAAU,CAAC;MACpG,MAAM,IAAI,IAAI,QAAQ,OAAO,CAAC,CAAC;KACjC;IACF,CAAC;IACD;GACF;EACF;EACA,OAAO;GAAE,QAAQ,CAAC;GAAG,YAAY;EAAK;CACxC;CAEA,MAAML,UAAU,OAA+D;EAC7E,MAAM,EAAE,SAAS,UAAW,MAAM,KAAKM,WAAW,KAAK,KAAM,CAAC;EAC9D,IAAI,CAAC,WAAW,CAAC,OAAO,OAAO;EAC/B,MAAM,EAAE,UAAU,UAAU,MAAM,KAAKC,iBAAiB,QAAQ,KAAK,MAAM,GAAG;EAC9E,OAAO;GACL,GAAG,KAAKF,eAAe,OAAO,QAAQ,OAAO;GAC7C,cAAc;GACd,aAAa,MAAM,OAAO,cAAc,UAAU,MAAM,OAAO,WAAW,KAAK,OAAO;GACtF,UAAU,SAAS,KAAI,aAAY;IACjC,QAAQ,QAAQ,QAAQ,eAAe;IACvC,MAAM,UAAU,QAAQ,IAAI;IAC5B,WAAW,QAAQ;GACrB,EAAE;EACJ;CACF;CAEA,MAAME,iBAAiB,KAAoB,SAAsE;EAC/G,MAAM,WAA0B,CAAC;EACjC,IAAI,QAAQ;EACZ,KAAK,IAAI,OAAO,GAAG,OAAO,0BAA0B,QAAQ;GAC1D,MAAM,SAAS,MAAM,IAAI,aAAa,SAAS,EAAE,SAAS,SAAS,OAAO,CAAC;GAC3E,SAAS,KAAK,GAAG,OAAO,QAAQ;GAChC,QAAQ,OAAO;GACf,IAAI,OAAO,SAAS,WAAW,KAAK,SAAS,UAAU,OAAO;EAChE;EACA,OAAO;GAAE;GAAU;EAAM;CAC3B;CAEA,MAAMN,eAAe,OAAuE;EAC1F,MAAM,WAAW,MAAM,KAAKO,gBAAgB,KAAK;EACjD,IAAI,MAAM,SAAS;EACnB,IAAI,CAAC,kBAAkB,KAAK,GAAG,GAC7B,IAAI;GACF,OAAO,MAAM,SAAS,QAAQ,IAAI,SAAS,GAAG,EAAA,CAAG;EACnD,SAAS,OAAO;GACd,IAAI,iBAAiB,gBAAgB,MAAM,WAAW,KAAK,OAAO;GAClE,MAAM;EACR;EAEF,MAAM,UAAU,MAAM,SAAS,QAAQ,IAAI,cAAc,KAAK,MAAM,IAAI;EACxE,OAAO;GACL,IAAI,QAAQ;GACZ,KAAK,GAAG,SAAS,QAAQ,QAAQ,UAAU,IAAI,oBAAoB,QAAQ;EAC7E;CACF;CAEA,MAAMN,aAAa,OAA4D;EAC7E,MAAM,WAAW,MAAM,KAAKM,gBAAgB,KAAK;EACjD,IAAI;EACJ,IAAI;GACF,QAAQ,MAAM,SAAS,QAAQ,IAAI,SAAS,SAAS,OAAO;EAC9D,SAAS,OAAO;GACd,IAAI,iBAAiB,gBAAgB,MAAM,WAAW,KAAK,OAAO;GAClE,MAAM;EACR;EACA,IAAI,qBAAqB,OAAO,MAAM,KAAK,GAAG,OAAO,KAAKH,eAAe,OAAO,SAAS,QAAQ,OAAO;EAExG,MAAM,aAAa,kBAAkB,MADX,SAAS,QAAQ,IAAI,gBAAgB,MAAM,GAAG,GACtB,MAAM,KAAK;EAC7D,IAAI,CAAC,YAAY,OAAO;EACxB,MAAM,SAAS,QAAQ,IAAI,gBAAgB,MAAM,KAAK,WAAW,EAAE;EACnE,OAAO,KAAKA,eAAe,MAAM,SAAS,QAAQ,IAAI,SAAS,MAAM,GAAG,GAAG,SAAS,QAAQ,OAAO;CACrG;CAEA,MAAMG,gBAAgB,OAA0F;EAC9G,MAAM,iBAAiB,qBAAqB,MAAM,OAAO;EACzD,MAAM,SAAS,MAAM,WAAW,eAAe,MAAM,QAAQ,IAAI;EACjE,MAAM,eACJ,gBAAgB,gBAAgB,QAAQ,gBAAgB,2BAA2B,MAAM,UAAU;EACrG,MAAM,UAAU,gBAAgB,WAAW,MAAM;EACjD,IAAI,cAAc,OAAO;GAAE,SAAS,MAAM,KAAKJ,uBAAuB,YAAY;GAAG;EAAQ;EAC7F,MAAM,SAAS,MAAM,KAAKT,mBAAmB;EAC7C,IAAI,OAAO,WAAW,GACpB,MAAM,IAAI,aAAa,sFAAsF,GAAG;EAElH,OAAO;GAAE,SAAS,MAAM,KAAKQ,mBAAmB,OAAO,EAAG;GAAG;EAAQ;CACvE;;;;;;;;;CAUA,MAAMG,WAAW,OAAkG;EACjH,MAAM,iBAAiB,qBAAqB,MAAM,OAAO;EACzD,MAAM,SAAS,MAAM,WAAW,eAAe,MAAM,QAAQ,IAAI;EACjE,MAAM,eACJ,gBAAgB,gBAAgB,QAAQ,gBAAgB,2BAA2B,MAAM,UAAU;EACrG,MAAM,UAAU,gBAAgB,WAAW,MAAM;EAEjD,MAAM,aAAsC,CAAC;EAC7C,IAAI,cACF,WAAW,KAAK,MAAM,KAAKF,uBAAuB,YAAY,CAAC;OAC1D;GACL,MAAM,SAAS,MAAM,KAAKT,mBAAmB;GAC7C,IAAI,OAAO,WAAW,GACpB,MAAM,IAAI,aAAa,gEAAgE,GAAG;GAE5F,KAAK,MAAM,cAAc,QAAQ,WAAW,KAAK,MAAM,KAAKQ,mBAAmB,UAAU,CAAC;EAC5F;EAEA,IAAI;EACJ,KAAK,MAAM,WAAW,YACpB,IAAI;GACF,OAAO;IAAE;IAAS,OAAO,MAAM,QAAQ,IAAI,SAAS,OAAO;GAAE;EAC/D,SAAS,OAAO;GACd,IAAI,iBAAiB,gBAAgB,MAAM,WAAW,KAAK;GAC3D,eAAe;EACjB;EAIF,IAAI,eAAe,KAAA,GAAW,MAAM;EACpC,OAAO;CACT;CAEA,eAAe,OAAkB,SAA8B;EAC7D,MAAM,EAAE,WAAW;EACnB,OAAO;GACL,IAAI,MAAM;GACV,YAAY,MAAM;GAClB,OAAO,OAAO,WAAW,MAAM;GAC/B,KAAK,GAAG,QAAQ,UAAU,MAAM;GAChC,QAAQ,OAAO,UAAU,eAAe;GACxC,OAAO,OAAO,QAAQ,QAAQ;GAC9B,WAAW,sBAAsB,OAAO,QAAQ,gBAAgB,GAAG;GACnE,UAAU,OAAO,UAAU,QAAQ;GACnC,UAAU,OAAO,UAAU,eAAe;GAC1C,QAAQ,OAAO,SAAS,OAAO;GAC/B,QAAQ,OAAO,UAAU,CAAC;GAC1B,cAAc;GACd,WAAW,OAAO,WAAW;GAC7B,WAAW,OAAO,WAAW;EAC/B;CACF;CAEA,MAAMR,qBAA+D;EACnE,QAAQ,MAAM,KAAK,gBAAgB,EAAA,CAAG,QAAO,eAAc,WAAW,WAAW,QAAQ;CAC3F;CAEA,MAAMS,uBAAuB,cAAsD;EACjF,MAAM,cAAc,MAAM,KAAKT,mBAAmB,EAAA,CAAG,MAAK,cAAa,UAAU,OAAO,YAAY;EACpG,IAAI,CAAC,YACH,MAAM,IAAI,aAAa,gEAAgE,GAAG;EAE5F,OAAO,KAAKQ,mBAAmB,UAAU;CAC3C;CAEA,MAAMM,SAAS,cAAuC;EACpD,MAAM,SAAS,KAAKpB,uBAAuB,IAAI,YAAY;EAC3D,IAAI,QAAQ,OAAO;EAMnB,MAAM,WAAU,MAJM,KAAKF,gBAAgB,QACzC,OACA,mBAAmB,mBAAmB,YAAY,EAAE,SACtD,EAAA,CACwB,mBAAmB;EAC3C,IAAI,OAAO,YAAY,YAAY,CAAC,aAAa,KAAK,OAAO,GAC3D,MAAM,IAAI,aAAa,gEAAgE,GAAG;EAE5F,KAAKE,uBAAuB,IAAI,cAAc,OAAO;EACrD,OAAO;CACT;CAEA,MAAMc,mBAAmB,YAA2E;EAClG,MAAM,eAAe,GAAG,KAAKjB,cAAc,QAAQ,QAAQ,QAAQ,EAAE,EAAE,kBAAkB,mBACvF,WAAW,EACb,EAAE;EACF,MAAM,UAAU,MAAM,KAAKuB,SAAS,WAAW,EAAE;EACjD,MAAM,MAAM,IAAI,cAAc;GAC5B,SAAS,GAAG,aAAa,WAAW,mBAAmB,OAAO;GAC9D,aAAa,KAAKvB,cAAc;GAChC,GAAI,KAAKA,cAAc,YAAY,EAAE,WAAW,KAAKA,cAAc,UAAU,IAAI,CAAC;EACpF,CAAC;EACD,IAAI,UAAU,KAAKI,uBAAuB,IAAI,WAAW,EAAE;EAC3D,IAAI,CAAC,SAAS;GACZ,UAAU,WAAW,eACjB,iBAAiB,WAAW,YAAY,IACxC,kBAAkB,MAAM,IAAI,cAAc,EAAA,CAAG,OAAO;GACxD,KAAKA,uBAAuB,IAAI,WAAW,IAAI,OAAO;EACxD;EACA,OAAO;GAAE;GAAY;GAAK;EAAQ;CACpC;CAEA,QAAQ,KAAyC;EAC/C,IAAI,CAAC,0BAA0B,GAAG,OAAO,CAAC;EAC1C,MAAM,YAAY,0BAA0B,MAAM,GAAG;EACrD,IAAI,CAAC,WAAW,OAAO,CAAC;EACxB,MAAM,aAAa,2BAA2B;EAC9C,OAAO,CACL,IAAI,qBAAqB;GACvB,eAAe,KAAK;GACpB;GACA,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;EACrC,CAAC,CACH;CACF;CAEA,OAAO,KAAqC;EAC1C,OAAO,wBAAwB;GAC7B,MAAM;GACN,MAAM,IAAI;GACV,QAAQ,IAAI,QAAQ;GACpB,iBAAiB,QAAQ,IAAI,cAAc;GAC3C,qBAAqB,gBAAgB,MAAM,GAAG;EAChD,CAAC;CACH;CAEA,MAAM,WAAW,MAAqE;EACpF,OAAO,4BAA4B;GAAE,gBAAgB,KAAK;GAAgB,MAAM;EAAK,CAAC;CACxF;CAEA,cAAuC;EACrC,OAAO;GAAE,YAAY;GAAM,MAAM;GAAY,cAAc,KAAKF;EAAc;CAChF;AACF;AAEA,SAAS,eAAe,cAA6C;CACnE,OAAO;EAAE,MAAM;EAAS,aAAa,GAAG,+BAA+B;CAAe;AACxF;AAEA,SAAS,2BAA2B,YAAkD;CACpF,IAAI,WAAW,SAAS,WAAW,CAAC,WAAW,YAAY,WAAW,4BAA4B,GAAG,OAAO;CAC5G,OAAO,WAAW,YAAY,MAAM,EAAmC,KAAK;AAC9E;AAEA,SAAgB,eAAe,cAAsB,WAA2B;CAC9E,OAAO,GAAG,qBAAqB,OAAO,KAAK,KAAK,UAAU;EAAE;EAAc;CAAU,CAAC,CAAC,CAAC,CAAC,SAAS,WAAW;AAC9G;AAEA,SAAgB,eAAe,UAAsE;CACnG,IAAI,CAAC,SAAS,WAAW,kBAAkB,GAAG,OAAO;CACrD,IAAI;EACF,MAAM,SAAS,KAAK,MAClB,OAAO,KAAK,SAAS,MAAM,EAAyB,GAAG,WAAW,CAAC,CAAC,SAAS,MAAM,CACrF;EACA,OAAO,OAAO,OAAO,iBAAiB,YAAY,OAAO,OAAO,cAAc,WAC1E;GAAE,cAAc,OAAO;GAAc,WAAW,OAAO;EAAU,IACjE;CACN,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAgB,qBAAqB,WAAuC;CAC1E,OAAO,GAAG,wBAAwB,OAAO,KAAK,KAAK,UAAU,SAAS,CAAC,CAAC,CAAC,SAAS,WAAW;AAC/F;AAEA,SAAgB,qBAAqB,OAA0C;CAC7E,IAAI,CAAC,MAAM,WAAW,qBAAqB,GAAG,OAAO;CACrD,IAAI;EACF,MAAM,SAAS,KAAK,MAClB,OAAO,KAAK,MAAM,MAAM,EAA4B,GAAG,WAAW,CAAC,CAAC,SAAS,MAAM,CACrF;EACA,IAAI,OAAO,OAAO,iBAAiB,YAAY,OAAO,OAAO,YAAY,UAAU,OAAO;EAC1F,OAAO;GACL,cAAc,OAAO;GACrB,SAAS,OAAO;GAChB,GAAI,OAAO,OAAO,cAAc,WAAW,EAAE,WAAW,OAAO,UAAU,IAAI,CAAC;EAChF;CACF,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,aAAa,WAA4E;CAChG,MAAM,yBAAS,IAAI,IAAyB;CAC5C,KAAK,MAAM,YAAY,WAAW;EAChC,MAAM,SAAS,eAAe,QAAQ;EACtC,IAAI,CAAC,QAAQ;EACb,MAAM,aAAa,OAAO,IAAI,OAAO,YAAY,qBAAK,IAAI,IAAY;EACtE,WAAW,IAAI,OAAO,SAAS;EAC/B,OAAO,IAAI,OAAO,cAAc,UAAU;CAC5C;CACA,OAAO,CAAC,GAAG,OAAO,QAAQ,CAAC,CAAC,CACzB,MAAM,CAAC,OAAO,CAAC,WAAW,KAAK,cAAc,KAAK,CAAC,CAAC,CACpD,KAAK,CAAC,cAAc,iBAAiB;EAAE;EAAc,YAAY,CAAC,GAAG,UAAU,CAAC,CAAC,KAAK;CAAE,EAAE;AAC/F;AAEA,SAAS,iBAAiB,QAAgC;CACxD,OAAO,OAAO,KAAK,KAAK,UAAU,MAAM,CAAC,CAAC,CAAC,SAAS,WAAW;AACjE;AAEA,SAAS,iBAAiB,QAA4C;CACpE,IAAI,CAAC,QAAQ,OAAO,EAAE,OAAO,EAAE;CAC/B,IAAI;EACF,MAAM,SAAS,KAAK,MAAM,OAAO,KAAK,QAAQ,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC;EAC3E,IAAI,CAAC,OAAO,UAAU,OAAO,KAAK,KAAM,OAAO,QAAmB,GAAG,MAAM,IAAI,MAAM;EACrF,OAAO;GACL,OAAO,OAAO;GACd,GAAI,OAAO,OAAO,SAAS,WAAW,EAAE,MAAM,OAAO,KAAK,IAAI,CAAC;EACjE;CACF,QAAQ;EACN,MAAM,IAAI,aAAa,sCAAsC,GAAG;CAClE;AACF;AAEA,SAAS,iBAAiB,OAAuB;CAC/C,MAAM,YAAY,gBAAgB,KAAK,KAAK,IAAI,QAAQ,WAAW;CAInE,IAAI;CACJ,IAAI;EACF,MAAM,IAAI,IAAI,SAAS;CACzB,QAAQ;EACN,MAAM,IAAI,aAAa,6BAA6B,GAAG;CACzD;CACA,IAAI,IAAI,aAAa,WAAW,IAAI,aAAa,UAAU,MAAM,IAAI,aAAa,6BAA6B,GAAG;CAClH,OAAO,IAAI;AACb;AAEA,SAAS,eAAe,YAAuB,QAAkC;CAC/E,MAAM,UAAoB,CAAC;CAC3B,MAAM,gBAAgB,cAAc,CAAC,EAAA,CAClC,KAAI,OAAM,GAAG,KAAK,CAAC,CAAC,CACpB,QAAO,OAAM,kBAAkB,KAAK,EAAE,CAAC,CAAC,CACxC,KAAI,OAAO,QAAQ,KAAK,EAAE,IAAI,KAAK,IAAI,GAAG,EAAG;CAChD,IAAI,cAAc,aAAa,WAAW,GAAG,OAAO;CACpD,IAAI,aAAa,SAAS,GAAG,QAAQ,KAAK,eAAe,aAAa,KAAK,IAAI,EAAE,EAAE;CACnF,QAAQ,KAAK,wBAAwB;CACrC,MAAM,aAAa,CAAC,GAAG,IAAI,KAAK,UAAU,CAAC,EAAA,CAAG,KAAI,UAAS,MAAM,KAAK,CAAC,CAAC,QAAQ,UAAU,EAAE,CAAC,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC;CAC/G,IAAI,WAAW,SAAS,GAAG,QAAQ,KAAK,cAAc,WAAW,KAAI,UAAS,IAAI,MAAM,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE,EAAE;CACzG,OAAO,GAAG,QAAQ,KAAK,OAAO,EAAE;AAClC;AAEA,SAAS,qBAAqB,OAAkB,QAAkD;CAChG,MAAM,SAAS,MAAM,OAAO;CAC5B,IAAI,CAAC,QAAQ,OAAO;CACpB,IAAI,OAAO,SAAS,UAAU,OAAO,OAAO,KAAK,YAAY,MAAM,OAAO,KAAK,YAAY;CAC3F,IAAI,OAAO,cAAc,YAAY,OAAO,OAAO,gBAAgB,QAAQ,UAAU,UAAU,KAAK,OAAO,IAAI;CAC/G,OAAO,OAAO,gBAAgB,QAAQ,uBAAuB,OAAO;AACtE;AAEA,SAAS,kBACP,aACA,QACuB;CACvB,IAAI,OAAO,SAAS,UAAU;EAC5B,MAAM,SAAS,OAAO,KAAK,YAAY;EACvC,OAAO,YAAY,MAAK,eAAc,WAAW,IAAI,KAAK,YAAY,MAAM,MAAM,KAAK;CACzF;CACA,IAAI,OAAO,cAAc,YACvB,OACE,YAAY,MACV,eAAc,WAAW,IAAI,gBAAgB,QAAQ,UAAU,UAAU,KAAK,WAAW,GAAG,IAAI,CAClG,KAAK;CAGT,MAAM,WAAW,uBAAuB,OAAO;CAC/C,OAAO,YAAY,MAAK,eAAc,WAAW,IAAI,gBAAgB,QAAQ,QAAQ,KAAK;AAC5F"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Mastra `apiRoutes` for the Jira intake feature.
3
+ *
4
+ * Registered alongside the other `/web/*` routes, behind the host auth gate.
5
+ * Jira connections are owned by the caller's Mastra Platform organization;
6
+ * provider requests stay server-side and flow through the integrations v2
7
+ * proxy. Every route re-resolves the authenticated user and scopes intake
8
+ * selections by the caller's org.
9
+ *
10
+ * When the feature is disabled (no auth, or no intake storage),
11
+ * `buildPlatformJiraRoutes` returns only `GET /web/jira/status`, which reports
12
+ * `enabled:false` so the SPA can cleanly hide all Jira UI.
13
+ */
14
+ import type { ApiRoute } from '@mastra/core/server';
15
+ import type { RouteAuth } from '../../../routes/route.js';
16
+ import type { IntakeStorage } from '../../../storage/domains/intake/base.js';
17
+ import type { JiraRulesIngress } from '../../jira/rules.js';
18
+ import type { PlatformJiraIntegration } from './integration.js';
19
+ /**
20
+ * Non-secret diagnostic snapshot of every Jira feature gate, mirroring the
21
+ * Linear diagnostics shape. Only booleans — never values.
22
+ */
23
+ export interface JiraFeatureDiagnostics {
24
+ jiraConfigured: boolean;
25
+ factoryAuthEnabled: boolean;
26
+ appDbConfigured: boolean;
27
+ }
28
+ export interface MountJiraRoutesOptions {
29
+ /**
30
+ * The integration instance providing REST access. Required for everything
31
+ * beyond the disabled `status` route.
32
+ */
33
+ jira?: PlatformJiraIntegration;
34
+ /** Host auth seam. Intake selections are org-owned, so the feature is inert without it. */
35
+ auth: RouteAuth;
36
+ /**
37
+ * Cross-integration intake selection domain. Required for the issues route's
38
+ * project filter; when absent, only the disabled `status` route is served.
39
+ */
40
+ intake?: IntakeStorage;
41
+ /** Whether the host configured the application database backing intake state. */
42
+ appDbConfigured: boolean;
43
+ /**
44
+ * Factory rules ingress for observed issues. When present, a board-scoped
45
+ * issue listing also materializes new cards through the Jira event rules —
46
+ * the same automatic intake Linear has.
47
+ */
48
+ ingestFactoryIssues?: (input: JiraRulesIngress) => Promise<unknown>;
49
+ }
50
+ /**
51
+ * Build the Jira routes as Mastra `apiRoutes`. When the feature is disabled,
52
+ * returns only the `status` route so the SPA can detect the disabled state.
53
+ */
54
+ export declare function buildPlatformJiraRoutes(options: MountJiraRoutesOptions): ApiRoute[];
55
+ //# sourceMappingURL=routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../../src/integrations/platform/jira/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAIpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAE7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAYhE;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,cAAc,EAAE,OAAO,CAAC;IACxB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,IAAI,CAAC,EAAE,uBAAuB,CAAC;IAC/B,2FAA2F;IAC3F,IAAI,EAAE,SAAS,CAAC;IAChB;;;OAGG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,iFAAiF;IACjF,eAAe,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACrE;AAqFD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,sBAAsB,GAAG,QAAQ,EAAE,CA0OnF"}
@@ -0,0 +1,274 @@
1
+ import { JiraApiError } from "../../jira/api.js";
2
+ import { registerApiRoute } from "@mastra/core/server";
3
+ //#region src/integrations/platform/jira/routes.ts
4
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
5
+ const ISSUE_KEY_RE = /^[A-Za-z][A-Za-z0-9_]*-\d+$/;
6
+ /** Erase a route handler's path-parameterized context to a plain `Context`. */
7
+ function loose(c) {
8
+ return c;
9
+ }
10
+ /**
11
+ * Narrow the caller's selected Jira projects to the ones that feed this
12
+ * Factory project.
13
+ *
14
+ * A Jira issue carries no Factory project of its own, so without a binding
15
+ * every board view would show every selected project's issues on whichever
16
+ * Factory happened to be on screen. Only sources explicitly bound to a board
17
+ * of this Factory pass — nothing is routed implicitly. Mirrors the Linear
18
+ * routes' scoping semantics locally — the generic binding storage is
19
+ * provider-neutral.
20
+ */
21
+ async function scopeSourceIdsToProject({ intake, orgId, factoryProjectId, selectedIds }) {
22
+ const selected = new Set(selectedIds);
23
+ const intakeBoards = {};
24
+ for (const binding of await intake.listBindings({
25
+ orgId,
26
+ integrationId: "jira"
27
+ })) if (binding.factoryProjectId === factoryProjectId && binding.board && selected.has(binding.sourceId)) intakeBoards[binding.sourceId] = binding.board;
28
+ return intakeBoards;
29
+ }
30
+ /**
31
+ * Resolve the org-scoped tenant for a Jira request. Intake selections are
32
+ * org-owned, so it requires both a signed-in user and an organization — same
33
+ * tenancy rules as the Linear routes.
34
+ */
35
+ async function resolveOrgTenant(c, auth) {
36
+ await auth.ensureUser(c);
37
+ const tenant = auth.tenant(c);
38
+ if (!tenant) return { response: c.json({ error: "unauthorized" }, 401) };
39
+ if (!tenant.orgId) return { response: c.json({
40
+ error: "organization_required",
41
+ message: "Jira intake requires an organization. Personal accounts cannot use Jira intake."
42
+ }, 403) };
43
+ return { tenant: {
44
+ orgId: tenant.orgId,
45
+ userId: tenant.userId
46
+ } };
47
+ }
48
+ /**
49
+ * Validate an opaque Jira pagination cursor from the query string. Cursors are
50
+ * server-issued (`nextPageToken`), so anything outside a conservative
51
+ * charset/length is rejected rather than forwarded to Jira.
52
+ */
53
+ function parseAfterCursor(raw) {
54
+ if (raw === void 0 || raw === "") return void 0;
55
+ if (raw.length > 512 || !/^[\w+/=.:-]+$/.test(raw)) return null;
56
+ return raw;
57
+ }
58
+ /** Map a Jira read failure to the API response for the SPA. */
59
+ function jiraFetchError(c, err) {
60
+ if (err instanceof JiraApiError && err.code === "jira_auth_failed") return c.json({
61
+ error: "jira_auth_failed",
62
+ message: "Jira rejected the connected account. Reconnect it in Mastra Platform."
63
+ }, 409);
64
+ return c.json({
65
+ error: "jira_fetch_failed",
66
+ message: err instanceof Error ? err.message : String(err)
67
+ }, 502);
68
+ }
69
+ /**
70
+ * Build the Jira routes as Mastra `apiRoutes`. When the feature is disabled,
71
+ * returns only the `status` route so the SPA can detect the disabled state.
72
+ */
73
+ function buildPlatformJiraRoutes(options) {
74
+ const routes = [];
75
+ const { jira, auth, intake } = options;
76
+ const enabled = Boolean(jira) && auth.enabled();
77
+ const diagnostics = () => ({
78
+ jiraConfigured: Boolean(jira),
79
+ factoryAuthEnabled: auth.enabled(),
80
+ appDbConfigured: options.appDbConfigured
81
+ });
82
+ routes.push(registerApiRoute("/web/jira/status", {
83
+ method: "GET",
84
+ requiresAuth: false,
85
+ handler: async (c) => {
86
+ if (!enabled || !jira || !intake) return c.json({
87
+ enabled: false,
88
+ configured: Boolean(jira),
89
+ mode: "platform",
90
+ site: null,
91
+ reason: "missing_config",
92
+ diagnostics: diagnostics()
93
+ });
94
+ await auth.ensureUser(loose(c));
95
+ const tenant = auth.tenant(loose(c));
96
+ if (!tenant) return c.json({
97
+ error: "unauthorized",
98
+ reason: "auth_required"
99
+ }, 401);
100
+ if (!tenant.orgId) return c.json({
101
+ enabled: true,
102
+ configured: false,
103
+ mode: "platform",
104
+ organizationRequired: true,
105
+ site: null,
106
+ sites: [],
107
+ connections: [],
108
+ reason: "organization_required",
109
+ diagnostics: diagnostics()
110
+ });
111
+ try {
112
+ const connections = await jira.listConnections();
113
+ const active = connections.filter((connection) => connection.status === "active");
114
+ const sites = active.flatMap((connection) => connection.accountLabel ? [connection.accountLabel] : []);
115
+ return c.json({
116
+ enabled: true,
117
+ configured: active.length > 0,
118
+ mode: "platform",
119
+ site: sites.length === 1 ? sites[0] : null,
120
+ sites,
121
+ connections,
122
+ reason: active.length > 0 ? "ready" : "not_connected",
123
+ diagnostics: diagnostics()
124
+ });
125
+ } catch (err) {
126
+ return jiraFetchError(loose(c), err);
127
+ }
128
+ }
129
+ }));
130
+ if (!enabled || !jira || !intake) return routes;
131
+ routes.push(registerApiRoute("/web/jira/projects", {
132
+ method: "GET",
133
+ requiresAuth: false,
134
+ handler: async (c) => {
135
+ const resolved = await resolveOrgTenant(loose(c), auth);
136
+ if ("response" in resolved) return resolved.response;
137
+ try {
138
+ const sources = await jira.intake.listSources(resolved.tenant);
139
+ return c.json({ projects: sources.map((source) => ({
140
+ id: source.id,
141
+ name: source.name,
142
+ key: typeof source.metadata?.key === "string" ? source.metadata.key : null,
143
+ connectionId: typeof source.metadata?.connectionId === "string" ? source.metadata.connectionId : null,
144
+ site: typeof source.metadata?.site === "string" ? source.metadata.site : null
145
+ })) });
146
+ } catch (err) {
147
+ return jiraFetchError(loose(c), err);
148
+ }
149
+ }
150
+ }));
151
+ routes.push(registerApiRoute("/web/jira/issues", {
152
+ method: "GET",
153
+ requiresAuth: false,
154
+ handler: async (c) => {
155
+ const resolved = await resolveOrgTenant(loose(c), auth);
156
+ if ("response" in resolved) return resolved.response;
157
+ const after = parseAfterCursor(c.req.query("after"));
158
+ if (after === null) return c.json({ error: "invalid_cursor" }, 400);
159
+ const factoryProjectId = c.req.query("factoryProjectId");
160
+ if (factoryProjectId && !UUID_RE.test(factoryProjectId)) return c.json({ error: "invalid_factory_project_id" }, 400);
161
+ await intake.ensureReady();
162
+ const selection = (await intake.getConfig({
163
+ orgId: resolved.tenant.orgId,
164
+ integrationIds: ["jira"]
165
+ })).jira;
166
+ if (!selection.enabled) return c.json({
167
+ error: "jira_intake_disabled",
168
+ message: "Jira intake is turned off in Settings."
169
+ }, 404);
170
+ const selectedIds = selection.sourceIds ?? [];
171
+ const intakeBoards = factoryProjectId ? await scopeSourceIdsToProject({
172
+ intake,
173
+ orgId: resolved.tenant.orgId,
174
+ factoryProjectId,
175
+ selectedIds
176
+ }) : null;
177
+ const projectIds = intakeBoards ? Object.keys(intakeBoards) : selectedIds;
178
+ if (projectIds.length === 0) return c.json({
179
+ issues: [],
180
+ nextCursor: null
181
+ });
182
+ try {
183
+ const { issues, nextCursor } = await jira.listActiveIssues(after, projectIds);
184
+ const issuePayload = issues.map((issue) => ({
185
+ id: issue.externalId,
186
+ identifier: issue.identifier,
187
+ title: issue.title,
188
+ url: issue.url,
189
+ author: issue.author,
190
+ state: issue.state ?? "",
191
+ stateType: issue.stateType ?? "",
192
+ priorityLabel: issue.priority ?? "",
193
+ assignee: issue.assignee,
194
+ project: issue.source,
195
+ site: issue.site,
196
+ labels: issue.labels,
197
+ createdAt: issue.createdAt,
198
+ updatedAt: issue.updatedAt,
199
+ sourceId: issue.sourceId || null
200
+ }));
201
+ if (factoryProjectId && intakeBoards && options.ingestFactoryIssues) await options.ingestFactoryIssues({
202
+ orgId: resolved.tenant.orgId,
203
+ userId: resolved.tenant.userId,
204
+ factoryProjectId,
205
+ issues: issuePayload.map((issue) => ({
206
+ ...issue,
207
+ site: issue.site ?? null
208
+ })),
209
+ intakeBoards
210
+ });
211
+ return c.json({
212
+ issues: issuePayload,
213
+ nextCursor
214
+ });
215
+ } catch (err) {
216
+ return jiraFetchError(loose(c), err);
217
+ }
218
+ }
219
+ }));
220
+ routes.push(registerApiRoute("/web/jira/issues/:identifier", {
221
+ method: "GET",
222
+ requiresAuth: false,
223
+ handler: async (c) => {
224
+ const resolved = await resolveOrgTenant(loose(c), auth);
225
+ if ("response" in resolved) return resolved.response;
226
+ const identifier = c.req.param("identifier");
227
+ const factoryProjectId = c.req.query("factoryProjectId");
228
+ const issueRef = c.req.query("issueRef");
229
+ if (!ISSUE_KEY_RE.test(identifier)) return c.json({ error: "invalid_issue_identifier" }, 400);
230
+ if (!factoryProjectId || !UUID_RE.test(factoryProjectId)) return c.json({ error: "invalid_factory_project_id" }, 400);
231
+ if (!issueRef || issueRef.length > 2048) return c.json({ error: "invalid_issue_ref" }, 400);
232
+ await intake.ensureReady();
233
+ const selection = (await intake.getConfig({
234
+ orgId: resolved.tenant.orgId,
235
+ integrationIds: ["jira"]
236
+ })).jira;
237
+ if (!selection.enabled) return c.json({
238
+ error: "jira_intake_disabled",
239
+ message: "Jira intake is turned off in Settings."
240
+ }, 404);
241
+ const intakeBoards = await scopeSourceIdsToProject({
242
+ intake,
243
+ orgId: resolved.tenant.orgId,
244
+ factoryProjectId,
245
+ selectedIds: selection.sourceIds ?? []
246
+ });
247
+ const dispatch = await jira.intake.resolveIntakeDispatch?.({
248
+ orgId: resolved.tenant.orgId,
249
+ externalSource: {
250
+ type: "issue",
251
+ externalId: issueRef
252
+ }
253
+ });
254
+ if (!dispatch?.sourceId || !(dispatch.sourceId in intakeBoards)) return c.json({ error: "issue_not_found" }, 404);
255
+ try {
256
+ const issue = await jira.intake.getIssue(dispatch);
257
+ if (!issue || issue.identifier.toUpperCase() !== identifier.toUpperCase()) return c.json({ error: "issue_not_found" }, 404);
258
+ return c.json({
259
+ identifier: issue.identifier,
260
+ title: issue.title,
261
+ url: issue.url,
262
+ description: issue.description
263
+ });
264
+ } catch (err) {
265
+ return jiraFetchError(loose(c), err);
266
+ }
267
+ }
268
+ }));
269
+ return routes;
270
+ }
271
+ //#endregion
272
+ export { buildPlatformJiraRoutes };
273
+
274
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","names":[],"sources":["../../../../src/integrations/platform/jira/routes.ts"],"sourcesContent":["/**\n * Mastra `apiRoutes` for the Jira intake feature.\n *\n * Registered alongside the other `/web/*` routes, behind the host auth gate.\n * Jira connections are owned by the caller's Mastra Platform organization;\n * provider requests stay server-side and flow through the integrations v2\n * proxy. Every route re-resolves the authenticated user and scopes intake\n * selections by the caller's org.\n *\n * When the feature is disabled (no auth, or no intake storage),\n * `buildPlatformJiraRoutes` returns only `GET /web/jira/status`, which reports\n * `enabled:false` so the SPA can cleanly hide all Jira UI.\n */\n\nimport type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { Context } from 'hono';\n\nimport type { RouteAuth } from '../../../routes/route.js';\nimport type { IntakeStorage } from '../../../storage/domains/intake/base.js';\nimport { JiraApiError } from '../../jira/api.js';\nimport type { JiraRulesIngress } from '../../jira/rules.js';\nimport type { PlatformJiraIntegration } from './integration.js';\n\ntype RouteContext = Context;\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nconst ISSUE_KEY_RE = /^[A-Za-z][A-Za-z0-9_]*-\\d+$/;\n\n/** Erase a route handler's path-parameterized context to a plain `Context`. */\nfunction loose(c: unknown): RouteContext {\n return c as RouteContext;\n}\n\n/**\n * Non-secret diagnostic snapshot of every Jira feature gate, mirroring the\n * Linear diagnostics shape. Only booleans — never values.\n */\nexport interface JiraFeatureDiagnostics {\n jiraConfigured: boolean;\n factoryAuthEnabled: boolean;\n appDbConfigured: boolean;\n}\n\nexport interface MountJiraRoutesOptions {\n /**\n * The integration instance providing REST access. Required for everything\n * beyond the disabled `status` route.\n */\n jira?: PlatformJiraIntegration;\n /** Host auth seam. Intake selections are org-owned, so the feature is inert without it. */\n auth: RouteAuth;\n /**\n * Cross-integration intake selection domain. Required for the issues route's\n * project filter; when absent, only the disabled `status` route is served.\n */\n intake?: IntakeStorage;\n /** Whether the host configured the application database backing intake state. */\n appDbConfigured: boolean;\n /**\n * Factory rules ingress for observed issues. When present, a board-scoped\n * issue listing also materializes new cards through the Jira event rules —\n * the same automatic intake Linear has.\n */\n ingestFactoryIssues?: (input: JiraRulesIngress) => Promise<unknown>;\n}\n\n/**\n * Narrow the caller's selected Jira projects to the ones that feed this\n * Factory project.\n *\n * A Jira issue carries no Factory project of its own, so without a binding\n * every board view would show every selected project's issues on whichever\n * Factory happened to be on screen. Only sources explicitly bound to a board\n * of this Factory pass — nothing is routed implicitly. Mirrors the Linear\n * routes' scoping semantics locally — the generic binding storage is\n * provider-neutral.\n */\nasync function scopeSourceIdsToProject({\n intake,\n orgId,\n factoryProjectId,\n selectedIds,\n}: {\n intake: IntakeStorage;\n orgId: string;\n factoryProjectId: string;\n selectedIds: string[];\n}): Promise<Record<string, string>> {\n const selected = new Set(selectedIds);\n const intakeBoards: Record<string, string> = {};\n for (const binding of await intake.listBindings({ orgId, integrationId: 'jira' })) {\n if (binding.factoryProjectId === factoryProjectId && binding.board && selected.has(binding.sourceId)) {\n intakeBoards[binding.sourceId] = binding.board;\n }\n }\n return intakeBoards;\n}\n\n/**\n * Resolve the org-scoped tenant for a Jira request. Intake selections are\n * org-owned, so it requires both a signed-in user and an organization — same\n * tenancy rules as the Linear routes.\n */\nasync function resolveOrgTenant(\n c: RouteContext,\n auth: RouteAuth,\n): Promise<{ tenant: { orgId: string; userId: string } } | { response: Response }> {\n await auth.ensureUser(c);\n const tenant = auth.tenant(c);\n if (!tenant) return { response: c.json({ error: 'unauthorized' }, 401) };\n if (!tenant.orgId) {\n return {\n response: c.json(\n {\n error: 'organization_required',\n message: 'Jira intake requires an organization. Personal accounts cannot use Jira intake.',\n },\n 403,\n ),\n };\n }\n return { tenant: { orgId: tenant.orgId, userId: tenant.userId } };\n}\n\n/**\n * Validate an opaque Jira pagination cursor from the query string. Cursors are\n * server-issued (`nextPageToken`), so anything outside a conservative\n * charset/length is rejected rather than forwarded to Jira.\n */\nfunction parseAfterCursor(raw: string | undefined): string | undefined | null {\n if (raw === undefined || raw === '') return undefined;\n if (raw.length > 512 || !/^[\\w+/=.:-]+$/.test(raw)) return null;\n return raw;\n}\n\n/** Map a Jira read failure to the API response for the SPA. */\nfunction jiraFetchError(c: RouteContext, err: unknown) {\n if (err instanceof JiraApiError && err.code === 'jira_auth_failed') {\n return c.json(\n {\n error: 'jira_auth_failed',\n message: 'Jira rejected the connected account. Reconnect it in Mastra Platform.',\n },\n 409,\n );\n }\n return c.json({ error: 'jira_fetch_failed', message: err instanceof Error ? err.message : String(err) }, 502);\n}\n\n/**\n * Build the Jira routes as Mastra `apiRoutes`. When the feature is disabled,\n * returns only the `status` route so the SPA can detect the disabled state.\n */\nexport function buildPlatformJiraRoutes(options: MountJiraRoutesOptions): ApiRoute[] {\n const routes: ApiRoute[] = [];\n const { jira, auth, intake } = options;\n const enabled = Boolean(jira) && auth.enabled();\n const diagnostics = (): JiraFeatureDiagnostics => ({\n jiraConfigured: Boolean(jira),\n factoryAuthEnabled: auth.enabled(),\n appDbConfigured: options.appDbConfigured,\n });\n\n // The status route is always registered so the SPA can detect the disabled state.\n routes.push(\n registerApiRoute('/web/jira/status', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n if (!enabled || !jira || !intake) {\n return c.json({\n enabled: false,\n configured: Boolean(jira),\n mode: 'platform',\n site: null,\n reason: 'missing_config',\n diagnostics: diagnostics(),\n });\n }\n await auth.ensureUser(loose(c));\n const tenant = auth.tenant(loose(c));\n if (!tenant) return c.json({ error: 'unauthorized', reason: 'auth_required' }, 401);\n\n if (!tenant.orgId) {\n return c.json({\n enabled: true,\n configured: false,\n mode: 'platform',\n organizationRequired: true,\n site: null,\n sites: [],\n connections: [],\n reason: 'organization_required',\n diagnostics: diagnostics(),\n });\n }\n\n try {\n const connections = await jira.listConnections();\n const active = connections.filter(connection => connection.status === 'active');\n const sites = active.flatMap(connection => (connection.accountLabel ? [connection.accountLabel] : []));\n return c.json({\n enabled: true,\n configured: active.length > 0,\n mode: 'platform',\n site: sites.length === 1 ? sites[0] : null,\n sites,\n connections,\n reason: active.length > 0 ? 'ready' : 'not_connected',\n diagnostics: diagnostics(),\n });\n } catch (err) {\n return jiraFetchError(loose(c), err);\n }\n },\n }),\n );\n\n // Without the integration instance or the intake domain the feature can't\n // serve org-scoped data — serve only the disabled `status` route.\n if (!enabled || !jira || !intake) {\n return routes;\n }\n\n // ── List the site's projects (Settings intake-source picker) ────────────\n routes.push(\n registerApiRoute('/web/jira/projects', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n\n try {\n const sources = await jira.intake.listSources(resolved.tenant);\n return c.json({\n projects: sources.map(source => ({\n id: source.id,\n name: source.name,\n key: typeof source.metadata?.key === 'string' ? source.metadata.key : null,\n connectionId: typeof source.metadata?.connectionId === 'string' ? source.metadata.connectionId : null,\n site: typeof source.metadata?.site === 'string' ? source.metadata.site : null,\n })),\n });\n } catch (err) {\n return jiraFetchError(loose(c), err);\n }\n },\n }),\n );\n\n // ── List the site's active issues (cursor-paged) ────────────────────────\n // Respects the caller's intake config: disabled Jira intake 404s the\n // source, and an explicit project selection narrows the issue filter.\n routes.push(\n registerApiRoute('/web/jira/issues', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n\n const after = parseAfterCursor(c.req.query('after'));\n if (after === null) return c.json({ error: 'invalid_cursor' }, 400);\n const factoryProjectId = c.req.query('factoryProjectId');\n if (factoryProjectId && !UUID_RE.test(factoryProjectId)) {\n return c.json({ error: 'invalid_factory_project_id' }, 400);\n }\n\n await intake.ensureReady();\n const config = await intake.getConfig({ orgId: resolved.tenant.orgId, integrationIds: ['jira'] });\n const selection = config.jira!;\n if (!selection.enabled) {\n return c.json({ error: 'jira_intake_disabled', message: 'Jira intake is turned off in Settings.' }, 404);\n }\n\n // No projects selected means nothing is synced — don't fan out to Jira.\n const selectedIds = selection.sourceIds ?? [];\n // A board request only ever sees the projects routed to a board of\n // that Factory project; unscoped listing stays available to callers\n // that don't view a specific board.\n const intakeBoards = factoryProjectId\n ? await scopeSourceIdsToProject({\n intake,\n orgId: resolved.tenant.orgId,\n factoryProjectId,\n selectedIds,\n })\n : null;\n const projectIds = intakeBoards ? Object.keys(intakeBoards) : selectedIds;\n if (projectIds.length === 0) {\n return c.json({ issues: [], nextCursor: null });\n }\n\n try {\n const { issues, nextCursor } = await jira.listActiveIssues(after, projectIds);\n const issuePayload = issues.map(issue => ({\n id: issue.externalId,\n identifier: issue.identifier,\n title: issue.title,\n url: issue.url,\n author: issue.author,\n state: issue.state ?? '',\n stateType: issue.stateType ?? '',\n priorityLabel: issue.priority ?? '',\n assignee: issue.assignee,\n project: issue.source,\n site: issue.site,\n labels: issue.labels,\n createdAt: issue.createdAt,\n updatedAt: issue.updatedAt,\n sourceId: issue.sourceId || null,\n }));\n if (factoryProjectId && intakeBoards && options.ingestFactoryIssues) {\n await options.ingestFactoryIssues({\n orgId: resolved.tenant.orgId,\n userId: resolved.tenant.userId,\n factoryProjectId,\n issues: issuePayload.map(issue => ({ ...issue, site: issue.site ?? null })),\n intakeBoards,\n });\n }\n return c.json({ issues: issuePayload, nextCursor });\n } catch (err) {\n return jiraFetchError(loose(c), err);\n }\n },\n }),\n );\n\n routes.push(\n registerApiRoute('/web/jira/issues/:identifier', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n\n const identifier = c.req.param('identifier');\n const factoryProjectId = c.req.query('factoryProjectId');\n const issueRef = c.req.query('issueRef');\n if (!ISSUE_KEY_RE.test(identifier)) return c.json({ error: 'invalid_issue_identifier' }, 400);\n if (!factoryProjectId || !UUID_RE.test(factoryProjectId)) {\n return c.json({ error: 'invalid_factory_project_id' }, 400);\n }\n if (!issueRef || issueRef.length > 2_048) return c.json({ error: 'invalid_issue_ref' }, 400);\n\n await intake.ensureReady();\n const config = await intake.getConfig({ orgId: resolved.tenant.orgId, integrationIds: ['jira'] });\n const selection = config.jira!;\n if (!selection.enabled) {\n return c.json({ error: 'jira_intake_disabled', message: 'Jira intake is turned off in Settings.' }, 404);\n }\n\n const intakeBoards = await scopeSourceIdsToProject({\n intake,\n orgId: resolved.tenant.orgId,\n factoryProjectId,\n selectedIds: selection.sourceIds ?? [],\n });\n const dispatch = await jira.intake.resolveIntakeDispatch?.({\n orgId: resolved.tenant.orgId,\n externalSource: { type: 'issue', externalId: issueRef },\n });\n if (!dispatch?.sourceId || !(dispatch.sourceId in intakeBoards)) {\n return c.json({ error: 'issue_not_found' }, 404);\n }\n\n try {\n const issue = await jira.intake.getIssue(dispatch);\n if (!issue || issue.identifier.toUpperCase() !== identifier.toUpperCase()) {\n return c.json({ error: 'issue_not_found' }, 404);\n }\n return c.json({\n identifier: issue.identifier,\n title: issue.title,\n url: issue.url,\n description: issue.description,\n });\n } catch (err) {\n return jiraFetchError(loose(c), err);\n }\n },\n }),\n );\n\n return routes;\n}\n"],"mappings":"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"}
@@ -6,7 +6,7 @@ import type { RouteAuth } from '../../../routes/route.js';
6
6
  import type { FactoryProjectsStorage } from '../../../storage/domains/projects/base.js';
7
7
  import type { FactoryIntegration, IntegrationContext, IntegrationTools } from '../../base.js';
8
8
  import type { LinearEventRules, LinearRuleOverrides } from '../../linear/default-rules.js';
9
- import type { LinearConnectionCheck } from '../../linear/integration.js';
9
+ import type { LinearConnectionCheck, LinearIssueDetail as LinearRouteIssueDetail } from '../../linear/integration.js';
10
10
  import type { LinearConnectionRow, LinearStorageHandle } from '../../linear/storage.js';
11
11
  type LinearWorkspace = {
12
12
  linearWorkspaceId: string;
@@ -24,6 +24,11 @@ type LinearProject = {
24
24
  name: string;
25
25
  }>;
26
26
  };
27
+ type LinearTeam = {
28
+ id: string;
29
+ key: string;
30
+ name: string;
31
+ };
27
32
  export declare class PlatformLinearIntegration implements FactoryIntegration {
28
33
  #private;
29
34
  readonly id = "linear";
@@ -53,7 +58,35 @@ export declare class PlatformLinearIntegration implements FactoryIntegration {
53
58
  listProjects(): Promise<Array<LinearProject & {
54
59
  workspaceId: string;
55
60
  }>>;
61
+ listTeams(_accessToken: string): Promise<Array<LinearTeam & {
62
+ workspaceId: string;
63
+ sourceId: string;
64
+ }>>;
65
+ fetchIssueDetail(_accessToken: string, idOrIdentifier: string, sourceIds?: string[], routedSourceIds?: string[]): Promise<LinearRouteIssueDetail | null>;
66
+ sourceMatchesIssue(sourceId: string, issue: Pick<LinearRouteIssueDetail, 'workspaceId' | 'projectId' | 'teamId'>): boolean;
56
67
  listWorkspaces(): Promise<LinearWorkspace[]>;
57
68
  }
69
+ export declare function encodeSourceId(workspaceId: string, projectId: string): string;
70
+ export declare function encodeTeamSourceId(workspaceId: string, teamId: string): string;
71
+ export declare function decodeTeamSourceId(sourceId: string): {
72
+ workspaceId: string;
73
+ teamId: string;
74
+ };
75
+ /**
76
+ * A decoded intake source: either a Linear project or a whole Linear team.
77
+ * Downstream code discriminates on `kind` to build the right issue-listing
78
+ * filter and to apply most-specific-wins routing (project beats team).
79
+ */
80
+ export type DecodedSource = {
81
+ kind: 'project';
82
+ workspaceId: string;
83
+ projectId: string;
84
+ } | {
85
+ kind: 'team';
86
+ workspaceId: string;
87
+ teamId: string;
88
+ };
89
+ /** Discriminate any Linear source id by its prefix and decode it. */
90
+ export declare function parseSourceId(sourceId: string): DecodedSource;
58
91
  export {};
59
92
  //# sourceMappingURL=integration.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../../../../src/integrations/platform/linear/integration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAIxD,OAAO,KAAK,EAAE,MAAM,EAA0D,MAAM,iCAAiC,CAAC;AACtH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AACxF,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAE9F,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAE3F,OAAO,KAAK,EAAE,qBAAqB,EAAqB,MAAM,6BAA6B,CAAC;AAQ5F,OAAO,KAAK,EAAwB,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AA+C9G,KAAK,eAAe,GAAG;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AACF,KAAK,aAAa,GAAG;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACzD,CAAC;AAwBF,qBAAa,yBAA0B,YAAW,kBAAkB;;IAClE,QAAQ,CAAC,EAAE,YAAY;IAYvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CA2IrB;IAIF,IAAI,KAAK,IAAI,gBAAgB,CAE5B;gBAEW,EAAE,KAAK,EAAE,GAAE;QAAE,KAAK,CAAC,EAAE,mBAAmB,CAAA;KAAO;IAO3D,IAAI,OAAO,IAAI,mBAAmB,CAuBjC;IAED,IAAI,QAAQ,IAAI,sBAAsB,CAGrC;IAED,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE;QAAE,QAAQ,EAAE,sBAAsB,CAAC;QAAC,IAAI,CAAC,EAAE,SAAS,CAAA;KAAE,GAAG,IAAI;IAM5F,IAAI,WAAW,IAAI,OAAO,CAEzB;IAEK,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IASxD,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;IAmBlE,mBAAmB,CAAC,WAAW,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC;IAyB5E,eAAe,CAAC,UAAU,EAAE,mBAAmB,GAAG,OAAO;IAKnD,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IASpE,OAAO,CAAC,GAAG,EAAE,kBAAkB,GAAG,YAAY,EAAE;IA8BhD,MAAM,CAAC,GAAG,EAAE,kBAAkB,GAAG,QAAQ,EAAE;IAsCrC,UAAU,CAAC,EAAE,cAAc,EAAE,EAAE;QAAE,cAAc,EAAE,cAAc,CAAA;KAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAInG,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAIhC,YAAY,IAAI,OAAO,CAAC,KAAK,CAAC,aAAa,GAAG;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IA+BvE,cAAc,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;CAuInD"}
1
+ {"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../../../../src/integrations/platform/linear/integration.ts"],"names":[],"mappings":"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"}