import { Suspense } from "react"; import { useAtomValue } from "@effect/atom-react"; import * as AsyncResult from "effect/unstable/reactivity/AsyncResult"; import type { ProviderKey } from "@executor-js/sdk/shared"; import { useSecretProviderPlugins } from "@executor-js/sdk/client"; import { providersAtom } from "../api/atoms"; import { CardStack, CardStackContent, CardStackEntry, CardStackEntryActions, CardStackEntryContent, CardStackEntryDescription, CardStackEntryTitle, CardStackHeader, } from "../components/card-stack"; import { Badge } from "../components/badge"; // --------------------------------------------------------------------------- // Providers page (v2) — repurposed from the v1 Secrets page. // // v1 stored standalone secrets and bound them per-source. v2 makes a connection // the credential, and a `CredentialProvider` is where its value lives (the // default store for pasted values, or an external backend like 1Password / // keychain). This page surfaces the registered providers plus any provider // plugin's settings card. The route still exports `SecretsPage` so existing app // wiring keeps resolving; new callers should treat it as the Providers view. // --------------------------------------------------------------------------- const PROVIDER_LABELS: Record = { default: "Default store", keychain: "Keychain", file: "Local file", memory: "Memory", onepassword: "1Password", "workos-vault": "WorkOS Vault", }; const providerLabel = (key: string): string => PROVIDER_LABELS[key] ?? key; export function SecretsPage(props: { showProviderInfo?: boolean }) { const showProviderInfo = props.showProviderInfo ?? true; const secretProviderPlugins = useSecretProviderPlugins(); const providers = useAtomValue(providersAtom); return (
{/* Header */}

Providers

Where your connections' credential values live — the default store for pasted values, or an external backend like 1Password or your system keychain.

{/* Provider plugins (settings cards) */} {showProviderInfo && secretProviderPlugins.length > 0 && (
Configure providers {secretProviderPlugins.map((plugin) => (
} >
))}
)} {/* Registered providers */} {AsyncResult.match(providers, { onInitial: () => (

Loading providers…

), onFailure: () => (

Failed to load providers

), onSuccess: ({ value }) => ( Available providers {value.length === 0 ? ( No credential providers are registered. ) : ( value.map((key: ProviderKey) => ( {providerLabel(String(key))} {String(key)} provider )) )} ), })}
); }