Initial Commit
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
import type { CurrencyProvider } from "@suaveplan/currency";
|
||||
import {
|
||||
CURRENCY_PROVIDER_CODES,
|
||||
CurrencyProviderError,
|
||||
} from "../error-codes/error-codes.js";
|
||||
|
||||
/**
|
||||
* In-memory registry of `CurrencyProvider` instances keyed by `provider.name`.
|
||||
*
|
||||
* Sibling `@suaveplan/currency-provider-<name>` packages register their
|
||||
* provider with this registry; consumers (e.g. `CurrencyConverter` wiring,
|
||||
* future `AggregatorProvider` / `RateLimitedProvider` wrappers) resolve
|
||||
* providers by name without having to track concrete classes themselves.
|
||||
*
|
||||
* The registry stores providers by reference — no cloning, freezing, or
|
||||
* defensive copy. Providers are expected to be immutable shells around their
|
||||
* config.
|
||||
*/
|
||||
export class CurrencyProviderRegistry {
|
||||
private readonly entries: Map<string, CurrencyProvider> = new Map();
|
||||
|
||||
/**
|
||||
* Register a provider under its own `provider.name`. Throws
|
||||
* `CurrencyProviderError(PROVIDER_ALREADY_REGISTERED)` when the name is
|
||||
* already in use. Explicit replacement requires `unregister(name)` first.
|
||||
*/
|
||||
public register(provider: CurrencyProvider): void {
|
||||
const name = provider.name;
|
||||
if (this.entries.has(name)) {
|
||||
throw new CurrencyProviderError(
|
||||
CURRENCY_PROVIDER_CODES.PROVIDER_ALREADY_REGISTERED,
|
||||
`Provider "${name}" is already registered`,
|
||||
{ providerName: name }
|
||||
);
|
||||
}
|
||||
this.entries.set(name, provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up a registered provider by name. Throws
|
||||
* `CurrencyProviderError(PROVIDER_NOT_REGISTERED)` when no provider has
|
||||
* been registered under `name`.
|
||||
*/
|
||||
public get(name: string): CurrencyProvider {
|
||||
const provider = this.entries.get(name);
|
||||
if (provider === undefined) {
|
||||
throw new CurrencyProviderError(
|
||||
CURRENCY_PROVIDER_CODES.PROVIDER_NOT_REGISTERED,
|
||||
`No provider registered under name "${name}"`,
|
||||
{ providerName: name }
|
||||
);
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
|
||||
/** Non-throwing probe — `true` when {@link get} would succeed. */
|
||||
public has(name: string): boolean {
|
||||
return this.entries.has(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorted snapshot of currently registered provider names. Equal sets of
|
||||
* providers list identically regardless of insertion order, which keeps
|
||||
* downstream golden-file tests deterministic.
|
||||
*/
|
||||
public list(): readonly string[] {
|
||||
return [...this.entries.keys()].sort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a registration. Returns `true` when something was removed,
|
||||
* `false` when no provider was registered under `name`. Never throws.
|
||||
*/
|
||||
public unregister(name: string): boolean {
|
||||
return this.entries.delete(name);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user