@rexeus/typeweaver-types 0.6.4 → 0.6.5
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.cjs +28 -13
- package/dist/index.mjs +28 -13
- package/dist/index.mjs.map +1 -1
- package/dist/lib/RequestValidator.d.ts +17 -0
- package/dist/lib/RequestValidator.js +19 -0
- package/dist/lib/ResponseValidator.d.ts +25 -0
- package/dist/lib/ResponseValidator.js +63 -0
- package/dist/lib/Validator.d.ts +25 -0
- package/dist/lib/Validator.js +185 -0
- package/dist/lib/assert.d.ts +1 -0
- package/dist/lib/assert.js +11 -0
- package/dist/templates/Request.ejs +11 -4
- package/dist/templates/Response.ejs +16 -7
- package/dist/templates/ResponseValidator.ejs +1 -2
- package/package.json +8 -7
- package/dist/lib/RequestValidator.ts +0 -54
- package/dist/lib/ResponseValidator.ts +0 -120
- package/dist/lib/Validator.ts +0 -268
- package/dist/lib/assert.ts +0 -12
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
IHttpRequest,
|
|
3
|
+
IRequestValidator,
|
|
4
|
+
SafeRequestValidationResult,
|
|
5
|
+
} from "@rexeus/typeweaver-core";
|
|
6
|
+
import { Validator } from "./Validator";
|
|
7
|
+
|
|
8
|
+
export declare abstract class RequestValidator
|
|
9
|
+
extends Validator
|
|
10
|
+
implements IRequestValidator
|
|
11
|
+
{
|
|
12
|
+
public constructor();
|
|
13
|
+
public abstract safeValidate(
|
|
14
|
+
request: IHttpRequest
|
|
15
|
+
): SafeRequestValidationResult<IHttpRequest>;
|
|
16
|
+
public abstract validate(request: IHttpRequest): IHttpRequest;
|
|
17
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Validator } from "./Validator";
|
|
2
|
+
/**
|
|
3
|
+
* Abstract base class for HTTP request validation.
|
|
4
|
+
*
|
|
5
|
+
* This class provides the foundation for request validators that:
|
|
6
|
+
* - Validate headers, body, query parameters, and path parameters
|
|
7
|
+
* - Support both safe (non-throwing) and unsafe (throwing) validation
|
|
8
|
+
* - Integrate with Zod schemas for runtime validation
|
|
9
|
+
* - Provide detailed error information for debugging
|
|
10
|
+
*
|
|
11
|
+
* Implementations should validate all request components and either:
|
|
12
|
+
* - Return validated data (for `validate`)
|
|
13
|
+
* - Return success/error result (for `safeValidate`)
|
|
14
|
+
*/
|
|
15
|
+
export class RequestValidator extends Validator {
|
|
16
|
+
constructor() {
|
|
17
|
+
super();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
IHttpResponse,
|
|
3
|
+
IResponseValidator,
|
|
4
|
+
ResponseValidationError,
|
|
5
|
+
SafeResponseValidationResult,
|
|
6
|
+
} from "@rexeus/typeweaver-core";
|
|
7
|
+
import { Validator } from "./Validator";
|
|
8
|
+
|
|
9
|
+
export declare abstract class ResponseValidator
|
|
10
|
+
extends Validator
|
|
11
|
+
implements IResponseValidator
|
|
12
|
+
{
|
|
13
|
+
public abstract safeValidate(
|
|
14
|
+
response: IHttpResponse
|
|
15
|
+
): SafeResponseValidationResult<IHttpResponse>;
|
|
16
|
+
public abstract validate(response: IHttpResponse): IHttpResponse;
|
|
17
|
+
protected validateResponseType<Response extends IHttpResponse>(
|
|
18
|
+
responseName: string,
|
|
19
|
+
headerSchema: unknown,
|
|
20
|
+
bodySchema: unknown
|
|
21
|
+
): (
|
|
22
|
+
response: IHttpResponse,
|
|
23
|
+
error: ResponseValidationError
|
|
24
|
+
) => SafeResponseValidationResult<Response>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Validator } from "./Validator";
|
|
2
|
+
/**
|
|
3
|
+
* Abstract base class for HTTP response validation.
|
|
4
|
+
*
|
|
5
|
+
* This class provides the foundation for response validators that:
|
|
6
|
+
* - Validate response status codes match expected values
|
|
7
|
+
* - Validate response headers and body against schemas
|
|
8
|
+
* - Support both safe (non-throwing) and unsafe (throwing) validation
|
|
9
|
+
* - Integrate with Zod schemas for runtime validation
|
|
10
|
+
*
|
|
11
|
+
* Response validators are typically used in API clients to ensure
|
|
12
|
+
* responses match the expected format before processing.
|
|
13
|
+
*/
|
|
14
|
+
export class ResponseValidator extends Validator {
|
|
15
|
+
/**
|
|
16
|
+
* Generic response validation method that validates header and body schemas.
|
|
17
|
+
* This method reduces code duplication across individual response validators.
|
|
18
|
+
*
|
|
19
|
+
* @param responseName - Name of the response type for error reporting
|
|
20
|
+
* @param headerSchema - Zod schema for header validation (optional)
|
|
21
|
+
* @param bodySchema - Zod schema for body validation (optional)
|
|
22
|
+
* @returns Function that validates response and returns result
|
|
23
|
+
*/
|
|
24
|
+
validateResponseType(responseName, headerSchema, bodySchema) {
|
|
25
|
+
return (response, error) => {
|
|
26
|
+
let isValid = true;
|
|
27
|
+
const validatedResponse = {
|
|
28
|
+
statusCode: response.statusCode,
|
|
29
|
+
header: undefined,
|
|
30
|
+
body: undefined
|
|
31
|
+
};
|
|
32
|
+
if (bodySchema) {
|
|
33
|
+
const validateBodyResult = bodySchema.safeParse(response.body);
|
|
34
|
+
if (!validateBodyResult.success) {
|
|
35
|
+
error.addBodyIssues(responseName, validateBodyResult.error.issues);
|
|
36
|
+
isValid = false;
|
|
37
|
+
} else {
|
|
38
|
+
validatedResponse.body = validateBodyResult.data;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (headerSchema) {
|
|
42
|
+
const coercedHeader = this.coerceHeaderToSchema(response.header, this.getSchema(headerSchema));
|
|
43
|
+
const validateHeaderResult = headerSchema.safeParse(coercedHeader);
|
|
44
|
+
if (!validateHeaderResult.success) {
|
|
45
|
+
error.addHeaderIssues(responseName, validateHeaderResult.error.issues);
|
|
46
|
+
isValid = false;
|
|
47
|
+
} else {
|
|
48
|
+
validatedResponse.header = validateHeaderResult.data;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (!isValid) {
|
|
52
|
+
return {
|
|
53
|
+
isValid: false,
|
|
54
|
+
error
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
isValid: true,
|
|
59
|
+
data: validatedResponse
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
type SchemaInfo = {
|
|
2
|
+
readonly originalKey: string;
|
|
3
|
+
readonly isArray: boolean;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export declare abstract class Validator {
|
|
7
|
+
protected analyzeSchema(
|
|
8
|
+
shape: Record<string, unknown>,
|
|
9
|
+
caseSensitive: boolean
|
|
10
|
+
): Map<string, SchemaInfo>;
|
|
11
|
+
protected getSchema(headerSchema: unknown): Record<string, unknown>;
|
|
12
|
+
protected coerceToSchema(
|
|
13
|
+
data: unknown,
|
|
14
|
+
shape: Record<string, unknown>,
|
|
15
|
+
caseSensitive: boolean
|
|
16
|
+
): unknown;
|
|
17
|
+
protected coerceHeaderToSchema(
|
|
18
|
+
header: unknown,
|
|
19
|
+
shape: Record<string, unknown>
|
|
20
|
+
): unknown;
|
|
21
|
+
protected coerceQueryToSchema(
|
|
22
|
+
query: unknown,
|
|
23
|
+
shape: Record<string, unknown>
|
|
24
|
+
): unknown;
|
|
25
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
import { $ZodArray, $ZodOptional } from "zod/v4/core";
|
|
3
|
+
/**
|
|
4
|
+
* Abstract base class for HTTP validation.
|
|
5
|
+
*
|
|
6
|
+
* This class provides the foundation for request and response validators that:
|
|
7
|
+
* - Analyze Zod schemas for correct single/multi value handling of headers and query parameters
|
|
8
|
+
* - Coerce objects to match schema expectations
|
|
9
|
+
*/
|
|
10
|
+
export class Validator {
|
|
11
|
+
static schemaCacheCaseSensitive = new WeakMap();
|
|
12
|
+
static schemaCacheCaseInsensitive = new WeakMap();
|
|
13
|
+
/**
|
|
14
|
+
* Analyzes a Zod schema shape to create an efficient lookup map.
|
|
15
|
+
* Results are cached using WeakMap for optimal performance.
|
|
16
|
+
*
|
|
17
|
+
* @param shape - The Zod schema shape to analyze
|
|
18
|
+
* @param caseSensitive - Whether to preserve key casing (true) or normalize to lowercase (false)
|
|
19
|
+
* @returns Map with lookup keys pointing to original key and array type information
|
|
20
|
+
*/
|
|
21
|
+
analyzeSchema(shape, caseSensitive) {
|
|
22
|
+
const cache = caseSensitive ? Validator.schemaCacheCaseSensitive : Validator.schemaCacheCaseInsensitive;
|
|
23
|
+
const cached = cache.get(shape);
|
|
24
|
+
if (cached) {
|
|
25
|
+
return cached;
|
|
26
|
+
}
|
|
27
|
+
const schemaMap = this.buildSchemaMap(shape, caseSensitive);
|
|
28
|
+
cache.set(shape, schemaMap);
|
|
29
|
+
return schemaMap;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
*
|
|
33
|
+
* Extracts a Zod schema shape from header or query schemas.
|
|
34
|
+
* This is used to support schema coercion and analysis.
|
|
35
|
+
*
|
|
36
|
+
* @param headerSchema
|
|
37
|
+
* @returns
|
|
38
|
+
*/
|
|
39
|
+
getSchema(headerSchema) {
|
|
40
|
+
if (headerSchema instanceof z.ZodObject) {
|
|
41
|
+
return headerSchema.shape;
|
|
42
|
+
}
|
|
43
|
+
if (headerSchema instanceof z.ZodOptional) {
|
|
44
|
+
const unwrapped = headerSchema.unwrap();
|
|
45
|
+
if (unwrapped instanceof z.ZodObject) {
|
|
46
|
+
return unwrapped.shape;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return {};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Builds a schema map by analyzing the Zod shape structure.
|
|
53
|
+
* Extracts type information for each field to support proper coercion.
|
|
54
|
+
*/
|
|
55
|
+
buildSchemaMap(shape, caseSensitive) {
|
|
56
|
+
const schemaMap = new Map();
|
|
57
|
+
for (const [key, zodType] of Object.entries(shape)) {
|
|
58
|
+
if (!zodType) continue;
|
|
59
|
+
const isArray = zodType instanceof $ZodArray || zodType instanceof $ZodOptional && zodType._zod.def.innerType instanceof $ZodArray;
|
|
60
|
+
const lookupKey = caseSensitive ? key : key.toLowerCase();
|
|
61
|
+
schemaMap.set(lookupKey, {
|
|
62
|
+
originalKey: key,
|
|
63
|
+
isArray
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return schemaMap;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Coerces objects to match schema expectations with configurable case sensitivity.
|
|
70
|
+
* Values not in the schema are ignored.
|
|
71
|
+
*
|
|
72
|
+
* @param data - The data object to coerce
|
|
73
|
+
* @param shape - The Zod schema shape to match against
|
|
74
|
+
* @param caseSensitive - Whether keys should match exactly (true) or case-insensitively (false)
|
|
75
|
+
* @returns Coerced data object with proper key casing and array coercion
|
|
76
|
+
*/
|
|
77
|
+
coerceToSchema(data, shape, caseSensitive) {
|
|
78
|
+
if (typeof data !== "object" || data === null) {
|
|
79
|
+
return data;
|
|
80
|
+
}
|
|
81
|
+
const schemaMap = this.analyzeSchema(shape, caseSensitive);
|
|
82
|
+
const coerced = {};
|
|
83
|
+
for (const [key, value] of Object.entries(data)) {
|
|
84
|
+
const normalizedKey = caseSensitive ? key : key.toLowerCase();
|
|
85
|
+
const schemaInfo = schemaMap.get(normalizedKey);
|
|
86
|
+
if (schemaInfo) {
|
|
87
|
+
this.addValueToCoerced(coerced, normalizedKey, value, schemaInfo.isArray);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// If case-sensitive, return coerced object as is
|
|
91
|
+
if (caseSensitive) {
|
|
92
|
+
return coerced;
|
|
93
|
+
}
|
|
94
|
+
// If case-insensitive, map back to original keys from schema
|
|
95
|
+
return this.mapToOriginalKeys(coerced, schemaMap);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Adds a value to the coerced object, handling collisions when multiple
|
|
99
|
+
* values exist for the same key (e.g., duplicate headers with different casing).
|
|
100
|
+
* Preserves all values as arrays when collisions occur to prevent data loss.
|
|
101
|
+
*/
|
|
102
|
+
addValueToCoerced(coerced, key, value, expectsArray) {
|
|
103
|
+
const existing = coerced[key];
|
|
104
|
+
const newValue = this.coerceValueStructure(value, expectsArray);
|
|
105
|
+
if (existing === undefined) {
|
|
106
|
+
coerced[key] = newValue;
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// Merge existing and new values
|
|
110
|
+
const existingArray = Array.isArray(existing) ? existing : [existing];
|
|
111
|
+
const newArray = Array.isArray(newValue) ? newValue : [newValue];
|
|
112
|
+
const merged = [...existingArray, ...newArray];
|
|
113
|
+
// If schema expects a single value but we have multiple, preserve as array
|
|
114
|
+
// to avoid data loss (validation will catch this later)
|
|
115
|
+
coerced[key] = expectsArray || merged.length > 1 ? merged : merged[0];
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Coerces a value's structure to match schema expectations.
|
|
119
|
+
* Wraps single values in arrays when schema expects array type,
|
|
120
|
+
* unwraps single-element arrays when schema expects single value.
|
|
121
|
+
*/
|
|
122
|
+
coerceValueStructure(value, expectsArray) {
|
|
123
|
+
if (expectsArray && !Array.isArray(value)) {
|
|
124
|
+
return [value];
|
|
125
|
+
}
|
|
126
|
+
if (!expectsArray && Array.isArray(value) && value.length === 1) {
|
|
127
|
+
return value[0];
|
|
128
|
+
}
|
|
129
|
+
return value;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Maps normalized (lowercase) keys back to their original casing as defined in the schema.
|
|
133
|
+
* Used for case-insensitive matching where the output should preserve schema-defined casing.
|
|
134
|
+
*/
|
|
135
|
+
mapToOriginalKeys(coerced, schemaMap) {
|
|
136
|
+
const withOriginalKeys = {};
|
|
137
|
+
for (const [key, value] of Object.entries(coerced)) {
|
|
138
|
+
const originalKey = schemaMap.get(key)?.originalKey ?? key;
|
|
139
|
+
withOriginalKeys[originalKey] = value;
|
|
140
|
+
}
|
|
141
|
+
return withOriginalKeys;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Coerces header data to match schema expectations with case-insensitive matching.
|
|
145
|
+
*
|
|
146
|
+
* @param header - The header object to coerce
|
|
147
|
+
* @param shape - The Zod schema shape for headers
|
|
148
|
+
* @returns Coerced header object
|
|
149
|
+
*/
|
|
150
|
+
coerceHeaderToSchema(header, shape) {
|
|
151
|
+
if (typeof header !== "object" || header === null) {
|
|
152
|
+
return this.coerceToSchema(header ?? {}, shape, false);
|
|
153
|
+
}
|
|
154
|
+
const preprocessed = this.splitCommaDelimitedValues(header, shape);
|
|
155
|
+
return this.coerceToSchema(preprocessed, shape, false);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Splits comma-separated header strings into arrays per RFC 7230.
|
|
159
|
+
* Only applies to fields where the schema expects an array type.
|
|
160
|
+
* Values that are already arrays pass through unchanged.
|
|
161
|
+
*/
|
|
162
|
+
splitCommaDelimitedValues(header, shape) {
|
|
163
|
+
const schemaMap = this.analyzeSchema(shape, false);
|
|
164
|
+
const result = {};
|
|
165
|
+
for (const [key, value] of Object.entries(header)) {
|
|
166
|
+
const schemaInfo = schemaMap.get(key.toLowerCase());
|
|
167
|
+
if (schemaInfo?.isArray && typeof value === "string") {
|
|
168
|
+
result[key] = value.split(",").map((v) => v.trim()).filter((v) => v !== "");
|
|
169
|
+
} else {
|
|
170
|
+
result[key] = value;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return result;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Coerces query data to match schema expectations with case-sensitive matching.
|
|
177
|
+
*
|
|
178
|
+
* @param query - The query object to coerce
|
|
179
|
+
* @param shape - The Zod schema shape for query parameters
|
|
180
|
+
* @returns Coerced query object
|
|
181
|
+
*/
|
|
182
|
+
coerceQueryToSchema(query, shape) {
|
|
183
|
+
return this.coerceToSchema(query ?? {}, shape, true);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function assert(value: unknown, message?: string): asserts value;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file was automatically generated by typeweaver.
|
|
3
|
+
* DO NOT EDIT. Instead, modify the source definition file and generate again.
|
|
4
|
+
*
|
|
5
|
+
* @generated by @rexeus/typeweaver
|
|
6
|
+
*/
|
|
7
|
+
export function assert(value, message) {
|
|
8
|
+
if (!value) {
|
|
9
|
+
throw new Error(message || "Assertion failed");
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* This file was automatically generated by typeweaver.
|
|
4
4
|
* DO NOT EDIT. Instead, modify the source definition file and generate again.
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
6
|
* @generated by @rexeus/typeweaver
|
|
7
7
|
*/
|
|
8
8
|
|
|
@@ -13,8 +13,11 @@ import {
|
|
|
13
13
|
<%= ownResponse.name %>Response,
|
|
14
14
|
<% } %>
|
|
15
15
|
} from "<%= responseFile %>";
|
|
16
|
-
<% for (const
|
|
17
|
-
|
|
16
|
+
<% for (const sharedError of sharedErrorResponses) { %>
|
|
17
|
+
import { <%= sharedError.name %>Response } from "<%= sharedError.path %>";
|
|
18
|
+
<% } %>
|
|
19
|
+
<% for (const entityError of entityErrorResponses) { %>
|
|
20
|
+
import { <%= entityError.name %>Response } from "<%= entityError.path %>";
|
|
18
21
|
<% } %>
|
|
19
22
|
|
|
20
23
|
<% if (headerTsType) { %>
|
|
@@ -47,6 +50,10 @@ export type I<%= pascalCaseOperationId %>Request = {
|
|
|
47
50
|
<% } else if (!hasErrorResponses) { %>
|
|
48
51
|
export type Successful<%= pascalCaseOperationId %>Response = <%= pascalCaseOperationId %>Response;
|
|
49
52
|
<% } else { %>
|
|
50
|
-
export type Successful<%= pascalCaseOperationId %>Response = Exclude<<%= pascalCaseOperationId %>Response, <%= [
|
|
53
|
+
export type Successful<%= pascalCaseOperationId %>Response = Exclude<<%= pascalCaseOperationId %>Response, <%= [
|
|
54
|
+
...sharedErrorResponses,
|
|
55
|
+
...ownErrorResponses,
|
|
56
|
+
...entityErrorResponses,
|
|
57
|
+
].map(({ name }) => `${name}Response`).join(" | ") %>
|
|
51
58
|
>;
|
|
52
59
|
<% } %>
|
|
@@ -2,13 +2,16 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* This file was automatically generated by typeweaver.
|
|
4
4
|
* DO NOT EDIT. Instead, modify the source definition file and generate again.
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
6
|
* @generated by @rexeus/typeweaver
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { HttpResponse, HttpStatusCode } from "<%= coreDir %>";
|
|
10
|
-
<% for(const
|
|
11
|
-
import type { I<%=
|
|
10
|
+
<% for (const shared of sharedResponses) { %>
|
|
11
|
+
import type { I<%= shared.name %>Response, <%= shared.name %>Response } from "<%= shared.path %>";
|
|
12
|
+
<% } %>
|
|
13
|
+
<% for(const entityResponse of entityResponses) { %>
|
|
14
|
+
import type { I<%= entityResponse.name %>Response, <%= entityResponse.name %>Response } from "<%= entityResponse.path %>";
|
|
12
15
|
<% } %>
|
|
13
16
|
|
|
14
17
|
<% for (const ownResponse of ownResponses) { %>
|
|
@@ -73,14 +76,20 @@ export type I<%= pascalCaseOperationId %>Response =
|
|
|
73
76
|
<% for (const ownResponse of ownResponses) { %>
|
|
74
77
|
| I<%= ownResponse.name %>Response
|
|
75
78
|
<% } %>
|
|
76
|
-
<% for (const
|
|
77
|
-
| I<%=
|
|
79
|
+
<% for (const shared of sharedResponses) { %>
|
|
80
|
+
| I<%= shared.name %>Response
|
|
81
|
+
<% } %>
|
|
82
|
+
<% for (const entityResponse of entityResponses) { %>
|
|
83
|
+
| I<%= entityResponse.name %>Response
|
|
78
84
|
<% } %>;
|
|
79
85
|
|
|
80
86
|
export type <%= pascalCaseOperationId %>Response =
|
|
81
87
|
<% for (const ownResponse of ownResponses) { %>
|
|
82
88
|
| <%= ownResponse.name %>Response
|
|
83
89
|
<% } %>
|
|
84
|
-
<% for (const
|
|
85
|
-
| <%=
|
|
90
|
+
<% for (const shared of sharedResponses) { %>
|
|
91
|
+
| <%= shared.name %>Response
|
|
92
|
+
<% } %>
|
|
93
|
+
<% for (const entityResponse of entityResponses) { %>
|
|
94
|
+
| <%= entityResponse.name %>Response
|
|
86
95
|
<% } %>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rexeus/typeweaver-types",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.5",
|
|
4
4
|
"description": "Generates request and response types plus validators aligned with your API contract. Powered by Typeweaver 🧵✨",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -47,22 +47,23 @@
|
|
|
47
47
|
},
|
|
48
48
|
"homepage": "https://github.com/rexeus/typeweaver#readme",
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@rexeus/typeweaver-core": "^0.6.
|
|
51
|
-
"@rexeus/typeweaver-gen": "^0.6.
|
|
50
|
+
"@rexeus/typeweaver-core": "^0.6.5",
|
|
51
|
+
"@rexeus/typeweaver-gen": "^0.6.5"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
+
"oxc-transform": "^0.115.0",
|
|
54
55
|
"test-utils": "file:../test-utils",
|
|
55
|
-
"@rexeus/typeweaver-
|
|
56
|
-
"@rexeus/typeweaver-
|
|
56
|
+
"@rexeus/typeweaver-core": "^0.6.5",
|
|
57
|
+
"@rexeus/typeweaver-gen": "^0.6.5"
|
|
57
58
|
},
|
|
58
59
|
"dependencies": {
|
|
59
60
|
"case": "^1.6.3",
|
|
60
|
-
"@rexeus/typeweaver-zod-to-ts": "^0.6.
|
|
61
|
+
"@rexeus/typeweaver-zod-to-ts": "^0.6.5"
|
|
61
62
|
},
|
|
62
63
|
"scripts": {
|
|
63
64
|
"typecheck": "tsc --noEmit",
|
|
64
65
|
"format": "oxfmt",
|
|
65
|
-
"build": "tsdown && mkdir -p ./dist/templates ./dist/lib && cp -r ./src/templates/* ./dist/templates/ && cp -
|
|
66
|
+
"build": "tsdown && mkdir -p ./dist/templates ./dist/lib && cp -r ./src/templates/* ./dist/templates/ && node scripts/compile-lib.mjs && cp src/lib-declarations/*.d.ts dist/lib/ && cp src/lib/index.ts dist/lib/ && cp ../../LICENSE ../../NOTICE ./dist/",
|
|
66
67
|
"test": "vitest --run",
|
|
67
68
|
"preversion": "npm run build"
|
|
68
69
|
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This file was automatically generated by typeweaver.
|
|
3
|
-
* DO NOT EDIT. Instead, modify the source definition file and generate again.
|
|
4
|
-
*
|
|
5
|
-
* @generated by @rexeus/typeweaver
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type {
|
|
9
|
-
IHttpRequest,
|
|
10
|
-
IRequestValidator,
|
|
11
|
-
SafeRequestValidationResult,
|
|
12
|
-
} from "@rexeus/typeweaver-core";
|
|
13
|
-
import { Validator } from "./Validator";
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Abstract base class for HTTP request validation.
|
|
17
|
-
*
|
|
18
|
-
* This class provides the foundation for request validators that:
|
|
19
|
-
* - Validate headers, body, query parameters, and path parameters
|
|
20
|
-
* - Support both safe (non-throwing) and unsafe (throwing) validation
|
|
21
|
-
* - Integrate with Zod schemas for runtime validation
|
|
22
|
-
* - Provide detailed error information for debugging
|
|
23
|
-
*
|
|
24
|
-
* Implementations should validate all request components and either:
|
|
25
|
-
* - Return validated data (for `validate`)
|
|
26
|
-
* - Return success/error result (for `safeValidate`)
|
|
27
|
-
*/
|
|
28
|
-
export abstract class RequestValidator
|
|
29
|
-
extends Validator
|
|
30
|
-
implements IRequestValidator
|
|
31
|
-
{
|
|
32
|
-
public constructor() {
|
|
33
|
-
super();
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Validates a request without throwing errors.
|
|
38
|
-
*
|
|
39
|
-
* @param request - The HTTP request to validate
|
|
40
|
-
* @returns A result object containing either the validated request or error details
|
|
41
|
-
*/
|
|
42
|
-
public abstract safeValidate(
|
|
43
|
-
request: IHttpRequest
|
|
44
|
-
): SafeRequestValidationResult<IHttpRequest>;
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Validates a request and throws if validation fails.
|
|
48
|
-
*
|
|
49
|
-
* @param request - The HTTP request to validate
|
|
50
|
-
* @returns The validated request with proper typing
|
|
51
|
-
* @throws {RequestValidationError} If any part of the request fails validation
|
|
52
|
-
*/
|
|
53
|
-
public abstract validate(request: IHttpRequest): IHttpRequest;
|
|
54
|
-
}
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This file was automatically generated by typeweaver.
|
|
3
|
-
* DO NOT EDIT. Instead, modify the source definition file and generate again.
|
|
4
|
-
*
|
|
5
|
-
* @generated by @rexeus/typeweaver
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type {
|
|
9
|
-
HttpBodySchema,
|
|
10
|
-
HttpHeaderSchema,
|
|
11
|
-
IHttpResponse,
|
|
12
|
-
IResponseValidator,
|
|
13
|
-
ResponseValidationError,
|
|
14
|
-
SafeResponseValidationResult,
|
|
15
|
-
} from "@rexeus/typeweaver-core";
|
|
16
|
-
import { Validator } from "./Validator";
|
|
17
|
-
import type { ZodSafeParseResult } from "zod";
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Abstract base class for HTTP response validation.
|
|
21
|
-
*
|
|
22
|
-
* This class provides the foundation for response validators that:
|
|
23
|
-
* - Validate response status codes match expected values
|
|
24
|
-
* - Validate response headers and body against schemas
|
|
25
|
-
* - Support both safe (non-throwing) and unsafe (throwing) validation
|
|
26
|
-
* - Integrate with Zod schemas for runtime validation
|
|
27
|
-
*
|
|
28
|
-
* Response validators are typically used in API clients to ensure
|
|
29
|
-
* responses match the expected format before processing.
|
|
30
|
-
*/
|
|
31
|
-
export abstract class ResponseValidator
|
|
32
|
-
extends Validator
|
|
33
|
-
implements IResponseValidator
|
|
34
|
-
{
|
|
35
|
-
/**
|
|
36
|
-
* Validates a response without throwing errors.
|
|
37
|
-
*
|
|
38
|
-
* @param response - The HTTP response to validate
|
|
39
|
-
* @returns A result object containing either the validated response or error details
|
|
40
|
-
*/
|
|
41
|
-
public abstract safeValidate(
|
|
42
|
-
response: IHttpResponse
|
|
43
|
-
): SafeResponseValidationResult<IHttpResponse>;
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Validates a response and throws if validation fails.
|
|
47
|
-
*
|
|
48
|
-
* @param response - The HTTP response to validate
|
|
49
|
-
* @returns The validated response with proper typing
|
|
50
|
-
* @throws {InvalidResponseStatusCodeError} If status code doesn't match expected
|
|
51
|
-
* @throws {ResponseValidationError} If response structure fails validation
|
|
52
|
-
*/
|
|
53
|
-
public abstract validate(response: IHttpResponse): IHttpResponse;
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Generic response validation method that validates header and body schemas.
|
|
57
|
-
* This method reduces code duplication across individual response validators.
|
|
58
|
-
*
|
|
59
|
-
* @param responseName - Name of the response type for error reporting
|
|
60
|
-
* @param headerSchema - Zod schema for header validation (optional)
|
|
61
|
-
* @param bodySchema - Zod schema for body validation (optional)
|
|
62
|
-
* @returns Function that validates response and returns result
|
|
63
|
-
*/
|
|
64
|
-
protected validateResponseType<Response extends IHttpResponse>(
|
|
65
|
-
responseName: string,
|
|
66
|
-
headerSchema: HttpHeaderSchema | undefined,
|
|
67
|
-
bodySchema: HttpBodySchema | undefined
|
|
68
|
-
): (
|
|
69
|
-
response: IHttpResponse,
|
|
70
|
-
error: ResponseValidationError
|
|
71
|
-
) => SafeResponseValidationResult<Response> {
|
|
72
|
-
return (response, error) => {
|
|
73
|
-
let isValid = true;
|
|
74
|
-
const validatedResponse: IHttpResponse = {
|
|
75
|
-
statusCode: response.statusCode,
|
|
76
|
-
header: undefined,
|
|
77
|
-
body: undefined,
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
if (bodySchema) {
|
|
81
|
-
const validateBodyResult = bodySchema.safeParse(
|
|
82
|
-
response.body
|
|
83
|
-
) as unknown as ZodSafeParseResult<Response["body"]>;
|
|
84
|
-
|
|
85
|
-
if (!validateBodyResult.success) {
|
|
86
|
-
error.addBodyIssues(responseName, validateBodyResult.error.issues);
|
|
87
|
-
isValid = false;
|
|
88
|
-
} else {
|
|
89
|
-
validatedResponse.body = validateBodyResult.data;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (headerSchema) {
|
|
94
|
-
const coercedHeader = this.coerceHeaderToSchema(
|
|
95
|
-
response.header,
|
|
96
|
-
this.getSchema(headerSchema)
|
|
97
|
-
);
|
|
98
|
-
const validateHeaderResult = headerSchema.safeParse(
|
|
99
|
-
coercedHeader
|
|
100
|
-
) as unknown as ZodSafeParseResult<Response["header"]>;
|
|
101
|
-
|
|
102
|
-
if (!validateHeaderResult.success) {
|
|
103
|
-
error.addHeaderIssues(
|
|
104
|
-
responseName,
|
|
105
|
-
validateHeaderResult.error.issues
|
|
106
|
-
);
|
|
107
|
-
isValid = false;
|
|
108
|
-
} else {
|
|
109
|
-
validatedResponse.header = validateHeaderResult.data;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (!isValid) {
|
|
114
|
-
return { isValid: false, error };
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return { isValid: true, data: validatedResponse as Response };
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
}
|