@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.
- package/dist/api-websocket.d.ts +18 -0
- package/dist/app.js +1 -1
- package/dist/auth/managed-auth.d.ts +6 -0
- package/dist/{chunk-WCXHI3FF.js → chunk-3TP54PPX.js} +26692 -15389
- package/dist/chunk-3TP54PPX.js.map +1 -0
- package/dist/codemode.d.ts +8 -1
- package/dist/company-brain-okf.d.ts +24 -0
- package/dist/connected-machine-computer-access.d.ts +11 -0
- package/dist/connection-authority-owner.d.ts +59 -0
- package/dist/connection-ownership.d.ts +47 -0
- package/dist/controller-data-plane.d.ts +16 -0
- package/dist/editable-artifact-websocket.d.ts +5 -15
- package/dist/editable-artifact-workspace-files.d.ts +1 -1
- package/dist/http/api-error.d.ts +10 -0
- package/dist/http/cors.d.ts +5 -0
- package/dist/http/interaction-control-error.d.ts +13 -0
- package/dist/http/sse.d.ts +2 -3
- package/dist/index.d.ts +5 -2
- package/dist/index.js +326 -82
- package/dist/index.js.map +1 -1
- package/dist/integrations/atlassian.d.ts +17 -0
- package/dist/integrations/fiken.d.ts +7 -2
- package/dist/integrations/google-drive.d.ts +18 -0
- package/dist/integrations/oauth-client.d.ts +22 -3
- package/dist/integrations/oauth-profiles.d.ts +195 -0
- package/dist/integrations/personal-github-repositories.d.ts +45 -0
- package/dist/integrations/personal-github.d.ts +40 -0
- package/dist/integrations/pr-review-provider.d.ts +22 -0
- package/dist/integrations/provider-oauth.d.ts +8 -0
- package/dist/integrations/slack-app-home.d.ts +24 -0
- package/dist/integrations/slack-bot.d.ts +157 -9
- package/dist/integrations/slack-interactions.d.ts +39 -5
- package/dist/integrations/slack-routing.d.ts +120 -0
- package/dist/integrations/social-oauth.d.ts +5 -0
- package/dist/interaction-frame-proxy.d.ts +68 -0
- package/dist/mcp/company-brain-governed-writes.d.ts +26 -0
- package/dist/mcp/company-profile-agent-admin.d.ts +44 -0
- package/dist/mcp/documents.d.ts +1 -0
- package/dist/mcp/remember.d.ts +28 -0
- package/dist/mcp/request-abort.d.ts +19 -0
- package/dist/mcp/scheduled-task-view.d.ts +4 -4
- package/dist/mcp/server.d.ts +15 -2
- package/dist/mcp/session-view.d.ts +4 -0
- package/dist/mcp/session-wait.d.ts +137 -0
- package/dist/routes/automations.d.ts +4 -0
- package/dist/routes/billing.d.ts +5 -0
- package/dist/routes/browser-sessions.d.ts +4 -1
- package/dist/routes/company-brain.d.ts +3 -0
- package/dist/routes/company-profile.d.ts +2 -1
- package/dist/routes/connection-authorities.d.ts +3 -0
- package/dist/routes/personal-github-git-broker.d.ts +29 -0
- package/dist/routes/personal-github.d.ts +3 -0
- package/dist/routes/pr-review.d.ts +3 -0
- package/dist/routes/sessions.d.ts +1 -0
- package/dist/routes/user-resource-authorities.d.ts +3 -0
- package/dist/routes/workspace-capture.d.ts +10 -2
- package/dist/routes/workspace-learning.d.ts +3 -0
- package/dist/routes/workspaces.d.ts +19 -0
- package/dist/sandbox/channel-a.d.ts +11 -1
- package/dist/sandbox/connection-authority.d.ts +3 -0
- package/dist/sandbox/enrollment.d.ts +2 -0
- package/dist/sandbox/machines.d.ts +2 -2
- package/dist/sandbox/metrics-ingestion.d.ts +10 -20
- package/dist/sandbox/viewer.d.ts +24 -1
- package/dist/sandbox-file-artifacts.d.ts +11 -0
- package/dist/scheduled-task-deletion.d.ts +14 -0
- package/dist/slack-reaction-files.d.ts +1 -1
- package/dist/temporal-schedule-cleanup.d.ts +1 -0
- package/package.json +20 -18
- package/src/api-websocket.ts +23 -0
- package/src/app.ts +161 -23
- package/src/auth/managed-auth.ts +25 -3
- package/src/codemode.ts +53 -23
- package/src/codex-realtime.ts +8 -2
- package/src/company-brain-okf.ts +340 -0
- package/src/connected-machine-computer-access.ts +33 -0
- package/src/connection-authority-owner.ts +61 -0
- package/src/connection-ownership.ts +180 -0
- package/src/controller-data-plane.ts +47 -0
- package/src/editable-artifact-native-kernel.ts +26 -15
- package/src/editable-artifact-office-import.ts +28 -3
- package/src/editable-artifact-production.ts +13 -7
- package/src/editable-artifact-websocket.ts +11 -18
- package/src/editable-artifact-workspace-files.ts +31 -6
- package/src/http/api-error.ts +28 -0
- package/src/http/auth.ts +4 -0
- package/src/http/cors.ts +35 -0
- package/src/http/interaction-control-error.ts +164 -0
- package/src/http/sse.ts +112 -66
- package/src/index.ts +46 -6
- package/src/integrations/atlassian.ts +146 -35
- package/src/integrations/fiken.ts +102 -22
- package/src/integrations/google-drive.ts +301 -92
- package/src/integrations/oauth-client.ts +272 -143
- package/src/integrations/oauth-profiles.ts +477 -0
- package/src/integrations/personal-github-repositories.ts +445 -0
- package/src/integrations/personal-github.ts +705 -0
- package/src/integrations/pr-review-provider.ts +246 -0
- package/src/integrations/provider-oauth.ts +121 -5
- package/src/integrations/slack-app-home.ts +300 -0
- package/src/integrations/slack-bot.ts +342 -57
- package/src/integrations/slack-interactions.ts +1898 -259
- package/src/integrations/slack-routing.ts +337 -0
- package/src/integrations/social-oauth.ts +25 -0
- package/src/interaction-frame-proxy.ts +409 -0
- package/src/mcp/company-brain-governed-writes.ts +262 -0
- package/src/mcp/company-profile-agent-admin.ts +205 -0
- package/src/mcp/documents.ts +37 -6
- package/src/mcp/files.ts +16 -1
- package/src/mcp/remember.ts +181 -0
- package/src/mcp/request-abort.ts +44 -0
- package/src/mcp/scheduled-task-view.ts +1 -0
- package/src/mcp/server.ts +719 -369
- package/src/mcp/session-view.ts +54 -0
- package/src/mcp/session-wait.ts +554 -0
- package/src/model-catalog.ts +20 -12
- package/src/routes/api-integrations.ts +4 -0
- package/src/routes/api-keys.ts +1 -0
- package/src/routes/automations.ts +534 -0
- package/src/routes/billing.ts +57 -1
- package/src/routes/browser-sessions.ts +329 -79
- package/src/routes/channels.ts +17 -1
- package/src/routes/codex.ts +50 -0
- package/src/routes/company-brain.ts +367 -0
- package/src/routes/company-profile.ts +1 -1
- package/src/routes/computer-sessions.ts +320 -93
- package/src/routes/connection-authorities.ts +139 -0
- package/src/routes/connections.ts +144 -34
- package/src/routes/documents.ts +353 -4
- package/src/routes/editable-artifacts.ts +11 -3
- package/src/routes/enrollments.ts +116 -26
- package/src/routes/environments.ts +127 -55
- package/src/routes/files.ts +72 -11
- package/src/routes/install.ts +82 -28
- package/src/routes/integration-facets.ts +29 -0
- package/src/routes/interaction-resources.ts +20 -2
- package/src/routes/machines.ts +275 -13
- package/src/routes/organization-memberships.ts +717 -28
- package/src/routes/packs.ts +4 -3
- package/src/routes/personal-github-git-broker.ts +785 -0
- package/src/routes/personal-github.ts +319 -0
- package/src/routes/pr-review.ts +531 -0
- package/src/routes/rigs.ts +104 -39
- package/src/routes/scheduled-tasks.ts +19 -21
- package/src/routes/sessions.ts +775 -38
- package/src/routes/social.ts +14 -2
- package/src/routes/supergrok.ts +23 -4
- package/src/routes/transcription-recordings.ts +8 -2
- package/src/routes/user-resource-authorities.ts +138 -0
- package/src/routes/workspace-artifacts.ts +4 -1
- package/src/routes/workspace-capture.ts +21 -0
- package/src/routes/workspace-learning.ts +228 -0
- package/src/routes/workspaces.ts +59 -6
- package/src/sandbox/auth-callout.ts +38 -12
- package/src/sandbox/channel-a.ts +242 -19
- package/src/sandbox/connection-authority.ts +3 -0
- package/src/sandbox/enrollment.ts +15 -3
- package/src/sandbox/machines.ts +186 -64
- package/src/sandbox/metrics-ingestion.ts +220 -58
- package/src/sandbox/viewer.ts +243 -19
- package/src/sandbox-file-artifacts.ts +329 -0
- package/src/scheduled-task-deletion.ts +127 -0
- package/src/slack-reaction-files.ts +16 -5
- package/src/temporal-schedule-cleanup.ts +13 -0
- package/dist/chunk-WCXHI3FF.js.map +0 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SandboxFileArtifactReceipt, type AccessGrant, type Session } from "@opengeni/contracts";
|
|
2
|
+
import { type ApiRouteDeps } from "@opengeni/core";
|
|
3
|
+
export declare function publishSandboxFileArtifact(deps: ApiRouteDeps, input: {
|
|
4
|
+
grant: AccessGrant;
|
|
5
|
+
session: Session;
|
|
6
|
+
path: string;
|
|
7
|
+
signal?: AbortSignal | undefined;
|
|
8
|
+
}): Promise<SandboxFileArtifactReceipt>;
|
|
9
|
+
export declare function sandboxArtifactRelativePath(value: string): string;
|
|
10
|
+
export declare function sandboxArtifactSafeFilename(filename: string): string;
|
|
11
|
+
export declare function sandboxFileContentType(filename: string): string;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ScheduledTask as ScheduledTaskValue } from "@opengeni/contracts";
|
|
2
|
+
import { type ApiRouteDeps } from "@opengeni/core";
|
|
3
|
+
import type { TemporalScheduleCleanupClaim } from "@opengeni/db";
|
|
4
|
+
/** Execute one exact connector obligation frozen into the tombstone outbox row. */
|
|
5
|
+
export declare function cleanupScheduledTaskConnectorAuthorization(deps: ApiRouteDeps, claim: TemporalScheduleCleanupClaim): Promise<void>;
|
|
6
|
+
/** Shared HTTP/MCP domain operation: authorize, tombstone, persist, then accelerate cleanup. */
|
|
7
|
+
export declare function deleteScheduledTaskWithDurableCleanup(deps: ApiRouteDeps, input: {
|
|
8
|
+
workspaceId: string;
|
|
9
|
+
taskId: string;
|
|
10
|
+
subjectId: string;
|
|
11
|
+
}): Promise<{
|
|
12
|
+
task: ScheduledTaskValue;
|
|
13
|
+
changed: boolean;
|
|
14
|
+
}>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { FileResourceRef } from "@opengeni/contracts";
|
|
2
2
|
import { completeFileUpload, prepareGeneratedWorkspaceFile, type Database } from "@opengeni/db";
|
|
3
|
-
import type
|
|
3
|
+
import { type ObjectStorage } from "@opengeni/storage";
|
|
4
4
|
import type { DownloadedSlackReactionImage } from "./integrations/slack-bot.js";
|
|
5
5
|
export type SlackReactionImageImportSource = Readonly<{
|
|
6
6
|
accountId: string;
|
|
@@ -2,6 +2,7 @@ import { type Database, type TemporalScheduleCleanupClaim } from "@opengeni/db";
|
|
|
2
2
|
import type { Observability } from "@opengeni/observability";
|
|
3
3
|
type TemporalScheduleCleanupDependencies = {
|
|
4
4
|
db: Database;
|
|
5
|
+
cleanupConnectorAuthorization?: (claim: TemporalScheduleCleanupClaim) => Promise<void>;
|
|
5
6
|
deleteSchedule: (temporalScheduleId: string) => Promise<void>;
|
|
6
7
|
observability?: Pick<Observability, "info" | "warn" | "error">;
|
|
7
8
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/api-router",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "2.2.0-canary.0",
|
|
4
4
|
"description": "OpenGeni HTTP surface: the Hono adapter/router (createApp), routes, MCP HTTP transport, and HTTP access adapters over @opengeni/core. An engine-distribution surface — its runtime closure includes engine-internal packages.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -43,30 +43,32 @@
|
|
|
43
43
|
"@hono/zod-validator": "^0.7.6",
|
|
44
44
|
"@llamaindex/liteparse": "^1.5.3",
|
|
45
45
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
46
|
-
"@opengeni/agent-proto": "^0.5.
|
|
47
|
-
"@opengeni/artifact-tool": "^0.
|
|
48
|
-
"@opengeni/capabilities": "^0.
|
|
49
|
-
"@opengeni/codemode": "^0.4.
|
|
50
|
-
"@opengeni/codex": "^0.2.
|
|
51
|
-
"@opengeni/config": "^0.
|
|
52
|
-
"@opengeni/contracts": "^
|
|
53
|
-
"@opengeni/core": "^
|
|
54
|
-
"@opengeni/db": "^
|
|
55
|
-
"@opengeni/documents": "^0.
|
|
56
|
-
"@opengeni/events": "^0.3.
|
|
57
|
-
"@opengeni/github": "^0.
|
|
58
|
-
"@opengeni/network": "^0.2.
|
|
59
|
-
"@opengeni/observability": "^0.
|
|
60
|
-
"@opengeni/runtime": "^1.
|
|
61
|
-
"@opengeni/storage": "^0.2.
|
|
62
|
-
"@opengeni/xai-subscription": "^0.1.0",
|
|
46
|
+
"@opengeni/agent-proto": "^0.5.1-canary.1",
|
|
47
|
+
"@opengeni/artifact-tool": "^0.3.5-canary.0",
|
|
48
|
+
"@opengeni/capabilities": "^0.3.1-canary.0",
|
|
49
|
+
"@opengeni/codemode": "^0.4.13-canary.0",
|
|
50
|
+
"@opengeni/codex": "^0.2.19-canary.0",
|
|
51
|
+
"@opengeni/config": "^0.19.1-canary.0",
|
|
52
|
+
"@opengeni/contracts": "^2.3.0-canary.0",
|
|
53
|
+
"@opengeni/core": "^2.2.0-canary.0",
|
|
54
|
+
"@opengeni/db": "^3.2.0-canary.0",
|
|
55
|
+
"@opengeni/documents": "^0.7.0-canary.0",
|
|
56
|
+
"@opengeni/events": "^0.3.124-canary.0",
|
|
57
|
+
"@opengeni/github": "^0.5.3-canary.0",
|
|
58
|
+
"@opengeni/network": "^0.2.3-canary.0",
|
|
59
|
+
"@opengeni/observability": "^0.8.4-canary.0",
|
|
60
|
+
"@opengeni/runtime": "^1.3.1-canary.0",
|
|
61
|
+
"@opengeni/storage": "^0.2.106-canary.0",
|
|
62
|
+
"@opengeni/xai-subscription": "^0.1.2-canary.0",
|
|
63
63
|
"@temporalio/client": "^1.17.0",
|
|
64
64
|
"better-auth": "^1.6.14",
|
|
65
65
|
"hono": "^4.12.18",
|
|
66
|
+
"json-bigint": "^1.0.0",
|
|
66
67
|
"pg": "^8.21.0",
|
|
67
68
|
"resend": "^6.12.4",
|
|
68
69
|
"sharp": "^0.34.5",
|
|
69
70
|
"stripe": "^22.2.0",
|
|
71
|
+
"ws": "8.21.1",
|
|
70
72
|
"zod": "^4.2.1"
|
|
71
73
|
},
|
|
72
74
|
"engines": {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type ApiWebSocketConnection = Readonly<{
|
|
2
|
+
attach(socket: ApiWebSocketLike): void;
|
|
3
|
+
receive(message: string | Uint8Array | ArrayBuffer): void;
|
|
4
|
+
transportClosed(): void;
|
|
5
|
+
}>;
|
|
6
|
+
|
|
7
|
+
export type ApiWebSocketLike = Readonly<{
|
|
8
|
+
data: ApiWebSocketConnection;
|
|
9
|
+
send(data: Uint8Array, compress?: boolean): number;
|
|
10
|
+
close(code?: number, reason?: string): void;
|
|
11
|
+
readonly bufferedAmount?: number;
|
|
12
|
+
getBufferedAmount?(): number;
|
|
13
|
+
}>;
|
|
14
|
+
|
|
15
|
+
export type ApiWebSocketUpgradeServer = Readonly<{
|
|
16
|
+
upgrade(
|
|
17
|
+
request: Request,
|
|
18
|
+
options: Readonly<{
|
|
19
|
+
data: ApiWebSocketConnection;
|
|
20
|
+
headers: HeadersInit;
|
|
21
|
+
}>,
|
|
22
|
+
): boolean;
|
|
23
|
+
}>;
|
package/src/app.ts
CHANGED
|
@@ -28,12 +28,13 @@ import {
|
|
|
28
28
|
type DocumentServices,
|
|
29
29
|
} from "@opengeni/documents";
|
|
30
30
|
import {
|
|
31
|
-
CodemodeCallBudgetExceededError,
|
|
32
31
|
CodemodeOperationConflictError,
|
|
33
32
|
CodemodeOperationNotExecutableError,
|
|
34
33
|
CodemodePayloadTooLargeError,
|
|
35
34
|
CodemodeToolApprovalRequiredError,
|
|
36
35
|
CodemodeToolNotInCatalogError,
|
|
36
|
+
configureChildLifecycleNotices,
|
|
37
|
+
configureWorkspaceControlRequestLockTimeoutMs,
|
|
37
38
|
dbSql,
|
|
38
39
|
getWorkspace,
|
|
39
40
|
rlsContextForWorkspace,
|
|
@@ -42,12 +43,13 @@ import {
|
|
|
42
43
|
import { createObservability } from "@opengeni/observability";
|
|
43
44
|
import { createObjectStorage } from "@opengeni/storage";
|
|
44
45
|
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
46
|
+
import { handleMcpRequestWithClientAbort } from "./mcp/request-abort";
|
|
45
47
|
import { Hono } from "hono";
|
|
46
48
|
import { bodyLimit } from "hono/body-limit";
|
|
47
49
|
import { compress } from "hono/compress";
|
|
48
50
|
import { cors } from "hono/cors";
|
|
49
51
|
import { HTTPException } from "hono/http-exception";
|
|
50
|
-
import { ApiHttpError } from "./http/api-error";
|
|
52
|
+
import { ApiHttpError, workspaceControlBusyHttpError } from "./http/api-error";
|
|
51
53
|
import type { ContentfulStatusCode } from "hono/utils/http-status";
|
|
52
54
|
import type { ApiRouteDeps, AppDependencies } from "@opengeni/core";
|
|
53
55
|
import {
|
|
@@ -66,6 +68,7 @@ import { requireLimit } from "@opengeni/core";
|
|
|
66
68
|
import { buildOpenGeniMcpServer } from "./mcp/server";
|
|
67
69
|
import {
|
|
68
70
|
CodemodeAuthorityError,
|
|
71
|
+
CodemodeCatalogNotReadyError,
|
|
69
72
|
isCodemodeGrant,
|
|
70
73
|
readCodemodeOperation,
|
|
71
74
|
requireActiveCodemodeCatalog,
|
|
@@ -95,11 +98,18 @@ import { registerBrowserIdentityRoutes } from "./routes/browser-identities";
|
|
|
95
98
|
import { registerBrowserSessionRoutes } from "./routes/browser-sessions";
|
|
96
99
|
import { registerComputerSessionRoutes } from "./routes/computer-sessions";
|
|
97
100
|
import { registerGitHubRoutes } from "./routes/github";
|
|
101
|
+
import { registerPersonalGitHubRoutes } from "./routes/personal-github";
|
|
102
|
+
import {
|
|
103
|
+
isPersonalGitHubGitBrokerRequest,
|
|
104
|
+
registerPersonalGitHubGitBrokerRoutes,
|
|
105
|
+
} from "./routes/personal-github-git-broker";
|
|
98
106
|
import { registerInstallRoutes } from "./routes/install";
|
|
99
107
|
import { registerApiIntegrationRoutes } from "./routes/api-integrations";
|
|
100
108
|
import { registerIntegrationFacetRoutes } from "./routes/integration-facets";
|
|
101
109
|
import { registerInteractionResourceRoutes } from "./routes/interaction-resources";
|
|
110
|
+
import { registerPrReviewRoutes } from "./routes/pr-review";
|
|
102
111
|
import { registerPackRoutes } from "./routes/packs";
|
|
112
|
+
import { registerAutomationRoutes } from "./routes/automations";
|
|
103
113
|
import { registerPluginRoutes } from "./routes/plugins";
|
|
104
114
|
import { registerSkillRoutes } from "./routes/skills";
|
|
105
115
|
import { registerChannelRoutes } from "./routes/channels";
|
|
@@ -109,7 +119,9 @@ import { registerSessionRoutes } from "./routes/sessions";
|
|
|
109
119
|
import { registerSocialRoutes } from "./routes/social";
|
|
110
120
|
import { registerWorkspaceRoutes } from "./routes/workspaces";
|
|
111
121
|
import { registerWorkspaceInstructionPolicyRoutes } from "./routes/workspace-instruction-policies";
|
|
122
|
+
import { registerWorkspaceLearningRoutes } from "./routes/workspace-learning";
|
|
112
123
|
import { registerCompanyProfileRoutes } from "./routes/company-profile";
|
|
124
|
+
import { registerCompanyBrainRoutes } from "./routes/company-brain";
|
|
113
125
|
import { registerSlackTaskPolicyRoutes } from "./routes/slack-task-policy";
|
|
114
126
|
import { registerWorkspaceStateRoutes } from "./routes/workspace-state";
|
|
115
127
|
import { registerWorkspaceArtifactRoutes } from "./routes/workspace-artifacts";
|
|
@@ -120,6 +132,8 @@ import { registerEditableArtifactRoutes } from "./routes/editable-artifacts";
|
|
|
120
132
|
import { registerVideoGenerationRoutes } from "./routes/video-generation";
|
|
121
133
|
import { registerCanonicalHumanIdentityRoutes } from "./routes/canonical-human-identities";
|
|
122
134
|
import { registerOrganizationMembershipRoutes } from "./routes/organization-memberships";
|
|
135
|
+
import { registerUserResourceAuthorityRoutes } from "./routes/user-resource-authorities";
|
|
136
|
+
import { registerConnectionAuthorityRoutes } from "./routes/connection-authorities";
|
|
123
137
|
import { projectClientModel } from "./model-catalog";
|
|
124
138
|
import { createTranscriptionService } from "./transcription/service";
|
|
125
139
|
import { createFfmpegTranscriptionSegmenter } from "./transcription/segmenter";
|
|
@@ -171,6 +185,14 @@ export function createAppComposition(deps: AppDependencies): {
|
|
|
171
185
|
app: Hono;
|
|
172
186
|
routeDeps: ApiRouteDeps;
|
|
173
187
|
} {
|
|
188
|
+
// The request-scoped workspace control-prefix budget is validated once by
|
|
189
|
+
// @opengeni/config at boot; install it for every request-scoped db command
|
|
190
|
+
// (Send/Steer/control/queue/settings/delete) built by this app.
|
|
191
|
+
configureWorkspaceControlRequestLockTimeoutMs(deps.settings.workspaceControlLockTimeoutMs);
|
|
192
|
+
// Child lifecycle notice producers (human-input/approval resolutions, direct
|
|
193
|
+
// Pause) run inside API-originated db commands; install the boot-validated
|
|
194
|
+
// rollout flag once for this process.
|
|
195
|
+
configureChildLifecycleNotices({ enabled: deps.settings.childLifecycleNoticesEnabled });
|
|
174
196
|
const managedAuth = deps.managedAuth ?? createManagedAuth(deps.settings, deps.db);
|
|
175
197
|
const objectStorage =
|
|
176
198
|
deps.objectStorage === undefined ? createObjectStorage(deps.settings) : deps.objectStorage;
|
|
@@ -332,14 +354,21 @@ export function createAppComposition(deps: AppDependencies): {
|
|
|
332
354
|
return middleware(c, next);
|
|
333
355
|
});
|
|
334
356
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
357
|
+
const standardRequestBodyLimit = bodyLimit({
|
|
358
|
+
maxSize: apiRequestBodyLimitBytes(deps.settings),
|
|
359
|
+
onError: (c) =>
|
|
360
|
+
c.json({ code: "PAYLOAD_TOO_LARGE", message: "Request body is too large." }, 413),
|
|
361
|
+
});
|
|
362
|
+
app.use("*", async (c, next) => {
|
|
363
|
+
// Git packfiles must stay streaming and can legitimately exceed the JSON
|
|
364
|
+
// request ceiling. The exact closed broker routes apply their own method,
|
|
365
|
+
// content-type, authority, and idle-deadline checks.
|
|
366
|
+
if (isPersonalGitHubGitBrokerRequest(c.req.method, new URL(c.req.url).pathname)) {
|
|
367
|
+
await next();
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
return await standardRequestBodyLimit(c, next);
|
|
371
|
+
});
|
|
343
372
|
|
|
344
373
|
// Large catalog, capture, and session-list responses are on the browser's
|
|
345
374
|
// critical path. Compress JSON at the API boundary while leaving SSE and
|
|
@@ -426,7 +455,17 @@ export function createAppComposition(deps: AppDependencies): {
|
|
|
426
455
|
}
|
|
427
456
|
});
|
|
428
457
|
|
|
429
|
-
|
|
458
|
+
const accessKeyBoundary = requireAccessKey(deps.settings);
|
|
459
|
+
app.use("*", async (c, next) => {
|
|
460
|
+
// Git's credential helper supplies the exact encrypted broker bearer in
|
|
461
|
+
// Authorization. It cannot also supply the deployment access key, and the
|
|
462
|
+
// route performs its own attempt-bound authorization before every use.
|
|
463
|
+
if (isPersonalGitHubGitBrokerRequest(c.req.method, new URL(c.req.url).pathname)) {
|
|
464
|
+
await next();
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
return await accessKeyBoundary(c, next);
|
|
468
|
+
});
|
|
430
469
|
|
|
431
470
|
app.use("/v1/*", async (c, next) => {
|
|
432
471
|
c.header(OPENGENI_API_CONTRACT_HEADER, OPENGENI_API_CONTRACT_REVISION);
|
|
@@ -597,7 +636,7 @@ export function createAppComposition(deps: AppDependencies): {
|
|
|
597
636
|
}
|
|
598
637
|
const workspace = await getWorkspace(routeDeps.db, workspaceId);
|
|
599
638
|
const workspaceMemoryEnabled = resolveWorkspaceMemoryEnabled(workspace?.settings);
|
|
600
|
-
const workspaceMemoryPromptMode = resolveWorkspaceMemoryPromptMode(
|
|
639
|
+
const workspaceMemoryPromptMode = resolveWorkspaceMemoryPromptMode();
|
|
601
640
|
const transport = new WebStandardStreamableHTTPServerTransport({
|
|
602
641
|
enableJsonResponse: true,
|
|
603
642
|
});
|
|
@@ -607,7 +646,9 @@ export function createAppComposition(deps: AppDependencies): {
|
|
|
607
646
|
workspaceMemoryPromptMode,
|
|
608
647
|
});
|
|
609
648
|
await mcp.connect(transport);
|
|
610
|
-
|
|
649
|
+
// Bind tool handlers' `extra.signal` to the HTTP client's connection: a
|
|
650
|
+
// worker that drops the call (Steer/Pause) aborts a blocking tool here.
|
|
651
|
+
return await handleMcpRequestWithClientAbort(transport, boundedRequest, c.req.raw.signal);
|
|
611
652
|
});
|
|
612
653
|
});
|
|
613
654
|
|
|
@@ -677,13 +718,17 @@ export function createAppComposition(deps: AppDependencies): {
|
|
|
677
718
|
registerWorkspaceRoutes(app, routeDeps);
|
|
678
719
|
registerInsightsRoutes(app, routeDeps);
|
|
679
720
|
registerWorkspaceInstructionPolicyRoutes(app, routeDeps);
|
|
721
|
+
registerWorkspaceLearningRoutes(app, routeDeps);
|
|
680
722
|
registerCompanyProfileRoutes(app, routeDeps);
|
|
723
|
+
registerCompanyBrainRoutes(app, routeDeps);
|
|
681
724
|
registerSlackTaskPolicyRoutes(app, routeDeps);
|
|
682
725
|
registerWorkspaceStateRoutes(app, routeDeps);
|
|
683
726
|
registerMemorySlackPublicationRoutes(app, routeDeps);
|
|
684
727
|
registerWorkspaceArtifactRoutes(app, routeDeps);
|
|
685
728
|
registerPreferenceRegistryRoutes(app, routeDeps);
|
|
686
729
|
registerSocialRoutes(app, routeDeps);
|
|
730
|
+
registerPersonalGitHubRoutes(app, routeDeps);
|
|
731
|
+
registerPersonalGitHubGitBrokerRoutes(app, routeDeps);
|
|
687
732
|
registerConnectionRoutes(app, routeDeps);
|
|
688
733
|
registerCapabilityRoutes(app, routeDeps);
|
|
689
734
|
registerApiIntegrationRoutes(app, routeDeps);
|
|
@@ -695,6 +740,8 @@ export function createAppComposition(deps: AppDependencies): {
|
|
|
695
740
|
registerChannelRoutes(app, routeDeps);
|
|
696
741
|
registerRigRoutes(app, routeDeps);
|
|
697
742
|
registerPackRoutes(app, routeDeps);
|
|
743
|
+
registerAutomationRoutes(app, routeDeps);
|
|
744
|
+
registerPrReviewRoutes(app, routeDeps);
|
|
698
745
|
registerPluginRoutes(app, routeDeps);
|
|
699
746
|
registerSkillRoutes(app, routeDeps);
|
|
700
747
|
registerSessionRoutes(app, routeDeps);
|
|
@@ -706,6 +753,8 @@ export function createAppComposition(deps: AppDependencies): {
|
|
|
706
753
|
registerVideoGenerationRoutes(app, routeDeps);
|
|
707
754
|
registerCanonicalHumanIdentityRoutes(app, routeDeps);
|
|
708
755
|
registerOrganizationMembershipRoutes(app, routeDeps);
|
|
756
|
+
registerUserResourceAuthorityRoutes(app, routeDeps);
|
|
757
|
+
registerConnectionAuthorityRoutes(app, routeDeps);
|
|
709
758
|
registerSlackInteractionRoutes(app, routeDeps);
|
|
710
759
|
|
|
711
760
|
app.notFound((c) => {
|
|
@@ -725,7 +774,10 @@ export function createAppComposition(deps: AppDependencies): {
|
|
|
725
774
|
);
|
|
726
775
|
});
|
|
727
776
|
|
|
728
|
-
app.onError((
|
|
777
|
+
app.onError((rawError, c) => {
|
|
778
|
+
// One central mapping for every Send/Steer/control route: a bounded
|
|
779
|
+
// control-prefix wait that expired is a known, retryable, not-applied 503.
|
|
780
|
+
const error = workspaceControlBusyHttpError(rawError) ?? rawError;
|
|
729
781
|
const compactionLock = codexCompactionV2ProviderLockedError(error);
|
|
730
782
|
const apiError = error instanceof ApiHttpError ? error : null;
|
|
731
783
|
const status = compactionLock ? 422 : httpStatusForError(error);
|
|
@@ -747,7 +799,9 @@ export function createAppComposition(deps: AppDependencies): {
|
|
|
747
799
|
? (boundedPublicMessage(apiError.message) ?? "Request failed.")
|
|
748
800
|
: publicErrorMessage(error, status),
|
|
749
801
|
retryable: apiError?.retryable ?? retryableHttpStatus(status),
|
|
750
|
-
...(mutationOutcomeUnknown(error, c.req.method)
|
|
802
|
+
...((apiError?.outcomeUnknown ?? mutationOutcomeUnknown(error, c.req.method))
|
|
803
|
+
? { outcomeUnknown: true }
|
|
804
|
+
: {}),
|
|
751
805
|
requestId,
|
|
752
806
|
...(apiError?.details ? { details: apiError.details } : {}),
|
|
753
807
|
},
|
|
@@ -870,7 +924,11 @@ async function requireMcpAccessGrant(
|
|
|
870
924
|
|
|
871
925
|
function clientAuthConfig(settings: AppDependencies["settings"]) {
|
|
872
926
|
if (settings.productAccessMode === "managed") {
|
|
873
|
-
return {
|
|
927
|
+
return {
|
|
928
|
+
mode: "managedSession" as const,
|
|
929
|
+
session: "cookie" as const,
|
|
930
|
+
emailVerificationRequired: settings.environment !== "local",
|
|
931
|
+
};
|
|
874
932
|
}
|
|
875
933
|
if (settings.productAccessMode === "configured") {
|
|
876
934
|
return {
|
|
@@ -901,18 +959,30 @@ function codemodeHttpError(error: unknown): HTTPException {
|
|
|
901
959
|
cause: error,
|
|
902
960
|
});
|
|
903
961
|
}
|
|
904
|
-
if (
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
962
|
+
if (error instanceof CodemodeCatalogNotReadyError) {
|
|
963
|
+
return new ApiHttpError(409, {
|
|
964
|
+
code: "conflict",
|
|
965
|
+
message: error.message,
|
|
966
|
+
retryable: true,
|
|
967
|
+
outcomeUnknown: false,
|
|
968
|
+
details: { code: error.code },
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
if (error instanceof CodemodeAuthorityError) {
|
|
972
|
+
return new ApiHttpError(error.reason === "invalid_grant" ? 403 : 409, {
|
|
973
|
+
code: error.reason === "invalid_grant" ? "forbidden" : "conflict",
|
|
974
|
+
message: error.message,
|
|
975
|
+
retryable: false,
|
|
976
|
+
outcomeUnknown: false,
|
|
977
|
+
details: { code: error.code },
|
|
978
|
+
});
|
|
979
|
+
}
|
|
980
|
+
if (error instanceof CodemodeOperationNotExecutableError) {
|
|
908
981
|
return new HTTPException(409, { message: error.message, cause: error });
|
|
909
982
|
}
|
|
910
983
|
if (error instanceof CodemodeOperationConflictError) {
|
|
911
984
|
return new HTTPException(409, { message: error.message, cause: error });
|
|
912
985
|
}
|
|
913
|
-
if (error instanceof CodemodeCallBudgetExceededError) {
|
|
914
|
-
return new HTTPException(429, { message: error.message, cause: error });
|
|
915
|
-
}
|
|
916
986
|
if (error instanceof CodemodeToolNotInCatalogError) {
|
|
917
987
|
return new HTTPException(404, { message: error.message, cause: error });
|
|
918
988
|
}
|
|
@@ -981,6 +1051,9 @@ export function httpStatusForError(error: unknown): number {
|
|
|
981
1051
|
if (codexCompactionV2ProviderLockedError(error)) {
|
|
982
1052
|
return 422;
|
|
983
1053
|
}
|
|
1054
|
+
if (workspaceControlBusyHttpError(error)) {
|
|
1055
|
+
return 503;
|
|
1056
|
+
}
|
|
984
1057
|
if (error instanceof HTTPException) {
|
|
985
1058
|
return error.status;
|
|
986
1059
|
}
|
|
@@ -1171,6 +1244,10 @@ const routeLabelPatterns: Array<{
|
|
|
1171
1244
|
label: "/v1/billing/entitlements",
|
|
1172
1245
|
},
|
|
1173
1246
|
{ pattern: /^\/v1\/webhooks\/stripe$/, label: "/v1/webhooks/stripe" },
|
|
1247
|
+
{
|
|
1248
|
+
pattern: /^\/v1\/workspaces\/[^/]+\/pr-review\/(registrations|repositories)(?:\/[^/]+)?$/,
|
|
1249
|
+
label: (match) => `/v1/workspaces/:workspaceId/pr-review/${match[1]}`,
|
|
1250
|
+
},
|
|
1174
1251
|
{
|
|
1175
1252
|
pattern: /^\/v1\/workspaces\/[^/]+\/mcp$/,
|
|
1176
1253
|
label: "/v1/workspaces/:workspaceId/mcp",
|
|
@@ -1372,6 +1449,10 @@ const routeLabelPatterns: Array<{
|
|
|
1372
1449
|
pattern: /^\/v1\/workspaces\/[^/]+\/sessions\/[^/]+\/events\/stream$/,
|
|
1373
1450
|
label: "/v1/workspaces/:workspaceId/sessions/:id/events/stream",
|
|
1374
1451
|
},
|
|
1452
|
+
{
|
|
1453
|
+
pattern: /^\/v1\/workspaces\/[^/]+\/sessions\/[^/]+\/(visibility|forks)$/,
|
|
1454
|
+
label: (match) => `/v1/workspaces/:workspaceId/sessions/:id/${match[1]}`,
|
|
1455
|
+
},
|
|
1375
1456
|
{
|
|
1376
1457
|
pattern: /^\/v1\/workspaces\/[^/]+\/sessions\/[^/]+\/lineage$/,
|
|
1377
1458
|
label: "/v1/workspaces/:workspaceId/sessions/:id/lineage",
|
|
@@ -1380,6 +1461,10 @@ const routeLabelPatterns: Array<{
|
|
|
1380
1461
|
pattern: /^\/v1\/workspaces\/[^/]+\/sessions\/[^/]+\/events$/,
|
|
1381
1462
|
label: "/v1/workspaces/:workspaceId/sessions/:id/events",
|
|
1382
1463
|
},
|
|
1464
|
+
{
|
|
1465
|
+
pattern: /^\/v1\/workspaces\/[^/]+\/sessions\/[^/]+\/turns$/,
|
|
1466
|
+
label: "/v1/workspaces/:workspaceId/sessions/:id/turns",
|
|
1467
|
+
},
|
|
1383
1468
|
{
|
|
1384
1469
|
pattern: /^\/v1\/workspaces\/[^/]+\/sessions\/[^/]+\/queue\/[^/]+\/(move|edit|steer|delete)$/,
|
|
1385
1470
|
label: "/v1/workspaces/:workspaceId/sessions/:id/queue/:turnId/:action",
|
|
@@ -1388,6 +1473,10 @@ const routeLabelPatterns: Array<{
|
|
|
1388
1473
|
pattern: /^\/v1\/workspaces\/[^/]+\/sessions\/[^/]+\/queue$/,
|
|
1389
1474
|
label: "/v1/workspaces/:workspaceId/sessions/:id/queue",
|
|
1390
1475
|
},
|
|
1476
|
+
{
|
|
1477
|
+
pattern: /^\/v1\/workspaces\/[^/]+\/sessions\/[^/]+\/composer-draft\/submit$/,
|
|
1478
|
+
label: "/v1/workspaces/:workspaceId/sessions/:id/composer-draft/submit",
|
|
1479
|
+
},
|
|
1391
1480
|
{
|
|
1392
1481
|
pattern: /^\/v1\/workspaces\/[^/]+\/sessions\/[^/]+\/composer-draft$/,
|
|
1393
1482
|
label: "/v1/workspaces/:workspaceId/sessions/:id/composer-draft",
|
|
@@ -1706,6 +1795,26 @@ const routeLabelPatterns: Array<{
|
|
|
1706
1795
|
pattern: /^\/v1\/workspaces\/[^/]+\/connections\/oauth\/start$/,
|
|
1707
1796
|
label: "/v1/workspaces/:workspaceId/connections/oauth/start",
|
|
1708
1797
|
},
|
|
1798
|
+
{
|
|
1799
|
+
pattern: /^\/v1\/workspaces\/[^/]+\/connections\/github$/,
|
|
1800
|
+
label: "/v1/workspaces/:workspaceId/connections/github",
|
|
1801
|
+
},
|
|
1802
|
+
{
|
|
1803
|
+
pattern: /^\/v1\/workspaces\/[^/]+\/connections\/github\/oauth\/start$/,
|
|
1804
|
+
label: "/v1/workspaces/:workspaceId/connections/github/oauth/start",
|
|
1805
|
+
},
|
|
1806
|
+
{
|
|
1807
|
+
pattern: /^\/v1\/workspaces\/[^/]+\/connections\/[^/]+\/github\/reconnect$/,
|
|
1808
|
+
label: "/v1/workspaces/:workspaceId/connections/:connectionId/github/reconnect",
|
|
1809
|
+
},
|
|
1810
|
+
{
|
|
1811
|
+
pattern: /^\/v1\/workspaces\/[^/]+\/connections\/[^/]+\/github\/repositories\/verify$/,
|
|
1812
|
+
label: "/v1/workspaces/:workspaceId/connections/:connectionId/github/repositories/verify",
|
|
1813
|
+
},
|
|
1814
|
+
{
|
|
1815
|
+
pattern: /^\/v1\/workspaces\/[^/]+\/connections\/[^/]+\/github\/repositories$/,
|
|
1816
|
+
label: "/v1/workspaces/:workspaceId/connections/:connectionId/github/repositories",
|
|
1817
|
+
},
|
|
1709
1818
|
{
|
|
1710
1819
|
pattern: /^\/v1\/workspaces\/[^/]+\/integrations\/oauth\/start$/,
|
|
1711
1820
|
label: "/v1/workspaces/:workspaceId/integrations/oauth/start",
|
|
@@ -1730,6 +1839,18 @@ const routeLabelPatterns: Array<{
|
|
|
1730
1839
|
pattern: /^\/v1\/workspaces\/[^/]+\/connections\/[^/]+$/,
|
|
1731
1840
|
label: "/v1/workspaces/:workspaceId/connections/:connectionId",
|
|
1732
1841
|
},
|
|
1842
|
+
{
|
|
1843
|
+
pattern: /^\/v1\/git\/personal\/[^/]+\/info\/refs$/,
|
|
1844
|
+
label: "/v1/git/personal/:routeId/info/refs",
|
|
1845
|
+
},
|
|
1846
|
+
{
|
|
1847
|
+
pattern: /^\/v1\/git\/personal\/[^/]+\/git-upload-pack$/,
|
|
1848
|
+
label: "/v1/git/personal/:routeId/git-upload-pack",
|
|
1849
|
+
},
|
|
1850
|
+
{
|
|
1851
|
+
pattern: /^\/v1\/git\/personal\/[^/]+\/git-receive-pack$/,
|
|
1852
|
+
label: "/v1/git/personal/:routeId/git-receive-pack",
|
|
1853
|
+
},
|
|
1733
1854
|
{ pattern: /^\/v1\/catalog-assets\/.+$/, label: "/v1/catalog-assets/*" },
|
|
1734
1855
|
{
|
|
1735
1856
|
pattern: /^\/v1\/integrations\/oauth\/callback$/,
|
|
@@ -1739,6 +1860,10 @@ const routeLabelPatterns: Array<{
|
|
|
1739
1860
|
pattern: /^\/v1\/integrations\/provider-oauth\/callback$/,
|
|
1740
1861
|
label: "/v1/integrations/provider-oauth/callback",
|
|
1741
1862
|
},
|
|
1863
|
+
{
|
|
1864
|
+
pattern: /^\/v1\/integrations\/github-personal\/oauth\/callback$/,
|
|
1865
|
+
label: "/v1/integrations/github-personal/oauth/callback",
|
|
1866
|
+
},
|
|
1742
1867
|
{
|
|
1743
1868
|
pattern: /^\/v1\/integrations\/google-drive\/callback$/,
|
|
1744
1869
|
label: "/v1/integrations/google-drive/callback",
|
|
@@ -1779,6 +1904,14 @@ const routeLabelPatterns: Array<{
|
|
|
1779
1904
|
pattern: /^\/v1\/workspaces\/[^/]+\/machines\/[^/]+\/metrics\/series$/,
|
|
1780
1905
|
label: "/v1/workspaces/:workspaceId/machines/:enrollmentId/metrics/series",
|
|
1781
1906
|
},
|
|
1907
|
+
{
|
|
1908
|
+
pattern: /^\/v1\/workspaces\/[^/]+\/machines\/[^/]+\/operation-policy$/,
|
|
1909
|
+
label: "/v1/workspaces/:workspaceId/machines/:enrollmentId/operation-policy",
|
|
1910
|
+
},
|
|
1911
|
+
{
|
|
1912
|
+
pattern: /^\/v1\/workspaces\/[^/]+\/machines\/[^/]+\/update$/,
|
|
1913
|
+
label: "/v1/workspaces/:workspaceId/machines/:enrollmentId/update",
|
|
1914
|
+
},
|
|
1782
1915
|
{
|
|
1783
1916
|
pattern: /^\/v1\/workspaces\/[^/]+\/machines$/,
|
|
1784
1917
|
label: "/v1/workspaces/:workspaceId/machines",
|
|
@@ -1796,6 +1929,10 @@ const routeLabelPatterns: Array<{
|
|
|
1796
1929
|
pattern: /^\/v1\/github\/oauth\/callback$/,
|
|
1797
1930
|
label: "/v1/github/oauth/callback",
|
|
1798
1931
|
},
|
|
1932
|
+
{
|
|
1933
|
+
pattern: /^\/v1\/workspaces\/[^/]+$/,
|
|
1934
|
+
label: "/v1/workspaces/:workspaceId",
|
|
1935
|
+
},
|
|
1799
1936
|
];
|
|
1800
1937
|
|
|
1801
1938
|
export function routeLabel(pathname: string): string {
|
|
@@ -1824,6 +1961,7 @@ export function isApiContractProtectedMutation(method: string, pathname: string)
|
|
|
1824
1961
|
pathname.startsWith("/v1/auth/") ||
|
|
1825
1962
|
pathname.startsWith("/v1/webhooks/") ||
|
|
1826
1963
|
pathname.startsWith("/v1/integrations/oauth/") ||
|
|
1964
|
+
isPersonalGitHubGitBrokerRequest(method, pathname) ||
|
|
1827
1965
|
pathname === "/v1/integrations/slack/events" ||
|
|
1828
1966
|
pathname === "/v1/integrations/slack/commands" ||
|
|
1829
1967
|
pathname === "/v1/integrations/slack/interactions" ||
|
package/src/auth/managed-auth.ts
CHANGED
|
@@ -20,10 +20,25 @@ import { decideCanonicalHumanSessionAdmission } from "./canonical-human-session-
|
|
|
20
20
|
// importers (`app.ts`) keep the same import path.
|
|
21
21
|
export type { ManagedAuth };
|
|
22
22
|
|
|
23
|
+
export function managedAuthRequiresEmailVerification(
|
|
24
|
+
settings: Pick<Settings, "environment">,
|
|
25
|
+
): boolean {
|
|
26
|
+
return settings.environment !== "local";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function managedAuthUserCreateOverride(
|
|
30
|
+
settings: Pick<Settings, "environment">,
|
|
31
|
+
user: { emailVerified: boolean } & Record<string, unknown>,
|
|
32
|
+
): { data: typeof user } | undefined {
|
|
33
|
+
if (managedAuthRequiresEmailVerification(settings)) return undefined;
|
|
34
|
+
return { data: { ...user, emailVerified: true } };
|
|
35
|
+
}
|
|
36
|
+
|
|
23
37
|
export function createManagedAuth(settings: Settings, db: Database): ManagedAuth | null {
|
|
24
38
|
if (settings.productAccessMode !== "managed") {
|
|
25
39
|
return null;
|
|
26
40
|
}
|
|
41
|
+
const requireEmailVerification = managedAuthRequiresEmailVerification(settings);
|
|
27
42
|
const pool = new Pool({ connectionString: settings.databaseUrl });
|
|
28
43
|
return betterAuth({
|
|
29
44
|
appName: "OpenGeni",
|
|
@@ -124,10 +139,13 @@ export function createManagedAuth(settings: Settings, db: Database): ManagedAuth
|
|
|
124
139
|
},
|
|
125
140
|
emailAndPassword: {
|
|
126
141
|
enabled: true,
|
|
127
|
-
|
|
142
|
+
// Local managed mode exists so the complete human/org tenancy flow can
|
|
143
|
+
// be exercised without first configuring a transactional-email vendor.
|
|
144
|
+
// Every non-local deployment retains the verified-email boundary.
|
|
145
|
+
requireEmailVerification,
|
|
128
146
|
revokeSessionsOnPasswordReset: true,
|
|
129
147
|
onExistingUserSignUp: async ({ user }) => {
|
|
130
|
-
if (!user.emailVerified) {
|
|
148
|
+
if (requireEmailVerification && !user.emailVerified) {
|
|
131
149
|
const url = await verificationUrl(settings, user.email);
|
|
132
150
|
await sendEmail(settings, {
|
|
133
151
|
to: user.email,
|
|
@@ -147,7 +165,7 @@ export function createManagedAuth(settings: Settings, db: Database): ManagedAuth
|
|
|
147
165
|
},
|
|
148
166
|
},
|
|
149
167
|
emailVerification: {
|
|
150
|
-
sendOnSignUp:
|
|
168
|
+
sendOnSignUp: requireEmailVerification,
|
|
151
169
|
sendVerificationEmail: async ({ user, url }) => {
|
|
152
170
|
await sendEmail(settings, {
|
|
153
171
|
to: user.email,
|
|
@@ -161,6 +179,7 @@ export function createManagedAuth(settings: Settings, db: Database): ManagedAuth
|
|
|
161
179
|
userId: user.id,
|
|
162
180
|
email: user.email,
|
|
163
181
|
name: user.name,
|
|
182
|
+
emailVerified: true,
|
|
164
183
|
});
|
|
165
184
|
},
|
|
166
185
|
},
|
|
@@ -239,11 +258,14 @@ export function createManagedAuth(settings: Settings, db: Database): ManagedAuth
|
|
|
239
258
|
},
|
|
240
259
|
user: {
|
|
241
260
|
create: {
|
|
261
|
+
before: async (user) => managedAuthUserCreateOverride(settings, user),
|
|
242
262
|
after: async (user) => {
|
|
263
|
+
if (!user.emailVerified) return;
|
|
243
264
|
await ensureManagedAccessForUser(db, {
|
|
244
265
|
userId: user.id,
|
|
245
266
|
email: user.email,
|
|
246
267
|
name: user.name,
|
|
268
|
+
emailVerified: true,
|
|
247
269
|
});
|
|
248
270
|
},
|
|
249
271
|
},
|