/** * TanStack Query (React Query) projection. * * Generates typed hooks for each entity and command in the IR: * - useEntityQuery (list) — wraps GET /api/{entity}/list * - useEntityQuery (detail) — wraps GET /api/{entity}/{id} * - useCommandMutation — wraps POST /api/manifest/{entity}/commands/{command} * * All hooks include: * - Typed query keys for deterministic cache identity * - Automatic cache invalidation on mutations * - Optimistic update helpers for entity mutations * - Error boundary integration via throwOnError option * * Surfaces: * - react-query.hooks — hooks + query key factories * - react-query.provider — QueryClient + QueryClientProvider setup */ import type { IR } from '../../ir'; import type { ProjectionTarget, ProjectionRequest, ProjectionResult } from '../interface'; import { type RouteCasing } from '../shared/naming.js'; /** Per-entity route base overrides (preserves original casing / domain routes). */ export interface EntityRouteOverride { /** Replaces `${apiBasePath}/${lowercased}` for list + detail reads. */ readBase?: string; /** Replaces `${dispatcherBasePath}/${lowercased}/commands` for command writes. */ writeBase?: string; } /** Per-entity read-envelope key overrides (replaces hardcoded pluralization). */ export interface ReadEnvelopeOverride { /** Key holding the array in a list response (default: `${camelEntity}s`). */ listKey?: string; /** Key holding the object in a detail response (default: `${camelEntity}`). */ detailKey?: string; /** Optional secondary key to fall back to (emits `data.x ?? data.fallback`). */ fallbackKey?: string; } /** Import a host-provided fetch adapter instead of the inline `apiFetch`. */ export interface FetchAdapterOption { /** Module to import the adapter from, e.g. '@/lib/api'. */ importPath: string; /** Exported name of the adapter (default: 'apiFetch'). Aliased to apiFetch. */ importName?: string; } export interface ReactQueryProjectionOptions { /** * URL prefix for list/detail read paths. Default: derived from `appDir` via the * shared route contract (the Next.js routing roots `src`/`app` are stripped, so * `app/api` → `/api`). Deriving it from the same `appDir` as the nextjs routes * keeps the hooks and the emitted routes on one prefix. Set explicitly only to * target a different origin prefix. */ apiBasePath?: string; /** * Dispatcher URL prefix for command mutations. Default: `${apiBasePath}/manifest` * (from the contract) — matches where the `nextjs.dispatcher` route is served. */ dispatcherBasePath?: string; /** * App Router base directory the read/dispatcher URL bases are derived from * (mirrors the nextjs projection's `appDir`). Default `'app/api'` ⇒ `/api`. * Change it and both the read paths and the dispatcher paths follow, so the * hooks cannot desync from routes generated with the same `appDir`. */ appDir?: string; /** Whether to generate optimistic update helpers (default: true) */ optimisticUpdates?: boolean; /** Whether to generate error boundary integration (default: true) */ errorBoundaryIntegration?: boolean; /** Import path for entity types (default: '@/types/manifest-generated') */ typesImportPath?: string; /** Default staleTime in ms (default: 30_000) */ defaultStaleTime?: number; /** * Per-entity route base overrides keyed by entity name. Lets a consumer route * reads/writes to domain paths with original casing (e.g. Event → * `/api/events/event`) instead of the default flattened lowercase path. */ entityRoutes?: Record; /** * Per-entity read-envelope key overrides keyed by entity name. Replaces the * default `+s` pluralization (which breaks on irregulars like Dish→dishes) and * supports a fallback key (e.g. `data.events ?? data.data`). */ readEnvelope?: Record; /** * When set, the generated hooks import an existing fetch adapter (for auth / * credentials) instead of emitting the inline `apiFetch`. */ fetchAdapter?: FetchAdapterOption; /** * EXPLICIT DEVIATION KNOB. By default command mutations type their response as * `ManifestCommandResponse` — the real wire body the Next.js dispatcher * returns (`{ data, events, diagnostics }`; on non-2xx `apiFetch` throws with * the `error` field). Set this to `true` only for a server that instead returns * the legacy sync envelope `{ success, result, events }`; it emits and uses a * `CommandEnvelope` type in place of the default. Default: false. */ commandEnvelope?: boolean; /** * How `date`/`datetime` scalars are typed. `'date'` (default) emits `Date`; * `'iso-string'` emits `string`, matching JSON/HTTP transport where dates * serialize to ISO-8601 strings. Non-breaking — defaults to `'date'`. */ dateSerialization?: 'date' | 'iso-string'; /** * Explicit per-entity URL path segment overrides (mirrors the nextjs * projection's `routeSegments`). Takes precedence over `routeCasing`. e.g. * `{ OrderLine: 'order-lines' }` → `/api/order-lines/list`. */ routeSegments?: Record; /** * Casing for the default entity URL segment in fetch paths (when no * `entityRoutes` override is given). Must match the nextjs projection's * `routeCasing` so hooks call the routes that exist. `'lowercase'` (default, * legacy) flattens `PrepTask` → `preptask`; `'kebab-case'` → `prep-task`, etc. */ routeCasing?: RouteCasing; } export declare class ReactQueryProjection implements ProjectionTarget { readonly name = "react-query"; readonly description = "TanStack Query (React Query) hooks with typed queries, mutations, and cache invalidation"; readonly surfaces: readonly ["react-query.hooks", "react-query.provider"]; readonly descriptorMeta: import("..").ProjectionDescriptorMeta; generate(ir: IR, request: ProjectionRequest): ProjectionResult; } //# sourceMappingURL=generator.d.ts.map