@@ -26,6 +26,7 @@ import {
2626 type EnvironmentId ,
2727 type ProjectId ,
2828 type ProviderDriverKind ,
29+ type SecretReference ,
2930 type ServerProvider ,
3031 type ServerProviderModel ,
3132} from "@t3tools/contracts" ;
@@ -43,7 +44,7 @@ import { Badge } from "../ui/badge";
4344import { Button } from "../ui/button" ;
4445import { MorphIcon } from "~/components/MorphIcon" ;
4546import { DraftInput } from "../ui/draft-input" ;
46- import { SecretInput } from "./SecretInput " ;
47+ import { SecretSourceInput , type SecretSource } from "./SecretSourceInput " ;
4748import { Popover , PopoverPopup , PopoverTrigger } from "../ui/popover" ;
4849import { Switch } from "../ui/switch" ;
4950import { stackedThreadToast , toastManager } from "../ui/toast" ;
@@ -98,7 +99,7 @@ const nextEnvironmentVariableDraftId = () => `provider-env-${environmentVariable
9899type EnvironmentDraftRow = {
99100 readonly id : string ;
100101 readonly name : string ;
101- readonly value : string ;
102+ readonly value : ProviderInstanceEnvironmentVariable [ "value" ] ;
102103 readonly sensitive : boolean ;
103104 readonly valueRedacted ?: boolean ;
104105} ;
@@ -119,6 +120,14 @@ function makeEnvironmentDraftRow(
119120const toEnvironmentDraftRows = ( environment : ReadonlyArray < ProviderInstanceEnvironmentVariable > ) =>
120121 environment . map ( makeEnvironmentDraftRow ) ;
121122
123+ function environmentValuesEqual (
124+ left : ProviderInstanceEnvironmentVariable [ "value" ] ,
125+ right : ProviderInstanceEnvironmentVariable [ "value" ] ,
126+ ) : boolean {
127+ if ( typeof left === "string" || typeof right === "string" ) return left === right ;
128+ return left . provider === right . provider && left . reference === right . reference ;
129+ }
130+
122131function providerEnvironmentsEqual (
123132 left : ReadonlyArray < ProviderInstanceEnvironmentVariable > ,
124133 right : ReadonlyArray < ProviderInstanceEnvironmentVariable > ,
@@ -130,7 +139,7 @@ function providerEnvironmentsEqual(
130139 return (
131140 other !== undefined &&
132141 variable . name === other . name &&
133- variable . value === other . value &&
142+ environmentValuesEqual ( variable . value , other . value ) &&
134143 variable . sensitive === other . sensitive &&
135144 variable . valueRedacted === other . valueRedacted
136145 ) ;
@@ -247,12 +256,28 @@ export function nextProviderEnvironmentWithFieldValue(
247256 return next ;
248257}
249258
259+ export function nextProviderEnvironmentWithFieldSecret (
260+ environment : ReadonlyArray < ProviderInstanceEnvironmentVariable > | undefined ,
261+ field : ProviderEnvironmentField ,
262+ secret : SecretReference | undefined ,
263+ ) : ReadonlyArray < ProviderInstanceEnvironmentVariable > {
264+ const others = providerEnvironmentWithoutNames ( environment , new Set ( [ field . name ] ) ) ;
265+ return secret === undefined
266+ ? others
267+ : [ ...others , { name : field . name , value : secret , sensitive : true } ] ;
268+ }
269+
250270function ProviderEnvironmentFieldRow ( props : {
251271 readonly field : ProviderEnvironmentField ;
252272 readonly variable : ProviderInstanceEnvironmentVariable | undefined ;
253273 readonly idPrefix : string ;
254274 readonly onCommit : ( field : ProviderEnvironmentField , value : string ) => void ;
275+ readonly onSecretChange : (
276+ field : ProviderEnvironmentField ,
277+ secret : SecretReference | undefined ,
278+ ) => void ;
255279 readonly onRemove : ( field : ProviderEnvironmentField ) => void ;
280+ readonly secretSources : ReadonlyArray < SecretSource > ;
256281} ) {
257282 const inputId = `${ props . idPrefix } -environment-${ props . field . name } ` ;
258283 const value = props . variable ?. valueRedacted ? "" : ( props . variable ?. value ?? "" ) ;
@@ -269,13 +294,13 @@ function ProviderEnvironmentFieldRow(props: {
269294 size = "sm"
270295 className = "min-w-0 flex-1"
271296 autoComplete = "off"
272- value = { value }
297+ value = { typeof value === "string" ? value : "" }
273298 onCommit = { ( next ) => props . onCommit ( props . field , next ) }
274299 placeholder = { props . field . placeholder }
275300 spellCheck = { false }
276301 />
277302 ) : (
278- < SecretInput
303+ < SecretSourceInput
279304 id = { inputId }
280305 size = "sm"
281306 className = "min-w-0 flex-1"
@@ -284,6 +309,9 @@ function ProviderEnvironmentFieldRow(props: {
284309 placeholder = { props . field . placeholder }
285310 configured = { props . variable ?. valueRedacted === true }
286311 spellCheck = { false }
312+ aria-label = { props . field . label }
313+ sources = { props . secretSources }
314+ onSecretChange = { ( secret ) => props . onSecretChange ( props . field , secret ) }
287315 />
288316 ) }
289317 { props . variable ? (
@@ -306,6 +334,7 @@ function ProviderEnvironmentFieldRow(props: {
306334export function ProviderEnvironmentSection ( props : {
307335 readonly environment : ReadonlyArray < ProviderInstanceEnvironmentVariable > ;
308336 readonly onChange : ( environment : ReadonlyArray < ProviderInstanceEnvironmentVariable > ) => void ;
337+ readonly secretSources ?: ReadonlyArray < SecretSource > ;
309338} ) {
310339 const [ storedDraft , setDraft ] = useState ( ( ) =>
311340 seedRowsDraft ( props . environment , toEnvironmentDraftRows ) ,
@@ -328,7 +357,7 @@ export function ProviderEnvironmentSection(props: {
328357 if ( ! ENVIRONMENT_VARIABLE_NAME_PATTERN . test ( name ) ) {
329358 if (
330359 name . length > 0 ||
331- row . value . length > 0 ||
360+ row . value !== "" ||
332361 row . sensitive !== true ||
333362 row . valueRedacted !== undefined
334363 ) {
@@ -357,6 +386,16 @@ export function ProviderEnvironmentSection(props: {
357386 publishRows ( nextRows ) ;
358387 } ;
359388
389+ const setVariableSecret = ( id : string , secret : SecretReference | undefined ) => {
390+ const nextRows = rows . map ( ( row ) => {
391+ if ( row . id !== id ) return row ;
392+ const { valueRedacted : _valueRedacted , ...rest } = row ;
393+ return { ...rest , value : secret ?? "" } ;
394+ } ) ;
395+ setRows ( nextRows ) ;
396+ publishRows ( nextRows ) ;
397+ } ;
398+
360399 const removeVariable = ( id : string ) => {
361400 const nextRows = rows . filter ( ( row ) => row . id !== id ) ;
362401 setRows ( nextRows ) ;
@@ -403,7 +442,7 @@ export function ProviderEnvironmentSection(props: {
403442 =
404443 </ span >
405444 { variable . sensitive ? (
406- < SecretInput
445+ < SecretSourceInput
407446 size = "sm"
408447 font = "mono"
409448 className = "min-w-0 flex-1"
@@ -413,13 +452,19 @@ export function ProviderEnvironmentSection(props: {
413452 configured = { variable . valueRedacted === true }
414453 spellCheck = { false }
415454 aria-label = { `Environment variable value ${ index + 1 } ` }
455+ sources = { props . secretSources ?? [ ] }
456+ onSecretChange = { ( secret ) => setVariableSecret ( variable . id , secret ) }
416457 />
417458 ) : (
418459 < DraftInput
419460 size = "sm"
420461 font = "mono"
421462 className = "min-w-0 flex-1"
422- value = { variable . valueRedacted ? "" : variable . value }
463+ value = {
464+ variable . valueRedacted || typeof variable . value !== "string"
465+ ? ""
466+ : variable . value
467+ }
423468 onCommit = { ( value ) => updateVariable ( variable . id , { value } ) }
424469 autoComplete = "off"
425470 placeholder = "value"
@@ -444,6 +489,7 @@ export function ProviderEnvironmentSection(props: {
444489 } ) ;
445490 } }
446491 aria-pressed = { variable . sensitive }
492+ disabled = { typeof variable . value !== "string" }
447493 aria-label = { `Mark environment variable ${ variable . name || index + 1 } as sensitive` }
448494 >
449495 < MorphIcon
@@ -584,6 +630,7 @@ interface ProviderInstanceCardProps {
584630 readonly isUpdating ?: boolean | undefined ;
585631 readonly onAcceptUrlAuth ?: ( ( action : AcpRegistryUrlAuthAction ) => void ) | undefined ;
586632 readonly environmentId ?: EnvironmentId | undefined ;
633+ readonly secretSources ?: ReadonlyArray < SecretSource > ;
587634 readonly projectOverride ?: ProjectOverrideControl | undefined ;
588635 readonly acpProjects ?:
589636 | ReadonlyArray < {
@@ -595,6 +642,7 @@ interface ProviderInstanceCardProps {
595642}
596643
597644const EMPTY_ACP_PROJECTS : NonNullable < ProviderInstanceCardProps [ "acpProjects" ] > = [ ] ;
645+ const NO_SECRET_SOURCES : ReadonlyArray < SecretSource > = [ ] ;
598646const NO_CUSTOM_MODELS : ReadonlyArray < CustomModelDefinition > = [ ] ;
599647
600648/** Unknown drivers stay read-only to preserve fork config. projectOverride switches affect only the
@@ -627,6 +675,7 @@ export function ProviderInstanceCard({
627675 onAcceptUrlAuth,
628676 environmentId,
629677 acpProjects = EMPTY_ACP_PROJECTS ,
678+ secretSources = NO_SECRET_SOURCES ,
630679 projectOverride,
631680} : ProviderInstanceCardProps ) {
632681 const enabled = projectOverride ?. effectiveEnabled ?? resolveProviderInstanceEnabled ( instance ) ;
@@ -781,6 +830,12 @@ export function ProviderInstanceCard({
781830 const updateEnvironmentField = ( field : ProviderEnvironmentField , value : string ) => {
782831 updateEnvironment ( nextProviderEnvironmentWithFieldValue ( instance . environment , field , value ) ) ;
783832 } ;
833+ const updateEnvironmentFieldSecret = (
834+ field : ProviderEnvironmentField ,
835+ secret : SecretReference | undefined ,
836+ ) => {
837+ updateEnvironment ( nextProviderEnvironmentWithFieldSecret ( instance . environment , field , secret ) ) ;
838+ } ;
784839 const removeEnvironmentField = ( field : ProviderEnvironmentField ) => {
785840 updateEnvironment ( providerEnvironmentWithoutNames ( instance . environment , new Set ( [ field . name ] ) ) ) ;
786841 } ;
@@ -1182,7 +1237,9 @@ export function ProviderInstanceCard({
11821237 variable = { readProviderEnvironmentVariable ( instance . environment , field . name ) }
11831238 idPrefix = { `provider-instance-${ instanceId } ` }
11841239 onCommit = { updateEnvironmentField }
1240+ onSecretChange = { updateEnvironmentFieldSecret }
11851241 onRemove = { removeEnvironmentField }
1242+ secretSources = { secretSources }
11861243 />
11871244 ) ) }
11881245 </ div >
@@ -1225,6 +1282,7 @@ export function ProviderInstanceCard({
12251282 < ProviderEnvironmentSection
12261283 environment = { genericEnvironment }
12271284 onChange = { updateGenericEnvironment }
1285+ secretSources = { secretSources }
12281286 />
12291287 </ SettingsSection >
12301288 { environmentId !== undefined && liveProvider ?. driver === "acpRegistry" ? (
0 commit comments