@lokalise/api-contracts 6.4.0 → 6.5.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/dist/contractBuilder.d.ts +16 -14
- package/dist/contractBuilder.js +1 -1
- package/dist/contractBuilder.js.map +1 -1
- package/dist/rest/restContractBuilder.d.ts +9 -7
- package/dist/rest/restContractBuilder.js +1 -1
- package/dist/rest/restContractBuilder.js.map +1 -1
- package/dist/sse/dualModeContracts.d.ts +20 -20
- package/dist/sse/sseContractBuilders.d.ts +46 -44
- package/dist/sse/sseContractBuilders.js +31 -30
- package/dist/sse/sseContractBuilders.js.map +1 -1
- package/dist/sse/sseContracts.d.ts +14 -14
- package/dist/sse/sseTypes.d.ts +4 -4
- package/package.json +1 -1
|
@@ -10,13 +10,13 @@ import type { SSEEventSchemas } from './sse/sseTypes.ts';
|
|
|
10
10
|
* Universal contract builder that creates either REST or SSE contracts based on configuration.
|
|
11
11
|
*
|
|
12
12
|
* This is a unified entry point that delegates to:
|
|
13
|
-
* - `buildRestContract` when no `
|
|
14
|
-
* - `buildSseContract` when `
|
|
13
|
+
* - `buildRestContract` when no `serverSentEventSchemas` is provided
|
|
14
|
+
* - `buildSseContract` when `serverSentEventSchemas` is provided
|
|
15
15
|
*
|
|
16
16
|
* ## Contract Type Detection
|
|
17
17
|
*
|
|
18
|
-
* | `
|
|
19
|
-
*
|
|
18
|
+
* | `serverSentEventSchemas` | `successResponseBodySchema` | `requestBodySchema` | Result |
|
|
19
|
+
* |--------------------|----------------------------|---------------------|--------|
|
|
20
20
|
* | ❌ | - | ❌ | REST GET |
|
|
21
21
|
* | ❌ | - | ✅ (method: post/put/patch) | REST Payload |
|
|
22
22
|
* | ❌ | - | ❌ (method: delete) | REST DELETE |
|
|
@@ -29,6 +29,7 @@ import type { SSEEventSchemas } from './sse/sseTypes.ts';
|
|
|
29
29
|
* ```typescript
|
|
30
30
|
* // REST GET route
|
|
31
31
|
* const getUsers = buildContract({
|
|
32
|
+
* method: 'get',
|
|
32
33
|
* successResponseBodySchema: z.array(userSchema),
|
|
33
34
|
* pathResolver: () => '/api/users',
|
|
34
35
|
* })
|
|
@@ -50,11 +51,12 @@ import type { SSEEventSchemas } from './sse/sseTypes.ts';
|
|
|
50
51
|
*
|
|
51
52
|
* // SSE-only streaming endpoint
|
|
52
53
|
* const notifications = buildContract({
|
|
54
|
+
* method: 'get',
|
|
53
55
|
* pathResolver: () => '/api/notifications/stream',
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
56
|
+
* requestPathParamsSchema: z.object({}),
|
|
57
|
+
* requestQuerySchema: z.object({}),
|
|
58
|
+
* requestHeaderSchema: z.object({}),
|
|
59
|
+
* serverSentEventSchemas: {
|
|
58
60
|
* notification: z.object({ id: z.string(), message: z.string() }),
|
|
59
61
|
* },
|
|
60
62
|
* })
|
|
@@ -63,12 +65,12 @@ import type { SSEEventSchemas } from './sse/sseTypes.ts';
|
|
|
63
65
|
* const chatCompletion = buildContract({
|
|
64
66
|
* method: 'post',
|
|
65
67
|
* pathResolver: () => '/api/chat/completions',
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
68
|
+
* requestPathParamsSchema: z.object({}),
|
|
69
|
+
* requestQuerySchema: z.object({}),
|
|
70
|
+
* requestHeaderSchema: z.object({}),
|
|
71
|
+
* requestBodySchema: z.object({ message: z.string() }),
|
|
72
|
+
* successResponseBodySchema: z.object({ reply: z.string() }),
|
|
73
|
+
* serverSentEventSchemas: {
|
|
72
74
|
* chunk: z.object({ delta: z.string() }),
|
|
73
75
|
* done: z.object({ usage: z.object({ tokens: z.number() }) }),
|
|
74
76
|
* },
|
package/dist/contractBuilder.js
CHANGED
|
@@ -6,7 +6,7 @@ import { buildSseContract, } from "./sse/sseContractBuilders.js";
|
|
|
6
6
|
export function buildContract(
|
|
7
7
|
// biome-ignore lint/suspicious/noExplicitAny: Union of all config types
|
|
8
8
|
config) {
|
|
9
|
-
const hasSseEvents = '
|
|
9
|
+
const hasSseEvents = 'serverSentEventSchemas' in config && config.serverSentEventSchemas !== undefined;
|
|
10
10
|
if (hasSseEvents) {
|
|
11
11
|
// Delegate to SSE contract builder
|
|
12
12
|
return buildSseContract(config);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contractBuilder.js","sourceRoot":"","sources":["../src/contractBuilder.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,iBAAiB,GAIlB,MAAM,+BAA+B,CAAA;AAEtC,OAAO,EACL,gBAAgB,GAKjB,MAAM,8BAA8B,CAAA;
|
|
1
|
+
{"version":3,"file":"contractBuilder.js","sourceRoot":"","sources":["../src/contractBuilder.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,iBAAiB,GAIlB,MAAM,+BAA+B,CAAA;AAEtC,OAAO,EACL,gBAAgB,GAKjB,MAAM,8BAA8B,CAAA;AAuTrC,+EAA+E;AAC/E,iBAAiB;AACjB,+EAA+E;AAE/E,MAAM,UAAU,aAAa;AAC3B,wEAAwE;AACxE,MAAW;IAGX,MAAM,YAAY,GAChB,wBAAwB,IAAI,MAAM,IAAI,MAAM,CAAC,sBAAsB,KAAK,SAAS,CAAA;IAEnF,IAAI,YAAY,EAAE,CAAC;QACjB,mCAAmC;QACnC,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAA;IACjC,CAAC;IAED,oCAAoC;IACpC,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAA;AAClC,CAAC"}
|
|
@@ -3,13 +3,13 @@ import type { CommonRouteDefinition, DeleteRouteDefinition, GetRouteDefinition,
|
|
|
3
3
|
import type { HttpStatusCode } from '../HttpStatusCodes.ts';
|
|
4
4
|
/**
|
|
5
5
|
* Configuration for building a GET route.
|
|
6
|
-
* GET routes have no request body and
|
|
6
|
+
* GET routes have no request body and require method: 'get'.
|
|
7
7
|
*/
|
|
8
8
|
export type GetContractConfig<SuccessResponseBodySchema extends z.Schema | undefined = undefined, PathParamsSchema extends z.Schema | undefined = undefined, RequestQuerySchema extends z.Schema | undefined = undefined, RequestHeaderSchema extends z.Schema | undefined = undefined, ResponseHeaderSchema extends z.Schema | undefined = undefined, IsNonJSONResponseExpected extends boolean = false, IsEmptyResponseExpected extends boolean = false, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.Schema>> | undefined = undefined> = Omit<CommonRouteDefinition<SuccessResponseBodySchema, PathParamsSchema, RequestQuerySchema, RequestHeaderSchema, ResponseHeaderSchema, IsNonJSONResponseExpected, IsEmptyResponseExpected, ResponseSchemasByStatusCode>, 'method'> & {
|
|
9
|
-
method
|
|
9
|
+
method: 'get';
|
|
10
10
|
requestBodySchema?: never;
|
|
11
11
|
/** Discriminator to distinguish from SSE contracts in buildContract */
|
|
12
|
-
|
|
12
|
+
serverSentEventSchemas?: never;
|
|
13
13
|
};
|
|
14
14
|
/**
|
|
15
15
|
* Configuration for building a DELETE route.
|
|
@@ -19,7 +19,7 @@ export type DeleteContractConfig<SuccessResponseBodySchema extends z.Schema | un
|
|
|
19
19
|
method: 'delete';
|
|
20
20
|
requestBodySchema?: never;
|
|
21
21
|
/** Discriminator to distinguish from SSE contracts in buildContract */
|
|
22
|
-
|
|
22
|
+
serverSentEventSchemas?: never;
|
|
23
23
|
};
|
|
24
24
|
/**
|
|
25
25
|
* Configuration for building a payload route (POST, PUT, PATCH).
|
|
@@ -29,7 +29,7 @@ export type PayloadContractConfig<RequestBodySchema extends z.Schema | undefined
|
|
|
29
29
|
method: 'post' | 'put' | 'patch';
|
|
30
30
|
requestBodySchema: RequestBodySchema;
|
|
31
31
|
/** Discriminator to distinguish from SSE contracts in buildContract */
|
|
32
|
-
|
|
32
|
+
serverSentEventSchemas?: never;
|
|
33
33
|
};
|
|
34
34
|
/**
|
|
35
35
|
* Builds REST API contracts with automatic type inference.
|
|
@@ -41,20 +41,22 @@ export type PayloadContractConfig<RequestBodySchema extends z.Schema | undefined
|
|
|
41
41
|
*
|
|
42
42
|
* | `method` | `requestBodySchema` | Result |
|
|
43
43
|
* |----------|---------------------|--------|
|
|
44
|
-
* |
|
|
44
|
+
* | `'get'` | ❌ | GET route |
|
|
45
45
|
* | `'delete'` | ❌ | DELETE route |
|
|
46
46
|
* | `'post'`/`'put'`/`'patch'` | ✅ | Payload route |
|
|
47
47
|
*
|
|
48
48
|
* @example
|
|
49
49
|
* ```typescript
|
|
50
|
-
* // GET route - method is
|
|
50
|
+
* // GET route - method: 'get' is required
|
|
51
51
|
* const getUsers = buildRestContract({
|
|
52
|
+
* method: 'get',
|
|
52
53
|
* pathResolver: () => '/api/users',
|
|
53
54
|
* successResponseBodySchema: z.array(userSchema),
|
|
54
55
|
* })
|
|
55
56
|
*
|
|
56
57
|
* // GET route with path params
|
|
57
58
|
* const getUser = buildRestContract({
|
|
59
|
+
* method: 'get',
|
|
58
60
|
* pathResolver: (params) => `/api/users/${params.userId}`,
|
|
59
61
|
* requestPathParamsSchema: z.object({ userId: z.string() }),
|
|
60
62
|
* successResponseBodySchema: userSchema,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"restContractBuilder.js","sourceRoot":"","sources":["../../src/rest/restContractBuilder.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"restContractBuilder.js","sourceRoot":"","sources":["../../src/rest/restContractBuilder.ts"],"names":[],"mappings":"AAiSA,iBAAiB;AACjB,MAAM,UAAU,iBAAiB,CAC/B,MAKsE;IAGtE,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAA;IAC5B,MAAM,OAAO,GAAG,mBAAmB,IAAI,MAAM,IAAI,MAAM,CAAC,iBAAiB,KAAK,SAAS,CAAA;IAEvF,oEAAoE;IACpE,MAAM,aAAa,GAAG,MAAM,KAAK,QAAQ,CAAA;IACzC,MAAM,8BAA8B,GAAG,aAAa,CAAA;IAEpD,MAAM,UAAU,GAAG;QACjB,uBAAuB,EAAE,MAAM,CAAC,uBAAuB,IAAI,8BAA8B;QACzF,yBAAyB,EAAE,MAAM,CAAC,yBAAyB,IAAI,KAAK;QACpE,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,mBAAmB,EAAE,MAAM,CAAC,mBAAmB;QAC/C,oBAAoB,EAAE,MAAM,CAAC,oBAAoB;QACjD,uBAAuB,EAAE,MAAM,CAAC,uBAAuB;QACvD,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;QAC7C,yBAAyB,EAAE,MAAM,CAAC,yBAAyB;QAC3D,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,2BAA2B,EAAE,MAAM,CAAC,2BAA2B;QAC/D,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,IAAI,EAAE,MAAM,CAAC,IAAI;KAClB,CAAA;IAED,IAAI,OAAO,EAAE,CAAC;QACZ,iCAAiC;QACjC,OAAO;YACL,GAAG,UAAU;YACb,MAAM,EAAE,MAAkC;YAC1C,qFAAqF;YACrF,iBAAiB,EAAG,MAAqC,CAAC,iBAAiB;SAC5E,CAAA;IACH,CAAC;IAED,IAAI,aAAa,EAAE,CAAC;QAClB,eAAe;QACf,OAAO;YACL,GAAG,UAAU;YACb,MAAM,EAAE,QAAiB;SAC1B,CAAA;IACH,CAAC;IAED,YAAY;IACZ,OAAO;QACL,GAAG,UAAU;QACb,MAAM,EAAE,KAAc;KACvB,CAAA;AACH,CAAC"}
|
|
@@ -5,13 +5,13 @@ import type { SSEMethod } from './sseContracts.ts';
|
|
|
5
5
|
import type { SSEEventSchemas } from './sseTypes.ts';
|
|
6
6
|
/**
|
|
7
7
|
* Definition for a dual-mode route.
|
|
8
|
-
* Use `
|
|
8
|
+
* Use `successResponseBodySchema` for the non-streaming response schema.
|
|
9
9
|
*
|
|
10
10
|
* @template Method - HTTP method (GET, POST, PUT, PATCH)
|
|
11
11
|
* @template Params - Path parameters schema
|
|
12
12
|
* @template Query - Query string parameters schema
|
|
13
13
|
* @template RequestHeaders - Request headers schema
|
|
14
|
-
* @template Body - Request
|
|
14
|
+
* @template Body - Request body schema (for POST/PUT/PATCH)
|
|
15
15
|
* @template SyncResponse - Sync response schema (for Accept: application/json)
|
|
16
16
|
* @template Events - SSE event schemas (for Accept: text/event-stream)
|
|
17
17
|
* @template ResponseHeaders - Response headers schema (for sync mode)
|
|
@@ -20,27 +20,27 @@ import type { SSEEventSchemas } from './sseTypes.ts';
|
|
|
20
20
|
export type DualModeContractDefinition<Method extends SSEMethod = SSEMethod, Params extends z.ZodTypeAny = z.ZodTypeAny, Query extends z.ZodTypeAny = z.ZodTypeAny, RequestHeaders extends z.ZodTypeAny = z.ZodTypeAny, Body extends z.ZodTypeAny | undefined = undefined, SyncResponse extends z.ZodTypeAny = z.ZodTypeAny, Events extends SSEEventSchemas = SSEEventSchemas, ResponseHeaders extends z.ZodTypeAny | undefined = undefined, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.ZodTypeAny>> | undefined = undefined> = {
|
|
21
21
|
method: Method;
|
|
22
22
|
pathResolver: RoutePathResolver<z.infer<Params>>;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
requestPathParamsSchema: Params;
|
|
24
|
+
requestQuerySchema: Query;
|
|
25
|
+
requestHeaderSchema: RequestHeaders;
|
|
26
|
+
requestBodySchema: Body;
|
|
27
27
|
/** Sync response schema - use with `sync` handler */
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
successResponseBodySchema: SyncResponse;
|
|
29
|
+
responseHeaderSchema?: ResponseHeaders;
|
|
30
30
|
/**
|
|
31
31
|
* Alternative response schemas by HTTP status code.
|
|
32
32
|
* Used to define different response shapes for error cases (e.g., 400, 404, 500).
|
|
33
33
|
*
|
|
34
34
|
* @example
|
|
35
35
|
* ```ts
|
|
36
|
-
*
|
|
36
|
+
* responseBodySchemasByStatusCode: {
|
|
37
37
|
* 400: z.object({ error: z.string(), details: z.array(z.string()) }),
|
|
38
38
|
* 404: z.object({ error: z.string() }),
|
|
39
39
|
* }
|
|
40
40
|
* ```
|
|
41
41
|
*/
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
responseBodySchemasByStatusCode?: ResponseSchemasByStatusCode;
|
|
43
|
+
serverSentEventSchemas: Events;
|
|
44
44
|
isDualMode: true;
|
|
45
45
|
};
|
|
46
46
|
/**
|
|
@@ -50,14 +50,14 @@ export type DualModeContractDefinition<Method extends SSEMethod = SSEMethod, Par
|
|
|
50
50
|
export type AnyDualModeContractDefinition = {
|
|
51
51
|
method: SSEMethod;
|
|
52
52
|
pathResolver: RoutePathResolver<any>;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
/** Sync response schema */
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
53
|
+
requestPathParamsSchema: z.ZodTypeAny;
|
|
54
|
+
requestQuerySchema: z.ZodTypeAny;
|
|
55
|
+
requestHeaderSchema: z.ZodTypeAny;
|
|
56
|
+
requestBodySchema: z.ZodTypeAny | undefined;
|
|
57
|
+
/** Sync response schema - use with `sync` handler */
|
|
58
|
+
successResponseBodySchema: z.ZodTypeAny;
|
|
59
|
+
responseHeaderSchema?: z.ZodTypeAny;
|
|
60
|
+
responseBodySchemasByStatusCode?: Partial<Record<HttpStatusCode, z.ZodTypeAny>>;
|
|
61
|
+
serverSentEventSchemas: SSEEventSchemas;
|
|
62
62
|
isDualMode: true;
|
|
63
63
|
};
|
|
@@ -6,14 +6,15 @@ import type { SSEContractDefinition } from './sseContracts.ts';
|
|
|
6
6
|
import type { SSEEventSchemas } from './sseTypes.ts';
|
|
7
7
|
/**
|
|
8
8
|
* Configuration for building a GET SSE route.
|
|
9
|
-
* Forbids
|
|
9
|
+
* Forbids requestBodySchema for GET variants.
|
|
10
10
|
*/
|
|
11
11
|
export type SSEGetContractConfig<Params extends z.ZodTypeAny, Query extends z.ZodTypeAny, RequestHeaders extends z.ZodTypeAny, Events extends SSEEventSchemas, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.ZodTypeAny>> | undefined = undefined> = {
|
|
12
|
+
method: 'get';
|
|
12
13
|
pathResolver: RoutePathResolver<z.infer<Params>>;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
requestPathParamsSchema: Params;
|
|
15
|
+
requestQuerySchema: Query;
|
|
16
|
+
requestHeaderSchema: RequestHeaders;
|
|
17
|
+
serverSentEventSchemas: Events;
|
|
17
18
|
/**
|
|
18
19
|
* Error response schemas by HTTP status code.
|
|
19
20
|
* Used to define response shapes for errors that occur before streaming starts
|
|
@@ -21,28 +22,28 @@ export type SSEGetContractConfig<Params extends z.ZodTypeAny, Query extends z.Zo
|
|
|
21
22
|
*
|
|
22
23
|
* @example
|
|
23
24
|
* ```ts
|
|
24
|
-
*
|
|
25
|
+
* responseBodySchemasByStatusCode: {
|
|
25
26
|
* 401: z.object({ error: z.literal('Unauthorized') }),
|
|
26
27
|
* 404: z.object({ error: z.string() }),
|
|
27
28
|
* }
|
|
28
29
|
* ```
|
|
29
30
|
*/
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
responseBodySchemasByStatusCode?: ResponseSchemasByStatusCode;
|
|
32
|
+
requestBodySchema?: never;
|
|
33
|
+
successResponseBodySchema?: never;
|
|
33
34
|
};
|
|
34
35
|
/**
|
|
35
|
-
* Configuration for building a POST/PUT/PATCH SSE route with request
|
|
36
|
-
* Requires
|
|
36
|
+
* Configuration for building a POST/PUT/PATCH SSE route with request body.
|
|
37
|
+
* Requires requestBodySchema for payload variants.
|
|
37
38
|
*/
|
|
38
39
|
export type SSEPayloadContractConfig<Params extends z.ZodTypeAny, Query extends z.ZodTypeAny, RequestHeaders extends z.ZodTypeAny, Body extends z.ZodTypeAny, Events extends SSEEventSchemas, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.ZodTypeAny>> | undefined = undefined> = {
|
|
39
|
-
method
|
|
40
|
+
method: 'post' | 'put' | 'patch';
|
|
40
41
|
pathResolver: RoutePathResolver<z.infer<Params>>;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
requestPathParamsSchema: Params;
|
|
43
|
+
requestQuerySchema: Query;
|
|
44
|
+
requestHeaderSchema: RequestHeaders;
|
|
45
|
+
requestBodySchema: Body;
|
|
46
|
+
serverSentEventSchemas: Events;
|
|
46
47
|
/**
|
|
47
48
|
* Error response schemas by HTTP status code.
|
|
48
49
|
* Used to define response shapes for errors that occur before streaming starts
|
|
@@ -50,95 +51,96 @@ export type SSEPayloadContractConfig<Params extends z.ZodTypeAny, Query extends
|
|
|
50
51
|
*
|
|
51
52
|
* @example
|
|
52
53
|
* ```ts
|
|
53
|
-
*
|
|
54
|
+
* responseBodySchemasByStatusCode: {
|
|
54
55
|
* 401: z.object({ error: z.literal('Unauthorized') }),
|
|
55
56
|
* 404: z.object({ error: z.string() }),
|
|
56
57
|
* }
|
|
57
58
|
* ```
|
|
58
59
|
*/
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
responseBodySchemasByStatusCode?: ResponseSchemasByStatusCode;
|
|
61
|
+
successResponseBodySchema?: never;
|
|
61
62
|
};
|
|
62
63
|
/**
|
|
63
64
|
* Configuration for building a GET dual-mode route.
|
|
64
|
-
* Requires
|
|
65
|
+
* Requires successResponseBodySchema, forbids requestBodySchema.
|
|
65
66
|
*/
|
|
66
67
|
export type DualModeGetContractConfig<Params extends z.ZodTypeAny, Query extends z.ZodTypeAny, RequestHeaders extends z.ZodTypeAny, JsonResponse extends z.ZodTypeAny, Events extends SSEEventSchemas, ResponseHeaders extends z.ZodTypeAny | undefined = undefined, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.ZodTypeAny>> | undefined = undefined> = {
|
|
68
|
+
method: 'get';
|
|
67
69
|
pathResolver: RoutePathResolver<z.infer<Params>>;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
requestPathParamsSchema: Params;
|
|
71
|
+
requestQuerySchema: Query;
|
|
72
|
+
requestHeaderSchema: RequestHeaders;
|
|
71
73
|
/** Single sync response schema */
|
|
72
|
-
|
|
74
|
+
successResponseBodySchema: JsonResponse;
|
|
73
75
|
/**
|
|
74
76
|
* Schema for validating response headers (sync mode only).
|
|
75
77
|
* Used to define and validate headers that the server will send in the response.
|
|
76
78
|
*
|
|
77
79
|
* @example
|
|
78
80
|
* ```ts
|
|
79
|
-
*
|
|
81
|
+
* responseHeaderSchema: z.object({
|
|
80
82
|
* 'x-ratelimit-limit': z.string(),
|
|
81
83
|
* 'x-ratelimit-remaining': z.string(),
|
|
82
84
|
* })
|
|
83
85
|
* ```
|
|
84
86
|
*/
|
|
85
|
-
|
|
87
|
+
responseHeaderSchema?: ResponseHeaders;
|
|
86
88
|
/**
|
|
87
89
|
* Alternative response schemas by HTTP status code.
|
|
88
90
|
* Used to define different response shapes for error cases.
|
|
89
91
|
*
|
|
90
92
|
* @example
|
|
91
93
|
* ```ts
|
|
92
|
-
*
|
|
94
|
+
* responseBodySchemasByStatusCode: {
|
|
93
95
|
* 400: z.object({ error: z.string(), details: z.array(z.string()) }),
|
|
94
96
|
* 404: z.object({ error: z.string() }),
|
|
95
97
|
* }
|
|
96
98
|
* ```
|
|
97
99
|
*/
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
100
|
+
responseBodySchemasByStatusCode?: ResponseSchemasByStatusCode;
|
|
101
|
+
serverSentEventSchemas: Events;
|
|
102
|
+
requestBodySchema?: never;
|
|
101
103
|
};
|
|
102
104
|
/**
|
|
103
|
-
* Configuration for building a POST/PUT/PATCH dual-mode route with request
|
|
104
|
-
* Requires both
|
|
105
|
+
* Configuration for building a POST/PUT/PATCH dual-mode route with request body.
|
|
106
|
+
* Requires both requestBodySchema and successResponseBodySchema.
|
|
105
107
|
*/
|
|
106
108
|
export type DualModePayloadContractConfig<Params extends z.ZodTypeAny, Query extends z.ZodTypeAny, RequestHeaders extends z.ZodTypeAny, Body extends z.ZodTypeAny, JsonResponse extends z.ZodTypeAny, Events extends SSEEventSchemas, ResponseHeaders extends z.ZodTypeAny | undefined = undefined, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.ZodTypeAny>> | undefined = undefined> = {
|
|
107
|
-
method
|
|
109
|
+
method: 'post' | 'put' | 'patch';
|
|
108
110
|
pathResolver: RoutePathResolver<z.infer<Params>>;
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
requestPathParamsSchema: Params;
|
|
112
|
+
requestQuerySchema: Query;
|
|
113
|
+
requestHeaderSchema: RequestHeaders;
|
|
114
|
+
requestBodySchema: Body;
|
|
113
115
|
/** Single sync response schema */
|
|
114
|
-
|
|
116
|
+
successResponseBodySchema: JsonResponse;
|
|
115
117
|
/**
|
|
116
118
|
* Schema for validating response headers (sync mode only).
|
|
117
119
|
* Used to define and validate headers that the server will send in the response.
|
|
118
120
|
*
|
|
119
121
|
* @example
|
|
120
122
|
* ```ts
|
|
121
|
-
*
|
|
123
|
+
* responseHeaderSchema: z.object({
|
|
122
124
|
* 'x-ratelimit-limit': z.string(),
|
|
123
125
|
* 'x-ratelimit-remaining': z.string(),
|
|
124
126
|
* })
|
|
125
127
|
* ```
|
|
126
128
|
*/
|
|
127
|
-
|
|
129
|
+
responseHeaderSchema?: ResponseHeaders;
|
|
128
130
|
/**
|
|
129
131
|
* Alternative response schemas by HTTP status code.
|
|
130
132
|
* Used to define different response shapes for error cases.
|
|
131
133
|
*
|
|
132
134
|
* @example
|
|
133
135
|
* ```ts
|
|
134
|
-
*
|
|
136
|
+
* responseBodySchemasByStatusCode: {
|
|
135
137
|
* 400: z.object({ error: z.string(), details: z.array(z.string()) }),
|
|
136
138
|
* 404: z.object({ error: z.string() }),
|
|
137
139
|
* }
|
|
138
140
|
* ```
|
|
139
141
|
*/
|
|
140
|
-
|
|
141
|
-
|
|
142
|
+
responseBodySchemasByStatusCode?: ResponseSchemasByStatusCode;
|
|
143
|
+
serverSentEventSchemas: Events;
|
|
142
144
|
};
|
|
143
145
|
export declare function buildSseContract<Params extends z.ZodTypeAny, Query extends z.ZodTypeAny, RequestHeaders extends z.ZodTypeAny, JsonResponse extends z.ZodTypeAny, Events extends SSEEventSchemas, ResponseHeaders extends z.ZodTypeAny | undefined = undefined, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.ZodTypeAny>> | undefined = undefined>(config: DualModeGetContractConfig<Params, Query, RequestHeaders, JsonResponse, Events, ResponseHeaders, ResponseSchemasByStatusCode>): DualModeContractDefinition<'get', Params, Query, RequestHeaders, undefined, JsonResponse, Events, ResponseHeaders, ResponseSchemasByStatusCode>;
|
|
144
146
|
export declare function buildSseContract<Params extends z.ZodTypeAny, Query extends z.ZodTypeAny, RequestHeaders extends z.ZodTypeAny, Events extends SSEEventSchemas, ResponseSchemasByStatusCode extends Partial<Record<HttpStatusCode, z.ZodTypeAny>> | undefined = undefined>(config: SSEGetContractConfig<Params, Query, RequestHeaders, Events, ResponseSchemasByStatusCode>): SSEContractDefinition<'get', Params, Query, RequestHeaders, undefined, Events, ResponseSchemasByStatusCode>;
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
* This is ideal for AI/LLM APIs (like OpenAI) where clients can choose between
|
|
13
13
|
* getting the full response at once or streaming it token-by-token.
|
|
14
14
|
*
|
|
15
|
-
* The contract type is automatically determined based on the presence of `
|
|
15
|
+
* The contract type is automatically determined based on the presence of `successResponseBodySchema`:
|
|
16
16
|
*
|
|
17
|
-
* | `
|
|
18
|
-
*
|
|
17
|
+
* | `successResponseBodySchema` | `requestBodySchema` | Result |
|
|
18
|
+
* |----------------------------|---------------------|--------|
|
|
19
19
|
* | ❌ | ❌ | SSE-only GET |
|
|
20
20
|
* | ❌ | ✅ | SSE-only POST/PUT/PATCH |
|
|
21
21
|
* | ✅ | ❌ | Dual-mode GET |
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
* // SSE-only: Pure streaming endpoint (e.g., live notifications)
|
|
27
27
|
* const notificationsStream = buildSseContract({
|
|
28
28
|
* pathResolver: () => '/api/notifications/stream',
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
29
|
+
* requestPathParamsSchema: z.object({}),
|
|
30
|
+
* requestQuerySchema: z.object({ userId: z.string().optional() }),
|
|
31
|
+
* requestHeaderSchema: z.object({}),
|
|
32
|
+
* serverSentEventSchemas: {
|
|
33
33
|
* notification: z.object({ id: z.string(), message: z.string() }),
|
|
34
34
|
* },
|
|
35
35
|
* })
|
|
@@ -40,12 +40,12 @@
|
|
|
40
40
|
* const chatCompletion = buildSseContract({
|
|
41
41
|
* method: 'POST',
|
|
42
42
|
* pathResolver: () => '/api/chat/completions',
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
43
|
+
* requestPathParamsSchema: z.object({}),
|
|
44
|
+
* requestQuerySchema: z.object({}),
|
|
45
|
+
* requestHeaderSchema: z.object({}),
|
|
46
|
+
* requestBodySchema: z.object({ message: z.string() }),
|
|
47
|
+
* successResponseBodySchema: z.object({ reply: z.string(), usage: z.object({ tokens: z.number() }) }),
|
|
48
|
+
* serverSentEventSchemas: {
|
|
49
49
|
* chunk: z.object({ delta: z.string() }),
|
|
50
50
|
* done: z.object({ usage: z.object({ total: z.number() }) }),
|
|
51
51
|
* },
|
|
@@ -57,40 +57,41 @@
|
|
|
57
57
|
function buildBaseFields(config, hasBody) {
|
|
58
58
|
return {
|
|
59
59
|
pathResolver: config.pathResolver,
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
requestPathParamsSchema: config.requestPathParamsSchema,
|
|
61
|
+
requestQuerySchema: config.requestQuerySchema,
|
|
62
|
+
requestHeaderSchema: config.requestHeaderSchema,
|
|
63
|
+
requestBodySchema: hasBody ? config.requestBodySchema : undefined,
|
|
64
|
+
serverSentEventSchemas: config.serverSentEventSchemas,
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
67
|
// Helper to determine method
|
|
68
|
-
function determineMethod(config
|
|
69
|
-
return
|
|
68
|
+
function determineMethod(config) {
|
|
69
|
+
return config.method;
|
|
70
70
|
}
|
|
71
71
|
// Implementation
|
|
72
72
|
export function buildSseContract(config) {
|
|
73
|
-
const hasSyncResponseBody = '
|
|
74
|
-
const hasBody = '
|
|
73
|
+
const hasSyncResponseBody = 'successResponseBodySchema' in config && config.successResponseBodySchema !== undefined;
|
|
74
|
+
const hasBody = 'requestBodySchema' in config && config.requestBodySchema !== undefined;
|
|
75
75
|
const base = buildBaseFields(config, hasBody);
|
|
76
76
|
if (hasSyncResponseBody) {
|
|
77
77
|
// Dual-mode contract
|
|
78
78
|
return {
|
|
79
79
|
...base,
|
|
80
|
-
method: determineMethod(config
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
80
|
+
method: determineMethod(config),
|
|
81
|
+
successResponseBodySchema: config
|
|
82
|
+
.successResponseBodySchema,
|
|
83
|
+
responseHeaderSchema: config.responseHeaderSchema,
|
|
84
|
+
responseBodySchemasByStatusCode: config
|
|
85
|
+
.responseBodySchemasByStatusCode,
|
|
85
86
|
isDualMode: true,
|
|
86
87
|
};
|
|
87
88
|
}
|
|
88
89
|
// SSE-only contract
|
|
89
90
|
return {
|
|
90
91
|
...base,
|
|
91
|
-
method: determineMethod(config
|
|
92
|
-
|
|
93
|
-
.
|
|
92
|
+
method: determineMethod(config),
|
|
93
|
+
responseBodySchemasByStatusCode: config
|
|
94
|
+
.responseBodySchemasByStatusCode,
|
|
94
95
|
isSSE: true,
|
|
95
96
|
};
|
|
96
97
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sseContractBuilders.js","sourceRoot":"","sources":["../../src/sse/sseContractBuilders.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sseContractBuilders.js","sourceRoot":"","sources":["../../src/sse/sseContractBuilders.ts"],"names":[],"mappings":"AA2LA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAEH,uCAAuC;AACvC,gEAAgE;AAChE,SAAS,eAAe,CAAC,MAAW,EAAE,OAAgB;IACpD,OAAO;QACL,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,uBAAuB,EAAE,MAAM,CAAC,uBAAuB;QACvD,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;QAC7C,mBAAmB,EAAE,MAAM,CAAC,mBAAmB;QAC/C,iBAAiB,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,SAAS;QACjE,sBAAsB,EAAE,MAAM,CAAC,sBAAsB;KACtD,CAAA;AACH,CAAC;AAED,6BAA6B;AAC7B,SAAS,eAAe,CAAC,MAA0B;IACjD,OAAO,MAAM,CAAC,MAAM,CAAA;AACtB,CAAC;AAwHD,iBAAiB;AACjB,MAAM,UAAU,gBAAgB,CAC9B,MAOiD;IAGjD,MAAM,mBAAmB,GACvB,2BAA2B,IAAI,MAAM,IAAI,MAAM,CAAC,yBAAyB,KAAK,SAAS,CAAA;IACzF,MAAM,OAAO,GAAG,mBAAmB,IAAI,MAAM,IAAI,MAAM,CAAC,iBAAiB,KAAK,SAAS,CAAA;IACvF,MAAM,IAAI,GAAG,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAE7C,IAAI,mBAAmB,EAAE,CAAC;QACxB,qBAAqB;QACrB,OAAO;YACL,GAAG,IAAI;YACP,MAAM,EAAE,eAAe,CAAC,MAA4B,CAAC;YACrD,yBAAyB,EAAG,MAAiD;iBAC1E,yBAAyB;YAC5B,oBAAoB,EAAG,MAA6C,CAAC,oBAAoB;YACzF,+BAA+B,EAAG,MAAwD;iBACvF,+BAA+B;YAClC,UAAU,EAAE,IAAI;SACjB,CAAA;IACH,CAAC;IAED,oBAAoB;IACpB,OAAO;QACL,GAAG,IAAI;QACP,MAAM,EAAE,eAAe,CAAC,MAA4B,CAAC;QACrD,+BAA+B,EAAG,MAAwD;aACvF,+BAA+B;QAClC,KAAK,EAAE,IAAI;KACZ,CAAA;AACH,CAAC"}
|
|
@@ -15,7 +15,7 @@ export type SSEMethod = 'get' | 'post' | 'put' | 'patch';
|
|
|
15
15
|
* @template Params - Path parameters schema
|
|
16
16
|
* @template Query - Query string parameters schema
|
|
17
17
|
* @template RequestHeaders - Request headers schema
|
|
18
|
-
* @template Body - Request
|
|
18
|
+
* @template Body - Request body schema (for POST/PUT/PATCH)
|
|
19
19
|
* @template Events - Map of event name to event data schema
|
|
20
20
|
* @template ResponseSchemasByStatusCode - Error response schemas by HTTP status code
|
|
21
21
|
*/
|
|
@@ -26,11 +26,11 @@ export type SSEContractDefinition<Method extends SSEMethod = SSEMethod, Params e
|
|
|
26
26
|
* Receives typed params and returns the URL path string.
|
|
27
27
|
*/
|
|
28
28
|
pathResolver: RoutePathResolver<z.infer<Params>>;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
requestPathParamsSchema: Params;
|
|
30
|
+
requestQuerySchema: Query;
|
|
31
|
+
requestHeaderSchema: RequestHeaders;
|
|
32
|
+
requestBodySchema: Body;
|
|
33
|
+
serverSentEventSchemas: Events;
|
|
34
34
|
/**
|
|
35
35
|
* Error response schemas by HTTP status code.
|
|
36
36
|
* Used to define response shapes for errors that occur before streaming starts
|
|
@@ -38,13 +38,13 @@ export type SSEContractDefinition<Method extends SSEMethod = SSEMethod, Params e
|
|
|
38
38
|
*
|
|
39
39
|
* @example
|
|
40
40
|
* ```ts
|
|
41
|
-
*
|
|
41
|
+
* responseBodySchemasByStatusCode: {
|
|
42
42
|
* 401: z.object({ error: z.literal('Unauthorized') }),
|
|
43
43
|
* 404: z.object({ error: z.string() }),
|
|
44
44
|
* }
|
|
45
45
|
* ```
|
|
46
46
|
*/
|
|
47
|
-
|
|
47
|
+
responseBodySchemasByStatusCode?: ResponseSchemasByStatusCode;
|
|
48
48
|
isSSE: true;
|
|
49
49
|
};
|
|
50
50
|
/**
|
|
@@ -54,11 +54,11 @@ export type SSEContractDefinition<Method extends SSEMethod = SSEMethod, Params e
|
|
|
54
54
|
export type AnySSEContractDefinition = {
|
|
55
55
|
method: SSEMethod;
|
|
56
56
|
pathResolver: RoutePathResolver<any>;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
requestPathParamsSchema: z.ZodTypeAny;
|
|
58
|
+
requestQuerySchema: z.ZodTypeAny;
|
|
59
|
+
requestHeaderSchema: z.ZodTypeAny;
|
|
60
|
+
requestBodySchema: z.ZodTypeAny | undefined;
|
|
61
|
+
serverSentEventSchemas: SSEEventSchemas;
|
|
62
|
+
responseBodySchemasByStatusCode?: Partial<Record<HttpStatusCode, z.ZodTypeAny>>;
|
|
63
63
|
isSSE: true;
|
|
64
64
|
};
|
package/dist/sse/sseTypes.d.ts
CHANGED
|
@@ -11,19 +11,19 @@ export type SSEEventSchemas = Record<string, z.ZodTypeAny>;
|
|
|
11
11
|
* @example
|
|
12
12
|
* ```typescript
|
|
13
13
|
* type Contracts = {
|
|
14
|
-
* notifications: {
|
|
15
|
-
* chat: {
|
|
14
|
+
* notifications: { serverSentEventSchemas: { alert: z.ZodObject<...> } }
|
|
15
|
+
* chat: { serverSentEventSchemas: { message: z.ZodObject<...>, done: z.ZodObject<...> } }
|
|
16
16
|
* }
|
|
17
17
|
* // AllContractEventNames<Contracts> = 'alert' | 'message' | 'done'
|
|
18
18
|
* ```
|
|
19
19
|
*/
|
|
20
|
-
export type AllContractEventNames<Contracts extends Record<string, AnySSEContractDefinition>> = Contracts[keyof Contracts]['
|
|
20
|
+
export type AllContractEventNames<Contracts extends Record<string, AnySSEContractDefinition>> = Contracts[keyof Contracts]['serverSentEventSchemas'] extends infer E ? E extends SSEEventSchemas ? keyof E & string : never : never;
|
|
21
21
|
/**
|
|
22
22
|
* Extract the schema for a specific event name across all contracts.
|
|
23
23
|
* Returns the Zod schema for the event, or never if not found.
|
|
24
24
|
*/
|
|
25
25
|
export type ExtractEventSchema<Contracts extends Record<string, AnySSEContractDefinition>, EventName extends string> = {
|
|
26
|
-
[K in keyof Contracts]: EventName extends keyof Contracts[K]['
|
|
26
|
+
[K in keyof Contracts]: EventName extends keyof Contracts[K]['serverSentEventSchemas'] ? Contracts[K]['serverSentEventSchemas'][EventName] : never;
|
|
27
27
|
}[keyof Contracts];
|
|
28
28
|
/**
|
|
29
29
|
* Flatten all events from all contracts into a single record.
|