Initial Commit
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
# `options` — Zod-validated resolver options
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Defines and validates the public option bundle accepted by
|
||||
`createSubdomainTenantResolver`. Every option is bounded by a Zod
|
||||
schema at construction time so an operator that misspells a key,
|
||||
supplies an invalid CIDR, or passes a negative `tenantLabelIndex`
|
||||
discovers the mistake immediately rather than at the first inbound
|
||||
request. The resolved bundle replaces every `??` ladder so the
|
||||
resolver body stays small and the hot-path is allocation-free.
|
||||
|
||||
The shape mirrors `@suaveplan/api-tenant-resolver-header` /
|
||||
`-jwt` (id + strict + validator + registry) plus the subdomain-specific
|
||||
fields (`baseDomain`, `tenantLabelIndex`, `trustForwardedHost`,
|
||||
`trustedProxyCidrs`) and a `getTransport` extractor so the host can
|
||||
inject framework-specific request metadata.
|
||||
|
||||
## Features
|
||||
|
||||
- Strict Zod schema — extra keys fail validation.
|
||||
- CIDR pre-parsing at construction time so the per-request hot-path is
|
||||
byte-array prefix comparison only.
|
||||
- Stable `INVALID_OPTIONS` code on every failure (Zod, CIDR parse,
|
||||
missing option object).
|
||||
- `LabelValidator` and `TenantRegistryLookup` opt-in extension points.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { parseSubdomainTenantResolverOptions } from "@suaveplan/api-tenant-resolver-subdomain/options";
|
||||
|
||||
const resolved = parseSubdomainTenantResolverOptions({
|
||||
baseDomain: "api.example.com",
|
||||
});
|
||||
// → { id: "subdomain", baseDomain: "api.example.com",
|
||||
// tenantLabelIndex: 0, strict: false, ... }
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import type { TenantId } from "@suaveplan/api-types/tenant";
|
||||
import { parseSubdomainTenantResolverOptions } from "@suaveplan/api-tenant-resolver-subdomain/options";
|
||||
|
||||
const registry = new Map<string, TenantId>([
|
||||
["acme", "t_acme" as TenantId],
|
||||
]);
|
||||
|
||||
const resolved = parseSubdomainTenantResolverOptions({
|
||||
id: "primary",
|
||||
baseDomain: "api.example.com",
|
||||
tenantLabelIndex: 0,
|
||||
strict: true,
|
||||
trustForwardedHost: true,
|
||||
trustedProxyCidrs: ["10.0.0.0/8", "2001:db8::/32"],
|
||||
registry: (slug) => registry.get(slug) ?? null,
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `SubdomainTenantResolverOptions` — public input bundle.
|
||||
- `ResolvedSubdomainTenantResolverOptions` — internal, every default
|
||||
applied, CIDRs pre-parsed.
|
||||
- `parseSubdomainTenantResolverOptions(input): Resolved...`.
|
||||
- `TenantRegistryLookup` — slug → `TenantId | null` (sync or async).
|
||||
- `RequestTransport` — `{ host, forwardedHost, remoteAddress }`.
|
||||
- `TransportExtractor` — `(request: Request) => RequestTransport`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The schema is `.strict()` so a typo (`requirePrincipal` instead of
|
||||
`requireTenant`) is a hard error at construction. `validate` and
|
||||
`registry` are stripped before the Zod parse — `z.function()` is
|
||||
deprecated and unnecessary here because runtime function calls already
|
||||
fail loudly if the wrong shape is passed. `trustedProxyCidrs` is
|
||||
re-parsed through `parseCidr` so every CIDR is normalised to a
|
||||
`ParsedCidr` once; this is the only allocation per resolver
|
||||
construction (per-request matching uses the cached array).
|
||||
Reference in New Issue
Block a user