116 lines · 4.3 KB · TypeScript
RawDownload
/** * ProviderAdapterRegistryLive — facade over `ProviderInstanceRegistry`. * * `ProviderAdapterRegistry` historically mapped one `ProviderDriverKind` to one * adapter via the four `<X>AdapterLive` singleton Layers. The per-instance * refactor moved adapter construction inside each `ProviderDriver.create()`: * adapters are now bundled on the `ProviderInstance` that the * `ProviderInstanceRegistry` owns. * * This facade fulfills the `ProviderAdapterRegistryShape` contract by doing * dynamic look-ups against `ProviderInstanceRegistry` on every call. That * means settings-driven hot-reload shows up here automatically — adding a * new instance via settings makes `getByInstance` resolve immediately * without rebuilding the facade. * * @module ProviderAdapterRegistryLive */import {  defaultInstanceIdForDriver,  ProviderInstanceId,  type ProviderDriverKind,} from "@t3tools/contracts";import { Effect, Layer } from "effect"; import { ProviderUnsupportedError } from "../Errors.ts";import { ProviderInstanceRegistry } from "../Services/ProviderInstanceRegistry.ts";import {  ProviderAdapterRegistry,  type ProviderAdapterRegistryShape,} from "../Services/ProviderAdapterRegistry.ts"; const makeProviderAdapterRegistry = Effect.fn("makeProviderAdapterRegistry")(function* () {  const registry = yield* ProviderInstanceRegistry;   const getByInstance: ProviderAdapterRegistryShape["getByInstance"] = (instanceId) =>    registry.getInstance(instanceId).pipe(      Effect.flatMap((instance) =>        instance === undefined          ? Effect.fail(              new ProviderUnsupportedError({                provider: instanceId,              }),            )          : Effect.succeed(instance.adapter),      ),    );   const getInstanceInfo: ProviderAdapterRegistryShape["getInstanceInfo"] = (instanceId) =>    registry.getInstance(instanceId).pipe(      Effect.flatMap((instance) =>        instance === undefined          ? Effect.fail(              new ProviderUnsupportedError({                provider: instanceId,              }),            )          : Effect.succeed({              instanceId: instance.instanceId,              driverKind: instance.driverKind,              displayName: instance.displayName,              accentColor: instance.accentColor,              enabled: instance.enabled,              continuationIdentity: instance.continuationIdentity,            }),      ),    );   const listInstances: ProviderAdapterRegistryShape["listInstances"] = () =>    registry.listInstances.pipe(      Effect.map((instances) => instances.map((instance) => instance.instanceId)),    );   const listProviders: ProviderAdapterRegistryShape["listProviders"] = () =>    registry.listInstances.pipe(      Effect.map((instances) => {        const kinds = new Set<ProviderDriverKind>();        for (const instance of instances) {          const defaultId = defaultInstanceIdForDriver(instance.driverKind);          if (instance.instanceId === defaultId) {            // Only the default-instance rows show up through the legacy            // shim — custom instances like `codex_personal` have no            // `ProviderDriverKind` equivalent.            kinds.add(instance.driverKind);          }        }        return Array.from(kinds);      }),    );   return {    getByInstance,    getInstanceInfo,    listInstances,    listProviders,    // Proxy directly — the facade has no state of its own; the instance    // registry already coalesces adds/removes/rebuilds into one emission.    streamChanges: registry.streamChanges,    subscribeChanges: registry.subscribeChanges,  } satisfies ProviderAdapterRegistryShape;}); export const ProviderAdapterRegistryLive = Layer.effect(  ProviderAdapterRegistry,  makeProviderAdapterRegistry(),); // Exposed for tests that want to build a facade over a pre-assembled// `ProviderInstanceRegistry` without pulling in the whole boot graph.export { makeProviderAdapterRegistry }; // Re-export for consumers that need the accessor shape. The service tag// itself lives in `Services/ProviderAdapterRegistry.ts`.export { ProviderAdapterRegistry } from "../Services/ProviderAdapterRegistry.ts";// Re-export for consumers (including tests) that construct a// `ProviderInstanceId` before calling `getByInstance`.export { ProviderInstanceId };