import { SecretReference, type EnvironmentId, type SecretProviderConfig, type SecretProviderId, type SecretProviderKind, } from "@t3tools/contracts"; import { builtInSecretProviderDefinitions } from "@t3tools/secret-provider-definitions/registry"; import { useAtomValue } from "@effect/atom-react"; import * as Option from "effect/Option"; import * as Schema from "effect/Schema"; import { KeyRoundIcon, TypeIcon } from "lucide-react"; import { useState, type ComponentProps, type ComponentType, type ReactNode } from "react"; import { isSecretsFeatureEnabled } from "../../env"; import { useEnvironmentSettings } from "../../hooks/useSettings"; import { OnePasswordIcon } from "../Icons"; import { serverEnvironment } from "../../state/server"; import { DraftInput } from "../ui/draft-input"; import { Select, SelectItem, SelectPopup, SelectTrigger, SelectValue } from "../ui/select"; import { SecretInput } from "./SecretInput"; import { classifySecretProvider } from "./SecretProviderDialog.logic"; export interface SecretSource { readonly id: SecretProviderId; readonly kind: SecretProviderKind; readonly label: string; } const NO_SECRET_SOURCES: ReadonlyArray = []; const STORED_VALUE = "__stored__"; const decodeSecretReference = Schema.decodeUnknownOption(SecretReference); /** Secret providers a setting can point at; empty when the environment cannot read references. */ export function useSecretSources(environmentId: EnvironmentId): ReadonlyArray { const providers = useEnvironmentSettings(environmentId, (settings) => settings.secretProviders); const supported = useAtomValue( serverEnvironment.configValueAtom(environmentId), (config) => config?.secretReferences === true, ); if (!isSecretsFeatureEnabled || !supported) return NO_SECRET_SOURCES; return (Object.entries(providers) as Array<[SecretProviderId, SecretProviderConfig]>) .filter(([, config]) => classifySecretProvider(config).kind !== "unsupported") .map(([id, config]) => ({ id, kind: config.kind, label: config.label })); } function SourceIcon(props: { readonly icon: ComponentType<{ readonly className?: string }> }) { return ; } function SourceLabel(props: { readonly icon: ComponentType<{ readonly className?: string }>; readonly label: string; }) { return ( {props.label} ); } type SecretSourceInputProps = Omit, "value" | "children"> & { readonly value: string | SecretReference; readonly sources: ReadonlyArray; readonly onSecretChange: (secret: SecretReference | undefined) => void; /** Places the parts in the caller's layout; `source` is null when there is nothing to pick. */ readonly children?: (parts: { readonly source: ReactNode; readonly value: ReactNode; }) => ReactNode; }; /** A secret entered here, or read from a secret provider when one is configured. */ export function SecretSourceInput({ value, sources, onSecretChange, children, ...rest }: SecretSourceInputProps) { // A provider picked here applies once a reference for it is committed. const [pendingProvider, setPendingProvider] = useState(null); const [rejectedReference, setRejectedReference] = useState(null); const secret = typeof value === "string" ? undefined : value; const input = { ...rest, value: typeof value === "string" ? value : "" }; const provider = pendingProvider ?? secret?.provider ?? null; const reference = secret !== undefined && secret.provider === provider ? secret.reference : ""; const providerSource = sources.find((source) => source.id === provider); const definition = providerSource && builtInSecretProviderDefinitions.find(providerSource.kind); const label = input["aria-label"] ?? "Secret"; const providerLabel = (id: SecretProviderId) => sources.find((source) => source.id === id)?.label ?? id; const providerIcon = (id: SecretProviderId) => sources.some((source) => source.id === id) ? OnePasswordIcon : KeyRoundIcon; const source = sources.length === 0 && provider === null ? null : ( ); const valueField = provider === null ? ( ) : (
{ if (next.trim().length === 0) { setRejectedReference(null); if (pendingProvider === null && secret !== undefined) onSecretChange(undefined); return; } const decoded = decodeSecretReference({ provider, reference: next }); if ( Option.isNone(decoded) || definition?.isReference(decoded.value.reference) === false ) { setRejectedReference(next); return; } setRejectedReference(null); setPendingProvider(null); onSecretChange(decoded.value); }} autoComplete="off" placeholder={definition?.referencePlaceholder} spellCheck={false} aria-label={`${label} reference`} aria-invalid={rejectedReference !== null} /> {rejectedReference !== null ? (

{definition?.invalidReferenceMessage ?? "Enter a valid secret reference."}

) : null}
); if (children !== undefined) return children({ source, value: valueField }); if (source === null) return valueField; return (
{source} {valueField}
); }