@mastra/factory 0.15.0 → 0.16.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/dist/boards/index.d.ts +1 -1
- package/dist/boards/index.d.ts.map +1 -1
- package/dist/boards/index.js +2 -2
- package/dist/boards/index.js.map +1 -1
- package/dist/boards/review.d.ts.map +1 -1
- package/dist/boards/review.js +4 -1
- package/dist/boards/review.js.map +1 -1
- package/dist/boards/semantics.d.ts +7 -0
- package/dist/boards/semantics.d.ts.map +1 -1
- package/dist/boards/semantics.js +15 -1
- package/dist/boards/semantics.js.map +1 -1
- package/dist/boards/transition-policy.d.ts +4 -0
- package/dist/boards/transition-policy.d.ts.map +1 -1
- package/dist/boards/transition-policy.js.map +1 -1
- package/dist/boards/work-transition-policy.d.ts.map +1 -1
- package/dist/boards/work-transition-policy.js +6 -1
- package/dist/boards/work-transition-policy.js.map +1 -1
- package/dist/boards/work.d.ts.map +1 -1
- package/dist/boards/work.js +37 -3
- package/dist/boards/work.js.map +1 -1
- package/dist/capabilities/intake.d.ts +4 -0
- package/dist/capabilities/intake.d.ts.map +1 -1
- package/dist/factory.d.ts +6 -3
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +66 -18
- package/dist/factory.js.map +1 -1
- package/dist/integrations/base.d.ts +6 -2
- package/dist/integrations/base.d.ts.map +1 -1
- package/dist/integrations/incidentio/agent-tools.d.ts +49 -0
- package/dist/integrations/incidentio/agent-tools.d.ts.map +1 -0
- package/dist/integrations/incidentio/agent-tools.js +90 -0
- package/dist/integrations/incidentio/agent-tools.js.map +1 -0
- package/dist/integrations/incidentio/claim.d.ts +8 -0
- package/dist/integrations/incidentio/claim.d.ts.map +1 -0
- package/dist/integrations/incidentio/claim.js +14 -0
- package/dist/integrations/incidentio/claim.js.map +1 -0
- package/dist/integrations/incidentio/default-rules.d.ts +46 -0
- package/dist/integrations/incidentio/default-rules.d.ts.map +1 -0
- package/dist/integrations/incidentio/default-rules.js +66 -0
- package/dist/integrations/incidentio/default-rules.js.map +1 -0
- package/dist/integrations/incidentio/integration.d.ts +48 -2
- package/dist/integrations/incidentio/integration.d.ts.map +1 -1
- package/dist/integrations/incidentio/integration.js +88 -2
- package/dist/integrations/incidentio/integration.js.map +1 -1
- package/dist/integrations/incidentio/issue-reconciler.d.ts +2 -0
- package/dist/integrations/incidentio/issue-reconciler.d.ts.map +1 -1
- package/dist/integrations/incidentio/issue-reconciler.js +38 -2
- package/dist/integrations/incidentio/issue-reconciler.js.map +1 -1
- package/dist/integrations/incidentio/routes.d.ts +71 -0
- package/dist/integrations/incidentio/routes.d.ts.map +1 -0
- package/dist/integrations/incidentio/routes.js +245 -0
- package/dist/integrations/incidentio/routes.js.map +1 -0
- package/dist/integrations/incidentio/rules.d.ts +55 -0
- package/dist/integrations/incidentio/rules.d.ts.map +1 -0
- package/dist/integrations/incidentio/rules.js +175 -0
- package/dist/integrations/incidentio/rules.js.map +1 -0
- package/dist/integrations/jira/adf.d.ts +26 -0
- package/dist/integrations/jira/adf.d.ts.map +1 -0
- package/dist/integrations/jira/adf.js +73 -0
- package/dist/integrations/jira/adf.js.map +1 -0
- package/dist/integrations/jira/agent-tools.d.ts +45 -0
- package/dist/integrations/jira/agent-tools.d.ts.map +1 -0
- package/dist/integrations/jira/agent-tools.js +87 -0
- package/dist/integrations/jira/agent-tools.js.map +1 -0
- package/dist/integrations/jira/api.d.ts +157 -0
- package/dist/integrations/jira/api.d.ts.map +1 -0
- package/dist/integrations/jira/api.js +141 -0
- package/dist/integrations/jira/api.js.map +1 -0
- package/dist/integrations/jira/claim.d.ts +9 -0
- package/dist/integrations/jira/claim.d.ts.map +1 -0
- package/dist/integrations/jira/claim.js +15 -0
- package/dist/integrations/jira/claim.js.map +1 -0
- package/dist/integrations/jira/default-rules.d.ts +47 -0
- package/dist/integrations/jira/default-rules.d.ts.map +1 -0
- package/dist/integrations/jira/default-rules.js +67 -0
- package/dist/integrations/jira/default-rules.js.map +1 -0
- package/dist/integrations/jira/integration.d.ts +114 -0
- package/dist/integrations/jira/integration.d.ts.map +1 -0
- package/dist/integrations/jira/integration.js +401 -0
- package/dist/integrations/jira/integration.js.map +1 -0
- package/dist/integrations/jira/issue-reconciler.d.ts +10 -0
- package/dist/integrations/jira/issue-reconciler.d.ts.map +1 -0
- package/dist/integrations/jira/issue-reconciler.js +70 -0
- package/dist/integrations/jira/issue-reconciler.js.map +1 -0
- package/dist/integrations/jira/reconciliation-config.d.ts +3 -0
- package/dist/integrations/jira/reconciliation-config.d.ts.map +1 -0
- package/dist/integrations/jira/reconciliation-config.js +17 -0
- package/dist/integrations/jira/reconciliation-config.js.map +1 -0
- package/dist/integrations/jira/routes.d.ts +54 -0
- package/dist/integrations/jira/routes.d.ts.map +1 -0
- package/dist/integrations/jira/routes.js +260 -0
- package/dist/integrations/jira/routes.js.map +1 -0
- package/dist/integrations/jira/rules.d.ts +57 -0
- package/dist/integrations/jira/rules.d.ts.map +1 -0
- package/dist/integrations/jira/rules.js +175 -0
- package/dist/integrations/jira/rules.js.map +1 -0
- package/dist/integrations/linear/claim.d.ts +8 -0
- package/dist/integrations/linear/claim.d.ts.map +1 -0
- package/dist/integrations/linear/claim.js +14 -0
- package/dist/integrations/linear/claim.js.map +1 -0
- package/dist/integrations/linear/default-rules.d.ts +1 -0
- package/dist/integrations/linear/default-rules.d.ts.map +1 -1
- package/dist/integrations/linear/default-rules.js +2 -0
- package/dist/integrations/linear/default-rules.js.map +1 -1
- package/dist/integrations/linear/integration.d.ts +24 -6
- package/dist/integrations/linear/integration.d.ts.map +1 -1
- package/dist/integrations/linear/integration.js +257 -37
- package/dist/integrations/linear/integration.js.map +1 -1
- package/dist/integrations/linear/routes.d.ts +10 -0
- package/dist/integrations/linear/routes.d.ts.map +1 -1
- package/dist/integrations/linear/routes.js +74 -12
- package/dist/integrations/linear/routes.js.map +1 -1
- package/dist/integrations/linear/rules.d.ts +1 -1
- package/dist/integrations/linear/rules.d.ts.map +1 -1
- package/dist/integrations/linear/rules.js +27 -2
- package/dist/integrations/linear/rules.js.map +1 -1
- package/dist/integrations/platform/connect/routes.d.ts +39 -0
- package/dist/integrations/platform/connect/routes.d.ts.map +1 -0
- package/dist/integrations/platform/connect/routes.js +129 -0
- package/dist/integrations/platform/connect/routes.js.map +1 -0
- package/dist/integrations/platform/github/event-worker.js +1 -1
- package/dist/integrations/platform/github/integration.js +1 -1
- package/dist/integrations/platform/incidentio/integration.d.ts +61 -4
- package/dist/integrations/platform/incidentio/integration.d.ts.map +1 -1
- package/dist/integrations/platform/incidentio/integration.js +371 -22
- package/dist/integrations/platform/incidentio/integration.js.map +1 -1
- package/dist/integrations/platform/jira/agent-tools.d.ts +36 -0
- package/dist/integrations/platform/jira/agent-tools.d.ts.map +1 -0
- package/dist/integrations/platform/jira/agent-tools.js +85 -0
- package/dist/integrations/platform/jira/agent-tools.js.map +1 -0
- package/dist/integrations/platform/jira/integration.d.ts +65 -0
- package/dist/integrations/platform/jira/integration.d.ts.map +1 -0
- package/dist/integrations/platform/jira/integration.js +540 -0
- package/dist/integrations/platform/jira/integration.js.map +1 -0
- package/dist/integrations/platform/jira/routes.d.ts +55 -0
- package/dist/integrations/platform/jira/routes.d.ts.map +1 -0
- package/dist/integrations/platform/jira/routes.js +274 -0
- package/dist/integrations/platform/jira/routes.js.map +1 -0
- package/dist/integrations/platform/linear/integration.d.ts +34 -1
- package/dist/integrations/platform/linear/integration.d.ts.map +1 -1
- package/dist/integrations/platform/linear/integration.js +271 -48
- package/dist/integrations/platform/linear/integration.js.map +1 -1
- package/dist/routes/intake.d.ts.map +1 -1
- package/dist/routes/intake.js +15 -5
- package/dist/routes/intake.js.map +1 -1
- package/dist/routes/oauth.js +2 -5
- package/dist/routes/oauth.js.map +1 -1
- package/dist/routes/surface.d.ts.map +1 -1
- package/dist/routes/surface.js +24 -4
- package/dist/routes/surface.js.map +1 -1
- package/dist/rules/dispatch-errors.d.ts.map +1 -1
- package/dist/rules/dispatch-errors.js +8 -0
- package/dist/rules/dispatch-errors.js.map +1 -1
- package/dist/rules/dispatcher.d.ts +1 -0
- package/dist/rules/dispatcher.d.ts.map +1 -1
- package/dist/rules/dispatcher.js +180 -106
- package/dist/rules/dispatcher.js.map +1 -1
- package/dist/rules/index.d.ts +2 -2
- package/dist/rules/index.d.ts.map +1 -1
- package/dist/rules/index.js +2 -2
- package/dist/rules/start-coordinator.d.ts.map +1 -1
- package/dist/rules/start-coordinator.js +4 -1
- package/dist/rules/start-coordinator.js.map +1 -1
- package/dist/rules/terminal-cleanup.d.ts +14 -1
- package/dist/rules/terminal-cleanup.d.ts.map +1 -1
- package/dist/rules/terminal-cleanup.js +20 -0
- package/dist/rules/terminal-cleanup.js.map +1 -1
- package/dist/rules/tools.d.ts +2 -0
- package/dist/rules/tools.d.ts.map +1 -1
- package/dist/rules/tools.js +30 -2
- package/dist/rules/tools.js.map +1 -1
- package/dist/rules/transition-service.d.ts +13 -0
- package/dist/rules/transition-service.d.ts.map +1 -1
- package/dist/rules/transition-service.js +11 -2
- package/dist/rules/transition-service.js.map +1 -1
- package/dist/rules/types.d.ts +72 -3
- package/dist/rules/types.d.ts.map +1 -1
- package/dist/rules/types.js +9 -1
- package/dist/rules/types.js.map +1 -1
- package/dist/rules/validation.d.ts.map +1 -1
- package/dist/rules/validation.js +13 -2
- package/dist/rules/validation.js.map +1 -1
- package/dist/session/run-audit.d.ts +9 -0
- package/dist/session/run-audit.d.ts.map +1 -1
- package/dist/session/run-audit.js +37 -6
- package/dist/session/run-audit.js.map +1 -1
- package/dist/skills/service.d.ts +12 -0
- package/dist/skills/service.d.ts.map +1 -1
- package/dist/skills/service.js +27 -1
- package/dist/skills/service.js.map +1 -1
- package/dist/storage/domains/intake/base.d.ts +11 -8
- package/dist/storage/domains/intake/base.d.ts.map +1 -1
- package/dist/storage/domains/intake/base.js +69 -24
- package/dist/storage/domains/intake/base.js.map +1 -1
- package/dist/storage/domains/work-items/base.d.ts +41 -2
- package/dist/storage/domains/work-items/base.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.js +159 -12
- package/dist/storage/domains/work-items/base.js.map +1 -1
- package/dist/supervisor/session-messaging.d.ts +23 -0
- package/dist/supervisor/session-messaging.d.ts.map +1 -0
- package/dist/supervisor/session-messaging.js +15 -0
- package/dist/supervisor/session-messaging.js.map +1 -0
- package/dist/supervisor/write-tools.d.ts +2 -1
- package/dist/supervisor/write-tools.d.ts.map +1 -1
- package/dist/supervisor/write-tools.js +11 -7
- package/dist/supervisor/write-tools.js.map +1 -1
- package/dist/work-item-branch.d.ts +1 -1
- package/dist/work-item-branch.d.ts.map +1 -1
- package/dist/work-item-branch.js +4 -2
- package/dist/work-item-branch.js.map +1 -1
- package/package.json +11 -11
package/dist/routes/oauth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth.js","names":[],"sources":["../../src/routes/oauth.ts"],"sourcesContent":["/**\n * Web OAuth sign-in routes for model providers (Settings › Providers).\n *\n * Wraps the SDK's step-based OAuth primitives (start/complete for Anthropic's\n * paste-code PKCE flow, start/poll for the Codex/Copilot/xAI device flows) in\n * HTTP routes. Flow state lives in login sessions — the `model-credentials`\n * domain's `oauth_login_sessions` table in tenant mode (any replica can\n * complete/poll), an in-memory store in local mode — so a flow can span\n * requests. Completed credentials are **user-scoped by default**; org admins\n * can start a flow with `{ scope: 'org' }` to share the credential with the\n * whole org. Local mode writes to the file-backed `AuthStorage`.\n *\n * Tokens never leave the server; responses only carry flow metadata (URLs,\n * user codes, poll delays).\n */\n\nimport { randomUUID } from 'node:crypto';\n\nimport { nextPollDelayMs } from '@mastra/code-sdk/auth/device-code';\nimport { completeAnthropicLogin, startAnthropicLogin } from '@mastra/code-sdk/auth/providers/anthropic';\nimport {\n copilotNextPollDelayMs,\n pollGitHubCopilotDeviceLogin,\n startGitHubCopilotDeviceLogin,\n} from '@mastra/code-sdk/auth/providers/github-copilot';\nimport type { CopilotDeviceLoginPending } from '@mastra/code-sdk/auth/providers/github-copilot';\nimport { pollCodexDeviceLogin, startCodexDeviceLogin } from '@mastra/code-sdk/auth/providers/openai-codex';\nimport type { CodexDeviceLoginPending } from '@mastra/code-sdk/auth/providers/openai-codex';\nimport { pollXAIDeviceLogin, startXAIDeviceLogin } from '@mastra/code-sdk/auth/providers/xai';\nimport type { XAIDeviceLoginPending } from '@mastra/code-sdk/auth/providers/xai';\nimport type { AuthStorage } from '@mastra/code-sdk/auth/storage';\nimport type { OAuthCredentials } from '@mastra/code-sdk/auth/types';\nimport type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { Context } from 'hono';\n\nimport { ModelCredentialsStorage } from '../storage/domains/credentials/base.js';\nimport type { LoginCredentialScope, LoginSessionKind, LoginSessionRow } from '../storage/domains/credentials/base.js';\nimport type { MemorySettingsStorage } from '../storage/domains/memory-settings/base.js';\nimport { seedPersonalOmDefaults } from './om-seed.js';\nimport { getAuthProviderId, resolveCredentialContext } from './provider-credentials.js';\nimport type { CredentialContext } from './provider-credentials.js';\nimport { Route } from './route.js';\nimport type { RouteDependencies } from './route.js';\n\n/** Lifetime of a paste-code session (Anthropic gives no explicit expiry). */\nconst PASTE_CODE_TTL_MS = 10 * 60 * 1000;\n\ninterface OAuthFlowStart {\n url: string;\n userCode?: string;\n instructions: string;\n /** ms epoch after which the flow expires. */\n expiresAt: number;\n /** Delay before the first upstream poll (device-code flows only). */\n nextPollMs?: number;\n /** Serializable flow state persisted in the login session. */\n pending: Record<string, unknown>;\n}\n\ntype OAuthFlowPoll =\n | { status: 'complete'; credentials: OAuthCredentials }\n | { status: 'pending'; nextPollMs: number; pending?: Record<string, unknown> }\n | { status: 'failed'; error: string };\n\ninterface OAuthFlow {\n kind: LoginSessionKind;\n start(): Promise<OAuthFlowStart>;\n /** Paste-code flows: exchange the pasted code for credentials. Throws on bad input. */\n complete?(pending: Record<string, unknown>, code: string): Promise<OAuthCredentials>;\n /** Device-code flows: perform exactly one upstream poll. */\n poll?(pending: Record<string, unknown>): Promise<OAuthFlowPoll>;\n}\n\n/** Web OAuth flows keyed by *catalog* provider id (mirrors {@link WEB_OAUTH_FLOW_KINDS}). */\nconst OAUTH_FLOWS: Record<string, OAuthFlow> = {\n anthropic: {\n kind: 'paste-code',\n start: async () => {\n const { url, verifier } = await startAnthropicLogin();\n return {\n url,\n instructions: 'Open the link, authorize, then paste the code shown on the final page.',\n expiresAt: Date.now() + PASTE_CODE_TTL_MS,\n pending: { verifier },\n };\n },\n complete: (pending, code) => completeAnthropicLogin(code, String(pending.verifier ?? '')),\n },\n openai: {\n kind: 'device-code',\n start: async () => {\n const p = await startCodexDeviceLogin();\n return {\n url: p.url,\n userCode: p.userCode,\n instructions: p.instructions,\n expiresAt: p.deadlineAt,\n nextPollMs: p.intervalMs,\n pending: { ...p },\n };\n },\n poll: async pending => {\n const r = await pollCodexDeviceLogin(pending as unknown as CodexDeviceLoginPending);\n if (r.status === 'complete') return { status: 'complete', credentials: r.credentials };\n if (r.status === 'pending') return { status: 'pending', nextPollMs: r.nextPollMs };\n return { status: 'failed', error: r.error };\n },\n },\n 'github-copilot': {\n kind: 'device-code',\n start: async () => {\n const p = await startGitHubCopilotDeviceLogin();\n return {\n url: p.url,\n userCode: p.userCode,\n instructions: p.instructions,\n expiresAt: p.deadlineAt,\n nextPollMs: copilotNextPollDelayMs(p),\n pending: { ...p },\n };\n },\n poll: async pending => {\n const p = pending as unknown as CopilotDeviceLoginPending;\n // Web flows are always started against github.com (no Enterprise input).\n // Never let deserialized session state redirect server-side polling to\n // an arbitrary hostname.\n if (p.domain !== 'github.com' || p.enterpriseDomain !== undefined) {\n return { status: 'failed', error: 'Unsupported GitHub host' };\n }\n const r = await pollGitHubCopilotDeviceLogin(p);\n if (r.status === 'complete') return { status: 'complete', credentials: r.credentials };\n if (r.status === 'pending') return { status: 'pending', nextPollMs: r.nextPollMs, pending: { ...r.pending } };\n return { status: 'failed', error: r.error };\n },\n },\n xai: {\n kind: 'device-code',\n start: async () => {\n const p = await startXAIDeviceLogin();\n return {\n url: p.url,\n userCode: p.userCode,\n instructions: p.instructions,\n expiresAt: p.state.deadlineAt,\n nextPollMs: nextPollDelayMs(p.state),\n pending: { ...p },\n };\n },\n poll: async pending => {\n const r = await pollXAIDeviceLogin(pending as unknown as XAIDeviceLoginPending);\n if (r.status === 'complete') return { status: 'complete', credentials: r.credentials };\n if (r.status === 'pending') return { status: 'pending', nextPollMs: r.nextPollMs, pending: { ...r.pending } };\n return { status: 'failed', error: r.error };\n },\n },\n};\n\nfunction loose(c: unknown): Context {\n return c as Context;\n}\n\n/**\n * Local-mode login sessions. Flows in local mode are single-process, so a\n * process-local libsql `:memory:` database (which already handles TTL\n * cleanup) is sufficient.\n */\nlet localSessionsPromise: Promise<ModelCredentialsStorage> | undefined;\nfunction localSessions(): Promise<ModelCredentialsStorage> {\n localSessionsPromise ??= (async () => {\n const { LibSQLFactoryStorage } = await import('@mastra/libsql');\n const storage = new LibSQLFactoryStorage({ id: 'local-oauth-sessions', url: ':memory:' });\n const store = storage.registerDomain(new ModelCredentialsStorage());\n await storage.init();\n return store;\n })();\n return localSessionsPromise;\n}\nconst LOCAL_TENANT = { orgId: 'local', userId: 'local' } as const;\n\nasync function sessionStore(ctx: CredentialContext): Promise<ModelCredentialsStorage> {\n return ctx.mode === 'tenant' ? ctx.storage : localSessions();\n}\n\nfunction sessionTenant(ctx: CredentialContext): { orgId: string; userId: string } {\n return ctx.mode === 'tenant' ? { orgId: ctx.orgId, userId: ctx.userId } : LOCAL_TENANT;\n}\n\n/** Load a session and verify it belongs to the caller + provider (else undefined). */\nasync function loadOwnedSession({\n ctx,\n provider,\n sessionId,\n}: {\n ctx: CredentialContext;\n provider: string;\n sessionId: string;\n}): Promise<LoginSessionRow | undefined> {\n const session = await (await sessionStore(ctx)).getLoginSession(sessionId);\n if (!session) return undefined;\n const tenant = sessionTenant(ctx);\n if (session.orgId !== tenant.orgId || session.userId !== tenant.userId) return undefined;\n if (session.provider !== provider) return undefined;\n return session;\n}\n\n/** Persist completed OAuth credentials — user-scoped unless the flow was started org-wide. */\nasync function persistOAuthCredential({\n ctx,\n provider,\n scope,\n credentials,\n authStorage,\n memorySettings,\n onCredentialsChanged,\n}: {\n ctx: CredentialContext;\n provider: string;\n scope: LoginCredentialScope | undefined;\n credentials: OAuthCredentials;\n authStorage: AuthStorage | undefined;\n memorySettings: MemorySettingsStorage | undefined;\n onCredentialsChanged: (tenant: { orgId: string; userId?: string }) => void;\n}): Promise<void> {\n const authProviderId = getAuthProviderId(provider);\n if (ctx.mode === 'tenant') {\n const tenant = { orgId: ctx.orgId, ...(scope === 'org' ? {} : { userId: ctx.userId }) };\n await ctx.storage.setCredential(tenant, authProviderId, {\n type: 'oauth',\n ...credentials,\n });\n onCredentialsChanged(tenant);\n await seedPersonalOmDefaults({ memorySettings, tenant, provider });\n return;\n }\n if (!authStorage) throw new Error('Credential storage is not available');\n authStorage.set(authProviderId, { type: 'oauth', ...credentials });\n}\n\nasync function readJsonBody(c: Context): Promise<Record<string, unknown>> {\n try {\n const body = (await c.req.json()) as unknown;\n return body && typeof body === 'object' ? (body as Record<string, unknown>) : {};\n } catch {\n return {};\n }\n}\n\nexport interface OAuthRoutesDeps extends RouteDependencies {\n /** File-backed credential store; used in local (no-auth) mode. */\n authStorage?: AuthStorage;\n /** Tenant credential domain handle; absent in local (no-DB) mode. */\n modelCredentials?: ModelCredentialsStorage;\n /** Personal OM settings; seeded from the login provider after a user-scoped sign-in. */\n memorySettings?: MemorySettingsStorage;\n /** Notifies the host after tenant credentials change so caches can be dropped. */\n onCredentialsChanged?: (tenant: { orgId: string; userId?: string }) => void;\n}\n\n/**\n * Provider OAuth sign-in routes as Mastra `apiRoutes`:\n * - `POST /web/config/providers/:provider/oauth/start` — begin a sign-in flow\n * - `POST /web/config/providers/:provider/oauth/complete` — paste-code exchange\n * - `POST /web/config/providers/:provider/oauth/poll` — one device-code poll\n * - `DELETE /web/config/providers/:provider/oauth/session/:sessionId` — cancel a flow\n * - `DELETE /web/config/providers/:provider/oauth` — sign out (caller only)\n */\nexport class OAuthRoutes extends Route<OAuthRoutesDeps> {\n routes(): ApiRoute[] {\n const { auth, authStorage, modelCredentials, memorySettings } = this.deps;\n const onCredentialsChanged = this.deps.onCredentialsChanged ?? (() => {});\n\n return [\n registerApiRoute('/web/config/providers/:provider/oauth/start', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const ctx = await resolveCredentialContext({ c: loose(c), auth, credentials: modelCredentials });\n if ('response' in ctx) return ctx.response;\n\n const provider = c.req.param('provider');\n const flow = OAUTH_FLOWS[provider];\n if (!flow) {\n return c.json({ error: 'oauth_not_supported', message: `Provider does not support web sign-in` }, 404);\n }\n // Body may carry `{ mode }` for future multi-mode providers; each web\n // flow currently has exactly one mode, so an unknown mode is rejected.\n const body = await readJsonBody(loose(c));\n if (typeof body.mode === 'string' && body.mode !== flow.kind) {\n return c.json({ error: 'invalid_mode', message: `Unsupported mode for ${provider}: ${body.mode}` }, 400);\n }\n\n // Optional `{ scope: 'org' }` shares the completed credential with\n // the whole org (admin-only, tenant mode). Anything else is personal.\n const scope: LoginCredentialScope = body.scope === 'org' ? 'org' : 'user';\n if (scope === 'org' && ctx.mode === 'tenant' && !(await auth.isOrganizationAdmin(loose(c), ctx.orgId))) {\n return c.json({ error: 'forbidden', message: 'Only org admins can sign in for the whole org' }, 403);\n }\n\n let started: OAuthFlowStart;\n try {\n started = await flow.start();\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 502);\n }\n\n const sessionId = randomUUID();\n const tenant = sessionTenant(ctx);\n await (\n await sessionStore(ctx)\n ).createLoginSession({\n sessionId,\n orgId: tenant.orgId,\n userId: tenant.userId,\n provider,\n kind: flow.kind,\n ...(scope === 'org' && ctx.mode === 'tenant' ? { credentialScope: scope } : {}),\n pending: started.pending,\n expiresAt: new Date(started.expiresAt),\n nextPollAt: started.nextPollMs != null ? new Date(Date.now() + started.nextPollMs) : null,\n });\n\n return c.json({\n sessionId,\n kind: flow.kind,\n url: started.url,\n ...(started.userCode ? { userCode: started.userCode } : {}),\n instructions: started.instructions,\n expiresAt: started.expiresAt,\n ...(started.nextPollMs != null ? { nextPollMs: started.nextPollMs } : {}),\n });\n },\n }),\n\n registerApiRoute('/web/config/providers/:provider/oauth/complete', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const ctx = await resolveCredentialContext({ c: loose(c), auth, credentials: modelCredentials });\n if ('response' in ctx) return ctx.response;\n\n const provider = c.req.param('provider');\n const flow = OAUTH_FLOWS[provider];\n if (!flow?.complete) return c.json({ error: 'oauth_not_supported' }, 404);\n\n const body = await readJsonBody(loose(c));\n const sessionId = typeof body.sessionId === 'string' ? body.sessionId : '';\n const code = typeof body.code === 'string' ? body.code.trim() : '';\n if (!sessionId || !code) return c.json({ error: 'Missing required fields: sessionId, code' }, 400);\n\n const session = await loadOwnedSession({ ctx, provider, sessionId });\n if (!session) return c.json({ error: 'session_not_found' }, 404);\n if (session.kind !== 'paste-code') return c.json({ error: 'wrong_session_kind' }, 400);\n // Org-scoped flows recheck admin access at completion time — the\n // caller may have lost admin since the flow was started.\n if (\n session.credentialScope === 'org' &&\n ctx.mode === 'tenant' &&\n !(await auth.isOrganizationAdmin(loose(c), ctx.orgId))\n ) {\n return c.json({ error: 'forbidden', message: 'Only org admins can sign in for the whole org' }, 403);\n }\n\n const claimed = await (\n await sessionStore(ctx)\n ).claimLoginSession(sessionId, {\n orgId: session.orgId,\n userId: session.userId,\n provider,\n kind: 'paste-code',\n });\n if (!claimed) return c.json({ error: 'oauth_in_progress' }, 409);\n\n let credentials: OAuthCredentials;\n try {\n credentials = await flow.complete(claimed.pending, code);\n } catch (error) {\n await (await sessionStore(ctx)).touchLoginSession(sessionId, { nextPollAt: null });\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 400);\n }\n\n await persistOAuthCredential({\n ctx,\n provider,\n scope: session.credentialScope,\n credentials,\n authStorage,\n memorySettings,\n onCredentialsChanged,\n });\n await (await sessionStore(ctx)).deleteLoginSession(sessionId);\n return c.json({ status: 'complete', ok: true });\n },\n }),\n\n registerApiRoute('/web/config/providers/:provider/oauth/poll', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const ctx = await resolveCredentialContext({ c: loose(c), auth, credentials: modelCredentials });\n if ('response' in ctx) return ctx.response;\n\n const provider = c.req.param('provider');\n const flow = OAUTH_FLOWS[provider];\n if (!flow?.poll) return c.json({ error: 'oauth_not_supported' }, 404);\n\n const body = await readJsonBody(loose(c));\n const sessionId = typeof body.sessionId === 'string' ? body.sessionId : '';\n if (!sessionId) return c.json({ error: 'Missing required field: sessionId' }, 400);\n\n const session = await loadOwnedSession({ ctx, provider, sessionId });\n if (!session) return c.json({ error: 'session_not_found' }, 404);\n if (session.kind !== 'device-code') return c.json({ error: 'wrong_session_kind' }, 400);\n // Org-scoped flows recheck admin access before the credential write —\n // the caller may have lost admin since the flow was started.\n if (\n session.credentialScope === 'org' &&\n ctx.mode === 'tenant' &&\n !(await auth.isOrganizationAdmin(loose(c), ctx.orgId))\n ) {\n return c.json({ error: 'forbidden', message: 'Only org admins can sign in for the whole org' }, 403);\n }\n\n // Server-side rate limit: at most one upstream poll per interval,\n // regardless of how eagerly the client calls this route.\n const now = Date.now();\n const nextPollAt = session.nextPollAt?.getTime();\n if (nextPollAt != null && now < nextPollAt) {\n return c.json({ status: 'pending', nextPollMs: nextPollAt - now });\n }\n\n const claimed = await (\n await sessionStore(ctx)\n ).claimLoginSession(sessionId, {\n orgId: session.orgId,\n userId: session.userId,\n provider,\n kind: 'device-code',\n });\n if (!claimed) return c.json({ status: 'pending', nextPollMs: 250 });\n\n let result: OAuthFlowPoll;\n try {\n result = await flow.poll(claimed.pending);\n } catch (error) {\n await (await sessionStore(ctx)).touchLoginSession(sessionId, { nextPollAt: null });\n throw error;\n }\n\n if (result.status === 'complete') {\n await persistOAuthCredential({\n ctx,\n provider,\n scope: session.credentialScope,\n credentials: result.credentials,\n authStorage,\n memorySettings,\n onCredentialsChanged,\n });\n await (await sessionStore(ctx)).deleteLoginSession(sessionId);\n return c.json({ status: 'complete', ok: true });\n }\n\n if (result.status === 'failed') {\n await (await sessionStore(ctx)).deleteLoginSession(sessionId);\n return c.json({ status: 'failed', error: result.error });\n }\n\n await (\n await sessionStore(ctx)\n ).touchLoginSession(sessionId, {\n ...(result.pending ? { pending: result.pending } : {}),\n nextPollAt: new Date(now + result.nextPollMs),\n });\n return c.json({ status: 'pending', nextPollMs: result.nextPollMs });\n },\n }),\n\n registerApiRoute('/web/config/providers/:provider/oauth/session/:sessionId', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const ctx = await resolveCredentialContext({ c: loose(c), auth, credentials: modelCredentials });\n if ('response' in ctx) return ctx.response;\n\n const provider = c.req.param('provider');\n const sessionId = c.req.param('sessionId');\n const session = await loadOwnedSession({ ctx, provider, sessionId });\n if (session) await (await sessionStore(ctx)).deleteLoginSession(sessionId);\n return c.json({ ok: true });\n },\n }),\n\n registerApiRoute('/web/config/providers/:provider/oauth', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const ctx = await resolveCredentialContext({ c: loose(c), auth, credentials: modelCredentials });\n if ('response' in ctx) return ctx.response;\n\n const provider = c.req.param('provider');\n const authProviderId = getAuthProviderId(provider);\n // `?scope=org` removes the shared org credential (admin-only);\n // default removes the caller's personal credential only.\n const scope = c.req.query('scope') === 'org' ? 'org' : 'user';\n try {\n if (ctx.mode === 'tenant') {\n if (scope === 'org' && !(await auth.isOrganizationAdmin(loose(c), ctx.orgId))) {\n return c.json({ error: 'forbidden', message: 'Only org admins can remove an org-wide sign-in' }, 403);\n }\n const tenant = { orgId: ctx.orgId, ...(scope === 'org' ? {} : { userId: ctx.userId }) };\n await ctx.storage.removeCredential(tenant, authProviderId);\n onCredentialsChanged(tenant);\n } else {\n if (!authStorage) return c.json({ error: 'Credential storage is not available' }, 503);\n authStorage.remove(authProviderId);\n }\n return c.json({ ok: true });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n ];\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CA,MAAM,oBAAoB,MAAU;;AA6BpC,MAAM,cAAyC;CAC7C,WAAW;EACT,MAAM;EACN,OAAO,YAAY;GACjB,MAAM,EAAE,KAAK,aAAa,MAAM,oBAAoB;GACpD,OAAO;IACL;IACA,cAAc;IACd,WAAW,KAAK,IAAI,IAAI;IACxB,SAAS,EAAE,SAAS;GACtB;EACF;EACA,WAAW,SAAS,SAAS,uBAAuB,MAAM,OAAO,QAAQ,YAAY,EAAE,CAAC;CAC1F;CACA,QAAQ;EACN,MAAM;EACN,OAAO,YAAY;GACjB,MAAM,IAAI,MAAM,sBAAsB;GACtC,OAAO;IACL,KAAK,EAAE;IACP,UAAU,EAAE;IACZ,cAAc,EAAE;IAChB,WAAW,EAAE;IACb,YAAY,EAAE;IACd,SAAS,EAAE,GAAG,EAAE;GAClB;EACF;EACA,MAAM,OAAM,YAAW;GACrB,MAAM,IAAI,MAAM,qBAAqB,OAA6C;GAClF,IAAI,EAAE,WAAW,YAAY,OAAO;IAAE,QAAQ;IAAY,aAAa,EAAE;GAAY;GACrF,IAAI,EAAE,WAAW,WAAW,OAAO;IAAE,QAAQ;IAAW,YAAY,EAAE;GAAW;GACjF,OAAO;IAAE,QAAQ;IAAU,OAAO,EAAE;GAAM;EAC5C;CACF;CACA,kBAAkB;EAChB,MAAM;EACN,OAAO,YAAY;GACjB,MAAM,IAAI,MAAM,8BAA8B;GAC9C,OAAO;IACL,KAAK,EAAE;IACP,UAAU,EAAE;IACZ,cAAc,EAAE;IAChB,WAAW,EAAE;IACb,YAAY,uBAAuB,CAAC;IACpC,SAAS,EAAE,GAAG,EAAE;GAClB;EACF;EACA,MAAM,OAAM,YAAW;GACrB,MAAM,IAAI;GAIV,IAAI,EAAE,WAAW,gBAAgB,EAAE,qBAAqB,KAAA,GACtD,OAAO;IAAE,QAAQ;IAAU,OAAO;GAA0B;GAE9D,MAAM,IAAI,MAAM,6BAA6B,CAAC;GAC9C,IAAI,EAAE,WAAW,YAAY,OAAO;IAAE,QAAQ;IAAY,aAAa,EAAE;GAAY;GACrF,IAAI,EAAE,WAAW,WAAW,OAAO;IAAE,QAAQ;IAAW,YAAY,EAAE;IAAY,SAAS,EAAE,GAAG,EAAE,QAAQ;GAAE;GAC5G,OAAO;IAAE,QAAQ;IAAU,OAAO,EAAE;GAAM;EAC5C;CACF;CACA,KAAK;EACH,MAAM;EACN,OAAO,YAAY;GACjB,MAAM,IAAI,MAAM,oBAAoB;GACpC,OAAO;IACL,KAAK,EAAE;IACP,UAAU,EAAE;IACZ,cAAc,EAAE;IAChB,WAAW,EAAE,MAAM;IACnB,YAAY,gBAAgB,EAAE,KAAK;IACnC,SAAS,EAAE,GAAG,EAAE;GAClB;EACF;EACA,MAAM,OAAM,YAAW;GACrB,MAAM,IAAI,MAAM,mBAAmB,OAA2C;GAC9E,IAAI,EAAE,WAAW,YAAY,OAAO;IAAE,QAAQ;IAAY,aAAa,EAAE;GAAY;GACrF,IAAI,EAAE,WAAW,WAAW,OAAO;IAAE,QAAQ;IAAW,YAAY,EAAE;IAAY,SAAS,EAAE,GAAG,EAAE,QAAQ;GAAE;GAC5G,OAAO;IAAE,QAAQ;IAAU,OAAO,EAAE;GAAM;EAC5C;CACF;AACF;AAEA,SAAS,MAAM,GAAqB;CAClC,OAAO;AACT;;;;;;AAOA,IAAI;AACJ,SAAS,gBAAkD;CACzD,0BAA0B,YAAY;EACpC,MAAM,EAAE,yBAAyB,MAAM,OAAO;EAC9C,MAAM,UAAU,IAAI,qBAAqB;GAAE,IAAI;GAAwB,KAAK;EAAW,CAAC;EACxF,MAAM,QAAQ,QAAQ,eAAe,IAAI,wBAAwB,CAAC;EAClE,MAAM,QAAQ,KAAK;EACnB,OAAO;CACT,EAAA,CAAG;CACH,OAAO;AACT;AACA,MAAM,eAAe;CAAE,OAAO;CAAS,QAAQ;AAAQ;AAEvD,eAAe,aAAa,KAA0D;CACpF,OAAO,IAAI,SAAS,WAAW,IAAI,UAAU,cAAc;AAC7D;AAEA,SAAS,cAAc,KAA2D;CAChF,OAAO,IAAI,SAAS,WAAW;EAAE,OAAO,IAAI;EAAO,QAAQ,IAAI;CAAO,IAAI;AAC5E;;AAGA,eAAe,iBAAiB,EAC9B,KACA,UACA,aAKuC;CACvC,MAAM,UAAU,OAAO,MAAM,aAAa,GAAG,EAAA,CAAG,gBAAgB,SAAS;CACzE,IAAI,CAAC,SAAS,OAAO,KAAA;CACrB,MAAM,SAAS,cAAc,GAAG;CAChC,IAAI,QAAQ,UAAU,OAAO,SAAS,QAAQ,WAAW,OAAO,QAAQ,OAAO,KAAA;CAC/E,IAAI,QAAQ,aAAa,UAAU,OAAO,KAAA;CAC1C,OAAO;AACT;;AAGA,eAAe,uBAAuB,EACpC,KACA,UACA,OACA,aACA,aACA,gBACA,wBASgB;CAChB,MAAM,iBAAiB,kBAAkB,QAAQ;CACjD,IAAI,IAAI,SAAS,UAAU;EACzB,MAAM,SAAS;GAAE,OAAO,IAAI;GAAO,GAAI,UAAU,QAAQ,CAAC,IAAI,EAAE,QAAQ,IAAI,OAAO;EAAG;EACtF,MAAM,IAAI,QAAQ,cAAc,QAAQ,gBAAgB;GACtD,MAAM;GACN,GAAG;EACL,CAAC;EACD,qBAAqB,MAAM;EAC3B,MAAM,uBAAuB;GAAE;GAAgB;GAAQ;EAAS,CAAC;EACjE;CACF;CACA,IAAI,CAAC,aAAa,MAAM,IAAI,MAAM,qCAAqC;CACvE,YAAY,IAAI,gBAAgB;EAAE,MAAM;EAAS,GAAG;CAAY,CAAC;AACnE;AAEA,eAAe,aAAa,GAA8C;CACxE,IAAI;EACF,MAAM,OAAQ,MAAM,EAAE,IAAI,KAAK;EAC/B,OAAO,QAAQ,OAAO,SAAS,WAAY,OAAmC,CAAC;CACjF,QAAQ;EACN,OAAO,CAAC;CACV;AACF;;;;;;;;;AAqBA,IAAa,cAAb,cAAiC,MAAuB;CACtD,SAAqB;EACnB,MAAM,EAAE,MAAM,aAAa,kBAAkB,mBAAmB,KAAK;EACrE,MAAM,uBAAuB,KAAK,KAAK,+BAA+B,CAAC;EAEvE,OAAO;GACL,iBAAiB,+CAA+C;IAC9D,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,MAAM,MAAM,yBAAyB;MAAE,GAAG,MAAM,CAAC;MAAG;MAAM,aAAa;KAAiB,CAAC;KAC/F,IAAI,cAAc,KAAK,OAAO,IAAI;KAElC,MAAM,WAAW,EAAE,IAAI,MAAM,UAAU;KACvC,MAAM,OAAO,YAAY;KACzB,IAAI,CAAC,MACH,OAAO,EAAE,KAAK;MAAE,OAAO;MAAuB,SAAS;KAAwC,GAAG,GAAG;KAIvG,MAAM,OAAO,MAAM,aAAa,MAAM,CAAC,CAAC;KACxC,IAAI,OAAO,KAAK,SAAS,YAAY,KAAK,SAAS,KAAK,MACtD,OAAO,EAAE,KAAK;MAAE,OAAO;MAAgB,SAAS,wBAAwB,SAAS,IAAI,KAAK;KAAO,GAAG,GAAG;KAKzG,MAAM,QAA8B,KAAK,UAAU,QAAQ,QAAQ;KACnE,IAAI,UAAU,SAAS,IAAI,SAAS,YAAY,CAAE,MAAM,KAAK,oBAAoB,MAAM,CAAC,GAAG,IAAI,KAAK,GAClG,OAAO,EAAE,KAAK;MAAE,OAAO;MAAa,SAAS;KAAgD,GAAG,GAAG;KAGrG,IAAI;KACJ,IAAI;MACF,UAAU,MAAM,KAAK,MAAM;KAC7B,SAAS,OAAO;MACd,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;KAEA,MAAM,YAAY,WAAW;KAC7B,MAAM,SAAS,cAAc,GAAG;KAChC,OACE,MAAM,aAAa,GAAG,EAAA,CACtB,mBAAmB;MACnB;MACA,OAAO,OAAO;MACd,QAAQ,OAAO;MACf;MACA,MAAM,KAAK;MACX,GAAI,UAAU,SAAS,IAAI,SAAS,WAAW,EAAE,iBAAiB,MAAM,IAAI,CAAC;MAC7E,SAAS,QAAQ;MACjB,WAAW,IAAI,KAAK,QAAQ,SAAS;MACrC,YAAY,QAAQ,cAAc,OAAO,IAAI,KAAK,KAAK,IAAI,IAAI,QAAQ,UAAU,IAAI;KACvF,CAAC;KAED,OAAO,EAAE,KAAK;MACZ;MACA,MAAM,KAAK;MACX,KAAK,QAAQ;MACb,GAAI,QAAQ,WAAW,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;MACzD,cAAc,QAAQ;MACtB,WAAW,QAAQ;MACnB,GAAI,QAAQ,cAAc,OAAO,EAAE,YAAY,QAAQ,WAAW,IAAI,CAAC;KACzE,CAAC;IACH;GACF,CAAC;GAED,iBAAiB,kDAAkD;IACjE,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,MAAM,MAAM,yBAAyB;MAAE,GAAG,MAAM,CAAC;MAAG;MAAM,aAAa;KAAiB,CAAC;KAC/F,IAAI,cAAc,KAAK,OAAO,IAAI;KAElC,MAAM,WAAW,EAAE,IAAI,MAAM,UAAU;KACvC,MAAM,OAAO,YAAY;KACzB,IAAI,CAAC,MAAM,UAAU,OAAO,EAAE,KAAK,EAAE,OAAO,sBAAsB,GAAG,GAAG;KAExE,MAAM,OAAO,MAAM,aAAa,MAAM,CAAC,CAAC;KACxC,MAAM,YAAY,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;KACxE,MAAM,OAAO,OAAO,KAAK,SAAS,WAAW,KAAK,KAAK,KAAK,IAAI;KAChE,IAAI,CAAC,aAAa,CAAC,MAAM,OAAO,EAAE,KAAK,EAAE,OAAO,2CAA2C,GAAG,GAAG;KAEjG,MAAM,UAAU,MAAM,iBAAiB;MAAE;MAAK;MAAU;KAAU,CAAC;KACnE,IAAI,CAAC,SAAS,OAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,GAAG,GAAG;KAC/D,IAAI,QAAQ,SAAS,cAAc,OAAO,EAAE,KAAK,EAAE,OAAO,qBAAqB,GAAG,GAAG;KAGrF,IACE,QAAQ,oBAAoB,SAC5B,IAAI,SAAS,YACb,CAAE,MAAM,KAAK,oBAAoB,MAAM,CAAC,GAAG,IAAI,KAAK,GAEpD,OAAO,EAAE,KAAK;MAAE,OAAO;MAAa,SAAS;KAAgD,GAAG,GAAG;KAGrG,MAAM,UAAU,OACd,MAAM,aAAa,GAAG,EAAA,CACtB,kBAAkB,WAAW;MAC7B,OAAO,QAAQ;MACf,QAAQ,QAAQ;MAChB;MACA,MAAM;KACR,CAAC;KACD,IAAI,CAAC,SAAS,OAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,GAAG,GAAG;KAE/D,IAAI;KACJ,IAAI;MACF,cAAc,MAAM,KAAK,SAAS,QAAQ,SAAS,IAAI;KACzD,SAAS,OAAO;MACd,OAAO,MAAM,aAAa,GAAG,EAAA,CAAG,kBAAkB,WAAW,EAAE,YAAY,KAAK,CAAC;MACjF,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;KAEA,MAAM,uBAAuB;MAC3B;MACA;MACA,OAAO,QAAQ;MACf;MACA;MACA;MACA;KACF,CAAC;KACD,OAAO,MAAM,aAAa,GAAG,EAAA,CAAG,mBAAmB,SAAS;KAC5D,OAAO,EAAE,KAAK;MAAE,QAAQ;MAAY,IAAI;KAAK,CAAC;IAChD;GACF,CAAC;GAED,iBAAiB,8CAA8C;IAC7D,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,MAAM,MAAM,yBAAyB;MAAE,GAAG,MAAM,CAAC;MAAG;MAAM,aAAa;KAAiB,CAAC;KAC/F,IAAI,cAAc,KAAK,OAAO,IAAI;KAElC,MAAM,WAAW,EAAE,IAAI,MAAM,UAAU;KACvC,MAAM,OAAO,YAAY;KACzB,IAAI,CAAC,MAAM,MAAM,OAAO,EAAE,KAAK,EAAE,OAAO,sBAAsB,GAAG,GAAG;KAEpE,MAAM,OAAO,MAAM,aAAa,MAAM,CAAC,CAAC;KACxC,MAAM,YAAY,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;KACxE,IAAI,CAAC,WAAW,OAAO,EAAE,KAAK,EAAE,OAAO,oCAAoC,GAAG,GAAG;KAEjF,MAAM,UAAU,MAAM,iBAAiB;MAAE;MAAK;MAAU;KAAU,CAAC;KACnE,IAAI,CAAC,SAAS,OAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,GAAG,GAAG;KAC/D,IAAI,QAAQ,SAAS,eAAe,OAAO,EAAE,KAAK,EAAE,OAAO,qBAAqB,GAAG,GAAG;KAGtF,IACE,QAAQ,oBAAoB,SAC5B,IAAI,SAAS,YACb,CAAE,MAAM,KAAK,oBAAoB,MAAM,CAAC,GAAG,IAAI,KAAK,GAEpD,OAAO,EAAE,KAAK;MAAE,OAAO;MAAa,SAAS;KAAgD,GAAG,GAAG;KAKrG,MAAM,MAAM,KAAK,IAAI;KACrB,MAAM,aAAa,QAAQ,YAAY,QAAQ;KAC/C,IAAI,cAAc,QAAQ,MAAM,YAC9B,OAAO,EAAE,KAAK;MAAE,QAAQ;MAAW,YAAY,aAAa;KAAI,CAAC;KAGnE,MAAM,UAAU,OACd,MAAM,aAAa,GAAG,EAAA,CACtB,kBAAkB,WAAW;MAC7B,OAAO,QAAQ;MACf,QAAQ,QAAQ;MAChB;MACA,MAAM;KACR,CAAC;KACD,IAAI,CAAC,SAAS,OAAO,EAAE,KAAK;MAAE,QAAQ;MAAW,YAAY;KAAI,CAAC;KAElE,IAAI;KACJ,IAAI;MACF,SAAS,MAAM,KAAK,KAAK,QAAQ,OAAO;KAC1C,SAAS,OAAO;MACd,OAAO,MAAM,aAAa,GAAG,EAAA,CAAG,kBAAkB,WAAW,EAAE,YAAY,KAAK,CAAC;MACjF,MAAM;KACR;KAEA,IAAI,OAAO,WAAW,YAAY;MAChC,MAAM,uBAAuB;OAC3B;OACA;OACA,OAAO,QAAQ;OACf,aAAa,OAAO;OACpB;OACA;OACA;MACF,CAAC;MACD,OAAO,MAAM,aAAa,GAAG,EAAA,CAAG,mBAAmB,SAAS;MAC5D,OAAO,EAAE,KAAK;OAAE,QAAQ;OAAY,IAAI;MAAK,CAAC;KAChD;KAEA,IAAI,OAAO,WAAW,UAAU;MAC9B,OAAO,MAAM,aAAa,GAAG,EAAA,CAAG,mBAAmB,SAAS;MAC5D,OAAO,EAAE,KAAK;OAAE,QAAQ;OAAU,OAAO,OAAO;MAAM,CAAC;KACzD;KAEA,OACE,MAAM,aAAa,GAAG,EAAA,CACtB,kBAAkB,WAAW;MAC7B,GAAI,OAAO,UAAU,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;MACpD,YAAY,IAAI,KAAK,MAAM,OAAO,UAAU;KAC9C,CAAC;KACD,OAAO,EAAE,KAAK;MAAE,QAAQ;MAAW,YAAY,OAAO;KAAW,CAAC;IACpE;GACF,CAAC;GAED,iBAAiB,4DAA4D;IAC3E,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,MAAM,MAAM,yBAAyB;MAAE,GAAG,MAAM,CAAC;MAAG;MAAM,aAAa;KAAiB,CAAC;KAC/F,IAAI,cAAc,KAAK,OAAO,IAAI;KAElC,MAAM,WAAW,EAAE,IAAI,MAAM,UAAU;KACvC,MAAM,YAAY,EAAE,IAAI,MAAM,WAAW;KAEzC,IAAI,MADkB,iBAAiB;MAAE;MAAK;MAAU;KAAU,CAAC,GACtD,OAAO,MAAM,aAAa,GAAG,EAAA,CAAG,mBAAmB,SAAS;KACzE,OAAO,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC;IAC5B;GACF,CAAC;GAED,iBAAiB,yCAAyC;IACxD,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,MAAM,MAAM,yBAAyB;MAAE,GAAG,MAAM,CAAC;MAAG;MAAM,aAAa;KAAiB,CAAC;KAC/F,IAAI,cAAc,KAAK,OAAO,IAAI;KAGlC,MAAM,iBAAiB,kBADN,EAAE,IAAI,MAAM,UACmB,CAAC;KAGjD,MAAM,QAAQ,EAAE,IAAI,MAAM,OAAO,MAAM,QAAQ,QAAQ;KACvD,IAAI;MACF,IAAI,IAAI,SAAS,UAAU;OACzB,IAAI,UAAU,SAAS,CAAE,MAAM,KAAK,oBAAoB,MAAM,CAAC,GAAG,IAAI,KAAK,GACzE,OAAO,EAAE,KAAK;QAAE,OAAO;QAAa,SAAS;OAAiD,GAAG,GAAG;OAEtG,MAAM,SAAS;QAAE,OAAO,IAAI;QAAO,GAAI,UAAU,QAAQ,CAAC,IAAI,EAAE,QAAQ,IAAI,OAAO;OAAG;OACtF,MAAM,IAAI,QAAQ,iBAAiB,QAAQ,cAAc;OACzD,qBAAqB,MAAM;MAC7B,OAAO;OACL,IAAI,CAAC,aAAa,OAAO,EAAE,KAAK,EAAE,OAAO,sCAAsC,GAAG,GAAG;OACrF,YAAY,OAAO,cAAc;MACnC;MACA,OAAO,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC;KAC5B,SAAS,OAAO;MACd,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;IACF;GACF,CAAC;EACH;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"oauth.js","names":[],"sources":["../../src/routes/oauth.ts"],"sourcesContent":["/**\n * Web OAuth sign-in routes for model providers (Settings › Providers).\n *\n * Wraps the SDK's step-based OAuth primitives (start/complete for Anthropic's\n * paste-code PKCE flow, start/poll for the Codex/Copilot/xAI device flows) in\n * HTTP routes. Flow state lives in login sessions — the `model-credentials`\n * domain's `oauth_login_sessions` table in tenant mode (any replica can\n * complete/poll), an in-memory store in local mode — so a flow can span\n * requests. Completed credentials are **user-scoped by default**; org admins\n * can start a flow with `{ scope: 'org' }` to share the credential with the\n * whole org. Local mode writes to the file-backed `AuthStorage`.\n *\n * Tokens never leave the server; responses only carry flow metadata (URLs,\n * user codes, poll delays).\n */\n\nimport { randomUUID } from 'node:crypto';\n\nimport { nextPollDelayMs } from '@mastra/code-sdk/auth/device-code';\nimport { completeAnthropicLogin, startAnthropicLogin } from '@mastra/code-sdk/auth/providers/anthropic';\nimport {\n copilotNextPollDelayMs,\n pollGitHubCopilotDeviceLogin,\n startGitHubCopilotDeviceLogin,\n} from '@mastra/code-sdk/auth/providers/github-copilot';\nimport type { CopilotDeviceLoginPending } from '@mastra/code-sdk/auth/providers/github-copilot';\nimport { pollCodexDeviceLogin, startCodexDeviceLogin } from '@mastra/code-sdk/auth/providers/openai-codex';\nimport type { CodexDeviceLoginPending } from '@mastra/code-sdk/auth/providers/openai-codex';\nimport { pollXAIDeviceLogin, startXAIDeviceLogin } from '@mastra/code-sdk/auth/providers/xai';\nimport type { XAIDeviceLoginPending } from '@mastra/code-sdk/auth/providers/xai';\nimport type { AuthStorage } from '@mastra/code-sdk/auth/storage';\nimport type { OAuthCredentials } from '@mastra/code-sdk/auth/types';\nimport type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { Context } from 'hono';\n\nimport { ModelCredentialsStorage } from '../storage/domains/credentials/base.js';\nimport type { LoginCredentialScope, LoginSessionKind, LoginSessionRow } from '../storage/domains/credentials/base.js';\nimport type { MemorySettingsStorage } from '../storage/domains/memory-settings/base.js';\nimport { seedPersonalOmDefaults } from './om-seed.js';\nimport { getAuthProviderId, resolveCredentialContext } from './provider-credentials.js';\nimport type { CredentialContext } from './provider-credentials.js';\nimport { Route } from './route.js';\nimport type { RouteDependencies } from './route.js';\n\n/** Lifetime of a paste-code session (Anthropic gives no explicit expiry). */\nconst PASTE_CODE_TTL_MS = 10 * 60 * 1000;\n\ninterface OAuthFlowStart {\n url: string;\n userCode?: string;\n instructions: string;\n /** ms epoch after which the flow expires. */\n expiresAt: number;\n /** Delay before the first upstream poll (device-code flows only). */\n nextPollMs?: number;\n /** Serializable flow state persisted in the login session. */\n pending: Record<string, unknown>;\n}\n\ntype OAuthFlowPoll =\n | { status: 'complete'; credentials: OAuthCredentials }\n | { status: 'pending'; nextPollMs: number; pending?: Record<string, unknown> }\n | { status: 'failed'; error: string };\n\ninterface OAuthFlow {\n kind: LoginSessionKind;\n start(): Promise<OAuthFlowStart>;\n /** Paste-code flows: exchange the pasted code for credentials. Throws on bad input. */\n complete?(pending: Record<string, unknown>, code: string): Promise<OAuthCredentials>;\n /** Device-code flows: perform exactly one upstream poll. */\n poll?(pending: Record<string, unknown>): Promise<OAuthFlowPoll>;\n}\n\n/** Web OAuth flows keyed by *catalog* provider id (mirrors {@link WEB_OAUTH_FLOW_KINDS}). */\nconst OAUTH_FLOWS: Record<string, OAuthFlow> = {\n anthropic: {\n kind: 'paste-code',\n start: async () => {\n const { url, verifier } = await startAnthropicLogin();\n return {\n url,\n instructions: 'Open the link, authorize, then paste the code shown on the final page.',\n expiresAt: Date.now() + PASTE_CODE_TTL_MS,\n pending: { verifier },\n };\n },\n complete: (pending, code) => completeAnthropicLogin(code, String(pending.verifier ?? '')),\n },\n openai: {\n kind: 'device-code',\n start: async () => {\n const p = await startCodexDeviceLogin();\n return {\n url: p.url,\n userCode: p.userCode,\n instructions: p.instructions,\n expiresAt: p.deadlineAt,\n nextPollMs: p.intervalMs,\n pending: { ...p },\n };\n },\n poll: async pending => {\n const r = await pollCodexDeviceLogin(pending as unknown as CodexDeviceLoginPending);\n if (r.status === 'complete') return { status: 'complete', credentials: r.credentials };\n if (r.status === 'pending') return { status: 'pending', nextPollMs: r.nextPollMs };\n return { status: 'failed', error: r.error };\n },\n },\n 'github-copilot': {\n kind: 'device-code',\n start: async () => {\n const p = await startGitHubCopilotDeviceLogin();\n return {\n url: p.url,\n userCode: p.userCode,\n instructions: p.instructions,\n expiresAt: p.deadlineAt,\n nextPollMs: copilotNextPollDelayMs(p),\n pending: { ...p },\n };\n },\n poll: async pending => {\n const p = pending as unknown as CopilotDeviceLoginPending;\n // Web flows are always started against github.com (no Enterprise input).\n // Never let deserialized session state redirect server-side polling to\n // an arbitrary hostname.\n if (p.domain !== 'github.com' || p.enterpriseDomain !== undefined) {\n return { status: 'failed', error: 'Unsupported GitHub host' };\n }\n const r = await pollGitHubCopilotDeviceLogin(p);\n if (r.status === 'complete') return { status: 'complete', credentials: r.credentials };\n if (r.status === 'pending') return { status: 'pending', nextPollMs: r.nextPollMs, pending: { ...r.pending } };\n return { status: 'failed', error: r.error };\n },\n },\n xai: {\n kind: 'device-code',\n start: async () => {\n const p = await startXAIDeviceLogin();\n return {\n url: p.url,\n userCode: p.userCode,\n instructions: p.instructions,\n expiresAt: p.state.deadlineAt,\n nextPollMs: nextPollDelayMs(p.state),\n pending: { ...p },\n };\n },\n poll: async pending => {\n const r = await pollXAIDeviceLogin(pending as unknown as XAIDeviceLoginPending);\n if (r.status === 'complete') return { status: 'complete', credentials: r.credentials };\n if (r.status === 'pending') return { status: 'pending', nextPollMs: r.nextPollMs, pending: { ...r.pending } };\n return { status: 'failed', error: r.error };\n },\n },\n};\n\nfunction loose(c: unknown): Context {\n return c as Context;\n}\n\n/**\n * Local-mode login sessions. Flows in local mode are single-process, so a\n * process-local libsql `:memory:` database (which already handles TTL\n * cleanup) is sufficient.\n */\nlet localSessionsPromise: Promise<ModelCredentialsStorage> | undefined;\nfunction localSessions(): Promise<ModelCredentialsStorage> {\n localSessionsPromise ??= (async () => {\n const { LibSQLFactoryStorage } = await import('@mastra/libsql');\n const storage = new LibSQLFactoryStorage({ id: 'local-oauth-sessions', url: ':memory:' });\n const store = storage.registerDomain(new ModelCredentialsStorage());\n await storage.init();\n return store;\n })();\n return localSessionsPromise;\n}\nconst LOCAL_TENANT = { orgId: 'local', userId: 'local' } as const;\n\nasync function sessionStore(ctx: CredentialContext): Promise<ModelCredentialsStorage> {\n return ctx.mode === 'tenant' ? ctx.storage : localSessions();\n}\n\nfunction sessionTenant(ctx: CredentialContext): { orgId: string; userId: string } {\n return ctx.mode === 'tenant' ? { orgId: ctx.orgId, userId: ctx.userId } : LOCAL_TENANT;\n}\n\n/** Load a session and verify it belongs to the caller + provider (else undefined). */\nasync function loadOwnedSession({\n ctx,\n provider,\n sessionId,\n}: {\n ctx: CredentialContext;\n provider: string;\n sessionId: string;\n}): Promise<LoginSessionRow | undefined> {\n const session = await (await sessionStore(ctx)).getLoginSession(sessionId);\n if (!session) return undefined;\n const tenant = sessionTenant(ctx);\n if (session.orgId !== tenant.orgId || session.userId !== tenant.userId) return undefined;\n if (session.provider !== provider) return undefined;\n return session;\n}\n\n/** Persist completed OAuth credentials — user-scoped unless the flow was started org-wide. */\nasync function persistOAuthCredential({\n ctx,\n provider,\n scope,\n credentials,\n authStorage,\n memorySettings,\n onCredentialsChanged,\n}: {\n ctx: CredentialContext;\n provider: string;\n scope: LoginCredentialScope | undefined;\n credentials: OAuthCredentials;\n authStorage: AuthStorage | undefined;\n memorySettings: MemorySettingsStorage | undefined;\n onCredentialsChanged: (tenant: { orgId: string; userId?: string }) => void;\n}): Promise<void> {\n const authProviderId = getAuthProviderId(provider);\n if (ctx.mode === 'tenant') {\n const tenant = { orgId: ctx.orgId, ...(scope === 'org' ? {} : { userId: ctx.userId }) };\n await ctx.storage.setCredential(tenant, authProviderId, {\n type: 'oauth',\n ...credentials,\n });\n onCredentialsChanged(tenant);\n await seedPersonalOmDefaults({ memorySettings, tenant, provider });\n return;\n }\n if (!authStorage) throw new Error('Credential storage is not available');\n await authStorage.addAccount(authProviderId, credentials);\n}\n\nasync function readJsonBody(c: Context): Promise<Record<string, unknown>> {\n try {\n const body = (await c.req.json()) as unknown;\n return body && typeof body === 'object' ? (body as Record<string, unknown>) : {};\n } catch {\n return {};\n }\n}\n\nexport interface OAuthRoutesDeps extends RouteDependencies {\n /** File-backed credential store; used in local (no-auth) mode. */\n authStorage?: AuthStorage;\n /** Tenant credential domain handle; absent in local (no-DB) mode. */\n modelCredentials?: ModelCredentialsStorage;\n /** Personal OM settings; seeded from the login provider after a user-scoped sign-in. */\n memorySettings?: MemorySettingsStorage;\n /** Notifies the host after tenant credentials change so caches can be dropped. */\n onCredentialsChanged?: (tenant: { orgId: string; userId?: string }) => void;\n}\n\n/**\n * Provider OAuth sign-in routes as Mastra `apiRoutes`:\n * - `POST /web/config/providers/:provider/oauth/start` — begin a sign-in flow\n * - `POST /web/config/providers/:provider/oauth/complete` — paste-code exchange\n * - `POST /web/config/providers/:provider/oauth/poll` — one device-code poll\n * - `DELETE /web/config/providers/:provider/oauth/session/:sessionId` — cancel a flow\n * - `DELETE /web/config/providers/:provider/oauth` — sign out (caller only)\n */\nexport class OAuthRoutes extends Route<OAuthRoutesDeps> {\n routes(): ApiRoute[] {\n const { auth, authStorage, modelCredentials, memorySettings } = this.deps;\n const onCredentialsChanged = this.deps.onCredentialsChanged ?? (() => {});\n\n return [\n registerApiRoute('/web/config/providers/:provider/oauth/start', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const ctx = await resolveCredentialContext({ c: loose(c), auth, credentials: modelCredentials });\n if ('response' in ctx) return ctx.response;\n\n const provider = c.req.param('provider');\n const flow = OAUTH_FLOWS[provider];\n if (!flow) {\n return c.json({ error: 'oauth_not_supported', message: `Provider does not support web sign-in` }, 404);\n }\n // Body may carry `{ mode }` for future multi-mode providers; each web\n // flow currently has exactly one mode, so an unknown mode is rejected.\n const body = await readJsonBody(loose(c));\n if (typeof body.mode === 'string' && body.mode !== flow.kind) {\n return c.json({ error: 'invalid_mode', message: `Unsupported mode for ${provider}: ${body.mode}` }, 400);\n }\n\n // Optional `{ scope: 'org' }` shares the completed credential with\n // the whole org (admin-only, tenant mode). Anything else is personal.\n const scope: LoginCredentialScope = body.scope === 'org' ? 'org' : 'user';\n if (scope === 'org' && ctx.mode === 'tenant' && !(await auth.isOrganizationAdmin(loose(c), ctx.orgId))) {\n return c.json({ error: 'forbidden', message: 'Only org admins can sign in for the whole org' }, 403);\n }\n\n let started: OAuthFlowStart;\n try {\n started = await flow.start();\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 502);\n }\n\n const sessionId = randomUUID();\n const tenant = sessionTenant(ctx);\n await (\n await sessionStore(ctx)\n ).createLoginSession({\n sessionId,\n orgId: tenant.orgId,\n userId: tenant.userId,\n provider,\n kind: flow.kind,\n ...(scope === 'org' && ctx.mode === 'tenant' ? { credentialScope: scope } : {}),\n pending: started.pending,\n expiresAt: new Date(started.expiresAt),\n nextPollAt: started.nextPollMs != null ? new Date(Date.now() + started.nextPollMs) : null,\n });\n\n return c.json({\n sessionId,\n kind: flow.kind,\n url: started.url,\n ...(started.userCode ? { userCode: started.userCode } : {}),\n instructions: started.instructions,\n expiresAt: started.expiresAt,\n ...(started.nextPollMs != null ? { nextPollMs: started.nextPollMs } : {}),\n });\n },\n }),\n\n registerApiRoute('/web/config/providers/:provider/oauth/complete', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const ctx = await resolveCredentialContext({ c: loose(c), auth, credentials: modelCredentials });\n if ('response' in ctx) return ctx.response;\n\n const provider = c.req.param('provider');\n const flow = OAUTH_FLOWS[provider];\n if (!flow?.complete) return c.json({ error: 'oauth_not_supported' }, 404);\n\n const body = await readJsonBody(loose(c));\n const sessionId = typeof body.sessionId === 'string' ? body.sessionId : '';\n const code = typeof body.code === 'string' ? body.code.trim() : '';\n if (!sessionId || !code) return c.json({ error: 'Missing required fields: sessionId, code' }, 400);\n\n const session = await loadOwnedSession({ ctx, provider, sessionId });\n if (!session) return c.json({ error: 'session_not_found' }, 404);\n if (session.kind !== 'paste-code') return c.json({ error: 'wrong_session_kind' }, 400);\n // Org-scoped flows recheck admin access at completion time — the\n // caller may have lost admin since the flow was started.\n if (\n session.credentialScope === 'org' &&\n ctx.mode === 'tenant' &&\n !(await auth.isOrganizationAdmin(loose(c), ctx.orgId))\n ) {\n return c.json({ error: 'forbidden', message: 'Only org admins can sign in for the whole org' }, 403);\n }\n\n const claimed = await (\n await sessionStore(ctx)\n ).claimLoginSession(sessionId, {\n orgId: session.orgId,\n userId: session.userId,\n provider,\n kind: 'paste-code',\n });\n if (!claimed) return c.json({ error: 'oauth_in_progress' }, 409);\n\n let credentials: OAuthCredentials;\n try {\n credentials = await flow.complete(claimed.pending, code);\n } catch (error) {\n await (await sessionStore(ctx)).touchLoginSession(sessionId, { nextPollAt: null });\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 400);\n }\n\n await persistOAuthCredential({\n ctx,\n provider,\n scope: session.credentialScope,\n credentials,\n authStorage,\n memorySettings,\n onCredentialsChanged,\n });\n await (await sessionStore(ctx)).deleteLoginSession(sessionId);\n return c.json({ status: 'complete', ok: true });\n },\n }),\n\n registerApiRoute('/web/config/providers/:provider/oauth/poll', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const ctx = await resolveCredentialContext({ c: loose(c), auth, credentials: modelCredentials });\n if ('response' in ctx) return ctx.response;\n\n const provider = c.req.param('provider');\n const flow = OAUTH_FLOWS[provider];\n if (!flow?.poll) return c.json({ error: 'oauth_not_supported' }, 404);\n\n const body = await readJsonBody(loose(c));\n const sessionId = typeof body.sessionId === 'string' ? body.sessionId : '';\n if (!sessionId) return c.json({ error: 'Missing required field: sessionId' }, 400);\n\n const session = await loadOwnedSession({ ctx, provider, sessionId });\n if (!session) return c.json({ error: 'session_not_found' }, 404);\n if (session.kind !== 'device-code') return c.json({ error: 'wrong_session_kind' }, 400);\n // Org-scoped flows recheck admin access before the credential write —\n // the caller may have lost admin since the flow was started.\n if (\n session.credentialScope === 'org' &&\n ctx.mode === 'tenant' &&\n !(await auth.isOrganizationAdmin(loose(c), ctx.orgId))\n ) {\n return c.json({ error: 'forbidden', message: 'Only org admins can sign in for the whole org' }, 403);\n }\n\n // Server-side rate limit: at most one upstream poll per interval,\n // regardless of how eagerly the client calls this route.\n const now = Date.now();\n const nextPollAt = session.nextPollAt?.getTime();\n if (nextPollAt != null && now < nextPollAt) {\n return c.json({ status: 'pending', nextPollMs: nextPollAt - now });\n }\n\n const claimed = await (\n await sessionStore(ctx)\n ).claimLoginSession(sessionId, {\n orgId: session.orgId,\n userId: session.userId,\n provider,\n kind: 'device-code',\n });\n if (!claimed) return c.json({ status: 'pending', nextPollMs: 250 });\n\n let result: OAuthFlowPoll;\n try {\n result = await flow.poll(claimed.pending);\n } catch (error) {\n await (await sessionStore(ctx)).touchLoginSession(sessionId, { nextPollAt: null });\n throw error;\n }\n\n if (result.status === 'complete') {\n await persistOAuthCredential({\n ctx,\n provider,\n scope: session.credentialScope,\n credentials: result.credentials,\n authStorage,\n memorySettings,\n onCredentialsChanged,\n });\n await (await sessionStore(ctx)).deleteLoginSession(sessionId);\n return c.json({ status: 'complete', ok: true });\n }\n\n if (result.status === 'failed') {\n await (await sessionStore(ctx)).deleteLoginSession(sessionId);\n return c.json({ status: 'failed', error: result.error });\n }\n\n await (\n await sessionStore(ctx)\n ).touchLoginSession(sessionId, {\n ...(result.pending ? { pending: result.pending } : {}),\n nextPollAt: new Date(now + result.nextPollMs),\n });\n return c.json({ status: 'pending', nextPollMs: result.nextPollMs });\n },\n }),\n\n registerApiRoute('/web/config/providers/:provider/oauth/session/:sessionId', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const ctx = await resolveCredentialContext({ c: loose(c), auth, credentials: modelCredentials });\n if ('response' in ctx) return ctx.response;\n\n const provider = c.req.param('provider');\n const sessionId = c.req.param('sessionId');\n const session = await loadOwnedSession({ ctx, provider, sessionId });\n if (session) await (await sessionStore(ctx)).deleteLoginSession(sessionId);\n return c.json({ ok: true });\n },\n }),\n\n registerApiRoute('/web/config/providers/:provider/oauth', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const ctx = await resolveCredentialContext({ c: loose(c), auth, credentials: modelCredentials });\n if ('response' in ctx) return ctx.response;\n\n const provider = c.req.param('provider');\n const authProviderId = getAuthProviderId(provider);\n // `?scope=org` removes the shared org credential (admin-only);\n // default removes the caller's personal credential only.\n const scope = c.req.query('scope') === 'org' ? 'org' : 'user';\n try {\n if (ctx.mode === 'tenant') {\n if (scope === 'org' && !(await auth.isOrganizationAdmin(loose(c), ctx.orgId))) {\n return c.json({ error: 'forbidden', message: 'Only org admins can remove an org-wide sign-in' }, 403);\n }\n const tenant = { orgId: ctx.orgId, ...(scope === 'org' ? {} : { userId: ctx.userId }) };\n await ctx.storage.removeCredential(tenant, authProviderId);\n onCredentialsChanged(tenant);\n } else {\n if (!authStorage) return c.json({ error: 'Credential storage is not available' }, 503);\n authStorage.logout(authProviderId);\n }\n return c.json({ ok: true });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n ];\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"surface.d.ts","sourceRoot":"","sources":["../../src/routes/surface.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"surface.d.ts","sourceRoot":"","sources":["../../src/routes/surface.ts"],"names":[],"mappings":"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"}
|
package/dist/routes/surface.js
CHANGED
|
@@ -197,9 +197,10 @@ function buildIntegrationContext(deps, integrationId) {
|
|
|
197
197
|
}
|
|
198
198
|
/**
|
|
199
199
|
* Disabled-status stub for the well-known integration ids. The SPA polls
|
|
200
|
-
* `/web/github/status
|
|
201
|
-
* integration is absent (or not ready) the status
|
|
202
|
-
* Unknown custom ids get no stub — the SPA doesn't
|
|
200
|
+
* `/web/github/status`, `/web/linear/status`, and `/web/jira/status`
|
|
201
|
+
* unconditionally, so when an integration is absent (or not ready) the status
|
|
202
|
+
* contract must still hold. Unknown custom ids get no stub — the SPA doesn't
|
|
203
|
+
* poll them.
|
|
203
204
|
*/
|
|
204
205
|
function disabledIntegrationStatusRoutes(deps, id, configured = false) {
|
|
205
206
|
if (id === "github") return [registerApiRoute("/web/github/status", {
|
|
@@ -234,6 +235,21 @@ function disabledIntegrationStatusRoutes(deps, id, configured = false) {
|
|
|
234
235
|
}
|
|
235
236
|
})
|
|
236
237
|
})];
|
|
238
|
+
if (id === "jira") return [registerApiRoute("/web/jira/status", {
|
|
239
|
+
method: "GET",
|
|
240
|
+
requiresAuth: false,
|
|
241
|
+
handler: (c) => c.json({
|
|
242
|
+
enabled: false,
|
|
243
|
+
configured,
|
|
244
|
+
site: null,
|
|
245
|
+
reason: "missing_config",
|
|
246
|
+
diagnostics: {
|
|
247
|
+
jiraConfigured: configured,
|
|
248
|
+
factoryAuthEnabled: deps.auth.enabled(),
|
|
249
|
+
appDbConfigured: deps.factoryStorage !== void 0
|
|
250
|
+
}
|
|
251
|
+
})
|
|
252
|
+
})];
|
|
237
253
|
return [];
|
|
238
254
|
}
|
|
239
255
|
/**
|
|
@@ -286,7 +302,11 @@ function assembleFactoryApiRoutes(deps) {
|
|
|
286
302
|
routes: integration.routes(context)
|
|
287
303
|
});
|
|
288
304
|
});
|
|
289
|
-
const absentStubs = [
|
|
305
|
+
const absentStubs = [
|
|
306
|
+
"github",
|
|
307
|
+
"linear",
|
|
308
|
+
"jira"
|
|
309
|
+
].filter((id) => !registrations.some(({ integration }) => integration.id === id)).flatMap((id) => disabledIntegrationStatusRoutes(deps, id));
|
|
290
310
|
const slackAbsentStubs = registrations.some(({ integration }) => integration.id === "slack") ? [] : absentSlackChannelAccountsRoutes();
|
|
291
311
|
const transitionService = deps.factoryReady ? deps.factoryTransitionService ?? new FactoryTransitionService({
|
|
292
312
|
configVersion: deps.configVersion,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"surface.js","names":[],"sources":["../../src/routes/surface.ts"],"sourcesContent":["import type { AuthStorage } from '@mastra/code-sdk/auth/storage';\nimport type { MastraCodeState } from '@mastra/code-sdk/schema';\nimport type { AgentController } from '@mastra/core/agent-controller';\nimport type { ApiRoute, IUserProvider } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { FactoryStorage } from '@mastra/core/storage';\n\nimport { boardForWorkItem } from '../boards/index.js';\nimport type { BoardRegistry } from '../boards/index.js';\nimport type { FactoryIntegration, IntegrationContext } from '../integrations/base.js';\nimport { getGithubFeatureDiagnostics } from '../integrations/github/config.js';\nimport type { GithubIntegration } from '../integrations/github/integration.js';\nimport { MaterializeError } from '../integrations/github/sandbox.js';\nimport { FactoryDispatchError } from '../rules/dispatch-errors.js';\nimport type { FactoryBindingPreparationInput } from '../rules/dispatcher.js';\nimport { FactoryStartCoordinator } from '../rules/start-coordinator.js';\nimport { FactoryTransitionService } from '../rules/transition-service.js';\nimport type { MastraFactorySandboxConfig } from '../sandbox/session-sandbox.js';\nimport {\n ensureFactorySourceSession,\n FactorySourceSessionResolutionError,\n resolveFactoryDefaultModelId,\n resolveFactoryProjectForSession,\n} from '../session/factory-session.js';\nimport type { EnsuredFactorySourceSession } from '../session/factory-session.js';\nimport type { LiveSessions } from '../session/live-sessions.js';\nimport type { StateSigner } from '../state-signing.js';\nimport type { AuditEmitter, AuditRecorder } from '../storage/domains/audit/domain.js';\nimport type { ChannelIdentityStorage } from '../storage/domains/channel-identity/base.js';\nimport type { WorkItemCommentsStorage } from '../storage/domains/comments/base.js';\nimport type { CommentsDomain } from '../storage/domains/comments/domain.js';\nimport type { ModelCredentialsStorage } from '../storage/domains/credentials/base.js';\nimport type { CustomProvidersStorage } from '../storage/domains/custom-providers/base.js';\nimport type { FilesystemStorage } from '../storage/domains/filesystem/base.js';\nimport type { IntakeStorage } from '../storage/domains/intake/base.js';\nimport type { IntegrationStorage } from '../storage/domains/integrations/base.js';\nimport type { MemorySettingsStorage } from '../storage/domains/memory-settings/base.js';\nimport type { ModelPacksStorage } from '../storage/domains/model-packs/base.js';\nimport type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';\nimport type { QueueHealthStorage } from '../storage/domains/queue-health/base.js';\nimport {\n SourceControlConnectionNotFoundError,\n type SourceControlStorage,\n} from '../storage/domains/source-control/base.js';\nimport {\n isAgentActor,\n type FactoryDispatchFailureCode,\n type WorkItemsStorage,\n} from '../storage/domains/work-items/base.js';\nimport { workItemBranch, workItemBranchSource, workItemThreadTitle } from '../work-item-branch.js';\nimport { buildAutomationRunRoutes } from './automation-runs.js';\nimport { ConfigRoutes } from './config.js';\nimport { invalidateCustomProvidersSnapshots } from './custom-provider-source.js';\nimport { buildFsRoutes } from './fs.js';\nimport { IntakeRoutes } from './intake.js';\nimport { KnowledgeRoutes } from './knowledge.js';\nimport { OAuthRoutes } from './oauth.js';\nimport type { RouteAuth } from './route.js';\nimport { SkillRoutes } from './skills.js';\nimport { invalidateTenantCredentialSnapshots } from './tenant-credentials.js';\nimport { WorkItemRoutes } from './work-items.js';\n\nconst MATERIALIZE_FAILURE_CODE = {\n 'git-missing': 'repository_git_missing',\n 'egress-blocked': 'repository_egress_blocked',\n 'clone-failed': 'repository_clone_failed',\n 'pull-failed': 'repository_pull_failed',\n 'push-failed': 'repository_push_failed',\n 'commit-failed': 'repository_commit_failed',\n 'gh-missing': 'repository_cli_missing',\n 'pr-failed': 'repository_pr_failed',\n} satisfies Record<MaterializeError['code'], FactoryDispatchFailureCode>;\nexport interface IntegrationRegistration {\n integration: FactoryIntegration;\n ready: boolean;\n ensureReady: () => Promise<void>;\n}\n\nexport interface FactoryApiRoutesDeps {\n controllerId: string;\n controller: AgentController<MastraCodeState>;\n /** Registry of the sessions this process holds, owned by the host so it can watch them too. */\n liveSessions: LiveSessions;\n /** Request-auth seam threaded from the host (no service locator). */\n auth: RouteAuth;\n /** Optional user directory for resolving persisted owners to display profiles. */\n users?: Pick<IUserProvider, 'getUser' | 'getUsers'>;\n authStorage: AuthStorage;\n audit: AuditEmitter & AuditRecorder;\n fsRoot?: string;\n publicOrigin: string;\n stateSigner?: StateSigner;\n /** Sandbox surface (enablement, provider label, create callback). */\n sandbox?: MastraFactorySandboxConfig;\n /** Root factory storage backend (distributed locks, app-db diagnostics). */\n factoryStorage?: FactoryStorage;\n integrationStorage: IntegrationStorage;\n sourceControlStorage: SourceControlStorage;\n /** App-table domain handles, registered and owned by `MastraFactory.prepare()`. */\n domains: {\n intake: IntakeStorage;\n modelCredentials: ModelCredentialsStorage;\n memorySettings: MemorySettingsStorage;\n customProviders: CustomProvidersStorage;\n filesystem: FilesystemStorage;\n modelPacks: ModelPacksStorage;\n projects: FactoryProjectsStorage;\n queueHealth: QueueHealthStorage;\n workItems: WorkItemsStorage;\n channelIdentity: ChannelIdentityStorage;\n comments: WorkItemCommentsStorage;\n };\n integrations?: IntegrationRegistration[];\n intakeReady: boolean;\n factoryReady: boolean;\n knowledgeEnabled: boolean;\n /** Resolved Factory rule set, threaded from the host (no service locator). */\n configVersion: string;\n /** Boards installed for this Factory instance. */\n boardRegistry: BoardRegistry;\n /** Work-item feed service, handed to integrations that ingest platform messages. */\n feed: CommentsDomain;\n factoryTransitionService?: FactoryTransitionService;\n sessionRetirement?: import('../sandbox/session-retirement.js').SessionRetirementCoordinator;\n onFactoryRuntime?: (runtime: {\n transitionService: FactoryTransitionService;\n prepareBinding?: (input: FactoryBindingPreparationInput) => Promise<void>;\n }) => void;\n}\n\nfunction guardIntegrationRoutes({\n integration,\n ready,\n ensureReady,\n routes,\n}: IntegrationRegistration & { routes: ApiRoute[] }): ApiRoute[] {\n if (ready) return routes;\n return routes.map(route => {\n if ('handler' in route) {\n const handler = route.handler;\n return {\n ...route,\n handler: async (context: Parameters<typeof handler>[0]) => {\n try {\n await ensureReady();\n } catch {\n return context.json(\n { error: 'integration_unavailable', message: `${integration.id} integration is unavailable.` },\n 503,\n );\n }\n return handler(context, async () => {});\n },\n };\n }\n\n const createHandler = route.createHandler;\n return {\n ...route,\n createHandler: async (args: Parameters<typeof createHandler>[0]) => {\n const handler = await createHandler(args);\n return async (context: Parameters<typeof handler>[0]) => {\n try {\n await ensureReady();\n } catch {\n return context.json(\n { error: 'integration_unavailable', message: `${integration.id} integration is unavailable.` },\n 503,\n );\n }\n return handler(context);\n };\n },\n };\n });\n}\n\n/**\n * Resolve the source-control session the work item already holds for this role,\n * when it still resolves to the item's org and factory project. Returns\n * `undefined` when there is no ref or the ref no longer resolves, so the caller\n * falls back to minting one.\n */\nasync function reuseBoundSession(\n sourceControl: GithubIntegration['sourceControlStorage'],\n input: FactoryBindingPreparationInput,\n): Promise<EnsuredFactorySourceSession | undefined> {\n const ref = input.item.sessions[input.role];\n if (!ref) return undefined;\n // At least as strict as the coordinator's resolveSourceSession: a ref it\n // would reject must fall through to minting, not hard-fail the run.\n const resolved = await resolveFactoryProjectForSession({ sourceControl, sessionId: ref.sessionId });\n if (\n !resolved ||\n resolved.orgId !== input.record.orgId ||\n resolved.factoryProjectId !== input.record.factoryProjectId\n ) {\n return undefined;\n }\n const session = await sourceControl.sessions.getBySessionId(ref.sessionId);\n if (!session) return undefined;\n return {\n sessionId: session.sessionId,\n userId: session.userId,\n projectRepositoryId: session.projectRepositoryId,\n branch: session.branch,\n baseBranch: session.baseBranch,\n };\n}\n\n/**\n * Start a factory run for a rule binding: ensure the source-control session the\n * coordinator requires, then hand it to `prepare` along with the factory's\n * default model. Exported for tests — this is the autonomous entry point with no\n * browser and no interactive user, so nothing else would catch a regression in\n * what it forwards.\n */\nexport async function prepareFactoryRuleBinding(\n github: GithubIntegration,\n coordinator: Pick<FactoryStartCoordinator, 'prepare'>,\n projects: FactoryProjectsStorage,\n boards: BoardRegistry,\n input: FactoryBindingPreparationInput,\n): Promise<void> {\n try {\n const source = workItemBranchSource(input.item.externalSource);\n const branch = workItemBranch({ id: input.item.id, source, metadata: input.item.metadata });\n // Only leaving a resting phase derives a lane from the role: roles don't own lanes,\n // and the Done close-out running in the triage seat must not drag the card back.\n // Both the current phase and the role's lane come from the installed board; an\n // unknown board or phase yields no destination rather than a guessed one.\n const board = boards.get(boardForWorkItem(input.item));\n const currentStage = input.item.stages.length === 1 ? input.item.stages[0] : undefined;\n const currentKind = currentStage === undefined ? undefined : board?.phaseKind(currentStage);\n const destinationStage =\n currentKind === undefined\n ? undefined\n : currentKind === 'resting'\n ? board?.phaseForRole(input.role)\n : currentStage;\n if (!destinationStage) {\n throw new FactoryDispatchError(\n 'unsupported_provider_item',\n `Factory skill invocation has no destination lane (role \"${input.role}\", stages [${input.item.stages.join(', ')}]).`,\n );\n }\n const repositorySlug =\n typeof input.item.metadata?.repository === 'string' ? input.item.metadata.repository : undefined;\n // Re-preparing a binding (server restart, retired controller session) must\n // land in the role's existing session: minting a replacement would repoint\n // the work item, flip the session's owner to the approver, and orphan the\n // previous sandbox.\n const approver = input.record.approvedBy ?? undefined;\n const preparedSession =\n (await reuseBoundSession(github.sourceControlStorage, input)) ??\n (await ensureFactorySourceSession({\n sourceControl: github.sourceControlStorage,\n orgId: input.record.orgId,\n factoryProjectId: input.record.factoryProjectId,\n repositorySlug,\n branch,\n // A person who approved the run is its interactive user: attribute it to\n // them, not the repo connector. An agent's pre-approval names no person.\n attributeToUserId: isAgentActor(approver) ? undefined : approver,\n }));\n\n await coordinator.prepare({\n orgId: input.record.orgId,\n userId: preparedSession.userId,\n factoryProjectId: input.record.factoryProjectId,\n sessionId: preparedSession.sessionId,\n defaultModelId: await resolveFactoryDefaultModelId(projects, input.record.factoryProjectId),\n threadTitle: workItemThreadTitle({ source, title: input.item.title, metadata: input.item.metadata }),\n kickoffKey: input.record.id,\n destinationStage,\n workItem: {\n id: input.item.id,\n role: input.role,\n input: {\n externalSource: input.item.externalSource,\n parentWorkItemId: input.item.parentWorkItemId,\n title: input.item.title,\n stages: ['intake'],\n sessions: input.item.sessions,\n metadata: input.item.metadata,\n },\n },\n });\n } catch (error) {\n if (error instanceof FactoryDispatchError) throw error;\n if (error instanceof FactorySourceSessionResolutionError) {\n const code = error.reason === 'connection' ? 'source_control_missing' : 'source_repository_missing';\n throw new FactoryDispatchError(code, error.message, { cause: error });\n }\n if (error instanceof SourceControlConnectionNotFoundError) {\n throw new FactoryDispatchError('source_control_missing', error.message, { cause: error });\n }\n if (error instanceof MaterializeError) {\n throw new FactoryDispatchError(MATERIALIZE_FAILURE_CODE[error.code], error.message, { cause: error });\n }\n throw error;\n }\n}\n\n/**\n * Build the {@link IntegrationContext} handed to an integration when the\n * factory collects its capabilities (routes, workers). One shape everywhere:\n * `assembleFactoryApiRoutes` uses it per registration, and `MastraFactory` uses it\n * when collecting integration workers at finalize.\n */\nexport function buildIntegrationContext(\n deps: Pick<\n FactoryApiRoutesDeps,\n | 'controller'\n | 'publicOrigin'\n | 'auth'\n | 'sandbox'\n | 'users'\n | 'factoryStorage'\n | 'integrationStorage'\n | 'sourceControlStorage'\n > & {\n stateSigner: StateSigner;\n emitAudit?: AuditEmitter['emit'];\n configVersion: string;\n boardRegistry: BoardRegistry;\n factoryReady: boolean;\n /** Work-item feed service, so a channel integration can ingest platform messages. */\n feed: CommentsDomain;\n domains: Pick<\n FactoryApiRoutesDeps['domains'],\n 'projects' | 'intake' | 'workItems' | 'channelIdentity' | 'memorySettings'\n >;\n /**\n * Stable id of the registered source-control-owning integration (today:\n * `'github'` when registered). Every call site must derive and pass it so\n * `routes()`, `channels()`, and `workers()` all see the same context shape.\n */\n sourceControlOwnerId?: string;\n },\n integrationId: string,\n): IntegrationContext {\n return {\n auth: deps.auth,\n sandbox: deps.sandbox,\n ...(deps.users ? { users: deps.users } : {}),\n factoryStorage: deps.factoryStorage,\n baseUrl: deps.publicOrigin,\n controller: deps.controller,\n stateSigner: deps.stateSigner,\n storage: {\n generic: deps.integrationStorage.forIntegration(integrationId),\n sourceControl: deps.sourceControlStorage.forIntegration(integrationId),\n ...(deps.sourceControlOwnerId\n ? { sourceControlOwner: deps.sourceControlStorage.forIntegration(deps.sourceControlOwnerId) }\n : {}),\n projects: deps.domains.projects,\n intake: deps.domains.intake,\n channelIdentity: deps.domains.channelIdentity,\n memorySettings: deps.domains.memorySettings,\n },\n ...(deps.factoryReady ? { workItems: deps.domains.workItems, feed: deps.feed } : {}),\n ...(deps.factoryReady\n ? {\n runtime: { configVersion: deps.configVersion, workItems: deps.domains.workItems, boards: deps.boardRegistry },\n }\n : {}),\n ...(deps.emitAudit ? { hooks: { emitAudit: deps.emitAudit } } : {}),\n };\n}\n\n/**\n * Disabled-status stub for the well-known integration ids. The SPA polls\n * `/web/github/status` and `/web/linear/status` unconditionally, so when an\n * integration is absent (or not ready) the status contract must still hold.\n * Unknown custom ids get no stub — the SPA doesn't poll them.\n */\nfunction disabledIntegrationStatusRoutes(deps: FactoryApiRoutesDeps, id: string, configured = false): ApiRoute[] {\n if (id === 'github') {\n return [\n registerApiRoute('/web/github/status', {\n method: 'GET',\n requiresAuth: false,\n handler: c =>\n c.json({\n enabled: false,\n connected: false,\n installations: [],\n reason: 'missing_config',\n diagnostics: getGithubFeatureDiagnostics({\n github: undefined,\n auth: deps.auth,\n appDbConfigured: deps.factoryStorage !== undefined,\n stateSigner: deps.stateSigner,\n sandbox: deps.sandbox,\n }),\n }),\n }),\n ];\n }\n if (id === 'linear') {\n return [\n registerApiRoute('/web/linear/status', {\n method: 'GET',\n requiresAuth: false,\n handler: c =>\n c.json({\n enabled: false,\n connected: false,\n workspace: null,\n reason: 'missing_config',\n diagnostics: {\n linearAppConfigured: configured,\n factoryAuthEnabled: deps.auth.enabled(),\n appDbConfigured: true,\n },\n }),\n }),\n ];\n }\n return [];\n}\n\n/**\n * Stub for `GET /web/channel-accounts` when NO Slack integration is\n * registered. The SPA's Connections section polls the path unconditionally;\n * without a stub the SPA fallback serves HTML, which the UI can only read as\n * \"old server / unknown\". The machine-readable reason lets it say the truth:\n * the integration isn't registered.\n *\n * Mounted only for ABSENT slack — a registered integration owns the path via\n * its connect routes (or, when the state signer is unstable, gets no routes\n * at all and the UI falls back to the generic copy). Static payload, leaks\n * nothing → no auth needed, same posture as the github/linear stubs.\n */\nfunction absentSlackChannelAccountsRoutes(): ApiRoute[] {\n return [\n registerApiRoute('/web/channel-accounts', {\n method: 'GET',\n requiresAuth: false,\n handler: c => c.json({ accounts: [], canConnect: false, reason: 'not_registered' }),\n }),\n ];\n}\n\n/**\n * Assemble the custom `/web/*` API routes as Mastra `server.apiRoutes`:\n * - fs browser routes (project picker), confined to `fsRoot`\n * - config routes (provider/API-key/model-pack/OM management)\n * - every registered integration's `routes()` surface (full set when ready,\n * disabled-status stub otherwise), plus stubs for absent known ids\n */\nexport function assembleFactoryApiRoutes(deps: FactoryApiRoutesDeps): ApiRoute[] {\n const emitAudit: AuditEmitter['emit'] = args => deps.audit.emit(args);\n const registrations = deps.integrations ?? [];\n const githubRegistration = registrations.find(({ integration }) => integration.id === 'github');\n const githubStorage = githubRegistration ? deps.sourceControlStorage.forIntegration('github') : undefined;\n const githubIntegration = githubRegistration?.integration as GithubIntegration | undefined;\n\n const integrationRoutes = registrations.flatMap(registration => {\n const { integration } = registration;\n if (!deps.stateSigner) return disabledIntegrationStatusRoutes(deps, integration.id, true);\n const context = buildIntegrationContext(\n {\n ...deps,\n stateSigner: deps.stateSigner,\n emitAudit,\n ...(githubRegistration ? { sourceControlOwnerId: 'github' } : {}),\n },\n integration.id,\n );\n return guardIntegrationRoutes({ ...registration, routes: integration.routes(context) });\n });\n // Absent known integrations still get their disabled-status stub.\n const absentStubs = ['github', 'linear']\n .filter(id => !registrations.some(({ integration }) => integration.id === id))\n .flatMap(id => disabledIntegrationStatusRoutes(deps, id));\n // Absent slack gets the channel-accounts not-registered stub (registered\n // slack owns the path via its own connect routes).\n const slackAbsentStubs = registrations.some(({ integration }) => integration.id === 'slack')\n ? []\n : absentSlackChannelAccountsRoutes();\n\n const transitionService = deps.factoryReady\n ? (deps.factoryTransitionService ??\n new FactoryTransitionService({\n configVersion: deps.configVersion,\n boards: deps.boardRegistry,\n storage: deps.domains.workItems,\n audit: deps.audit,\n }))\n : undefined;\n const startCoordinator = transitionService\n ? new FactoryStartCoordinator(\n deps.controller,\n deps.domains.workItems,\n transitionService,\n githubIntegration?.sourceControlStorage,\n deps.domains.memorySettings,\n )\n : undefined;\n if (transitionService && startCoordinator) {\n deps.onFactoryRuntime?.({\n transitionService,\n ...(githubIntegration\n ? {\n prepareBinding: (input: FactoryBindingPreparationInput) =>\n prepareFactoryRuleBinding(\n githubIntegration,\n startCoordinator,\n deps.domains.projects,\n deps.boardRegistry,\n input,\n ),\n }\n : {}),\n });\n }\n\n return [\n ...buildFsRoutes({\n root: deps.fsRoot,\n sessionFs: {\n auth: deps.auth,\n sessions: deps.sourceControlStorage.forIntegration('github').sessions,\n filesystem: deps.domains.filesystem,\n },\n }),\n ...new ConfigRoutes({\n auth: deps.auth,\n controller: deps.controller,\n authStorage: deps.authStorage,\n modelCredentials: deps.domains.modelCredentials,\n modelPacks: deps.domains.modelPacks,\n sourceControlSessions: deps.sourceControlStorage.forIntegration('github').sessions,\n memorySettings: deps.domains.memorySettings,\n factoryProjects: deps.domains.projects,\n customProviders: deps.domains.customProviders,\n features: { knowledge: deps.knowledgeEnabled },\n onCredentialsChanged: invalidateTenantCredentialSnapshots,\n onCustomProvidersChanged: invalidateCustomProvidersSnapshots,\n }).routes(),\n ...new OAuthRoutes({\n auth: deps.auth,\n authStorage: deps.authStorage,\n modelCredentials: deps.domains.modelCredentials,\n memorySettings: deps.domains.memorySettings,\n onCredentialsChanged: invalidateTenantCredentialSnapshots,\n }).routes(),\n ...new SkillRoutes({\n auth: deps.auth,\n controllerId: deps.controllerId,\n controller: deps.controller,\n sourceControlStorage: githubStorage,\n ensureSourceControlReady: githubRegistration?.ensureReady,\n }).routes(),\n ...integrationRoutes,\n ...absentStubs,\n ...slackAbsentStubs,\n ...(deps.intakeReady\n ? new IntakeRoutes({\n auth: deps.auth,\n audit: deps.audit,\n intake: deps.domains.intake,\n projects: deps.domains.projects,\n boardRegistry: deps.boardRegistry,\n // Relocation reads and writes work items, which init fail-soft separately from intake.\n ...(deps.factoryReady ? { workItems: deps.domains.workItems } : {}),\n integrations: (deps.integrations ?? []).flatMap(({ integration }) =>\n integration.intake ? [{ id: integration.id, intake: integration.intake }] : [],\n ),\n }).routes()\n : []),\n ...(deps.factoryReady && deps.knowledgeEnabled\n ? new KnowledgeRoutes({\n auth: deps.auth,\n projects: deps.domains.projects,\n knowledge: async () => deps.factoryStorage?.getMastraStorage().getStore('knowledge'),\n }).routes()\n : []),\n ...(deps.factoryReady\n ? new WorkItemRoutes({\n auth: deps.auth,\n audit: deps.audit,\n projects: deps.domains.projects,\n workItems: deps.domains.workItems,\n boardRegistry: deps.boardRegistry,\n comments: deps.domains.comments,\n queueHealth: deps.domains.queueHealth,\n transitionService,\n startCoordinator,\n liveSessions: deps.liveSessions,\n }).routes()\n : []),\n ...(deps.factoryReady\n ? buildAutomationRunRoutes({\n auth: deps.auth,\n audit: deps.audit,\n projects: deps.domains.projects,\n workItems: deps.domains.workItems,\n configVersion: deps.configVersion,\n })\n : []),\n ];\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"surface.js","names":[],"sources":["../../src/routes/surface.ts"],"sourcesContent":["import type { AuthStorage } from '@mastra/code-sdk/auth/storage';\nimport type { MastraCodeState } from '@mastra/code-sdk/schema';\nimport type { AgentController } from '@mastra/core/agent-controller';\nimport type { ApiRoute, IUserProvider } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { FactoryStorage } from '@mastra/core/storage';\n\nimport { boardForWorkItem } from '../boards/index.js';\nimport type { BoardRegistry } from '../boards/index.js';\nimport type { FactoryIntegration, IntegrationContext } from '../integrations/base.js';\nimport { getGithubFeatureDiagnostics } from '../integrations/github/config.js';\nimport type { GithubIntegration } from '../integrations/github/integration.js';\nimport { MaterializeError } from '../integrations/github/sandbox.js';\nimport { FactoryDispatchError } from '../rules/dispatch-errors.js';\nimport type { FactoryBindingPreparationInput } from '../rules/dispatcher.js';\nimport { FactoryStartCoordinator } from '../rules/start-coordinator.js';\nimport { FactoryTransitionService } from '../rules/transition-service.js';\nimport type { MastraFactorySandboxConfig } from '../sandbox/session-sandbox.js';\nimport {\n ensureFactorySourceSession,\n FactorySourceSessionResolutionError,\n resolveFactoryDefaultModelId,\n resolveFactoryProjectForSession,\n} from '../session/factory-session.js';\nimport type { EnsuredFactorySourceSession } from '../session/factory-session.js';\nimport type { LiveSessions } from '../session/live-sessions.js';\nimport type { StateSigner } from '../state-signing.js';\nimport type { AuditEmitter, AuditRecorder } from '../storage/domains/audit/domain.js';\nimport type { ChannelIdentityStorage } from '../storage/domains/channel-identity/base.js';\nimport type { WorkItemCommentsStorage } from '../storage/domains/comments/base.js';\nimport type { CommentsDomain } from '../storage/domains/comments/domain.js';\nimport type { ModelCredentialsStorage } from '../storage/domains/credentials/base.js';\nimport type { CustomProvidersStorage } from '../storage/domains/custom-providers/base.js';\nimport type { FilesystemStorage } from '../storage/domains/filesystem/base.js';\nimport type { IntakeStorage } from '../storage/domains/intake/base.js';\nimport type { IntegrationStorage } from '../storage/domains/integrations/base.js';\nimport type { MemorySettingsStorage } from '../storage/domains/memory-settings/base.js';\nimport type { ModelPacksStorage } from '../storage/domains/model-packs/base.js';\nimport type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';\nimport type { QueueHealthStorage } from '../storage/domains/queue-health/base.js';\nimport {\n SourceControlConnectionNotFoundError,\n type SourceControlStorage,\n} from '../storage/domains/source-control/base.js';\nimport {\n isAgentActor,\n type FactoryDispatchFailureCode,\n type WorkItemsStorage,\n} from '../storage/domains/work-items/base.js';\nimport { workItemBranch, workItemBranchSource, workItemThreadTitle } from '../work-item-branch.js';\nimport { buildAutomationRunRoutes } from './automation-runs.js';\nimport { ConfigRoutes } from './config.js';\nimport { invalidateCustomProvidersSnapshots } from './custom-provider-source.js';\nimport { buildFsRoutes } from './fs.js';\nimport { IntakeRoutes } from './intake.js';\nimport { KnowledgeRoutes } from './knowledge.js';\nimport { OAuthRoutes } from './oauth.js';\nimport type { RouteAuth } from './route.js';\nimport { SkillRoutes } from './skills.js';\nimport { invalidateTenantCredentialSnapshots } from './tenant-credentials.js';\nimport { WorkItemRoutes } from './work-items.js';\n\nconst MATERIALIZE_FAILURE_CODE = {\n 'git-missing': 'repository_git_missing',\n 'egress-blocked': 'repository_egress_blocked',\n 'clone-failed': 'repository_clone_failed',\n 'pull-failed': 'repository_pull_failed',\n 'push-failed': 'repository_push_failed',\n 'commit-failed': 'repository_commit_failed',\n 'gh-missing': 'repository_cli_missing',\n 'pr-failed': 'repository_pr_failed',\n} satisfies Record<MaterializeError['code'], FactoryDispatchFailureCode>;\nexport interface IntegrationRegistration {\n integration: FactoryIntegration;\n ready: boolean;\n ensureReady: () => Promise<void>;\n}\n\nexport interface FactoryApiRoutesDeps {\n controllerId: string;\n controller: AgentController<MastraCodeState>;\n /** Registry of the sessions this process holds, owned by the host so it can watch them too. */\n liveSessions: LiveSessions;\n /** Request-auth seam threaded from the host (no service locator). */\n auth: RouteAuth;\n /** Optional user directory for resolving persisted owners to display profiles. */\n users?: Pick<IUserProvider, 'getUser' | 'getUsers'>;\n authStorage: AuthStorage;\n audit: AuditEmitter & AuditRecorder;\n fsRoot?: string;\n publicOrigin: string;\n stateSigner?: StateSigner;\n /** Sandbox surface (enablement, provider label, create callback). */\n sandbox?: MastraFactorySandboxConfig;\n /** Root factory storage backend (distributed locks, app-db diagnostics). */\n factoryStorage?: FactoryStorage;\n integrationStorage: IntegrationStorage;\n sourceControlStorage: SourceControlStorage;\n /** App-table domain handles, registered and owned by `MastraFactory.prepare()`. */\n domains: {\n intake: IntakeStorage;\n modelCredentials: ModelCredentialsStorage;\n memorySettings: MemorySettingsStorage;\n customProviders: CustomProvidersStorage;\n filesystem: FilesystemStorage;\n modelPacks: ModelPacksStorage;\n projects: FactoryProjectsStorage;\n queueHealth: QueueHealthStorage;\n workItems: WorkItemsStorage;\n channelIdentity: ChannelIdentityStorage;\n comments: WorkItemCommentsStorage;\n };\n integrations?: IntegrationRegistration[];\n intakeReady: boolean;\n factoryReady: boolean;\n knowledgeEnabled: boolean;\n /** Resolved Factory rule set, threaded from the host (no service locator). */\n configVersion: string;\n /** Boards installed for this Factory instance. */\n boardRegistry: BoardRegistry;\n /** Work-item feed service, handed to integrations that ingest platform messages. */\n feed: CommentsDomain;\n factoryTransitionService?: FactoryTransitionService;\n sessionRetirement?: import('../sandbox/session-retirement.js').SessionRetirementCoordinator;\n onFactoryRuntime?: (runtime: {\n transitionService: FactoryTransitionService;\n prepareBinding?: (input: FactoryBindingPreparationInput) => Promise<void>;\n }) => void;\n}\n\nfunction guardIntegrationRoutes({\n integration,\n ready,\n ensureReady,\n routes,\n}: IntegrationRegistration & { routes: ApiRoute[] }): ApiRoute[] {\n if (ready) return routes;\n return routes.map(route => {\n if ('handler' in route) {\n const handler = route.handler;\n return {\n ...route,\n handler: async (context: Parameters<typeof handler>[0]) => {\n try {\n await ensureReady();\n } catch {\n return context.json(\n { error: 'integration_unavailable', message: `${integration.id} integration is unavailable.` },\n 503,\n );\n }\n return handler(context, async () => {});\n },\n };\n }\n\n const createHandler = route.createHandler;\n return {\n ...route,\n createHandler: async (args: Parameters<typeof createHandler>[0]) => {\n const handler = await createHandler(args);\n return async (context: Parameters<typeof handler>[0]) => {\n try {\n await ensureReady();\n } catch {\n return context.json(\n { error: 'integration_unavailable', message: `${integration.id} integration is unavailable.` },\n 503,\n );\n }\n return handler(context);\n };\n },\n };\n });\n}\n\n/**\n * Resolve the source-control session the work item already holds for this role,\n * when it still resolves to the item's org and factory project. Returns\n * `undefined` when there is no ref or the ref no longer resolves, so the caller\n * falls back to minting one.\n */\nasync function reuseBoundSession(\n sourceControl: GithubIntegration['sourceControlStorage'],\n input: FactoryBindingPreparationInput,\n): Promise<EnsuredFactorySourceSession | undefined> {\n const ref = input.item.sessions[input.role];\n if (!ref) return undefined;\n // At least as strict as the coordinator's resolveSourceSession: a ref it\n // would reject must fall through to minting, not hard-fail the run.\n const resolved = await resolveFactoryProjectForSession({ sourceControl, sessionId: ref.sessionId });\n if (\n !resolved ||\n resolved.orgId !== input.record.orgId ||\n resolved.factoryProjectId !== input.record.factoryProjectId\n ) {\n return undefined;\n }\n const session = await sourceControl.sessions.getBySessionId(ref.sessionId);\n if (!session) return undefined;\n return {\n sessionId: session.sessionId,\n userId: session.userId,\n projectRepositoryId: session.projectRepositoryId,\n branch: session.branch,\n baseBranch: session.baseBranch,\n };\n}\n\n/**\n * Start a factory run for a rule binding: ensure the source-control session the\n * coordinator requires, then hand it to `prepare` along with the factory's\n * default model. Exported for tests — this is the autonomous entry point with no\n * browser and no interactive user, so nothing else would catch a regression in\n * what it forwards.\n */\nexport async function prepareFactoryRuleBinding(\n github: GithubIntegration,\n coordinator: Pick<FactoryStartCoordinator, 'prepare'>,\n projects: FactoryProjectsStorage,\n boards: BoardRegistry,\n input: FactoryBindingPreparationInput,\n): Promise<void> {\n try {\n const source = workItemBranchSource(input.item.externalSource);\n const branch = workItemBranch({ id: input.item.id, source, metadata: input.item.metadata });\n // Only leaving a resting phase derives a lane from the role: roles don't own lanes,\n // and the Done close-out running in the triage seat must not drag the card back.\n // Both the current phase and the role's lane come from the installed board; an\n // unknown board or phase yields no destination rather than a guessed one.\n const board = boards.get(boardForWorkItem(input.item));\n const currentStage = input.item.stages.length === 1 ? input.item.stages[0] : undefined;\n const currentKind = currentStage === undefined ? undefined : board?.phaseKind(currentStage);\n const destinationStage =\n currentKind === undefined\n ? undefined\n : currentKind === 'resting'\n ? board?.phaseForRole(input.role)\n : currentStage;\n if (!destinationStage) {\n throw new FactoryDispatchError(\n 'unsupported_provider_item',\n `Factory skill invocation has no destination lane (role \"${input.role}\", stages [${input.item.stages.join(', ')}]).`,\n );\n }\n const repositorySlug =\n typeof input.item.metadata?.repository === 'string' ? input.item.metadata.repository : undefined;\n // Re-preparing a binding (server restart, retired controller session) must\n // land in the role's existing session: minting a replacement would repoint\n // the work item, flip the session's owner to the approver, and orphan the\n // previous sandbox.\n const approver = input.record.approvedBy ?? undefined;\n const preparedSession =\n (await reuseBoundSession(github.sourceControlStorage, input)) ??\n (await ensureFactorySourceSession({\n sourceControl: github.sourceControlStorage,\n orgId: input.record.orgId,\n factoryProjectId: input.record.factoryProjectId,\n repositorySlug,\n branch,\n // A person who approved the run is its interactive user: attribute it to\n // them, not the repo connector. An agent's pre-approval names no person.\n attributeToUserId: isAgentActor(approver) ? undefined : approver,\n }));\n\n await coordinator.prepare({\n orgId: input.record.orgId,\n userId: preparedSession.userId,\n factoryProjectId: input.record.factoryProjectId,\n sessionId: preparedSession.sessionId,\n defaultModelId: await resolveFactoryDefaultModelId(projects, input.record.factoryProjectId),\n threadTitle: workItemThreadTitle({ source, title: input.item.title, metadata: input.item.metadata }),\n kickoffKey: input.record.id,\n destinationStage,\n workItem: {\n id: input.item.id,\n role: input.role,\n input: {\n externalSource: input.item.externalSource,\n parentWorkItemId: input.item.parentWorkItemId,\n title: input.item.title,\n stages: ['intake'],\n sessions: input.item.sessions,\n metadata: input.item.metadata,\n },\n },\n });\n } catch (error) {\n if (error instanceof FactoryDispatchError) throw error;\n if (error instanceof FactorySourceSessionResolutionError) {\n const code = error.reason === 'connection' ? 'source_control_missing' : 'source_repository_missing';\n throw new FactoryDispatchError(code, error.message, { cause: error });\n }\n if (error instanceof SourceControlConnectionNotFoundError) {\n throw new FactoryDispatchError('source_control_missing', error.message, { cause: error });\n }\n if (error instanceof MaterializeError) {\n throw new FactoryDispatchError(MATERIALIZE_FAILURE_CODE[error.code], error.message, { cause: error });\n }\n throw error;\n }\n}\n\n/**\n * Build the {@link IntegrationContext} handed to an integration when the\n * factory collects its capabilities (routes, workers). One shape everywhere:\n * `assembleFactoryApiRoutes` uses it per registration, and `MastraFactory` uses it\n * when collecting integration workers at finalize.\n */\nexport function buildIntegrationContext(\n deps: Pick<\n FactoryApiRoutesDeps,\n | 'controller'\n | 'publicOrigin'\n | 'auth'\n | 'sandbox'\n | 'users'\n | 'factoryStorage'\n | 'integrationStorage'\n | 'sourceControlStorage'\n > & {\n stateSigner: StateSigner;\n emitAudit?: AuditEmitter['emit'];\n configVersion: string;\n boardRegistry: BoardRegistry;\n factoryReady: boolean;\n /** Work-item feed service, so a channel integration can ingest platform messages. */\n feed: CommentsDomain;\n domains: Pick<\n FactoryApiRoutesDeps['domains'],\n 'projects' | 'intake' | 'workItems' | 'channelIdentity' | 'memorySettings'\n >;\n /**\n * Stable id of the registered source-control-owning integration (today:\n * `'github'` when registered). Every call site must derive and pass it so\n * `routes()`, `channels()`, and `workers()` all see the same context shape.\n */\n sourceControlOwnerId?: string;\n },\n integrationId: string,\n): IntegrationContext {\n return {\n auth: deps.auth,\n sandbox: deps.sandbox,\n ...(deps.users ? { users: deps.users } : {}),\n factoryStorage: deps.factoryStorage,\n baseUrl: deps.publicOrigin,\n controller: deps.controller,\n stateSigner: deps.stateSigner,\n storage: {\n generic: deps.integrationStorage.forIntegration(integrationId),\n sourceControl: deps.sourceControlStorage.forIntegration(integrationId),\n ...(deps.sourceControlOwnerId\n ? { sourceControlOwner: deps.sourceControlStorage.forIntegration(deps.sourceControlOwnerId) }\n : {}),\n projects: deps.domains.projects,\n intake: deps.domains.intake,\n channelIdentity: deps.domains.channelIdentity,\n memorySettings: deps.domains.memorySettings,\n },\n ...(deps.factoryReady ? { workItems: deps.domains.workItems, feed: deps.feed } : {}),\n ...(deps.factoryReady\n ? {\n runtime: { configVersion: deps.configVersion, workItems: deps.domains.workItems, boards: deps.boardRegistry },\n }\n : {}),\n ...(deps.emitAudit ? { hooks: { emitAudit: deps.emitAudit } } : {}),\n };\n}\n\n/**\n * Disabled-status stub for the well-known integration ids. The SPA polls\n * `/web/github/status`, `/web/linear/status`, and `/web/jira/status`\n * unconditionally, so when an integration is absent (or not ready) the status\n * contract must still hold. Unknown custom ids get no stub — the SPA doesn't\n * poll them.\n */\nfunction disabledIntegrationStatusRoutes(deps: FactoryApiRoutesDeps, id: string, configured = false): ApiRoute[] {\n if (id === 'github') {\n return [\n registerApiRoute('/web/github/status', {\n method: 'GET',\n requiresAuth: false,\n handler: c =>\n c.json({\n enabled: false,\n connected: false,\n installations: [],\n reason: 'missing_config',\n diagnostics: getGithubFeatureDiagnostics({\n github: undefined,\n auth: deps.auth,\n appDbConfigured: deps.factoryStorage !== undefined,\n stateSigner: deps.stateSigner,\n sandbox: deps.sandbox,\n }),\n }),\n }),\n ];\n }\n if (id === 'linear') {\n return [\n registerApiRoute('/web/linear/status', {\n method: 'GET',\n requiresAuth: false,\n handler: c =>\n c.json({\n enabled: false,\n connected: false,\n workspace: null,\n reason: 'missing_config',\n diagnostics: {\n linearAppConfigured: configured,\n factoryAuthEnabled: deps.auth.enabled(),\n appDbConfigured: true,\n },\n }),\n }),\n ];\n }\n if (id === 'jira') {\n return [\n registerApiRoute('/web/jira/status', {\n method: 'GET',\n requiresAuth: false,\n handler: c =>\n c.json({\n enabled: false,\n configured,\n site: null,\n reason: 'missing_config',\n diagnostics: {\n jiraConfigured: configured,\n factoryAuthEnabled: deps.auth.enabled(),\n appDbConfigured: deps.factoryStorage !== undefined,\n },\n }),\n }),\n ];\n }\n return [];\n}\n\n/**\n * Stub for `GET /web/channel-accounts` when NO Slack integration is\n * registered. The SPA's Connections section polls the path unconditionally;\n * without a stub the SPA fallback serves HTML, which the UI can only read as\n * \"old server / unknown\". The machine-readable reason lets it say the truth:\n * the integration isn't registered.\n *\n * Mounted only for ABSENT slack — a registered integration owns the path via\n * its connect routes (or, when the state signer is unstable, gets no routes\n * at all and the UI falls back to the generic copy). Static payload, leaks\n * nothing → no auth needed, same posture as the github/linear stubs.\n */\nfunction absentSlackChannelAccountsRoutes(): ApiRoute[] {\n return [\n registerApiRoute('/web/channel-accounts', {\n method: 'GET',\n requiresAuth: false,\n handler: c => c.json({ accounts: [], canConnect: false, reason: 'not_registered' }),\n }),\n ];\n}\n\n/**\n * Assemble the custom `/web/*` API routes as Mastra `server.apiRoutes`:\n * - fs browser routes (project picker), confined to `fsRoot`\n * - config routes (provider/API-key/model-pack/OM management)\n * - every registered integration's `routes()` surface (full set when ready,\n * disabled-status stub otherwise), plus stubs for absent known ids\n */\nexport function assembleFactoryApiRoutes(deps: FactoryApiRoutesDeps): ApiRoute[] {\n const emitAudit: AuditEmitter['emit'] = args => deps.audit.emit(args);\n const registrations = deps.integrations ?? [];\n const githubRegistration = registrations.find(({ integration }) => integration.id === 'github');\n const githubStorage = githubRegistration ? deps.sourceControlStorage.forIntegration('github') : undefined;\n const githubIntegration = githubRegistration?.integration as GithubIntegration | undefined;\n\n const integrationRoutes = registrations.flatMap(registration => {\n const { integration } = registration;\n if (!deps.stateSigner) return disabledIntegrationStatusRoutes(deps, integration.id, true);\n const context = buildIntegrationContext(\n {\n ...deps,\n stateSigner: deps.stateSigner,\n emitAudit,\n ...(githubRegistration ? { sourceControlOwnerId: 'github' } : {}),\n },\n integration.id,\n );\n return guardIntegrationRoutes({ ...registration, routes: integration.routes(context) });\n });\n // Absent known integrations still get their disabled-status stub.\n const absentStubs = ['github', 'linear', 'jira']\n .filter(id => !registrations.some(({ integration }) => integration.id === id))\n .flatMap(id => disabledIntegrationStatusRoutes(deps, id));\n // Absent slack gets the channel-accounts not-registered stub (registered\n // slack owns the path via its own connect routes).\n const slackAbsentStubs = registrations.some(({ integration }) => integration.id === 'slack')\n ? []\n : absentSlackChannelAccountsRoutes();\n\n const transitionService = deps.factoryReady\n ? (deps.factoryTransitionService ??\n new FactoryTransitionService({\n configVersion: deps.configVersion,\n boards: deps.boardRegistry,\n storage: deps.domains.workItems,\n audit: deps.audit,\n }))\n : undefined;\n const startCoordinator = transitionService\n ? new FactoryStartCoordinator(\n deps.controller,\n deps.domains.workItems,\n transitionService,\n githubIntegration?.sourceControlStorage,\n deps.domains.memorySettings,\n )\n : undefined;\n if (transitionService && startCoordinator) {\n deps.onFactoryRuntime?.({\n transitionService,\n ...(githubIntegration\n ? {\n prepareBinding: (input: FactoryBindingPreparationInput) =>\n prepareFactoryRuleBinding(\n githubIntegration,\n startCoordinator,\n deps.domains.projects,\n deps.boardRegistry,\n input,\n ),\n }\n : {}),\n });\n }\n\n return [\n ...buildFsRoutes({\n root: deps.fsRoot,\n sessionFs: {\n auth: deps.auth,\n sessions: deps.sourceControlStorage.forIntegration('github').sessions,\n filesystem: deps.domains.filesystem,\n },\n }),\n ...new ConfigRoutes({\n auth: deps.auth,\n controller: deps.controller,\n authStorage: deps.authStorage,\n modelCredentials: deps.domains.modelCredentials,\n modelPacks: deps.domains.modelPacks,\n sourceControlSessions: deps.sourceControlStorage.forIntegration('github').sessions,\n memorySettings: deps.domains.memorySettings,\n factoryProjects: deps.domains.projects,\n customProviders: deps.domains.customProviders,\n features: { knowledge: deps.knowledgeEnabled },\n onCredentialsChanged: invalidateTenantCredentialSnapshots,\n onCustomProvidersChanged: invalidateCustomProvidersSnapshots,\n }).routes(),\n ...new OAuthRoutes({\n auth: deps.auth,\n authStorage: deps.authStorage,\n modelCredentials: deps.domains.modelCredentials,\n memorySettings: deps.domains.memorySettings,\n onCredentialsChanged: invalidateTenantCredentialSnapshots,\n }).routes(),\n ...new SkillRoutes({\n auth: deps.auth,\n controllerId: deps.controllerId,\n controller: deps.controller,\n sourceControlStorage: githubStorage,\n ensureSourceControlReady: githubRegistration?.ensureReady,\n }).routes(),\n ...integrationRoutes,\n ...absentStubs,\n ...slackAbsentStubs,\n ...(deps.intakeReady\n ? new IntakeRoutes({\n auth: deps.auth,\n audit: deps.audit,\n intake: deps.domains.intake,\n projects: deps.domains.projects,\n boardRegistry: deps.boardRegistry,\n // Relocation reads and writes work items, which init fail-soft separately from intake.\n ...(deps.factoryReady ? { workItems: deps.domains.workItems } : {}),\n integrations: (deps.integrations ?? []).flatMap(({ integration }) =>\n integration.intake ? [{ id: integration.id, intake: integration.intake }] : [],\n ),\n }).routes()\n : []),\n ...(deps.factoryReady && deps.knowledgeEnabled\n ? new KnowledgeRoutes({\n auth: deps.auth,\n projects: deps.domains.projects,\n knowledge: async () => deps.factoryStorage?.getMastraStorage().getStore('knowledge'),\n }).routes()\n : []),\n ...(deps.factoryReady\n ? new WorkItemRoutes({\n auth: deps.auth,\n audit: deps.audit,\n projects: deps.domains.projects,\n workItems: deps.domains.workItems,\n boardRegistry: deps.boardRegistry,\n comments: deps.domains.comments,\n queueHealth: deps.domains.queueHealth,\n transitionService,\n startCoordinator,\n liveSessions: deps.liveSessions,\n }).routes()\n : []),\n ...(deps.factoryReady\n ? buildAutomationRunRoutes({\n auth: deps.auth,\n audit: deps.audit,\n projects: deps.domains.projects,\n workItems: deps.domains.workItems,\n configVersion: deps.configVersion,\n })\n : []),\n ];\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch-errors.d.ts","sourceRoot":"","sources":["../../src/rules/dispatch-errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,gCAAgC,EACjC,MAAM,uCAAuC,CAAC;AAE/C,UAAU,8BAA8B;IACtC,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;
|
|
1
|
+
{"version":3,"file":"dispatch-errors.d.ts","sourceRoot":"","sources":["../../src/rules/dispatch-errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,gCAAgC,EACjC,MAAM,uCAAuC,CAAC;AAE/C,UAAU,8BAA8B;IACtC,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AA0BD,qBAAa,oBAAqB,SAAQ,KAAK;IAE3C,QAAQ,CAAC,IAAI,EAAE,0BAA0B;gBAAhC,IAAI,EAAE,0BAA0B,EACzC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,YAAY;CAKzB;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,0BAA0B,CAErF;AAED,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,gCAAgC,GAAG,IAAI,GAC5C,8BAA8B,CAEhC"}
|
|
@@ -20,6 +20,14 @@ const FAILURE_METADATA = {
|
|
|
20
20
|
canRetry: true,
|
|
21
21
|
label: "Factory message delivery failed"
|
|
22
22
|
},
|
|
23
|
+
run_terminal_event_missing: {
|
|
24
|
+
canRetry: false,
|
|
25
|
+
label: "Agent run terminal event was not observed"
|
|
26
|
+
},
|
|
27
|
+
skill_delivery_ambiguous: {
|
|
28
|
+
canRetry: false,
|
|
29
|
+
label: "Factory skill delivery could not be confirmed"
|
|
30
|
+
},
|
|
23
31
|
run_overdue: {
|
|
24
32
|
canRetry: false,
|
|
25
33
|
label: "Agent run is overdue"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch-errors.js","names":[],"sources":["../../src/rules/dispatch-errors.ts"],"sourcesContent":["import type {\n FactoryDispatchFailureCode,\n StoredFactoryDispatchFailureCode,\n} from '../storage/domains/work-items/base.js';\n\ninterface FactoryDispatchFailureMetadata {\n canRetry: boolean;\n label: string;\n}\n\nconst FAILURE_METADATA = {\n session_unavailable: { canRetry: true, label: 'Factory session unavailable' },\n source_control_missing: { canRetry: true, label: 'Source-control connection unavailable' },\n source_repository_missing: { canRetry: true, label: 'Source repository unavailable' },\n unsupported_provider_item: { canRetry: false, label: 'Unsupported provider work item' },\n notification_delivery_failed: { canRetry: true, label: 'Factory message delivery failed' },\n run_overdue: { canRetry: false, label: 'Agent run is overdue' },\n repository_git_missing: { canRetry: false, label: 'Git is unavailable in the workspace' },\n repository_egress_blocked: { canRetry: false, label: 'Repository network access is blocked' },\n repository_clone_failed: { canRetry: true, label: 'Repository clone failed' },\n repository_pull_failed: { canRetry: true, label: 'Repository update failed' },\n repository_push_failed: { canRetry: true, label: 'Repository push failed' },\n repository_commit_failed: { canRetry: true, label: 'Repository commit failed' },\n repository_cli_missing: { canRetry: false, label: 'GitHub CLI is unavailable in the workspace' },\n repository_pr_failed: { canRetry: true, label: 'Pull request creation failed' },\n run_configuration_invalid: { canRetry: false, label: 'Run configuration rejected by provider' },\n unknown: { canRetry: true, label: 'Factory automation failed' },\n // Retired: no path writes these any more, stored rows still read through here.\n plan_awaiting_approval: { canRetry: false, label: 'Plan waiting for review' },\n run_awaiting_input: { canRetry: false, label: 'Agent is waiting for an answer' },\n} satisfies Record<StoredFactoryDispatchFailureCode, FactoryDispatchFailureMetadata>;\n\nexport class FactoryDispatchError extends Error {\n constructor(\n readonly code: FactoryDispatchFailureCode,\n message: string,\n options?: ErrorOptions,\n ) {\n super(message, options);\n this.name = 'FactoryDispatchError';\n }\n}\n\nexport function factoryDispatchFailureCode(error: unknown): FactoryDispatchFailureCode {\n return error instanceof FactoryDispatchError ? error.code : 'unknown';\n}\n\nexport function factoryDispatchFailureMetadata(\n code: StoredFactoryDispatchFailureCode | null,\n): FactoryDispatchFailureMetadata {\n return code === null ? FAILURE_METADATA.unknown : FAILURE_METADATA[code];\n}\n"],"mappings":";AAUA,MAAM,mBAAmB;CACvB,qBAAqB;EAAE,UAAU;EAAM,OAAO;CAA8B;CAC5E,wBAAwB;EAAE,UAAU;EAAM,OAAO;CAAwC;CACzF,2BAA2B;EAAE,UAAU;EAAM,OAAO;CAAgC;CACpF,2BAA2B;EAAE,UAAU;EAAO,OAAO;CAAiC;CACtF,8BAA8B;EAAE,UAAU;EAAM,OAAO;CAAkC;CACzF,aAAa;EAAE,UAAU;EAAO,OAAO;CAAuB;CAC9D,wBAAwB;EAAE,UAAU;EAAO,OAAO;CAAsC;CACxF,2BAA2B;EAAE,UAAU;EAAO,OAAO;CAAuC;CAC5F,yBAAyB;EAAE,UAAU;EAAM,OAAO;CAA0B;CAC5E,wBAAwB;EAAE,UAAU;EAAM,OAAO;CAA2B;CAC5E,wBAAwB;EAAE,UAAU;EAAM,OAAO;CAAyB;CAC1E,0BAA0B;EAAE,UAAU;EAAM,OAAO;CAA2B;CAC9E,wBAAwB;EAAE,UAAU;EAAO,OAAO;CAA6C;CAC/F,sBAAsB;EAAE,UAAU;EAAM,OAAO;CAA+B;CAC9E,2BAA2B;EAAE,UAAU;EAAO,OAAO;CAAyC;CAC9F,SAAS;EAAE,UAAU;EAAM,OAAO;CAA4B;CAE9D,wBAAwB;EAAE,UAAU;EAAO,OAAO;CAA0B;CAC5E,oBAAoB;EAAE,UAAU;EAAO,OAAO;CAAiC;AACjF;AAEA,IAAa,uBAAb,cAA0C,MAAM;CAEnC;CADX,YACE,MACA,SACA,SACA;EACA,MAAM,SAAS,OAAO;EAJb,KAAA,OAAA;EAKT,KAAK,OAAO;CACd;AACF;AAEA,SAAgB,2BAA2B,OAA4C;CACrF,OAAO,iBAAiB,uBAAuB,MAAM,OAAO;AAC9D;AAEA,SAAgB,+BACd,MACgC;CAChC,OAAO,SAAS,OAAO,iBAAiB,UAAU,iBAAiB;AACrE"}
|
|
1
|
+
{"version":3,"file":"dispatch-errors.js","names":[],"sources":["../../src/rules/dispatch-errors.ts"],"sourcesContent":["import type {\n FactoryDispatchFailureCode,\n StoredFactoryDispatchFailureCode,\n} from '../storage/domains/work-items/base.js';\n\ninterface FactoryDispatchFailureMetadata {\n canRetry: boolean;\n label: string;\n}\n\nconst FAILURE_METADATA = {\n session_unavailable: { canRetry: true, label: 'Factory session unavailable' },\n source_control_missing: { canRetry: true, label: 'Source-control connection unavailable' },\n source_repository_missing: { canRetry: true, label: 'Source repository unavailable' },\n unsupported_provider_item: { canRetry: false, label: 'Unsupported provider work item' },\n notification_delivery_failed: { canRetry: true, label: 'Factory message delivery failed' },\n run_terminal_event_missing: { canRetry: false, label: 'Agent run terminal event was not observed' },\n skill_delivery_ambiguous: { canRetry: false, label: 'Factory skill delivery could not be confirmed' },\n run_overdue: { canRetry: false, label: 'Agent run is overdue' },\n repository_git_missing: { canRetry: false, label: 'Git is unavailable in the workspace' },\n repository_egress_blocked: { canRetry: false, label: 'Repository network access is blocked' },\n repository_clone_failed: { canRetry: true, label: 'Repository clone failed' },\n repository_pull_failed: { canRetry: true, label: 'Repository update failed' },\n repository_push_failed: { canRetry: true, label: 'Repository push failed' },\n repository_commit_failed: { canRetry: true, label: 'Repository commit failed' },\n repository_cli_missing: { canRetry: false, label: 'GitHub CLI is unavailable in the workspace' },\n repository_pr_failed: { canRetry: true, label: 'Pull request creation failed' },\n run_configuration_invalid: { canRetry: false, label: 'Run configuration rejected by provider' },\n unknown: { canRetry: true, label: 'Factory automation failed' },\n // Retired: no path writes these any more, stored rows still read through here.\n plan_awaiting_approval: { canRetry: false, label: 'Plan waiting for review' },\n run_awaiting_input: { canRetry: false, label: 'Agent is waiting for an answer' },\n} satisfies Record<StoredFactoryDispatchFailureCode, FactoryDispatchFailureMetadata>;\n\nexport class FactoryDispatchError extends Error {\n constructor(\n readonly code: FactoryDispatchFailureCode,\n message: string,\n options?: ErrorOptions,\n ) {\n super(message, options);\n this.name = 'FactoryDispatchError';\n }\n}\n\nexport function factoryDispatchFailureCode(error: unknown): FactoryDispatchFailureCode {\n return error instanceof FactoryDispatchError ? error.code : 'unknown';\n}\n\nexport function factoryDispatchFailureMetadata(\n code: StoredFactoryDispatchFailureCode | null,\n): FactoryDispatchFailureMetadata {\n return code === null ? FAILURE_METADATA.unknown : FAILURE_METADATA[code];\n}\n"],"mappings":";AAUA,MAAM,mBAAmB;CACvB,qBAAqB;EAAE,UAAU;EAAM,OAAO;CAA8B;CAC5E,wBAAwB;EAAE,UAAU;EAAM,OAAO;CAAwC;CACzF,2BAA2B;EAAE,UAAU;EAAM,OAAO;CAAgC;CACpF,2BAA2B;EAAE,UAAU;EAAO,OAAO;CAAiC;CACtF,8BAA8B;EAAE,UAAU;EAAM,OAAO;CAAkC;CACzF,4BAA4B;EAAE,UAAU;EAAO,OAAO;CAA4C;CAClG,0BAA0B;EAAE,UAAU;EAAO,OAAO;CAAgD;CACpG,aAAa;EAAE,UAAU;EAAO,OAAO;CAAuB;CAC9D,wBAAwB;EAAE,UAAU;EAAO,OAAO;CAAsC;CACxF,2BAA2B;EAAE,UAAU;EAAO,OAAO;CAAuC;CAC5F,yBAAyB;EAAE,UAAU;EAAM,OAAO;CAA0B;CAC5E,wBAAwB;EAAE,UAAU;EAAM,OAAO;CAA2B;CAC5E,wBAAwB;EAAE,UAAU;EAAM,OAAO;CAAyB;CAC1E,0BAA0B;EAAE,UAAU;EAAM,OAAO;CAA2B;CAC9E,wBAAwB;EAAE,UAAU;EAAO,OAAO;CAA6C;CAC/F,sBAAsB;EAAE,UAAU;EAAM,OAAO;CAA+B;CAC9E,2BAA2B;EAAE,UAAU;EAAO,OAAO;CAAyC;CAC9F,SAAS;EAAE,UAAU;EAAM,OAAO;CAA4B;CAE9D,wBAAwB;EAAE,UAAU;EAAO,OAAO;CAA0B;CAC5E,oBAAoB;EAAE,UAAU;EAAO,OAAO;CAAiC;AACjF;AAEA,IAAa,uBAAb,cAA0C,MAAM;CAEnC;CADX,YACE,MACA,SACA,SACA;EACA,MAAM,SAAS,OAAO;EAJb,KAAA,OAAA;EAKT,KAAK,OAAO;CACd;AACF;AAEA,SAAgB,2BAA2B,OAA4C;CACrF,OAAO,iBAAiB,uBAAuB,MAAM,OAAO;AAC9D;AAEA,SAAgB,+BACd,MACgC;CAChC,OAAO,SAAS,OAAO,iBAAiB,UAAU,iBAAiB;AACrE"}
|
|
@@ -85,6 +85,7 @@ export declare const FACTORY_DISPATCH_CONSTANTS: {
|
|
|
85
85
|
readonly maxBackoffMs: 60000;
|
|
86
86
|
readonly skillCompletionObservationTimeoutMs: number;
|
|
87
87
|
readonly runRegistryHeartbeatMs: number;
|
|
88
|
+
readonly openRunStaleMs: 30000;
|
|
88
89
|
readonly maxInFlight: 25;
|
|
89
90
|
readonly stages: readonly ["intake", "triage", "planning", "execute", "review", "done", "canceled"];
|
|
90
91
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/rules/dispatcher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAgC,OAAO,EAAE,MAAM,+BAA+B,CAAC;AAU5G,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/rules/dispatcher.ts"],"names":[],"mappings":"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"}
|