@mastra/factory 0.24.0-alpha.8 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. package/README.md +4 -4
  2. package/dist/environment/build-runner.js +2 -1
  3. package/dist/environment/build-runner.js.map +1 -1
  4. package/dist/environment/build-workflow.js +1 -1
  5. package/dist/environment/build-workflow.js.map +1 -1
  6. package/dist/environment/build.js +16 -14
  7. package/dist/environment/build.js.map +1 -1
  8. package/dist/factory.d.ts.map +1 -1
  9. package/dist/factory.js +111 -19
  10. package/dist/factory.js.map +1 -1
  11. package/dist/integrations/base.d.ts +1 -1
  12. package/dist/integrations/base.d.ts.map +1 -1
  13. package/dist/integrations/github/app-identity.js.map +1 -1
  14. package/dist/integrations/github/integration.js +1 -1
  15. package/dist/integrations/github/integration.js.map +1 -1
  16. package/dist/integrations/github/reconcile-worker.js +1 -1
  17. package/dist/integrations/github/reconcile-worker.js.map +1 -1
  18. package/dist/integrations/github/routes.d.ts +1 -1
  19. package/dist/integrations/github/routes.d.ts.map +1 -1
  20. package/dist/integrations/github/routes.js +24 -13
  21. package/dist/integrations/github/routes.js.map +1 -1
  22. package/dist/integrations/github/rules.d.ts.map +1 -1
  23. package/dist/integrations/github/rules.js +53 -9
  24. package/dist/integrations/github/rules.js.map +1 -1
  25. package/dist/integrations/github/sandbox.js +2 -2
  26. package/dist/integrations/github/sandbox.js.map +1 -1
  27. package/dist/integrations/github/session-subscriptions.d.ts.map +1 -1
  28. package/dist/integrations/github/session-subscriptions.js +1 -2
  29. package/dist/integrations/github/session-subscriptions.js.map +1 -1
  30. package/dist/integrations/github/subscriptions.d.ts +7 -4
  31. package/dist/integrations/github/subscriptions.d.ts.map +1 -1
  32. package/dist/integrations/github/subscriptions.js +5 -5
  33. package/dist/integrations/github/subscriptions.js.map +1 -1
  34. package/dist/integrations/gitlab/api.js.map +1 -1
  35. package/dist/integrations/gitlab/integration.js.map +1 -1
  36. package/dist/integrations/gitlab/reconciliation-config.js +2 -1
  37. package/dist/integrations/gitlab/reconciliation-config.js.map +1 -1
  38. package/dist/integrations/gitlab/routes.d.ts.map +1 -1
  39. package/dist/integrations/gitlab/routes.js +10 -6
  40. package/dist/integrations/gitlab/routes.js.map +1 -1
  41. package/dist/integrations/gitlab/rules.js.map +1 -1
  42. package/dist/integrations/gitlab/session-subscriptions.d.ts.map +1 -1
  43. package/dist/integrations/gitlab/session-subscriptions.js +1 -2
  44. package/dist/integrations/gitlab/session-subscriptions.js.map +1 -1
  45. package/dist/integrations/gitlab/subscriptions.d.ts +7 -4
  46. package/dist/integrations/gitlab/subscriptions.d.ts.map +1 -1
  47. package/dist/integrations/gitlab/subscriptions.js +5 -5
  48. package/dist/integrations/gitlab/subscriptions.js.map +1 -1
  49. package/dist/integrations/incidentio/api.js.map +1 -1
  50. package/dist/integrations/incidentio/integration.js.map +1 -1
  51. package/dist/integrations/incidentio/rules.js.map +1 -1
  52. package/dist/integrations/issue-reconcile-worker.js +1 -1
  53. package/dist/integrations/issue-reconcile-worker.js.map +1 -1
  54. package/dist/integrations/issue-reconciler.js +1 -1
  55. package/dist/integrations/issue-reconciler.js.map +1 -1
  56. package/dist/integrations/jira/api.js.map +1 -1
  57. package/dist/integrations/jira/integration.js.map +1 -1
  58. package/dist/integrations/jira/rules.js.map +1 -1
  59. package/dist/integrations/linear/agent-tools.d.ts.map +1 -1
  60. package/dist/integrations/linear/agent-tools.js.map +1 -1
  61. package/dist/integrations/linear/integration.js.map +1 -1
  62. package/dist/integrations/linear/rules.js.map +1 -1
  63. package/dist/integrations/platform/api-client.js.map +1 -1
  64. package/dist/integrations/platform/github/event-worker.js +1 -1
  65. package/dist/integrations/platform/github/event-worker.js.map +1 -1
  66. package/dist/integrations/platform/github/integration.js +2 -2
  67. package/dist/integrations/platform/github/integration.js.map +1 -1
  68. package/dist/integrations/platform/gitlab/event-worker.js.map +1 -1
  69. package/dist/integrations/platform/gitlab/integration.js.map +1 -1
  70. package/dist/integrations/platform/incidentio/integration.js +2 -1
  71. package/dist/integrations/platform/incidentio/integration.js.map +1 -1
  72. package/dist/integrations/platform/jira/integration.js.map +1 -1
  73. package/dist/integrations/platform/linear/event-worker.js +1 -1
  74. package/dist/integrations/platform/linear/event-worker.js.map +1 -1
  75. package/dist/integrations/platform/linear/integration.js.map +1 -1
  76. package/dist/integrations/slack/connect-route.js +1 -1
  77. package/dist/integrations/slack/connect-route.js.map +1 -1
  78. package/dist/integrations/slack/feed-publisher.js +1 -1
  79. package/dist/integrations/slack/feed-publisher.js.map +1 -1
  80. package/dist/integrations/slack/integration.js +1 -1
  81. package/dist/integrations/slack/integration.js.map +1 -1
  82. package/dist/integrations/slack/slack.d.ts +16 -5
  83. package/dist/integrations/slack/slack.d.ts.map +1 -1
  84. package/dist/integrations/slack/slack.js +87 -34
  85. package/dist/integrations/slack/slack.js.map +1 -1
  86. package/dist/integrations/subscription-session.d.ts +0 -1
  87. package/dist/integrations/subscription-session.d.ts.map +1 -1
  88. package/dist/integrations/subscription-session.js +1 -4
  89. package/dist/integrations/subscription-session.js.map +1 -1
  90. package/dist/integrations/workos/integration.js.map +1 -1
  91. package/dist/mcp/routes.d.ts.map +1 -1
  92. package/dist/mcp/routes.js +1 -1
  93. package/dist/mcp/routes.js.map +1 -1
  94. package/dist/packages/_internals/workspace/dist/index.js +18 -1
  95. package/dist/packages/_internals/workspace/dist/index.js.map +1 -1
  96. package/dist/routes/attention-activity.d.ts.map +1 -1
  97. package/dist/routes/attention-activity.js +5 -2
  98. package/dist/routes/attention-activity.js.map +1 -1
  99. package/dist/routes/attention-parked.js.map +1 -1
  100. package/dist/routes/attention-providers.d.ts +0 -1
  101. package/dist/routes/attention-providers.d.ts.map +1 -1
  102. package/dist/routes/attention-providers.js +5 -6
  103. package/dist/routes/attention-providers.js.map +1 -1
  104. package/dist/routes/automation-runs.js.map +1 -1
  105. package/dist/routes/config.d.ts +6 -7
  106. package/dist/routes/config.d.ts.map +1 -1
  107. package/dist/routes/config.js +20 -19
  108. package/dist/routes/config.js.map +1 -1
  109. package/dist/routes/contracts.js +1 -1
  110. package/dist/routes/contracts.js.map +1 -1
  111. package/dist/routes/custom-provider-source.js.map +1 -1
  112. package/dist/routes/fs.d.ts +31 -23
  113. package/dist/routes/fs.d.ts.map +1 -1
  114. package/dist/routes/fs.js +218 -64
  115. package/dist/routes/fs.js.map +1 -1
  116. package/dist/routes/intake.js +2 -1
  117. package/dist/routes/intake.js.map +1 -1
  118. package/dist/routes/knowledge.js +1 -1
  119. package/dist/routes/knowledge.js.map +1 -1
  120. package/dist/routes/oauth.js +3 -2
  121. package/dist/routes/oauth.js.map +1 -1
  122. package/dist/routes/projects.d.ts +1 -1
  123. package/dist/routes/projects.d.ts.map +1 -1
  124. package/dist/routes/projects.js +33 -31
  125. package/dist/routes/projects.js.map +1 -1
  126. package/dist/routes/provider-credentials.d.ts.map +1 -1
  127. package/dist/routes/provider-credentials.js +6 -1
  128. package/dist/routes/provider-credentials.js.map +1 -1
  129. package/dist/routes/session-access.d.ts +55 -0
  130. package/dist/routes/session-access.d.ts.map +1 -0
  131. package/dist/routes/session-access.js +165 -0
  132. package/dist/routes/session-access.js.map +1 -0
  133. package/dist/routes/skills.d.ts +2 -4
  134. package/dist/routes/skills.d.ts.map +1 -1
  135. package/dist/routes/skills.js +19 -65
  136. package/dist/routes/skills.js.map +1 -1
  137. package/dist/routes/source-control-sessions.d.ts +6 -1
  138. package/dist/routes/source-control-sessions.d.ts.map +1 -1
  139. package/dist/routes/source-control-sessions.js +95 -12
  140. package/dist/routes/source-control-sessions.js.map +1 -1
  141. package/dist/routes/surface.d.ts +5 -0
  142. package/dist/routes/surface.d.ts.map +1 -1
  143. package/dist/routes/surface.js +10 -4
  144. package/dist/routes/surface.js.map +1 -1
  145. package/dist/routes/tenant-credentials.js.map +1 -1
  146. package/dist/routes/work-items.js.map +1 -1
  147. package/dist/rules/binding-context.js +11 -9
  148. package/dist/rules/binding-context.js.map +1 -1
  149. package/dist/rules/dispatcher.d.ts +1 -1
  150. package/dist/rules/dispatcher.d.ts.map +1 -1
  151. package/dist/rules/dispatcher.js +10 -10
  152. package/dist/rules/dispatcher.js.map +1 -1
  153. package/dist/rules/start-coordinator.d.ts +4 -0
  154. package/dist/rules/start-coordinator.d.ts.map +1 -1
  155. package/dist/rules/start-coordinator.js +36 -4
  156. package/dist/rules/start-coordinator.js.map +1 -1
  157. package/dist/rules/tools.js +2 -2
  158. package/dist/rules/tools.js.map +1 -1
  159. package/dist/rules/transition-service.js.map +1 -1
  160. package/dist/sandbox/callback-factory-sandbox.js.map +1 -1
  161. package/dist/sandbox/local-factory-sandbox.js.map +1 -1
  162. package/dist/sandbox/session-retirement.js.map +1 -1
  163. package/dist/secret-encryption.d.ts.map +1 -1
  164. package/dist/secret-encryption.js +65 -25
  165. package/dist/secret-encryption.js.map +1 -1
  166. package/dist/session/channel-reply-processor.d.ts +7 -6
  167. package/dist/session/channel-reply-processor.d.ts.map +1 -1
  168. package/dist/session/channel-reply-processor.js +9 -9
  169. package/dist/session/channel-reply-processor.js.map +1 -1
  170. package/dist/session/channel-session-link-processor.js +1 -0
  171. package/dist/session/channel-session-link-processor.js.map +1 -1
  172. package/dist/session/credential-policy.d.ts.map +1 -1
  173. package/dist/session/credential-policy.js +7 -6
  174. package/dist/session/credential-policy.js.map +1 -1
  175. package/dist/session/default-model-hydration.d.ts +1 -0
  176. package/dist/session/default-model-hydration.d.ts.map +1 -1
  177. package/dist/session/default-model-hydration.js +3 -2
  178. package/dist/session/default-model-hydration.js.map +1 -1
  179. package/dist/session/environment-state-processor.js +1 -1
  180. package/dist/session/environment-state-processor.js.map +1 -1
  181. package/dist/session/filesystem-capture.d.ts +3 -3
  182. package/dist/session/filesystem-capture.d.ts.map +1 -1
  183. package/dist/session/filesystem-capture.js +16 -17
  184. package/dist/session/filesystem-capture.js.map +1 -1
  185. package/dist/session/first-exec-capture.d.ts +1 -1
  186. package/dist/session/first-exec-capture.d.ts.map +1 -1
  187. package/dist/session/first-exec-capture.js +1 -1
  188. package/dist/session/first-exec-capture.js.map +1 -1
  189. package/dist/session/first-message-capture.d.ts +1 -1
  190. package/dist/session/first-message-capture.d.ts.map +1 -1
  191. package/dist/session/first-message-capture.js +1 -1
  192. package/dist/session/first-message-capture.js.map +1 -1
  193. package/dist/session/live-sessions.d.ts +1 -1
  194. package/dist/session/live-sessions.js +1 -1
  195. package/dist/session/live-sessions.js.map +1 -1
  196. package/dist/session/memory-settings-hydration.d.ts +1 -1
  197. package/dist/session/memory-settings-hydration.d.ts.map +1 -1
  198. package/dist/session/memory-settings-hydration.js +2 -1
  199. package/dist/session/memory-settings-hydration.js.map +1 -1
  200. package/dist/session/resource-migration.d.ts +105 -0
  201. package/dist/session/resource-migration.d.ts.map +1 -0
  202. package/dist/session/resource-migration.js +195 -0
  203. package/dist/session/resource-migration.js.map +1 -0
  204. package/dist/session/session-threads.d.ts +58 -0
  205. package/dist/session/session-threads.d.ts.map +1 -0
  206. package/dist/session/session-threads.js +90 -0
  207. package/dist/session/session-threads.js.map +1 -0
  208. package/dist/session/source-control-tools.js +8 -8
  209. package/dist/session/source-control-tools.js.map +1 -1
  210. package/dist/session/thinking-default.d.ts.map +1 -1
  211. package/dist/session/thinking-default.js +3 -4
  212. package/dist/session/thinking-default.js.map +1 -1
  213. package/dist/session/thread-session-stamp.d.ts +21 -0
  214. package/dist/session/thread-session-stamp.d.ts.map +1 -0
  215. package/dist/session/thread-session-stamp.js +20 -0
  216. package/dist/session/thread-session-stamp.js.map +1 -0
  217. package/dist/session/thread-title-mirror.d.ts +1 -1
  218. package/dist/session/thread-title-mirror.d.ts.map +1 -1
  219. package/dist/session/thread-title-mirror.js +1 -1
  220. package/dist/session/thread-title-mirror.js.map +1 -1
  221. package/dist/skills/service.d.ts +6 -8
  222. package/dist/skills/service.d.ts.map +1 -1
  223. package/dist/skills/service.js +3 -3
  224. package/dist/skills/service.js.map +1 -1
  225. package/dist/spa-static.js.map +1 -1
  226. package/dist/state-signing.js +1 -1
  227. package/dist/state-signing.js.map +1 -1
  228. package/dist/storage/domains/audit/agent-audit.d.ts.map +1 -1
  229. package/dist/storage/domains/audit/agent-audit.js +2 -2
  230. package/dist/storage/domains/audit/agent-audit.js.map +1 -1
  231. package/dist/storage/domains/audit/base.js.map +1 -1
  232. package/dist/storage/domains/audit/domain.js.map +1 -1
  233. package/dist/storage/domains/channel-identity/base.js.map +1 -1
  234. package/dist/storage/domains/comments/base.js.map +1 -1
  235. package/dist/storage/domains/comments/domain.js.map +1 -1
  236. package/dist/storage/domains/comments/feed-context.js.map +1 -1
  237. package/dist/storage/domains/credentials/base.js.map +1 -1
  238. package/dist/storage/domains/custom-providers/base.js.map +1 -1
  239. package/dist/storage/domains/intake/base.js.map +1 -1
  240. package/dist/storage/domains/integrations/base.d.ts +8 -0
  241. package/dist/storage/domains/integrations/base.d.ts.map +1 -1
  242. package/dist/storage/domains/integrations/base.js +7 -0
  243. package/dist/storage/domains/integrations/base.js.map +1 -1
  244. package/dist/storage/domains/memory-settings/base.js.map +1 -1
  245. package/dist/storage/domains/model-defaults/base.js.map +1 -1
  246. package/dist/storage/domains/projects/base.js.map +1 -1
  247. package/dist/storage/domains/queue-health/base.js.map +1 -1
  248. package/dist/storage/domains/source-control/base.d.ts +19 -0
  249. package/dist/storage/domains/source-control/base.d.ts.map +1 -1
  250. package/dist/storage/domains/source-control/base.js +42 -0
  251. package/dist/storage/domains/source-control/base.js.map +1 -1
  252. package/dist/storage/domains/source-control/inmemory.d.ts +5 -1
  253. package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
  254. package/dist/storage/domains/source-control/inmemory.js +7 -0
  255. package/dist/storage/domains/source-control/inmemory.js.map +1 -1
  256. package/dist/storage/domains/work-items/base.d.ts +14 -0
  257. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  258. package/dist/storage/domains/work-items/base.js +25 -1
  259. package/dist/storage/domains/work-items/base.js.map +1 -1
  260. package/dist/storage/domains/work-items/board-version.js.map +1 -1
  261. package/dist/storage/domains/work-items/metrics.js.map +1 -1
  262. package/dist/tools/approval-tools.js +1 -1
  263. package/dist/tools/approval-tools.js.map +1 -1
  264. package/dist/tools/deliver.d.ts +8 -5
  265. package/dist/tools/deliver.d.ts.map +1 -1
  266. package/dist/tools/deliver.js +22 -8
  267. package/dist/tools/deliver.js.map +1 -1
  268. package/dist/tools/messaging-tools.d.ts +1 -1
  269. package/dist/tools/messaging-tools.d.ts.map +1 -1
  270. package/dist/tools/messaging-tools.js +203 -72
  271. package/dist/tools/messaging-tools.js.map +1 -1
  272. package/dist/tools/permissions.d.ts +1 -1
  273. package/dist/tools/permissions.d.ts.map +1 -1
  274. package/dist/tools/permissions.js +1 -1
  275. package/dist/tools/permissions.js.map +1 -1
  276. package/dist/tools/reports.d.ts.map +1 -1
  277. package/dist/tools/reports.js +10 -3
  278. package/dist/tools/reports.js.map +1 -1
  279. package/dist/tools/run-watch.d.ts +2 -0
  280. package/dist/tools/run-watch.d.ts.map +1 -1
  281. package/dist/tools/run-watch.js +42 -2
  282. package/dist/tools/run-watch.js.map +1 -1
  283. package/dist/tools/scope.d.ts +2 -1
  284. package/dist/tools/scope.d.ts.map +1 -1
  285. package/dist/tools/scope.js +3 -2
  286. package/dist/tools/scope.js.map +1 -1
  287. package/dist/tools/session-tools.d.ts +1 -1
  288. package/dist/tools/session-tools.d.ts.map +1 -1
  289. package/dist/tools/session-tools.js +33 -16
  290. package/dist/tools/session-tools.js.map +1 -1
  291. package/dist/tools/sessions-state-processor.js +2 -2
  292. package/dist/tools/sessions-state-processor.js.map +1 -1
  293. package/dist/tools/side-sessions.d.ts +1 -1
  294. package/dist/tools/side-sessions.d.ts.map +1 -1
  295. package/dist/tools/side-sessions.js +1 -1
  296. package/dist/tools/side-sessions.js.map +1 -1
  297. package/dist/workspace.d.ts +5 -2
  298. package/dist/workspace.d.ts.map +1 -1
  299. package/dist/workspace.js +28 -15
  300. package/dist/workspace.js.map +1 -1
  301. package/package.json +13 -13
@@ -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 { SourceControlStorageHandle } from '../storage/domains/source-control/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 /** GitHub repositories, used to match a card to the repository binding its source id names. */\n githubRepositories?: Pick<SourceControlStorageHandle['repositories'], 'get'>;\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 — when none of them is\n * routed any more — to its GitHub repository binding's board, falling back to Work.\n */\nasync function relocateLabeledCards({\n workItems,\n boardRegistry,\n orgId,\n userId,\n factoryProjectId,\n integrationId,\n label,\n routes,\n intake,\n githubRepositories,\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 intake: Pick<IntakeStorage, 'listBindings'>;\n githubRepositories?: Pick<SourceControlStorageHandle['repositories'], 'get'>;\n}): Promise<{ moved: number; skipped: number }> {\n const changed = normalizeIntakeLabel(label);\n const repositoryBoards =\n integrationId === 'github'\n ? await githubRepositoryBoards({ intake, githubRepositories, boardRegistry, orgId, factoryProjectId })\n : [];\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 =\n resolveIntakeLabelRoute(routes, labels)?.board ??\n repositoryBoards.find(candidate => cardInRepository(item, candidate))?.board ??\n '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\ninterface GithubRepositoryBoard {\n board: string;\n slug: string;\n externalId?: string;\n}\n\n/**\n * The project's GitHub repository bindings that name an installed board. A binding's source id is\n * the internal repository id or the repository slug, so ids are resolved to the slug and external id\n * a card carries.\n */\nasync function githubRepositoryBoards({\n intake,\n githubRepositories,\n boardRegistry,\n orgId,\n factoryProjectId,\n}: {\n intake: Pick<IntakeStorage, 'listBindings'>;\n githubRepositories?: Pick<SourceControlStorageHandle['repositories'], 'get'>;\n boardRegistry: BoardRegistry;\n orgId: string;\n factoryProjectId: string;\n}): Promise<GithubRepositoryBoard[]> {\n const boards: GithubRepositoryBoard[] = [];\n for (const binding of await intake.listBindings({ orgId, integrationId: 'github' })) {\n if (binding.factoryProjectId !== factoryProjectId || !binding.board || !boardRegistry.has(binding.board)) continue;\n const repository = await githubRepositories?.get({ orgId, id: binding.sourceId });\n boards.push(\n repository\n ? { board: binding.board, slug: repository.slug.toLowerCase(), externalId: repository.externalId }\n : { board: binding.board, slug: binding.sourceId.toLowerCase() },\n );\n }\n return boards;\n}\n\nfunction cardInRepository(\n item: { metadata?: Record<string, unknown> | null; externalSource?: { url?: string } | null },\n repository: GithubRepositoryBoard,\n): boolean {\n const repositoryId = item.metadata?.githubRepositoryId;\n if (\n repository.externalId !== undefined &&\n repositoryId !== undefined &&\n String(repositoryId) === repository.externalId\n )\n return true;\n const match = /^https?:\\/\\/[^/]+\\/(.+)\\/(?:issues|pull)\\/\\d+(?:[/?#]|$)/.exec(item.externalSource?.url ?? '');\n return match?.[1]?.toLowerCase() === repository.slug;\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, githubRepositories } = 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 — when the\n // label is no longer routed anywhere — to the repository binding's board or Work.\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 intake,\n githubRepositories,\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":[],"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 { SourceControlStorageHandle } from '../storage/domains/source-control/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 /** GitHub repositories, used to match a card to the repository binding its source id names. */\n githubRepositories?: Pick<SourceControlStorageHandle['repositories'], 'get'>;\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 — when none of them is\n * routed any more — to its GitHub repository binding's board, falling back to Work.\n */\nasync function relocateLabeledCards({\n workItems,\n boardRegistry,\n orgId,\n userId,\n factoryProjectId,\n integrationId,\n label,\n routes,\n intake,\n githubRepositories,\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 intake: Pick<IntakeStorage, 'listBindings'>;\n githubRepositories?: Pick<SourceControlStorageHandle['repositories'], 'get'>;\n}): Promise<{ moved: number; skipped: number }> {\n const changed = normalizeIntakeLabel(label);\n const repositoryBoards =\n integrationId === 'github'\n ? await githubRepositoryBoards({ intake, githubRepositories, boardRegistry, orgId, factoryProjectId })\n : [];\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 =\n resolveIntakeLabelRoute(routes, labels)?.board ??\n repositoryBoards.find(candidate => cardInRepository(item, candidate))?.board ??\n '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\ninterface GithubRepositoryBoard {\n board: string;\n slug: string;\n externalId?: string;\n}\n\n/**\n * The project's GitHub repository bindings that name an installed board. A binding's source id is\n * the internal repository id or the repository slug, so ids are resolved to the slug and external id\n * a card carries.\n */\nasync function githubRepositoryBoards({\n intake,\n githubRepositories,\n boardRegistry,\n orgId,\n factoryProjectId,\n}: {\n intake: Pick<IntakeStorage, 'listBindings'>;\n githubRepositories?: Pick<SourceControlStorageHandle['repositories'], 'get'>;\n boardRegistry: BoardRegistry;\n orgId: string;\n factoryProjectId: string;\n}): Promise<GithubRepositoryBoard[]> {\n const boards: GithubRepositoryBoard[] = [];\n for (const binding of await intake.listBindings({ orgId, integrationId: 'github' })) {\n if (binding.factoryProjectId !== factoryProjectId || !binding.board || !boardRegistry.has(binding.board)) continue;\n const repository = await githubRepositories?.get({ orgId, id: binding.sourceId });\n boards.push(\n repository\n ? { board: binding.board, slug: repository.slug.toLowerCase(), externalId: repository.externalId }\n : { board: binding.board, slug: binding.sourceId.toLowerCase() },\n );\n }\n return boards;\n}\n\nfunction cardInRepository(\n item: { metadata?: Record<string, unknown> | null; externalSource?: { url?: string } | null },\n repository: GithubRepositoryBoard,\n): boolean {\n const repositoryId = item.metadata?.githubRepositoryId;\n if (\n repository.externalId !== undefined &&\n repositoryId !== undefined &&\n String(repositoryId) === repository.externalId\n )\n return true;\n const match = /^https?:\\/\\/[^/]+\\/(.+)\\/(?:issues|pull)\\/\\d+(?:[/?#]|$)/.exec(item.externalSource?.url ?? '');\n return match?.[1]?.toLowerCase() === repository.slug;\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, githubRepositories } = 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 — when the\n // label is no longer routed anywhere — to the repository binding's board or Work.\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 intake,\n githubRepositories,\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":";;;;;;;AA+CA,MAAM,mBAAmB;;;;;;AAMzB,MAAM,wBAAwB;;;;;AAM9B,SAAS,qBAAqB,eAAuB,MAA4B;CAC/E,MAAM,aAAa,KAAK,UAAU;CAClC,OAAO,OAAO,eAAe,YAAY,WAAW,SAAS,IACzD,CAAC,KAAK,OAAO,YAAY,GAAG,cAAc,GAAG,YAAY,IACzD,CAAC,KAAK,OAAO,UAAU;AAC7B;;;;;;;AAQA,eAAe,oBAAoB,EACjC,WACA,aACA,eACA,OACA,QACA,kBACA,UACA,aACA,wBAW8C;CAC9C,IAAI,CAAC,cAAc,IAAI,WAAW,GAAG,OAAO;EAAE,OAAO;EAAG,SAAS;CAAE;CAEnE,MAAM,6BAAa,IAAI,IAAY;CACnC,IAAI;CACJ,MAAM,WAAW,KAAK,IAAI,IAAI;CAC9B,KAAK,IAAI,OAAO,GAAG,OAAO,kBAAkB,QAAQ,GAAG;EACrD,MAAM,SAAS,MAAM,YACnB,YAAY,UAEV,YAAY,OAAO,UAAU;GAC3B;GACA;GACA,WAAW,CAAC,QAAQ;GACpB;GACA;EACF,CAAC,GACH,WAAW,KAAK,IAAI,CACtB;EACA,KAAK,MAAM,QAAQ,OAAO,OAAO;GAC/B,IAAI,KAAK,aAAa,UAAU;GAChC,KAAK,MAAM,OAAO,qBAAqB,YAAY,IAAI,IAAI,GAAG,WAAW,IAAI,GAAG;EAClF;EACA,IAAI,CAAC,OAAO,YAAY;EACxB,SAAS,OAAO;CAClB;CACA,IAAI,WAAW,SAAS,GAAG,OAAO;EAAE,OAAO;EAAG,SAAS;CAAE;CAEzD,IAAI,QAAQ;CACZ,IAAI,UAAU;CACd,MAAM,QAAQ,MAAM,UAAU,KAAK;EAAE;EAAO;CAAiB,CAAC;CAC9D,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,SAAS,KAAK;EACpB,IAAI,CAAC,UAAU,OAAO,kBAAkB,YAAY,MAAM,CAAC,WAAW,IAAI,OAAO,UAAU,GAAG;EAC9F,MAAM,UAAU,MAAM,gBAAgB;GAAE;GAAW;GAAe;GAAQ;GAAM;EAAY,CAAC;EAC7F,IAAI,YAAY,SAAS,SAAS;OAC7B,IAAI,YAAY,WAAW,WAAW;CAC7C;CACA,OAAO;EAAE;EAAO;CAAQ;AAC1B;;;;;;AAOA,eAAe,qBAAqB,EAClC,WACA,eACA,OACA,QACA,kBACA,eACA,OACA,QACA,QACA,sBAY8C;CAC9C,MAAM,UAAU,qBAAqB,KAAK;CAC1C,MAAM,mBACJ,kBAAkB,WACd,MAAM,uBAAuB;EAAE;EAAQ;EAAoB;EAAe;EAAO;CAAiB,CAAC,IACnG,CAAC;CACP,IAAI,QAAQ;CACZ,IAAI,UAAU;CACd,KAAK,MAAM,QAAQ,MAAM,UAAU,KAAK;EAAE;EAAO;CAAiB,CAAC,GAAG;EACpE,MAAM,SAAS,KAAK;EACpB,IAAI,CAAC,UAAU,OAAO,kBAAkB,iBAAiB,OAAO,SAAS,SAAS;EAClF,MAAM,SAAS,WAAW,IAAI;EAC9B,IAAI,CAAC,OAAO,MAAK,cAAa,qBAAqB,SAAS,MAAM,OAAO,GAAG;EAC5E,MAAM,cACJ,wBAAwB,QAAQ,MAAM,CAAC,EAAE,SACzC,iBAAiB,MAAK,cAAa,iBAAiB,MAAM,SAAS,CAAC,CAAC,EAAE,SACvE;EACF,MAAM,UAAU,MAAM,gBAAgB;GAAE;GAAW;GAAe;GAAQ;GAAM;EAAY,CAAC;EAC7F,IAAI,YAAY,SAAS,SAAS;OAC7B,IAAI,YAAY,WAAW,WAAW;CAC7C;CACA,OAAO;EAAE;EAAO;CAAQ;AAC1B;;;;;;AAaA,eAAe,uBAAuB,EACpC,QACA,oBACA,eACA,OACA,oBAOmC;CACnC,MAAM,SAAkC,CAAC;CACzC,KAAK,MAAM,WAAW,MAAM,OAAO,aAAa;EAAE;EAAO,eAAe;CAAS,CAAC,GAAG;EACnF,IAAI,QAAQ,qBAAqB,oBAAoB,CAAC,QAAQ,SAAS,CAAC,cAAc,IAAI,QAAQ,KAAK,GAAG;EAC1G,MAAM,aAAa,MAAM,oBAAoB,IAAI;GAAE;GAAO,IAAI,QAAQ;EAAS,CAAC;EAChF,OAAO,KACL,aACI;GAAE,OAAO,QAAQ;GAAO,MAAM,WAAW,KAAK,YAAY;GAAG,YAAY,WAAW;EAAW,IAC/F;GAAE,OAAO,QAAQ;GAAO,MAAM,QAAQ,SAAS,YAAY;EAAE,CACnE;CACF;CACA,OAAO;AACT;AAEA,SAAS,iBACP,MACA,YACS;CACT,MAAM,eAAe,KAAK,UAAU;CACpC,IACE,WAAW,eAAe,KAAA,KAC1B,iBAAiB,KAAA,KACjB,OAAO,YAAY,MAAM,WAAW,YAEpC,OAAO;CAET,OADc,2DAA2D,KAAK,KAAK,gBAAgB,OAAO,EAC/F,CAAC,GAAG,EAAE,EAAE,YAAY,MAAM,WAAW;AAClD;AAUA,MAAM,2BAA2B;;AAGjC,SAAS,YACP,eACA,MACA,YAAoB,0BACR;CACZ,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,SAAS,KAAK,IAAI,GAAG,SAAS;EACpC,MAAM,QAAQ,iBACN,uBAAO,IAAI,MAAM,GAAG,cAAc,yBAAyB,KAAK,MAAM,SAAS,GAAI,EAAE,EAAE,CAAC,GAC9F,MACF;EACA,KAAK,CAAC,CACH,KAAK,SAAS,MAAM,CAAC,CACrB,cAAc,aAAa,KAAK,CAAC;CACtC,CAAC;AACH;;;;;AAMA,eAAe,oBACb,UACsG;CACtG,MAAM,UAAU,MAAM,QAAQ,IAC5B,SAAS,IAAI,OAAO,EAAE,eAAe,WAA2C;EAC9E,IAAI;GACF,OAAO;IAAE;IAAe,OAAO,MAAM,YAAY,eAAe,IAAI;GAAE;EACxE,SAAS,OAAO;GACd,QAAQ,MAAM,gCAAgC,cAAc,mBAAmB,KAAK;GACpF,OAAO;IAAE;IAAe,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;GAAE;EAC1F;CACF,CAAC,CACH;CACA,MAAM,QAAoD,CAAC;CAC3D,MAAM,WAAuC,CAAC;CAC9C,KAAK,MAAM,SAAS,SAClB,IAAI,WAAW,OAAO,MAAM,KAAK,KAAK;MACjC,SAAS,KAAK,KAAK;CAE1B,OAAO;EAAE;EAAO;CAAS;AAC3B;AAEA,MAAM,8BAA8B;;AAWpC,SAAgB,mBAAmB,MAAqC;CACtE,IAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,MAAM,QAAQ,IAAI,GAAG,OAAO;CAC7E,MAAM,EAAE,eAAe,UAAU,kBAAkB,UAAU;CAC7D,MAAM,QAAQ,UAAmB,OAAO,UAAU,YAAY,MAAM,SAAS,KAAK,MAAM,UAAU;CAClG,MAAM,cAAc,UAClB,OAAO,UAAU,YAAY,MAAM,SAAS,KAAK,MAAM,UAAU;CACnE,IAAI,CAAC,KAAK,aAAa,KAAK,CAAC,WAAW,QAAQ,GAAG,OAAO;CAC1D,IAAI,qBAAqB,QAAQ,CAAC,KAAK,gBAAgB,GAAG,OAAO;CACjE,IAAI,UAAU,KAAA,KAAa,UAAU,QAAQ,CAAC,KAAK,KAAK,GAAG,OAAO;CAClE,OAAO;EACU;EACL;EACQ;EAClB,OAAQ,SAAuC;CACjD;AACF;AAEA,MAAM,aAAa,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG;AAC5C,MAAM,uBAAuB,EAAE,OAAO;CACpC,kBAAkB;CAClB,eAAe;CACf,OAAO,EACJ,OAAO,CAAC,CACR,IAAI,GAAG,CAAC,CACR,UAAU,oBAAoB,CAAC,CAC/B,QAAO,UAAS,MAAM,SAAS,GAAG,yBAAyB;;CAE9D,OAAO,WAAW,QAAQ,CAAC,CAAC,WAAU,UAAS,SAAS,IAAI;AAC9D,CAAC;;AAID,SAAgB,sBAAsB,MAAwC;CAC5E,MAAM,SAAS,qBAAqB,UAAU,IAAI;CAClD,OAAO,OAAO,UAAU,OAAO,OAAO;AACxC;AAEA,SAAS,MAAM,GAAqB;CAClC,OAAO;AACT;AAEA,SAAS,eAAe,OAA6C;CACnE,IAAI,UAAU,MAAM,OAAO;CAC3B,IAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,KAAK,OAAO,KAAA;CACxD,MAAM,MAAM,MAAM,QACf,SAAyB,OAAO,SAAS,YAAY,KAAK,SAAS,KAAK,KAAK,UAAU,2BAC1F;CACA,OAAO,IAAI,WAAW,MAAM,UAAU,IAAI,IAAI,GAAG,CAAC,CAAC,SAAS,IAAI,SAAS,MAAM,KAAA;AACjF;AAEA,SAAS,4BAA4B,OAAoD;CACvF,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GAAG,OAAO,KAAA;CAChF,MAAM,UAAU,OAAO,QAAQ,KAAK;CACpC,IAAI,QAAQ,SAAS,KAAK,OAAO,KAAA;CACjC,MAAM,UAAkC,OAAO,OAAO,IAAI;CAC1D,KAAK,MAAM,CAAC,WAAW,SAAS,SAAS;EACvC,IACE,CAAC,aACD,UAAU,SAAS,+BACnB,OAAO,SAAS,YAChB,CAAC,KAAK,KAAK,KACX,KAAK,SAAS,KAEd;EAEF,QAAQ,aAAa;CACvB;CACA,OAAO;AACT;;AAGA,SAAgB,kBAAkB,MAAoC;CACpE,IAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,MAAM,QAAQ,IAAI,GAAG,OAAO;CAC7E,MAAM,UAAU,OAAO,QAAQ,IAAI;CACnC,IAAI,QAAQ,SAAS,IAAI,OAAO;CAIhC,MAAM,SAAuB,OAAO,OAAO,IAAI;CAC/C,KAAK,MAAM,CAAC,eAAe,UAAU,SAAS;EAC5C,IACE,CAAC,iBACD,cAAc,SAAS,OACvB,OAAO,UAAU,YACjB,UAAU,QACV,MAAM,QAAQ,KAAK,GAEnB,OAAO;EAET,MAAM,YAAY;EAClB,IAAI,OAAO,UAAU,YAAY,WAAW,OAAO;EACnD,MAAM,YAAY,eAAe,UAAU,aAAa,IAAI;EAC5D,IAAI,cAAc,KAAA,GAAW,OAAO;EACpC,MAAM,4BACJ,kBAAkB,WAAW,4BAA4B,UAAU,yBAAyB,IAAI,KAAA;EAClG,IACE,kBAAkB,YAClB,UAAU,8BAA8B,KAAA,KACxC,8BAA8B,KAAA,GAE9B,OAAO;EACT,OAAO,iBAAiB;GACtB,SAAS,UAAU;GACnB;GACA,GAAI,4BAA4B,EAAE,0BAA0B,IAAI,CAAC;EACnE;CACF;CACA,OAAO;AACT;AAEA,SAAS,aAAa,SAAgD;CACpE,OAAO,OAAO,KAAK,OAAO,CAAC,CAAC,SAAS,IAAI,OAAO,KAAK,KAAK,UAAU,OAAO,CAAC,CAAC,CAAC,SAAS,WAAW,IAAI;AACxG;AAEA,SAAS,aAAa,OAA0D;CAC9E,IAAI,CAAC,OAAO,OAAO,CAAC;CACpB,IAAI;EACF,MAAM,SAAS,KAAK,MAAM,OAAO,KAAK,OAAO,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC;EAC1E,IAAI,OAAO,WAAW,YAAY,WAAW,QAAQ,MAAM,QAAQ,MAAM,GAAG,OAAO;EACnF,MAAM,UAAU,OAAO,QAAQ,MAAM;EACrC,IAAI,QAAQ,MAAM,CAAC,KAAK,YAAY,CAAC,OAAO,OAAO,WAAW,QAAQ,GAAG,OAAO;EAChF,OAAO,OAAO,YAAY,OAAO;CACnC,QAAQ;EACN,OAAO;CACT;AACF;AAEA,IAAa,eAAb,cAAkC,MAAwB;CACxD,MAAM,eAAe,GAAiF;EACpG,MAAM,KAAK,KAAK,KAAK,WAAW,CAAC;EACjC,MAAM,SAAS,KAAK,KAAK,KAAK,OAAO,CAAC;EACtC,IAAI,CAAC,QAAQ,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,eAAe,GAAG,GAAG,EAAE;EACvE,IAAI,CAAC,OAAO,OACV,OAAO,EACL,UAAU,EAAE,KACV;GAAE,OAAO;GAAyB,SAAS;EAAiD,GAC5F,GACF,EACF;EAEF,OAAO;GAAE,OAAO,OAAO;GAAO,QAAQ,OAAO;EAAO;CACtD;CAEA,SAAqB;EACnB,MAAM,EAAE,OAAO,QAAQ,UAAU,eAAe,CAAC,GAAG,eAAe,WAAW,uBAAuB,KAAK;EAC1G,MAAM,iBAAiB,aAAa,KAAI,gBAAe,YAAY,EAAE;EAErE,OAAO;GACL,iBAAiB,sBAAsB;IACrC,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,SAAS,MAAM,KAAK,eAAe,MAAM,CAAC,CAAC;KACjD,IAAI,cAAc,QAAQ,OAAO,OAAO;KACxC,MAAM,OAAO,YAAY;KACzB,MAAM,SAAS,MAAM,OAAO,UAAU;MAAE,OAAO,OAAO;MAAO;KAAe,CAAC;KAC7E,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC;IAC1B;GACF,CAAC;GACD,iBAAiB,sBAAsB;IACrC,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,SAAS,MAAM,KAAK,eAAe,MAAM,CAAC,CAAC;KACjD,IAAI,cAAc,QAAQ,OAAO,OAAO;KAExC,IAAI;KACJ,IAAI;MACF,OAAO,MAAM,EAAE,IAAI,KAAK;KAC1B,QAAQ;MACN,OAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,GAAG,GAAG;KACnD;KACA,MAAM,SAAS,kBAAkB,IAAI;KACrC,IAAI,CAAC,QACH,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,GAAG,GAAG;KAGhD,MAAM,mBAAiC,OAAO,OAAO,IAAI;KACzD,KAAK,MAAM,CAAC,eAAe,cAAc,OAAO,QAAQ,MAAM,GAAG;MAC/D,IAAI,eAAe,SAAS,aAAa,GAAG;OAC1C,iBAAiB,iBAAiB;OAClC;MACF;MACA,IAAI,UAAU,WAAW,UAAU,WAAW,QAC5C,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,GAAG,GAAG;KAElD;KAEA,MAAM,OAAO,YAAY;KACzB,MAAM,OAAO,WAAW;MAAE,OAAO,OAAO;MAAO,QAAQ;KAAiB,CAAC;KACzE,MAAM,MAAM,KAAK;MACf,SAAS,MAAM,CAAC;MAChB,OAAO;OACL,QAAQ;OACR,SAAS,CAAC;QAAE,MAAM;QAAiB,IAAI,OAAO;OAAM,CAAC;OACrD,UAAU,OAAO,YACf,OAAO,QAAQ,gBAAgB,CAAC,CAAC,KAAK,CAAC,eAAe,eAAe,CACnE,eACA;QAAE,SAAS,UAAU;QAAS,SAAS,UAAU,WAAW,UAAU;OAAK,CAC7E,CAAC,CACH;MACF;KACF,CAAC;KACD,OAAO,EAAE,KAAK,EAAE,QAAQ,iBAAiB,CAAC;IAC5C;GACF,CAAC;GACD,iBAAiB,wBAAwB;IACvC,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,SAAS,MAAM,KAAK,eAAe,MAAM,CAAC,CAAC;KACjD,IAAI,cAAc,QAAQ,OAAO,OAAO;KACxC,MAAM,OAAO,YAAY;KACzB,OAAO,EAAE,KAAK,EAAE,UAAU,MAAM,OAAO,aAAa,EAAE,OAAO,OAAO,MAAM,CAAC,EAAE,CAAC;IAChF;GACF,CAAC;GACD,iBAAiB,wBAAwB;IACvC,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,SAAS,MAAM,KAAK,eAAe,MAAM,CAAC,CAAC;KACjD,IAAI,cAAc,QAAQ,OAAO,OAAO;KAExC,IAAI;KACJ,IAAI;MACF,OAAO,MAAM,EAAE,IAAI,KAAK;KAC1B,QAAQ;MACN,OAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,GAAG,GAAG;KACnD;KACA,MAAM,UAAU,mBAAmB,IAAI;KACvC,IAAI,CAAC,WAAW,CAAC,eAAe,SAAS,QAAQ,aAAa,GAC5D,OAAO,EAAE,KAAK,EAAE,OAAO,kBAAkB,GAAG,GAAG;KAEjD,IAAI,QAAQ,oBAAoB,UAE1B;UAAA,CAAC,MADiB,SAAS,IAAI;OAAE,OAAO,OAAO;OAAO,IAAI,QAAQ;MAAiB,CAAC,GAC1E,OAAO,EAAE,KAAK,EAAE,OAAO,4BAA4B,GAAG,GAAG;KAAA;KAEzE,IAAI,QAAQ,UAAU,QAAQ,CAAC,eAAe,IAAI,QAAQ,KAAK,GAC7D,OAAO,EAAE,KAAK;MAAE,OAAO;MAAiB,SAAS,UAAU,QAAQ,MAAM;KAAqB,GAAG,GAAG;KAGtG,MAAM,OAAO,YAAY;KACzB,IAAI,wBAAwB,QAAQ;KACpC,IAAI,YAAuD;KAC3D,IAAI,QAAQ,qBAAqB,MAM/B,yBAAwB,MALM,OAAO,aAAa;MAChD,OAAO,OAAO;MACd,eAAe,QAAQ;MACvB,UAAU,QAAQ;KACpB,CAAC,EAAA,EACwC,oBAAoB;UACxD;MACL,MAAM,kBAAkB,MAAM,OAAO,WAAW;OAC9C,OAAO,OAAO;OACd,eAAe,QAAQ;OACvB,UAAU,QAAQ;MACpB,CAAC;MACD,MAAM,OAAO,WAAW;OACtB,OAAO,OAAO;OACd,QAAQ,OAAO;OACf,eAAe,QAAQ;OACvB,UAAU,QAAQ;OAClB,kBAAkB,QAAQ;OAC1B,OAAO,QAAQ;MACjB,CAAC;MAKD,MAAM,YAAY,QAAQ;MAC1B,MAAM,cAAc,aAAa,MAAK,cAAa,UAAU,OAAO,QAAQ,aAAa;MACzF,IACE,aACA,iBACA,eACA,iBAAiB,qBAAqB,QAAQ,oBAC9C,cAAc,QACd,gBAAgB,UAAU,WAE1B,IAAI;OAKF,MAAM,uBAAsB,MAJP,OAAO,UAAU;QACpC,OAAO,OAAO;QACd,gBAAgB,CAAC,QAAQ,aAAa;OACxC,CAAC,EAAA,CACkC,QAAQ,cAAc,EAAE,aAAa,CAAC;OACzE,MAAM,uBAAuB,oBAAoB,SAAS,QAAQ,QAAQ,IACtE,sBACA,CAAC,GAAG,qBAAqB,QAAQ,QAAQ;OAC7C,YAAY,MAAM,oBAAoB;QACpC;QACA;QACA;QACA,OAAO,OAAO;QACd,QAAQ,OAAO;QACf,kBAAkB,QAAQ;QAC1B,UAAU,QAAQ;QAClB;QACA,aAAa;OACf,CAAC;MACH,SAAS,OAAO;OAEd,QAAQ,MAAM,8CAA8C,QAAQ,cAAc,UAAU,KAAK;MACnG;KAEJ;KACA,MAAM,MAAM,KAAK;MACf,SAAS,MAAM,CAAC;MAChB,OAAO;OACL,QAAQ;OACR,GAAI,wBAAwB,EAAE,kBAAkB,sBAAsB,IAAI,CAAC;OAC3E,SAAS,CAAC;QAAE,MAAM;QAAiB,IAAI,GAAG,QAAQ,cAAc,GAAG,QAAQ;OAAW,CAAC;OACvF,UAAU;QACR,kBAAkB,QAAQ;QAC1B,OAAO,QAAQ;QACf,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;OACnC;MACF;KACF,CAAC;KACD,OAAO,EAAE,KAAK;MACZ,UAAU,MAAM,OAAO,aAAa,EAAE,OAAO,OAAO,MAAM,CAAC;MAC3D,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;KACnC,CAAC;IACH;GACF,CAAC;GACD,iBAAiB,4BAA4B;IAC3C,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,SAAS,MAAM,KAAK,eAAe,MAAM,CAAC,CAAC;KACjD,IAAI,cAAc,QAAQ,OAAO,OAAO;KACxC,MAAM,mBAAmB,EAAE,IAAI,MAAM,kBAAkB;KACvD,MAAM,OAAO,YAAY;KACzB,OAAO,EAAE,KAAK,EACZ,QAAQ,MAAM,OAAO,gBAAgB;MACnC,OAAO,OAAO;MACd,GAAI,mBAAmB,EAAE,iBAAiB,IAAI,CAAC;KACjD,CAAC,EACH,CAAC;IACH;GACF,CAAC;GACD,iBAAiB,4BAA4B;IAC3C,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,SAAS,MAAM,KAAK,eAAe,MAAM,CAAC,CAAC;KACjD,IAAI,cAAc,QAAQ,OAAO,OAAO;KAExC,IAAI;KACJ,IAAI;MACF,OAAO,MAAM,EAAE,IAAI,KAAK;KAC1B,QAAQ;MACN,OAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,GAAG,GAAG;KACnD;KACA,MAAM,QAAQ,sBAAsB,IAAI;KACxC,IAAI,CAAC,SAAS,CAAC,eAAe,SAAS,MAAM,aAAa,GACxD,OAAO,EAAE,KAAK,EAAE,OAAO,sBAAsB,GAAG,GAAG;KAErD,IAAI,UAEE;UAAA,CAAC,MADiB,SAAS,IAAI;OAAE,OAAO,OAAO;OAAO,IAAI,MAAM;MAAiB,CAAC,GACxE,OAAO,EAAE,KAAK,EAAE,OAAO,4BAA4B,GAAG,GAAG;KAAA;KAEzE,IAAI,MAAM,UAAU,QAAQ,CAAC,eAAe,IAAI,MAAM,KAAK,GACzD,OAAO,EAAE,KAAK;MAAE,OAAO;MAAiB,SAAS,UAAU,MAAM,MAAM;KAAqB,GAAG,GAAG;KAGpG,MAAM,OAAO,YAAY;KACzB,MAAM,QAAQ;MACZ,OAAO,OAAO;MACd,kBAAkB,MAAM;MACxB,eAAe,MAAM;KACvB;KACA,MAAM,YAAY,MAAM,OAAO,gBAAgB,KAAK,EAAA,CAAG,MAAK,aAAY,SAAS,UAAU,MAAM,KAAK;KACtG,IAAI,MAAM,UAAU,MAClB,MAAM,OAAO,gBAAgB;MAAE,GAAG;MAAO,OAAO,MAAM;KAAM,CAAC;UAE7D,MAAM,OAAO,cAAc;MAAE,GAAG;MAAO,OAAO,MAAM;MAAO,OAAO,MAAM;MAAO,QAAQ,OAAO;KAAO,CAAC;KAKxG,IAAI,YAAuD;KAC3D,IAAI,aAAa,kBAAkB,UAAU,SAAS,UAAU,MAAM,OACpE,IAAI;MACF,YAAY,MAAM,qBAAqB;OACrC;OACA;OACA,OAAO,OAAO;OACd,QAAQ,OAAO;OACf,kBAAkB,MAAM;OACxB,eAAe,MAAM;OACrB,OAAO,MAAM;OACb,QAAQ,MAAM,OAAO,gBAAgB,KAAK;OAC1C;OACA;MACF,CAAC;KACH,SAAS,OAAO;MAEd,QAAQ,MAAM,mDAAmD,MAAM,cAAc,UAAU,KAAK;KACtG;KAEF,MAAM,MAAM,KAAK;MACf,SAAS,MAAM,CAAC;MAChB,OAAO;OACL,QAAQ;OACR,kBAAkB,MAAM;OACxB,SAAS,CAAC;QAAE,MAAM;QAAsB,IAAI,GAAG,MAAM,cAAc,GAAG,MAAM;OAAQ,CAAC;OACrF,UAAU;QAAE,OAAO,MAAM;QAAO,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;OAAG;MACtE;KACF,CAAC;KACD,OAAO,EAAE,KAAK;MACZ,QAAQ,MAAM,OAAO,gBAAgB;OAAE,OAAO,OAAO;OAAO,kBAAkB,MAAM;MAAiB,CAAC;MACtG,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;KACnC,CAAC;IACH;GACF,CAAC;GACD,iBAAiB,uBAAuB;IACtC,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,SAAS,MAAM,KAAK,eAAe,MAAM,CAAC,CAAC;KACjD,IAAI,cAAc,QAAQ,OAAO,OAAO;KACxC,MAAM,EAAE,OAAO,aAAa,MAAM,oBAChC,aAAa,KAAI,iBAAgB;MAC/B,eAAe,YAAY;MAC3B,YAAY,YAAY,OAAO,YAAY,MAAM;KACnD,EAAE,CACJ;KACA,OAAO,EAAE,KAAK;MACZ,SAAS,MAAM,SAAS,EAAE,eAAe,YAAY,MAAM,KAAI,YAAW;OAAE;OAAe,GAAG;MAAO,EAAE,CAAC;MACxG;KACF,CAAC;IACH;GACF,CAAC;GACD,iBAAiB,qBAAqB;IACpC,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,SAAS,MAAM,KAAK,eAAe,MAAM,CAAC,CAAC;KACjD,IAAI,cAAc,QAAQ,OAAO,OAAO;KACxC,MAAM,UAAU,aAAa,EAAE,IAAI,MAAM,QAAQ,CAAC;KAClD,IAAI,CAAC,SAAS,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,GAAG,GAAG;KAE5D,MAAM,OAAO,YAAY;KACzB,MAAM,SAAS,MAAM,OAAO,UAAU;MAAE,OAAO,OAAO;MAAO;KAAe,CAAC;KAC7E,MAAM,EAAE,OAAO,aAAa,MAAM,oBAChC,aAAa,SAAQ,gBAAe;MAClC,MAAM,YAAY,OAAO,YAAY;MACrC,IAAI,CAAC,WAAW,WAAW,CAAC,UAAU,WAAW,QAAQ,OAAO,CAAC;MACjE,MAAM,YAAY,UAAU;MAC5B,MAAM,SAAS,QAAQ,YAAY;MACnC,OAAO,CACL;OACE,eAAe,YAAY;OAC3B,YAAY,YAAY,OAAO,UAAU;QAAE,GAAG;QAAQ;QAAW,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;OAAG,CAAC;MAClG,CACF;KACF,CAAC,CACH;KAEA,MAAM,QAAgC,CAAC;KACvC,MAAM,cAAsC,CAAC;KAC7C,KAAK,MAAM,EAAE,eAAe,WAAW,OAAO;MAC5C,MAAM,KACJ,GAAG,MAAM,MAAM,KAAI,SAAQ;OACzB,MAAM,EAAE,QAAQ,GAAG,cAAc;OACjC,OAAO;QAAE,GAAG;QAAW;QAAe,gBAAgB;SAAE;SAAe,GAAG;QAAO;OAAE;MACrF,CAAC,CACH;MACA,IAAI,MAAM,YAAY,YAAY,iBAAiB,MAAM;KAC3D;KAEA,KAAK,MAAM,EAAE,mBAAmB,UAAU;MACxC,MAAM,SAAS,QAAQ;MACvB,IAAI,QAAQ,YAAY,iBAAiB;KAC3C;KACA,OAAO,EAAE,KAAK;MAAE;MAAO,YAAY,aAAa,WAAW;MAAG;KAAS,CAAC;IAC1E;GACF,CAAC;EACH;CACF;AACF"}
@@ -7,7 +7,7 @@ const PINNED_NODE_NAME = "pinned";
7
7
  /** Hover-card budget for record text shipped in the graph payload. */
8
8
  const RECORD_TEXT_LIMIT = 240;
9
9
  function truncateRecordText(text) {
10
- return text.length > RECORD_TEXT_LIMIT ? `${text.slice(0, RECORD_TEXT_LIMIT - 1)}…` : text;
10
+ return text.length > RECORD_TEXT_LIMIT ? `${text.slice(0, 239)}…` : text;
11
11
  }
12
12
  const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
13
13
  /** Authorized visible events returned per activity page. */