| 1 | import * as Effect from "effect/Effect"; |
| 2 | import * as Output from "../Output.ts"; |
| 3 | import type { ProviderMode } from "../ProviderMode.ts"; |
| 4 | import { isResource, type ResourceLike } from "../Resource.ts"; |
| 5 | import type { AIGatewayProps } from "./AIGateway.ts"; |
| 6 | |
| 7 | type CredentialScope = Pick<AIGatewayProps, "branch" | "project">; |
| 8 | |
| 9 | export const scopeIdentity = (scope: CredentialScope) => { |
| 10 | const source = scope.branch ?? scope.project; |
| 11 | if (isResource(source)) return `${source.Type}:${source.FQN}`; |
| 12 | if (Effect.isEffect(source) || Output.isOutput(source)) return undefined; |
| 13 | if ( |
| 14 | typeof scope.branch?.projectId === "string" && |
| 15 | typeof scope.branch.branchId === "string" |
| 16 | ) { |
| 17 | return `branch:${scope.branch.projectId}:${scope.branch.branchId}`; |
| 18 | } |
| 19 | if (typeof scope.project?.projectId === "string") |
| 20 | return `project:${scope.project.projectId}`; |
| 21 | return undefined; |
| 22 | }; |
| 23 | |
| 24 | /** Unknown scope identity falls back to a managed credential. */ |
| 25 | export const usesInjectedCredentials = ( |
| 26 | host: Pick<ResourceLike, "Type" | "Props" | "Mode"> | undefined, |
| 27 | target: CredentialScope, |
| 28 | defaultMode: ProviderMode, |
| 29 | ) => { |
| 30 | if (host?.Type !== "Neon.Function" || (host.Mode ?? defaultMode) !== "live") |
| 31 | return false; |
| 32 | const current: CredentialScope | undefined = host.Props; |
| 33 | if (!current || Effect.isEffect(current) || Output.isOutput(current)) |
| 34 | return false; |
| 35 | return ( |
| 36 | (current.branch !== undefined && current.branch === target.branch) || |
| 37 | (current.project !== undefined && current.project === target.project) || |
| 38 | (scopeIdentity(current) !== undefined && |
| 39 | scopeIdentity(current) === scopeIdentity(target)) |
| 40 | ); |
| 41 | }; |