# Config schemas _(no submodules)_ ## Purpose Provides Zod boundary schemas for `IMessageWatcherConfig` and `IMessageAdapterConfig`, plus the `parseWatcherConfig` / `parseAdapterConfig` helpers that callers use to validate untrusted input before constructing a watcher or adapter. Both schemas are strict — extra keys are rejected — so consumers cannot silently smuggle additional fields past the boundary. ## Features - Strict object validation (`.strict()`) — unknown properties are rejected at the boundary, preventing prototype-pollution-style smuggling. - `pollIntervalMs` constrained to positive integers; `sinceDate` required to be a `Date` instance (no millisecond-since-epoch numbers); `chatFilter` constrained to string arrays. - Custom `SqliteReaderSchema` confirms the optional injected `sqliteReader` exposes a callable `open()` member. - Failures throw `IMessageInvalidConfigError` (`IMESSAGE.INVALID_CONFIG`) carrying a serialisable `issues` array in `context` so problem+json responders can surface the Zod path + reason without re-running the schema. ## Usage: Basic ```ts import { parseWatcherConfig } from "@suaveplan/imessage-adapter/schemas"; const config = parseWatcherConfig({ pollIntervalMs: 5000 }); ``` ## Usage: Advanced ```ts import { parseWatcherConfig, IMessageInvalidConfigError, } from "@suaveplan/imessage-adapter"; try { parseWatcherConfig({ pollIntervalMs: -1, oops: true }); } catch (err) { if (err instanceof IMessageInvalidConfigError) { return Response.json( { issues: err.context["issues"] }, { status: 400 }, ); } throw err; } ``` ## API Reference - `IMessageWatcherConfigSchema: z.ZodObject` — validates watcher config. - `IMessageAdapterConfigSchema` — alias for the watcher schema. - `SqliteReaderSchema: z.ZodType` — structural check for `SqliteReader`. - `parseWatcherConfig(input: unknown): IMessageWatcherConfig` — throws `IMessageInvalidConfigError` on failure. - `parseAdapterConfig(input: unknown): IMessageAdapterConfig` — throws `IMessageInvalidConfigError` on failure. ## Implementation Notes The schemas use `z.custom` for the `SqliteReader` slot because the reader is a structural type — there is no Zod-expressible shape that captures every legal implementation. The check confirms the presence of a function-typed `open` member, which is enough to surface mistakes (passing a stray object or `null`) without inspecting the reader's behaviour. Issue arrays are projected through `toIssues` which strips Zod's internal symbols so the resulting record is safe to JSON-serialise.