1import * as Crypto from "effect/Crypto";
2import * as Effect from "effect/Effect";
3import * as Hex from "effect/encoding/Hex";
4import * as ServerSecretStore from "../auth/ServerSecretStore.ts";
5
6/** A provider binding stores opaque bytes; only its adapter decodes or refreshes them. */
7export const make = Effect.fn("ProviderCredentialStore.make")(function* (
8 driver: string,
9 bindingId: string,
10) {
11 const secrets = yield* ServerSecretStore.ServerSecretStore;
12 const crypto = yield* Crypto.Crypto;
13 // Hash the tuple so arbitrary bindings cannot escape or exceed a filename.
14 const bindingHash = yield* crypto
15 .digest("SHA-256", new TextEncoder().encode(`${driver.length}:${driver}${bindingId}`))
16 .pipe(Effect.map(Hex.encode), Effect.orDie);
17 const key = `provider-auth-${bindingHash}`;
18 return {
19 binding: { owner: "t3" as const, key },
20 get: secrets.get(key),
21 set: (credentials: Uint8Array) => secrets.set(key, credentials),
22 remove: secrets.remove(key),
23 };
24});