@ts-contract/plugins 1.0.0-alpha.0 → 1.0.0-alpha.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
@@ -1,7 +1,216 @@
1
- # utils
1
+ # @ts-contract/plugins
2
2
 
3
- This library was generated with [Nx](https://nx.dev).
3
+ Built-in plugins for path building and schema validation for ts-contract.
4
4
 
5
- ## Building
5
+ ## Overview
6
6
 
7
- Run `nx build utils` to build the library.
7
+ `@ts-contract/plugins` provides official plugins that extend ts-contract with commonly needed functionality:
8
+
9
+ - **Path Plugin** - Build URL paths with type-safe parameter substitution
10
+ - **Validate Plugin** - Validate request/response data against schemas
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install @ts-contract/plugins @ts-contract/core
16
+ # or
17
+ pnpm add @ts-contract/plugins @ts-contract/core
18
+ # or
19
+ yarn add @ts-contract/plugins @ts-contract/core
20
+ ```
21
+
22
+ ## Plugins
23
+
24
+ ### Path Plugin
25
+
26
+ Build type-safe URL paths with parameter substitution and query string generation.
27
+
28
+ #### Usage
29
+
30
+ ```typescript
31
+ import { initContract } from '@ts-contract/core';
32
+ import { pathPlugin } from '@ts-contract/plugins';
33
+ import { contract } from './contract';
34
+
35
+ const api = initContract(contract).use(pathPlugin).build();
36
+
37
+ // Build path with parameters
38
+ const path = api.getUser.buildPath({ id: '123' });
39
+ // => "/users/123"
40
+
41
+ // Build path with query parameters
42
+ const path = api.listUsers.buildPath(undefined, { page: '1', limit: '10' });
43
+ // => "/users?page=1&limit=10"
44
+
45
+ // Build path with both
46
+ const path = api.searchUsers.buildPath(
47
+ { category: 'active' },
48
+ { sort: 'name' },
49
+ );
50
+ // => "/users/active?sort=name"
51
+ ```
52
+
53
+ #### API
54
+
55
+ **`buildPath(params?, query?)`**
56
+
57
+ Builds a URL path from the route definition.
58
+
59
+ - **params** - Path parameters (typed from contract)
60
+ - **query** - Query parameters (typed from contract)
61
+ - **Returns:** String URL path
62
+
63
+ ### Validate Plugin
64
+
65
+ Validate request bodies and response data against your contract schemas.
66
+
67
+ #### Usage
68
+
69
+ ```typescript
70
+ import { initContract } from '@ts-contract/core';
71
+ import { validatePlugin } from '@ts-contract/plugins';
72
+ import { contract } from './contract';
73
+
74
+ const api = initContract(contract).use(validatePlugin).build();
75
+
76
+ // Validate request body
77
+ try {
78
+ const validatedBody = api.createUser.validateBody({
79
+ name: 'Alice',
80
+ email: 'alice@example.com',
81
+ });
82
+ // validatedBody is typed and validated
83
+ } catch (error) {
84
+ // Validation failed
85
+ }
86
+
87
+ // Validate response
88
+ try {
89
+ const validatedResponse = api.getUser.validateResponse(200, {
90
+ id: '123',
91
+ name: 'Alice',
92
+ email: 'alice@example.com',
93
+ });
94
+ // validatedResponse is typed and validated
95
+ } catch (error) {
96
+ // Validation failed
97
+ }
98
+
99
+ // Validate path parameters
100
+ const validatedParams = api.getUser.validatePathParams({ id: '123' });
101
+
102
+ // Validate query parameters
103
+ const validatedQuery = api.listUsers.validateQuery({ page: '1', limit: '10' });
104
+
105
+ // Validate headers
106
+ const validatedHeaders = api.getUser.validateHeaders({
107
+ authorization: 'Bearer token',
108
+ });
109
+ ```
110
+
111
+ #### API
112
+
113
+ **`validateBody(data)`**
114
+
115
+ Validates request body data against the route's body schema.
116
+
117
+ - **data** - Data to validate
118
+ - **Returns:** Validated and typed data
119
+ - **Throws:** Validation error if data is invalid
120
+
121
+ **`validateResponse(status, data)`**
122
+
123
+ Validates response data against the route's response schema for a specific status code.
124
+
125
+ - **status** - HTTP status code
126
+ - **data** - Data to validate
127
+ - **Returns:** Validated and typed data
128
+ - **Throws:** Validation error if data is invalid
129
+
130
+ **`validatePathParams(data)`**
131
+
132
+ Validates path parameters against the route's pathParams schema.
133
+
134
+ **`validateQuery(data)`**
135
+
136
+ Validates query parameters against the route's query schema.
137
+
138
+ **`validateHeaders(data)`**
139
+
140
+ Validates headers against the route's headers schema.
141
+
142
+ ## Using Both Plugins
143
+
144
+ Combine plugins for full functionality:
145
+
146
+ ```typescript
147
+ import { initContract } from '@ts-contract/core';
148
+ import { pathPlugin, validatePlugin } from '@ts-contract/plugins';
149
+
150
+ const api = initContract(contract).use(pathPlugin).use(validatePlugin).build();
151
+
152
+ // Use both plugin methods
153
+ const path = api.createUser.buildPath();
154
+ const validatedBody = api.createUser.validateBody({
155
+ name: 'Alice',
156
+ email: 'alice@example.com',
157
+ });
158
+
159
+ // Make request
160
+ const response = await fetch(path, {
161
+ method: 'POST',
162
+ headers: { 'Content-Type': 'application/json' },
163
+ body: JSON.stringify(validatedBody),
164
+ });
165
+
166
+ const data = await response.json();
167
+ const validatedResponse = api.createUser.validateResponse(201, data);
168
+ ```
169
+
170
+ ## Type Safety
171
+
172
+ All plugin methods are fully typed based on your contract:
173
+
174
+ - Path parameters are typed from `pathParams` schema
175
+ - Query parameters are typed from `query` schema
176
+ - Request body is typed from `body` schema
177
+ - Response data is typed from `responses` schema
178
+ - TypeScript will catch type errors at compile time
179
+
180
+ ## Error Handling
181
+
182
+ Validation errors include detailed information:
183
+
184
+ ```typescript
185
+ try {
186
+ api.createUser.validateBody({ name: 'Alice' }); // Missing email
187
+ } catch (error) {
188
+ console.error(error.message);
189
+ // Detailed validation error from schema library
190
+ }
191
+ ```
192
+
193
+ ## Schema Library Support
194
+
195
+ Works with any schema library that implements the [Standard Schema](https://github.com/standard-schema/standard-schema) specification:
196
+
197
+ - ✅ Zod
198
+ - ✅ Valibot
199
+ - ✅ Arktype
200
+ - ✅ And more...
201
+
202
+ ## Documentation
203
+
204
+ For complete documentation and examples, visit:
205
+
206
+ - [Path Plugin Documentation](https://github.com/mbrimmer83/ts-contract/tree/main/docs/plugins/path-plugin.md)
207
+ - [Validate Plugin Documentation](https://github.com/mbrimmer83/ts-contract/tree/main/docs/plugins/validate-plugin.md)
208
+ - [Creating Custom Plugins](https://github.com/mbrimmer83/ts-contract/tree/main/docs/plugins/creating-custom-plugins.md)
209
+
210
+ ## License
211
+
212
+ MIT
213
+
214
+ ## Contributing
215
+
216
+ Contributions are welcome! Please see the [contributing guide](../../CONTRIBUTING.md) for details.
package/dist/index.d.ts CHANGED
@@ -2,4 +2,8 @@ export * from './lib/path';
2
2
  export * from './lib/validate';
3
3
  export * from './lib/plugins/path';
4
4
  export * from './lib/plugins/validate';
5
+ export * from './lib/websocket-path';
6
+ export * from './lib/websocket-validate';
7
+ export * from './lib/plugins/websocket-path';
8
+ export * from './lib/plugins/websocket-validate';
5
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kCAAkC,CAAC"}
package/dist/index.js CHANGED
@@ -2,3 +2,7 @@ export * from './lib/path';
2
2
  export * from './lib/validate';
3
3
  export * from './lib/plugins/path';
4
4
  export * from './lib/plugins/validate';
5
+ export * from './lib/websocket-path';
6
+ export * from './lib/websocket-validate';
7
+ export * from './lib/plugins/websocket-path';
8
+ export * from './lib/plugins/websocket-validate';
@@ -0,0 +1,12 @@
1
+ import type { WebSocketDef, InferWebSocketPathParams, InferWebSocketQuery, WebSocketPlugin } from '@ts-contract/core';
2
+ type BuildPathArgs<W extends WebSocketDef> = InferWebSocketPathParams<W> extends undefined ? InferWebSocketQuery<W> extends undefined ? [] : [params?: undefined, query?: InferWebSocketQuery<W>] : InferWebSocketQuery<W> extends undefined ? [params: InferWebSocketPathParams<W>] : [params: InferWebSocketPathParams<W>, query?: InferWebSocketQuery<W>];
3
+ declare module '@ts-contract/core' {
4
+ interface WebSocketPluginTypeRegistry<W> {
5
+ 'websocket-path': {
6
+ buildPath: W extends WebSocketDef ? (...args: BuildPathArgs<W>) => string : never;
7
+ };
8
+ }
9
+ }
10
+ export declare const websocketPathPlugin: WebSocketPlugin<'websocket-path'>;
11
+ export {};
12
+ //# sourceMappingURL=websocket-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket-path.d.ts","sourceRoot":"","sources":["../../../src/lib/plugins/websocket-path.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,wBAAwB,EACxB,mBAAmB,EACnB,eAAe,EAChB,MAAM,mBAAmB,CAAC;AAG3B,KAAK,aAAa,CAAC,CAAC,SAAS,YAAY,IACvC,wBAAwB,CAAC,CAAC,CAAC,SAAS,SAAS,GACzC,mBAAmB,CAAC,CAAC,CAAC,SAAS,SAAS,GACtC,EAAE,GACF,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAC,GACtD,mBAAmB,CAAC,CAAC,CAAC,SAAS,SAAS,GACtC,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC,CAAC,CAAC,GACrC,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9E,OAAO,QAAQ,mBAAmB,CAAC;IACjC,UAAU,2BAA2B,CAAC,CAAC;QACrC,gBAAgB,EAAE;YAChB,SAAS,EAAE,CAAC,SAAS,YAAY,GAC7B,CAAC,GAAG,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,MAAM,GACrC,KAAK,CAAC;SACX,CAAC;KACH;CACF;AAED,eAAO,MAAM,mBAAmB,EAAE,eAAe,CAAC,gBAAgB,CASjE,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { buildWebSocketPath } from '../websocket-path';
2
+ export const websocketPathPlugin = {
3
+ name: 'websocket-path',
4
+ websocket: (def) => ({
5
+ buildPath: (...args) => buildWebSocketPath(def, ...args),
6
+ }),
7
+ };
@@ -0,0 +1,14 @@
1
+ import type { WebSocketDef, InferWebSocketPathParams, InferWebSocketQuery, InferWebSocketHeaders, InferClientMessage, InferServerMessage, WebSocketPlugin } from '@ts-contract/core';
2
+ declare module '@ts-contract/core' {
3
+ interface WebSocketPluginTypeRegistry<W> {
4
+ 'websocket-validate': {
5
+ validateClientMessage: W extends WebSocketDef ? <E extends keyof W['clientMessages'] & string>(eventName: E, data: unknown) => InferClientMessage<W, E> : never;
6
+ validateServerMessage: W extends WebSocketDef ? <E extends keyof W['serverMessages'] & string>(eventName: E, data: unknown) => InferServerMessage<W, E> : never;
7
+ validatePathParams: W extends WebSocketDef ? (params: unknown) => InferWebSocketPathParams<W> : never;
8
+ validateQuery: W extends WebSocketDef ? (query: unknown) => InferWebSocketQuery<W> : never;
9
+ validateHeaders: W extends WebSocketDef ? (headers: Record<string, unknown>) => InferWebSocketHeaders<W> : never;
10
+ };
11
+ }
12
+ }
13
+ export declare const websocketValidatePlugin: WebSocketPlugin<'websocket-validate'>;
14
+ //# sourceMappingURL=websocket-validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket-validate.d.ts","sourceRoot":"","sources":["../../../src/lib/plugins/websocket-validate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,wBAAwB,EACxB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EAChB,MAAM,mBAAmB,CAAC;AAS3B,OAAO,QAAQ,mBAAmB,CAAC;IACjC,UAAU,2BAA2B,CAAC,CAAC;QACrC,oBAAoB,EAAE;YACpB,qBAAqB,EAAE,CAAC,SAAS,YAAY,GACzC,CAAC,CAAC,SAAS,MAAM,CAAC,CAAC,gBAAgB,CAAC,GAAG,MAAM,EAC3C,SAAS,EAAE,CAAC,EACZ,IAAI,EAAE,OAAO,KACV,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,GAC7B,KAAK,CAAC;YACV,qBAAqB,EAAE,CAAC,SAAS,YAAY,GACzC,CAAC,CAAC,SAAS,MAAM,CAAC,CAAC,gBAAgB,CAAC,GAAG,MAAM,EAC3C,SAAS,EAAE,CAAC,EACZ,IAAI,EAAE,OAAO,KACV,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,GAC7B,KAAK,CAAC;YACV,kBAAkB,EAAE,CAAC,SAAS,YAAY,GACtC,CAAC,MAAM,EAAE,OAAO,KAAK,wBAAwB,CAAC,CAAC,CAAC,GAChD,KAAK,CAAC;YACV,aAAa,EAAE,CAAC,SAAS,YAAY,GACjC,CAAC,KAAK,EAAE,OAAO,KAAK,mBAAmB,CAAC,CAAC,CAAC,GAC1C,KAAK,CAAC;YACV,eAAe,EAAE,CAAC,SAAS,YAAY,GACnC,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,qBAAqB,CAAC,CAAC,CAAC,GAC9D,KAAK,CAAC;SACX,CAAC;KACH;CACF;AAED,eAAO,MAAM,uBAAuB,EAAE,eAAe,CAAC,oBAAoB,CAazE,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { validateClientMessage, validateServerMessage, validateWebSocketPathParams, validateWebSocketQuery, validateWebSocketHeaders, } from '../websocket-validate';
2
+ export const websocketValidatePlugin = {
3
+ name: 'websocket-validate',
4
+ websocket: (def) => ({
5
+ validateClientMessage: (eventName, data) => validateClientMessage(def, eventName, data),
6
+ validateServerMessage: (eventName, data) => validateServerMessage(def, eventName, data),
7
+ validatePathParams: (params) => validateWebSocketPathParams(def, params),
8
+ validateQuery: (query) => validateWebSocketQuery(def, query),
9
+ validateHeaders: (headers) => validateWebSocketHeaders(def, headers),
10
+ }),
11
+ };
@@ -0,0 +1,5 @@
1
+ import type { WebSocketDef, InferWebSocketPathParams, InferWebSocketQuery } from '@ts-contract/core';
2
+ type BuildWebSocketPathArgs<W extends WebSocketDef> = InferWebSocketPathParams<W> extends undefined ? InferWebSocketQuery<W> extends undefined ? [] : [params?: undefined, query?: InferWebSocketQuery<W>] : InferWebSocketQuery<W> extends undefined ? [params: InferWebSocketPathParams<W>] : [params: InferWebSocketPathParams<W>, query?: InferWebSocketQuery<W>];
3
+ export declare const buildWebSocketPath: <W extends WebSocketDef>(def: W, ...args: BuildWebSocketPathArgs<W>) => string;
4
+ export {};
5
+ //# sourceMappingURL=websocket-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket-path.d.ts","sourceRoot":"","sources":["../../src/lib/websocket-path.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,wBAAwB,EACxB,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAE3B,KAAK,sBAAsB,CAAC,CAAC,SAAS,YAAY,IAChD,wBAAwB,CAAC,CAAC,CAAC,SAAS,SAAS,GACzC,mBAAmB,CAAC,CAAC,CAAC,SAAS,SAAS,GACtC,EAAE,GACF,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAC,GACtD,mBAAmB,CAAC,CAAC,CAAC,SAAS,SAAS,GACtC,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC,CAAC,CAAC,GACrC,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9E,eAAO,MAAM,kBAAkB,GAAI,CAAC,SAAS,YAAY,EACvD,KAAK,CAAC,EACN,GAAG,MAAM,sBAAsB,CAAC,CAAC,CAAC,KACjC,MA+BF,CAAC"}
@@ -0,0 +1,25 @@
1
+ export const buildWebSocketPath = (def, ...args) => {
2
+ const [params, query] = args;
3
+ let path = def.path;
4
+ if (params) {
5
+ path = path.replace(/:([^/]+)/g, (_, key) => {
6
+ if (!(key in params)) {
7
+ throw new Error(`Missing path parameter: ${key}`);
8
+ }
9
+ return encodeURIComponent(params[key]);
10
+ });
11
+ }
12
+ if (query) {
13
+ const searchParams = new URLSearchParams();
14
+ for (const [key, value] of Object.entries(query)) {
15
+ if (value !== undefined && value !== null) {
16
+ searchParams.append(key, String(value));
17
+ }
18
+ }
19
+ const qs = searchParams.toString();
20
+ if (qs) {
21
+ path += `?${qs}`;
22
+ }
23
+ }
24
+ return path;
25
+ };
@@ -0,0 +1,7 @@
1
+ import type { WebSocketDef, InferWebSocketPathParams, InferWebSocketQuery, InferWebSocketHeaders, InferClientMessage, InferServerMessage } from '@ts-contract/core';
2
+ export declare const validateClientMessage: <W extends WebSocketDef, E extends keyof W["clientMessages"] & string>(def: W, eventName: E, data: unknown) => InferClientMessage<W, E>;
3
+ export declare const validateServerMessage: <W extends WebSocketDef, E extends keyof W["serverMessages"] & string>(def: W, eventName: E, data: unknown) => InferServerMessage<W, E>;
4
+ export declare const validateWebSocketPathParams: <W extends WebSocketDef>(def: W, params: unknown) => InferWebSocketPathParams<W>;
5
+ export declare const validateWebSocketQuery: <W extends WebSocketDef>(def: W, query: unknown) => InferWebSocketQuery<W>;
6
+ export declare const validateWebSocketHeaders: <W extends WebSocketDef>(def: W, headers: Record<string, unknown>) => InferWebSocketHeaders<W>;
7
+ //# sourceMappingURL=websocket-validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket-validate.d.ts","sourceRoot":"","sources":["../../src/lib/websocket-validate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,wBAAwB,EACxB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAEnB,MAAM,mBAAmB,CAAC;AAoB3B,eAAO,MAAM,qBAAqB,GAChC,CAAC,SAAS,YAAY,EACtB,CAAC,SAAS,MAAM,CAAC,CAAC,gBAAgB,CAAC,GAAG,MAAM,EAE5C,KAAK,CAAC,EACN,WAAW,CAAC,EACZ,MAAM,OAAO,KACZ,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAYzB,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,CAAC,SAAS,YAAY,EACtB,CAAC,SAAS,MAAM,CAAC,CAAC,gBAAgB,CAAC,GAAG,MAAM,EAE5C,KAAK,CAAC,EACN,WAAW,CAAC,EACZ,MAAM,OAAO,KACZ,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAYzB,CAAC;AAEF,eAAO,MAAM,2BAA2B,GAAI,CAAC,SAAS,YAAY,EAChE,KAAK,CAAC,EACN,QAAQ,OAAO,KACd,wBAAwB,CAAC,CAAC,CAS5B,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,CAAC,SAAS,YAAY,EAC3D,KAAK,CAAC,EACN,OAAO,OAAO,KACb,mBAAmB,CAAC,CAAC,CASvB,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAI,CAAC,SAAS,YAAY,EAC7D,KAAK,CAAC,EACN,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC/B,qBAAqB,CAAC,CAAC,CAazB,CAAC"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Validate a value against a Standard Schema, throwing on failure
3
+ */
4
+ const validateSchema = (schema, value, label) => {
5
+ const result = schema['~standard'].validate(value);
6
+ if ('issues' in result && result.issues) {
7
+ const messages = result.issues.map((i) => i.message).join(', ');
8
+ throw new Error(`Validation failed for ${label}: ${messages}`);
9
+ }
10
+ return result.value;
11
+ };
12
+ export const validateClientMessage = (def, eventName, data) => {
13
+ const schema = def.clientMessages[eventName];
14
+ if (!schema) {
15
+ throw new Error(`WebSocket "${def.path}" has no client message schema for event "${eventName}"`);
16
+ }
17
+ return validateSchema(schema, data, `client message "${eventName}" of ${def.path}`);
18
+ };
19
+ export const validateServerMessage = (def, eventName, data) => {
20
+ const schema = def.serverMessages[eventName];
21
+ if (!schema) {
22
+ throw new Error(`WebSocket "${def.path}" has no server message schema for event "${eventName}"`);
23
+ }
24
+ return validateSchema(schema, data, `server message "${eventName}" of ${def.path}`);
25
+ };
26
+ export const validateWebSocketPathParams = (def, params) => {
27
+ if (!def.pathParams) {
28
+ throw new Error(`WebSocket "${def.path}" has no pathParams schema`);
29
+ }
30
+ return validateSchema(def.pathParams, params, `pathParams of ${def.path}`);
31
+ };
32
+ export const validateWebSocketQuery = (def, query) => {
33
+ if (!def.query) {
34
+ throw new Error(`WebSocket "${def.path}" has no query schema`);
35
+ }
36
+ return validateSchema(def.query, query, `query of ${def.path}`);
37
+ };
38
+ export const validateWebSocketHeaders = (def, headers) => {
39
+ if (!def.headers) {
40
+ throw new Error(`WebSocket "${def.path}" has no headers schema`);
41
+ }
42
+ const result = {};
43
+ for (const [key, schema] of Object.entries(def.headers)) {
44
+ result[key] = validateSchema(schema, headers[key], `header "${key}" of ${def.path}`);
45
+ }
46
+ return result;
47
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ts-contract/plugins",
3
- "version": "1.0.0-alpha.0",
3
+ "version": "1.0.0-alpha.1",
4
4
  "description": "Built-in plugins for path building and schema validation for ts-contract",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -40,7 +40,7 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "tslib": "^2.3.0",
43
- "@ts-contract/core": "1.0.0-alpha.0"
43
+ "@ts-contract/core": "1.0.0-alpha.1"
44
44
  },
45
45
  "scripts": {
46
46
  "build": "tsc -b tsconfig.lib.json",