@lokalise/api-contracts 6.12.0 → 6.13.1

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/README.md CHANGED
@@ -121,6 +121,52 @@ const chatCompletion = defineApiContract({
121
121
  })
122
122
  ```
123
123
 
124
+ ### Wildcard and default response keys
125
+
126
+ In addition to exact status codes, `responsesByStatusCode` accepts OpenAPI-style range keys (`'1xx'`–`'5xx'`) and `'default'` as fallbacks.
127
+
128
+ Lookup precedence at runtime: **exact code → range key → `'default'`**.
129
+
130
+ ```ts
131
+ import { defineApiContract } from '@lokalise/api-contracts'
132
+ import { z } from 'zod/v4'
133
+
134
+ // '2xx' covers all 200–299 responses
135
+ const listItems = defineApiContract({
136
+ method: 'get',
137
+ pathResolver: () => '/items',
138
+ responsesByStatusCode: {
139
+ '2xx': z.object({ items: z.array(z.string()) }),
140
+ '4xx': z.object({ message: z.string() }),
141
+ },
142
+ })
143
+
144
+ // exact code takes precedence over the range key
145
+ const createItem = defineApiContract({
146
+ method: 'post',
147
+ pathResolver: () => '/items',
148
+ requestBodySchema: z.object({ name: z.string() }),
149
+ responsesByStatusCode: {
150
+ 201: z.object({ id: z.string() }),
151
+ '4xx': z.object({ message: z.string() }),
152
+ },
153
+ })
154
+
155
+ // 'default' matches any status code not covered by a more specific entry
156
+ const flexible = defineApiContract({
157
+ method: 'get',
158
+ pathResolver: () => '/data',
159
+ responsesByStatusCode: {
160
+ 200: z.object({ data: z.unknown() }),
161
+ default: z.object({ error: z.string() }),
162
+ },
163
+ })
164
+ ```
165
+
166
+ The `'2xx'` range key participates in SSE detection and success/error type narrowing exactly like explicit 2xx codes: `InferNonSseClientResponse` maps it to `SuccessfulHttpStatusCode`, and `hasAnySuccessSseResponse` returns `true` when it holds an SSE schema.
167
+
168
+ `'default'` is split into a success half (`SuccessfulHttpStatusCode`) and a non-success half in `InferSseClientResponse` / `InferNonSseClientResponse` so that `captureAsError` type narrowing stays correct regardless of the actual status code.
169
+
124
170
  ### OpenAPI response descriptions
125
171
 
126
172
  All response factories accept an optional `ResponseOptions` object as their last argument.
@@ -171,31 +217,36 @@ getSseSchemaByEventName(chatCompletion)
171
217
  ### All fields
172
218
 
173
219
  ```ts
174
- defineApiContract({
220
+ type ApiContractOptions = {
175
221
  // Required
176
- method: 'get' | 'post' | 'put' | 'patch' | 'delete',
177
- pathResolver: (pathParams) => string,
178
- responsesByStatusCode: {
179
- [statusCode]: z.ZodType | NoBodyResponse | TypedTextResponse | TypedBlobResponse | TypedSseResponse | AnyOfResponses
180
- },
222
+ method: 'get' | 'post' | 'put' | 'patch' | 'delete'
223
+ pathResolver: (pathParams: Record<string, string>) => string
224
+ // Accepts exact codes, OpenAPI-style range keys ('1xx'–'5xx'), and a catch-all 'default'.
225
+ // Lookup precedence at runtime: exact code range key 'default'.
226
+ responsesByStatusCode: Partial<
227
+ Record<
228
+ HttpStatusCode | '1xx' | '2xx' | '3xx' | '4xx' | '5xx' | 'default',
229
+ z.ZodType | NoBodyResponse | TypedTextResponse | TypedBlobResponse | TypedSseResponse | AnyOfResponses
230
+ >
231
+ >
181
232
 
182
233
  // Path params — links pathResolver parameter type to the schema
183
- requestPathParamsSchema: z.ZodObject,
234
+ requestPathParamsSchema?: z.ZodObject<z.ZodRawShape>
184
235
 
185
236
  // Request
186
- requestBodySchema: z.ZodType | ContractNoBody, // required for POST / PUT / PATCH, forbidden otherwise
187
- requestQuerySchema: z.ZodObject,
188
- requestHeaderSchema: z.ZodObject,
237
+ requestBodySchema?: z.ZodType | ContractNoBody // required for POST / PUT / PATCH, forbidden otherwise
238
+ requestQuerySchema?: z.ZodObject<z.ZodRawShape>
239
+ requestHeaderSchema?: z.ZodObject<z.ZodRawShape>
189
240
 
190
241
  // Response
191
- responseHeaderSchema: z.ZodObject,
242
+ responseHeaderSchema?: z.ZodObject<z.ZodRawShape>
192
243
 
193
244
  // Documentation
194
- summary: string,
195
- description: string,
196
- tags: readonly string[],
197
- metadata: Record<string, unknown>,
198
- })
245
+ summary?: string
246
+ description?: string
247
+ tags?: readonly string[]
248
+ metadata?: Record<string, unknown>
249
+ }
199
250
  ```
200
251
 
201
252
  ### Header schemas
@@ -236,7 +287,7 @@ type CsvResponse = InferNonSseSuccessResponses<typeof exportCsv['responsesByStat
236
287
 
237
288
  **`InferSseSuccessResponses<T>`** — extracts the SSE event schema map type from a `responsesByStatusCode` map. Returns `never` when no SSE schemas are present.
238
289
 
239
- **`HasAnySseSuccessResponse<T>`** — `true` if any 2xx entry is a `TypedSseResponse` or an `AnyOfResponses` containing one.
290
+ **`HasAnySseSuccessResponse<T>`** — `true` if any 2xx entry (exact code or `'2xx'` range key) is a `TypedSseResponse` or an `AnyOfResponses` containing one.
240
291
 
241
292
  **`HasAnyJsonSuccessResponse<T>`** — `true` if any 2xx entry is a JSON Zod schema or an `AnyOfResponses` containing one.
242
293
 
@@ -264,9 +315,9 @@ These types are primarily consumed by HTTP client implementations.
264
315
 
265
316
  **`ClientRequestParams<TApiContract, TIsStreaming>`** — infers the request parameter object for a contract. Includes `pathParams`, `body`, `queryParams`, `headers` (required when the corresponding schema is defined), `pathPrefix` (always optional), and `streaming` (required for dual-mode contracts, forbidden otherwise).
266
317
 
267
- **`InferSseClientResponse<TApiContract>`** — discriminated union of `{ statusCode, headers, body }` for SSE mode. Success status codes yield `AsyncIterable<SseEventOf<...>>`; error codes yield the declared body type.
318
+ **`InferSseClientResponse<TApiContract>`** — discriminated union of `{ statusCode, headers, body }` for SSE mode. Exact 2xx codes and the `'2xx'` range key yield `AsyncIterable<SseEventOf<...>>`; error codes, other range keys, and `'default'` yield the declared body type. `'default'` is split into a `SuccessfulHttpStatusCode` half and a non-success half.
268
319
 
269
- **`InferNonSseClientResponse<TApiContract>`** — same shape as above for non-SSE mode. Success status codes yield JSON / `string` / `Blob` / `null`; SSE entries are excluded (`never`).
320
+ **`InferNonSseClientResponse<TApiContract>`** — same shape as above for non-SSE mode. Exact 2xx codes and the `'2xx'` range key yield JSON / `string` / `Blob` / `null` (SSE excluded); error codes, other range keys, and `'default'` yield the declared body type as-is. `'default'` is split the same way.
270
321
 
271
322
  **`DefaultStreaming<T>`** — `true` for SSE-only contracts, `false` for everything else.
272
323
 
@@ -324,7 +375,7 @@ getIsEmptyResponseExpected(deleteUser) // true
324
375
  getIsEmptyResponseExpected(getUser) // false
325
376
  ```
326
377
 
327
- **`hasAnySuccessSseResponse`** — `true` when any 2xx entry is an SSE response (including inside `anyOfResponses`).
378
+ **`hasAnySuccessSseResponse`** — `true` when any 2xx entry (exact code or `'2xx'` range key) is an SSE response (including inside `anyOfResponses`).
328
379
 
329
380
  ```ts
330
381
  import { hasAnySuccessSseResponse } from '@lokalise/api-contracts'
@@ -1,3 +1,40 @@
1
- export type HttpStatusCode = 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 226 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511;
1
+ /** Tuple of all 1xx informational HTTP status codes. */
2
+ export declare const INFORMATIONAL_HTTP_STATUS_CODES: readonly [100, 101, 102, 103];
3
+ /** Union of all 1xx informational HTTP status codes. */
4
+ export type InformationalHttpStatusCode = (typeof INFORMATIONAL_HTTP_STATUS_CODES)[number];
5
+ /** Tuple of all 2xx successful HTTP status codes. */
2
6
  export declare const SUCCESSFUL_HTTP_STATUS_CODES: readonly [200, 201, 202, 203, 204, 205, 206, 207, 208, 226];
7
+ /** Union of all 2xx successful HTTP status codes. */
3
8
  export type SuccessfulHttpStatusCode = (typeof SUCCESSFUL_HTTP_STATUS_CODES)[number];
9
+ /** Tuple of all 3xx redirection HTTP status codes. */
10
+ export declare const REDIRECTION_HTTP_STATUS_CODES: readonly [300, 301, 302, 303, 304, 305, 306, 307, 308];
11
+ /** Union of all 3xx redirection HTTP status codes. */
12
+ export type RedirectionHttpStatusCode = (typeof REDIRECTION_HTTP_STATUS_CODES)[number];
13
+ /** Tuple of all 4xx client-error HTTP status codes. */
14
+ export declare const CLIENT_ERROR_HTTP_STATUS_CODES: readonly [400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 421, 422, 423, 424, 425, 426, 428, 429, 431, 451];
15
+ /** Union of all 4xx client-error HTTP status codes. */
16
+ export type ClientErrorHttpStatusCode = (typeof CLIENT_ERROR_HTTP_STATUS_CODES)[number];
17
+ /** Tuple of all 5xx server-error HTTP status codes. */
18
+ export declare const SERVER_ERROR_HTTP_STATUS_CODES: readonly [500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511];
19
+ /** Union of all 5xx server-error HTTP status codes. */
20
+ export type ServerErrorHttpStatusCode = (typeof SERVER_ERROR_HTTP_STATUS_CODES)[number];
21
+ /** Union of every standard HTTP status code across all classes (1xx–5xx). */
22
+ export type HttpStatusCode = InformationalHttpStatusCode | SuccessfulHttpStatusCode | RedirectionHttpStatusCode | ClientErrorHttpStatusCode | ServerErrorHttpStatusCode;
23
+ /** String representation of an HTTP status class. */
24
+ export type HttpStatusCodeRange = '1xx' | '2xx' | '3xx' | '4xx' | '5xx';
25
+ /** Range key or catch-all fallback. */
26
+ export type WildcardStatusCodeKey = HttpStatusCodeRange | 'default';
27
+ type RangeExpansion = {
28
+ '1xx': InformationalHttpStatusCode;
29
+ '2xx': SuccessfulHttpStatusCode;
30
+ '3xx': RedirectionHttpStatusCode;
31
+ '4xx': ClientErrorHttpStatusCode;
32
+ '5xx': ServerErrorHttpStatusCode;
33
+ default: HttpStatusCode;
34
+ };
35
+ /**
36
+ * Maps a `WildcardStatusCodeKey` to its concrete `HttpStatusCode` union.
37
+ * `'default'` expands to the full `HttpStatusCode` union.
38
+ */
39
+ export type ExpandStatusRangeKey<K extends WildcardStatusCodeKey> = RangeExpansion[K];
40
+ export {};
@@ -1,4 +1,18 @@
1
+ /** Tuple of all 1xx informational HTTP status codes. */
2
+ export const INFORMATIONAL_HTTP_STATUS_CODES = [100, 101, 102, 103];
3
+ /** Tuple of all 2xx successful HTTP status codes. */
1
4
  export const SUCCESSFUL_HTTP_STATUS_CODES = [
2
5
  200, 201, 202, 203, 204, 205, 206, 207, 208, 226,
3
6
  ];
7
+ /** Tuple of all 3xx redirection HTTP status codes. */
8
+ export const REDIRECTION_HTTP_STATUS_CODES = [300, 301, 302, 303, 304, 305, 306, 307, 308];
9
+ /** Tuple of all 4xx client-error HTTP status codes. */
10
+ export const CLIENT_ERROR_HTTP_STATUS_CODES = [
11
+ 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418,
12
+ 421, 422, 423, 424, 425, 426, 428, 429, 431, 451,
13
+ ];
14
+ /** Tuple of all 5xx server-error HTTP status codes. */
15
+ export const SERVER_ERROR_HTTP_STATUS_CODES = [
16
+ 500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511,
17
+ ];
4
18
  //# sourceMappingURL=HttpStatusCodes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"HttpStatusCodes.js","sourceRoot":"","sources":["../src/HttpStatusCodes.ts"],"names":[],"mappings":"AAiEA,MAAM,CAAC,MAAM,4BAA4B,GAAG;IAC1C,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;CACxC,CAAA"}
1
+ {"version":3,"file":"HttpStatusCodes.js","sourceRoot":"","sources":["../src/HttpStatusCodes.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAU,CAAA;AAI5E,qDAAqD;AACrD,MAAM,CAAC,MAAM,4BAA4B,GAAG;IAC1C,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;CACxC,CAAA;AAIV,sDAAsD;AACtD,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAU,CAAA;AAInG,uDAAuD;AACvD,MAAM,CAAC,MAAM,8BAA8B,GAAG;IAC5C,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;IAC7F,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;CACxC,CAAA;AAIV,uDAAuD;AACvD,MAAM,CAAC,MAAM,8BAA8B,GAAG;IAC5C,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;CAC7C,CAAA"}
@@ -1,6 +1,6 @@
1
1
  import type { z } from 'zod/v4';
2
2
  import type { InferSchemaInput, InferSchemaOutput } from '../apiContracts.ts';
3
- import type { HttpStatusCode, SuccessfulHttpStatusCode } from '../HttpStatusCodes.ts';
3
+ import type { ExpandStatusRangeKey, HttpStatusCode, HttpStatusCodeRange, SuccessfulHttpStatusCode, WildcardStatusCodeKey } from '../HttpStatusCodes.ts';
4
4
  import type { Prettify } from '../typeUtils.ts';
5
5
  import type { ContractNoBody } from './constants.ts';
6
6
  import type { ResponsesByStatusCode, SseSchemaByEventName } from './contractResponse.ts';
@@ -27,8 +27,11 @@ export type ClientRequestParams<TApiContract extends ApiContract, TIsStreaming e
27
27
  type InferClientResponseHeaders<TApiContract extends ApiContract> = TApiContract['responseHeaderSchema'] extends z.ZodType ? Omit<Record<string, string>, keyof InferSchemaOutput<TApiContract['responseHeaderSchema']>> & InferSchemaOutput<TApiContract['responseHeaderSchema']> : Record<string, string>;
28
28
  /**
29
29
  * Maps a single responsesByStatusCode entry value to its TypeScript body type.
30
+ * Both no-body forms (the ContractNoBody symbol and tagged noBodyResponse()) map to null.
30
31
  */
31
- type InferClientResponseBody<T> = T extends typeof ContractNoBody ? null : T extends z.ZodType ? InferSchemaOutput<T> : T extends {
32
+ type InferClientResponseBody<T> = T extends typeof ContractNoBody ? null : T extends {
33
+ _tag: 'NoBodyResponse';
34
+ } ? null : T extends z.ZodType ? InferSchemaOutput<T> : T extends {
32
35
  _tag: 'TextResponse';
33
36
  } ? string : T extends {
34
37
  _tag: 'BlobResponse';
@@ -47,10 +50,47 @@ type SseInferClientResponseBody<T> = Extract<InferClientResponseBody<T>, AsyncIt
47
50
  * Like InferClientResponseBody but returns only non-SSE bodies — SSE entries resolve to never.
48
51
  */
49
52
  type NonSseInferClientResponseBody<T> = Exclude<InferClientResponseBody<T>, AsyncIterable<unknown>>;
53
+ type WildcardSseBody<V, K extends WildcardStatusCodeKey> = K extends '2xx' ? SseInferClientResponseBody<V> : InferClientResponseBody<V>;
54
+ type WildcardNonSseBody<V, K extends WildcardStatusCodeKey> = K extends '2xx' ? NonSseInferClientResponseBody<V> : InferClientResponseBody<V>;
55
+ type ExactStatusCodes<TApiContract extends ApiContract> = keyof TApiContract['responsesByStatusCode'] & HttpStatusCode;
56
+ type RangeStatusCodes<TApiContract extends ApiContract> = {
57
+ [K in keyof TApiContract['responsesByStatusCode'] & HttpStatusCodeRange]: ExpandStatusRangeKey<K>;
58
+ }[keyof TApiContract['responsesByStatusCode'] & HttpStatusCodeRange];
59
+ type DefaultSuccessStatusCodes<TApiContract extends ApiContract> = Exclude<SuccessfulHttpStatusCode, ExactStatusCodes<TApiContract> | RangeStatusCodes<TApiContract>>;
60
+ type DefaultNonSuccessStatusCodes<TApiContract extends ApiContract> = Exclude<Exclude<HttpStatusCode, SuccessfulHttpStatusCode>, ExactStatusCodes<TApiContract> | RangeStatusCodes<TApiContract>>;
61
+ type WildcardSseEntry<TApiContract extends ApiContract, K extends WildcardStatusCodeKey> = K extends 'default' ? {
62
+ statusCode: DefaultSuccessStatusCodes<TApiContract>;
63
+ headers: InferClientResponseHeaders<TApiContract>;
64
+ body: SseInferClientResponseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>>;
65
+ } | {
66
+ statusCode: DefaultNonSuccessStatusCodes<TApiContract>;
67
+ headers: InferClientResponseHeaders<TApiContract>;
68
+ body: InferClientResponseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>>;
69
+ } : {
70
+ statusCode: Exclude<ExpandStatusRangeKey<K>, ExactStatusCodes<TApiContract>>;
71
+ headers: InferClientResponseHeaders<TApiContract>;
72
+ body: WildcardSseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>, K>;
73
+ };
74
+ type WildcardNonSseEntry<TApiContract extends ApiContract, K extends WildcardStatusCodeKey> = K extends 'default' ? {
75
+ statusCode: DefaultSuccessStatusCodes<TApiContract>;
76
+ headers: InferClientResponseHeaders<TApiContract>;
77
+ body: NonSseInferClientResponseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>>;
78
+ } | {
79
+ statusCode: DefaultNonSuccessStatusCodes<TApiContract>;
80
+ headers: InferClientResponseHeaders<TApiContract>;
81
+ body: InferClientResponseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>>;
82
+ } : {
83
+ statusCode: Exclude<ExpandStatusRangeKey<K>, ExactStatusCodes<TApiContract>>;
84
+ headers: InferClientResponseHeaders<TApiContract>;
85
+ body: WildcardNonSseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>, K>;
86
+ };
50
87
  /**
51
88
  * Infers a discriminated union of `{ statusCode, headers, body }` for SSE mode:
52
- * - success status codes → SSE body only (AsyncIterable)
53
- * - error status codes → body as-is (all kinds)
89
+ * - exact success status codes and `'2xx'` range → SSE body only (AsyncIterable)
90
+ * - error status codes, other ranges, and `'default'` → body as-is (all kinds)
91
+ *
92
+ * `'default'` is split into a success half (`SuccessfulHttpStatusCode`) and a non-success half
93
+ * so that `captureAsError` type narrowing stays correct regardless of the actual status code.
54
94
  *
55
95
  * Headers are typed via `InferClientResponseHeaders`: known headers from `responseHeaderSchema`
56
96
  * are strongly typed; all other headers remain accessible as `string | undefined`.
@@ -61,11 +101,16 @@ export type InferSseClientResponse<TApiContract extends ApiContract> = {
61
101
  headers: InferClientResponseHeaders<TApiContract>;
62
102
  body: K extends SuccessfulHttpStatusCode ? SseInferClientResponseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>> : InferClientResponseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>>;
63
103
  };
64
- }[keyof TApiContract['responsesByStatusCode'] & HttpStatusCode];
104
+ }[keyof TApiContract['responsesByStatusCode'] & HttpStatusCode] | {
105
+ [K in keyof TApiContract['responsesByStatusCode'] & WildcardStatusCodeKey]: WildcardSseEntry<TApiContract, K>;
106
+ }[keyof TApiContract['responsesByStatusCode'] & WildcardStatusCodeKey];
65
107
  /**
66
108
  * Infers a discriminated union of `{ statusCode, headers, body }` for non-SSE mode:
67
- * - success status codes → non-SSE body only (JSON / text / blob / null)
68
- * - error status codes → body as-is (all kinds)
109
+ * - exact success status codes and `'2xx'` range → non-SSE body only (JSON / text / blob / null)
110
+ * - error status codes, other ranges, and `'default'` → body as-is (all kinds)
111
+ *
112
+ * `'default'` is split into a success half (`SuccessfulHttpStatusCode`) and a non-success half
113
+ * so that `captureAsError` type narrowing stays correct regardless of the actual status code.
69
114
  *
70
115
  * Headers are typed via `InferClientResponseHeaders`: known headers from `responseHeaderSchema`
71
116
  * are strongly typed; all other headers remain accessible as `string | undefined`.
@@ -76,5 +121,7 @@ export type InferNonSseClientResponse<TApiContract extends ApiContract> = {
76
121
  headers: InferClientResponseHeaders<TApiContract>;
77
122
  body: K extends SuccessfulHttpStatusCode ? NonSseInferClientResponseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>> : InferClientResponseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>>;
78
123
  };
79
- }[keyof TApiContract['responsesByStatusCode'] & HttpStatusCode];
124
+ }[keyof TApiContract['responsesByStatusCode'] & HttpStatusCode] | {
125
+ [K in keyof TApiContract['responsesByStatusCode'] & WildcardStatusCodeKey]: WildcardNonSseEntry<TApiContract, K>;
126
+ }[keyof TApiContract['responsesByStatusCode'] & WildcardStatusCodeKey];
80
127
  export {};
@@ -1,5 +1,5 @@
1
1
  import type { z } from 'zod/v4';
2
- import type { HttpStatusCode } from '../HttpStatusCodes.ts';
2
+ import type { HttpStatusCode, WildcardStatusCodeKey } from '../HttpStatusCodes.ts';
3
3
  import { ContractNoBody } from './constants.ts';
4
4
  export type ResponseOptions = {
5
5
  readonly description?: string;
@@ -43,7 +43,7 @@ export type NoBodyResponse = {
43
43
  export declare const noBodyResponse: (options?: ResponseOptions) => NoBodyResponse;
44
44
  export declare const isNoBodyResponse: (value: ApiContractResponse) => value is NoBodyResponse;
45
45
  export type ApiContractResponse = typeof ContractNoBody | NoBodyResponse | TypedApiContractResponse | AnyOfResponses;
46
- export type ResponsesByStatusCode = Partial<Record<HttpStatusCode, ApiContractResponse>>;
46
+ export type ResponsesByStatusCode = Partial<Record<HttpStatusCode | WildcardStatusCodeKey, ApiContractResponse>>;
47
47
  export type ResponseKind = {
48
48
  kind: 'noContent';
49
49
  } | {
@@ -76,6 +76,7 @@ export type ResponseKind = {
76
76
  export declare const resolveContractResponse: (schemaEntry: ApiContractResponse, contentType: string | undefined, strict?: boolean) => ResponseKind | null;
77
77
  /**
78
78
  * Combines status-code lookup and content-type resolution into a single call.
79
- * Returns `null` when the status code is not in the contract or the content-type cannot be matched.
79
+ * Lookup precedence: exact code range key (e.g. `'4xx'`) `'default'`.
80
+ * Returns `null` when no entry matches or the content-type cannot be matched.
80
81
  */
81
82
  export declare function resolveResponseEntry(responsesByStatusCode: ResponsesByStatusCode, statusCode: number, contentType: string | undefined, strictContentType: boolean): ResponseKind | null;
@@ -97,15 +97,40 @@ export const resolveContractResponse = (schemaEntry, contentType, strict = true)
97
97
  const matched = matchTypedResponse(schemaEntry, contentType);
98
98
  return matched ?? (strict ? null : resolveByKind(schemaEntry));
99
99
  };
100
+ function getRangeKey(statusCode) {
101
+ if (statusCode >= 100 && statusCode < 200)
102
+ return '1xx';
103
+ if (statusCode >= 200 && statusCode < 300)
104
+ return '2xx';
105
+ if (statusCode >= 300 && statusCode < 400)
106
+ return '3xx';
107
+ if (statusCode >= 400 && statusCode < 500)
108
+ return '4xx';
109
+ if (statusCode >= 500 && statusCode < 600)
110
+ return '5xx';
111
+ return null;
112
+ }
100
113
  /**
101
114
  * Combines status-code lookup and content-type resolution into a single call.
102
- * Returns `null` when the status code is not in the contract or the content-type cannot be matched.
115
+ * Lookup precedence: exact code range key (e.g. `'4xx'`) `'default'`.
116
+ * Returns `null` when no entry matches or the content-type cannot be matched.
103
117
  */
104
118
  export function resolveResponseEntry(responsesByStatusCode, statusCode, contentType, strictContentType) {
105
- const schemaEntry = responsesByStatusCode[statusCode];
106
- if (!schemaEntry) {
107
- return null;
119
+ const exactEntry = responsesByStatusCode[statusCode];
120
+ if (exactEntry) {
121
+ return resolveContractResponse(exactEntry, contentType, strictContentType);
108
122
  }
109
- return resolveContractResponse(schemaEntry, contentType, strictContentType);
123
+ const rangeKey = getRangeKey(statusCode);
124
+ if (rangeKey) {
125
+ const rangeEntry = responsesByStatusCode[rangeKey];
126
+ if (rangeEntry) {
127
+ return resolveContractResponse(rangeEntry, contentType, strictContentType);
128
+ }
129
+ }
130
+ const defaultEntry = responsesByStatusCode.default;
131
+ if (defaultEntry) {
132
+ return resolveContractResponse(defaultEntry, contentType, strictContentType);
133
+ }
134
+ return null;
110
135
  }
111
136
  //# sourceMappingURL=contractResponse.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"contractResponse.js","sourceRoot":"","sources":["../../src/new/contractResponse.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"contractResponse.js","sourceRoot":"","sources":["../../src/new/contractResponse.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod/v4';
2
2
  import type { CommonRouteDefinitionMetadata, InferSchemaOutput, RoutePathResolver } from '../apiContracts.ts';
3
- import type { Exactly } from '../typeUtils.ts';
3
+ import type { DistributiveOmit, Exactly } from '../typeUtils.ts';
4
4
  import { ContractNoBody } from './constants.ts';
5
5
  import { type ResponsesByStatusCode, type SseSchemaByEventName } from './contractResponse.ts';
6
6
  export type RequestPathParamsSchema = z.ZodObject;
@@ -32,13 +32,13 @@ export type PayloadApiContract = CommonApiContract & {
32
32
  requestBodySchema: typeof ContractNoBody | z.ZodType;
33
33
  };
34
34
  export type ApiContract = GetApiContract | DeleteApiContract | PayloadApiContract;
35
- type TypedPathApiContract<T extends RequestPathParamsSchema> = Omit<ApiContract, 'pathResolver' | 'requestPathParamsSchema'> & {
36
- pathResolver: RoutePathResolver<InferSchemaOutput<T>>;
37
- requestPathParamsSchema?: T;
35
+ type TypedPathApiContract<TPathParamsSchema extends RequestPathParamsSchema | undefined> = DistributiveOmit<ApiContract, 'pathResolver' | 'requestPathParamsSchema'> & {
36
+ pathResolver: RoutePathResolver<InferSchemaOutput<TPathParamsSchema>>;
37
+ requestPathParamsSchema?: TPathParamsSchema;
38
38
  };
39
- export declare const defineApiContract: <PathParamsSchema extends RequestPathParamsSchema, const Contract extends TypedPathApiContract<PathParamsSchema>>(contract: Exactly<Contract, TypedPathApiContract<PathParamsSchema>> & {
40
- requestPathParamsSchema?: PathParamsSchema;
41
- }) => Contract;
39
+ export declare const defineApiContract: <TPathParamsSchema extends RequestPathParamsSchema | undefined = undefined, const TContract extends TypedPathApiContract<TPathParamsSchema> = TypedPathApiContract<TPathParamsSchema>>(contract: Exactly<TContract, TypedPathApiContract<TPathParamsSchema>> & {
40
+ requestPathParamsSchema?: TPathParamsSchema;
41
+ }) => TContract;
42
42
  export declare const mapApiContractToPath: (routeConfig: ApiContract) => string;
43
43
  export declare const describeApiContract: (routeConfig: ApiContract) => string;
44
44
  export declare const getSseSchemaByEventName: (routeConfig: ApiContract) => SseSchemaByEventName | null;
@@ -33,7 +33,7 @@ export const getSseSchemaByEventName = (routeConfig) => {
33
33
  return Object.keys(result).length > 0 ? result : null;
34
34
  };
35
35
  export const hasAnySuccessSseResponse = (apiContract) => {
36
- for (const code of SUCCESSFUL_HTTP_STATUS_CODES) {
36
+ for (const code of [...SUCCESSFUL_HTTP_STATUS_CODES, '2xx', 'default']) {
37
37
  const value = apiContract.responsesByStatusCode[code];
38
38
  if (!value) {
39
39
  continue;
@@ -1 +1 @@
1
- {"version":3,"file":"defineApiContract.js","sourceRoot":"","sources":["../../src/new/defineApiContract.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"defineApiContract.js","sourceRoot":"","sources":["../../src/new/defineApiContract.ts"],"names":[],"mappings":"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"}
@@ -2,14 +2,17 @@ import type { z } from 'zod/v4';
2
2
  import type { SuccessfulHttpStatusCode } from '../HttpStatusCodes.ts';
3
3
  import type { ValueOf } from '../typeUtils.ts';
4
4
  import type { ContractNoBody } from './constants.ts';
5
- import type { ResponsesByStatusCode } from './contractResponse.ts';
6
- type ExtractSuccessResponses<T extends ResponsesByStatusCode> = ValueOf<T, Extract<keyof T, SuccessfulHttpStatusCode>>;
5
+ import type { NoBodyResponse, ResponsesByStatusCode } from './contractResponse.ts';
6
+ type ExtractSuccessResponses<T extends ResponsesByStatusCode> = ValueOf<T, Extract<keyof T, SuccessfulHttpStatusCode | '2xx' | 'default'>>;
7
7
  /**
8
- * Returns true if all success responses have no body (ContractNoBody or no success status codes defined).
8
+ * Returns true if all success responses have no body
9
+ * (ContractNoBody, noBodyResponse(), or no success status codes defined).
10
+ *
11
+ * @deprecated No known consumers — will be removed in a future release.
9
12
  */
10
13
  export type IsNoBodySuccessResponse<T extends ResponsesByStatusCode> = [
11
14
  ExtractSuccessResponses<T>
12
- ] extends [typeof ContractNoBody | undefined] ? true : false;
15
+ ] extends [typeof ContractNoBody | NoBodyResponse | undefined] ? true : false;
13
16
  type UnpackAnyOf<T> = T extends {
14
17
  _tag: 'AnyOfResponses';
15
18
  responses: Array<infer Item>;
@@ -46,7 +49,7 @@ type NonSseBodyOf<T> = T extends {
46
49
  /**
47
50
  * Infers the TypeScript output type of all non-SSE success responses.
48
51
  * JSON schemas → z.output<T>. TextResponse → string. BlobResponse → Blob.
49
- * ContractNoBody → undefined. SseResponse → never (excluded).
52
+ * ContractNoBody and noBodyResponse() → undefined. SseResponse → never (excluded).
50
53
  * AnyOfResponses are unpacked before mapping.
51
54
  */
52
55
  export type InferNonSseSuccessResponses<T extends ResponsesByStatusCode> = NonSseBodyOf<FlatSuccessResponses<T>>;
@@ -90,5 +93,7 @@ export type AvailableResponseModes<T extends ResponsesByStatusCode> = (HasAnyJso
90
93
  _tag: 'BlobResponse';
91
94
  }> extends never ? never : 'blob') | (Extract<FlatSuccessResponses<T>, {
92
95
  _tag: 'TextResponse';
93
- }> extends never ? never : 'text') | (Extract<FlatSuccessResponses<T>, typeof ContractNoBody> extends never ? never : 'noContent');
96
+ }> extends never ? never : 'text') | (Extract<FlatSuccessResponses<T>, typeof ContractNoBody | {
97
+ _tag: 'NoBodyResponse';
98
+ }> extends never ? never : 'noContent');
94
99
  export {};
@@ -15,6 +15,20 @@ export type IsUnion<T, U = T> = (T extends unknown ? ([U] extends [T] ? 0 : 1) :
15
15
  export type Exactly<T, U> = T & {
16
16
  [K in keyof T]: K extends keyof U ? T[K] : never;
17
17
  };
18
+ /**
19
+ * Distributed `keyof`: the union of keys across all members of a union type.
20
+ * (Plain `keyof` over a union yields only the keys common to every member.)
21
+ */
22
+ export type KeysOfUnion<TUnion> = TUnion extends unknown ? keyof TUnion : never;
23
+ /**
24
+ * Like `Omit`, but distributes over unions: each union member is transformed
25
+ * separately, preserving discriminated-union relationships between keys.
26
+ * (Plain `Omit` collapses a union into a single object type of its common keys.)
27
+ *
28
+ * Keys are constrained to `KeysOfUnion` rather than `keyof TUnion`, so keys present
29
+ * on only some union members can be omitted too — members without the key pass through unchanged.
30
+ */
31
+ export type DistributiveOmit<TUnion, TKeys extends KeysOfUnion<TUnion>> = TUnion extends unknown ? Omit<TUnion, TKeys> : never;
18
32
  /**
19
33
  * Extracts a union of value types from an object type.
20
34
  * Optionally constrained to a subset of keys via ValueType.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lokalise/api-contracts",
3
- "version": "6.12.0",
3
+ "version": "6.13.1",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -36,14 +36,14 @@
36
36
  "zod": ">=3.25.56"
37
37
  },
38
38
  "devDependencies": {
39
- "@biomejs/biome": "^2.4.7",
39
+ "@biomejs/biome": "^2.5.0",
40
40
  "@lokalise/biome-config": "^3.1.0",
41
41
  "@lokalise/tsconfig": "^4.0.0",
42
- "@types/node": "^25.9.0",
43
- "@vitest/coverage-v8": "^4.0.18",
42
+ "@types/node": "^25.9.3",
43
+ "@vitest/coverage-v8": "^4.1.9",
44
44
  "rimraf": "^6.1.2",
45
45
  "typescript": "6.0.3",
46
- "vitest": "^4.0.18",
46
+ "vitest": "^4.1.9",
47
47
  "zod": "^4.3.6"
48
48
  },
49
49
  "scripts": {