@rexeus/typeweaver-types 0.0.2 โ†’ 0.0.4

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,483 +1,217 @@
1
- # @rexeus/typeweaver-types
1
+ # ๐Ÿงตโœจ @rexeus/typeweaver-types
2
2
 
3
- TypeScript type and Zod validator generators for TypeWeaver APIs.
3
+ [![npm version](https://img.shields.io/npm/v/@rexeus/typeweaver-types.svg)](https://www.npmjs.com/package/@rexeus/typeweaver-types)
4
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
4
6
 
5
- ## Overview
7
+ Typeweaver is a type-safe HTTP API framework built for API-first development with a focus on
8
+ developer experience. Use typeweaver to specify your HTTP APIs in TypeScript and Zod, and generate
9
+ clients, validators, routers, and more โœจ
6
10
 
7
- This plugin generates TypeScript types and Zod validators from your TypeWeaver API definitions,
8
- providing the foundation for type-safe API development. This is the core plugin that's included by
9
- default in TypeWeaver.
11
+ ## ๐Ÿ“ Types Plugin
10
12
 
11
- ## Installation
13
+ This plugin generates TypeScript types and Zod validators from your typeweaver API definitions,
14
+ providing the foundation for type-safe API development. This is the core plugin that's included by
15
+ default in every typeweaver generation.
12
16
 
13
- ```bash
14
- npm install @rexeus/typeweaver-types
15
- ```
17
+ ---
16
18
 
17
- **Peer Dependencies:**
19
+ ## ๐Ÿ“ฅ Installation
18
20
 
19
21
  ```bash
20
- npm install @rexeus/typeweaver-core @rexeus/typeweaver-gen
22
+ # Install the CLI as a dev dependency
23
+ # Types plugin will be automatically included
24
+ npm install -D @rexeus/typeweaver
25
+
26
+ # Install the runtime as a dependency
27
+ npm install @rexeus/typeweaver-core
21
28
  ```
22
29
 
23
- ## Usage
30
+ ## ๐Ÿ’ก How to use
24
31
 
25
32
  This plugin is included by default and doesn't need to be explicitly specified:
26
33
 
27
34
  ```bash
28
- npx typeweaver generate --input ./api/definitions --output ./api/generated
35
+ # Generate with clients + types plugins
36
+ npx typeweaver generate --input ./api/definition --output ./api/generated --plugins clients
29
37
  ```
30
38
 
31
- You can also explicitly include it with other plugins:
39
+ More details on how to use the [CLI](https://github.com/rexeus/typeweaver/tree/main/packages/cli/README.md#๏ธ-cli).
32
40
 
33
- ```bash
34
- npx typeweaver generate --input ./api/definitions --output ./api/generated --plugins types,clients,aws-cdk
35
- ```
41
+ ## ๐Ÿ“‚ Generated Output
36
42
 
37
- ## Generated Output
43
+ For each operation (e.g., `CreateTodo`), the plugin generates four main files:
38
44
 
39
- This plugin generates comprehensive TypeScript types and validators for each API operation.
45
+ - `<OperationId>Request.ts`
46
+ - `<OperationId>Response.ts`
47
+ - `<OperationId>RequestValidator.ts`
48
+ - `<OperationId>ResponseValidator.ts`
40
49
 
41
- ### Generated Files per Operation
50
+ These files contain the necessary types and validators for requests and responses. All of these
51
+ provided types and classes are exported.
42
52
 
43
- For each operation (e.g., `GetUser`), the plugin generates:
53
+ ### ๐Ÿ“จ Request Types
44
54
 
45
- 1. **Request Types** (`GetUserRequest.ts`)
46
- 2. **Response Types** (`GetUserResponse.ts`)
47
- 3. **Request Validators** (`GetUserRequestValidator.ts`)
48
- 4. **Response Validators** (`GetUserResponseValidator.ts`)
55
+ All request-related types for an operation are defined in one file: `<OperationId>Request.ts`, e.g.
56
+ `CreateTodoRequest.ts`. This file contains:
49
57
 
50
- ### Shared Response Types
58
+ - **`I<OperationId>RequestHeader`** - Type of request headers, if defined, e.g.
59
+ `ICreateTodoRequestHeader`
60
+ - **`I<OperationId>RequestPath`** - Type for path parameters, if defined, e.g.
61
+ `ICreateTodoRequestPath`
62
+ - **`I<OperationId>RequestQuery`** - Type for query parameters, if defined, e.g.
63
+ `ICreateTodoRequestQuery`
64
+ - **`I<OperationId>RequestBody`** - Type for request body, if defined, e.g. `ICreateTodoRequestBody`
65
+ - **`I<OperationId>Request`** - Complete request interface combining path, method, headers, and
66
+ body, e.g. `ICreateTodoRequest`
67
+ - **`Successful<OperationId>Response`** - Union type excluding error responses for success-only
68
+ handling
51
69
 
52
- For shared error responses, generates:
70
+ ### ๐Ÿ“ฌ Response Types
53
71
 
54
- - **Shared Response Types** (in `shared/` directory)
72
+ All response-related types for an operation are defined in one file: `<OperationId>Response.ts`,
73
+ e.g. `CreateTodoResponse.ts`. This file contains for each response defined inline in an operation:
55
74
 
56
- ## Example Generated Code
75
+ - **`I<ResponseName>ResponseHeader`** - Type for success response headers, if defined, e.g.
76
+ `ICreateTodoSuccessResponseHeader`
77
+ - **`I<ResponseName>ResponseBody`** - Type for success response payload structure, if defined, e.g.
78
+ `ICreateTodoSuccessResponseBody`
79
+ - **`I<ResponseName>Response`** - Complete success response interface with status code, e.g.
80
+ `I<ResponseName>Response`
81
+ - **`<ResponseName>Response`** - Response class extending HttpResponse with validation and type
82
+ safety, e.g. `CreateTodoSuccessResponse`
57
83
 
58
- ### Request Types
84
+ Furthermore, two union types are generated, which include details about all possible responses
85
+ (success + error), not only those defined inline in the operation:
59
86
 
60
- ```typescript
61
- // GetUserRequest.ts
62
- import { HttpRequest } from "@rexeus/typeweaver-core";
63
- import { z } from "zod/v4";
64
-
65
- export const GetUserRequestSchema = z.object({
66
- param: z.object({
67
- userId: z.string().uuid(),
68
- }),
69
- header: z
70
- .object({
71
- Authorization: z.string(),
72
- Accept: z.literal("application/json"),
73
- })
74
- .optional(),
75
- });
76
-
77
- export type GetUserRequest = z.infer<typeof GetUserRequestSchema>;
78
-
79
- export interface IGetUserRequest extends HttpRequest {
80
- param: {
81
- userId: string;
82
- };
83
- header?: {
84
- Authorization: string;
85
- Accept: "application/json";
86
- };
87
- }
87
+ - **`I<OperationId>Response`** - Union type of all response types e.g. `ICreateTodoResponse`
88
+ - **`<OperationId>Response`** - Union type of all response classes, e.g. `CreateTodoResponse`
88
89
 
89
- export class GetUserRequestCommand {
90
- constructor(public readonly data: IGetUserRequest) {
91
- GetUserRequestSchema.parse(data);
92
- }
93
- }
94
- ```
90
+ ### ๐Ÿ“จโœ“ Request Validators
95
91
 
96
- ### Response Types
92
+ Request validation logic for an operation is defined in one file:
93
+ `<OperationId>RequestValidator.ts`, e.g. `CreateTodoRequestValidator.ts`. This file contains:
97
94
 
98
- ```typescript
99
- // GetUserResponse.ts
100
- import { HttpResponse } from "@rexeus/typeweaver-core";
101
- import { z } from "zod/v4";
102
-
103
- // Success Response
104
- export const GetUserSuccessResponseSchema = z.object({
105
- statusCode: z.literal(200),
106
- header: z.object({
107
- "Content-Type": z.literal("application/json"),
108
- }),
109
- body: z.object({
110
- id: z.string().uuid(),
111
- name: z.string(),
112
- email: z.string().email(),
113
- }),
114
- });
115
-
116
- export type GetUserSuccessResponse = z.infer<typeof GetUserSuccessResponseSchema>;
117
-
118
- // Error Responses
119
- export type GetUserErrorResponse =
120
- | UserNotFoundErrorResponse
121
- | ValidationErrorResponse
122
- | InternalServerErrorResponse;
123
-
124
- // Union Type
125
- export type GetUserResponse = GetUserSuccessResponse | GetUserErrorResponse;
126
-
127
- export interface IGetUserResponse extends HttpResponse {
128
- statusCode: 200 | 404 | 400 | 500;
129
- header: {
130
- "Content-Type": "application/json";
131
- };
132
- body:
133
- | {
134
- id: string;
135
- name: string;
136
- email: string;
137
- }
138
- | {
139
- message: string;
140
- code: string;
141
- };
142
- }
143
- ```
95
+ - **`<OperationId>RequestValidator`** - Main validation class extending `RequestValidator`, e.g.
96
+ `CreateTodoRequestValidator`
97
+ - **`safeValidate()`** - Non-throwing validation method returning `SafeRequestValidationResult`
98
+ - **`validate()`** - Throwing validation method that returns validated request or throws
99
+ `RequestValidationError`
100
+ - **Header coercion logic** - Automatic conversion of headers to schema-appropriate types (single
101
+ string value & multi string value headers)
102
+ - **Query parameter coercion logic** - Automatic conversion of query parameters to
103
+ schema-appropriate types (single string value & multi string value query parameters)
104
+ - **Request validation errors** - Includes all issues related to the incoming request for headers,
105
+ query parameters, and body.
106
+ - **Unknown property filtering** - Automatically removes properties not defined in the request
107
+ schema. If a request exceeds the definition, it is not rejected directly.
144
108
 
145
- ### Request Validators
109
+ **Using the generated request validators**
146
110
 
147
111
  ```typescript
148
- // GetUserRequestValidator.ts
149
- import { RequestValidator } from "@rexeus/typeweaver-core";
150
- import { GetUserRequestSchema } from "./GetUserRequest";
151
-
152
- export class GetUserRequestValidator extends RequestValidator<typeof GetUserRequestSchema> {
153
- constructor() {
154
- super(GetUserRequestSchema);
155
- }
156
-
157
- public validate(request: unknown): GetUserRequest {
158
- return this.schema.parse(request);
159
- }
160
-
161
- public safeValidate(request: unknown): SafeParseResult<GetUserRequest> {
162
- return this.schema.safeParse(request);
163
- }
164
- }
165
- ```
166
-
167
- ### Response Validators
168
-
169
- ```typescript
170
- // GetUserResponseValidator.ts
171
- import { ResponseValidator } from "@rexeus/typeweaver-core";
172
- import { GetUserResponse } from "./GetUserResponse";
173
-
174
- export class GetUserResponseValidator extends ResponseValidator {
175
- public validate(response: unknown): GetUserResponse {
176
- const statusCode = (response as any)?.statusCode;
177
-
178
- switch (statusCode) {
179
- case 200:
180
- return this.validateSuccessResponse(response);
181
- case 404:
182
- return this.validateUserNotFoundError(response);
183
- case 400:
184
- return this.validateValidationError(response);
185
- case 500:
186
- return this.validateInternalServerError(response);
187
- default:
188
- throw new ResponseValidationError(`Unexpected status code: ${statusCode}`);
189
- }
190
- }
112
+ import { RequestValidationError, type IHttpRequest } from "@rexeus/typeweaver-core";
113
+ import { CreateTodoRequestValidator } from "path/to/generated/output";
191
114
 
192
- private validateSuccessResponse(response: unknown): GetUserSuccessResponse {
193
- return GetUserSuccessResponseSchema.parse(response);
194
- }
195
-
196
- // ... other validation methods
197
- }
198
- ```
199
-
200
- ## Type Features
201
-
202
- ### Complete Type Safety
203
-
204
- - **Request Types** - Fully typed request interfaces
205
- - **Response Types** - Union types for all possible responses
206
- - **Parameter Types** - Path, query, header, and body parameters
207
- - **Validation Types** - Runtime validation with Zod schemas
115
+ const requestValidator = new CreateTodoRequestValidator();
208
116
 
209
- ### Zod Integration
210
-
211
- - **Schema Generation** - Automatic Zod schema creation
212
- - **Runtime Validation** - Type-safe validation at runtime
213
- - **Error Handling** - Structured validation errors
214
- - **Type Inference** - TypeScript types inferred from Zod schemas
215
-
216
- ### Error Response Handling
217
-
218
- ```typescript
219
- // Shared error responses are reused across operations
220
- export type UserNotFoundErrorResponse = {
221
- statusCode: 404;
222
- body: {
223
- message: "User not found";
224
- code: "USER_NOT_FOUND";
225
- userId: string;
226
- };
117
+ // A request in structure of IHttpRequest
118
+ const request: IHttpRequest = {
119
+ // ...
227
120
  };
228
121
 
229
- // Operation-specific error handling
230
- export type GetUserErrorResponse =
231
- | UserNotFoundErrorResponse
232
- | ValidationErrorResponse
233
- | InternalServerErrorResponse;
234
- ```
235
-
236
- ## Usage Examples
237
-
238
- ### Request Validation
239
-
240
- ```typescript
241
- import { GetUserRequestValidator } from "./api/generated";
242
-
243
- const validator = new GetUserRequestValidator();
244
-
245
- try {
246
- const validatedRequest = validator.validate({
247
- param: { userId: "123e4567-e89b-12d3-a456-426614174000" },
248
- header: { Authorization: "Bearer token" },
249
- });
250
-
251
- // validatedRequest is fully typed
252
- console.log(validatedRequest.param.userId);
253
- } catch (error) {
254
- console.error("Validation failed:", error.issues);
122
+ // Using safe validation
123
+ const safeResult = requestValidator.safeValidate(request);
124
+ if (safeResult.isValid) {
125
+ console.log("Request is valid", safeResult.data);
126
+ } else {
127
+ // Error is instance of RequestValidationError class
128
+ console.log("Request is invalid", safeResult.error);
255
129
  }
256
- ```
257
-
258
- ### Response Validation
259
-
260
- ```typescript
261
- import { GetUserResponseValidator } from "./api/generated";
262
-
263
- const validator = new GetUserResponseValidator();
264
130
 
131
+ // Using throwing validation
265
132
  try {
266
- const validatedResponse = validator.validate({
267
- statusCode: 200,
268
- header: { "Content-Type": "application/json" },
269
- body: { id: "123", name: "John", email: "john@example.com" },
270
- });
271
-
272
- // Response is typed based on status code
273
- if (validatedResponse.statusCode === 200) {
274
- console.log(validatedResponse.body.name); // Type-safe access
275
- }
133
+ const validatedRequest = requestValidator.validate(request);
134
+ console.log("Request is valid", validatedRequest);
276
135
  } catch (error) {
277
- console.error("Response validation failed:", error);
278
- }
279
- ```
280
-
281
- ### Type Guards
282
-
283
- ```typescript
284
- import { GetUserResponse } from "./api/generated";
285
-
286
- function isSuccessResponse(response: GetUserResponse): response is GetUserSuccessResponse {
287
- return response.statusCode === 200;
288
- }
289
-
290
- function handleResponse(response: GetUserResponse) {
291
- if (isSuccessResponse(response)) {
292
- // TypeScript knows this is a success response
293
- console.log(response.body.name);
294
- } else {
295
- // TypeScript knows this is an error response
296
- console.error(response.body.message);
136
+ if (error instanceof RequestValidationError) {
137
+ console.log("Request is invalid", error);
297
138
  }
298
139
  }
299
140
  ```
300
141
 
301
- ## Integration with Other Plugins
302
-
303
- ### With Clients Plugin
142
+ ### ๐Ÿ“ฌโœ“ Response Validators
304
143
 
305
- The types plugin provides the foundation for type-safe clients:
306
-
307
- ```typescript
308
- // Generated by types plugin
309
- import { GetUserRequestCommand, GetUserResponse } from "./GetUserRequest";
310
- import { GetUserResponseValidator } from "./GetUserResponseValidator";
311
-
312
- // Used by clients plugin
313
- export class UsersClient {
314
- async send(command: GetUserRequestCommand): Promise<GetUserResponse> {
315
- const response = await this.makeRequest(command);
316
- const validator = new GetUserResponseValidator();
317
- return validator.validate(response);
318
- }
319
- }
320
- ```
144
+ Response validation logic for an operation is defined in one file:
145
+ `<OperationId>ResponseValidator.ts`, e.g. `CreateTodoResponseValidator.ts`. This file contains:
321
146
 
322
- ### With AWS CDK Plugin
147
+ - **`<OperationId>ResponseValidator`** - Main validation class extending `ResponseValidator`, e.g.
148
+ `CreateTodoResponseValidator`
149
+ - **`safeValidate()`** - Non-throwing validation method returning `SafeResponseValidationResult`
150
+ - **`validate()`** - Throwing validation method that returns validated response or throws
151
+ ResponseValidationError
152
+ - Valid response data is an instance of one of the generated response classes
153
+ - **Header coercion logic** - Automatic conversion of headers to schema-appropriate types (single
154
+ string value & multi string value headers)
155
+ - **Response validation errors** - Include details about the issues with all possible responses for
156
+ the given status code:
157
+ - An issue for a possible response includes details about header and body issues
158
+ - If the given status code is not specified in the operation at all an issue with details about
159
+ expected status codes is included
160
+ - **Unknown property filtering** - Automatically removes properties not defined in the response
161
+ schema. If a response exceeds the definition, it is not rejected directly.
323
162
 
324
- Types provide the foundation for request/response handling:
163
+ **Using the generated response validators**
325
164
 
326
165
  ```typescript
327
- // In your Lambda handler
328
- import { GetUserRequestValidator, GetUserResponseValidator } from "./api/generated";
329
-
330
- export const handler = async (event: APIGatewayProxyEvent) => {
331
- const requestValidator = new GetUserRequestValidator();
332
-
333
- try {
334
- const validatedRequest = requestValidator.validate({
335
- param: event.pathParameters,
336
- header: event.headers,
337
- });
338
-
339
- // Handle request with type safety
340
- const user = await userService.getUser(validatedRequest.param.userId);
341
-
342
- return {
343
- statusCode: 200,
344
- body: JSON.stringify(user),
345
- };
346
- } catch (error) {
347
- if (error instanceof ValidationError) {
348
- return {
349
- statusCode: 400,
350
- body: JSON.stringify({ message: "Invalid request", issues: error.issues }),
351
- };
352
- }
353
- throw error;
354
- }
166
+ import { ResponseValidationError, type IHttpResponse } from "@rexeus/typeweaver-core";
167
+ import {
168
+ CreateTodoResponseValidator,
169
+ CreateTodoSuccessResponse,
170
+ InternalServerErrorResponse,
171
+ } from "path/to/generated/output";
172
+
173
+ const responseValidator = new CreateTodoResponseValidator();
174
+
175
+ // A response in structure of IHttpResponse
176
+ const response: IHttpResponse = {
177
+ // ...
355
178
  };
356
- ```
357
-
358
- ## Advanced Features
359
-
360
- ### Custom Validators
361
-
362
- Extend generated validators for custom validation logic:
363
-
364
- ```typescript
365
- import { GetUserRequestValidator } from "./api/generated";
366
179
 
367
- export class CustomGetUserRequestValidator extends GetUserRequestValidator {
368
- public validate(request: unknown): GetUserRequest {
369
- const validated = super.validate(request);
180
+ // Using safe validation
181
+ const safeResult = responseValidator.safeValidate(response);
182
+ if (safeResult.isValid) {
183
+ console.log("Response is valid", safeResult.data);
370
184
 
371
- // Custom validation logic
372
- if (validated.param.userId.startsWith("test_")) {
373
- throw new Error("Test users not allowed in production");
374
- }
375
-
376
- return validated;
185
+ // Data is an instance of one of the defined response classes
186
+ if (safeResult.data instanceof CreateTodoSuccessResponse) {
187
+ // handle CreateTodoSuccessResponse
377
188
  }
378
- }
379
- ```
380
-
381
- ### Schema Composition
382
-
383
- Generated schemas can be composed and extended:
384
-
385
- ```typescript
386
- import { GetUserRequestSchema } from "./api/generated";
387
-
388
- // Extend for internal usage
389
- export const InternalGetUserRequestSchema = GetUserRequestSchema.extend({
390
- internal: z.object({
391
- requestId: z.string(),
392
- userId: z.string(),
393
- }),
394
- });
395
- ```
396
-
397
- ## Plugin Architecture
398
-
399
- This plugin extends the TypeWeaver plugin system:
400
-
401
- ```typescript
402
- import { BasePlugin, type GeneratorContext } from "@rexeus/typeweaver-gen";
403
-
404
- export default class TypesPlugin extends BasePlugin {
405
- public name = "types";
406
-
407
- public override generate(context: GeneratorContext): void {
408
- // Generates types and validators for all operations
409
- SharedResponseGenerator.generate(context);
410
- RequestGenerator.generate(context);
411
- RequestValidationGenerator.generate(context);
412
- ResponseGenerator.generate(context);
413
- ResponseValidationGenerator.generate(context);
189
+ if (safeResult.data instanceof InternalServerErrorResponse) {
190
+ // handle InternalServerErrorResponse
414
191
  }
192
+ // handle other response types ...
193
+ } else {
194
+ // Error is instance of ResponseValidationError class
195
+ console.log("Response is invalid", safeResult.error);
415
196
  }
416
- ```
417
197
 
418
- ## Best Practices
419
-
420
- ### Organization
421
-
422
- - Keep generated types in source control for review
423
- - Regenerate types when API definitions change
424
- - Use TypeScript strict mode for maximum safety
425
-
426
- ### Validation Strategy
198
+ // Using throwing validation
199
+ try {
200
+ const validatedResponse = responseValidator.validate(response);
201
+ console.log("Response is valid", validatedResponse);
427
202
 
428
- ```typescript
429
- // Validate at boundaries
430
- export class ApiController {
431
- async getUser(request: unknown) {
432
- // Validate input
433
- const validator = new GetUserRequestValidator();
434
- const validatedRequest = validator.validate(request);
435
-
436
- // Business logic with typed data
437
- const user = await this.userService.getUser(validatedRequest.param.userId);
438
-
439
- // Return typed response
440
- return {
441
- statusCode: 200,
442
- body: user,
443
- } as GetUserSuccessResponse;
203
+ // Same here: Data is an instance of one of the defined response classes
204
+ if (validatedResponse instanceof CreateTodoSuccessResponse) {
205
+ // handle CreateTodoSuccessResponse
206
+ }
207
+ // ... handle other response types
208
+ } catch (error) {
209
+ if (error instanceof ResponseValidationError) {
210
+ console.log("Response is invalid", error);
444
211
  }
445
212
  }
446
213
  ```
447
214
 
448
- ### Error Handling
449
-
450
- ```typescript
451
- // Centralized error mapping
452
- export function mapValidationError(error: ZodError): ValidationErrorResponse {
453
- return {
454
- statusCode: 400,
455
- body: {
456
- message: "Validation failed",
457
- issues: error.issues.map(issue => ({
458
- path: issue.path.join("."),
459
- message: issue.message,
460
- })),
461
- },
462
- };
463
- }
464
- ```
465
-
466
- ## Troubleshooting
467
-
468
- ### Common Issues
469
-
470
- **Type conflicts**: Ensure API definitions are consistent **Validation errors**: Check Zod schema
471
- compatibility **Import issues**: Verify generated files are properly exported
472
-
473
- ### Debug Mode
474
-
475
- Enable detailed generation logging:
476
-
477
- ```bash
478
- DEBUG=typeweaver:types npx typeweaver generate --plugins types
479
- ```
480
-
481
- ## License
215
+ ## ๐Ÿ“„ License
482
216
 
483
- ISC ยฉ Dennis Wentzien 2025
217
+ Apache 2.0 ยฉ Dennis Wentzien 2025