Unified · Split
| @@ -46,16 +46,7 @@ export interface KeychainPluginConfig { · 45 unmodified lines | |||
| 46 | // Plugin extension — public API on executor.keychain | 46 | // Plugin extension — public API on executor.keychain |
| 47 | // --------------------------------------------------------------------------- | 47 | // --------------------------------------------------------------------------- |
| 48 | 48 | ||
| 49 | export interface KeychainExtension { | 49 | export type KeychainExtension = ReturnType<typeof makeKeychainExtension>; |
| 50 | /** Human-readable name for the keychain on this platform */ | ||
| 51 | readonly displayName: string; | ||
| 52 | |||
| 53 | /** Whether the current platform supports system keychain */ | ||
| 54 | readonly isSupported: boolean; | ||
| 55 | |||
| 56 | /** Check if a secret exists in the system keychain */ | ||
| 57 | readonly has: (id: string) => Effect.Effect<boolean>; | ||
| 58 | } | ||
| 59 | 50 | ||
| 60 | // --------------------------------------------------------------------------- | 51 | // --------------------------------------------------------------------------- |
| 61 | // Plugin definition | 52 | // Plugin definition |
| @@ -69,25 +60,35 @@ const scopedServiceName = ( · 7 unmodified lines | |||
| 69 | ctx: PluginCtx<unknown>, | 60 | ctx: PluginCtx<unknown>, |
| 70 | options: KeychainPluginConfig | undefined, | 61 | options: KeychainPluginConfig | undefined, |
| 71 | ): string => | 62 | ): string => |
| 72 | `${resolveServiceName(options?.serviceName)}/${ctx.scopes[0]!.id as string}`; | 63 | `${resolveServiceName(options?.serviceName)}/${ctx.scopes[0]!.id}`; |
| 64 | |||
| 65 | const makeKeychainExtension = ( | ||
| 66 | ctx: PluginCtx<unknown>, | ||
| 67 | options: KeychainPluginConfig | undefined, | ||
| 68 | ) => { | ||
| 69 | const serviceName = scopedServiceName(ctx, options); | ||
| 70 | return { | ||
| 71 | /** Human-readable name for the keychain on this platform */ | ||
| 72 | displayName: displayName(), | ||
| 73 | |||
| 74 | /** Whether the current platform supports system keychain */ | ||
| 75 | isSupported: isSupportedPlatform(), | ||
| 76 | |||
| 77 | /** Check if a secret exists in the system keychain */ | ||
| 78 | has: (id: string) => | ||
| 79 | getPassword(serviceName, id).pipe( | ||
| 80 | Effect.map((v) => v !== null), | ||
| 81 | Effect.orElseSucceed(() => false), | ||
| 82 | ), | ||
| 83 | }; | ||
| 84 | }; | ||
| 73 | 85 | ||
| 74 | export const keychainPlugin = definePlugin( | 86 | export const keychainPlugin = definePlugin( |
| 75 | (options?: KeychainPluginConfig) => ({ | 87 | (options?: KeychainPluginConfig) => ({ |
| 76 | id: "keychain" as const, | 88 | id: "keychain" as const, |
| 77 | storage: () => ({}), | 89 | storage: () => ({}), |
| 78 | 90 | ||
| 79 | extension: (ctx): KeychainExtension => { | 91 | extension: (ctx): KeychainExtension => makeKeychainExtension(ctx, options), |
| 80 | const serviceName = scopedServiceName(ctx, options); | ||
| 81 | return { | ||
| 82 | displayName: displayName(), | ||
| 83 | isSupported: isSupportedPlatform(), | ||
| 84 | has: (id) => | ||
| 85 | getPassword(serviceName, id).pipe( | ||
| 86 | Effect.map((v) => v !== null), | ||
| 87 | Effect.orElseSucceed(() => false), | ||
| 88 | ), | ||
| 89 | }; | ||
| 90 | }, | ||
| 91 | 92 | ||
| 92 | secretProviders: (ctx): Effect.Effect<readonly SecretProvider[]> => | 93 | secretProviders: (ctx): Effect.Effect<readonly SecretProvider[]> => |
| 93 | Effect.gen(function* () { | 94 | Effect.gen(function* () { |
| @@ -103,9 +104,9 @@ export const keychainPlugin = definePlugin( · 9 unmodified lines | |||
| 103 | ), | 104 | ), |
| 104 | ), | 105 | ), |
| 105 | Effect.as(true), | 106 | Effect.as(true), |
| 106 | Effect.catch((cause) => | 107 | Effect.catch(() => |
| 107 | Effect.logWarning( | 108 | Effect.logWarning( |
| 108 | `keychain unavailable, skipping provider registration: ${cause.message}`, | 109 | "keychain unavailable, skipping provider registration", |
| 109 | ).pipe(Effect.as(false)), | 110 | ).pipe(Effect.as(false)), |
| 110 | ), | 111 | ), |
| 111 | ); | 112 | ); |