@lokalise/api-contracts 6.8.0 → 6.9.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/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './apiContracts.ts';
2
2
  export * from './contractBuilder.ts';
3
3
  export * from './HttpStatusCodes.ts';
4
+ export * from './new/clientTypes.ts';
4
5
  export * from './new/constants.ts';
5
6
  export * from './new/contractResponse.ts';
6
7
  export * from './new/defineApiContract.ts';
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ export * from "./apiContracts.js";
2
2
  // Universal contract builder
3
3
  export * from "./contractBuilder.js";
4
4
  export * from "./HttpStatusCodes.js";
5
+ export * from "./new/clientTypes.js";
5
6
  export * from "./new/constants.js";
6
7
  export * from "./new/contractResponse.js";
7
8
  export * from "./new/defineApiContract.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAA;AACjC,6BAA6B;AAC7B,cAAc,sBAAsB,CAAA;AACpC,cAAc,sBAAsB,CAAA;AACpC,cAAc,oBAAoB,CAAA;AAClC,cAAc,2BAA2B,CAAA;AACzC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,qBAAqB,CAAA;AACnC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,+BAA+B,CAAA;AAC7C,+BAA+B;AAC/B,cAAc,4BAA4B,CAAA;AAC1C,oBAAoB;AACpB,cAAc,8BAA8B,CAAA;AAC5C,gBAAgB;AAChB,cAAc,uBAAuB,CAAA;AACrC,cAAc,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAA;AACjC,6BAA6B;AAC7B,cAAc,sBAAsB,CAAA;AACpC,cAAc,sBAAsB,CAAA;AACpC,cAAc,sBAAsB,CAAA;AACpC,cAAc,oBAAoB,CAAA;AAClC,cAAc,2BAA2B,CAAA;AACzC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,qBAAqB,CAAA;AACnC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,+BAA+B,CAAA;AAC7C,+BAA+B;AAC/B,cAAc,4BAA4B,CAAA;AAC1C,oBAAoB;AACpB,cAAc,8BAA8B,CAAA;AAC5C,gBAAgB;AAChB,cAAc,uBAAuB,CAAA;AACrC,cAAc,mBAAmB,CAAA"}
@@ -0,0 +1,80 @@
1
+ import type { z } from 'zod/v4';
2
+ import type { InferSchemaInput, InferSchemaOutput } from '../apiContracts.ts';
3
+ import type { HttpStatusCode, SuccessfulHttpStatusCode } from '../HttpStatusCodes.ts';
4
+ import type { Prettify } from '../typeUtils.ts';
5
+ import type { ContractNoBody } from './constants.ts';
6
+ import type { ResponsesByStatusCode, SseSchemaByEventName } from './contractResponse.ts';
7
+ import type { ApiContract } from './defineApiContract.ts';
8
+ import type { ContractResponseMode, SseEventOf } from './inferTypes.ts';
9
+ export type HeadersParam<T> = T | (() => T) | (() => Promise<T>);
10
+ type ExtractRequestBody<T> = T extends {
11
+ requestBodySchema: z.ZodType;
12
+ } ? T['requestBodySchema'] : undefined;
13
+ type StreamingParam<T extends ResponsesByStatusCode, TIsStreaming extends boolean> = ContractResponseMode<T> extends 'dual' ? {
14
+ streaming: TIsStreaming;
15
+ } : {
16
+ streaming?: never;
17
+ };
18
+ export type DefaultStreaming<T extends ResponsesByStatusCode> = ContractResponseMode<T> extends 'sse' ? true : false;
19
+ type RequiredWhenDefined<T, TKey extends string, TExtra = T> = [T] extends [undefined] ? {
20
+ [K in TKey]?: undefined;
21
+ } : {
22
+ [K in TKey]: TExtra;
23
+ };
24
+ export type ClientRequestParams<TApiContract extends ApiContract, TIsStreaming extends boolean> = Prettify<StreamingParam<TApiContract['responsesByStatusCode'], TIsStreaming> & RequiredWhenDefined<InferSchemaInput<TApiContract['requestPathParamsSchema']>, 'pathParams'> & RequiredWhenDefined<InferSchemaInput<ExtractRequestBody<TApiContract>>, 'body'> & RequiredWhenDefined<InferSchemaInput<TApiContract['requestQuerySchema']>, 'queryParams'> & RequiredWhenDefined<InferSchemaInput<TApiContract['requestHeaderSchema']>, 'headers', HeadersParam<InferSchemaInput<TApiContract['requestHeaderSchema']>>> & {
25
+ pathPrefix?: string;
26
+ }>;
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
+ /**
29
+ * Maps a single responsesByStatusCode entry value to its TypeScript body type.
30
+ */
31
+ type InferClientResponseBody<T> = T extends typeof ContractNoBody ? null : T extends z.ZodType ? InferSchemaOutput<T> : T extends {
32
+ _tag: 'TextResponse';
33
+ } ? string : T extends {
34
+ _tag: 'BlobResponse';
35
+ } ? Blob : T extends {
36
+ _tag: 'SseResponse';
37
+ schemaByEventName: infer S extends SseSchemaByEventName;
38
+ } ? AsyncIterable<SseEventOf<S>> : T extends {
39
+ _tag: 'AnyOfResponses';
40
+ responses: Array<infer Item>;
41
+ } ? InferClientResponseBody<Item> : never;
42
+ /**
43
+ * Like InferClientResponseBody but returns only SSE bodies — non-SSE entries resolve to never.
44
+ */
45
+ type SseInferClientResponseBody<T> = Extract<InferClientResponseBody<T>, AsyncIterable<unknown>>;
46
+ /**
47
+ * Like InferClientResponseBody but returns only non-SSE bodies — SSE entries resolve to never.
48
+ */
49
+ type NonSseInferClientResponseBody<T> = Exclude<InferClientResponseBody<T>, AsyncIterable<unknown>>;
50
+ /**
51
+ * 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)
54
+ *
55
+ * Headers are typed via `InferClientResponseHeaders`: known headers from `responseHeaderSchema`
56
+ * are strongly typed; all other headers remain accessible as `string | undefined`.
57
+ */
58
+ export type InferSseClientResponse<TApiContract extends ApiContract> = {
59
+ [K in keyof TApiContract['responsesByStatusCode'] & HttpStatusCode]: {
60
+ statusCode: K;
61
+ headers: InferClientResponseHeaders<TApiContract>;
62
+ body: K extends SuccessfulHttpStatusCode ? SseInferClientResponseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>> : InferClientResponseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>>;
63
+ };
64
+ }[keyof TApiContract['responsesByStatusCode'] & HttpStatusCode];
65
+ /**
66
+ * 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)
69
+ *
70
+ * Headers are typed via `InferClientResponseHeaders`: known headers from `responseHeaderSchema`
71
+ * are strongly typed; all other headers remain accessible as `string | undefined`.
72
+ */
73
+ export type InferNonSseClientResponse<TApiContract extends ApiContract> = {
74
+ [K in keyof TApiContract['responsesByStatusCode'] & HttpStatusCode]: {
75
+ statusCode: K;
76
+ headers: InferClientResponseHeaders<TApiContract>;
77
+ body: K extends SuccessfulHttpStatusCode ? NonSseInferClientResponseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>> : InferClientResponseBody<NonNullable<TApiContract['responsesByStatusCode'][K]>>;
78
+ };
79
+ }[keyof TApiContract['responsesByStatusCode'] & HttpStatusCode];
80
+ export {};
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=clientTypes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientTypes.js","sourceRoot":"","sources":["../../src/new/clientTypes.ts"],"names":[],"mappings":""}
@@ -43,4 +43,25 @@ export type ResponseKind = {
43
43
  kind: 'sse';
44
44
  schemaByEventName: SseSchemaByEventName;
45
45
  };
46
- export declare const resolveContractResponse: (schemaEntry: ApiContractResponse, contentType: string | undefined) => ResponseKind | null;
46
+ /**
47
+ * Resolves a contract's response entry for a given status code into a concrete `ResponseKind`,
48
+ * taking the response `content-type` into account.
49
+ *
50
+ * Returns `null` when the content-type cannot be matched to any entry in the contract,
51
+ * indicating the response is unexpected and should be treated as an error by the caller.
52
+ *
53
+ * @param schemaEntry - The contract entry for the matched status code (`ContractNoBody`,
54
+ * a Zod schema, `textResponse`, `blobResponse`, `sseResponse`, or `anyOfResponses`).
55
+ * @param contentType - The `content-type` header value from the actual HTTP response,
56
+ * or `undefined` when the header is absent.
57
+ * @param strict - When `true` (default), returns `null` if the `content-type` is absent or does
58
+ * not match the contract entry. When `false`, falls back to the entry's declared kind instead of
59
+ * returning `null` — only applies to single-entry responses; `anyOfResponses` always requires a
60
+ * content-type to disambiguate regardless of this flag.
61
+ */
62
+ export declare const resolveContractResponse: (schemaEntry: ApiContractResponse, contentType: string | undefined, strict?: boolean) => ResponseKind | null;
63
+ /**
64
+ * Combines status-code lookup and content-type resolution into a single call.
65
+ * Returns `null` when the status code is not in the contract or the content-type cannot be matched.
66
+ */
67
+ export declare function resolveResponseEntry(responsesByStatusCode: ResponsesByStatusCode, statusCode: number, contentType: string | undefined, strictContentType: boolean): ResponseKind | null;
@@ -36,14 +36,43 @@ const matchTypedResponse = (entry, contentType) => {
36
36
  }
37
37
  return null;
38
38
  };
39
- export const resolveContractResponse = (schemaEntry, contentType) => {
39
+ const resolveByKind = (entry) => {
40
+ if (isTextResponse(entry)) {
41
+ return { kind: 'text' };
42
+ }
43
+ if (isBlobResponse(entry)) {
44
+ return { kind: 'blob' };
45
+ }
46
+ if (isSseResponse(entry)) {
47
+ return { kind: 'sse', schemaByEventName: entry.schemaByEventName };
48
+ }
49
+ return { kind: 'json', schema: entry };
50
+ };
51
+ /**
52
+ * Resolves a contract's response entry for a given status code into a concrete `ResponseKind`,
53
+ * taking the response `content-type` into account.
54
+ *
55
+ * Returns `null` when the content-type cannot be matched to any entry in the contract,
56
+ * indicating the response is unexpected and should be treated as an error by the caller.
57
+ *
58
+ * @param schemaEntry - The contract entry for the matched status code (`ContractNoBody`,
59
+ * a Zod schema, `textResponse`, `blobResponse`, `sseResponse`, or `anyOfResponses`).
60
+ * @param contentType - The `content-type` header value from the actual HTTP response,
61
+ * or `undefined` when the header is absent.
62
+ * @param strict - When `true` (default), returns `null` if the `content-type` is absent or does
63
+ * not match the contract entry. When `false`, falls back to the entry's declared kind instead of
64
+ * returning `null` — only applies to single-entry responses; `anyOfResponses` always requires a
65
+ * content-type to disambiguate regardless of this flag.
66
+ */
67
+ export const resolveContractResponse = (schemaEntry, contentType, strict = true) => {
40
68
  if (schemaEntry === ContractNoBody) {
41
69
  return { kind: 'noContent' };
42
70
  }
43
- if (!contentType) {
44
- return null;
45
- }
46
71
  if (isAnyOfResponses(schemaEntry)) {
72
+ // AnyOfResponses always requires content-type to disambiguate — strict mode has no effect here
73
+ if (!contentType) {
74
+ return null;
75
+ }
47
76
  for (const item of schemaEntry.responses) {
48
77
  const resolved = matchTypedResponse(item, contentType);
49
78
  if (resolved) {
@@ -52,6 +81,21 @@ export const resolveContractResponse = (schemaEntry, contentType) => {
52
81
  }
53
82
  return null;
54
83
  }
55
- return matchTypedResponse(schemaEntry, contentType);
84
+ if (!contentType) {
85
+ return strict ? null : resolveByKind(schemaEntry);
86
+ }
87
+ const matched = matchTypedResponse(schemaEntry, contentType);
88
+ return matched ?? (strict ? null : resolveByKind(schemaEntry));
56
89
  };
90
+ /**
91
+ * Combines status-code lookup and content-type resolution into a single call.
92
+ * Returns `null` when the status code is not in the contract or the content-type cannot be matched.
93
+ */
94
+ export function resolveResponseEntry(responsesByStatusCode, statusCode, contentType, strictContentType) {
95
+ const schemaEntry = responsesByStatusCode[statusCode];
96
+ if (!schemaEntry) {
97
+ return null;
98
+ }
99
+ return resolveContractResponse(schemaEntry, contentType, strictContentType);
100
+ }
57
101
  //# 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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"}
@@ -4,12 +4,15 @@ import type { 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;
7
+ export type RequestQuerySchema = z.ZodObject;
8
+ export type RequestHeaderSchema = z.ZodObject;
9
+ export type ResponseHeaderSchema = z.ZodObject;
7
10
  export type CommonApiContract = {
8
11
  pathResolver: RoutePathResolver<any>;
9
12
  requestPathParamsSchema?: RequestPathParamsSchema;
10
- requestQuerySchema?: z.ZodType;
11
- requestHeaderSchema?: z.ZodType;
12
- responseHeaderSchema?: z.ZodType;
13
+ requestQuerySchema?: RequestQuerySchema;
14
+ requestHeaderSchema?: RequestHeaderSchema;
15
+ responseHeaderSchema?: ResponseHeaderSchema;
13
16
  responsesByStatusCode: ResponsesByStatusCode;
14
17
  metadata?: CommonRouteDefinitionMetadata;
15
18
  summary?: string;
@@ -39,6 +42,7 @@ export declare const defineApiContract: <PathParamsSchema extends RequestPathPar
39
42
  export declare const mapApiContractToPath: (routeConfig: ApiContract) => string;
40
43
  export declare const describeApiContract: (routeConfig: ApiContract) => string;
41
44
  export declare const getSseSchemaByEventName: (routeConfig: ApiContract) => SseSchemaByEventName | null;
45
+ export declare const hasAnySuccessSseResponse: (apiContract: ApiContract) => boolean;
42
46
  export declare const getSuccessResponseSchema: (routeConfig: ApiContract) => z.ZodType | null;
43
47
  export declare const getIsEmptyResponseExpected: (routeConfig: ApiContract) => boolean;
44
48
  export {};
@@ -32,6 +32,25 @@ export const getSseSchemaByEventName = (routeConfig) => {
32
32
  }
33
33
  return Object.keys(result).length > 0 ? result : null;
34
34
  };
35
+ export const hasAnySuccessSseResponse = (apiContract) => {
36
+ for (const code of SUCCESSFUL_HTTP_STATUS_CODES) {
37
+ const value = apiContract.responsesByStatusCode[code];
38
+ if (!value) {
39
+ continue;
40
+ }
41
+ if (isSseResponse(value)) {
42
+ return true;
43
+ }
44
+ else if (isAnyOfResponses(value)) {
45
+ for (const response of value.responses) {
46
+ if (isSseResponse(response)) {
47
+ return true;
48
+ }
49
+ }
50
+ }
51
+ }
52
+ return false;
53
+ };
35
54
  // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: it is acceptable
36
55
  export const getSuccessResponseSchema = (routeConfig) => {
37
56
  const schemas = [];
@@ -61,8 +80,9 @@ export const getSuccessResponseSchema = (routeConfig) => {
61
80
  if (schemas.length > 1) {
62
81
  return z.union(schemas);
63
82
  }
64
- if (schemas.length === 1) {
65
- return schemas[0];
83
+ const firstSchema = schemas.at(0);
84
+ if (firstSchema) {
85
+ return firstSchema;
66
86
  }
67
87
  return hasDirectNonJsonEntry ? z.never() : null;
68
88
  };
@@ -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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"}
@@ -1,6 +1,6 @@
1
1
  import type { z } from 'zod/v4';
2
2
  import type { SuccessfulHttpStatusCode } from '../HttpStatusCodes.ts';
3
- import type { IsUnion, ValueOf } from '../typeUtils.ts';
3
+ import type { ValueOf } from '../typeUtils.ts';
4
4
  import type { ContractNoBody } from './constants.ts';
5
5
  import type { ResponsesByStatusCode } from './contractResponse.ts';
6
6
  type ExtractSuccessResponses<T extends ResponsesByStatusCode> = ValueOf<T, Extract<keyof T, SuccessfulHttpStatusCode>>;
@@ -15,13 +15,6 @@ type UnpackAnyOf<T> = T extends {
15
15
  responses: Array<infer Item>;
16
16
  } ? Item : T;
17
17
  type FlatSuccessResponses<T extends ResponsesByStatusCode> = UnpackAnyOf<ExtractSuccessResponses<T>>;
18
- /**
19
- * Returns true if any success status code entry is TypedSseResponse,
20
- * or an AnyOfResponses containing a TypedSseResponse.
21
- */
22
- export type HasAnySseSuccessResponse<T extends ResponsesByStatusCode> = Extract<FlatSuccessResponses<T>, {
23
- _tag: 'SseResponse';
24
- }> extends never ? false : true;
25
18
  type SseSchemaOf<T> = T extends {
26
19
  _tag: 'SseResponse';
27
20
  schemaByEventName: infer S;
@@ -59,18 +52,37 @@ type NonSseBodyOf<T> = T extends {
59
52
  export type InferNonSseSuccessResponses<T extends ResponsesByStatusCode> = NonSseBodyOf<FlatSuccessResponses<T>>;
60
53
  /**
61
54
  * Discriminated union of SSE events inferred from a schemaByEventName map.
62
- * Each event is `{ event: EventName, data: z.output<Schema> }`.
55
+ * Aligns with the browser MessageEvent shape.
63
56
  */
64
57
  export type SseEventOf<S> = {
65
58
  [K in keyof S]: K extends string ? {
66
- event: K;
59
+ type: K;
67
60
  data: S[K] extends z.ZodType ? z.output<S[K]> : never;
61
+ lastEventId: string;
62
+ retry: number | undefined;
68
63
  } : never;
69
64
  }[keyof S];
70
65
  /**
71
- * True when the contract has both SSE and non-SSE success responses (dual-mode).
66
+ * Returns true if any success status code entry is TypedSseResponse,
67
+ * or an AnyOfResponses containing a TypedSseResponse.
68
+ */
69
+ export type HasAnySseSuccessResponse<T extends ResponsesByStatusCode> = Extract<FlatSuccessResponses<T>, {
70
+ _tag: 'SseResponse';
71
+ }> extends never ? false : true;
72
+ /**
73
+ * Returns true if any success status code entry has a non-SSE response
74
+ * (JSON, text, blob, or no-body). Mirrors HasAnySseSuccessResponse.
75
+ */
76
+ export type HasAnyNonSseSuccessResponse<T extends ResponsesByStatusCode> = Exclude<FlatSuccessResponses<T>, {
77
+ _tag: 'SseResponse';
78
+ }> extends never ? false : true;
79
+ /**
80
+ * Classifies a contract's response mode into one of three cases:
81
+ * - 'dual' — SSE + non-SSE success responses; caller chooses via streaming param
82
+ * - 'sse' — SSE-only success responses; always streams
83
+ * - 'non-sse' — JSON / text / blob / no-body; never streams
72
84
  */
73
- export type IsDualModeSse<T extends ResponsesByStatusCode> = HasAnySseSuccessResponse<T> extends true ? IsUnion<AvailableResponseModes<T>> extends true ? true : false : false;
85
+ export type ContractResponseMode<T extends ResponsesByStatusCode> = HasAnySseSuccessResponse<T> extends true ? HasAnyNonSseSuccessResponse<T> extends true ? 'dual' : 'sse' : 'non-sse';
74
86
  /**
75
87
  * Union of response mode literals available for a given responsesByStatusCode map.
76
88
  */
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Flattens an intersection type into a single object type, making hover tooltips
3
+ * show the fully-resolved shape instead of `A & B & C`.
4
+ */
5
+ export type Prettify<T> = {
6
+ [K in keyof T]: T[K];
7
+ } & {};
1
8
  /**
2
9
  * Returns true when T is a union with more than one member.
3
10
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lokalise/api-contracts",
3
- "version": "6.8.0",
3
+ "version": "6.9.0",
4
4
  "files": [
5
5
  "dist"
6
6
  ],