(userId: string)
| 203 | |
| 204 | /** Enrich a bare OAuth `userId` into the full provider-neutral principal. */ |
| 205 | const principalFromUserId = (userId: string): Effect.Effect<Principal | null> => |
| 206 | Effect.gen(function* () { |
| 207 | const user = yield* Effect.promise(() => context.internalAdapter.findUserById(userId)); |
| 208 | if (!user) return null; |
| 209 | // The workspace role, read from the INSTANCE org's membership row |
| 210 | // (an OAuth token carries no session, so the header-based |
| 211 | // `getActiveMemberRole` gate is out of reach — the adapter query |
| 212 | // answers the same question against the same table). FAIL CLOSED to |
| 213 | // "member": an infra fault demotes rather than escalates. |
| 214 | const membership = yield* Effect.promise(() => |
| 215 | context.adapter.findOne<{ readonly role?: string | null }>({ |
| 216 | model: "member", |
| 217 | where: [ |
| 218 | { field: "userId", value: userId }, |
| 219 | { field: "organizationId", value: organizationId }, |
| 220 | ], |
| 221 | }), |
| 222 | ).pipe(Effect.orElseSucceed(() => null)); |
| 223 | const orgRole = |
| 224 | membership?.role != null && isPrivileged(membership.role) |
| 225 | ? ("admin" as const) |
| 226 | : ("member" as const); |
| 227 | return { |
| 228 | accountId: user.id, |
| 229 | // Single-org self-host: OAuth tokens carry no active org, so pin to |
| 230 | // the seeded org (same default as the cookie/api-key path). |
| 231 | organizationId, |
| 232 | organizationName, |
| 233 | organizationSlug, |
| 234 | email: user.email ?? "", |
| 235 | name: user.name ?? null, |
| 236 | avatarUrl: user.image ?? null, |
| 237 | roles: parseRoles(userRole(user)), |
| 238 | orgRoleModel: "organization", |
| 239 | orgRole, |
| 240 | } satisfies Principal; |
| 241 | }); |
| 242 | |
| 243 | /** (a) The mcp() OAuth opaque bearer, with self-enforced expiry. */ |
| 244 | const authenticateOAuthBearer = (request: Request): Effect.Effect<Principal | null> => |
no test coverage detected