@mastra/factory 0.21.1-alpha.3 → 0.22.0-alpha.4

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 (174) hide show
  1. package/dist/capabilities/version-control.d.ts +13 -8
  2. package/dist/capabilities/version-control.d.ts.map +1 -1
  3. package/dist/environment/build-runner.d.ts +72 -0
  4. package/dist/environment/build-runner.d.ts.map +1 -0
  5. package/dist/environment/build-runner.js +131 -0
  6. package/dist/environment/build-runner.js.map +1 -0
  7. package/dist/environment/build-schedule.d.ts +40 -0
  8. package/dist/environment/build-schedule.d.ts.map +1 -0
  9. package/dist/environment/build-schedule.js +94 -0
  10. package/dist/environment/build-schedule.js.map +1 -0
  11. package/dist/environment/build-workflow.d.ts +62 -0
  12. package/dist/environment/build-workflow.d.ts.map +1 -0
  13. package/dist/environment/build-workflow.js +149 -0
  14. package/dist/environment/build-workflow.js.map +1 -0
  15. package/dist/environment/build.d.ts +111 -0
  16. package/dist/environment/build.d.ts.map +1 -0
  17. package/dist/environment/build.js +344 -0
  18. package/dist/environment/build.js.map +1 -0
  19. package/dist/environment/heads.d.ts +36 -0
  20. package/dist/environment/heads.d.ts.map +1 -0
  21. package/dist/environment/heads.js +60 -0
  22. package/dist/environment/heads.js.map +1 -0
  23. package/dist/factory.d.ts +18 -4
  24. package/dist/factory.d.ts.map +1 -1
  25. package/dist/factory.js +89 -15
  26. package/dist/factory.js.map +1 -1
  27. package/dist/index.d.ts +2 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +3 -2
  30. package/dist/integrations/base.d.ts +17 -2
  31. package/dist/integrations/base.d.ts.map +1 -1
  32. package/dist/integrations/github/commits.d.ts +11 -0
  33. package/dist/integrations/github/commits.d.ts.map +1 -1
  34. package/dist/integrations/github/commits.js +20 -1
  35. package/dist/integrations/github/commits.js.map +1 -1
  36. package/dist/integrations/github/config.d.ts +3 -3
  37. package/dist/integrations/github/config.d.ts.map +1 -1
  38. package/dist/integrations/github/config.js +1 -1
  39. package/dist/integrations/github/config.js.map +1 -1
  40. package/dist/integrations/github/routes.d.ts +2 -2
  41. package/dist/integrations/github/routes.d.ts.map +1 -1
  42. package/dist/integrations/github/routes.js +6 -5
  43. package/dist/integrations/github/routes.js.map +1 -1
  44. package/dist/integrations/github/rules.d.ts +3 -1
  45. package/dist/integrations/github/rules.d.ts.map +1 -1
  46. package/dist/integrations/github/rules.js +31 -1
  47. package/dist/integrations/github/rules.js.map +1 -1
  48. package/dist/integrations/github/sandbox.d.ts +35 -0
  49. package/dist/integrations/github/sandbox.d.ts.map +1 -1
  50. package/dist/integrations/github/sandbox.js +203 -2
  51. package/dist/integrations/github/sandbox.js.map +1 -1
  52. package/dist/integrations/github/session-subscriptions.d.ts.map +1 -1
  53. package/dist/integrations/github/session-subscriptions.js +117 -62
  54. package/dist/integrations/github/session-subscriptions.js.map +1 -1
  55. package/dist/integrations/github/token-refresh.d.ts +7 -0
  56. package/dist/integrations/github/token-refresh.d.ts.map +1 -1
  57. package/dist/integrations/github/token-refresh.js.map +1 -1
  58. package/dist/integrations/github/webhook.js.map +1 -1
  59. package/dist/integrations/gitlab/agent-tools.js +1 -1
  60. package/dist/integrations/gitlab/routes.d.ts +2 -2
  61. package/dist/integrations/gitlab/routes.d.ts.map +1 -1
  62. package/dist/integrations/gitlab/routes.js.map +1 -1
  63. package/dist/integrations/gitlab/session-subscriptions.d.ts.map +1 -1
  64. package/dist/integrations/gitlab/session-subscriptions.js +8 -7
  65. package/dist/integrations/gitlab/session-subscriptions.js.map +1 -1
  66. package/dist/integrations/incidentio/agent-tools.js +1 -1
  67. package/dist/integrations/jira/agent-tools.js +1 -1
  68. package/dist/integrations/linear/agent-tools.js +1 -1
  69. package/dist/integrations/platform/github/integration.d.ts.map +1 -1
  70. package/dist/integrations/platform/github/integration.js +46 -2
  71. package/dist/integrations/platform/github/integration.js.map +1 -1
  72. package/dist/integrations/platform/jira/agent-tools.js +1 -1
  73. package/dist/integrations/slack/slack.d.ts.map +1 -1
  74. package/dist/integrations/slack/slack.js +15 -16
  75. package/dist/integrations/slack/slack.js.map +1 -1
  76. package/dist/integrations/subscription-session.js +1 -1
  77. package/dist/packages/_internals/workspace/dist/index.js +21 -1
  78. package/dist/packages/_internals/workspace/dist/index.js.map +1 -1
  79. package/dist/routes/contracts.d.ts +386 -2
  80. package/dist/routes/contracts.d.ts.map +1 -1
  81. package/dist/routes/contracts.js +166 -1
  82. package/dist/routes/contracts.js.map +1 -1
  83. package/dist/routes/fs.d.ts +25 -0
  84. package/dist/routes/fs.d.ts.map +1 -1
  85. package/dist/routes/fs.js +142 -46
  86. package/dist/routes/fs.js.map +1 -1
  87. package/dist/routes/projects.d.ts +6 -0
  88. package/dist/routes/projects.d.ts.map +1 -1
  89. package/dist/routes/projects.js +344 -1
  90. package/dist/routes/projects.js.map +1 -1
  91. package/dist/routes/source-control-sessions.d.ts +2 -0
  92. package/dist/routes/source-control-sessions.d.ts.map +1 -1
  93. package/dist/routes/source-control-sessions.js +36 -1
  94. package/dist/routes/source-control-sessions.js.map +1 -1
  95. package/dist/routes/supervisor.js +1 -1
  96. package/dist/routes/surface.d.ts +6 -3
  97. package/dist/routes/surface.d.ts.map +1 -1
  98. package/dist/routes/surface.js +21 -34
  99. package/dist/routes/surface.js.map +1 -1
  100. package/dist/rules/binding-context.d.ts +1 -1
  101. package/dist/rules/binding-context.d.ts.map +1 -1
  102. package/dist/rules/binding-context.js +1 -1
  103. package/dist/rules/binding-context.js.map +1 -1
  104. package/dist/rules/review-source-tool.js +1 -1
  105. package/dist/rules/start-coordinator.d.ts.map +1 -1
  106. package/dist/rules/start-coordinator.js +7 -2
  107. package/dist/rules/start-coordinator.js.map +1 -1
  108. package/dist/rules/tools.js +1 -1
  109. package/dist/sandbox/callback-factory-sandbox.d.ts +15 -0
  110. package/dist/sandbox/callback-factory-sandbox.d.ts.map +1 -0
  111. package/dist/sandbox/callback-factory-sandbox.js +22 -0
  112. package/dist/sandbox/callback-factory-sandbox.js.map +1 -0
  113. package/dist/sandbox/local-factory-sandbox.d.ts +20 -0
  114. package/dist/sandbox/local-factory-sandbox.d.ts.map +1 -0
  115. package/dist/sandbox/local-factory-sandbox.js +27 -0
  116. package/dist/sandbox/local-factory-sandbox.js.map +1 -0
  117. package/dist/sandbox/session-retirement.d.ts.map +1 -1
  118. package/dist/sandbox/session-retirement.js +23 -3
  119. package/dist/sandbox/session-retirement.js.map +1 -1
  120. package/dist/sandbox/session-sandbox.d.ts +82 -40
  121. package/dist/sandbox/session-sandbox.d.ts.map +1 -1
  122. package/dist/sandbox/session-sandbox.js +130 -13
  123. package/dist/sandbox/session-sandbox.js.map +1 -1
  124. package/dist/sandbox/workdir.d.ts +10 -0
  125. package/dist/sandbox/workdir.d.ts.map +1 -1
  126. package/dist/sandbox/workdir.js +10 -1
  127. package/dist/sandbox/workdir.js.map +1 -1
  128. package/dist/session/environment-repositories.d.ts +31 -0
  129. package/dist/session/environment-repositories.d.ts.map +1 -0
  130. package/dist/session/environment-repositories.js +89 -0
  131. package/dist/session/environment-repositories.js.map +1 -0
  132. package/dist/session/environment-state-processor.d.ts +59 -0
  133. package/dist/session/environment-state-processor.d.ts.map +1 -0
  134. package/dist/session/environment-state-processor.js +105 -0
  135. package/dist/session/environment-state-processor.js.map +1 -0
  136. package/dist/session/factory-session.d.ts +26 -35
  137. package/dist/session/factory-session.d.ts.map +1 -1
  138. package/dist/session/factory-session.js +34 -71
  139. package/dist/session/factory-session.js.map +1 -1
  140. package/dist/session/filesystem-capture.d.ts +13 -0
  141. package/dist/session/filesystem-capture.d.ts.map +1 -1
  142. package/dist/session/filesystem-capture.js +73 -14
  143. package/dist/session/filesystem-capture.js.map +1 -1
  144. package/dist/session/source-control-tools.d.ts +1 -1
  145. package/dist/session/source-control-tools.d.ts.map +1 -1
  146. package/dist/session/source-control-tools.js +144 -71
  147. package/dist/session/source-control-tools.js.map +1 -1
  148. package/dist/spa-static.js +2 -2
  149. package/dist/storage/domains/audit/agent-audit.d.ts +6 -1
  150. package/dist/storage/domains/audit/agent-audit.d.ts.map +1 -1
  151. package/dist/storage/domains/audit/agent-audit.js +31 -13
  152. package/dist/storage/domains/audit/agent-audit.js.map +1 -1
  153. package/dist/storage/domains/projects/base.d.ts +115 -2
  154. package/dist/storage/domains/projects/base.d.ts.map +1 -1
  155. package/dist/storage/domains/projects/base.js +219 -12
  156. package/dist/storage/domains/projects/base.js.map +1 -1
  157. package/dist/storage/domains/source-control/base.d.ts +123 -7
  158. package/dist/storage/domains/source-control/base.d.ts.map +1 -1
  159. package/dist/storage/domains/source-control/base.js +406 -33
  160. package/dist/storage/domains/source-control/base.js.map +1 -1
  161. package/dist/storage/domains/source-control/inmemory.d.ts +19 -6
  162. package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
  163. package/dist/storage/domains/source-control/inmemory.js +90 -2
  164. package/dist/storage/domains/source-control/inmemory.js.map +1 -1
  165. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  166. package/dist/storage/domains/work-items/base.js +12 -5
  167. package/dist/storage/domains/work-items/base.js.map +1 -1
  168. package/dist/supervisor/read-tools.js +1 -1
  169. package/dist/supervisor/write-tools.js +1 -1
  170. package/dist/workspace.d.ts +50 -7
  171. package/dist/workspace.d.ts.map +1 -1
  172. package/dist/workspace.js +344 -24
  173. package/dist/workspace.js.map +1 -1
  174. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/integrations/gitlab/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AAEnF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAS1E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAG9D,OAAO,KAAK,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAQrF,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,OAAO,CAAC,EAAE,0BAA0B,CAAC;IACrC,SAAS,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACtE,iFAAiF;IACjF,UAAU,CAAC,EAAE,2BAA2B,CAAC,YAAY,CAAC,CAAC;CACxD;AAkGD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,QAAQ,EAAE,CAyZ/E"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/integrations/gitlab/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAS1E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAG9D,OAAO,KAAK,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAQrF,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,SAAS,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACtE,iFAAiF;IACjF,UAAU,CAAC,EAAE,2BAA2B,CAAC,YAAY,CAAC,CAAC;CACxD;AAkGD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,QAAQ,EAAE,CAyZ/E"}
@@ -1 +1 @@
1
- {"version":3,"file":"routes.js","names":[],"sources":["../../../src/integrations/gitlab/routes.ts"],"sourcesContent":["import type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { Context } from 'hono';\nimport type { RouteAuth } from '../../routes/route.js';\nimport type { MastraFactorySandboxConfig } from '../../sandbox/session-sandbox.js';\nimport { sanitizeSegment } from '../../sandbox/workdir.js';\nimport type { AuditEmitter } from '../../storage/domains/audit/domain.js';\nimport type { IntakeStorage } from '../../storage/domains/intake/base.js';\nimport { GitLabApiError } from './api.js';\nimport {\n decodeIssueReference,\n decodeSourceId,\n encodeIssueReference,\n encodeSourceId,\n gitlabConnection,\n} from './integration.js';\nimport type { GitLabIntegrationBase } from './integration.js';\nimport { listMergeRequestSubscriptionsForThread, mergeRequestUrl } from './subscriptions.js';\nimport { handleGitLabWebhook } from './webhook.js';\nimport type { GitLabWebhookHandlerOptions, ParsedGitLabWebhook } from './webhook.js';\n\ntype RouteContext = Context;\n\nfunction loose(c: unknown): RouteContext {\n return c as RouteContext;\n}\n\nexport interface BuildGitLabRoutesOptions {\n gitlab?: GitLabIntegrationBase;\n auth?: RouteAuth;\n intake?: IntakeStorage;\n sandbox?: MastraFactorySandboxConfig;\n emitAudit?: AuditEmitter['emit'];\n webhookSecret?: string;\n ingestFactoryEvent?: (event: ParsedGitLabWebhook) => Promise<unknown>;\n /** Mounted agent controller; enables webhook delivery to subscribed sessions. */\n controller?: GitLabWebhookHandlerOptions['controller'];\n}\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', reason: 'auth_required' }, 401) };\n if (!tenant.orgId) {\n return {\n response: c.json(\n {\n error: 'organization_required',\n message: 'GitLab intake requires an organization. Personal accounts cannot use GitLab intake.',\n },\n 403,\n ),\n };\n }\n return { tenant: { orgId: tenant.orgId, userId: tenant.userId } };\n}\n\nfunction gitlabFetchError(c: RouteContext, error: unknown) {\n if (error instanceof GitLabApiError && error.code === 'gitlab_auth_failed') {\n return c.json({ error: 'gitlab_auth_failed', message: error.message }, 409);\n }\n return c.json({ error: 'gitlab_fetch_failed', message: error instanceof Error ? error.message : String(error) }, 502);\n}\n\ntype GitLabSourceIdentityMigration = { from: string; to: string };\n\nfunction gitlabProjectPayload(source: { id: string; name: string; metadata?: Record<string, unknown> }) {\n const connectionId = typeof source.metadata?.connectionId === 'string' ? source.metadata.connectionId : null;\n const projectId = typeof source.metadata?.projectId === 'string' ? source.metadata.projectId : null;\n const projectPath = typeof source.metadata?.projectPath === 'string' ? source.metadata.projectPath : source.name;\n if (!connectionId || !projectId) return null;\n const repositoryName = projectPath.split('/').filter(Boolean).at(-1) ?? 'repo';\n return {\n id: source.id,\n name: source.name,\n projectId,\n projectPath,\n connectionId,\n accountLabel: typeof source.metadata?.accountLabel === 'string' ? source.metadata.accountLabel : null,\n defaultBranch: typeof source.metadata?.defaultBranch === 'string' ? source.metadata.defaultBranch : 'main',\n sandboxProvider: 'none',\n sandboxWorkdir: `~/${sanitizeSegment(repositoryName)}`,\n };\n}\n\nfunction positiveId(value: string | undefined): number | null {\n const number = Number(value);\n return value && /^[1-9]\\d*$/.test(value) && Number.isSafeInteger(number) ? number : null;\n}\n\nfunction mergeRequestSourceKey(host: string, projectId: number, mergeRequestIid: number): string {\n return `gitlab-pr:${Buffer.from(JSON.stringify({ version: 1, host, projectId, mergeRequestIid }), 'utf8').toString('base64url')}`;\n}\n\nasync function reconcileGitLabSourceIdentity({\n intake,\n orgId,\n sources,\n}: {\n intake: IntakeStorage;\n orgId: string;\n sources: Array<{ id: string; metadata?: Record<string, unknown> }>;\n}): Promise<{ migrations: GitLabSourceIdentityMigration[]; conflicts: GitLabSourceIdentityMigration[] }> {\n await intake.ensureReady();\n const [config, bindings] = await Promise.all([\n intake.getConfig({ orgId }),\n intake.listBindings({ orgId, integrationId: 'gitlab' }),\n ]);\n const selected = config.gitlab?.sourceIds ?? [];\n const canonicalByProject = new Map<string, string[]>();\n for (const source of sources) {\n const reference = decodeSourceId(source.id);\n if (!reference?.host) continue;\n const ids = canonicalByProject.get(reference.projectId) ?? [];\n ids.push(source.id);\n canonicalByProject.set(reference.projectId, ids);\n }\n\n const migrations = new Map<string, string>();\n for (const sourceId of new Set([...selected, ...bindings.map(binding => binding.sourceId)])) {\n const reference = decodeSourceId(sourceId);\n if (!reference || reference.host) continue;\n const candidates = canonicalByProject.get(reference.projectId) ?? [];\n if (candidates.length === 1) migrations.set(sourceId, candidates[0]!);\n }\n return intake.migrateSourceIds({\n orgId,\n integrationId: 'gitlab',\n migrations: [...migrations].map(([from, to]) => ({ from, to })),\n });\n}\n\nexport function buildGitLabRoutes(options: BuildGitLabRoutesOptions): ApiRoute[] {\n const routes: ApiRoute[] = [];\n const { gitlab, auth, intake, emitAudit } = options;\n const enabled = Boolean(gitlab && auth?.enabled());\n\n if (gitlab && auth) {\n routes.push(\n registerApiRoute('/web/gitlab/status', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const diagnostics = gitlab.diagnostics();\n if (!enabled) {\n return c.json({ enabled: false, configured: true, reauthRequired: false, reason: 'missing_config' });\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 if (!tenant.orgId) {\n return c.json({\n enabled: true,\n configured: false,\n organizationRequired: true,\n connections: [],\n accounts: [],\n reauthRequired: false,\n reason: 'organization_required',\n });\n }\n\n try {\n await gitlab.verifyStatus();\n const connections = await gitlab.statusConnections();\n const active = connections?.filter(connection => connection.status === 'active');\n const direct = connections === undefined;\n const endpointHost = typeof diagnostics.endpointHost === 'string' ? diagnostics.endpointHost : null;\n const accounts = direct\n ? endpointHost\n ? [endpointHost]\n : []\n : (active ?? []).flatMap(connection => (connection.accountLabel ? [connection.accountLabel] : []));\n const configured = direct || (active?.length ?? 0) > 0;\n return c.json({\n enabled: true,\n configured,\n mode: direct ? 'direct' : 'platform',\n ...(connections ? { connections } : {}),\n accounts,\n reauthRequired: connections?.some(connection => connection.status === 'needs_reauth') ?? false,\n reason: configured ? 'ready' : 'not_connected',\n });\n } catch (error) {\n return gitlabFetchError(loose(c), error);\n }\n },\n }),\n registerApiRoute('/web/gitlab/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 try {\n const sources = await gitlab.intake.listSources(resolved.tenant);\n if (intake) {\n const identity = await reconcileGitLabSourceIdentity({\n intake,\n orgId: resolved.tenant.orgId,\n sources,\n });\n if (identity.conflicts.length > 0) {\n return c.json(\n {\n error: 'gitlab_source_identity_conflict',\n message: 'Conflicting routes exist for the same GitLab project. Resolve the duplicate bindings.',\n conflicts: identity.conflicts,\n },\n 409,\n );\n }\n if (identity.migrations.length > 0) {\n await emitAudit?.({\n context: loose(c),\n input: {\n action: 'factory.intake.config_updated',\n targets: identity.migrations.map(migration => ({ type: 'intake_source', id: migration.to })),\n metadata: { provider: 'gitlab', migrated: identity.migrations.length },\n },\n });\n }\n }\n return c.json({\n projects: sources.flatMap(source => {\n const project = gitlabProjectPayload(source);\n return project ? [{ ...project, sandboxProvider: options.sandbox ? 'custom' : 'none' }] : [];\n }),\n });\n } catch (error) {\n return gitlabFetchError(loose(c), error);\n }\n },\n }),\n registerApiRoute('/web/gitlab/projects/registration', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n const input = (await c.req.json().catch(() => null)) as { sourceId?: unknown } | null;\n const sourceId = typeof input?.sourceId === 'string' ? input.sourceId.trim() : '';\n if (!sourceId) return c.json({ error: 'invalid_gitlab_source' }, 400);\n try {\n const source = (await gitlab.intake.listSources(resolved.tenant)).find(\n candidate => candidate.id === sourceId,\n );\n const project = source ? gitlabProjectPayload(source) : null;\n if (!project) return c.json({ error: 'gitlab_project_not_found' }, 404);\n const installation = await gitlab.versionControl.registerInstallation({\n orgId: resolved.tenant.orgId,\n userId: resolved.tenant.userId,\n installation: {\n externalId: project.connectionId,\n accountName: project.accountLabel ?? 'GitLab',\n accountType: 'GitLab',\n metadata: { connection: gitlabConnection(project.connectionId) },\n },\n });\n return c.json({\n project: {\n ...project,\n installationStorageId: installation.id,\n sandboxProvider: options.sandbox ? 'custom' : 'none',\n },\n });\n } catch (error) {\n return gitlabFetchError(loose(c), error);\n }\n },\n }),\n registerApiRoute('/web/gitlab/projects/:id/prs', {\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 const factoryProjectId = c.req.query('factoryProjectId')?.trim();\n const page = positiveId(c.req.query('page') ?? '1');\n if (!factoryProjectId || !page) return c.json({ error: 'invalid_request' }, 400);\n if ((await gitlab.resolveOrgId(factoryProjectId)) !== resolved.tenant.orgId)\n return c.json({ error: 'factory_project_not_found' }, 404);\n const linked = await gitlab.getLinkedRepository({\n orgId: resolved.tenant.orgId,\n factoryProjectId,\n projectRepositoryId: c.req.param('id'),\n });\n if (!linked) return c.json({ error: 'project_repository_not_found' }, 404);\n const projectId = positiveId(linked.repository.externalId);\n if (!projectId) return c.json({ error: 'invalid_gitlab_project' }, 502);\n try {\n const target = await gitlab.versionControl.getRepositoryTarget({\n orgId: resolved.tenant.orgId,\n repositoryId: linked.repository.id,\n });\n const result = await gitlab.versionControl.listPullRequests({\n ...target,\n includeDrafts: false,\n cursor: String(page),\n });\n return c.json({\n pullRequests: result.pullRequests.map(pr => ({\n number: Number(pr.id),\n externalId: mergeRequestSourceKey(linked.host, projectId, Number(pr.id)),\n title: pr.title,\n url: pr.url,\n author: pr.author,\n assignees: pr.assignees ?? [],\n requestedReviewers: pr.requestedReviewers ?? [],\n labels: pr.labels ?? [],\n baseBranch: pr.baseBranch,\n headBranch: pr.headBranch,\n createdAt: pr.createdAt,\n updatedAt: pr.updatedAt,\n })),\n nextPage: result.nextCursor === null ? null : Number(result.nextCursor),\n });\n } catch (error) {\n return gitlabFetchError(loose(c), error);\n }\n },\n }),\n registerApiRoute('/web/gitlab/projects/:id/prs/:number', {\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 const factoryProjectId = c.req.query('factoryProjectId')?.trim();\n const number = positiveId(c.req.param('number'));\n if (!factoryProjectId || !number) return c.json({ error: 'invalid_request' }, 400);\n if ((await gitlab.resolveOrgId(factoryProjectId)) !== resolved.tenant.orgId)\n return c.json({ error: 'factory_project_not_found' }, 404);\n const linked = await gitlab.getLinkedRepository({\n orgId: resolved.tenant.orgId,\n factoryProjectId,\n projectRepositoryId: c.req.param('id'),\n });\n if (!linked) return c.json({ error: 'project_repository_not_found' }, 404);\n try {\n const target = await gitlab.versionControl.getRepositoryTarget({\n orgId: resolved.tenant.orgId,\n repositoryId: linked.repository.id,\n });\n const pr = await gitlab.versionControl.getPullRequest({ ...target, pullRequestId: String(number) });\n if (!pr) return c.json({ error: 'merge_request_not_found' }, 404);\n return c.json({\n number,\n title: pr.title,\n url: pr.url,\n author: pr.author,\n assignees: pr.assignees ?? [],\n requestedReviewers: pr.requestedReviewers ?? [],\n baseBranch: pr.baseBranch,\n headBranch: pr.headBranch,\n createdAt: pr.createdAt,\n updatedAt: pr.updatedAt,\n description: pr.body,\n });\n } catch (error) {\n return gitlabFetchError(loose(c), error);\n }\n },\n }),\n );\n }\n\n if (gitlab && auth && intake) {\n routes.push(\n registerApiRoute('/web/gitlab/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 const factoryProjectId = c.req.query('factoryProjectId')?.trim();\n if (!factoryProjectId) return c.json({ error: 'invalid_factory_project_id' }, 400);\n const board = c.req.query('board')?.trim();\n if (!board) return c.json({ error: 'invalid_board' }, 400);\n if ((await gitlab.resolveOrgId(factoryProjectId)) !== resolved.tenant.orgId) {\n return c.json({ error: 'factory_project_not_found' }, 404);\n }\n\n await intake.ensureReady();\n const config = await intake.getConfig({ orgId: resolved.tenant.orgId, integrationIds: ['gitlab'] });\n const selection = config.gitlab!;\n if (!selection.enabled) {\n return c.json(\n { error: 'gitlab_intake_disabled', message: 'GitLab intake is turned off in Settings.' },\n 404,\n );\n }\n const selected = new Set(selection.sourceIds ?? []);\n const sourceIds = [\n ...new Set(\n (await intake.listBindings({ orgId: resolved.tenant.orgId, integrationId: 'gitlab' }))\n .filter(\n binding =>\n binding.factoryProjectId === factoryProjectId &&\n binding.board === board &&\n selected.has(binding.sourceId),\n )\n .map(binding => binding.sourceId),\n ),\n ];\n if (sourceIds.length === 0) return c.json({ issues: [], nextCursor: null });\n\n try {\n const result = await gitlab.intake.listIssues({\n connection: { type: 'oauth', accessToken: 'gitlab-route' },\n sourceIds,\n cursor: c.req.query('after')?.trim() || undefined,\n });\n return c.json({\n ...result,\n issues: result.issues.map(issue => {\n const source = decodeSourceId(issue.sourceId ?? '');\n const issueIid = Number(issue.id);\n if (!source || !Number.isSafeInteger(issueIid) || issueIid <= 0) {\n throw new Error('GitLab returned an invalid routed issue reference.');\n }\n return { ...issue, externalId: encodeIssueReference({ ...source, issueIid }) };\n }),\n });\n } catch (error) {\n return gitlabFetchError(loose(c), error);\n }\n },\n }),\n );\n\n routes.push(\n registerApiRoute('/web/gitlab/issues/:issueId', {\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 const factoryProjectId = c.req.query('factoryProjectId')?.trim();\n if (!factoryProjectId) return c.json({ error: 'invalid_factory_project_id' }, 400);\n if ((await gitlab.resolveOrgId(factoryProjectId)) !== resolved.tenant.orgId) {\n return c.json({ error: 'factory_project_not_found' }, 404);\n }\n const issueId = c.req.param('issueId')?.trim();\n const issueReference = issueId ? decodeIssueReference(issueId) : null;\n if (!issueReference) return c.json({ error: 'invalid_gitlab_issue_id' }, 400);\n\n const { host, connectionId, projectId, projectPath } = issueReference;\n const sourceId = host\n ? encodeSourceId({ host, projectId })\n : encodeSourceId({ connectionId, projectId, projectPath });\n await intake.ensureReady();\n const config = await intake.getConfig({ orgId: resolved.tenant.orgId, integrationIds: ['gitlab'] });\n const selection = config.gitlab!;\n const selected = new Set(selection.sourceIds ?? []);\n const routed =\n selection.enabled &&\n selected.has(sourceId) &&\n (await intake.listBindings({ orgId: resolved.tenant.orgId, integrationId: 'gitlab' })).some(\n binding => binding.factoryProjectId === factoryProjectId && binding.sourceId === sourceId,\n );\n if (!routed) return c.json({ error: 'gitlab_issue_not_routed' }, 404);\n\n try {\n const issue = await gitlab.intake.getIssue({\n connection: { type: 'oauth', accessToken: 'gitlab-route' },\n issueId,\n });\n if (!issue) return c.json({ error: 'gitlab_issue_not_found' }, 404);\n return c.json(issue);\n } catch (error) {\n return gitlabFetchError(loose(c), error);\n }\n },\n }),\n );\n }\n\n if (gitlab && auth) {\n routes.push(\n registerApiRoute('/web/gitlab/subscriptions', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n await auth.ensureUser(loose(c));\n const tenant = auth.tenant(loose(c));\n if (!tenant?.orgId) return c.json({ error: 'unauthorized' }, 401);\n\n const resourceId = c.req.query('resourceId');\n const threadId = c.req.query('threadId');\n const sessionScope = c.req.query('scope');\n if (!resourceId || !threadId) return c.json({ error: 'resourceId and threadId are required' }, 400);\n\n const subscriptions = await listMergeRequestSubscriptionsForThread(\n { orgId: tenant.orgId, resourceId, threadId, sessionScope },\n gitlab.integrationStorage,\n );\n return c.json({\n subscriptions: subscriptions.map(subscription => ({\n id: subscription.id,\n repoFullName: subscription.data.projectPath,\n pullRequestNumber: Number(subscription.data.changeRequestId),\n status: subscription.status,\n url: mergeRequestUrl(\n subscription.data.host,\n subscription.data.projectPath,\n subscription.data.changeRequestId,\n ),\n })),\n });\n },\n }),\n );\n }\n\n routes.push(\n registerApiRoute('/web/gitlab/webhook', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const result = await handleGitLabWebhook(loose(c), {\n webhookSecret: options.webhookSecret,\n ingestFactoryEvent: options.ingestFactoryEvent,\n ...(options.controller && gitlab\n ? {\n controller: options.controller,\n gitlab,\n onTargetError: (subscription, error) => {\n console.warn(\n `[GitLab Webhook] Delivery failed for subscription ${subscription.id} (${subscription.resourceId}/${subscription.threadId}).`,\n error,\n );\n },\n }\n : {}),\n });\n return c.json(result.body, result.status);\n },\n }),\n );\n return routes;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"routes.js","names":[],"sources":["../../../src/integrations/gitlab/routes.ts"],"sourcesContent":["import type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { FactorySandbox } from '@mastra/core/workspace';\nimport type { Context } from 'hono';\nimport type { RouteAuth } from '../../routes/route.js';\nimport { sanitizeSegment } from '../../sandbox/workdir.js';\nimport type { AuditEmitter } from '../../storage/domains/audit/domain.js';\nimport type { IntakeStorage } from '../../storage/domains/intake/base.js';\nimport { GitLabApiError } from './api.js';\nimport {\n decodeIssueReference,\n decodeSourceId,\n encodeIssueReference,\n encodeSourceId,\n gitlabConnection,\n} from './integration.js';\nimport type { GitLabIntegrationBase } from './integration.js';\nimport { listMergeRequestSubscriptionsForThread, mergeRequestUrl } from './subscriptions.js';\nimport { handleGitLabWebhook } from './webhook.js';\nimport type { GitLabWebhookHandlerOptions, ParsedGitLabWebhook } from './webhook.js';\n\ntype RouteContext = Context;\n\nfunction loose(c: unknown): RouteContext {\n return c as RouteContext;\n}\n\nexport interface BuildGitLabRoutesOptions {\n gitlab?: GitLabIntegrationBase;\n auth?: RouteAuth;\n intake?: IntakeStorage;\n sandbox?: FactorySandbox;\n emitAudit?: AuditEmitter['emit'];\n webhookSecret?: string;\n ingestFactoryEvent?: (event: ParsedGitLabWebhook) => Promise<unknown>;\n /** Mounted agent controller; enables webhook delivery to subscribed sessions. */\n controller?: GitLabWebhookHandlerOptions['controller'];\n}\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', reason: 'auth_required' }, 401) };\n if (!tenant.orgId) {\n return {\n response: c.json(\n {\n error: 'organization_required',\n message: 'GitLab intake requires an organization. Personal accounts cannot use GitLab intake.',\n },\n 403,\n ),\n };\n }\n return { tenant: { orgId: tenant.orgId, userId: tenant.userId } };\n}\n\nfunction gitlabFetchError(c: RouteContext, error: unknown) {\n if (error instanceof GitLabApiError && error.code === 'gitlab_auth_failed') {\n return c.json({ error: 'gitlab_auth_failed', message: error.message }, 409);\n }\n return c.json({ error: 'gitlab_fetch_failed', message: error instanceof Error ? error.message : String(error) }, 502);\n}\n\ntype GitLabSourceIdentityMigration = { from: string; to: string };\n\nfunction gitlabProjectPayload(source: { id: string; name: string; metadata?: Record<string, unknown> }) {\n const connectionId = typeof source.metadata?.connectionId === 'string' ? source.metadata.connectionId : null;\n const projectId = typeof source.metadata?.projectId === 'string' ? source.metadata.projectId : null;\n const projectPath = typeof source.metadata?.projectPath === 'string' ? source.metadata.projectPath : source.name;\n if (!connectionId || !projectId) return null;\n const repositoryName = projectPath.split('/').filter(Boolean).at(-1) ?? 'repo';\n return {\n id: source.id,\n name: source.name,\n projectId,\n projectPath,\n connectionId,\n accountLabel: typeof source.metadata?.accountLabel === 'string' ? source.metadata.accountLabel : null,\n defaultBranch: typeof source.metadata?.defaultBranch === 'string' ? source.metadata.defaultBranch : 'main',\n sandboxProvider: 'none',\n sandboxWorkdir: `~/${sanitizeSegment(repositoryName)}`,\n };\n}\n\nfunction positiveId(value: string | undefined): number | null {\n const number = Number(value);\n return value && /^[1-9]\\d*$/.test(value) && Number.isSafeInteger(number) ? number : null;\n}\n\nfunction mergeRequestSourceKey(host: string, projectId: number, mergeRequestIid: number): string {\n return `gitlab-pr:${Buffer.from(JSON.stringify({ version: 1, host, projectId, mergeRequestIid }), 'utf8').toString('base64url')}`;\n}\n\nasync function reconcileGitLabSourceIdentity({\n intake,\n orgId,\n sources,\n}: {\n intake: IntakeStorage;\n orgId: string;\n sources: Array<{ id: string; metadata?: Record<string, unknown> }>;\n}): Promise<{ migrations: GitLabSourceIdentityMigration[]; conflicts: GitLabSourceIdentityMigration[] }> {\n await intake.ensureReady();\n const [config, bindings] = await Promise.all([\n intake.getConfig({ orgId }),\n intake.listBindings({ orgId, integrationId: 'gitlab' }),\n ]);\n const selected = config.gitlab?.sourceIds ?? [];\n const canonicalByProject = new Map<string, string[]>();\n for (const source of sources) {\n const reference = decodeSourceId(source.id);\n if (!reference?.host) continue;\n const ids = canonicalByProject.get(reference.projectId) ?? [];\n ids.push(source.id);\n canonicalByProject.set(reference.projectId, ids);\n }\n\n const migrations = new Map<string, string>();\n for (const sourceId of new Set([...selected, ...bindings.map(binding => binding.sourceId)])) {\n const reference = decodeSourceId(sourceId);\n if (!reference || reference.host) continue;\n const candidates = canonicalByProject.get(reference.projectId) ?? [];\n if (candidates.length === 1) migrations.set(sourceId, candidates[0]!);\n }\n return intake.migrateSourceIds({\n orgId,\n integrationId: 'gitlab',\n migrations: [...migrations].map(([from, to]) => ({ from, to })),\n });\n}\n\nexport function buildGitLabRoutes(options: BuildGitLabRoutesOptions): ApiRoute[] {\n const routes: ApiRoute[] = [];\n const { gitlab, auth, intake, emitAudit } = options;\n const enabled = Boolean(gitlab && auth?.enabled());\n\n if (gitlab && auth) {\n routes.push(\n registerApiRoute('/web/gitlab/status', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const diagnostics = gitlab.diagnostics();\n if (!enabled) {\n return c.json({ enabled: false, configured: true, reauthRequired: false, reason: 'missing_config' });\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 if (!tenant.orgId) {\n return c.json({\n enabled: true,\n configured: false,\n organizationRequired: true,\n connections: [],\n accounts: [],\n reauthRequired: false,\n reason: 'organization_required',\n });\n }\n\n try {\n await gitlab.verifyStatus();\n const connections = await gitlab.statusConnections();\n const active = connections?.filter(connection => connection.status === 'active');\n const direct = connections === undefined;\n const endpointHost = typeof diagnostics.endpointHost === 'string' ? diagnostics.endpointHost : null;\n const accounts = direct\n ? endpointHost\n ? [endpointHost]\n : []\n : (active ?? []).flatMap(connection => (connection.accountLabel ? [connection.accountLabel] : []));\n const configured = direct || (active?.length ?? 0) > 0;\n return c.json({\n enabled: true,\n configured,\n mode: direct ? 'direct' : 'platform',\n ...(connections ? { connections } : {}),\n accounts,\n reauthRequired: connections?.some(connection => connection.status === 'needs_reauth') ?? false,\n reason: configured ? 'ready' : 'not_connected',\n });\n } catch (error) {\n return gitlabFetchError(loose(c), error);\n }\n },\n }),\n registerApiRoute('/web/gitlab/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 try {\n const sources = await gitlab.intake.listSources(resolved.tenant);\n if (intake) {\n const identity = await reconcileGitLabSourceIdentity({\n intake,\n orgId: resolved.tenant.orgId,\n sources,\n });\n if (identity.conflicts.length > 0) {\n return c.json(\n {\n error: 'gitlab_source_identity_conflict',\n message: 'Conflicting routes exist for the same GitLab project. Resolve the duplicate bindings.',\n conflicts: identity.conflicts,\n },\n 409,\n );\n }\n if (identity.migrations.length > 0) {\n await emitAudit?.({\n context: loose(c),\n input: {\n action: 'factory.intake.config_updated',\n targets: identity.migrations.map(migration => ({ type: 'intake_source', id: migration.to })),\n metadata: { provider: 'gitlab', migrated: identity.migrations.length },\n },\n });\n }\n }\n return c.json({\n projects: sources.flatMap(source => {\n const project = gitlabProjectPayload(source);\n return project ? [{ ...project, sandboxProvider: options.sandbox ? 'custom' : 'none' }] : [];\n }),\n });\n } catch (error) {\n return gitlabFetchError(loose(c), error);\n }\n },\n }),\n registerApiRoute('/web/gitlab/projects/registration', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await resolveOrgTenant(loose(c), auth);\n if ('response' in resolved) return resolved.response;\n const input = (await c.req.json().catch(() => null)) as { sourceId?: unknown } | null;\n const sourceId = typeof input?.sourceId === 'string' ? input.sourceId.trim() : '';\n if (!sourceId) return c.json({ error: 'invalid_gitlab_source' }, 400);\n try {\n const source = (await gitlab.intake.listSources(resolved.tenant)).find(\n candidate => candidate.id === sourceId,\n );\n const project = source ? gitlabProjectPayload(source) : null;\n if (!project) return c.json({ error: 'gitlab_project_not_found' }, 404);\n const installation = await gitlab.versionControl.registerInstallation({\n orgId: resolved.tenant.orgId,\n userId: resolved.tenant.userId,\n installation: {\n externalId: project.connectionId,\n accountName: project.accountLabel ?? 'GitLab',\n accountType: 'GitLab',\n metadata: { connection: gitlabConnection(project.connectionId) },\n },\n });\n return c.json({\n project: {\n ...project,\n installationStorageId: installation.id,\n sandboxProvider: options.sandbox ? 'custom' : 'none',\n },\n });\n } catch (error) {\n return gitlabFetchError(loose(c), error);\n }\n },\n }),\n registerApiRoute('/web/gitlab/projects/:id/prs', {\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 const factoryProjectId = c.req.query('factoryProjectId')?.trim();\n const page = positiveId(c.req.query('page') ?? '1');\n if (!factoryProjectId || !page) return c.json({ error: 'invalid_request' }, 400);\n if ((await gitlab.resolveOrgId(factoryProjectId)) !== resolved.tenant.orgId)\n return c.json({ error: 'factory_project_not_found' }, 404);\n const linked = await gitlab.getLinkedRepository({\n orgId: resolved.tenant.orgId,\n factoryProjectId,\n projectRepositoryId: c.req.param('id'),\n });\n if (!linked) return c.json({ error: 'project_repository_not_found' }, 404);\n const projectId = positiveId(linked.repository.externalId);\n if (!projectId) return c.json({ error: 'invalid_gitlab_project' }, 502);\n try {\n const target = await gitlab.versionControl.getRepositoryTarget({\n orgId: resolved.tenant.orgId,\n repositoryId: linked.repository.id,\n });\n const result = await gitlab.versionControl.listPullRequests({\n ...target,\n includeDrafts: false,\n cursor: String(page),\n });\n return c.json({\n pullRequests: result.pullRequests.map(pr => ({\n number: Number(pr.id),\n externalId: mergeRequestSourceKey(linked.host, projectId, Number(pr.id)),\n title: pr.title,\n url: pr.url,\n author: pr.author,\n assignees: pr.assignees ?? [],\n requestedReviewers: pr.requestedReviewers ?? [],\n labels: pr.labels ?? [],\n baseBranch: pr.baseBranch,\n headBranch: pr.headBranch,\n createdAt: pr.createdAt,\n updatedAt: pr.updatedAt,\n })),\n nextPage: result.nextCursor === null ? null : Number(result.nextCursor),\n });\n } catch (error) {\n return gitlabFetchError(loose(c), error);\n }\n },\n }),\n registerApiRoute('/web/gitlab/projects/:id/prs/:number', {\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 const factoryProjectId = c.req.query('factoryProjectId')?.trim();\n const number = positiveId(c.req.param('number'));\n if (!factoryProjectId || !number) return c.json({ error: 'invalid_request' }, 400);\n if ((await gitlab.resolveOrgId(factoryProjectId)) !== resolved.tenant.orgId)\n return c.json({ error: 'factory_project_not_found' }, 404);\n const linked = await gitlab.getLinkedRepository({\n orgId: resolved.tenant.orgId,\n factoryProjectId,\n projectRepositoryId: c.req.param('id'),\n });\n if (!linked) return c.json({ error: 'project_repository_not_found' }, 404);\n try {\n const target = await gitlab.versionControl.getRepositoryTarget({\n orgId: resolved.tenant.orgId,\n repositoryId: linked.repository.id,\n });\n const pr = await gitlab.versionControl.getPullRequest({ ...target, pullRequestId: String(number) });\n if (!pr) return c.json({ error: 'merge_request_not_found' }, 404);\n return c.json({\n number,\n title: pr.title,\n url: pr.url,\n author: pr.author,\n assignees: pr.assignees ?? [],\n requestedReviewers: pr.requestedReviewers ?? [],\n baseBranch: pr.baseBranch,\n headBranch: pr.headBranch,\n createdAt: pr.createdAt,\n updatedAt: pr.updatedAt,\n description: pr.body,\n });\n } catch (error) {\n return gitlabFetchError(loose(c), error);\n }\n },\n }),\n );\n }\n\n if (gitlab && auth && intake) {\n routes.push(\n registerApiRoute('/web/gitlab/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 const factoryProjectId = c.req.query('factoryProjectId')?.trim();\n if (!factoryProjectId) return c.json({ error: 'invalid_factory_project_id' }, 400);\n const board = c.req.query('board')?.trim();\n if (!board) return c.json({ error: 'invalid_board' }, 400);\n if ((await gitlab.resolveOrgId(factoryProjectId)) !== resolved.tenant.orgId) {\n return c.json({ error: 'factory_project_not_found' }, 404);\n }\n\n await intake.ensureReady();\n const config = await intake.getConfig({ orgId: resolved.tenant.orgId, integrationIds: ['gitlab'] });\n const selection = config.gitlab!;\n if (!selection.enabled) {\n return c.json(\n { error: 'gitlab_intake_disabled', message: 'GitLab intake is turned off in Settings.' },\n 404,\n );\n }\n const selected = new Set(selection.sourceIds ?? []);\n const sourceIds = [\n ...new Set(\n (await intake.listBindings({ orgId: resolved.tenant.orgId, integrationId: 'gitlab' }))\n .filter(\n binding =>\n binding.factoryProjectId === factoryProjectId &&\n binding.board === board &&\n selected.has(binding.sourceId),\n )\n .map(binding => binding.sourceId),\n ),\n ];\n if (sourceIds.length === 0) return c.json({ issues: [], nextCursor: null });\n\n try {\n const result = await gitlab.intake.listIssues({\n connection: { type: 'oauth', accessToken: 'gitlab-route' },\n sourceIds,\n cursor: c.req.query('after')?.trim() || undefined,\n });\n return c.json({\n ...result,\n issues: result.issues.map(issue => {\n const source = decodeSourceId(issue.sourceId ?? '');\n const issueIid = Number(issue.id);\n if (!source || !Number.isSafeInteger(issueIid) || issueIid <= 0) {\n throw new Error('GitLab returned an invalid routed issue reference.');\n }\n return { ...issue, externalId: encodeIssueReference({ ...source, issueIid }) };\n }),\n });\n } catch (error) {\n return gitlabFetchError(loose(c), error);\n }\n },\n }),\n );\n\n routes.push(\n registerApiRoute('/web/gitlab/issues/:issueId', {\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 const factoryProjectId = c.req.query('factoryProjectId')?.trim();\n if (!factoryProjectId) return c.json({ error: 'invalid_factory_project_id' }, 400);\n if ((await gitlab.resolveOrgId(factoryProjectId)) !== resolved.tenant.orgId) {\n return c.json({ error: 'factory_project_not_found' }, 404);\n }\n const issueId = c.req.param('issueId')?.trim();\n const issueReference = issueId ? decodeIssueReference(issueId) : null;\n if (!issueReference) return c.json({ error: 'invalid_gitlab_issue_id' }, 400);\n\n const { host, connectionId, projectId, projectPath } = issueReference;\n const sourceId = host\n ? encodeSourceId({ host, projectId })\n : encodeSourceId({ connectionId, projectId, projectPath });\n await intake.ensureReady();\n const config = await intake.getConfig({ orgId: resolved.tenant.orgId, integrationIds: ['gitlab'] });\n const selection = config.gitlab!;\n const selected = new Set(selection.sourceIds ?? []);\n const routed =\n selection.enabled &&\n selected.has(sourceId) &&\n (await intake.listBindings({ orgId: resolved.tenant.orgId, integrationId: 'gitlab' })).some(\n binding => binding.factoryProjectId === factoryProjectId && binding.sourceId === sourceId,\n );\n if (!routed) return c.json({ error: 'gitlab_issue_not_routed' }, 404);\n\n try {\n const issue = await gitlab.intake.getIssue({\n connection: { type: 'oauth', accessToken: 'gitlab-route' },\n issueId,\n });\n if (!issue) return c.json({ error: 'gitlab_issue_not_found' }, 404);\n return c.json(issue);\n } catch (error) {\n return gitlabFetchError(loose(c), error);\n }\n },\n }),\n );\n }\n\n if (gitlab && auth) {\n routes.push(\n registerApiRoute('/web/gitlab/subscriptions', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n await auth.ensureUser(loose(c));\n const tenant = auth.tenant(loose(c));\n if (!tenant?.orgId) return c.json({ error: 'unauthorized' }, 401);\n\n const resourceId = c.req.query('resourceId');\n const threadId = c.req.query('threadId');\n const sessionScope = c.req.query('scope');\n if (!resourceId || !threadId) return c.json({ error: 'resourceId and threadId are required' }, 400);\n\n const subscriptions = await listMergeRequestSubscriptionsForThread(\n { orgId: tenant.orgId, resourceId, threadId, sessionScope },\n gitlab.integrationStorage,\n );\n return c.json({\n subscriptions: subscriptions.map(subscription => ({\n id: subscription.id,\n repoFullName: subscription.data.projectPath,\n pullRequestNumber: Number(subscription.data.changeRequestId),\n status: subscription.status,\n url: mergeRequestUrl(\n subscription.data.host,\n subscription.data.projectPath,\n subscription.data.changeRequestId,\n ),\n })),\n });\n },\n }),\n );\n }\n\n routes.push(\n registerApiRoute('/web/gitlab/webhook', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const result = await handleGitLabWebhook(loose(c), {\n webhookSecret: options.webhookSecret,\n ingestFactoryEvent: options.ingestFactoryEvent,\n ...(options.controller && gitlab\n ? {\n controller: options.controller,\n gitlab,\n onTargetError: (subscription, error) => {\n console.warn(\n `[GitLab Webhook] Delivery failed for subscription ${subscription.id} (${subscription.resourceId}/${subscription.threadId}).`,\n error,\n );\n },\n }\n : {}),\n });\n return c.json(result.body, result.status);\n },\n }),\n );\n return routes;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"session-subscriptions.d.ts","sourceRoot":"","sources":["../../../src/integrations/gitlab/session-subscriptions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAWnE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAG9D,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AAiCzE,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAMhH;AAmHD,wBAAsB,qCAAqC,CACzD,cAAc,EAAE,cAAc,EAC9B,YAAY,EAAE,MAAM,GAAG,MAAM,EAC7B,MAAM,EAAE,8BAA8B,EACtC,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAmB7B;AAED,wBAAsB,yCAAyC,CAC7D,cAAc,EAAE,cAAc,EAC9B,YAAY,EAAE,MAAM,GAAG,MAAM,EAC7B,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAKjB;AAED,wBAAgB,6BAA6B,CAAC,cAAc,EAAE,cAAc,EAAE,MAAM,EAAE,qBAAqB;;;;;;;;;;EAyB1G;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,MAAM,GAAG,SAAS,CAKrB"}
1
+ {"version":3,"file":"session-subscriptions.d.ts","sourceRoot":"","sources":["../../../src/integrations/gitlab/session-subscriptions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAWnE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAG9D,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AAiCzE,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAMhH;AA0HD,wBAAsB,qCAAqC,CACzD,cAAc,EAAE,cAAc,EAC9B,YAAY,EAAE,MAAM,GAAG,MAAM,EAC7B,MAAM,EAAE,8BAA8B,EACtC,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAmB7B;AAED,wBAAsB,yCAAyC,CAC7D,cAAc,EAAE,cAAc,EAC9B,YAAY,EAAE,MAAM,GAAG,MAAM,EAC7B,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAKjB;AAED,wBAAgB,6BAA6B,CAAC,cAAc,EAAE,cAAc,EAAE,MAAM,EAAE,qBAAqB;;;;;;;;;;EAyB1G;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,MAAM,GAAG,SAAS,CAKrB"}
@@ -1,8 +1,8 @@
1
1
  import { getFactoryAuthOrgId, getFactoryAuthUserFromContext, getFactoryAuthUserId } from "../../auth.js";
2
2
  import { subscribeToMergeRequest, unsubscribeFromMergeRequest } from "./subscriptions.js";
3
3
  import { normalizeGitLabHost } from "./integration.js";
4
- import { createTool } from "@mastra/core/tools";
5
4
  import { z } from "zod";
5
+ import { createTool } from "@mastra/core/tools";
6
6
  //#region src/integrations/gitlab/session-subscriptions.ts
7
7
  const MERGE_REQUEST_URL = /^https?:\/\/([^/\s]+)\/(.+?)\/-\/merge_requests\/(\d+)\/?$/i;
8
8
  function sessionUserId(requestContext) {
@@ -35,23 +35,24 @@ function parseMergeRequest(value, target) {
35
35
  }
36
36
  /**
37
37
  * Whether the current request comes from a session that merge-request
38
- * subscriptions can ever apply to: an authenticated org user on a repository
38
+ * subscriptions can ever apply to: an authenticated org user on a factory
39
39
  * session with an active thread. Mirrors the GitHub gate; whether the
40
- * repository is GitLab-linked is only known after a storage read, so the
41
- * entry points verify that and fail loudly for the explicit tools.
40
+ * session's repository is GitLab-linked is only known after a storage read,
41
+ * so the entry points verify that and fail loudly for the explicit tools.
42
42
  */
43
43
  function isRepositorySession(requestContext) {
44
44
  const context = requestContext.get("controller");
45
- return Boolean(context?.threadId && context.getState().projectRepositoryId && sessionOrgId(requestContext) && sessionUserId(requestContext));
45
+ return Boolean(context?.threadId && context.getState().factoryProjectId && sessionOrgId(requestContext) && sessionUserId(requestContext));
46
46
  }
47
47
  async function resolveSessionTarget(requestContext, gitlab) {
48
48
  const context = requestContext.get("controller");
49
49
  const orgId = sessionOrgId(requestContext);
50
50
  const userId = sessionUserId(requestContext);
51
- const projectRepositoryId = context?.getState().projectRepositoryId;
52
- if (!context || !context.threadId || !projectRepositoryId || !orgId || !userId) throw new Error("GitLab subscriptions require an authenticated repository session with an active thread.");
51
+ if (!context || !context.threadId || !context.getState().factoryProjectId || !orgId || !userId) throw new Error("GitLab subscriptions require an authenticated repository session with an active thread.");
53
52
  const storage = gitlab.sourceControlStorage;
54
53
  if (!storage) throw new Error("GitLab source control is unavailable.");
54
+ const projectRepositoryId = context.getState().projectRepositoryId ?? (await storage.sessions.getBySessionId(context.resourceId))?.projectRepositoryId;
55
+ if (!projectRepositoryId) return void 0;
55
56
  const projectRepository = await storage.projectRepositories.get({
56
57
  orgId,
57
58
  id: projectRepositoryId
@@ -1 +1 @@
1
- {"version":3,"file":"session-subscriptions.js","names":[],"sources":["../../../src/integrations/gitlab/session-subscriptions.ts"],"sourcesContent":["import type { AgentControllerRequestContext } from '@mastra/core/agent-controller';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport { createTool } from '@mastra/core/tools';\nimport { z } from 'zod';\n\nimport { getFactoryAuthOrgId, getFactoryAuthUserFromContext, getFactoryAuthUserId } from '../../auth.js';\nimport type {\n ProjectRepository,\n ProjectSourceControlConnection,\n SourceControlInstallation,\n SourceControlRepository,\n} from '../../storage/domains/source-control/base.js';\nimport type { GitLabIntegrationBase } from './integration.js';\nimport { normalizeGitLabHost } from './integration.js';\nimport { subscribeToMergeRequest, unsubscribeFromMergeRequest } from './subscriptions.js';\nimport type { GitLabSignalSubscriptionSource } from './subscriptions.js';\n\ntype RepositorySessionState = { factoryProjectId?: string; projectRepositoryId?: string };\n\nconst MERGE_REQUEST_URL = /^https?:\\/\\/([^/\\s]+)\\/(.+?)\\/-\\/merge_requests\\/(\\d+)\\/?$/i;\n\nfunction sessionUserId(requestContext: RequestContext): string | undefined {\n return getFactoryAuthUserId(getFactoryAuthUserFromContext(requestContext));\n}\n\nfunction sessionOrgId(requestContext: RequestContext): string | undefined {\n return getFactoryAuthOrgId(getFactoryAuthUserFromContext(requestContext));\n}\n\nconst mergeRequestInputSchema = z.object({\n mergeRequest: z.union([z.number().int().positive(), z.string().min(1)]),\n});\n\ninterface SessionTarget {\n context: AgentControllerRequestContext<RepositorySessionState>;\n projectRepository: ProjectRepository;\n connection: ProjectSourceControlConnection;\n installation: SourceControlInstallation;\n repository: SourceControlRepository;\n host: string;\n orgId: string;\n userId: string;\n}\n\nfunction normalizePath(value: string): string {\n return value.replace(/^\\/+|\\/+$/g, '').toLowerCase();\n}\n\nexport function parseMergeRequestUrl(url: string): { host: string; projectPath: string; iid: number } | undefined {\n const match = url.trim().match(MERGE_REQUEST_URL);\n if (!match) return undefined;\n const iid = Number(match[3]);\n if (!Number.isSafeInteger(iid) || iid < 1) return undefined;\n return { host: normalizeGitLabHost(match[1]!), projectPath: match[2]!.replace(/\\/+$/, ''), iid };\n}\n\nfunction parseMergeRequest(value: number | string, target: SessionTarget): number {\n if (typeof value === 'number') return value;\n if (/^\\d+$/.test(value)) return Number(value);\n const parsed = parseMergeRequestUrl(value);\n if (\n !parsed ||\n parsed.host !== target.host ||\n normalizePath(parsed.projectPath) !== normalizePath(target.repository.slug)\n ) {\n throw new Error(`Merge request must belong to ${target.host}/${target.repository.slug}.`);\n }\n return parsed.iid;\n}\n\n/**\n * Whether the current request comes from a session that merge-request\n * subscriptions can ever apply to: an authenticated org user on a repository\n * session with an active thread. Mirrors the GitHub gate; whether the\n * repository is GitLab-linked is only known after a storage read, so the\n * entry points verify that and fail loudly for the explicit tools.\n */\nfunction isRepositorySession(requestContext: RequestContext): boolean {\n const context = requestContext.get('controller') as AgentControllerRequestContext<RepositorySessionState> | undefined;\n return Boolean(\n context?.threadId &&\n context.getState().projectRepositoryId &&\n sessionOrgId(requestContext) &&\n sessionUserId(requestContext),\n );\n}\n\nasync function resolveSessionTarget(\n requestContext: RequestContext,\n gitlab: GitLabIntegrationBase,\n): Promise<SessionTarget | undefined> {\n const context = requestContext.get('controller') as AgentControllerRequestContext<RepositorySessionState> | undefined;\n const orgId = sessionOrgId(requestContext);\n const userId = sessionUserId(requestContext);\n const projectRepositoryId = context?.getState().projectRepositoryId;\n if (!context || !context.threadId || !projectRepositoryId || !orgId || !userId) {\n throw new Error('GitLab subscriptions require an authenticated repository session with an active thread.');\n }\n const storage = gitlab.sourceControlStorage;\n if (!storage) throw new Error('GitLab source control is unavailable.');\n\n // The handle is scoped to GitLab rows, so a GitHub-linked repository is\n // simply absent here rather than misidentified.\n const projectRepository = await storage.projectRepositories.get({ orgId, id: projectRepositoryId });\n if (!projectRepository) return undefined;\n const connection = await storage.connections.get({ orgId, id: projectRepository.connectionId });\n if (!connection || connection.integrationId !== 'gitlab') return undefined;\n const repository = await storage.repositories.get({ orgId, id: projectRepository.repositoryId });\n if (!repository) throw new Error('Repository not found for this organization.');\n const installation = await storage.installations.get({ orgId, id: connection.installationId });\n if (!installation) throw new Error('Source-control installation not found for this organization.');\n const host = installation.providerMetadata.host;\n if (typeof host !== 'string' || !host) throw new Error('GitLab installation is missing its instance host.');\n return {\n context,\n projectRepository,\n connection,\n installation,\n repository,\n host: normalizeGitLabHost(host),\n orgId,\n userId,\n };\n}\n\nasync function requireGitLabSessionTarget(\n requestContext: RequestContext,\n gitlab: GitLabIntegrationBase,\n): Promise<SessionTarget> {\n const target = await resolveSessionTarget(requestContext, gitlab);\n if (!target) throw new Error('The active session is not backed by a GitLab repository.');\n return target;\n}\n\nasync function verifyMergeRequest(target: SessionTarget, iid: number, gitlab: GitLabIntegrationBase): Promise<void> {\n const repositoryTarget = await gitlab.versionControl.getRepositoryTarget({\n orgId: target.orgId,\n repositoryId: target.repository.id,\n });\n const mergeRequest = await gitlab.versionControl.getPullRequest({ ...repositoryTarget, pullRequestId: String(iid) });\n if (!mergeRequest) throw new Error(`Merge request !${iid} was not found in ${target.repository.slug}.`);\n const parsed = parseMergeRequestUrl(mergeRequest.url);\n if (\n parsed &&\n (parsed.host !== target.host || normalizePath(parsed.projectPath) !== normalizePath(target.repository.slug))\n ) {\n throw new Error('Merge request project does not match the active project repository.');\n }\n}\n\nfunction subscriptionInput(target: SessionTarget, iid: number) {\n return {\n orgId: target.orgId,\n host: target.host,\n projectId: target.repository.externalId,\n projectPath: target.repository.slug,\n projectRepositoryId: target.projectRepository.id,\n installationExternalId: target.installation.externalId,\n changeRequestId: String(iid),\n sessionId: target.context.session.id,\n ownerId: target.context.session.ownerId,\n resourceId: target.connection.factoryProjectId,\n threadId: target.context.threadId!,\n sessionScope: target.context.scope,\n source: 'explicit-tool' as GitLabSignalSubscriptionSource,\n subscribedByUserId: target.userId,\n };\n}\n\nexport async function subscribeCurrentSessionToMergeRequest(\n requestContext: RequestContext,\n mergeRequest: number | string,\n source: GitLabSignalSubscriptionSource,\n gitlab: GitLabIntegrationBase,\n): Promise<number | undefined> {\n // The auto path observes every successful change-request creation in every\n // session, including GitHub-project sessions where a GitLab subscription can\n // never apply. Skip silently there; only the explicit tool should surface\n // \"this session cannot subscribe\" as an error.\n if (source === 'auto-create-change-request') {\n if (!isRepositorySession(requestContext)) return undefined;\n const target = await resolveSessionTarget(requestContext, gitlab);\n if (!target) return undefined;\n const iid = parseMergeRequest(mergeRequest, target);\n await verifyMergeRequest(target, iid, gitlab);\n await subscribeToMergeRequest({ ...subscriptionInput(target, iid), source }, gitlab.integrationStorage);\n return iid;\n }\n const target = await requireGitLabSessionTarget(requestContext, gitlab);\n const iid = parseMergeRequest(mergeRequest, target);\n await verifyMergeRequest(target, iid, gitlab);\n await subscribeToMergeRequest({ ...subscriptionInput(target, iid), source }, gitlab.integrationStorage);\n return iid;\n}\n\nexport async function unsubscribeCurrentSessionFromMergeRequest(\n requestContext: RequestContext,\n mergeRequest: number | string,\n gitlab: GitLabIntegrationBase,\n): Promise<number> {\n const target = await requireGitLabSessionTarget(requestContext, gitlab);\n const iid = parseMergeRequest(mergeRequest, target);\n await unsubscribeFromMergeRequest(subscriptionInput(target, iid), gitlab.integrationStorage);\n return iid;\n}\n\nexport function createGitLabSubscriptionTools(requestContext: RequestContext, gitlab: GitLabIntegrationBase) {\n if (!isRepositorySession(requestContext)) return {};\n\n return {\n gitlab_subscribe_mr: createTool({\n id: 'gitlab_subscribe_mr',\n description:\n 'Subscribe this thread to GitLab merge request activity. You usually do not need this tool: successful source_control_create_change_request calls subscribe automatically. Use it for an existing MR or to recover when automatic subscription did not occur. Closed or merged MRs are unsubscribed automatically. Accepts an MR IID or canonical URL for the active project.',\n inputSchema: mergeRequestInputSchema,\n execute: async ({ mergeRequest }) => {\n const iid = await subscribeCurrentSessionToMergeRequest(requestContext, mergeRequest, 'explicit-tool', gitlab);\n return { subscribed: true, mergeRequestIid: iid };\n },\n }),\n gitlab_unsubscribe_mr: createTool({\n id: 'gitlab_unsubscribe_mr',\n description:\n 'Manually unsubscribe this thread from GitLab merge request activity. You usually do not need this tool because closed or merged MRs are unsubscribed automatically. Use it to stop notifications before then. Accepts an MR IID or canonical URL for the active project.',\n inputSchema: mergeRequestInputSchema,\n execute: async ({ mergeRequest }) => {\n const iid = await unsubscribeCurrentSessionFromMergeRequest(requestContext, mergeRequest, gitlab);\n return { subscribed: false, mergeRequestIid: iid };\n },\n }),\n };\n}\n\n/**\n * The merge request URL a successful provider-neutral change-request creation\n * reported, when that URL is a GitLab one. Anything else is not ours to observe.\n */\nexport function parseCreatedMergeRequest(context: {\n toolName: string;\n input: unknown;\n output?: unknown;\n error?: unknown;\n}): string | undefined {\n if (context.toolName !== 'source_control_create_change_request' || context.error) return undefined;\n const url = (context.output as { url?: unknown } | undefined)?.url;\n if (typeof url !== 'string' || !parseMergeRequestUrl(url)) return undefined;\n return url.trim().replace(/\\/$/, '');\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"session-subscriptions.js","names":[],"sources":["../../../src/integrations/gitlab/session-subscriptions.ts"],"sourcesContent":["import type { AgentControllerRequestContext } from '@mastra/core/agent-controller';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport { createTool } from '@mastra/core/tools';\nimport { z } from 'zod';\n\nimport { getFactoryAuthOrgId, getFactoryAuthUserFromContext, getFactoryAuthUserId } from '../../auth.js';\nimport type {\n ProjectRepository,\n ProjectSourceControlConnection,\n SourceControlInstallation,\n SourceControlRepository,\n} from '../../storage/domains/source-control/base.js';\nimport type { GitLabIntegrationBase } from './integration.js';\nimport { normalizeGitLabHost } from './integration.js';\nimport { subscribeToMergeRequest, unsubscribeFromMergeRequest } from './subscriptions.js';\nimport type { GitLabSignalSubscriptionSource } from './subscriptions.js';\n\ntype RepositorySessionState = { factoryProjectId?: string; projectRepositoryId?: string };\n\nconst MERGE_REQUEST_URL = /^https?:\\/\\/([^/\\s]+)\\/(.+?)\\/-\\/merge_requests\\/(\\d+)\\/?$/i;\n\nfunction sessionUserId(requestContext: RequestContext): string | undefined {\n return getFactoryAuthUserId(getFactoryAuthUserFromContext(requestContext));\n}\n\nfunction sessionOrgId(requestContext: RequestContext): string | undefined {\n return getFactoryAuthOrgId(getFactoryAuthUserFromContext(requestContext));\n}\n\nconst mergeRequestInputSchema = z.object({\n mergeRequest: z.union([z.number().int().positive(), z.string().min(1)]),\n});\n\ninterface SessionTarget {\n context: AgentControllerRequestContext<RepositorySessionState>;\n projectRepository: ProjectRepository;\n connection: ProjectSourceControlConnection;\n installation: SourceControlInstallation;\n repository: SourceControlRepository;\n host: string;\n orgId: string;\n userId: string;\n}\n\nfunction normalizePath(value: string): string {\n return value.replace(/^\\/+|\\/+$/g, '').toLowerCase();\n}\n\nexport function parseMergeRequestUrl(url: string): { host: string; projectPath: string; iid: number } | undefined {\n const match = url.trim().match(MERGE_REQUEST_URL);\n if (!match) return undefined;\n const iid = Number(match[3]);\n if (!Number.isSafeInteger(iid) || iid < 1) return undefined;\n return { host: normalizeGitLabHost(match[1]!), projectPath: match[2]!.replace(/\\/+$/, ''), iid };\n}\n\nfunction parseMergeRequest(value: number | string, target: SessionTarget): number {\n if (typeof value === 'number') return value;\n if (/^\\d+$/.test(value)) return Number(value);\n const parsed = parseMergeRequestUrl(value);\n if (\n !parsed ||\n parsed.host !== target.host ||\n normalizePath(parsed.projectPath) !== normalizePath(target.repository.slug)\n ) {\n throw new Error(`Merge request must belong to ${target.host}/${target.repository.slug}.`);\n }\n return parsed.iid;\n}\n\n/**\n * Whether the current request comes from a session that merge-request\n * subscriptions can ever apply to: an authenticated org user on a factory\n * session with an active thread. Mirrors the GitHub gate; whether the\n * session's repository is GitLab-linked is only known after a storage read,\n * so the entry points verify that and fail loudly for the explicit tools.\n */\nfunction isRepositorySession(requestContext: RequestContext): boolean {\n const context = requestContext.get('controller') as AgentControllerRequestContext<RepositorySessionState> | undefined;\n return Boolean(\n context?.threadId &&\n context.getState().factoryProjectId &&\n sessionOrgId(requestContext) &&\n sessionUserId(requestContext),\n );\n}\n\nasync function resolveSessionTarget(\n requestContext: RequestContext,\n gitlab: GitLabIntegrationBase,\n): Promise<SessionTarget | undefined> {\n const context = requestContext.get('controller') as AgentControllerRequestContext<RepositorySessionState> | undefined;\n const orgId = sessionOrgId(requestContext);\n const userId = sessionUserId(requestContext);\n if (!context || !context.threadId || !context.getState().factoryProjectId || !orgId || !userId) {\n throw new Error('GitLab subscriptions require an authenticated repository session with an active thread.');\n }\n const storage = gitlab.sourceControlStorage;\n if (!storage) throw new Error('GitLab source control is unavailable.');\n\n // Merge requests stay bound to the link the session is filed under: the\n // controller state names it for dispatched sessions, the session row for\n // the rest. A session filed under no link cannot subscribe.\n const projectRepositoryId =\n context.getState().projectRepositoryId ??\n (await storage.sessions.getBySessionId(context.resourceId))?.projectRepositoryId;\n if (!projectRepositoryId) return undefined;\n\n // The handle is scoped to GitLab rows, so a GitHub-linked repository is\n // simply absent here rather than misidentified.\n const projectRepository = await storage.projectRepositories.get({ orgId, id: projectRepositoryId });\n if (!projectRepository) return undefined;\n const connection = await storage.connections.get({ orgId, id: projectRepository.connectionId });\n if (!connection || connection.integrationId !== 'gitlab') return undefined;\n const repository = await storage.repositories.get({ orgId, id: projectRepository.repositoryId });\n if (!repository) throw new Error('Repository not found for this organization.');\n const installation = await storage.installations.get({ orgId, id: connection.installationId });\n if (!installation) throw new Error('Source-control installation not found for this organization.');\n const host = installation.providerMetadata.host;\n if (typeof host !== 'string' || !host) throw new Error('GitLab installation is missing its instance host.');\n return {\n context,\n projectRepository,\n connection,\n installation,\n repository,\n host: normalizeGitLabHost(host),\n orgId,\n userId,\n };\n}\n\nasync function requireGitLabSessionTarget(\n requestContext: RequestContext,\n gitlab: GitLabIntegrationBase,\n): Promise<SessionTarget> {\n const target = await resolveSessionTarget(requestContext, gitlab);\n if (!target) throw new Error('The active session is not backed by a GitLab repository.');\n return target;\n}\n\nasync function verifyMergeRequest(target: SessionTarget, iid: number, gitlab: GitLabIntegrationBase): Promise<void> {\n const repositoryTarget = await gitlab.versionControl.getRepositoryTarget({\n orgId: target.orgId,\n repositoryId: target.repository.id,\n });\n const mergeRequest = await gitlab.versionControl.getPullRequest({ ...repositoryTarget, pullRequestId: String(iid) });\n if (!mergeRequest) throw new Error(`Merge request !${iid} was not found in ${target.repository.slug}.`);\n const parsed = parseMergeRequestUrl(mergeRequest.url);\n if (\n parsed &&\n (parsed.host !== target.host || normalizePath(parsed.projectPath) !== normalizePath(target.repository.slug))\n ) {\n throw new Error('Merge request project does not match the active project repository.');\n }\n}\n\nfunction subscriptionInput(target: SessionTarget, iid: number) {\n return {\n orgId: target.orgId,\n host: target.host,\n projectId: target.repository.externalId,\n projectPath: target.repository.slug,\n projectRepositoryId: target.projectRepository.id,\n installationExternalId: target.installation.externalId,\n changeRequestId: String(iid),\n sessionId: target.context.session.id,\n ownerId: target.context.session.ownerId,\n resourceId: target.connection.factoryProjectId,\n threadId: target.context.threadId!,\n sessionScope: target.context.scope,\n source: 'explicit-tool' as GitLabSignalSubscriptionSource,\n subscribedByUserId: target.userId,\n };\n}\n\nexport async function subscribeCurrentSessionToMergeRequest(\n requestContext: RequestContext,\n mergeRequest: number | string,\n source: GitLabSignalSubscriptionSource,\n gitlab: GitLabIntegrationBase,\n): Promise<number | undefined> {\n // The auto path observes every successful change-request creation in every\n // session, including GitHub-project sessions where a GitLab subscription can\n // never apply. Skip silently there; only the explicit tool should surface\n // \"this session cannot subscribe\" as an error.\n if (source === 'auto-create-change-request') {\n if (!isRepositorySession(requestContext)) return undefined;\n const target = await resolveSessionTarget(requestContext, gitlab);\n if (!target) return undefined;\n const iid = parseMergeRequest(mergeRequest, target);\n await verifyMergeRequest(target, iid, gitlab);\n await subscribeToMergeRequest({ ...subscriptionInput(target, iid), source }, gitlab.integrationStorage);\n return iid;\n }\n const target = await requireGitLabSessionTarget(requestContext, gitlab);\n const iid = parseMergeRequest(mergeRequest, target);\n await verifyMergeRequest(target, iid, gitlab);\n await subscribeToMergeRequest({ ...subscriptionInput(target, iid), source }, gitlab.integrationStorage);\n return iid;\n}\n\nexport async function unsubscribeCurrentSessionFromMergeRequest(\n requestContext: RequestContext,\n mergeRequest: number | string,\n gitlab: GitLabIntegrationBase,\n): Promise<number> {\n const target = await requireGitLabSessionTarget(requestContext, gitlab);\n const iid = parseMergeRequest(mergeRequest, target);\n await unsubscribeFromMergeRequest(subscriptionInput(target, iid), gitlab.integrationStorage);\n return iid;\n}\n\nexport function createGitLabSubscriptionTools(requestContext: RequestContext, gitlab: GitLabIntegrationBase) {\n if (!isRepositorySession(requestContext)) return {};\n\n return {\n gitlab_subscribe_mr: createTool({\n id: 'gitlab_subscribe_mr',\n description:\n 'Subscribe this thread to GitLab merge request activity. You usually do not need this tool: successful source_control_create_change_request calls subscribe automatically. Use it for an existing MR or to recover when automatic subscription did not occur. Closed or merged MRs are unsubscribed automatically. Accepts an MR IID or canonical URL for the active project.',\n inputSchema: mergeRequestInputSchema,\n execute: async ({ mergeRequest }) => {\n const iid = await subscribeCurrentSessionToMergeRequest(requestContext, mergeRequest, 'explicit-tool', gitlab);\n return { subscribed: true, mergeRequestIid: iid };\n },\n }),\n gitlab_unsubscribe_mr: createTool({\n id: 'gitlab_unsubscribe_mr',\n description:\n 'Manually unsubscribe this thread from GitLab merge request activity. You usually do not need this tool because closed or merged MRs are unsubscribed automatically. Use it to stop notifications before then. Accepts an MR IID or canonical URL for the active project.',\n inputSchema: mergeRequestInputSchema,\n execute: async ({ mergeRequest }) => {\n const iid = await unsubscribeCurrentSessionFromMergeRequest(requestContext, mergeRequest, gitlab);\n return { subscribed: false, mergeRequestIid: iid };\n },\n }),\n };\n}\n\n/**\n * The merge request URL a successful provider-neutral change-request creation\n * reported, when that URL is a GitLab one. Anything else is not ours to observe.\n */\nexport function parseCreatedMergeRequest(context: {\n toolName: string;\n input: unknown;\n output?: unknown;\n error?: unknown;\n}): string | undefined {\n if (context.toolName !== 'source_control_create_change_request' || context.error) return undefined;\n const url = (context.output as { url?: unknown } | undefined)?.url;\n if (typeof url !== 'string' || !parseMergeRequestUrl(url)) return undefined;\n return url.trim().replace(/\\/$/, '');\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { IncidentioApiError } from "./api.js";
2
2
  import { scopeSourceIdsToProject } from "./routes.js";
3
- import { createTool } from "@mastra/core/tools";
4
3
  import { z } from "zod";
4
+ import { createTool } from "@mastra/core/tools";
5
5
  //#region src/integrations/incidentio/agent-tools.ts
6
6
  /**
7
7
  * Prompt-injection boundary: follow-up titles and descriptions are authored by
@@ -1,7 +1,7 @@
1
1
  import { JiraApiError } from "./api.js";
2
2
  import { DEPLOYMENT_CONNECTION } from "./integration.js";
3
- import { createTool } from "@mastra/core/tools";
4
3
  import { z } from "zod";
4
+ import { createTool } from "@mastra/core/tools";
5
5
  //#region src/integrations/jira/agent-tools.ts
6
6
  /**
7
7
  * Prompt-injection boundary: Jira descriptions and comments are authored by
@@ -1,6 +1,6 @@
1
1
  import { LinearReauthRequiredError } from "./integration.js";
2
- import { createTool } from "@mastra/core/tools";
3
2
  import { z } from "zod";
3
+ import { createTool } from "@mastra/core/tools";
4
4
  //#region src/integrations/linear/agent-tools.ts
5
5
  function createLinearGetIssueTool(linear, orgId) {
6
6
  return createTool({
@@ -1 +1 @@
1
- {"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../../../../src/integrations/platform/github/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;AAKxD,OAAO,KAAK,EAEV,MAAM,EAIP,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAwBV,cAAc,EACf,MAAM,0CAA0C,CAAC;AAClD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,+CAA+C,CAAC;AAC9F,OAAO,KAAK,EAEV,0BAA0B,EAC3B,MAAM,iDAAiD,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC9F,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAE3F,OAAO,KAAK,EACV,iBAAiB,EACjB,0BAA0B,EAC1B,8BAA8B,EAC9B,+BAA+B,EAC/B,WAAW,EACZ,MAAM,6BAA6B,CAAC;AAKrC,OAAO,KAAK,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAO5F,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAyJ/E,qBAAa,yBAA0B,YAAW,kBAAkB;;IAClE,QAAQ,CAAC,EAAE,YAAY;IAGvB,IAAI,KAAK,IAAI,gBAAgB,CAE5B;IAID;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC;;;OAGG;IACH,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAqB3C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAsHrB;IAEF,QAAQ,CAAC,cAAc,EAAE,cAAc,CAsIrC;gBAGA,OAAO,GAAE;QACP,uFAAuF;QACvF,KAAK,CAAC,EAAE,mBAAmB,CAAC;QAC5B,sEAAsE;QACtE,IAAI,CAAC,EAAE,MAAM,CAAC;KACV;IAoCR,kEAAkE;IAClE,IAAI,IAAI,IAAI,MAAM,GAAG,SAAS,CAE7B;IAED,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO;IAIjE,IAAI,OAAO,IAAI,0BAA0B,CAGxC;IAED,IAAI,oBAAoB,IAAI,0BAA0B,CAErD;IAED,IAAI,kBAAkB,IAAI,yBAAyB,CAKlD;IAuBD,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE;QAAE,OAAO,EAAE,wBAAwB,CAAA;KAAE,GAAG,IAAI;IAWpE,MAAM,CAAC,GAAG,EAAE,kBAAkB,GAAG,QAAQ,EAAE;IAiL3C,OAAO,CAAC,GAAG,EAAE,kBAAkB,GAAG,YAAY,EAAE;IA2ChD;;;;OAIG;IACG,qBAAqB,CAAC,KAAK,EAAE;QACjC,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;KAChB,GAAG,OAAO,CAAC,yBAAyB,GAAG,SAAS,CAAC;IAkDlD;;;;OAIG;IACG,eAAe,CAAC,KAAK,EAAE;QAC3B,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;KAChB,GAAG,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC;IA0CtC,mBAAmB,CAAC,KAAK,EAAE;QAC/B,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC,KAAK,CAAC,mBAAmB,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IA0BtD,0BAA0B,CAAC,KAAK,EAAE,8BAA8B,GAAG,OAAO,CAAC,+BAA+B,CAAC;IAmCjH,YAAY,CAAC,EAAE,cAAc,EAAE,EAAE;QAAE,cAAc,EAAE,cAAc,CAAA;KAAE,GAAG,gBAAgB;IAIhF,gBAAgB,CAAC,EACrB,WAAW,EACX,cAAc,GACf,EAAE,UAAU,CAAC,WAAW,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAWrF,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAuBhC,mCAAmC,CACvC,eAAe,EAAE,MAAM,EACvB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC;IAsC5C,qBAAqB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IA0BrE,qBAAqB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAa9D,cAAc,CAClB,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EAAE,GACf,OAAO,CAAC,MAAM,EAAE,CAAC;IASd,gBAAgB,CAAC,eAAe,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASpH,sBAAsB,CAAC,eAAe,EAAE,MAAM,GAAG,UAAU,CAAC,iBAAiB,CAAC,wBAAwB,CAAC,CAAC;CAyZzG"}
1
+ {"version":3,"file":"integration.d.ts","sourceRoot":"","sources":["../../../../src/integrations/platform/github/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;AAKxD,OAAO,KAAK,EAEV,MAAM,EAIP,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAwBV,cAAc,EACf,MAAM,0CAA0C,CAAC;AAClD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,+CAA+C,CAAC;AAC9F,OAAO,KAAK,EAEV,0BAA0B,EAC3B,MAAM,iDAAiD,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC9F,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAE3F,OAAO,KAAK,EACV,iBAAiB,EACjB,0BAA0B,EAC1B,8BAA8B,EAC9B,+BAA+B,EAC/B,WAAW,EACZ,MAAM,6BAA6B,CAAC;AAKrC,OAAO,KAAK,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAO5F,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AA4J/E,qBAAa,yBAA0B,YAAW,kBAAkB;;IAClE,QAAQ,CAAC,EAAE,YAAY;IAGvB,IAAI,KAAK,IAAI,gBAAgB,CAE5B;IAID;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC;;;OAGG;IACH,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAqB3C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAsHrB;IAEF,QAAQ,CAAC,cAAc,EAAE,cAAc,CA4KrC;gBAGA,OAAO,GAAE;QACP,uFAAuF;QACvF,KAAK,CAAC,EAAE,mBAAmB,CAAC;QAC5B,sEAAsE;QACtE,IAAI,CAAC,EAAE,MAAM,CAAC;KACV;IAoCR,kEAAkE;IAClE,IAAI,IAAI,IAAI,MAAM,GAAG,SAAS,CAE7B;IAED,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO;IAIjE,IAAI,OAAO,IAAI,0BAA0B,CAGxC;IAED,IAAI,oBAAoB,IAAI,0BAA0B,CAErD;IAED,IAAI,kBAAkB,IAAI,yBAAyB,CAKlD;IAuBD,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE;QAAE,OAAO,EAAE,wBAAwB,CAAA;KAAE,GAAG,IAAI;IAWpE,MAAM,CAAC,GAAG,EAAE,kBAAkB,GAAG,QAAQ,EAAE;IAiL3C,OAAO,CAAC,GAAG,EAAE,kBAAkB,GAAG,YAAY,EAAE;IA2ChD;;;;OAIG;IACG,qBAAqB,CAAC,KAAK,EAAE;QACjC,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;KAChB,GAAG,OAAO,CAAC,yBAAyB,GAAG,SAAS,CAAC;IAkDlD;;;;OAIG;IACG,eAAe,CAAC,KAAK,EAAE;QAC3B,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;KAChB,GAAG,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC;IA0CtC,mBAAmB,CAAC,KAAK,EAAE;QAC/B,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC,KAAK,CAAC,mBAAmB,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IA0BtD,0BAA0B,CAAC,KAAK,EAAE,8BAA8B,GAAG,OAAO,CAAC,+BAA+B,CAAC;IAmCjH,YAAY,CAAC,EAAE,cAAc,EAAE,EAAE;QAAE,cAAc,EAAE,cAAc,CAAA;KAAE,GAAG,gBAAgB;IAIhF,gBAAgB,CAAC,EACrB,WAAW,EACX,cAAc,GACf,EAAE,UAAU,CAAC,WAAW,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAWrF,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAuBhC,mCAAmC,CACvC,eAAe,EAAE,MAAM,EACvB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC;IAsC5C,qBAAqB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IA0BrE,qBAAqB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAa9D,cAAc,CAClB,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EAAE,GACf,OAAO,CAAC,MAAM,EAAE,CAAC;IASd,gBAAgB,CAAC,eAAe,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASpH,sBAAsB,CAAC,eAAe,EAAE,MAAM,GAAG,UAAU,CAAC,iBAAiB,CAAC,wBAAwB,CAAC,CAAC;CAyZzG"}
@@ -64,6 +64,8 @@ const REPOSITORY_TOKEN_PERMISSIONS = {
64
64
  issues: "write",
65
65
  pull_requests: "write"
66
66
  };
67
+ /** The Platform mints one installation token for at most this many named repositories. */
68
+ const MAX_REPOSITORIES_PER_TOKEN = 10;
67
69
  function loose(c) {
68
70
  return c;
69
71
  }
@@ -327,6 +329,44 @@ var PlatformGithubIntegration = class {
327
329
  return access;
328
330
  }
329
331
  },
332
+ getRepositoriesAccess: async ({ orgId, repositoryIds }) => {
333
+ const ids = [...new Set(repositoryIds)];
334
+ if (ids.length === 0 || ids.length > MAX_REPOSITORIES_PER_TOKEN) return void 0;
335
+ const cacheKey = `${orgId}:${[...ids].sort().join(",")}`;
336
+ const cached = this.#repositoryAccessCache.get(cacheKey);
337
+ if (cached && cached.expiresAt > Date.now()) return cached.access;
338
+ this.#repositoryAccessCache.delete(cacheKey);
339
+ const repositories = await Promise.all(ids.map((id) => this.storage.repositories.get({
340
+ orgId,
341
+ id
342
+ })));
343
+ if (repositories.some((repository) => !repository)) throw new Error("Version-control repository not found.");
344
+ const found = repositories;
345
+ if (new Set(found.map((repository) => repository.installationId)).size !== 1) return void 0;
346
+ const installation = await this.storage.installations.get({
347
+ orgId,
348
+ id: found[0].installationId
349
+ });
350
+ if (!installation) throw new Error("Version-control installation not found.");
351
+ const installationId = parsePositiveInteger(installation.externalId);
352
+ if (installationId === null) throw new Error("GitHub installation id is invalid.");
353
+ const token = await this.#client.request("POST", `${API_PREFIX}/github-app/installations/${installationId}/token`, {
354
+ repositories: found.map((repository) => splitRepository(repository.slug).repo),
355
+ permissions: REPOSITORY_TOKEN_PERMISSIONS
356
+ });
357
+ const access = {
358
+ cloneUrl: `https://github.com/${found[0].slug}.git`,
359
+ authorization: {
360
+ scheme: "bearer",
361
+ token: token.token
362
+ }
363
+ };
364
+ setBounded(this.#repositoryAccessCache, cacheKey, {
365
+ access,
366
+ expiresAt: Date.now() + REPOSITORY_ACCESS_CACHE_TTL_MS
367
+ });
368
+ return access;
369
+ },
330
370
  listPullRequests: (input) => this.#listPullRequests(input),
331
371
  getPullRequest: (input) => this.#getPullRequest(input),
332
372
  createPullRequest: (input) => this.#createPullRequest(input),
@@ -775,7 +815,7 @@ var PlatformGithubIntegration = class {
775
815
  }
776
816
  async mintInstallationToken(installationId) {
777
817
  const repositories = await this.listInstallationRepos(installationId);
778
- if (repositories.length === 0 || repositories.length > 10) throw new Error("Platform GitHub token minting requires between one and ten installation repositories.");
818
+ if (repositories.length === 0 || repositories.length > MAX_REPOSITORIES_PER_TOKEN) throw new Error("Platform GitHub token minting requires between one and ten installation repositories.");
779
819
  return (await this.#client.request("POST", `${API_PREFIX}/github-app/installations/${installationId}/token`, {
780
820
  repositories: repositories.map((repository) => repository.name),
781
821
  permissions: REPOSITORY_TOKEN_PERMISSIONS
@@ -791,7 +831,11 @@ var PlatformGithubIntegration = class {
791
831
  }
792
832
  getInstallationOctokit(_installationId) {
793
833
  return { pulls: { get: async ({ owner, repo, pull_number }) => {
794
- return { data: { base: { repo: { id: (await this.#client.request("GET", repositoryPath(`${owner}/${repo}`, `pulls/${pull_number}`))).base.repo.id } } } };
834
+ const data = await this.#client.request("GET", repositoryPath(`${owner}/${repo}`, `pulls/${pull_number}`));
835
+ return { data: {
836
+ base: { repo: { id: data.base.repo.id } },
837
+ head: { ref: data.head.ref }
838
+ } };
795
839
  } } };
796
840
  }
797
841
  async #listIssues(connection, sourceId, page, labels) {