@opengeni/api-router 0.30.3 → 2.2.0-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/dist/api-websocket.d.ts +18 -0
  2. package/dist/app.js +1 -1
  3. package/dist/auth/managed-auth.d.ts +6 -0
  4. package/dist/{chunk-WCXHI3FF.js → chunk-3TP54PPX.js} +26692 -15389
  5. package/dist/chunk-3TP54PPX.js.map +1 -0
  6. package/dist/codemode.d.ts +8 -1
  7. package/dist/company-brain-okf.d.ts +24 -0
  8. package/dist/connected-machine-computer-access.d.ts +11 -0
  9. package/dist/connection-authority-owner.d.ts +59 -0
  10. package/dist/connection-ownership.d.ts +47 -0
  11. package/dist/controller-data-plane.d.ts +16 -0
  12. package/dist/editable-artifact-websocket.d.ts +5 -15
  13. package/dist/editable-artifact-workspace-files.d.ts +1 -1
  14. package/dist/http/api-error.d.ts +10 -0
  15. package/dist/http/cors.d.ts +5 -0
  16. package/dist/http/interaction-control-error.d.ts +13 -0
  17. package/dist/http/sse.d.ts +2 -3
  18. package/dist/index.d.ts +5 -2
  19. package/dist/index.js +326 -82
  20. package/dist/index.js.map +1 -1
  21. package/dist/integrations/atlassian.d.ts +17 -0
  22. package/dist/integrations/fiken.d.ts +7 -2
  23. package/dist/integrations/google-drive.d.ts +18 -0
  24. package/dist/integrations/oauth-client.d.ts +22 -3
  25. package/dist/integrations/oauth-profiles.d.ts +195 -0
  26. package/dist/integrations/personal-github-repositories.d.ts +45 -0
  27. package/dist/integrations/personal-github.d.ts +40 -0
  28. package/dist/integrations/pr-review-provider.d.ts +22 -0
  29. package/dist/integrations/provider-oauth.d.ts +8 -0
  30. package/dist/integrations/slack-app-home.d.ts +24 -0
  31. package/dist/integrations/slack-bot.d.ts +157 -9
  32. package/dist/integrations/slack-interactions.d.ts +39 -5
  33. package/dist/integrations/slack-routing.d.ts +120 -0
  34. package/dist/integrations/social-oauth.d.ts +5 -0
  35. package/dist/interaction-frame-proxy.d.ts +68 -0
  36. package/dist/mcp/company-brain-governed-writes.d.ts +26 -0
  37. package/dist/mcp/company-profile-agent-admin.d.ts +44 -0
  38. package/dist/mcp/documents.d.ts +1 -0
  39. package/dist/mcp/remember.d.ts +28 -0
  40. package/dist/mcp/request-abort.d.ts +19 -0
  41. package/dist/mcp/scheduled-task-view.d.ts +4 -4
  42. package/dist/mcp/server.d.ts +15 -2
  43. package/dist/mcp/session-view.d.ts +4 -0
  44. package/dist/mcp/session-wait.d.ts +137 -0
  45. package/dist/routes/automations.d.ts +4 -0
  46. package/dist/routes/billing.d.ts +5 -0
  47. package/dist/routes/browser-sessions.d.ts +4 -1
  48. package/dist/routes/company-brain.d.ts +3 -0
  49. package/dist/routes/company-profile.d.ts +2 -1
  50. package/dist/routes/connection-authorities.d.ts +3 -0
  51. package/dist/routes/personal-github-git-broker.d.ts +29 -0
  52. package/dist/routes/personal-github.d.ts +3 -0
  53. package/dist/routes/pr-review.d.ts +3 -0
  54. package/dist/routes/sessions.d.ts +1 -0
  55. package/dist/routes/user-resource-authorities.d.ts +3 -0
  56. package/dist/routes/workspace-capture.d.ts +10 -2
  57. package/dist/routes/workspace-learning.d.ts +3 -0
  58. package/dist/routes/workspaces.d.ts +19 -0
  59. package/dist/sandbox/channel-a.d.ts +11 -1
  60. package/dist/sandbox/connection-authority.d.ts +3 -0
  61. package/dist/sandbox/enrollment.d.ts +2 -0
  62. package/dist/sandbox/machines.d.ts +2 -2
  63. package/dist/sandbox/metrics-ingestion.d.ts +10 -20
  64. package/dist/sandbox/viewer.d.ts +24 -1
  65. package/dist/sandbox-file-artifacts.d.ts +11 -0
  66. package/dist/scheduled-task-deletion.d.ts +14 -0
  67. package/dist/slack-reaction-files.d.ts +1 -1
  68. package/dist/temporal-schedule-cleanup.d.ts +1 -0
  69. package/package.json +20 -18
  70. package/src/api-websocket.ts +23 -0
  71. package/src/app.ts +161 -23
  72. package/src/auth/managed-auth.ts +25 -3
  73. package/src/codemode.ts +53 -23
  74. package/src/codex-realtime.ts +8 -2
  75. package/src/company-brain-okf.ts +340 -0
  76. package/src/connected-machine-computer-access.ts +33 -0
  77. package/src/connection-authority-owner.ts +61 -0
  78. package/src/connection-ownership.ts +180 -0
  79. package/src/controller-data-plane.ts +47 -0
  80. package/src/editable-artifact-native-kernel.ts +26 -15
  81. package/src/editable-artifact-office-import.ts +28 -3
  82. package/src/editable-artifact-production.ts +13 -7
  83. package/src/editable-artifact-websocket.ts +11 -18
  84. package/src/editable-artifact-workspace-files.ts +31 -6
  85. package/src/http/api-error.ts +28 -0
  86. package/src/http/auth.ts +4 -0
  87. package/src/http/cors.ts +35 -0
  88. package/src/http/interaction-control-error.ts +164 -0
  89. package/src/http/sse.ts +112 -66
  90. package/src/index.ts +46 -6
  91. package/src/integrations/atlassian.ts +146 -35
  92. package/src/integrations/fiken.ts +102 -22
  93. package/src/integrations/google-drive.ts +301 -92
  94. package/src/integrations/oauth-client.ts +272 -143
  95. package/src/integrations/oauth-profiles.ts +477 -0
  96. package/src/integrations/personal-github-repositories.ts +445 -0
  97. package/src/integrations/personal-github.ts +705 -0
  98. package/src/integrations/pr-review-provider.ts +246 -0
  99. package/src/integrations/provider-oauth.ts +121 -5
  100. package/src/integrations/slack-app-home.ts +300 -0
  101. package/src/integrations/slack-bot.ts +342 -57
  102. package/src/integrations/slack-interactions.ts +1898 -259
  103. package/src/integrations/slack-routing.ts +337 -0
  104. package/src/integrations/social-oauth.ts +25 -0
  105. package/src/interaction-frame-proxy.ts +409 -0
  106. package/src/mcp/company-brain-governed-writes.ts +262 -0
  107. package/src/mcp/company-profile-agent-admin.ts +205 -0
  108. package/src/mcp/documents.ts +37 -6
  109. package/src/mcp/files.ts +16 -1
  110. package/src/mcp/remember.ts +181 -0
  111. package/src/mcp/request-abort.ts +44 -0
  112. package/src/mcp/scheduled-task-view.ts +1 -0
  113. package/src/mcp/server.ts +719 -369
  114. package/src/mcp/session-view.ts +54 -0
  115. package/src/mcp/session-wait.ts +554 -0
  116. package/src/model-catalog.ts +20 -12
  117. package/src/routes/api-integrations.ts +4 -0
  118. package/src/routes/api-keys.ts +1 -0
  119. package/src/routes/automations.ts +534 -0
  120. package/src/routes/billing.ts +57 -1
  121. package/src/routes/browser-sessions.ts +329 -79
  122. package/src/routes/channels.ts +17 -1
  123. package/src/routes/codex.ts +50 -0
  124. package/src/routes/company-brain.ts +367 -0
  125. package/src/routes/company-profile.ts +1 -1
  126. package/src/routes/computer-sessions.ts +320 -93
  127. package/src/routes/connection-authorities.ts +139 -0
  128. package/src/routes/connections.ts +144 -34
  129. package/src/routes/documents.ts +353 -4
  130. package/src/routes/editable-artifacts.ts +11 -3
  131. package/src/routes/enrollments.ts +116 -26
  132. package/src/routes/environments.ts +127 -55
  133. package/src/routes/files.ts +72 -11
  134. package/src/routes/install.ts +82 -28
  135. package/src/routes/integration-facets.ts +29 -0
  136. package/src/routes/interaction-resources.ts +20 -2
  137. package/src/routes/machines.ts +275 -13
  138. package/src/routes/organization-memberships.ts +717 -28
  139. package/src/routes/packs.ts +4 -3
  140. package/src/routes/personal-github-git-broker.ts +785 -0
  141. package/src/routes/personal-github.ts +319 -0
  142. package/src/routes/pr-review.ts +531 -0
  143. package/src/routes/rigs.ts +104 -39
  144. package/src/routes/scheduled-tasks.ts +19 -21
  145. package/src/routes/sessions.ts +775 -38
  146. package/src/routes/social.ts +14 -2
  147. package/src/routes/supergrok.ts +23 -4
  148. package/src/routes/transcription-recordings.ts +8 -2
  149. package/src/routes/user-resource-authorities.ts +138 -0
  150. package/src/routes/workspace-artifacts.ts +4 -1
  151. package/src/routes/workspace-capture.ts +21 -0
  152. package/src/routes/workspace-learning.ts +228 -0
  153. package/src/routes/workspaces.ts +59 -6
  154. package/src/sandbox/auth-callout.ts +38 -12
  155. package/src/sandbox/channel-a.ts +242 -19
  156. package/src/sandbox/connection-authority.ts +3 -0
  157. package/src/sandbox/enrollment.ts +15 -3
  158. package/src/sandbox/machines.ts +186 -64
  159. package/src/sandbox/metrics-ingestion.ts +220 -58
  160. package/src/sandbox/viewer.ts +243 -19
  161. package/src/sandbox-file-artifacts.ts +329 -0
  162. package/src/scheduled-task-deletion.ts +127 -0
  163. package/src/slack-reaction-files.ts +16 -5
  164. package/src/temporal-schedule-cleanup.ts +13 -0
  165. package/dist/chunk-WCXHI3FF.js.map +0 -1
@@ -25,6 +25,7 @@ export declare function browseAtlassianSources(deps: ApiRouteDeps, input: {
25
25
  }): Promise<{
26
26
  connection: {
27
27
  id: string;
28
+ authorityId?: string | undefined;
28
29
  accountId: string;
29
30
  workspaceId: string;
30
31
  subjectId: string | null;
@@ -167,10 +168,26 @@ export declare function disconnectAtlassian(deps: ApiRouteDeps, input: {
167
168
  connection: AtlassianConnectionRecord;
168
169
  payload: AtlassianDisconnectRequest;
169
170
  }): Promise<import("@opengeni/db").ConnectionMetadataWithVerification | null>;
171
+ export declare function preflightAtlassianScheduleAuthorization(deps: ApiRouteDeps, input: {
172
+ task: ScheduledTask;
173
+ subjectId: string;
174
+ }): Promise<void>;
170
175
  export declare function revokeAtlassianScheduleAuthorization(deps: ApiRouteDeps, input: {
171
176
  task: ScheduledTask;
172
177
  subjectId: string;
173
178
  }): Promise<void>;
179
+ export declare function cleanupAtlassianScheduleAuthorization(deps: ApiRouteDeps, input: {
180
+ taskId: string;
181
+ accountId: string;
182
+ workspaceId: string;
183
+ connectionId: string;
184
+ connectionVersion: number;
185
+ sourceId: string;
186
+ sourceLifecycleGeneration: number;
187
+ sourceConfigGeneration: number;
188
+ externalSourceId: string;
189
+ subjectId: string;
190
+ }): Promise<void>;
174
191
  export declare function isSelectableConfluenceSpaceType(value: unknown): boolean;
175
192
  export declare function confluenceNextUrl(cloudId: string, next: string): URL;
176
193
  export {};
@@ -25,6 +25,7 @@ type FikenContext = {
25
25
  subjectId: string | null;
26
26
  sessionId: string | null;
27
27
  };
28
+ type FikenProviderAuthorization = () => Promise<boolean | void>;
28
29
  /**
29
30
  * Validates a pasted Fiken personal API token before it enters encrypted
30
31
  * storage, and discovers the companies it can act on. The companies list is
@@ -57,8 +58,10 @@ export declare class FikenClient {
57
58
  private readonly metadata;
58
59
  private readonly context;
59
60
  private readonly fetchImpl;
61
+ private readonly authorizeProviderRequest?;
60
62
  private readonly resolveCredential;
61
- constructor(db: Database, settings: Settings, connection: ConnectionMetadata, metadata: FikenConnectionMetadata, context: FikenContext, fetchImpl?: FetchLike);
63
+ private expectedConnectionVersion;
64
+ constructor(db: Database, settings: Settings, connection: ConnectionMetadata, metadata: FikenConnectionMetadata, context: FikenContext, fetchImpl?: FetchLike, authorizeProviderRequest?: FikenProviderAuthorization | undefined);
62
65
  listCompanies(input?: {
63
66
  page?: number;
64
67
  pageSize?: number;
@@ -202,7 +205,8 @@ export declare class FikenClient {
202
205
  private request;
203
206
  private readResponse;
204
207
  private markNeedsReauth;
205
- private headersFor;
208
+ private currentAuthority;
209
+ private credentialFor;
206
210
  private receipt;
207
211
  private recordAudit;
208
212
  }
@@ -210,6 +214,7 @@ export declare function createFikenClient(deps: {
210
214
  db: Database;
211
215
  settings: Settings;
212
216
  fikenFetch?: typeof fetch;
217
+ authorizeProviderRequest?: FikenProviderAuthorization;
213
218
  }, resolved: Awaited<ReturnType<typeof resolveFikenConnectionForTool>>): FikenClient;
214
219
  export declare class FikenOAuthCallbackError extends Error {
215
220
  readonly reason: string;
@@ -52,6 +52,7 @@ export declare function browseGoogleDrive(deps: ApiRouteDeps, input: {
52
52
  }): Promise<{
53
53
  connection: {
54
54
  id: string;
55
+ authorityId?: string | undefined;
55
56
  accountId: string;
56
57
  workspaceId: string;
57
58
  subjectId: string | null;
@@ -107,6 +108,7 @@ export declare function browseGoogleDriveFacetSource(deps: ApiRouteDeps, input:
107
108
  }): Promise<{
108
109
  connection: {
109
110
  id: string;
111
+ authorityId?: string | undefined;
110
112
  accountId: string;
111
113
  workspaceId: string;
112
114
  subjectId: string | null;
@@ -174,8 +176,24 @@ export declare function saveGoogleDriveSource(deps: ApiRouteDeps, input: {
174
176
  canManageWorkspaceDestination: boolean;
175
177
  canManagePersonalDestination: boolean;
176
178
  }): Promise<import("@opengeni/db").ConnectionMetadataWithVerification>;
179
+ export declare function preflightKnowledgeSourceScheduleAuthorization(deps: ApiRouteDeps, input: {
180
+ task: ScheduledTask;
181
+ subjectId: string;
182
+ }): Promise<void>;
177
183
  export declare function revokeKnowledgeSourceScheduleAuthorization(deps: ApiRouteDeps, input: {
178
184
  task: ScheduledTask;
179
185
  subjectId: string;
180
186
  }): Promise<void>;
187
+ export declare function cleanupKnowledgeSourceScheduleAuthorization(deps: ApiRouteDeps, input: {
188
+ taskId: string;
189
+ accountId: string;
190
+ workspaceId: string;
191
+ connectionId: string;
192
+ connectionVersion: number;
193
+ sourceId: string;
194
+ sourceLifecycleGeneration: number;
195
+ sourceConfigGeneration: number;
196
+ externalSourceId: string;
197
+ subjectId: string;
198
+ }): Promise<void>;
181
199
  export {};
@@ -2,10 +2,9 @@ import { type Settings } from "@opengeni/config";
2
2
  import { OAuthStartResponse, type ConnectionOwnership, type OAuthStartRequest } from "@opengeni/contracts";
3
3
  import type { Observability } from "@opengeni/observability";
4
4
  import { type Database } from "@opengeni/db";
5
+ import { type OAuthProviderProfile } from "./oauth-profiles.js";
5
6
  export declare const oauthStateTtlMs: number;
6
- export declare const OFFICIAL_SLACK_MCP_URL: "https://mcp.slack.com/mcp";
7
- export declare const OFFICIAL_GMAIL_MCP_URL = "https://gmailmcp.googleapis.com/mcp/v1";
8
- export declare const OFFICIAL_GMAIL_MCP_SCOPES: readonly ["https://www.googleapis.com/auth/gmail.readonly", "https://www.googleapis.com/auth/gmail.compose", "https://www.googleapis.com/auth/gmail.modify"];
7
+ export { OFFICIAL_GMAIL_MCP_SCOPES, OFFICIAL_GMAIL_MCP_URL, OFFICIAL_SLACK_MCP_URL, } from "./oauth-profiles.js";
9
8
  export { OAUTH_MAX_RESPONSE_BYTES } from "@opengeni/network";
10
9
  type OAuthClientDeps = {
11
10
  db: Database;
@@ -18,6 +17,12 @@ export type OAuthStartContext = {
18
17
  accountId: string;
19
18
  workspaceId: string;
20
19
  subjectId: string;
20
+ /**
21
+ * False for every principal that cannot own a personal Connection (API keys,
22
+ * the configured key, services, agent attempts). Resolved by the route from
23
+ * the live authenticated principal, never inferred here.
24
+ */
25
+ personalOwnershipAllowed: boolean;
21
26
  requestUrl: string;
22
27
  payload: OAuthStartRequest;
23
28
  };
@@ -39,7 +44,16 @@ export declare const OAUTH_START_DEADLINE_MS = 15000;
39
44
  export declare const OAUTH_CALLBACK_DEADLINE_MS = 30000;
40
45
  export type OAuthStartStage = "connection_lookup" | "mcp_challenge" | "protected_resource_metadata" | "authorization_server_metadata" | "client_registration";
41
46
  export declare function startMcpOAuth(deps: OAuthClientDeps, context: OAuthStartContext): Promise<OAuthStartResponse>;
47
+ /** Ownership fence for the official Gmail profile, keyed by exact MCP URL. */
42
48
  export declare function assertOfficialGmailPersonalOwnership(mcpUrl: string, ownership: ConnectionOwnership): void;
49
+ /**
50
+ * Slack's hosted MCP issues user tokens only. Sharing one human's grant as
51
+ * workspace authority made every shared agent act as a named employee; the
52
+ * OpenGeni workspace bot owns shared Slack access instead (bot-token search
53
+ * covers public channels, files, and users).
54
+ */
55
+ export declare function assertHostedSlackMcpPersonalOwnership(hostedSlackMcp: boolean, ownership: ConnectionOwnership): void;
56
+ export declare function isHostedSlackMcpTarget(providerDomain: string, mcpUrl: string): boolean;
43
57
  export declare function completeMcpOAuthCallback(deps: OAuthClientDeps, input: {
44
58
  code?: string | undefined;
45
59
  state?: string | undefined;
@@ -47,8 +61,11 @@ export declare function completeMcpOAuthCallback(deps: OAuthClientDeps, input: {
47
61
  }): Promise<OAuthCallbackResult>;
48
62
  export declare function integrationBaseUrl(publicBaseUrl: string | undefined, requestUrl: string): string;
49
63
  export declare function requireIntegrationsStateSecret(settings: Settings): string;
64
+ /** The hosted-Slack profile's origin pins, kept exported for its tests. */
50
65
  export declare function assertSlackAuthorizationServer(as: AuthorizationServerMetadata): void;
66
+ /** The official-Gmail profile's origin pins, kept exported for its tests. */
51
67
  export declare function assertGoogleAuthorizationServer(as: AuthorizationServerMetadata): void;
68
+ export declare function preferredOAuthSelfRegistration(as: Pick<AuthorizationServerMetadata, "clientIdMetadataDocumentSupported" | "registrationEndpoint">, clientSource: OAuthProviderProfile["clientSource"]): "cimd" | "dcr" | null;
52
69
  export declare function buildAuthorizationUrl(input: {
53
70
  endpoint: string;
54
71
  settings: Settings;
@@ -59,6 +76,8 @@ export declare function buildAuthorizationUrl(input: {
59
76
  verifier: string;
60
77
  scopes: string[];
61
78
  resourceParameterSupported: boolean;
79
+ /** Profile-declared extra authorize parameters, applied last. */
80
+ extraParams?: Readonly<Record<string, string>> | undefined;
62
81
  }): string;
63
82
  export type OAuthPublicErrorFields = {
64
83
  errorClass: "OAuthOperationError";
@@ -0,0 +1,195 @@
1
+ import { type ConnectionOwnership } from "@opengeni/contracts";
2
+ import type { Settings } from "@opengeni/config";
3
+ import { z } from "zod";
4
+ /**
5
+ * Provider OAuth quirks as data.
6
+ *
7
+ * Some providers do not support DCR or CIMD and need a pre-registered client
8
+ * with pinned metadata; some issue personal tokens only; some reject RFC 8707's
9
+ * `resource` parameter. Each used to be a hand-written branch set inside
10
+ * `oauth-client.ts`; every quirk is now a field on an `OAuthProviderProfile`.
11
+ * The flow reads exactly one resolved profile and contains no provider-name
12
+ * conditional.
13
+ *
14
+ * Profiles come from two layers:
15
+ *
16
+ * 1. Built-in profiles below, for the providers whose fences are security
17
+ * invariants (hosted Slack MCP and official Gmail are personal-only, their
18
+ * authorization servers are origin-pinned). These live in code as data so
19
+ * the fences never depend on catalog import state.
20
+ * 2. A validated `oauthProfile` object on a global catalog row (curated
21
+ * overlay -> importer -> `capability_catalog_items.metadata`). A catalog
22
+ * profile applies only when no built-in matches, and it can only narrow the
23
+ * default behavior, never loosen a built-in fence.
24
+ */
25
+ export declare const OFFICIAL_SLACK_MCP_URL: "https://mcp.slack.com/mcp";
26
+ export declare const OFFICIAL_GMAIL_MCP_URL = "https://gmailmcp.googleapis.com/mcp/v1";
27
+ export declare const OFFICIAL_GMAIL_MCP_SCOPES: readonly ["https://www.googleapis.com/auth/gmail.readonly", "https://www.googleapis.com/auth/gmail.compose", "https://www.googleapis.com/auth/gmail.modify"];
28
+ /** The slice of discovered authorization-server metadata the pins constrain. */
29
+ export type PinnableAuthorizationServer = {
30
+ issuer: string;
31
+ authorizationServer: string;
32
+ authorizationEndpoint: string;
33
+ tokenEndpoint: string;
34
+ };
35
+ export type AuthorizationServerPins = {
36
+ /** Origins `issuer` and `authorizationServer` must both belong to. */
37
+ issuerOrigins: readonly string[];
38
+ /** Origins the authorization endpoint must belong to. */
39
+ authorizationEndpointOrigins: readonly string[];
40
+ /** Origins the token endpoint must belong to. */
41
+ tokenEndpointOrigins: readonly string[];
42
+ /** Exact 422 message when a pin fails. */
43
+ message: string;
44
+ /** Skip enforcement in a local test environment (loopback fixtures). */
45
+ skipInLocalTest: boolean;
46
+ };
47
+ export type OAuthProviderProfile = {
48
+ /** Stable identity for guards, logs, and tests. */
49
+ key: string;
50
+ /** Built-in matching; catalog profiles match their own row's exact mcpUrl. */
51
+ match: {
52
+ mcpUrls?: readonly string[];
53
+ providerDomains?: readonly string[];
54
+ };
55
+ /**
56
+ * Canonical provider identity forced when the profile matches by URL, so a
57
+ * caller cannot relabel a pinned resource under another domain.
58
+ */
59
+ canonicalProviderDomain?: string;
60
+ /** Reject a caller-supplied manual OAuth client (deployment-managed only). */
61
+ rejectCallerOAuthClient?: {
62
+ message: string;
63
+ };
64
+ /** The payload's explicit providerDomain must canonicalize to this domain. */
65
+ requireProviderDomain?: {
66
+ domain: string;
67
+ message: string;
68
+ };
69
+ /** Outside a local test environment, the start URL must be exactly this. */
70
+ requireExactMcpUrl?: {
71
+ url: string;
72
+ message: string;
73
+ };
74
+ /** Deployment-managed client credentials must be configured (503 otherwise). */
75
+ requireDeploymentClient?: {
76
+ key: DeploymentManagedClientKey;
77
+ message: string;
78
+ };
79
+ /** Ownerships a connection may take; a singleton also sets the default. */
80
+ allowedOwnership: readonly ConnectionOwnership[];
81
+ /** Exact 422 message when an explicit disallowed ownership is requested. */
82
+ ownershipMessage?: string;
83
+ /** Bind reconnect/dedupe to the exact mcpUrl, not just the provider domain. */
84
+ exactMcpBinding: boolean;
85
+ /** How an existing connection is chosen for reconnect coalescing. */
86
+ connectionSelection: "canonical_personal" | "first_active";
87
+ /** Post-discovery authorization-server origin pins. */
88
+ authorizationServer?: AuthorizationServerPins;
89
+ /**
90
+ * Post-discovery identity check: the resolved providerDomain must equal this
91
+ * domain (the reserved-authorization-server guard shares its message).
92
+ */
93
+ postDiscoveryProviderDomain?: {
94
+ domain: string;
95
+ message: string;
96
+ };
97
+ /**
98
+ * Client registration preference. `dcr` or `cimd` forces that advertised
99
+ * self-registration mechanism after operator/deployment clients. Without an
100
+ * explicit preference, DCR wins when both mechanisms are advertised.
101
+ */
102
+ clientSource?: "deployment_managed" | "cimd" | "dcr";
103
+ /** Send RFC 8707 `resource` on authorize and token requests. */
104
+ sendResourceParameter: boolean;
105
+ /** Extra authorize-URL query parameters (e.g. offline-consent opts). */
106
+ extraAuthorizeParams?: Readonly<Record<string, string>>;
107
+ /** Exact scope override; the caller can never widen past it. */
108
+ requestedScopes?: readonly string[];
109
+ };
110
+ export declare const DEFAULT_OAUTH_PROFILE: OAuthProviderProfile;
111
+ /** Exact built-in profile by its stable key; throws on an unknown key. */
112
+ export declare function builtInOAuthProfileByKey(key: string): OAuthProviderProfile;
113
+ export type DeploymentManagedClientKey = "slack";
114
+ /**
115
+ * Pre-registered deployment clients resolved from dedicated settings, keyed by
116
+ * the authorization-server origins they serve. Consulted before the operator
117
+ * clients JSON so a deployment-managed provider can never be shadowed.
118
+ */
119
+ export declare const DEPLOYMENT_MANAGED_CLIENTS: readonly {
120
+ key: DeploymentManagedClientKey;
121
+ issuerOrigins: readonly string[];
122
+ resolve: (settings: Settings) => {
123
+ clientId: string;
124
+ clientSecret: string;
125
+ tokenEndpointAuthMethod: "client_secret_post";
126
+ } | null;
127
+ }[];
128
+ export declare function deploymentManagedClientFor(settings: Settings, key: DeploymentManagedClientKey): ReturnType<(typeof DEPLOYMENT_MANAGED_CLIENTS)[number]["resolve"]>;
129
+ /** Built-in profile for a start target, or null when only the default applies. */
130
+ export declare function builtInOAuthProfileFor(input: {
131
+ mcpUrl: string;
132
+ providerDomain?: string | undefined;
133
+ }): OAuthProviderProfile | null;
134
+ /** Ownership an omitted request defaults to under a profile. */
135
+ export declare function defaultOwnershipFor(profile: OAuthProviderProfile): ConnectionOwnership;
136
+ /** Rejects an ownership outside the profile's allowed set with its exact message. */
137
+ export declare function assertOwnershipAllowed(profile: OAuthProviderProfile, ownership: ConnectionOwnership): void;
138
+ /** Enforces a profile's authorization-server origin pins with its exact message. */
139
+ export declare function assertAuthorizationServerPins(as: PinnableAuthorizationServer, pins: Pick<AuthorizationServerPins, "issuerOrigins" | "authorizationEndpointOrigins" | "tokenEndpointOrigins" | "message">): void;
140
+ /**
141
+ * Reserved-authorization-server guard: a discovered identity claimed by one
142
+ * profile is rejected on every other flow with that guard's exact message.
143
+ */
144
+ export declare function assertAuthorizationServerNotReserved(as: PinnableAuthorizationServer, profile: OAuthProviderProfile): void;
145
+ /**
146
+ * Catalog-row profile: the declarative subset a curated row may carry. It can
147
+ * only narrow the default flow; the fields that grant authority (deployment
148
+ * client settings, reserved-server membership) are built-in-only by
149
+ * construction because the schema cannot express them.
150
+ */
151
+ /**
152
+ * Authorize-URL parameters owned by the OAuth client itself. A profile's
153
+ * `extraAuthorizeParams` may never name one: overriding `scope` or `resource`
154
+ * would widen the grant past the recorded contract, and the rest carry the
155
+ * PKCE/state security machinery. Enforced in this schema, in the curation
156
+ * parser, and defensively again in `buildAuthorizationUrl`.
157
+ */
158
+ export declare const RESERVED_AUTHORIZE_PARAMS: ReadonlySet<string>;
159
+ export declare const catalogOAuthProfileSchema: z.ZodObject<{
160
+ clientSource: z.ZodOptional<z.ZodEnum<{
161
+ cimd: "cimd";
162
+ dcr: "dcr";
163
+ deployment_managed: "deployment_managed";
164
+ }>>;
165
+ exactMcpUrl: z.ZodOptional<z.ZodString>;
166
+ pinnedIssuerOrigins: z.ZodOptional<z.ZodArray<z.ZodString>>;
167
+ pinnedEndpointOrigins: z.ZodOptional<z.ZodArray<z.ZodString>>;
168
+ sendResourceParameter: z.ZodOptional<z.ZodBoolean>;
169
+ allowedOwnership: z.ZodOptional<z.ZodArray<z.ZodEnum<{
170
+ personal: "personal";
171
+ workspace: "workspace";
172
+ }>>>;
173
+ requestedScopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
174
+ extraAuthorizeParams: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
175
+ }, z.core.$strict>;
176
+ export type CatalogOAuthProfile = z.infer<typeof catalogOAuthProfileSchema>;
177
+ /**
178
+ * Canonical catalog lookup key for an MCP URL, mirroring the importer's
179
+ * `canonicalMcpUrl` (`scripts/catalog-curation.ts`): no fragment, lowercase
180
+ * host, default ports stripped, trailing slashes collapsed. Without this, a
181
+ * trailing-slash or uppercase-host variant of a profiled URL would miss the
182
+ * row and silently fall back to the default profile.
183
+ */
184
+ export declare function catalogMcpUrlKey(value: string): string;
185
+ /**
186
+ * Applies a validated catalog profile over the default profile for a row with
187
+ * no built-in. `deployment_managed` from catalog data resolves through the
188
+ * operator clients JSON (issuer-keyed) only; named settings-backed clients
189
+ * remain built-in-only.
190
+ *
191
+ * A present-but-invalid profile fails closed with a 422: the row's operator
192
+ * declared constraints, and silently degrading to the default profile would
193
+ * drop an ownership fence or origin pin on a JSON typo.
194
+ */
195
+ export declare function oauthProfileFromCatalog(mcpUrl: string, raw: unknown): OAuthProviderProfile;
@@ -0,0 +1,45 @@
1
+ import { type PersonalGitHubRepository as PersonalGitHubRepositoryContract, type PersonalGitHubRepositorySelectionInput } from "@opengeni/contracts/personal-github";
2
+ import type { ApiRouteDeps } from "@opengeni/core";
3
+ import { getConnectionMetadata } from "@opengeni/db";
4
+ import { HTTPException } from "hono/http-exception";
5
+ export type PersonalGitHubRepositoryConnection = NonNullable<Awaited<ReturnType<typeof getConnectionMetadata>>>;
6
+ export type PersonalGitHubRepositoryProviderErrorCode = "connection_changed" | "connection_inactive" | "invalid_provider_response" | "provider_denied" | "provider_rate_limited" | "provider_unavailable" | "repository_archived" | "repository_not_found" | "repository_read_denied" | "repository_write_denied";
7
+ export declare class PersonalGitHubRepositoryProviderError extends Error {
8
+ readonly code: PersonalGitHubRepositoryProviderErrorCode;
9
+ constructor(code: PersonalGitHubRepositoryProviderErrorCode);
10
+ }
11
+ export declare function requirePersonalGitHubRepositoryConnection(deps: ApiRouteDeps, input: {
12
+ accountId: string;
13
+ workspaceId: string;
14
+ subjectId: string;
15
+ connectionId: string;
16
+ }): Promise<PersonalGitHubRepositoryConnection>;
17
+ export declare function listLivePersonalGitHubRepositories(deps: ApiRouteDeps, input: {
18
+ workspaceId: string;
19
+ accountId: string;
20
+ subjectId: string;
21
+ connectionId: string;
22
+ expectedConnectionAuthorityGeneration: number;
23
+ page: number;
24
+ limit: number;
25
+ }): Promise<{
26
+ repositories: PersonalGitHubRepositoryContract[];
27
+ nextPage: number | null;
28
+ }>;
29
+ /** Serial by design: one bounded provider request and one authority check at a time. */
30
+ export declare function verifyLivePersonalGitHubRepositories(deps: ApiRouteDeps, input: {
31
+ workspaceId: string;
32
+ accountId: string;
33
+ subjectId: string;
34
+ connectionId: string;
35
+ expectedConnectionAuthorityGeneration: number;
36
+ repositories: PersonalGitHubRepositorySelectionInput[];
37
+ }): Promise<Array<PersonalGitHubRepositoryContract & {
38
+ selectedAccess: "read" | "write";
39
+ }>>;
40
+ export declare function personalGitHubRepositoryProviderHttpError(error: PersonalGitHubRepositoryProviderError): HTTPException;
41
+ /** Keep provider integer lexemes exact before repository IDs become bigint-backed strings. */
42
+ export declare function parsePersonalGitHubProviderJson(value: string): unknown;
43
+ export declare function personalGitHubRepositoryCanRead(permissions: PersonalGitHubRepositoryContract["permissions"]): boolean;
44
+ export declare function personalGitHubRepositoryCanWrite(permissions: PersonalGitHubRepositoryContract["permissions"]): boolean;
45
+ export declare function parsePersonalGitHubRepository(value: unknown): PersonalGitHubRepositoryContract;
@@ -0,0 +1,40 @@
1
+ import { type Settings } from "@opengeni/config";
2
+ import { type PersonalGitHubDisconnectRequest } from "@opengeni/contracts/personal-github";
3
+ import { type AccessGrantAuthorization, type ApiRouteDeps } from "@opengeni/core";
4
+ export declare function personalGitHubClientMarker(clientId: string): string;
5
+ export declare function requirePersonalGitHubOAuthSettings(settings: Settings): {
6
+ clientId: string;
7
+ clientSecret: string;
8
+ callbackUrl: string;
9
+ oauthEnvironment: string;
10
+ oauthClientMarker: string;
11
+ };
12
+ export declare function listPersonalGitHubConnections(deps: ApiRouteDeps, input: {
13
+ workspaceId: string;
14
+ subjectId: string;
15
+ }): Promise<import("@opengeni/db").ConnectionMetadataWithVerification[]>;
16
+ export declare function disconnectPersonalGitHub(deps: ApiRouteDeps, input: {
17
+ workspaceId: string;
18
+ subjectId: string;
19
+ connectionId: string;
20
+ payload: PersonalGitHubDisconnectRequest;
21
+ }): Promise<import("@opengeni/db").ConnectionMetadataWithVerification | null>;
22
+ export declare function startPersonalGitHubOAuth(deps: ApiRouteDeps, input: {
23
+ access: AccessGrantAuthorization;
24
+ workspaceId: string;
25
+ connectionId?: string;
26
+ returnPath?: string;
27
+ }): Promise<{
28
+ authorizationUrl: string;
29
+ expiresAt: string;
30
+ }>;
31
+ export declare function completePersonalGitHubOAuthCallback(deps: ApiRouteDeps, input: {
32
+ code?: string;
33
+ state?: string;
34
+ error?: string;
35
+ requestUrl: string;
36
+ }): Promise<{
37
+ redirectTo: string;
38
+ }>;
39
+ export declare function personalGitHubReviewUrl(settings: Settings): string | null;
40
+ export declare const PERSONAL_GITHUB_CONNECTION_PRINCIPAL_MESSAGE: string;
@@ -0,0 +1,22 @@
1
+ import type { PrReviewProvider } from "@opengeni/contracts";
2
+ import { type FetchLike, type OutboundNetworkSettings } from "@opengeni/network";
3
+ export declare class PrReviewProviderRepositoryError extends Error {
4
+ readonly reason: "denied" | "identity_mismatch" | "unavailable";
5
+ constructor(reason: "denied" | "identity_mismatch" | "unavailable", message: string);
6
+ }
7
+ export type VerifiedPrReviewProviderRepository = {
8
+ repositoryUri: string;
9
+ repositoryFullName: string;
10
+ providerRepositoryId: string;
11
+ projectId: string;
12
+ };
13
+ export declare function verifyPrReviewProviderRepository(input: {
14
+ provider: Exclude<PrReviewProvider, "github">;
15
+ providerBaseUrl: string;
16
+ providerRepositoryId: string;
17
+ projectId?: string;
18
+ token: string;
19
+ username: string | null;
20
+ settings: OutboundNetworkSettings;
21
+ fetchImpl?: FetchLike;
22
+ }): Promise<VerifiedPrReviewProviderRepository>;
@@ -1,9 +1,16 @@
1
+ import { type Settings } from "@opengeni/config";
1
2
  import { OAuthStartResponse, type ApiIntegrationOAuthStartRequest } from "@opengeni/contracts";
2
3
  import { type ApiRouteDeps } from "@opengeni/core";
3
4
  export declare function startApiIntegrationProviderOAuth(deps: ApiRouteDeps, input: {
4
5
  accountId: string;
5
6
  workspaceId: string;
6
7
  subjectId: string;
8
+ /**
9
+ * False for every principal that cannot own a personal Connection (API
10
+ * keys, the configured key, services, agent attempts). Resolved by the
11
+ * route from the live authenticated principal, never inferred here.
12
+ */
13
+ personalOwnershipAllowed: boolean;
7
14
  requestUrl: string;
8
15
  payload: ApiIntegrationOAuthStartRequest;
9
16
  }): Promise<OAuthStartResponse>;
@@ -15,3 +22,4 @@ export declare function completeApiIntegrationProviderOAuth(deps: ApiRouteDeps,
15
22
  }): Promise<{
16
23
  redirectTo: string;
17
24
  }>;
25
+ export declare function isApiIntegrationProviderOAuthState(value: string | undefined, settings: Settings): boolean;
@@ -0,0 +1,24 @@
1
+ import type { Session } from "@opengeni/contracts";
2
+ import type { SlackHomeBlock } from "./slack-bot.js";
3
+ export type SlackAppHomeOpenedEvent = {
4
+ eventId: string;
5
+ slackTeamId: string;
6
+ slackUserId: string;
7
+ viewHash: string | null;
8
+ };
9
+ export declare function slackAppHomeOpenedEvent(payload: unknown): SlackAppHomeOpenedEvent | null;
10
+ /** URL-only App Home buttons are acknowledged but never become Slack commands. */
11
+ export declare function isSlackAppHomeLinkAction(payload: unknown): boolean;
12
+ export declare function buildSlackAppHomeBlocks(input: {
13
+ sessions: readonly Session[];
14
+ workspaceUrl: string | null;
15
+ sessionUrl: (sessionId: string) => string | null;
16
+ nowMs?: number;
17
+ }): SlackHomeBlock[];
18
+ export declare function buildSlackAppHomeAccessBlocks(input: {
19
+ title: string;
20
+ message: string;
21
+ actionLabel?: string;
22
+ actionUrl?: string | null;
23
+ }): SlackHomeBlock[];
24
+ export declare function escapeSlackMrkdwn(value: string): string;