@zodapi/client 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alan Christensen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,106 @@
1
+ # @zodapi/client
2
+
3
+ Typed HTTP client over [zodapi](https://github.com/christensena/zodapi) route contracts:
4
+ path- or alias-addressed calls, optional zod validation at runtime, and zodios-style error guards.
5
+ Works over fetch by default, axios via `@zodapi/client/axios`, or any custom adapter.
6
+
7
+ ```ts
8
+ import { ValidationApiError, createClient, matchErrorByStatus } from '@zodapi/client'
9
+ import { z } from 'zod'
10
+ import { createUser, routes } from './contract.js'
11
+
12
+ const client = createClient(routes, { baseUrl: 'http://localhost:3000' })
13
+
14
+ const user = await client.get('/users/{id}', { params: { id: '1' } }) // by path
15
+ const same = await client.getUser({ params: { id: '1' } }) // by alias
16
+
17
+ try {
18
+ await client.createUser({ body: newUser })
19
+ } catch (err) {
20
+ if (err instanceof ValidationApiError) {
21
+ z.flattenError(err.error).fieldErrors // a real ZodError, revived from the server's issues
22
+ } else if (matchErrorByStatus(createUser, err, 409)) {
23
+ err.data.error.existingId // fully typed, runtime-checked with zod
24
+ }
25
+ }
26
+ ```
27
+
28
+ Argument objects (`params`, `query`, `body`, `headers`, `signal`) are typed from the route's
29
+ request schemas; return types are the union of the route's declared 2xx json bodies.
30
+
31
+ ## Options
32
+
33
+ ```ts
34
+ createClient(routes, {
35
+ baseUrl: 'http://localhost:3000',
36
+ validate: 'response', // 'none' | 'request' | 'response' | 'both' (default 'response')
37
+ encodeRequests: false, // pass decoded (z.output) request values, encoded to the wire via z.encode
38
+ fullResponse: false, // resolve with { data, status, headers } instead of the bare body
39
+ headers: () => ({ authorization: `Bearer ${token}` }), // static object or (async) function
40
+ adapter: fetchAdapter(), // transport seam
41
+ decoders: decodersFor(problemFlavor), // error decoders (default: zodapi's own 400)
42
+ onError: ({ error, attempt }) => {}, // error hook; return 'retry' to re-run the request
43
+ })
44
+ ```
45
+
46
+ - **Validation default is `'response'`** (zodios behaviour): 2xx bodies are parsed with the
47
+ contract schema; error-response bodies stay raw and are checked by the error guards instead.
48
+ Override per call with `{ validate: ... }`.
49
+ - **Errors throw.** Non-2xx responses run through the error decoders first: server-side validation
50
+ failures throw `ValidationApiError` (its `error` is a real `z.ZodError` revived from the server's
51
+ issues, so client- and server-side failures share one handling path), other recognised
52
+ problem+json responses throw `ProblemApiError`. Otherwise declared statuses throw `ApiError`
53
+ (narrow with `isErrorFromRoute`, `isErrorFromAlias`, `matchErrorByStatus`, `isValidationError` —
54
+ all re-exported from `@zodapi/core`); undeclared statuses throw `UnexpectedResponseApiError`;
55
+ client-side validation failures throw `RequestValidationError` / `ResponseValidationError`.
56
+ - **Non-zodapi backends** that speak RFC 9457 (ASP.NET, Spring, ...) opt in with
57
+ `decoders: [...decodersFor('problem-details', { keyCasing: 'camel' })]` — an ASP.NET
58
+ `ValidationProblemDetails` `errors` map is converted to zod issues (keys camelCased and split
59
+ into paths; `$.items[0].qty` becomes `['items', 0, 'qty']`). Contracts generated by
60
+ `@zodapi/codegen` export a detected `problemFlavor` to feed `decodersFor`. Pass `decoders: []`
61
+ to disable decoding entirely.
62
+ - **Query arrays** are serialised with the `[]` key suffix (`tags[]=a&tags[]=b`), matching the
63
+ normalisation `createApp()` from `@zodapi/hono` applies at the edge.
64
+ - **Codecs** (e.g. the date codecs `@zodapi/codegen` emits with its `dates` options) only decode
65
+ when response validation runs, so the client fails fast — before sending — when a 2xx response
66
+ schema with a codec would be skipped (`validate` must be `'response'` or `'both'`). Validated
67
+ codec-bearing request data is re-encoded to its wire form (a date-only codec stays `YYYY-MM-DD`
68
+ instead of being `JSON.stringify`'d as a full datetime). With `encodeRequests: true`
69
+ (client-level or per call, flipping the request arg types from `z.input` to `z.output`) you pass
70
+ decoded values — `Date` objects — and the client `z.encode`s them; encoding is a serialization
71
+ concern independent of `validate`, though `z.encode` validates as it encodes, so an invalid
72
+ value throws `RequestValidationError` even with request validation off. `z.encode` rejects
73
+ one-way transforms, so a schema mixing a codec with `queryArray()` cannot be encoded.
74
+ - **Raw response access** goes through `fullResponse` (client-level default, or per call in either
75
+ direction): the call resolves with `{ data, status, headers }` — `data` validated/decoded exactly
76
+ as without the envelope, `headers` the raw `Headers` — for pagination headers, tests, and the
77
+ like. Non-2xx responses already carry `status`/`headers`/`data` on the thrown `ApiError`.
78
+ - **Retries** go through `onError` (client-level, or per call to replace it): the hook receives
79
+ `{ error, route, alias, attempt }` before an error is thrown and may return `'retry'` (sync or
80
+ async) to re-run the request. The `headers` function is re-evaluated on every attempt, so an
81
+ expired-token flow is just: on a 401, refresh the token, return `'retry'`. Transport errors,
82
+ `ApiError` and subclasses, and `ResponseValidationError` reach the hook; client-side request
83
+ validation/encoding failures don't (the same input would fail again). There's no built-in
84
+ attempt cap — bound retries with `attempt`.
85
+
86
+ ## Axios
87
+
88
+ ```ts
89
+ import axios from 'axios'
90
+ import { axiosAdapter } from '@zodapi/client/axios'
91
+
92
+ const client = createClient(routes, { baseUrl, adapter: axiosAdapter(axios.create()) })
93
+ ```
94
+
95
+ Status handling stays with the zodapi client (`validateStatus` is disabled), so declared error
96
+ responses throw `ApiError` exactly as with the fetch adapter. axios is an optional peer dependency.
97
+ A custom transport is just an `Adapter`: `(request: AdapterRequest) => Promise<AdapterResponse>`.
98
+
99
+ ## Install
100
+
101
+ ```sh
102
+ pnpm add @zodapi/client zod
103
+ ```
104
+
105
+ Contracts come from `@zodapi/hono` route definitions shared out of a TypeScript backend, or from
106
+ `@zodapi/codegen` for backends that only publish an OpenAPI 3.1 document.
@@ -0,0 +1,17 @@
1
+ import type { Method } from '@zodapi/core';
2
+ export interface AdapterRequest {
3
+ method: Method;
4
+ url: string;
5
+ headers: Record<string, string>;
6
+ body?: string | undefined;
7
+ signal?: AbortSignal | undefined;
8
+ }
9
+ export interface AdapterResponse {
10
+ status: number;
11
+ headers: Headers;
12
+ text: string;
13
+ }
14
+ /** Transport seam: fetch and axios adapters are provided; bring your own if needed. */
15
+ export type Adapter = (request: AdapterRequest) => Promise<AdapterResponse>;
16
+ export declare function fetchAdapter(fetchImpl?: typeof fetch): Adapter;
17
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAE1C,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;CACb;AAED,uFAAuF;AACvF,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,eAAe,CAAC,CAAA;AAE3E,wBAAgB,YAAY,CAAC,SAAS,GAAE,OAAO,KAAa,GAAG,OAAO,CAUrE"}
@@ -0,0 +1,12 @@
1
+ export function fetchAdapter(fetchImpl = fetch) {
2
+ return async (request) => {
3
+ const response = await fetchImpl(request.url, {
4
+ method: request.method.toUpperCase(),
5
+ headers: request.headers,
6
+ ...(request.body !== undefined ? { body: request.body } : {}),
7
+ ...(request.signal ? { signal: request.signal } : {}),
8
+ });
9
+ return { status: response.status, headers: response.headers, text: await response.text() };
10
+ };
11
+ }
12
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAmBA,MAAM,UAAU,YAAY,CAAC,SAAS,GAAiB,KAAK;IAC1D,OAAO,KAAK,EAAE,OAAO,EAAE,EAAE;QACvB,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE;YAC5C,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE;YACpC,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7D,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACtD,CAAC,CAAA;QACF,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAA;IAC5F,CAAC,CAAA;AACH,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { AxiosInstance } from 'axios';
2
+ import type { Adapter } from './adapter.js';
3
+ /**
4
+ * Adapter over an axios instance. Status handling stays with the zodapi client
5
+ * (`validateStatus` is disabled), so declared error responses throw `ApiError`
6
+ * exactly as with the fetch adapter.
7
+ */
8
+ export declare function axiosAdapter(instance: AxiosInstance): Adapter;
9
+ //# sourceMappingURL=axios.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"axios.d.ts","sourceRoot":"","sources":["../src/axios.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAE1C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAE3C;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAsB7D"}
package/dist/axios.js ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Adapter over an axios instance. Status handling stays with the zodapi client
3
+ * (`validateStatus` is disabled), so declared error responses throw `ApiError`
4
+ * exactly as with the fetch adapter.
5
+ */
6
+ export function axiosAdapter(instance) {
7
+ return async (request) => {
8
+ const response = await instance.request({
9
+ url: request.url,
10
+ method: request.method,
11
+ headers: request.headers,
12
+ ...(request.body !== undefined ? { data: request.body } : {}),
13
+ ...(request.signal ? { signal: request.signal } : {}),
14
+ responseType: 'text',
15
+ transformResponse: (data) => data,
16
+ validateStatus: () => true,
17
+ });
18
+ const headers = new Headers();
19
+ for (const [key, value] of Object.entries(response.headers ?? {})) {
20
+ if (Array.isArray(value)) {
21
+ for (const item of value)
22
+ headers.append(key, String(item));
23
+ }
24
+ else if (value !== undefined && value !== null) {
25
+ headers.set(key, String(value));
26
+ }
27
+ }
28
+ return { status: response.status, headers, text: response.data ?? '' };
29
+ };
30
+ }
31
+ //# sourceMappingURL=axios.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"axios.js","sourceRoot":"","sources":["../src/axios.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,QAAuB;IAClD,OAAO,KAAK,EAAE,OAAO,EAAE,EAAE;QACvB,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAS;YAC9C,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7D,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACrD,YAAY,EAAE,MAAM;YACpB,iBAAiB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI;YACjC,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI;SAC3B,CAAC,CAAA;QACF,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;QAC7B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;YAClE,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBACzB,KAAK,MAAM,IAAI,IAAI,KAAK;oBAAE,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;YAC7D,CAAC;iBAAM,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACjD,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;YACjC,CAAC;QACH,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,IAAI,EAAE,EAAE,CAAA;IACxE,CAAC,CAAA;AACH,CAAC"}
@@ -0,0 +1,74 @@
1
+ import { type ErrorDecoder, type RouteDef } from '@zodapi/core';
2
+ import { type Adapter } from './adapter.js';
3
+ import type { OnError, ValidateMode, ZodapiClient } from './types.js';
4
+ export interface ClientOptions {
5
+ baseUrl: string;
6
+ adapter?: Adapter;
7
+ /**
8
+ * What to validate with zod at runtime. Defaults to 'response' (zodios
9
+ * behaviour): 2xx bodies are parsed with the contract schema; error-response
10
+ * bodies stay raw and are checked by the error guards instead.
11
+ */
12
+ validate?: ValidateMode;
13
+ /** Headers sent with every request; a function is re-evaluated per call. */
14
+ headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
15
+ /**
16
+ * Error decoders tried in order against every non-2xx response; the first
17
+ * decoded error is thrown instead of a plain `ApiError`. Defaults to
18
+ * zodapi's own problem+json 400 decoder; add `problemDetails(...)` (or use
19
+ * `decodersFor(...)`) for non-zodapi backends. Pass `[]` to disable.
20
+ */
21
+ decoders?: readonly ErrorDecoder[];
22
+ /**
23
+ * Supply request data in decoded (schema output) form — e.g. `Date` objects
24
+ * where the contract uses date codecs — and let the client encode it to the
25
+ * wire form with `z.encode`. Request args are then typed with `z.output`
26
+ * instead of `z.input`. Encoding is a serialization concern, independent of
27
+ * `validate`: codec-bearing request data is always encoded (and `z.encode`
28
+ * validates as it encodes, so an invalid value throws
29
+ * `RequestValidationError` even with `validate: 'none'`). Overridable per
30
+ * call. Note: `z.encode` rejects one-way transforms, so a schema mixing a
31
+ * codec with e.g. `queryArray()` cannot be encoded.
32
+ */
33
+ encodeRequests?: boolean;
34
+ /**
35
+ * Resolve calls with a `FullResponse` envelope — `{ data, status, headers }`
36
+ * — instead of the bare parsed body, for consumers that need the raw
37
+ * response's status or headers (pagination headers, tests, ...). `data` is
38
+ * still validated/decoded exactly as without the envelope. Defaults to
39
+ * false. Overridable per call in either direction.
40
+ */
41
+ fullResponse?: boolean;
42
+ /**
43
+ * Error hook with a retry decision, called whenever a call is about to
44
+ * throw. Return `'retry'` (may be async) to re-run the request; any other
45
+ * return value — or a throw from the hook itself — lets the original error
46
+ * propagate.
47
+ *
48
+ * The hook receives the error, the route (and alias), and the 1-based
49
+ * `attempt` count. It covers transport/network errors, `ApiError` and its
50
+ * subclasses, and `ResponseValidationError`; client-side request
51
+ * validation/encoding failures are thrown before the hook and never
52
+ * retried. A `headers` function is re-evaluated on every attempt, which
53
+ * makes token refresh a one-liner:
54
+ *
55
+ * ```ts
56
+ * onError: async ({ error, attempt }) => {
57
+ * if (error instanceof ApiError && error.status === 401 && attempt === 1) {
58
+ * await refreshTokens() // headers() picks up the new token on the retry
59
+ * return 'retry'
60
+ * }
61
+ * }
62
+ * ```
63
+ *
64
+ * There is no built-in attempt cap — bound retries with `attempt`. A
65
+ * per-call `onError` replaces this one for that call.
66
+ */
67
+ onError?: OnError;
68
+ }
69
+ export declare function createClient<const Rs extends readonly RouteDef[], const O extends ClientOptions>(routes: Rs, options: O): ZodapiClient<Rs, O extends {
70
+ encodeRequests: true;
71
+ } ? 'output' : 'input', O extends {
72
+ fullResponse: true;
73
+ } ? true : false>;
74
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EAQjB,KAAK,QAAQ,EAGd,MAAM,cAAc,CAAA;AAGrB,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,cAAc,CAAA;AACzD,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAErE,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAA;IACvB,4EAA4E;IAC5E,OAAO,CAAC,EACJ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtB,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;IACpE;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;IAClC;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAiED,wBAAgB,YAAY,CAAC,KAAK,CAAC,EAAE,SAAS,SAAS,QAAQ,EAAE,EAAE,KAAK,CAAC,CAAC,SAAS,aAAa,EAC9F,MAAM,EAAE,EAAE,EACV,OAAO,EAAE,CAAC,GACT,YAAY,CACb,EAAE,EACF,CAAC,SAAS;IAAE,cAAc,EAAE,IAAI,CAAA;CAAE,GAAG,QAAQ,GAAG,OAAO,EACvD,CAAC,SAAS;IAAE,YAAY,EAAE,IAAI,CAAA;CAAE,GAAG,IAAI,GAAG,KAAK,CAChD,CAuJA"}
package/dist/client.js ADDED
@@ -0,0 +1,202 @@
1
+ import { ApiError, RequestValidationError, ResponseValidationError, UnexpectedResponseApiError, decodeError, jsonSchemaOfResponse, mediaTypeOf, responseDefForStatus, schemaContainsCodec, zodapiValidationDecoder, } from '@zodapi/core';
2
+ import { z } from 'zod';
3
+ import { fetchAdapter } from './adapter.js';
4
+ function serializeQueryValue(value) {
5
+ if (value instanceof Date)
6
+ return value.toISOString();
7
+ if (typeof value === 'object' && value !== null)
8
+ return JSON.stringify(value);
9
+ return String(value);
10
+ }
11
+ function buildUrl(baseUrl, route, args) {
12
+ let path = route.path;
13
+ for (const [key, value] of Object.entries(args.params ?? {})) {
14
+ path = path.replaceAll(`{${key}}`, encodeURIComponent(String(value)));
15
+ }
16
+ const missing = path.match(/\{([^}]+)\}/);
17
+ if (missing) {
18
+ throw new Error(`Missing path parameter '${missing[1]}' for ${route.method} ${route.path}`);
19
+ }
20
+ const search = new URLSearchParams();
21
+ for (const [key, value] of Object.entries(args.query ?? {})) {
22
+ if (value === undefined || value === null)
23
+ continue;
24
+ if (Array.isArray(value)) {
25
+ for (const item of value)
26
+ search.append(`${key}[]`, serializeQueryValue(item));
27
+ }
28
+ else {
29
+ search.append(key, serializeQueryValue(value));
30
+ }
31
+ }
32
+ const query = search.toString();
33
+ return `${baseUrl.replace(/\/+$/, '')}${path}${query ? `?${query}` : ''}`;
34
+ }
35
+ function jsonBodySchema(route) {
36
+ const body = route.request?.body;
37
+ return body ? jsonSchemaOfResponse(body) : undefined;
38
+ }
39
+ /**
40
+ * With response validation off, a codec-bearing 2xx schema would return wire
41
+ * data (e.g. ISO strings) while the types promise decoded values (`Date`) —
42
+ * fail fast before the request is sent instead.
43
+ */
44
+ function assertNoCodecInSuccessResponses(route) {
45
+ for (const [status, def] of Object.entries(route.responses)) {
46
+ if (!String(status).startsWith('2'))
47
+ continue;
48
+ const schema = jsonSchemaOfResponse(def);
49
+ if (schema && schemaContainsCodec(schema)) {
50
+ throw new Error(`Response schema (${status}) for ${route.method.toUpperCase()} ${route.path} contains a codec; ` +
51
+ `enable response validation (validate: 'response' or 'both') so decoded values match the contract types`);
52
+ }
53
+ }
54
+ }
55
+ export function createClient(routes, options) {
56
+ const adapter = options.adapter ?? fetchAdapter();
57
+ const defaultValidate = options.validate ?? 'response';
58
+ const defaultEncodeRequests = options.encodeRequests ?? false;
59
+ const defaultFullResponse = options.fullResponse ?? false;
60
+ const decoders = options.decoders ?? [zodapiValidationDecoder];
61
+ const call = async (route, args = {}) => {
62
+ const validate = args.validate ?? defaultValidate;
63
+ const encodeRequests = args.encodeRequests ?? defaultEncodeRequests;
64
+ const fullResponse = args.fullResponse ?? defaultFullResponse;
65
+ const onError = args.onError ?? options.onError;
66
+ const validateRequest = validate === 'request' || validate === 'both';
67
+ const validateResponse = validate === 'response' || validate === 'both';
68
+ if (!validateResponse)
69
+ assertNoCodecInSuccessResponses(route);
70
+ const parseInput = (target, schema, value) => {
71
+ if (!schema)
72
+ return value;
73
+ // The wire form of a codec is its input side, so codec-bearing values
74
+ // need z.encode regardless of the validate mode — JSON.stringify would
75
+ // serialize e.g. a date-only codec's Date as a full datetime.
76
+ if (encodeRequests && schemaContainsCodec(schema)) {
77
+ const encoded = z.safeEncode(schema, value);
78
+ if (!encoded.success)
79
+ throw new RequestValidationError(target, encoded.error);
80
+ return encoded.data;
81
+ }
82
+ if (!validateRequest)
83
+ return value;
84
+ if (schemaContainsCodec(schema)) {
85
+ // Parsing decodes; re-encode so the wire keeps the codec input form.
86
+ const parsed = schema.safeParse(value);
87
+ if (!parsed.success)
88
+ throw new RequestValidationError(target, parsed.error);
89
+ const encoded = z.safeEncode(schema, parsed.data);
90
+ if (!encoded.success)
91
+ throw new RequestValidationError(target, encoded.error);
92
+ return encoded.data;
93
+ }
94
+ const result = schema.safeParse(value);
95
+ if (!result.success)
96
+ throw new RequestValidationError(target, result.error);
97
+ return result.data;
98
+ };
99
+ // Serialization happens once, outside the retry loop: the same input
100
+ // cannot fail differently on a retry, so these errors never reach onError.
101
+ const request = route.request ?? {};
102
+ const params = parseInput('param', request.params, args.params);
103
+ const query = parseInput('query', request.query, args.query);
104
+ const headerSchema = Array.isArray(request.headers) ? undefined : request.headers;
105
+ parseInput('header', headerSchema, args.headers);
106
+ const bodySchema = jsonBodySchema(route);
107
+ const body = bodySchema !== undefined ? parseInput('json', bodySchema, args.body) : args.body;
108
+ const hasBody = body !== undefined;
109
+ const attemptOnce = async () => {
110
+ const headers = {};
111
+ const baseHeaders = typeof options.headers === 'function' ? await options.headers() : options.headers;
112
+ Object.assign(headers, baseHeaders);
113
+ for (const [key, value] of Object.entries(args.headers ?? {})) {
114
+ if (value !== undefined)
115
+ headers[key] = value;
116
+ }
117
+ if (hasBody && !Object.keys(headers).some((h) => h.toLowerCase() === 'content-type')) {
118
+ headers['content-type'] = 'application/json';
119
+ }
120
+ const response = await adapter({
121
+ method: route.method,
122
+ url: buildUrl(options.baseUrl, route, { ...args, params, query }),
123
+ headers,
124
+ body: hasBody ? JSON.stringify(body) : undefined,
125
+ signal: args.signal,
126
+ });
127
+ let data;
128
+ if (response.text !== '' && response.status !== 204 && response.status !== 205) {
129
+ if (/\bjson\b/i.test(response.headers.get('content-type') ?? '')) {
130
+ try {
131
+ data = JSON.parse(response.text);
132
+ }
133
+ catch {
134
+ data = response.text;
135
+ }
136
+ }
137
+ else {
138
+ data = response.text;
139
+ }
140
+ }
141
+ const match = responseDefForStatus(route, response.status);
142
+ if (response.status >= 200 && response.status < 300) {
143
+ if (!match) {
144
+ throw new UnexpectedResponseApiError(route, response.status, data, response.headers);
145
+ }
146
+ const resolve = (body) => fullResponse ? { data: body, status: response.status, headers: response.headers } : body;
147
+ const schema = jsonSchemaOfResponse(match.def);
148
+ if (schema && validateResponse) {
149
+ const result = schema.safeParse(data);
150
+ if (!result.success) {
151
+ throw new ResponseValidationError(response.status, result.error, data);
152
+ }
153
+ return resolve(result.data);
154
+ }
155
+ return resolve(data);
156
+ }
157
+ const decoded = decodeError(decoders, {
158
+ route,
159
+ status: response.status,
160
+ data,
161
+ headers: response.headers,
162
+ mediaType: mediaTypeOf(response.headers.get('content-type')),
163
+ });
164
+ if (decoded)
165
+ throw decoded;
166
+ if (match)
167
+ throw new ApiError(route, response.status, data, response.headers);
168
+ throw new UnexpectedResponseApiError(route, response.status, data, response.headers);
169
+ };
170
+ if (onError === undefined)
171
+ return attemptOnce();
172
+ for (let attempt = 1;; attempt++) {
173
+ try {
174
+ return await attemptOnce();
175
+ }
176
+ catch (error) {
177
+ const decision = await onError({ error, route, alias: route.alias, attempt });
178
+ if (decision !== 'retry')
179
+ throw error;
180
+ }
181
+ }
182
+ };
183
+ const client = {};
184
+ const byMethodPath = new Map();
185
+ for (const route of routes) {
186
+ byMethodPath.set(`${route.method} ${route.path}`, route);
187
+ if (route.alias !== undefined) {
188
+ client[route.alias] = (args) => call(route, args);
189
+ }
190
+ }
191
+ for (const method of new Set(routes.map((r) => r.method))) {
192
+ client[method] = (path, args) => {
193
+ const route = byMethodPath.get(`${method} ${path}`);
194
+ if (!route) {
195
+ throw new Error(`No route registered for ${method.toUpperCase()} ${path}`);
196
+ }
197
+ return call(route, args);
198
+ };
199
+ }
200
+ return client;
201
+ }
202
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { createClient, type ClientOptions } from './client.js';
2
+ export { fetchAdapter, type Adapter, type AdapterRequest, type AdapterResponse } from './adapter.js';
3
+ export type { AliasCallers, ArgsTuple, ErrorContext, FullResponse, MethodCallers, OnError, RequestArgs, RequestIO, ValidateMode, ZodapiClient, } from './types.js';
4
+ export { ApiError, type ApiErrorOf, type DecodableResponse, type ErrorDecoder, type KeyCasing, PROBLEM_JSON_CONTENT_TYPE, ProblemApiError, ProblemDetails, type ProblemDetailsOptions, type ProblemFlavor, RequestValidationError, ResponseValidationError, UnexpectedResponseApiError, ValidationApiError, ValidationError, ZODAPI_VALIDATION_TYPE, decodeError, decodersFor, isAxiosErrorFromRoute, isErrorFromAlias, isErrorFromRoute, isValidationError, isValidationErrorBody, matchErrorByStatus, mediaTypeOf, problemDetails, zodapiValidationDecoder, } from '@zodapi/core';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAA;AAC9D,OAAO,EAAE,YAAY,EAAE,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAA;AACpG,YAAY,EACV,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,OAAO,EACP,WAAW,EACX,SAAS,EACT,YAAY,EACZ,YAAY,GACb,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,QAAQ,EACR,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,yBAAyB,EACzB,eAAe,EACf,cAAc,EACd,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAClB,sBAAsB,EACtB,uBAAuB,EACvB,0BAA0B,EAC1B,kBAAkB,EAClB,eAAe,EACf,sBAAsB,EACtB,WAAW,EACX,WAAW,EACX,qBAAqB,EACrB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,WAAW,EACX,cAAc,EACd,uBAAuB,GACxB,MAAM,cAAc,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { createClient } from './client.js';
2
+ export { fetchAdapter } from './adapter.js';
3
+ export { ApiError, PROBLEM_JSON_CONTENT_TYPE, ProblemApiError, ProblemDetails, RequestValidationError, ResponseValidationError, UnexpectedResponseApiError, ValidationApiError, ValidationError, ZODAPI_VALIDATION_TYPE, decodeError, decodersFor, isAxiosErrorFromRoute, isErrorFromAlias, isErrorFromRoute, isValidationError, isValidationErrorBody, matchErrorByStatus, mediaTypeOf, problemDetails, zodapiValidationDecoder, } from '@zodapi/core';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAsB,MAAM,aAAa,CAAA;AAC9D,OAAO,EAAE,YAAY,EAA2D,MAAM,cAAc,CAAA;AAapG,OAAO,EACL,QAAQ,EAKR,yBAAyB,EACzB,eAAe,EACf,cAAc,EAGd,sBAAsB,EACtB,uBAAuB,EACvB,0BAA0B,EAC1B,kBAAkB,EAClB,eAAe,EACf,sBAAsB,EACtB,WAAW,EACX,WAAW,EACX,qBAAqB,EACrB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,WAAW,EACX,cAAc,EACd,uBAAuB,GACxB,MAAM,cAAc,CAAA"}
@@ -0,0 +1,155 @@
1
+ import type { JsonBodySchema, Method, RouteDef, SuccessData } from '@zodapi/core';
2
+ import type { z } from 'zod';
3
+ export type ValidateMode = 'none' | 'request' | 'response' | 'both';
4
+ /** What an {@link OnError} hook receives when a call is about to throw. */
5
+ export interface ErrorContext {
6
+ /**
7
+ * The error that will be thrown if the hook does not return `'retry'`: a
8
+ * transport/network error from the adapter, an `ApiError` (or subclass:
9
+ * `UnexpectedResponseApiError`, `ValidationApiError`, `ProblemApiError`), or
10
+ * a `ResponseValidationError`. Narrow with `instanceof` before deciding.
11
+ */
12
+ error: unknown;
13
+ /** The route definition of the failing call. */
14
+ route: RouteDef;
15
+ /** The route's alias, when it has one. */
16
+ alias: string | undefined;
17
+ /**
18
+ * How many attempts have failed so far, starting at 1. There is no built-in
19
+ * cap — use this to bound retries (e.g. `attempt === 1` for a single retry).
20
+ */
21
+ attempt: number;
22
+ }
23
+ /**
24
+ * Error hook with a retry decision.
25
+ *
26
+ * Called whenever a call is about to throw (may be async). Return `'retry'`
27
+ * to re-run the request; any other return value — or a throw from the hook
28
+ * itself — lets the original error propagate. The literal return type leaves
29
+ * room for future decisions without a breaking change.
30
+ *
31
+ * The client re-evaluates a `headers` function on every attempt, so the
32
+ * refresh-token flow is just:
33
+ *
34
+ * ```ts
35
+ * onError: async ({ error, attempt }) => {
36
+ * if (error instanceof ApiError && error.status === 401 && attempt === 1) {
37
+ * await refreshTokens() // headers() picks up the new token on the retry
38
+ * return 'retry'
39
+ * }
40
+ * }
41
+ * ```
42
+ *
43
+ * Client-side request validation/encoding failures
44
+ * (`RequestValidationError`) are thrown before the hook and never retried —
45
+ * the same input would fail the same way again.
46
+ */
47
+ export type OnError = (context: ErrorContext) => 'retry' | void | Promise<'retry' | void>;
48
+ /**
49
+ * Which side of the request schemas the caller supplies: 'input' (wire form,
50
+ * the default) or 'output' (decoded form, when `encodeRequests` is on — e.g.
51
+ * `Date` objects where a contract uses date codecs).
52
+ */
53
+ export type RequestIO = 'input' | 'output';
54
+ type Simplify<T> = {
55
+ [K in keyof T]: T[K];
56
+ } & {};
57
+ type OtherIO<M extends RequestIO> = M extends 'input' ? 'output' : 'input';
58
+ type SchemaVal<S extends z.ZodType, M extends RequestIO> = M extends 'output' ? z.output<S> : z.input<S>;
59
+ type ParamsArg<R extends RouteDef, M extends RequestIO> = R['request'] extends {
60
+ params: infer S extends z.ZodType;
61
+ } ? {
62
+ params: SchemaVal<S, M>;
63
+ } : {};
64
+ type QueryArg<R extends RouteDef, M extends RequestIO> = R['request'] extends {
65
+ query: infer S extends z.ZodType;
66
+ } ? {} extends SchemaVal<S, M> ? {
67
+ query?: SchemaVal<S, M>;
68
+ } : {
69
+ query: SchemaVal<S, M>;
70
+ } : {};
71
+ type BodyArg<R extends RouteDef, M extends RequestIO> = [JsonBodySchema<R>] extends [never] ? {} : {
72
+ body: SchemaVal<JsonBodySchema<R>, M>;
73
+ };
74
+ type HeadersArg<R extends RouteDef, M extends RequestIO> = R['request'] extends {
75
+ headers: infer S extends z.ZodType;
76
+ } ? {
77
+ headers: SchemaVal<S, M> & Record<string, string | undefined>;
78
+ } : {
79
+ headers?: Record<string, string | undefined>;
80
+ };
81
+ type BaseArgs<R extends RouteDef, M extends RequestIO> = ParamsArg<R, M> & QueryArg<R, M> & BodyArg<R, M> & HeadersArg<R, M> & {
82
+ signal?: AbortSignal;
83
+ /** Override the client-level validation mode for this call. */
84
+ validate?: ValidateMode;
85
+ /**
86
+ * Error hook for this call, replacing any client-level `onError`. Return
87
+ * `'retry'` to re-run the request — see {@link OnError}.
88
+ */
89
+ onError?: OnError;
90
+ /**
91
+ * Override the client-level `fullResponse` mode for this call: `true`
92
+ * resolves with a {@link FullResponse} envelope (`data` + `status` +
93
+ * `headers`) instead of the bare body; `false` opts back out.
94
+ */
95
+ fullResponse?: boolean;
96
+ };
97
+ type EncodeFlag<M extends RequestIO> = M extends 'output' ? true : false;
98
+ /**
99
+ * Args for one call. The default member matches the client's request IO mode;
100
+ * flipping `encodeRequests` per call flips the request value types with it.
101
+ */
102
+ export type RequestArgs<R extends RouteDef, M extends RequestIO = 'input'> = Simplify<BaseArgs<R, M> & {
103
+ encodeRequests?: EncodeFlag<M>;
104
+ }> | Simplify<BaseArgs<R, OtherIO<M>> & {
105
+ encodeRequests: EncodeFlag<OtherIO<M>>;
106
+ }>;
107
+ type RequiredKeys<T> = {
108
+ [K in keyof T]-?: {} extends Pick<T, K> ? never : K;
109
+ }[keyof T];
110
+ export type ArgsTuple<R extends RouteDef, M extends RequestIO = 'input'> = [
111
+ RequiredKeys<Simplify<BaseArgs<R, M>>>
112
+ ] extends [never] ? [args?: RequestArgs<R, M>] : [args: RequestArgs<R, M>];
113
+ type PathsFor<Rs extends readonly RouteDef[], M extends Method> = Extract<Rs[number], {
114
+ method: M;
115
+ }>['path'];
116
+ type RouteFor<Rs extends readonly RouteDef[], M extends Method, P extends string> = Extract<Rs[number], {
117
+ method: M;
118
+ path: P;
119
+ }>;
120
+ /**
121
+ * What a call resolves with in `fullResponse` mode: the parsed (and, with
122
+ * codecs, decoded) body plus the raw response's status and headers.
123
+ */
124
+ export interface FullResponse<R extends RouteDef> {
125
+ data: SuccessData<R>;
126
+ status: number;
127
+ headers: Headers;
128
+ }
129
+ type CallResult<R extends RouteDef, F extends boolean> = F extends true ? FullResponse<R> : SuccessData<R>;
130
+ type Not<F extends boolean> = F extends true ? false : true;
131
+ /**
132
+ * Two call signatures per route: the first flips the client-level
133
+ * `fullResponse` mode via an explicit literal flag, the second follows it.
134
+ */
135
+ export type MethodCallers<Rs extends readonly RouteDef[], IO extends RequestIO = 'input', F extends boolean = false> = {
136
+ [M in Rs[number]['method']]: {
137
+ <P extends PathsFor<Rs, M>>(path: P, args: RequestArgs<RouteFor<Rs, M, P>, IO> & {
138
+ fullResponse: Not<F>;
139
+ }): Promise<CallResult<RouteFor<Rs, M, P>, Not<F>>>;
140
+ <P extends PathsFor<Rs, M>>(path: P, ...args: ArgsTuple<RouteFor<Rs, M, P>, IO>): Promise<CallResult<RouteFor<Rs, M, P>, F>>;
141
+ };
142
+ };
143
+ export type AliasCallers<Rs extends readonly RouteDef[], IO extends RequestIO = 'input', F extends boolean = false> = {
144
+ [R in Rs[number] as R extends {
145
+ alias: infer A extends string;
146
+ } ? A : never]: {
147
+ (args: RequestArgs<R, IO> & {
148
+ fullResponse: Not<F>;
149
+ }): Promise<CallResult<R, Not<F>>>;
150
+ (...args: ArgsTuple<R, IO>): Promise<CallResult<R, F>>;
151
+ };
152
+ };
153
+ export type ZodapiClient<Rs extends readonly RouteDef[], IO extends RequestIO = 'input', F extends boolean = false> = MethodCallers<Rs, IO, F> & AliasCallers<Rs, IO, F>;
154
+ export {};
155
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@zodapi/client",
3
+ "version": "0.2.0",
4
+ "description": "Typed fetch/axios client over zodapi route contracts with optional zod validation",
5
+ "license": "MIT",
6
+ "files": [
7
+ "dist"
8
+ ],
9
+ "type": "module",
10
+ "sideEffects": false,
11
+ "main": "./dist/index.js",
12
+ "types": "./dist/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ },
18
+ "./axios": {
19
+ "types": "./dist/axios.d.ts",
20
+ "default": "./dist/axios.js"
21
+ }
22
+ },
23
+ "dependencies": {
24
+ "@zodapi/core": "0.2.0"
25
+ },
26
+ "devDependencies": {
27
+ "@hono/node-server": "^2.1.1",
28
+ "@hono/zod-openapi": "^1.6.1",
29
+ "@zodapi/hono": "0.2.0",
30
+ "axios": "^1.20.0",
31
+ "hono": "^4.13.5",
32
+ "zod": "^4.4.3"
33
+ },
34
+ "peerDependencies": {
35
+ "axios": "^1.0.0",
36
+ "zod": "^4.0.0"
37
+ },
38
+ "peerDependenciesMeta": {
39
+ "axios": {
40
+ "optional": true
41
+ }
42
+ },
43
+ "scripts": {
44
+ "build": "tsc -p tsconfig.build.json",
45
+ "typecheck": "tsc --noEmit"
46
+ }
47
+ }