# `registry.schemas` ## Purpose Strict-object Zod schemas for every plugin kind accepted by `ReactI18nRegistry`. The schemas are the boundary at which a malformed plugin shape is rejected at registration time — before any callsite has a chance to consume the bad plugin and throw a less-actionable runtime error elsewhere. Each schema is `.strict()`-locked so extra fields on a plugin (typos, stale fields from an older registry version) trigger validation failure rather than silently passing through. ## Features - One schema per plugin kind — `DetectorPluginSchema`, `FormatterPluginSchema`, `PostProcessorPluginSchema`, `LocaleAdapterPluginSchema`. - Non-empty id enforced (`z.string().min(1)`) so every plugin has a stable lookup key. - Function-shape fields validated structurally; their semantic correctness is exercised by the tests of each consumer (e.g. `useFormatter` test calls the registered plugin's `format` and asserts the output). - Schemas surface failure as a Zod `ZodError`, which the registry wraps in a `ReactI18nError(REACT_I18N.PLUGIN_INVALID)` with the issues attached to `cause`. ## Usage: Basic Example ```ts import { FormatterPluginSchema } from "@suaveplan/react-i18n/registry"; const result = FormatterPluginSchema.safeParse({ id: "duration", format: (locale, args) => String(args.ms), }); result.success; // true ``` ## Usage: Advanced Example The schemas accept generic `format` / `process` / `resolve` / `detect` functions because their signatures cannot be expressed as a closed Zod shape. The schema verifies the function is *present* and is a function; the actual `(locale, args) => result` contract is enforced at the type-system level via `FormatterPlugin` and at the test level by exercising the plugin's behavior. ```ts import { DetectorPluginSchema } from "@suaveplan/react-i18n/registry"; const malformed = { id: "ab", priority: 0, detect: { name: "ab" /* missing environment */ }, }; const result = DetectorPluginSchema.safeParse(malformed); result.success; // false result.error.issues; // [{ path: ["detect", "environment"], message: "Required" }] ``` ## API Reference ### `DetectorPluginSchema` Validates `{ id: string; priority: number; detect: { name; environment; detect?; detectAsync?; cache? } }`. The inner `detect` object is `passthrough` because `LocaleDetector` from `@suaveplan/i18n-detector` may carry forward-compatible fields the registry does not own. ### `FormatterPluginSchema` Validates `{ id: string; schema?: unknown; defaultOptions?: unknown; format: function }`. The `schema` field is opaque (`z.unknown()`) because it is a Zod schema reference and Zod cannot meaningfully validate "is this a Zod schema." ### `PostProcessorPluginSchema` Validates `{ id: string; priority: number; process: function }`. ### `LocaleAdapterPluginSchema` Validates `{ id: string; resolve: function }`. ## Implementation Notes - All schemas are `.strict()` — extra keys cause validation failure. This catches stale fields from older registry versions and typos in plugin objects. - The schemas are exported from a single file rather than co-located with their plugin types so a consumer importing `@suaveplan/react-i18n/registry` for runtime validation does not pay the bundle cost of the plugin function code. - Validation errors are passed through to the registry which decorates them with stable error codes; consumers should never `safeParse` directly against these schemas — register through `ReactI18nRegistry.register*` to get the decorated error. - The schemas live in this package rather than in `@suaveplan/types` because they validate React-specific plugin shapes; the `ReactI18nRegistry` is itself React-bound (consumed via context).