@efebia/fastify-zod-reply 1.2.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -30,6 +30,5 @@ declare module 'fastify' {
30
30
  declare const _default: import("fastify").FastifyPluginCallback<FastifyReplyPluginOptions, import("fastify").RawServerDefault, import("fastify").FastifyTypeProviderDefault, import("fastify").FastifyBaseLogger>;
31
31
  export default _default;
32
32
  export * from './error.js';
33
- export * from './route.js';
34
33
  export * from './routeV4.js';
35
34
  export * from './types.js';
package/lib/cjs/index.js CHANGED
@@ -25,7 +25,7 @@ const defaultOptions = {
25
25
  ok: { statusCode: 200, payload: { message: 'ok' } },
26
26
  created: { statusCode: 201, payload: { message: 'created' } },
27
27
  accepted: { statusCode: 202, payload: { message: 'accepted' } },
28
- noContent: { statusCode: 204, payload: { message: 'noContent' } },
28
+ noContent: { statusCode: 204, payload: undefined },
29
29
  badRequest: { statusCode: 400, payload: { message: 'badRequest' } },
30
30
  unauthorized: { statusCode: 401, payload: { message: 'unauthorized' } },
31
31
  forbidden: { statusCode: 403, payload: { message: 'forbidden' } },
@@ -45,6 +45,5 @@ exports.default = (0, fastify_plugin_1.default)(async (fastify, opts) => {
45
45
  name: '@efebia/fastify-zod-reply'
46
46
  });
47
47
  __exportStar(require("./error.js"), exports);
48
- __exportStar(require("./route.js"), exports);
49
48
  __exportStar(require("./routeV4.js"), exports);
50
49
  __exportStar(require("./types.js"), exports);
@@ -30,6 +30,5 @@ declare module 'fastify' {
30
30
  declare const _default: import("fastify").FastifyPluginCallback<FastifyReplyPluginOptions, import("fastify").RawServerDefault, import("fastify").FastifyTypeProviderDefault, import("fastify").FastifyBaseLogger>;
31
31
  export default _default;
32
32
  export * from './error.js';
33
- export * from './route.js';
34
33
  export * from './routeV4.js';
35
34
  export * from './types.js';
package/lib/esm/index.js CHANGED
@@ -6,7 +6,7 @@ const defaultOptions = {
6
6
  ok: { statusCode: 200, payload: { message: 'ok' } },
7
7
  created: { statusCode: 201, payload: { message: 'created' } },
8
8
  accepted: { statusCode: 202, payload: { message: 'accepted' } },
9
- noContent: { statusCode: 204, payload: { message: 'noContent' } },
9
+ noContent: { statusCode: 204, payload: undefined },
10
10
  badRequest: { statusCode: 400, payload: { message: 'badRequest' } },
11
11
  unauthorized: { statusCode: 401, payload: { message: 'unauthorized' } },
12
12
  forbidden: { statusCode: 403, payload: { message: 'forbidden' } },
@@ -26,6 +26,5 @@ export default fp(async (fastify, opts) => {
26
26
  name: '@efebia/fastify-zod-reply'
27
27
  });
28
28
  export * from './error.js';
29
- export * from './route.js';
30
29
  export * from './routeV4.js';
31
30
  export * from './types.js';
package/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "@efebia/fastify-zod-reply",
3
- "version": "1.2.2",
3
+ "version": "1.3.0",
4
4
  "license": "MIT",
5
5
  "dependencies": {
6
6
  "fastify": "^5.3.0",
7
7
  "fastify-plugin": "^5.0.1",
8
- "zod": "^3.25.47",
9
- "zod-to-json-schema": "^3.24.5"
8
+ "zod": "^4.1.8"
10
9
  },
11
10
  "files": [
12
11
  "/lib"
@@ -1,31 +0,0 @@
1
- import { z } from 'zod';
2
- import { APIHandler, APIOptions, RouteSecurity, RouteTag } from './types.js';
3
- export type BaseZodSchema = {
4
- Body?: z.ZodTypeAny;
5
- Params?: z.ZodTypeAny;
6
- Query?: z.ZodTypeAny;
7
- Headers?: z.ZodTypeAny;
8
- Reply: z.AnyZodObject;
9
- Security?: (RouteSecurity[keyof RouteSecurity])[];
10
- Tags?: (keyof RouteTag)[];
11
- };
12
- export type FastifyZodSchema<TZodSchema extends BaseZodSchema> = {
13
- Body: TZodSchema['Body'] extends z.ZodTypeAny ? z.output<TZodSchema['Body']> : undefined;
14
- Params: TZodSchema['Params'] extends z.ZodTypeAny ? z.output<TZodSchema['Params']> : undefined;
15
- Querystring: TZodSchema['Query'] extends z.ZodTypeAny ? z.output<TZodSchema['Query']> : undefined;
16
- Reply: TZodSchema['Reply'] extends z.ZodTypeAny ? z.input<TZodSchema['Reply']>[keyof z.infer<TZodSchema['Reply']>] : undefined;
17
- };
18
- export type RouteOptions = {
19
- strict?: boolean | {
20
- body: boolean;
21
- query: boolean;
22
- params: boolean;
23
- headers: boolean;
24
- };
25
- };
26
- export declare const createRoute: ({ strict: globalStrict }?: RouteOptions) => <TSchema extends BaseZodSchema, FastifySchema extends FastifyZodSchema<TSchema> = FastifyZodSchema<TSchema>>(schema: TSchema, handler: APIHandler<FastifySchema>, options?: RouteOptions) => APIOptions<FastifySchema> & {
27
- handler: APIHandler<FastifySchema>;
28
- };
29
- export declare const route: <TSchema extends BaseZodSchema, FastifySchema extends FastifyZodSchema<TSchema> = FastifyZodSchema<TSchema>>(schema: TSchema, handler: APIHandler<FastifySchema>, options?: RouteOptions) => APIOptions<FastifySchema> & {
30
- handler: APIHandler<FastifySchema>;
31
- };
package/lib/cjs/route.js DELETED
@@ -1,85 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.route = exports.createRoute = void 0;
4
- const zod_to_json_schema_1 = require("zod-to-json-schema");
5
- const error_js_1 = require("./error.js");
6
- const mapZodError = (zodError, prefix) => {
7
- return zodError.issues.map(issue => {
8
- const pathStr = `Error at ${prefix}->${issue.path.join('->')}`;
9
- return issue.message ? `${pathStr}->${issue.message}` : pathStr;
10
- }).join('\n');
11
- };
12
- const parse = async (schema, payload, tag) => {
13
- const result = await schema.safeParseAsync(payload);
14
- return Object.assign(Object.assign({}, result), { tag });
15
- };
16
- const findStatusCode = (statusCode, availableStatusCodes) => {
17
- return availableStatusCodes.find(([key]) => {
18
- if (!['number', 'string'].includes(typeof key))
19
- return false;
20
- if (typeof key === 'number')
21
- return statusCode === key;
22
- if (/^[0-9]{3}$/.test(key))
23
- return statusCode === parseInt(key);
24
- if (/^[0-9]xx$/i.test(key))
25
- return statusCode.toString()[0] === key[0];
26
- });
27
- };
28
- const strictifySchema = (schema, strict) => {
29
- if (!strict)
30
- return schema;
31
- return 'strict' in schema && typeof schema['strict'] === 'function' ? schema.strict() : schema;
32
- };
33
- const parseStrict = (tag, value) => {
34
- if (typeof value === 'boolean')
35
- return value;
36
- return value[tag];
37
- };
38
- const createRoute = ({ strict: globalStrict = false } = {}) => (schema, handler, options) => {
39
- const strict = typeof (options === null || options === void 0 ? void 0 : options.strict) !== 'undefined' ? options === null || options === void 0 ? void 0 : options.strict : globalStrict;
40
- const finalResult = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (schema.Body && { body: (0, zod_to_json_schema_1.zodToJsonSchema)(strictifySchema(schema.Body, parseStrict('body', strict)), { $refStrategy: 'none', removeAdditionalStrategy: 'strict', allowedAdditionalProperties: undefined }) })), (schema.Params && { params: (0, zod_to_json_schema_1.zodToJsonSchema)(strictifySchema(schema.Params, parseStrict('params', strict)), { $refStrategy: 'none', removeAdditionalStrategy: 'strict', allowedAdditionalProperties: undefined }) })), (schema.Query && { querystring: (0, zod_to_json_schema_1.zodToJsonSchema)(strictifySchema(schema.Query, parseStrict('query', strict)), { $refStrategy: 'none', removeAdditionalStrategy: 'strict', allowedAdditionalProperties: undefined }) })), (schema.Headers && { headers: (0, zod_to_json_schema_1.zodToJsonSchema)(strictifySchema(schema.Headers, parseStrict('headers', strict)), { $refStrategy: 'none', removeAdditionalStrategy: 'strict', allowedAdditionalProperties: undefined }) })), { response: (0, zod_to_json_schema_1.zodToJsonSchema)(schema.Reply.partial(), {
41
- $refStrategy: 'none',
42
- strictUnions: true,
43
- })['properties'] }), (schema.Security && { security: schema.Security })), (schema.Tags && { tags: schema.Tags }));
44
- return {
45
- schema: finalResult,
46
- handler,
47
- preHandler: async (request, reply) => {
48
- var _a, _b, _c;
49
- const results = await Promise.all([
50
- ...(schema.Body ? [parse(schema.Body, request.body, 'body')] : []),
51
- ...(schema.Params ? [parse(schema.Params, request.params, 'params')] : []),
52
- ...(schema.Query ? [parse(schema.Query, request.query, 'query')] : []),
53
- ]);
54
- for (const result of results) {
55
- if (!result.success) {
56
- return reply
57
- .code(400)
58
- .type('application/json')
59
- .send({
60
- message: mapZodError(result.error, result.tag),
61
- });
62
- }
63
- }
64
- request.body = ((_a = results.find(r => r.tag === 'body')) === null || _a === void 0 ? void 0 : _a.data) || {};
65
- request.params = ((_b = results.find(r => r.tag === 'params')) === null || _b === void 0 ? void 0 : _b.data) || {};
66
- request.query = ((_c = results.find(r => r.tag === 'query')) === null || _c === void 0 ? void 0 : _c.data) || {};
67
- },
68
- preSerialization: (request, reply, payload, done) => {
69
- const foundSchema = findStatusCode(reply.statusCode, Object.entries(schema.Reply.shape));
70
- if (!foundSchema) {
71
- if (reply.statusCode >= 400)
72
- return done(null, payload);
73
- request.log.warn(`[@efebia/fastify-zod-reply]: Reply schema of: ${request.routeOptions.url} does not have the specified status code: ${reply.statusCode}.`);
74
- return done(new error_js_1.FastifyZodReplyError(`Reply schema of: ${request.routeOptions.url} does not have the specified status code: ${reply.statusCode}.`, 500));
75
- }
76
- const serialized = foundSchema[1].safeParse(payload);
77
- if (serialized.success) {
78
- return done(null, serialized.data);
79
- }
80
- return done(new error_js_1.FastifyZodReplyError(mapZodError(serialized.error, 'reply'), 500));
81
- },
82
- };
83
- };
84
- exports.createRoute = createRoute;
85
- exports.route = (0, exports.createRoute)({ strict: false });
@@ -1,31 +0,0 @@
1
- import { z } from 'zod';
2
- import { APIHandler, APIOptions, RouteSecurity, RouteTag } from './types.js';
3
- export type BaseZodSchema = {
4
- Body?: z.ZodTypeAny;
5
- Params?: z.ZodTypeAny;
6
- Query?: z.ZodTypeAny;
7
- Headers?: z.ZodTypeAny;
8
- Reply: z.AnyZodObject;
9
- Security?: (RouteSecurity[keyof RouteSecurity])[];
10
- Tags?: (keyof RouteTag)[];
11
- };
12
- export type FastifyZodSchema<TZodSchema extends BaseZodSchema> = {
13
- Body: TZodSchema['Body'] extends z.ZodTypeAny ? z.output<TZodSchema['Body']> : undefined;
14
- Params: TZodSchema['Params'] extends z.ZodTypeAny ? z.output<TZodSchema['Params']> : undefined;
15
- Querystring: TZodSchema['Query'] extends z.ZodTypeAny ? z.output<TZodSchema['Query']> : undefined;
16
- Reply: TZodSchema['Reply'] extends z.ZodTypeAny ? z.input<TZodSchema['Reply']>[keyof z.infer<TZodSchema['Reply']>] : undefined;
17
- };
18
- export type RouteOptions = {
19
- strict?: boolean | {
20
- body: boolean;
21
- query: boolean;
22
- params: boolean;
23
- headers: boolean;
24
- };
25
- };
26
- export declare const createRoute: ({ strict: globalStrict }?: RouteOptions) => <TSchema extends BaseZodSchema, FastifySchema extends FastifyZodSchema<TSchema> = FastifyZodSchema<TSchema>>(schema: TSchema, handler: APIHandler<FastifySchema>, options?: RouteOptions) => APIOptions<FastifySchema> & {
27
- handler: APIHandler<FastifySchema>;
28
- };
29
- export declare const route: <TSchema extends BaseZodSchema, FastifySchema extends FastifyZodSchema<TSchema> = FastifyZodSchema<TSchema>>(schema: TSchema, handler: APIHandler<FastifySchema>, options?: RouteOptions) => APIOptions<FastifySchema> & {
30
- handler: APIHandler<FastifySchema>;
31
- };
package/lib/esm/route.js DELETED
@@ -1,81 +0,0 @@
1
- import { zodToJsonSchema } from 'zod-to-json-schema';
2
- import { FastifyZodReplyError } from './error.js';
3
- const mapZodError = (zodError, prefix) => {
4
- return zodError.issues.map(issue => {
5
- const pathStr = `Error at ${prefix}->${issue.path.join('->')}`;
6
- return issue.message ? `${pathStr}->${issue.message}` : pathStr;
7
- }).join('\n');
8
- };
9
- const parse = async (schema, payload, tag) => {
10
- const result = await schema.safeParseAsync(payload);
11
- return Object.assign(Object.assign({}, result), { tag });
12
- };
13
- const findStatusCode = (statusCode, availableStatusCodes) => {
14
- return availableStatusCodes.find(([key]) => {
15
- if (!['number', 'string'].includes(typeof key))
16
- return false;
17
- if (typeof key === 'number')
18
- return statusCode === key;
19
- if (/^[0-9]{3}$/.test(key))
20
- return statusCode === parseInt(key);
21
- if (/^[0-9]xx$/i.test(key))
22
- return statusCode.toString()[0] === key[0];
23
- });
24
- };
25
- const strictifySchema = (schema, strict) => {
26
- if (!strict)
27
- return schema;
28
- return 'strict' in schema && typeof schema['strict'] === 'function' ? schema.strict() : schema;
29
- };
30
- const parseStrict = (tag, value) => {
31
- if (typeof value === 'boolean')
32
- return value;
33
- return value[tag];
34
- };
35
- export const createRoute = ({ strict: globalStrict = false } = {}) => (schema, handler, options) => {
36
- const strict = typeof (options === null || options === void 0 ? void 0 : options.strict) !== 'undefined' ? options === null || options === void 0 ? void 0 : options.strict : globalStrict;
37
- const finalResult = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (schema.Body && { body: zodToJsonSchema(strictifySchema(schema.Body, parseStrict('body', strict)), { $refStrategy: 'none', removeAdditionalStrategy: 'strict', allowedAdditionalProperties: undefined }) })), (schema.Params && { params: zodToJsonSchema(strictifySchema(schema.Params, parseStrict('params', strict)), { $refStrategy: 'none', removeAdditionalStrategy: 'strict', allowedAdditionalProperties: undefined }) })), (schema.Query && { querystring: zodToJsonSchema(strictifySchema(schema.Query, parseStrict('query', strict)), { $refStrategy: 'none', removeAdditionalStrategy: 'strict', allowedAdditionalProperties: undefined }) })), (schema.Headers && { headers: zodToJsonSchema(strictifySchema(schema.Headers, parseStrict('headers', strict)), { $refStrategy: 'none', removeAdditionalStrategy: 'strict', allowedAdditionalProperties: undefined }) })), { response: zodToJsonSchema(schema.Reply.partial(), {
38
- $refStrategy: 'none',
39
- strictUnions: true,
40
- })['properties'] }), (schema.Security && { security: schema.Security })), (schema.Tags && { tags: schema.Tags }));
41
- return {
42
- schema: finalResult,
43
- handler,
44
- preHandler: async (request, reply) => {
45
- var _a, _b, _c;
46
- const results = await Promise.all([
47
- ...(schema.Body ? [parse(schema.Body, request.body, 'body')] : []),
48
- ...(schema.Params ? [parse(schema.Params, request.params, 'params')] : []),
49
- ...(schema.Query ? [parse(schema.Query, request.query, 'query')] : []),
50
- ]);
51
- for (const result of results) {
52
- if (!result.success) {
53
- return reply
54
- .code(400)
55
- .type('application/json')
56
- .send({
57
- message: mapZodError(result.error, result.tag),
58
- });
59
- }
60
- }
61
- request.body = ((_a = results.find(r => r.tag === 'body')) === null || _a === void 0 ? void 0 : _a.data) || {};
62
- request.params = ((_b = results.find(r => r.tag === 'params')) === null || _b === void 0 ? void 0 : _b.data) || {};
63
- request.query = ((_c = results.find(r => r.tag === 'query')) === null || _c === void 0 ? void 0 : _c.data) || {};
64
- },
65
- preSerialization: (request, reply, payload, done) => {
66
- const foundSchema = findStatusCode(reply.statusCode, Object.entries(schema.Reply.shape));
67
- if (!foundSchema) {
68
- if (reply.statusCode >= 400)
69
- return done(null, payload);
70
- request.log.warn(`[@efebia/fastify-zod-reply]: Reply schema of: ${request.routeOptions.url} does not have the specified status code: ${reply.statusCode}.`);
71
- return done(new FastifyZodReplyError(`Reply schema of: ${request.routeOptions.url} does not have the specified status code: ${reply.statusCode}.`, 500));
72
- }
73
- const serialized = foundSchema[1].safeParse(payload);
74
- if (serialized.success) {
75
- return done(null, serialized.data);
76
- }
77
- return done(new FastifyZodReplyError(mapZodError(serialized.error, 'reply'), 500));
78
- },
79
- };
80
- };
81
- export const route = createRoute({ strict: false });