@opengeni/api-router 2.11.3 → 2.12.3-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/app.js +1 -1
- package/dist/{chunk-5X3XM6CE.js → chunk-4AQMKVQM.js} +17727 -14427
- package/dist/chunk-4AQMKVQM.js.map +1 -0
- package/dist/connection-ownership.d.ts +5 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/integrations/atlassian.d.ts +4 -0
- package/dist/integrations/connect-authority.d.ts +1 -0
- package/dist/integrations/connect-callback-return.d.ts +6 -0
- package/dist/integrations/fiken.d.ts +7 -0
- package/dist/integrations/github-app-connect.d.ts +47 -0
- package/dist/integrations/github-installation-proof.d.ts +3 -0
- package/dist/integrations/github-lens-connect.d.ts +153 -0
- package/dist/integrations/google-drive.d.ts +4 -0
- package/dist/integrations/oauth-client.d.ts +4 -0
- package/dist/integrations/oauth-return-path.d.ts +1 -0
- package/dist/integrations/personal-github.d.ts +2 -0
- package/dist/integrations/provider-oauth.d.ts +11 -1
- package/dist/integrations/slack-install.d.ts +20 -0
- package/dist/integrations/social-oauth.d.ts +2 -0
- package/dist/mcp/scheduled-task-view.d.ts +3 -3
- package/dist/routes/api-integrations.d.ts +14 -0
- package/dist/routes/connect.d.ts +5 -0
- package/dist/routes/external-identity-links.d.ts +6 -0
- package/dist/routes/host-mcp-bindings.d.ts +5 -0
- package/dist/sandbox/rematerialize.d.ts +1 -1
- package/dist/workspace-tool-gateway.d.ts +1 -0
- package/package.json +19 -19
- package/src/app.ts +22 -2
- package/src/connection-ownership.ts +14 -1
- package/src/index.ts +2 -0
- package/src/integrations/atlassian.ts +143 -39
- package/src/integrations/connect-authority.ts +2 -0
- package/src/integrations/connect-callback-return.ts +86 -0
- package/src/integrations/fiken.ts +222 -40
- package/src/integrations/github-app-connect.ts +389 -0
- package/src/integrations/github-installation-proof.ts +60 -0
- package/src/integrations/github-lens-connect.ts +97 -0
- package/src/integrations/google-drive.ts +152 -47
- package/src/integrations/oauth-client.ts +180 -84
- package/src/integrations/oauth-return-path.ts +18 -0
- package/src/integrations/personal-github.ts +146 -52
- package/src/integrations/provider-oauth.ts +132 -21
- package/src/integrations/slack-install.ts +83 -0
- package/src/integrations/social-oauth.ts +142 -1
- package/src/mcp/documents.ts +1 -1
- package/src/mcp/server.ts +64 -17
- package/src/routes/api-integrations.ts +74 -64
- package/src/routes/connect.ts +1869 -0
- package/src/routes/connections.ts +263 -221
- package/src/routes/documents.ts +2 -2
- package/src/routes/external-identity-links.ts +200 -0
- package/src/routes/github.ts +39 -64
- package/src/routes/host-mcp-bindings.ts +122 -0
- package/src/routes/organization-memberships.ts +23 -0
- package/src/routes/organization-sessions.ts +2 -2
- package/src/routes/personal-github.ts +8 -1
- package/src/routes/pr-review-github.ts +30 -3
- package/src/routes/scheduled-tasks.ts +29 -4
- package/src/routes/sessions.ts +61 -32
- package/src/routes/social.ts +5 -1
- package/src/routes/supergrok.ts +90 -3
- package/src/routes/workspaces.ts +16 -0
- package/src/sandbox/rematerialize.ts +33 -1
- package/src/workspace-tool-gateway.ts +136 -24
- package/dist/chunk-5X3XM6CE.js.map +0 -1
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
+
import { ExternalActorContinuation } from "@opengeni/contracts/external-identities";
|
|
3
|
+
import { requireConnectOwnerAuthority } from "./connect-authority";
|
|
2
4
|
import {
|
|
3
5
|
configuredGoogleDriveSyncLimits,
|
|
4
6
|
googleDriveOAuthCallbackUrl,
|
|
@@ -46,7 +48,6 @@ import {
|
|
|
46
48
|
import {
|
|
47
49
|
captureScheduledTaskRestoreState,
|
|
48
50
|
createValidatedScheduledTask,
|
|
49
|
-
hasPermission,
|
|
50
51
|
manualScheduledTaskTriggerWorkflowId,
|
|
51
52
|
requireEnvironmentEncryption,
|
|
52
53
|
syncCreatedScheduledTask,
|
|
@@ -62,6 +63,10 @@ import {
|
|
|
62
63
|
ConnectionDisconnectGenerationError,
|
|
63
64
|
ConnectionDisconnectIdempotencyError,
|
|
64
65
|
consumeIntegrationOAuthStateNonce,
|
|
66
|
+
claimConnectOperation,
|
|
67
|
+
finishConnectOperation,
|
|
68
|
+
getConnectAttempt,
|
|
69
|
+
type Database,
|
|
65
70
|
createConnection,
|
|
66
71
|
decryptEnvironmentValue,
|
|
67
72
|
disconnectConnectionIdempotently,
|
|
@@ -70,7 +75,6 @@ import {
|
|
|
70
75
|
getConnectionMetadata,
|
|
71
76
|
getKnowledgeSourceByExternalIdentityForSyncAuthority,
|
|
72
77
|
getKnowledgeSourceForSyncAuthority,
|
|
73
|
-
getWorkspaceGrant,
|
|
74
78
|
listKnowledgeSourceSyncTasksForConnection,
|
|
75
79
|
loadConnectionCredentialForBroker,
|
|
76
80
|
listIntegrationInstanceFacets,
|
|
@@ -127,6 +131,8 @@ const GOOGLE_DRIVE_RECONSENT_ERROR_CODES = new Set([
|
|
|
127
131
|
]);
|
|
128
132
|
|
|
129
133
|
type GoogleDriveOAuthState = {
|
|
134
|
+
connectAttemptId?: string;
|
|
135
|
+
externalContinuation?: ExternalActorContinuation;
|
|
130
136
|
accountId: string;
|
|
131
137
|
workspaceId: string;
|
|
132
138
|
subjectId: string;
|
|
@@ -239,6 +245,8 @@ export async function startGoogleDriveOAuth(
|
|
|
239
245
|
subjectId: string;
|
|
240
246
|
requestUrl: string;
|
|
241
247
|
payload: GoogleDriveOAuthStartRequest;
|
|
248
|
+
connectAttemptId?: string;
|
|
249
|
+
externalContinuation?: ExternalActorContinuation;
|
|
242
250
|
},
|
|
243
251
|
): Promise<GoogleDriveOAuthStartResponse> {
|
|
244
252
|
const google = requireGoogleDriveSettings(deps.settings);
|
|
@@ -270,6 +278,15 @@ export async function startGoogleDriveOAuth(
|
|
|
270
278
|
workspaceId: input.workspaceId,
|
|
271
279
|
subjectId: input.subjectId,
|
|
272
280
|
kind: GOOGLE_DRIVE_OAUTH_STATE_KIND,
|
|
281
|
+
...(input.connectAttemptId ? { connectAttemptId: input.connectAttemptId } : {}),
|
|
282
|
+
...(input.externalContinuation
|
|
283
|
+
? {
|
|
284
|
+
encryptedExternalContinuation: encryptEnvironmentValue(
|
|
285
|
+
key,
|
|
286
|
+
JSON.stringify(ExternalActorContinuation.parse(input.externalContinuation)),
|
|
287
|
+
),
|
|
288
|
+
}
|
|
289
|
+
: {}),
|
|
273
290
|
// The route admits only a managed human, so reaching here is the proof; the
|
|
274
291
|
// callback has no live principal and enforces exactly this claim.
|
|
275
292
|
[PERSONAL_OWNER_VERIFIED_STATE_CLAIM]: true,
|
|
@@ -319,13 +336,37 @@ export async function completeGoogleDriveOAuthCallback(
|
|
|
319
336
|
pickedFileIds?: string | undefined;
|
|
320
337
|
requestUrl: string;
|
|
321
338
|
},
|
|
322
|
-
): Promise<{ redirectTo: string }> {
|
|
339
|
+
): Promise<{ redirectTo: string; exactReturn?: boolean }> {
|
|
323
340
|
const redirectUri = requireGoogleDriveOAuthCallbackUrl(deps.settings);
|
|
324
341
|
const baseUrl = integrationBaseUrl(deps.settings.publicBaseUrl, input.requestUrl);
|
|
325
342
|
const returnBaseUrl = deps.settings.webBaseUrl?.replace(/\/+$/, "") ?? baseUrl;
|
|
326
343
|
let state: GoogleDriveOAuthState | null = null;
|
|
344
|
+
let exactReturnUrl: string | undefined;
|
|
345
|
+
let operation: { attemptId: string; operationId: string; inputDigest: string } | undefined;
|
|
327
346
|
try {
|
|
328
347
|
state = readGoogleDriveOAuthState(input.state, deps.settings);
|
|
348
|
+
if (state.connectAttemptId) {
|
|
349
|
+
const stored = await getConnectAttempt(deps.db, state, state.connectAttemptId);
|
|
350
|
+
if (
|
|
351
|
+
stored.attempt.providerId !==
|
|
352
|
+
(state.capability === "publish" ? "google-drive-publish" : "google-drive-knowledge") ||
|
|
353
|
+
stored.attempt.ownership !== "personal"
|
|
354
|
+
)
|
|
355
|
+
throw new GoogleDriveCallbackError("connection_conflict");
|
|
356
|
+
exactReturnUrl = stored.returnUrl;
|
|
357
|
+
operation = {
|
|
358
|
+
attemptId: state.connectAttemptId,
|
|
359
|
+
operationId: `oauth:${state.nonce}`,
|
|
360
|
+
inputDigest: createHash("sha256").update(input.state!).digest("hex"),
|
|
361
|
+
};
|
|
362
|
+
const claim = await claimConnectOperation(deps.db, state, {
|
|
363
|
+
...operation,
|
|
364
|
+
expectedRevision: stored.attempt.revision,
|
|
365
|
+
authorize: (tx, _attempt, origin) =>
|
|
366
|
+
requireConnectOwnerAuthority(tx, state!, "connections:write", origin),
|
|
367
|
+
});
|
|
368
|
+
if (claim.status === "replayed") return { redirectTo: exactReturnUrl, exactReturn: true };
|
|
369
|
+
}
|
|
329
370
|
await requireGoogleDriveCallbackGrant(deps, state);
|
|
330
371
|
const consumed = await consumeIntegrationOAuthStateNonce(deps.db, {
|
|
331
372
|
accountId: state.accountId,
|
|
@@ -338,6 +379,25 @@ export async function completeGoogleDriveOAuthCallback(
|
|
|
338
379
|
if (!consumed) {
|
|
339
380
|
throw new HTTPException(400, { message: "Google Drive OAuth state has already been used" });
|
|
340
381
|
}
|
|
382
|
+
if (operation && (input.error || !input.code)) {
|
|
383
|
+
await finishConnectOperation(deps.db, state, {
|
|
384
|
+
...operation,
|
|
385
|
+
authorize: (tx, _attempt, origin) =>
|
|
386
|
+
requireConnectOwnerAuthority(tx, state!, "connections:write", origin),
|
|
387
|
+
commit: async (_tx, current) => ({
|
|
388
|
+
...current,
|
|
389
|
+
revision: current.revision + 1,
|
|
390
|
+
state: input.error === "access_denied" ? "cancelled" : "failed",
|
|
391
|
+
nextAction: { type: "none" },
|
|
392
|
+
error: {
|
|
393
|
+
code: input.error ? "provider_denied" : "missing_code",
|
|
394
|
+
message: "Authorization was not completed. Start a new connection attempt.",
|
|
395
|
+
retryable: false,
|
|
396
|
+
},
|
|
397
|
+
}),
|
|
398
|
+
});
|
|
399
|
+
return { redirectTo: exactReturnUrl!, exactReturn: true };
|
|
400
|
+
}
|
|
341
401
|
if (input.error) {
|
|
342
402
|
throw new GoogleDriveCallbackError("provider_denied");
|
|
343
403
|
}
|
|
@@ -402,16 +462,6 @@ export async function completeGoogleDriveOAuthCallback(
|
|
|
402
462
|
: previousMetadata?.outputDestination;
|
|
403
463
|
if (state.capability === "publish") {
|
|
404
464
|
if (!existing) throw new GoogleDriveCallbackError("connection_conflict");
|
|
405
|
-
await ensureConnectorActionPolicyDefault(deps.db, {
|
|
406
|
-
accountId: state.accountId,
|
|
407
|
-
workspaceId: state.workspaceId,
|
|
408
|
-
subjectId: state.subjectId,
|
|
409
|
-
connectionId: existing.id,
|
|
410
|
-
serverId: GOOGLE_DRIVE_PUBLICATION_SERVER_ID,
|
|
411
|
-
toolName: GOOGLE_DRIVE_PUBLICATION_TOOL_NAME,
|
|
412
|
-
actionName: GOOGLE_DRIVE_PUBLICATION_CREATE_ACTION,
|
|
413
|
-
policy: "ask",
|
|
414
|
-
});
|
|
415
465
|
}
|
|
416
466
|
let refreshToken = token.refreshToken;
|
|
417
467
|
if (!refreshToken && existing) {
|
|
@@ -461,34 +511,82 @@ export async function completeGoogleDriveOAuthCallback(
|
|
|
461
511
|
? { selectedSources: [previousMetadata.selectedSource] }
|
|
462
512
|
: {}),
|
|
463
513
|
});
|
|
464
|
-
const
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
providerDomain: GOOGLE_DRIVE_PROVIDER_DOMAIN,
|
|
472
|
-
kind: "oauth2",
|
|
473
|
-
status: "active",
|
|
474
|
-
credentialEncrypted,
|
|
475
|
-
grantedScopes,
|
|
476
|
-
expiresAt: token.expiresAt,
|
|
477
|
-
metadata,
|
|
478
|
-
updatedBySubjectId: state.subjectId,
|
|
479
|
-
})
|
|
480
|
-
: await createConnection(deps.db, {
|
|
514
|
+
const acceptedState = state;
|
|
515
|
+
const persist = async (tx: Database) => {
|
|
516
|
+
// Capture the validated immutable callback state for delayed persistence.
|
|
517
|
+
// eslint-disable-next-line no-shadow
|
|
518
|
+
const state = acceptedState;
|
|
519
|
+
if (state.capability === "publish" && existing)
|
|
520
|
+
await ensureConnectorActionPolicyDefault(tx, {
|
|
481
521
|
accountId: state.accountId,
|
|
482
522
|
workspaceId: state.workspaceId,
|
|
483
523
|
subjectId: state.subjectId,
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
metadata,
|
|
490
|
-
createdBySubjectId: state.subjectId,
|
|
524
|
+
connectionId: existing.id,
|
|
525
|
+
serverId: GOOGLE_DRIVE_PUBLICATION_SERVER_ID,
|
|
526
|
+
toolName: GOOGLE_DRIVE_PUBLICATION_TOOL_NAME,
|
|
527
|
+
actionName: GOOGLE_DRIVE_PUBLICATION_CREATE_ACTION,
|
|
528
|
+
policy: "ask",
|
|
491
529
|
});
|
|
530
|
+
return existing
|
|
531
|
+
? updateConnection(tx, {
|
|
532
|
+
workspaceId: state.workspaceId,
|
|
533
|
+
connectionId: existing.id,
|
|
534
|
+
visibleToSubjectId: state.subjectId,
|
|
535
|
+
expectedVersion: existing.version,
|
|
536
|
+
subjectId: state.subjectId,
|
|
537
|
+
providerDomain: GOOGLE_DRIVE_PROVIDER_DOMAIN,
|
|
538
|
+
kind: "oauth2",
|
|
539
|
+
status: "active",
|
|
540
|
+
credentialEncrypted,
|
|
541
|
+
grantedScopes,
|
|
542
|
+
expiresAt: token.expiresAt,
|
|
543
|
+
metadata,
|
|
544
|
+
updatedBySubjectId: state.subjectId,
|
|
545
|
+
})
|
|
546
|
+
: createConnection(tx, {
|
|
547
|
+
accountId: state.accountId,
|
|
548
|
+
workspaceId: state.workspaceId,
|
|
549
|
+
subjectId: state.subjectId,
|
|
550
|
+
providerDomain: GOOGLE_DRIVE_PROVIDER_DOMAIN,
|
|
551
|
+
kind: "oauth2",
|
|
552
|
+
credentialEncrypted,
|
|
553
|
+
grantedScopes,
|
|
554
|
+
expiresAt: token.expiresAt,
|
|
555
|
+
metadata,
|
|
556
|
+
createdBySubjectId: state.subjectId,
|
|
557
|
+
});
|
|
558
|
+
};
|
|
559
|
+
if (operation) {
|
|
560
|
+
await finishConnectOperation(deps.db, acceptedState, {
|
|
561
|
+
...operation,
|
|
562
|
+
authorize: (tx, _attempt, origin) =>
|
|
563
|
+
requireConnectOwnerAuthority(tx, acceptedState, "connections:write", origin),
|
|
564
|
+
commit: async (tx, current) => {
|
|
565
|
+
const connection = await persist(tx);
|
|
566
|
+
if (!connection) throw new GoogleDriveCallbackError("connection_conflict");
|
|
567
|
+
return {
|
|
568
|
+
...current,
|
|
569
|
+
revision: current.revision + 1,
|
|
570
|
+
state: "complete",
|
|
571
|
+
credentialsCommitted: true,
|
|
572
|
+
nextAction: { type: "none" },
|
|
573
|
+
account: {
|
|
574
|
+
id: connection.id,
|
|
575
|
+
version: connection.version,
|
|
576
|
+
providerId: current.providerId,
|
|
577
|
+
label: identity.emailAddress ?? identity.displayName,
|
|
578
|
+
ownership: "personal",
|
|
579
|
+
status: "connected",
|
|
580
|
+
},
|
|
581
|
+
};
|
|
582
|
+
},
|
|
583
|
+
});
|
|
584
|
+
return { redirectTo: exactReturnUrl!, exactReturn: true };
|
|
585
|
+
}
|
|
586
|
+
const connection = await deps.db.transaction(async (tx) => {
|
|
587
|
+
await requireGoogleDriveCallbackGrant({ ...deps, db: tx }, acceptedState);
|
|
588
|
+
return persist(tx);
|
|
589
|
+
});
|
|
492
590
|
if (!connection) {
|
|
493
591
|
throw new GoogleDriveCallbackError("connection_conflict");
|
|
494
592
|
}
|
|
@@ -496,6 +594,7 @@ export async function completeGoogleDriveOAuthCallback(
|
|
|
496
594
|
redirectTo: googleDriveReturnUrl(returnBaseUrl, state.returnPath, "connected", connection.id),
|
|
497
595
|
};
|
|
498
596
|
} catch (error) {
|
|
597
|
+
if (exactReturnUrl) return { redirectTo: exactReturnUrl, exactReturn: true };
|
|
499
598
|
return {
|
|
500
599
|
redirectTo: googleDriveReturnUrl(
|
|
501
600
|
returnBaseUrl,
|
|
@@ -2017,6 +2116,21 @@ function readGoogleDriveOAuthState(
|
|
|
2017
2116
|
workspaceId,
|
|
2018
2117
|
subjectId,
|
|
2019
2118
|
personalOwnerVerified: personalOwnerVerifiedInState(payload),
|
|
2119
|
+
...(typeof payload.connectAttemptId === "string"
|
|
2120
|
+
? { connectAttemptId: payload.connectAttemptId }
|
|
2121
|
+
: {}),
|
|
2122
|
+
...(typeof payload.encryptedExternalContinuation === "string"
|
|
2123
|
+
? {
|
|
2124
|
+
externalContinuation: ExternalActorContinuation.parse(
|
|
2125
|
+
JSON.parse(
|
|
2126
|
+
decryptEnvironmentValue(
|
|
2127
|
+
requireEnvironmentEncryption(settings),
|
|
2128
|
+
payload.encryptedExternalContinuation,
|
|
2129
|
+
),
|
|
2130
|
+
),
|
|
2131
|
+
),
|
|
2132
|
+
}
|
|
2133
|
+
: {}),
|
|
2020
2134
|
returnPath,
|
|
2021
2135
|
encryptedPkceVerifier: requiredString(
|
|
2022
2136
|
payload.encryptedPkceVerifier,
|
|
@@ -2048,16 +2162,7 @@ async function requireGoogleDriveCallbackGrant(
|
|
|
2048
2162
|
message: personalOnlyConnectionPrincipalMessage("Google Drive"),
|
|
2049
2163
|
});
|
|
2050
2164
|
}
|
|
2051
|
-
|
|
2052
|
-
if (
|
|
2053
|
-
!grant ||
|
|
2054
|
-
grant.accountId !== state.accountId ||
|
|
2055
|
-
!hasPermission(grant.permissions, "connections:write")
|
|
2056
|
-
) {
|
|
2057
|
-
throw new HTTPException(403, {
|
|
2058
|
-
message: "Google Drive OAuth subject no longer has permission for this workspace",
|
|
2059
|
-
});
|
|
2060
|
-
}
|
|
2165
|
+
await requireConnectOwnerAuthority(deps.db, state, "connections:write");
|
|
2061
2166
|
}
|
|
2062
2167
|
|
|
2063
2168
|
async function exchangeGoogleAuthorizationCode(
|