/** * Identity admin routes — contact points, postal addresses, and named contacts * (CRUD + the entity-scoped list/create legs under `/entities/{entityType}/ * {entityId}/...`). * * Migrated to `@hono/zod-openapi` for the OpenAPI admin backfill (voyant#2114 — * identity sub-batch) via a NON-BREAKING dual-mount: the same `OpenAPIHono` * instance is exported as `identityRoutes` and mounted by the framework on BOTH * the legacy `/v1/identity/*` surface (the dashboard still calls those paths) * AND the documented staff surface at `/v1/admin/identity/*` (see `index.ts`). * Request schemas reuse the exported `validation.ts` insert/update/list-query * schemas the handlers already parsed; response row schemas live in * `routes/openapi-schemas.ts` (authored from the Drizzle `$inferSelect` shapes; * §17 timestamps → strings). Business logic, primary-flag enforcement, and the * wire envelopes (`{ data, total, limit, offset }` lists, `{ data }` singles, * `{ success: true }` deletes) are unchanged; handlers read `c.req.valid(...)`. * * Each resource family is its own small `OpenAPIHono` sub-chain composed onto * the parent via `.route("/")` so the `.openapi()` operations propagate up while * keeping type-inference cost bounded (one flat chain has O(n²) inference cost). */ import { OpenAPIHono } from "@hono/zod-openapi"; import type { IdentityRouteEnv } from "./routes/env.js"; export declare const identityRoutes: OpenAPIHono | null | undefined; }; }; output: { error: string; }; outputFormat: "json"; status: 400; } | { input: { param: { entityType: string; entityId: string; }; } & { json: { value: string; kind: "email" | "phone" | "mobile" | "whatsapp" | "website" | "sms" | "fax" | "social" | "other"; label?: string | null | undefined; normalizedValue?: string | null | undefined; isPrimary?: boolean | undefined; notes?: string | null | undefined; metadata?: Record | null | undefined; }; }; output: { data: { id: string; entityType: string; entityId: string; kind: "email" | "phone" | "mobile" | "whatsapp" | "website" | "sms" | "fax" | "social" | "other"; label: string | null; value: string; normalizedValue: string | null; isPrimary: boolean; notes: string | null; metadata: { [x: string]: import("hono/utils/types").JSONValue; } | null; createdAt: string; updatedAt: string; }; }; outputFormat: "json"; status: 201; }; }; } & { "/entities/:entityType/:entityId/addresses": { $get: { input: { param: { entityType: string; entityId: string; }; }; output: { data: { id: string; entityType: string; entityId: string; label: "other" | "primary" | "billing" | "shipping" | "mailing" | "meeting" | "service" | "legal"; fullText: string | null; line1: string | null; line2: string | null; city: string | null; region: string | null; postalCode: string | null; country: string | null; latitude: number | null; longitude: number | null; timezone: string | null; isPrimary: boolean; notes: string | null; metadata: { [x: string]: import("hono/utils/types").JSONValue; } | null; createdAt: string; updatedAt: string; }[]; }; outputFormat: "json"; status: 200; }; }; } & { "/entities/:entityType/:entityId/addresses": { $post: { input: { param: { entityType: string; entityId: string; }; } & { json: { label?: "other" | "primary" | "billing" | "shipping" | "mailing" | "meeting" | "service" | "legal" | undefined; isPrimary?: boolean | undefined; notes?: string | null | undefined; metadata?: Record | null | undefined; fullText?: string | null | undefined; line1?: string | null | undefined; line2?: string | null | undefined; city?: string | null | undefined; region?: string | null | undefined; postalCode?: string | null | undefined; country?: string | null | undefined; latitude?: number | null | undefined; longitude?: number | null | undefined; timezone?: string | null | undefined; }; }; output: { error: string; }; outputFormat: "json"; status: 400; } | { input: { param: { entityType: string; entityId: string; }; } & { json: { label?: "other" | "primary" | "billing" | "shipping" | "mailing" | "meeting" | "service" | "legal" | undefined; isPrimary?: boolean | undefined; notes?: string | null | undefined; metadata?: Record | null | undefined; fullText?: string | null | undefined; line1?: string | null | undefined; line2?: string | null | undefined; city?: string | null | undefined; region?: string | null | undefined; postalCode?: string | null | undefined; country?: string | null | undefined; latitude?: number | null | undefined; longitude?: number | null | undefined; timezone?: string | null | undefined; }; }; output: { data: { id: string; entityType: string; entityId: string; label: "other" | "primary" | "billing" | "shipping" | "mailing" | "meeting" | "service" | "legal"; fullText: string | null; line1: string | null; line2: string | null; city: string | null; region: string | null; postalCode: string | null; country: string | null; latitude: number | null; longitude: number | null; timezone: string | null; isPrimary: boolean; notes: string | null; metadata: { [x: string]: import("hono/utils/types").JSONValue; } | null; createdAt: string; updatedAt: string; }; }; outputFormat: "json"; status: 201; }; }; } & { "/entities/:entityType/:entityId/named-contacts": { $get: { input: { param: { entityType: string; entityId: string; }; }; output: { data: { id: string; entityType: string; entityId: string; role: "other" | "primary" | "legal" | "general" | "reservations" | "operations" | "front_desk" | "sales" | "emergency" | "accounting"; name: string; title: string | null; email: string | null; phone: string | null; isPrimary: boolean; notes: string | null; metadata: { [x: string]: import("hono/utils/types").JSONValue; } | null; createdAt: string; updatedAt: string; }[]; }; outputFormat: "json"; status: 200; }; }; } & { "/entities/:entityType/:entityId/named-contacts": { $post: { input: { param: { entityType: string; entityId: string; }; } & { json: { name: string; email?: string | null | undefined; phone?: string | null | undefined; isPrimary?: boolean | undefined; notes?: string | null | undefined; metadata?: Record | null | undefined; role?: "other" | "primary" | "legal" | "general" | "reservations" | "operations" | "front_desk" | "sales" | "emergency" | "accounting" | undefined; title?: string | null | undefined; }; }; output: { error: string; }; outputFormat: "json"; status: 400; } | { input: { param: { entityType: string; entityId: string; }; } & { json: { name: string; email?: string | null | undefined; phone?: string | null | undefined; isPrimary?: boolean | undefined; notes?: string | null | undefined; metadata?: Record | null | undefined; role?: "other" | "primary" | "legal" | "general" | "reservations" | "operations" | "front_desk" | "sales" | "emergency" | "accounting" | undefined; title?: string | null | undefined; }; }; output: { data: { id: string; entityType: string; entityId: string; role: "other" | "primary" | "legal" | "general" | "reservations" | "operations" | "front_desk" | "sales" | "emergency" | "accounting"; name: string; title: string | null; email: string | null; phone: string | null; isPrimary: boolean; notes: string | null; metadata: { [x: string]: import("hono/utils/types").JSONValue; } | null; createdAt: string; updatedAt: string; }; }; outputFormat: "json"; status: 201; }; }; }, "/"> & import("hono/types").MergeSchemaPath<{ "/named-contacts": { $get: { input: { query: { limit?: unknown; offset?: unknown; entityType?: string | undefined; entityId?: string | undefined; role?: "other" | "primary" | "legal" | "general" | "reservations" | "operations" | "front_desk" | "sales" | "emergency" | "accounting" | undefined; isPrimary?: "0" | "1" | "true" | "false" | undefined; search?: string | undefined; }; }; output: { data: { id: string; entityType: string; entityId: string; role: "other" | "primary" | "legal" | "general" | "reservations" | "operations" | "front_desk" | "sales" | "emergency" | "accounting"; name: string; title: string | null; email: string | null; phone: string | null; isPrimary: boolean; notes: string | null; metadata: { [x: string]: import("hono/utils/types").JSONValue; } | null; createdAt: string; updatedAt: string; }[]; total: number; limit: number; offset: number; }; outputFormat: "json"; status: 200; }; }; } & { "/named-contacts": { $post: { input: { json: { entityType: string; entityId: string; name: string; role?: "other" | "primary" | "legal" | "general" | "reservations" | "operations" | "front_desk" | "sales" | "emergency" | "accounting" | undefined; title?: string | null | undefined; email?: string | null | undefined; phone?: string | null | undefined; isPrimary?: boolean | undefined; notes?: string | null | undefined; metadata?: Record | null | undefined; }; }; output: { error: string; }; outputFormat: "json"; status: 400; } | { input: { json: { entityType: string; entityId: string; name: string; role?: "other" | "primary" | "legal" | "general" | "reservations" | "operations" | "front_desk" | "sales" | "emergency" | "accounting" | undefined; title?: string | null | undefined; email?: string | null | undefined; phone?: string | null | undefined; isPrimary?: boolean | undefined; notes?: string | null | undefined; metadata?: Record | null | undefined; }; }; output: { data: { id: string; entityType: string; entityId: string; role: "other" | "primary" | "legal" | "general" | "reservations" | "operations" | "front_desk" | "sales" | "emergency" | "accounting"; name: string; title: string | null; email: string | null; phone: string | null; isPrimary: boolean; notes: string | null; metadata: { [x: string]: import("hono/utils/types").JSONValue; } | null; createdAt: string; updatedAt: string; }; }; outputFormat: "json"; status: 201; }; }; } & { "/named-contacts/:id": { $get: { input: { param: { id: string; }; }; output: { error: string; }; outputFormat: "json"; status: 404; } | { input: { param: { id: string; }; }; output: { data: { id: string; entityType: string; entityId: string; role: "other" | "primary" | "legal" | "general" | "reservations" | "operations" | "front_desk" | "sales" | "emergency" | "accounting"; name: string; title: string | null; email: string | null; phone: string | null; isPrimary: boolean; notes: string | null; metadata: { [x: string]: import("hono/utils/types").JSONValue; } | null; createdAt: string; updatedAt: string; }; }; outputFormat: "json"; status: 200; }; }; } & { "/named-contacts/:id": { $patch: { input: { param: { id: string; }; } & { json: { entityType?: string | undefined; entityId?: string | undefined; role?: "other" | "primary" | "legal" | "general" | "reservations" | "operations" | "front_desk" | "sales" | "emergency" | "accounting" | undefined; name?: string | undefined; title?: string | null | undefined; email?: string | null | undefined; phone?: string | null | undefined; isPrimary?: boolean | undefined; notes?: string | null | undefined; metadata?: Record | null | undefined; }; }; output: { error: string; }; outputFormat: "json"; status: 400; } | { input: { param: { id: string; }; } & { json: { entityType?: string | undefined; entityId?: string | undefined; role?: "other" | "primary" | "legal" | "general" | "reservations" | "operations" | "front_desk" | "sales" | "emergency" | "accounting" | undefined; name?: string | undefined; title?: string | null | undefined; email?: string | null | undefined; phone?: string | null | undefined; isPrimary?: boolean | undefined; notes?: string | null | undefined; metadata?: Record | null | undefined; }; }; output: { error: string; }; outputFormat: "json"; status: 404; } | { input: { param: { id: string; }; } & { json: { entityType?: string | undefined; entityId?: string | undefined; role?: "other" | "primary" | "legal" | "general" | "reservations" | "operations" | "front_desk" | "sales" | "emergency" | "accounting" | undefined; name?: string | undefined; title?: string | null | undefined; email?: string | null | undefined; phone?: string | null | undefined; isPrimary?: boolean | undefined; notes?: string | null | undefined; metadata?: Record | null | undefined; }; }; output: { data: { id: string; entityType: string; entityId: string; role: "other" | "primary" | "legal" | "general" | "reservations" | "operations" | "front_desk" | "sales" | "emergency" | "accounting"; name: string; title: string | null; email: string | null; phone: string | null; isPrimary: boolean; notes: string | null; metadata: { [x: string]: import("hono/utils/types").JSONValue; } | null; createdAt: string; updatedAt: string; }; }; outputFormat: "json"; status: 200; }; }; } & { "/named-contacts/:id": { $delete: { input: { param: { id: string; }; }; output: { error: string; }; outputFormat: "json"; status: 404; } | { input: { param: { id: string; }; }; output: { success: true; }; outputFormat: "json"; status: 200; }; }; }, "/"> & import("hono/types").MergeSchemaPath<{ "/addresses": { $get: { input: { query: { limit?: unknown; offset?: unknown; entityType?: string | undefined; entityId?: string | undefined; label?: "other" | "primary" | "billing" | "shipping" | "mailing" | "meeting" | "service" | "legal" | undefined; isPrimary?: "0" | "1" | "true" | "false" | undefined; search?: string | undefined; }; }; output: { data: { id: string; entityType: string; entityId: string; label: "other" | "primary" | "billing" | "shipping" | "mailing" | "meeting" | "service" | "legal"; fullText: string | null; line1: string | null; line2: string | null; city: string | null; region: string | null; postalCode: string | null; country: string | null; latitude: number | null; longitude: number | null; timezone: string | null; isPrimary: boolean; notes: string | null; metadata: { [x: string]: import("hono/utils/types").JSONValue; } | null; createdAt: string; updatedAt: string; }[]; total: number; limit: number; offset: number; }; outputFormat: "json"; status: 200; }; }; } & { "/addresses": { $post: { input: { json: { entityType: string; entityId: string; label?: "other" | "primary" | "billing" | "shipping" | "mailing" | "meeting" | "service" | "legal" | undefined; fullText?: string | null | undefined; line1?: string | null | undefined; line2?: string | null | undefined; city?: string | null | undefined; region?: string | null | undefined; postalCode?: string | null | undefined; country?: string | null | undefined; latitude?: number | null | undefined; longitude?: number | null | undefined; timezone?: string | null | undefined; isPrimary?: boolean | undefined; notes?: string | null | undefined; metadata?: Record | null | undefined; }; }; output: { error: string; }; outputFormat: "json"; status: 400; } | { input: { json: { entityType: string; entityId: string; label?: "other" | "primary" | "billing" | "shipping" | "mailing" | "meeting" | "service" | "legal" | undefined; fullText?: string | null | undefined; line1?: string | null | undefined; line2?: string | null | undefined; city?: string | null | undefined; region?: string | null | undefined; postalCode?: string | null | undefined; country?: string | null | undefined; latitude?: number | null | undefined; longitude?: number | null | undefined; timezone?: string | null | undefined; isPrimary?: boolean | undefined; notes?: string | null | undefined; metadata?: Record | null | undefined; }; }; output: { data: { id: string; entityType: string; entityId: string; label: "other" | "primary" | "billing" | "shipping" | "mailing" | "meeting" | "service" | "legal"; fullText: string | null; line1: string | null; line2: string | null; city: string | null; region: string | null; postalCode: string | null; country: string | null; latitude: number | null; longitude: number | null; timezone: string | null; isPrimary: boolean; notes: string | null; metadata: { [x: string]: import("hono/utils/types").JSONValue; } | null; createdAt: string; updatedAt: string; }; }; outputFormat: "json"; status: 201; }; }; } & { "/addresses/:id": { $get: { input: { param: { id: string; }; }; output: { error: string; }; outputFormat: "json"; status: 404; } | { input: { param: { id: string; }; }; output: { data: { id: string; entityType: string; entityId: string; label: "other" | "primary" | "billing" | "shipping" | "mailing" | "meeting" | "service" | "legal"; fullText: string | null; line1: string | null; line2: string | null; city: string | null; region: string | null; postalCode: string | null; country: string | null; latitude: number | null; longitude: number | null; timezone: string | null; isPrimary: boolean; notes: string | null; metadata: { [x: string]: import("hono/utils/types").JSONValue; } | null; createdAt: string; updatedAt: string; }; }; outputFormat: "json"; status: 200; }; }; } & { "/addresses/:id": { $patch: { input: { param: { id: string; }; } & { json: { entityType?: string | undefined; entityId?: string | undefined; label?: "other" | "primary" | "billing" | "shipping" | "mailing" | "meeting" | "service" | "legal" | undefined; fullText?: string | null | undefined; line1?: string | null | undefined; line2?: string | null | undefined; city?: string | null | undefined; region?: string | null | undefined; postalCode?: string | null | undefined; country?: string | null | undefined; latitude?: number | null | undefined; longitude?: number | null | undefined; timezone?: string | null | undefined; isPrimary?: boolean | undefined; notes?: string | null | undefined; metadata?: Record | null | undefined; }; }; output: { error: string; }; outputFormat: "json"; status: 400; } | { input: { param: { id: string; }; } & { json: { entityType?: string | undefined; entityId?: string | undefined; label?: "other" | "primary" | "billing" | "shipping" | "mailing" | "meeting" | "service" | "legal" | undefined; fullText?: string | null | undefined; line1?: string | null | undefined; line2?: string | null | undefined; city?: string | null | undefined; region?: string | null | undefined; postalCode?: string | null | undefined; country?: string | null | undefined; latitude?: number | null | undefined; longitude?: number | null | undefined; timezone?: string | null | undefined; isPrimary?: boolean | undefined; notes?: string | null | undefined; metadata?: Record | null | undefined; }; }; output: { error: string; }; outputFormat: "json"; status: 404; } | { input: { param: { id: string; }; } & { json: { entityType?: string | undefined; entityId?: string | undefined; label?: "other" | "primary" | "billing" | "shipping" | "mailing" | "meeting" | "service" | "legal" | undefined; fullText?: string | null | undefined; line1?: string | null | undefined; line2?: string | null | undefined; city?: string | null | undefined; region?: string | null | undefined; postalCode?: string | null | undefined; country?: string | null | undefined; latitude?: number | null | undefined; longitude?: number | null | undefined; timezone?: string | null | undefined; isPrimary?: boolean | undefined; notes?: string | null | undefined; metadata?: Record | null | undefined; }; }; output: { data: { id: string; entityType: string; entityId: string; label: "other" | "primary" | "billing" | "shipping" | "mailing" | "meeting" | "service" | "legal"; fullText: string | null; line1: string | null; line2: string | null; city: string | null; region: string | null; postalCode: string | null; country: string | null; latitude: number | null; longitude: number | null; timezone: string | null; isPrimary: boolean; notes: string | null; metadata: { [x: string]: import("hono/utils/types").JSONValue; } | null; createdAt: string; updatedAt: string; }; }; outputFormat: "json"; status: 200; }; }; } & { "/addresses/:id": { $delete: { input: { param: { id: string; }; }; output: { error: string; }; outputFormat: "json"; status: 404; } | { input: { param: { id: string; }; }; output: { success: true; }; outputFormat: "json"; status: 200; }; }; }, "/"> & import("hono/types").MergeSchemaPath<{ "/contact-points": { $get: { input: { query: { limit?: unknown; offset?: unknown; entityType?: string | undefined; entityId?: string | undefined; kind?: "email" | "phone" | "mobile" | "whatsapp" | "website" | "sms" | "fax" | "social" | "other" | undefined; isPrimary?: "0" | "1" | "true" | "false" | undefined; search?: string | undefined; }; }; output: { data: { id: string; entityType: string; entityId: string; kind: "email" | "phone" | "mobile" | "whatsapp" | "website" | "sms" | "fax" | "social" | "other"; label: string | null; value: string; normalizedValue: string | null; isPrimary: boolean; notes: string | null; metadata: { [x: string]: import("hono/utils/types").JSONValue; } | null; createdAt: string; updatedAt: string; }[]; total: number; limit: number; offset: number; }; outputFormat: "json"; status: 200; }; }; } & { "/contact-points": { $post: { input: { json: { entityType: string; entityId: string; kind: "email" | "phone" | "mobile" | "whatsapp" | "website" | "sms" | "fax" | "social" | "other"; value: string; label?: string | null | undefined; normalizedValue?: string | null | undefined; isPrimary?: boolean | undefined; notes?: string | null | undefined; metadata?: Record | null | undefined; }; }; output: { data: { id: string; entityType: string; entityId: string; kind: "email" | "phone" | "mobile" | "whatsapp" | "website" | "sms" | "fax" | "social" | "other"; label: string | null; value: string; normalizedValue: string | null; isPrimary: boolean; notes: string | null; metadata: { [x: string]: import("hono/utils/types").JSONValue; } | null; createdAt: string; updatedAt: string; }; }; outputFormat: "json"; status: 201; } | { input: { json: { entityType: string; entityId: string; kind: "email" | "phone" | "mobile" | "whatsapp" | "website" | "sms" | "fax" | "social" | "other"; value: string; label?: string | null | undefined; normalizedValue?: string | null | undefined; isPrimary?: boolean | undefined; notes?: string | null | undefined; metadata?: Record | null | undefined; }; }; output: { error: string; }; outputFormat: "json"; status: 400; }; }; } & { "/contact-points/:id": { $get: { input: { param: { id: string; }; }; output: { data: { id: string; entityType: string; entityId: string; kind: "email" | "phone" | "mobile" | "whatsapp" | "website" | "sms" | "fax" | "social" | "other"; label: string | null; value: string; normalizedValue: string | null; isPrimary: boolean; notes: string | null; metadata: { [x: string]: import("hono/utils/types").JSONValue; } | null; createdAt: string; updatedAt: string; }; }; outputFormat: "json"; status: 200; } | { input: { param: { id: string; }; }; output: { error: string; }; outputFormat: "json"; status: 404; }; }; } & { "/contact-points/:id": { $patch: { input: { param: { id: string; }; } & { json: { entityType?: string | undefined; entityId?: string | undefined; kind?: "email" | "phone" | "mobile" | "whatsapp" | "website" | "sms" | "fax" | "social" | "other" | undefined; label?: string | null | undefined; value?: string | undefined; normalizedValue?: string | null | undefined; isPrimary?: boolean | undefined; notes?: string | null | undefined; metadata?: Record | null | undefined; }; }; output: { error: string; }; outputFormat: "json"; status: 400; } | { input: { param: { id: string; }; } & { json: { entityType?: string | undefined; entityId?: string | undefined; kind?: "email" | "phone" | "mobile" | "whatsapp" | "website" | "sms" | "fax" | "social" | "other" | undefined; label?: string | null | undefined; value?: string | undefined; normalizedValue?: string | null | undefined; isPrimary?: boolean | undefined; notes?: string | null | undefined; metadata?: Record | null | undefined; }; }; output: { error: string; }; outputFormat: "json"; status: 404; } | { input: { param: { id: string; }; } & { json: { entityType?: string | undefined; entityId?: string | undefined; kind?: "email" | "phone" | "mobile" | "whatsapp" | "website" | "sms" | "fax" | "social" | "other" | undefined; label?: string | null | undefined; value?: string | undefined; normalizedValue?: string | null | undefined; isPrimary?: boolean | undefined; notes?: string | null | undefined; metadata?: Record | null | undefined; }; }; output: { data: { id: string; entityType: string; entityId: string; kind: "email" | "phone" | "mobile" | "whatsapp" | "website" | "sms" | "fax" | "social" | "other"; label: string | null; value: string; normalizedValue: string | null; isPrimary: boolean; notes: string | null; metadata: { [x: string]: import("hono/utils/types").JSONValue; } | null; createdAt: string; updatedAt: string; }; }; outputFormat: "json"; status: 200; }; }; } & { "/contact-points/:id": { $delete: { input: { param: { id: string; }; }; output: { error: string; }; outputFormat: "json"; status: 404; } | { input: { param: { id: string; }; }; output: { success: true; }; outputFormat: "json"; status: 200; }; }; }, "/">, "/">; export type IdentityRoutes = typeof identityRoutes;