4.5 KiB
schemas — Zod boundary for @suaveplan/currency
(no submodules)
Purpose
The schemas module is the package's input-validation boundary. Every public
options bundle that crosses into a CurrencyConverter method or a reference
provider is parsed against a Zod schema first; failures raise a typed
CurrencyError with code CURRENCY.INVALID_CONFIG (constructor arguments,
virtual-currency entries) or CURRENCY.INVALID_OPTIONS (per-call options,
RateFetchOptions). The Zod issue array is attached to
error.context.issues so downstream loggers and APIs can surface field-level
diagnostics without re-running validation.
Centralising validation here keeps the converter and provider implementations
focused on behaviour: by the time control enters convert or fetchRates,
every option is already the shape the implementation expects, and the
implementation can rely on TypeScript's structural typing without runtime
double-checks.
Features
ConverterConfigSchema— validates the constructor argument (provider shape, optional fallback array, positive integer TTL, currency-code default base, virtual-currency record).ConvertOptionsSchema— validates per-call options (roundingenum, optionalfresh: boolean, optionalAbortSignal).VirtualCurrencyConfigSchema—rate > 0, non-emptyname/symbol, optionalexponent ∈ [0, 18]/issuerId.RateFetchOptionsSchema— optionalbase,targetsarray of currency codes, optionalAbortSignal.parseConverterConfig/parseConvertOptions/parseVirtualCurrencyConfig/parseRateFetchOptions— safe-parse helpers that raise the appropriateCurrencyErroron failure.
Usage: Basic Example
import { parseConvertOptions } from "@suaveplan/currency";
const options = parseConvertOptions({ rounding: "half-up", fresh: false });
// options is typed as ConvertOptions; bad shapes raise CURRENCY.INVALID_OPTIONS.
Usage: Advanced Example
A consumer wraps API input through the schemas before delegating to the converter, surfacing Zod issues as user-facing field errors:
import {
CurrencyError,
CURRENCY_CODES,
parseConverterConfig,
CurrencyConverter,
} from "@suaveplan/currency";
export function makeConverter(raw: unknown) {
try {
const config = parseConverterConfig(raw);
return new CurrencyConverter(config);
} catch (err) {
if (
err instanceof CurrencyError &&
err.code === CURRENCY_CODES.INVALID_CONFIG
) {
const issues = (err.context?.issues as { path: (string | number)[]; message: string }[] | undefined) ?? [];
throw new Error(
`Bad converter config: ${issues
.map((i) => `${i.path.join(".")}: ${i.message}`)
.join(", ")}`
);
}
throw err;
}
}
API Reference
| Export | Kind | Description |
|---|---|---|
ConverterConfigSchema |
Zod schema | Validates ConverterConfig. |
ConvertOptionsSchema |
Zod schema | Validates ConvertOptions. |
VirtualCurrencyConfigSchema |
Zod schema | Validates a single VirtualCurrencyConfig. |
RateFetchOptionsSchema |
Zod schema | Validates RateFetchOptions. |
parseConverterConfig(input) |
(unknown) => ConverterConfig |
Raises CurrencyError({ code: CURRENCY.INVALID_CONFIG }) on failure. |
parseConvertOptions(input) |
(unknown) => ConvertOptions |
Raises CurrencyError({ code: CURRENCY.INVALID_OPTIONS }) on failure. |
parseVirtualCurrencyConfig(input) |
(unknown) => VirtualCurrencyConfig |
Raises CurrencyError({ code: CURRENCY.INVALID_CONFIG }) on failure. |
parseRateFetchOptions(input) |
(unknown) => RateFetchOptions |
Raises CurrencyError({ code: CURRENCY.INVALID_OPTIONS }) on failure. |
Implementation Notes
The signal field uses a z.custom<AbortSignal> because AbortSignal is a
host object — Zod cannot introspect it. The custom predicate accepts any
object exposing an aborted property, which matches both the platform
AbortSignal and consumer-side polyfills. provider is validated
structurally (name, supportsCrypto, supportsFiat, optional
supportsVirtual, function-typed fetchRates); we deliberately do not
descend into the function body. Currency codes are validated as non-empty
strings — the converter checks against the @suaveplan/money registry at
use time, so unknown codes raise CURRENCY.UNSUPPORTED_CURRENCY (via
getCurrencyOrThrow) rather than failing schema validation.