MCPcopy Create free account
hub / github.com/UsefulSoftwareCo/executor / start

Function start

packages/core/sdk/src/oauth-service.ts:1402–1823  ·  view source on GitHub ↗
(
    input: OAuthStartInput,
  )

Source from the content-addressed store, hash-verified

1400 // start — begin a flow through a client to mint a connection.
1401 // -----------------------------------------------------------------------
1402 const start = (
1403 input: OAuthStartInput,
1404 ): Effect.Effect<ConnectResult, OAuthStartError | StorageFailure> =>
1405 Effect.gen(function* () {
1406 const keys = yield* Effect.try({
1407 try: () => deps.ownedKeys(input.owner),
1408 catch: (cause) =>
1409 new StorageError({
1410 message: "Cannot start OAuth flow for owner without a subject",
1411 cause,
1412 }),
1413 });
1414 // Sharing is one-directional (org → members): a Workspace (org) connection
1415 // cannot be backed by a member's private (user) app. The connection owner
1416 // and the app owner are otherwise independent — a Personal connection
1417 // through a shared Workspace app is the supported cross-owner case.
1418 // First-party apps are deployment-owned, outside the owner lattice
1419 // entirely, so the rule does not apply to them.
1420 const firstPartyFlow = isFirstPartyOAuthClientSlug(String(input.client));
1421 yield* Effect.annotateCurrentSpan({
1422 "executor.oauth.client_first_party": firstPartyFlow,
1423 });
1424 if (!firstPartyFlow && input.owner === "org" && input.clientOwner === "user") {
1425 return yield* new OAuthStartError({
1426 message: "A Workspace connection must use a Workspace app.",
1427 });
1428 }
1429 // Load the app by its EXPLICIT owner (the caller knows it — no derivation).
1430 // The connection is still minted under `input.owner`. Storage visibility
1431 // policy hides apps the actor cannot see, so a wrong owner yields null.
1432 const client = yield* loadClient(input.clientOwner, input.client);
1433 if (!client) {
1434 return yield* new OAuthStartError({
1435 message: `OAuth client not found: ${input.client}`,
1436 });
1437 }
1438
1439 // Normalize the name the same way the mint stores it, so the free-name
1440 // guard below compares against the exact stored form.
1441 const requestedName = connectionIdentifier(String(input.name));
1442 // newConnection: resolve the requested name to a FREE one against the
1443 // stored rows (not a client-side, policy-filtered view), so a second
1444 // untyped connect mints `personalGmail2` instead of silently re-minting
1445 // the first account's row. Reconnects omit the flag and keep targeting
1446 // their existing row. Bounded: a pathological owner with 1000 same-named
1447 // connections fails loudly rather than scanning forever.
1448 let name = requestedName;
1449 if (input.newConnection === true) {
1450 let suffix = 2;
1451 while (
1452 yield* deps.connectionNameTaken({
1453 owner: input.owner,
1454 integration: input.integration,
1455 name,
1456 })
1457 ) {
1458 if (suffix > 1000) {
1459 return yield* new OAuthStartError({

Callers

nothing calls this directly

Calls 15

connectionIdentifierFunction · 0.90
createPkceCodeVerifierFunction · 0.90
createPkceCodeChallengeFunction · 0.90
createOAuthStateFunction · 0.90
encodeOAuthCallbackStateFunction · 0.90
buildAuthorizationUrlFunction · 0.90
providerAuthorizeExtrasFunction · 0.90
loadClientFunction · 0.85

Tested by

no test coverage detected