first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
# Config schemas
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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<unknown>` — 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.