@lokalise/api-contracts 6.11.0 → 6.13.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/README.md CHANGED
@@ -12,7 +12,7 @@ This eliminates assumptions across the boundary and keeps documentation, validat
12
12
  ### REST routes
13
13
 
14
14
  ```ts
15
- import { defineApiContract, ContractNoBody } from '@lokalise/api-contracts'
15
+ import { defineApiContract, noBodyResponse } from '@lokalise/api-contracts'
16
16
  import { z } from 'zod/v4'
17
17
 
18
18
  // GET with path params
@@ -41,7 +41,7 @@ const deleteUser = defineApiContract({
41
41
  requestPathParamsSchema: z.object({ userId: z.uuid() }),
42
42
  pathResolver: ({ userId }) => `/users/${userId}`,
43
43
  responsesByStatusCode: {
44
- 204: ContractNoBody,
44
+ 204: noBodyResponse(),
45
45
  },
46
46
  })
47
47
  ```
@@ -121,6 +121,87 @@ 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
+
170
+ ### OpenAPI response descriptions
171
+
172
+ All response factories accept an optional `ResponseOptions` object as their last argument.
173
+
174
+ ```ts
175
+ import {
176
+ defineApiContract,
177
+ noBodyResponse,
178
+ textResponse,
179
+ blobResponse,
180
+ sseResponse,
181
+ anyOfResponses,
182
+ } from '@lokalise/api-contracts'
183
+ import { z } from 'zod/v4'
184
+
185
+ const contract = defineApiContract({
186
+ method: 'post',
187
+ pathResolver: () => '/files',
188
+ requestBodySchema: z.object({ name: z.string() }),
189
+ responsesByStatusCode: {
190
+ 201: z.object({ id: z.string() }).describe('Created resource'),
191
+ 204: noBodyResponse({ description: 'Deleted — no content returned' }),
192
+ 200: anyOfResponses(
193
+ [
194
+ z.object({ id: z.string() }).describe('JSON representation'),
195
+ textResponse('text/csv', { description: 'CSV export' }),
196
+ blobResponse('application/pdf', { description: 'PDF report' }),
197
+ sseResponse({ update: z.object({ id: z.string() }) }, { description: 'Live update stream' }),
198
+ ],
199
+ { description: 'Multiple response formats available' },
200
+ ),
201
+ },
202
+ })
203
+ ```
204
+
124
205
  `getSseSchemaByEventName(contract)` extracts SSE event schemas from a contract:
125
206
 
126
207
  ```ts
@@ -136,31 +217,36 @@ getSseSchemaByEventName(chatCompletion)
136
217
  ### All fields
137
218
 
138
219
  ```ts
139
- defineApiContract({
220
+ type ApiContractOptions = {
140
221
  // Required
141
- method: 'get' | 'post' | 'put' | 'patch' | 'delete',
142
- pathResolver: (pathParams) => string,
143
- responsesByStatusCode: {
144
- [statusCode]: z.ZodType | ContractNoBody | TypedTextResponse | TypedBlobResponse | TypedSseResponse | AnyOfResponses
145
- },
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
+ >
146
232
 
147
233
  // Path params — links pathResolver parameter type to the schema
148
- requestPathParamsSchema: z.ZodObject,
234
+ requestPathParamsSchema?: z.ZodObject<z.ZodRawShape>
149
235
 
150
236
  // Request
151
- requestBodySchema: z.ZodType | ContractNoBody, // required for POST / PUT / PATCH, forbidden otherwise
152
- requestQuerySchema: z.ZodObject,
153
- 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>
154
240
 
155
241
  // Response
156
- responseHeaderSchema: z.ZodObject,
242
+ responseHeaderSchema?: z.ZodObject<z.ZodRawShape>
157
243
 
158
244
  // Documentation
159
- summary: string,
160
- description: string,
161
- tags: readonly string[],
162
- metadata: Record<string, unknown>,
163
- })
245
+ summary?: string
246
+ description?: string
247
+ tags?: readonly string[]
248
+ metadata?: Record<string, unknown>
249
+ }
164
250
  ```
165
251
 
166
252
  ### Header schemas
@@ -185,7 +271,7 @@ const contract = defineApiContract({
185
271
 
186
272
  ### Type utilities
187
273
 
188
- **`InferNonSseSuccessResponses<T>`** — TypeScript output type of all non-SSE 2xx responses. JSON schemas → `z.output<T>`, `textResponse` → `string`, `blobResponse` → `Blob`, `ContractNoBody` → `undefined`, `sseResponse` → `never` (excluded). `anyOfResponses` entries are unpacked before mapping.
274
+ **`InferNonSseSuccessResponses<T>`** — TypeScript output type of all non-SSE 2xx responses. JSON schemas → `z.output<T>`, `textResponse` → `string`, `blobResponse` → `Blob`, `ContractNoBody`/`NoBodyResponse` → `undefined`, `sseResponse` → `never` (excluded). `anyOfResponses` entries are unpacked before mapping.
189
275
 
190
276
  ```ts
191
277
  import type { InferNonSseSuccessResponses } from '@lokalise/api-contracts'
@@ -201,13 +287,13 @@ type CsvResponse = InferNonSseSuccessResponses<typeof exportCsv['responsesByStat
201
287
 
202
288
  **`InferSseSuccessResponses<T>`** — extracts the SSE event schema map type from a `responsesByStatusCode` map. Returns `never` when no SSE schemas are present.
203
289
 
204
- **`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.
205
291
 
206
292
  **`HasAnyJsonSuccessResponse<T>`** — `true` if any 2xx entry is a JSON Zod schema or an `AnyOfResponses` containing one.
207
293
 
208
294
  **`HasAnyNonSseSuccessResponse<T>`** — `true` if any 2xx entry is a non-SSE response (JSON, text, blob, or no-body).
209
295
 
210
- **`IsNoBodySuccessResponse<T>`** — `true` when all 2xx entries are `ContractNoBody` or no 2xx status codes are defined.
296
+ **`IsNoBodySuccessResponse<T>`** — `true` when all 2xx entries are `ContractNoBody`/`NoBodyResponse` or no 2xx status codes are defined.
211
297
 
212
298
  **`ContractResponseMode<T>`** — classifies a contract into `'dual'` (SSE + non-SSE), `'sse'` (SSE-only), or `'non-sse'` (JSON/text/blob/no-body).
213
299
 
@@ -229,9 +315,9 @@ These types are primarily consumed by HTTP client implementations.
229
315
 
230
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).
231
317
 
232
- **`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.
233
319
 
234
- **`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.
235
321
 
236
322
  **`DefaultStreaming<T>`** — `true` for SSE-only contracts, `false` for everything else.
237
323
 
@@ -271,7 +357,7 @@ import { describeApiContract } from '@lokalise/api-contracts'
271
357
  describeApiContract(getUser) // "GET /users/:userId"
272
358
  ```
273
359
 
274
- **`getSuccessResponseSchema`** — merged Zod schema from all 2xx JSON entries. `ContractNoBody` and non-JSON entries are excluded. Returns `null` when no schema is present.
360
+ **`getSuccessResponseSchema`** *(deprecated no known consumers, will be removed in a future release)* — merged Zod schema from all 2xx JSON entries. `ContractNoBody`/`NoBodyResponse` and non-JSON entries are excluded. Returns `null` when no schema is present.
275
361
 
276
362
  ```ts
277
363
  import { getSuccessResponseSchema } from '@lokalise/api-contracts'
@@ -280,7 +366,7 @@ getSuccessResponseSchema(getUser) // ZodObject
280
366
  getSuccessResponseSchema(deleteUser) // null
281
367
  ```
282
368
 
283
- **`getIsEmptyResponseExpected`** — `true` when no Zod schema exists among 2xx entries.
369
+ **`getIsEmptyResponseExpected`** *(deprecated no known consumers, will be removed in a future release)* — `true` when no Zod schema exists among 2xx entries.
284
370
 
285
371
  ```ts
286
372
  import { getIsEmptyResponseExpected } from '@lokalise/api-contracts'
@@ -289,7 +375,7 @@ getIsEmptyResponseExpected(deleteUser) // true
289
375
  getIsEmptyResponseExpected(getUser) // false
290
376
  ```
291
377
 
292
- **`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`).
293
379
 
294
380
  ```ts
295
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';
@@ -47,10 +47,47 @@ type SseInferClientResponseBody<T> = Extract<InferClientResponseBody<T>, AsyncIt
47
47
  * Like InferClientResponseBody but returns only non-SSE bodies — SSE entries resolve to never.
48
48
  */
49
49
  type NonSseInferClientResponseBody<T> = Exclude<InferClientResponseBody<T>, AsyncIterable<unknown>>;
50
+ type WildcardSseBody<V, K extends WildcardStatusCodeKey> = K extends '2xx' ? SseInferClientResponseBody<V> : InferClientResponseBody<V>;
51
+ type WildcardNonSseBody<V, K extends WildcardStatusCodeKey> = K extends '2xx' ? NonSseInferClientResponseBody<V> : InferClientResponseBody<V>;
52
+ type ExactStatusCodes<TApiContract extends ApiContract> = keyof TApiContract['responsesByStatusCode'] & HttpStatusCode;
53
+ type RangeStatusCodes<TApiContract extends ApiContract> = {
54
+ [K in keyof TApiContract['responsesByStatusCode'] & HttpStatusCodeRange]: ExpandStatusRangeKey<K>;
55
+ }[keyof TApiContract['responsesByStatusCode'] & HttpStatusCodeRange];
56
+ type DefaultSuccessStatusCodes<TApiContract extends ApiContract> = Exclude<SuccessfulHttpStatusCode, ExactStatusCodes<TApiContract> | RangeStatusCodes<TApiContract>>;
57
+ type DefaultNonSuccessStatusCodes<TApiContract extends ApiContract> = Exclude<Exclude<HttpStatusCode, SuccessfulHttpStatusCode>, ExactStatusCodes<TApiContract> | RangeStatusCodes<TApiContract>>;
58
+ type WildcardSseEntry<TApiContract extends ApiContract, K extends WildcardStatusCodeKey> = K extends 'default' ? {
59
+ statusCode: DefaultSuccessStatusCodes<TApiContract>;
60
+ headers: InferClientResponseHeaders<TApiContract>;
61
+ body: SseInferClientResponseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>>;
62
+ } | {
63
+ statusCode: DefaultNonSuccessStatusCodes<TApiContract>;
64
+ headers: InferClientResponseHeaders<TApiContract>;
65
+ body: InferClientResponseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>>;
66
+ } : {
67
+ statusCode: Exclude<ExpandStatusRangeKey<K>, ExactStatusCodes<TApiContract>>;
68
+ headers: InferClientResponseHeaders<TApiContract>;
69
+ body: WildcardSseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>, K>;
70
+ };
71
+ type WildcardNonSseEntry<TApiContract extends ApiContract, K extends WildcardStatusCodeKey> = K extends 'default' ? {
72
+ statusCode: DefaultSuccessStatusCodes<TApiContract>;
73
+ headers: InferClientResponseHeaders<TApiContract>;
74
+ body: NonSseInferClientResponseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>>;
75
+ } | {
76
+ statusCode: DefaultNonSuccessStatusCodes<TApiContract>;
77
+ headers: InferClientResponseHeaders<TApiContract>;
78
+ body: InferClientResponseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>>;
79
+ } : {
80
+ statusCode: Exclude<ExpandStatusRangeKey<K>, ExactStatusCodes<TApiContract>>;
81
+ headers: InferClientResponseHeaders<TApiContract>;
82
+ body: WildcardNonSseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>, K>;
83
+ };
50
84
  /**
51
85
  * 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)
86
+ * - exact success status codes and `'2xx'` range → SSE body only (AsyncIterable)
87
+ * - error status codes, other ranges, and `'default'` → body as-is (all kinds)
88
+ *
89
+ * `'default'` is split into a success half (`SuccessfulHttpStatusCode`) and a non-success half
90
+ * so that `captureAsError` type narrowing stays correct regardless of the actual status code.
54
91
  *
55
92
  * Headers are typed via `InferClientResponseHeaders`: known headers from `responseHeaderSchema`
56
93
  * are strongly typed; all other headers remain accessible as `string | undefined`.
@@ -61,11 +98,16 @@ export type InferSseClientResponse<TApiContract extends ApiContract> = {
61
98
  headers: InferClientResponseHeaders<TApiContract>;
62
99
  body: K extends SuccessfulHttpStatusCode ? SseInferClientResponseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>> : InferClientResponseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>>;
63
100
  };
64
- }[keyof TApiContract['responsesByStatusCode'] & HttpStatusCode];
101
+ }[keyof TApiContract['responsesByStatusCode'] & HttpStatusCode] | {
102
+ [K in keyof TApiContract['responsesByStatusCode'] & WildcardStatusCodeKey]: WildcardSseEntry<TApiContract, K>;
103
+ }[keyof TApiContract['responsesByStatusCode'] & WildcardStatusCodeKey];
65
104
  /**
66
105
  * 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)
106
+ * - exact success status codes and `'2xx'` range → non-SSE body only (JSON / text / blob / null)
107
+ * - error status codes, other ranges, and `'default'` → body as-is (all kinds)
108
+ *
109
+ * `'default'` is split into a success half (`SuccessfulHttpStatusCode`) and a non-success half
110
+ * so that `captureAsError` type narrowing stays correct regardless of the actual status code.
69
111
  *
70
112
  * Headers are typed via `InferClientResponseHeaders`: known headers from `responseHeaderSchema`
71
113
  * are strongly typed; all other headers remain accessible as `string | undefined`.
@@ -76,5 +118,7 @@ export type InferNonSseClientResponse<TApiContract extends ApiContract> = {
76
118
  headers: InferClientResponseHeaders<TApiContract>;
77
119
  body: K extends SuccessfulHttpStatusCode ? NonSseInferClientResponseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>> : InferClientResponseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>>;
78
120
  };
79
- }[keyof TApiContract['responsesByStatusCode'] & HttpStatusCode];
121
+ }[keyof TApiContract['responsesByStatusCode'] & HttpStatusCode] | {
122
+ [K in keyof TApiContract['responsesByStatusCode'] & WildcardStatusCodeKey]: WildcardNonSseEntry<TApiContract, K>;
123
+ }[keyof TApiContract['responsesByStatusCode'] & WildcardStatusCodeKey];
80
124
  export {};
@@ -1,24 +1,30 @@
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
+ export type ResponseOptions = {
5
+ readonly description?: string;
6
+ };
4
7
  export type TypedTextResponse = {
5
8
  readonly _tag: 'TextResponse';
6
9
  readonly contentType: string;
10
+ readonly description?: string;
7
11
  };
8
- export declare const textResponse: (contentType: string) => TypedTextResponse;
12
+ export declare const textResponse: (contentType: string, options?: ResponseOptions) => TypedTextResponse;
9
13
  export declare const isTextResponse: (value: ApiContractResponse) => value is TypedTextResponse;
10
14
  export type TypedBlobResponse = {
11
15
  readonly _tag: 'BlobResponse';
12
16
  readonly contentType: string;
17
+ readonly description?: string;
13
18
  };
14
- export declare const blobResponse: (contentType: string) => TypedBlobResponse;
19
+ export declare const blobResponse: (contentType: string, options?: ResponseOptions) => TypedBlobResponse;
15
20
  export declare const isBlobResponse: (value: ApiContractResponse) => value is TypedBlobResponse;
16
21
  export type SseSchemaByEventName = Record<string, z.ZodType>;
17
22
  export type TypedSseResponse<T extends SseSchemaByEventName = SseSchemaByEventName> = {
18
23
  readonly _tag: 'SseResponse';
19
24
  readonly schemaByEventName: T;
25
+ readonly description?: string;
20
26
  };
21
- export declare const sseResponse: <T extends SseSchemaByEventName>(schemaByEventName: T) => TypedSseResponse<T>;
27
+ export declare const sseResponse: <T extends SseSchemaByEventName>(schemaByEventName: T, options?: ResponseOptions) => TypedSseResponse<T>;
22
28
  export declare const isSseResponse: (value: ApiContractResponse) => value is TypedSseResponse;
23
29
  export type TypedJsonResponse = z.ZodType;
24
30
  export declare const isJsonResponse: (value: ApiContractResponse) => value is TypedJsonResponse;
@@ -26,11 +32,18 @@ export type TypedApiContractResponse = TypedJsonResponse | TypedTextResponse | T
26
32
  export type AnyOfResponses<T extends TypedApiContractResponse = TypedApiContractResponse> = {
27
33
  readonly _tag: 'AnyOfResponses';
28
34
  readonly responses: T[];
35
+ readonly description?: string;
29
36
  };
30
- export declare const anyOfResponses: <T extends TypedApiContractResponse>(responses: T[]) => AnyOfResponses<T>;
37
+ export declare const anyOfResponses: <T extends TypedApiContractResponse>(responses: T[], options?: ResponseOptions) => AnyOfResponses<T>;
31
38
  export declare const isAnyOfResponses: (value: ApiContractResponse) => value is AnyOfResponses;
32
- export type ApiContractResponse = typeof ContractNoBody | TypedApiContractResponse | AnyOfResponses;
33
- export type ResponsesByStatusCode = Partial<Record<HttpStatusCode, ApiContractResponse>>;
39
+ export type NoBodyResponse = {
40
+ readonly _tag: 'NoBodyResponse';
41
+ readonly description?: string;
42
+ };
43
+ export declare const noBodyResponse: (options?: ResponseOptions) => NoBodyResponse;
44
+ export declare const isNoBodyResponse: (value: ApiContractResponse) => value is NoBodyResponse;
45
+ export type ApiContractResponse = typeof ContractNoBody | NoBodyResponse | TypedApiContractResponse | AnyOfResponses;
46
+ export type ResponsesByStatusCode = Partial<Record<HttpStatusCode | WildcardStatusCodeKey, ApiContractResponse>>;
34
47
  export type ResponseKind = {
35
48
  kind: 'noContent';
36
49
  } | {
@@ -63,6 +76,7 @@ export type ResponseKind = {
63
76
  export declare const resolveContractResponse: (schemaEntry: ApiContractResponse, contentType: string | undefined, strict?: boolean) => ResponseKind | null;
64
77
  /**
65
78
  * Combines status-code lookup and content-type resolution into a single call.
66
- * 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.
67
81
  */
68
82
  export declare function resolveResponseEntry(responsesByStatusCode: ResponsesByStatusCode, statusCode: number, contentType: string | undefined, strictContentType: boolean): ResponseKind | null;
@@ -1,25 +1,34 @@
1
1
  import { ContractNoBody } from "./constants.js";
2
- export const textResponse = (contentType) => ({
2
+ export const textResponse = (contentType, options) => ({
3
3
  _tag: 'TextResponse',
4
4
  contentType,
5
+ ...(options?.description !== undefined && { description: options.description }),
5
6
  });
6
7
  export const isTextResponse = (value) => typeof value === 'object' && value !== null && '_tag' in value && value._tag === 'TextResponse';
7
- export const blobResponse = (contentType) => ({
8
+ export const blobResponse = (contentType, options) => ({
8
9
  _tag: 'BlobResponse',
9
10
  contentType,
11
+ ...(options?.description !== undefined && { description: options.description }),
10
12
  });
11
13
  export const isBlobResponse = (value) => typeof value === 'object' && value !== null && '_tag' in value && value._tag === 'BlobResponse';
12
- export const sseResponse = (schemaByEventName) => ({
14
+ export const sseResponse = (schemaByEventName, options) => ({
13
15
  _tag: 'SseResponse',
14
16
  schemaByEventName,
17
+ ...(options?.description !== undefined && { description: options.description }),
15
18
  });
16
19
  export const isSseResponse = (value) => typeof value === 'object' && value !== null && '_tag' in value && value._tag === 'SseResponse';
17
20
  export const isJsonResponse = (value) => typeof value === 'object' && value !== null && !('_tag' in value);
18
- export const anyOfResponses = (responses) => ({
21
+ export const anyOfResponses = (responses, options) => ({
19
22
  _tag: 'AnyOfResponses',
20
23
  responses,
24
+ ...(options?.description !== undefined && { description: options.description }),
21
25
  });
22
26
  export const isAnyOfResponses = (value) => typeof value === 'object' && value !== null && '_tag' in value && value._tag === 'AnyOfResponses';
27
+ export const noBodyResponse = (options) => ({
28
+ _tag: 'NoBodyResponse',
29
+ ...(options?.description !== undefined && { description: options.description }),
30
+ });
31
+ export const isNoBodyResponse = (value) => typeof value === 'object' && value !== null && '_tag' in value && value._tag === 'NoBodyResponse';
23
32
  const matchTypedResponse = (entry, contentType) => {
24
33
  if (isTextResponse(entry)) {
25
34
  return contentType.includes(entry.contentType) ? { kind: 'text' } : null;
@@ -66,7 +75,7 @@ const resolveByKind = (entry) => {
66
75
  * content-type to disambiguate regardless of this flag.
67
76
  */
68
77
  export const resolveContractResponse = (schemaEntry, contentType, strict = true) => {
69
- if (schemaEntry === ContractNoBody) {
78
+ if (schemaEntry === ContractNoBody || isNoBodyResponse(schemaEntry)) {
70
79
  return { kind: 'noContent' };
71
80
  }
72
81
  if (isAnyOfResponses(schemaEntry)) {
@@ -88,15 +97,40 @@ export const resolveContractResponse = (schemaEntry, contentType, strict = true)
88
97
  const matched = matchTypedResponse(schemaEntry, contentType);
89
98
  return matched ?? (strict ? null : resolveByKind(schemaEntry));
90
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
+ }
91
113
  /**
92
114
  * Combines status-code lookup and content-type resolution into a single call.
93
- * 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.
94
117
  */
95
118
  export function resolveResponseEntry(responsesByStatusCode, statusCode, contentType, strictContentType) {
96
- const schemaEntry = responsesByStatusCode[statusCode];
97
- if (!schemaEntry) {
98
- return null;
119
+ const exactEntry = responsesByStatusCode[statusCode];
120
+ if (exactEntry) {
121
+ return resolveContractResponse(exactEntry, contentType, strictContentType);
99
122
  }
100
- 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;
101
135
  }
102
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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"}
@@ -43,6 +43,8 @@ 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;
45
45
  export declare const hasAnySuccessSseResponse: (apiContract: ApiContract) => boolean;
46
+ /** @deprecated No known consumers — will be removed in a future release. */
46
47
  export declare const getSuccessResponseSchema: (routeConfig: ApiContract) => z.ZodType | null;
48
+ /** @deprecated No known consumers — will be removed in a future release. */
47
49
  export declare const getIsEmptyResponseExpected: (routeConfig: ApiContract) => boolean;
48
50
  export {};
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod/v4';
2
2
  import { SUCCESSFUL_HTTP_STATUS_CODES } from "../HttpStatusCodes.js";
3
3
  import { ContractNoBody } from "./constants.js";
4
- import { isAnyOfResponses, isBlobResponse, isSseResponse, isTextResponse, } from "./contractResponse.js";
4
+ import { isAnyOfResponses, isBlobResponse, isNoBodyResponse, isSseResponse, isTextResponse, } from "./contractResponse.js";
5
5
  export const defineApiContract = (contract) => contract;
6
6
  export const mapApiContractToPath = (routeConfig) => {
7
7
  if (!routeConfig.requestPathParamsSchema) {
@@ -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;
@@ -51,6 +51,7 @@ export const hasAnySuccessSseResponse = (apiContract) => {
51
51
  }
52
52
  return false;
53
53
  };
54
+ /** @deprecated No known consumers — will be removed in a future release. */
54
55
  // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: it is acceptable
55
56
  export const getSuccessResponseSchema = (routeConfig) => {
56
57
  const schemas = [];
@@ -68,6 +69,7 @@ export const getSuccessResponseSchema = (routeConfig) => {
68
69
  }
69
70
  }
70
71
  else if (value === ContractNoBody ||
72
+ isNoBodyResponse(value) ||
71
73
  isSseResponse(value) ||
72
74
  isTextResponse(value) ||
73
75
  isBlobResponse(value)) {
@@ -86,11 +88,12 @@ export const getSuccessResponseSchema = (routeConfig) => {
86
88
  }
87
89
  return hasDirectNonJsonEntry ? z.never() : null;
88
90
  };
91
+ /** @deprecated No known consumers — will be removed in a future release. */
89
92
  export const getIsEmptyResponseExpected = (routeConfig) => {
90
93
  let isEmptyResponseExpected = true;
91
94
  for (const code of SUCCESSFUL_HTTP_STATUS_CODES) {
92
95
  const value = routeConfig.responsesByStatusCode[code];
93
- if (value && value !== ContractNoBody) {
96
+ if (value && value !== ContractNoBody && !isNoBodyResponse(value)) {
94
97
  isEmptyResponseExpected = false;
95
98
  break;
96
99
  }
@@ -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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"}
@@ -3,7 +3,7 @@ import type { SuccessfulHttpStatusCode } from '../HttpStatusCodes.ts';
3
3
  import type { ValueOf } from '../typeUtils.ts';
4
4
  import type { ContractNoBody } from './constants.ts';
5
5
  import type { ResponsesByStatusCode } from './contractResponse.ts';
6
- type ExtractSuccessResponses<T extends ResponsesByStatusCode> = ValueOf<T, Extract<keyof T, SuccessfulHttpStatusCode>>;
6
+ type ExtractSuccessResponses<T extends ResponsesByStatusCode> = ValueOf<T, Extract<keyof T, SuccessfulHttpStatusCode | '2xx' | 'default'>>;
7
7
  /**
8
8
  * Returns true if all success responses have no body (ContractNoBody or no success status codes defined).
9
9
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lokalise/api-contracts",
3
- "version": "6.11.0",
3
+ "version": "6.13.0",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -11,7 +11,8 @@
11
11
  "homepage": "https://github.com/lokalise/shared-ts-libs",
12
12
  "repository": {
13
13
  "type": "git",
14
- "url": "git://github.com/lokalise/shared-ts-libs.git"
14
+ "url": "git://github.com/lokalise/shared-ts-libs.git",
15
+ "directory": "packages/app/api-contracts"
15
16
  },
16
17
  "exports": {
17
18
  ".": "./dist/index.js",
@@ -38,11 +39,11 @@
38
39
  "@biomejs/biome": "^2.4.7",
39
40
  "@lokalise/biome-config": "^3.1.0",
40
41
  "@lokalise/tsconfig": "^4.0.0",
41
- "@types/node": "^25.0.3",
42
- "@vitest/coverage-v8": "^4.0.18",
42
+ "@types/node": "^25.9.1",
43
+ "@vitest/coverage-v8": "^4.1.7",
43
44
  "rimraf": "^6.1.2",
44
45
  "typescript": "6.0.3",
45
- "vitest": "^4.0.18",
46
+ "vitest": "^4.1.7",
46
47
  "zod": "^4.3.6"
47
48
  },
48
49
  "scripts": {