@bram-dc/fastify-type-provider-zod 3.1.1 → 3.1.2

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,3 +1,6 @@
1
+ ## Please use the original package [fastify-type-provider-zod](https://www.npmjs.com/package/fastify-type-provider-zod)
2
+ This repository is no longer maintained since all the changed have been merged into the original package.
3
+
1
4
  # Fastify Type Provider Zod
2
5
 
3
6
  [![NPM Version](https://img.shields.io/npm/v/@bram-dc/fastify-type-provider-zod.svg)](https://www.npmjs.com/package/@bram-dc/fastify-type-provider-zod)
@@ -0,0 +1,10 @@
1
+ import type { z, ZodIssue } from 'zod';
2
+ export type ResponseValidationErrorDetails = {
3
+ error: ZodIssue[];
4
+ method: string;
5
+ url: string;
6
+ };
7
+ export declare class ResponseValidationError extends Error {
8
+ details: ResponseValidationErrorDetails;
9
+ constructor(validationResult: z.SafeParseReturnType<unknown, unknown>, method: string, url: string);
10
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ResponseValidationError = void 0;
4
+ class ResponseValidationError extends Error {
5
+ constructor(validationResult, method, url) {
6
+ super("Response doesn't match the schema");
7
+ this.name = 'ResponseValidationError';
8
+ this.details = {
9
+ error: validationResult.error?.issues ?? [],
10
+ method,
11
+ url,
12
+ };
13
+ }
14
+ }
15
+ exports.ResponseValidationError = ResponseValidationError;
@@ -0,0 +1,78 @@
1
+ import type { FastifyPluginAsync, FastifyPluginCallback, FastifyPluginOptions, FastifySchema, FastifySchemaCompiler, FastifyTypeProvider, RawServerBase, RawServerDefault } from 'fastify';
2
+ import type { FastifySerializerCompiler } from 'fastify/types/schema';
3
+ import type { OpenAPIV2, OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';
4
+ import type { z } from 'zod';
5
+ type FreeformRecord = Record<string, any>;
6
+ export interface ZodTypeProvider extends FastifyTypeProvider {
7
+ validator: this['schema'] extends z.ZodTypeAny ? z.output<this['schema']> : unknown;
8
+ serializer: this['schema'] extends z.ZodTypeAny ? z.input<this['schema']> : unknown;
9
+ }
10
+ interface Schema extends FastifySchema {
11
+ hide?: boolean;
12
+ }
13
+ export declare const createJsonSchemaTransform: ({ skipList }: {
14
+ skipList: readonly string[];
15
+ }) => ({ schema, url }: {
16
+ schema: Schema;
17
+ url: string;
18
+ }) => {
19
+ schema: Schema;
20
+ url: string;
21
+ } | {
22
+ schema: FreeformRecord;
23
+ url: string;
24
+ };
25
+ export declare const jsonSchemaTransform: ({ schema, url }: {
26
+ schema: Schema;
27
+ url: string;
28
+ }) => {
29
+ schema: Schema;
30
+ url: string;
31
+ } | {
32
+ schema: FreeformRecord;
33
+ url: string;
34
+ };
35
+ export declare const createJsonSchemaTransformObject: ({ schemas }: {
36
+ schemas: Record<string, z.ZodTypeAny>;
37
+ }) => (input: {
38
+ swaggerObject: Partial<OpenAPIV2.Document>;
39
+ } | {
40
+ openapiObject: Partial<OpenAPIV3.Document | OpenAPIV3_1.Document>;
41
+ }) => any;
42
+ export declare const validatorCompiler: FastifySchemaCompiler<z.ZodTypeAny>;
43
+ type ReplacerFunction = (this: any, key: string, value: any) => any;
44
+ type ZodSerializerCompilerOptions = {
45
+ replacer?: ReplacerFunction;
46
+ };
47
+ export declare const createSerializerCompiler: (options?: ZodSerializerCompilerOptions) => FastifySerializerCompiler<z.ZodTypeAny | {
48
+ properties: z.ZodTypeAny;
49
+ }>;
50
+ export declare const serializerCompiler: FastifySerializerCompiler<z.ZodTypeAny | {
51
+ properties: z.ZodTypeAny;
52
+ }>;
53
+ /**
54
+ * FastifyPluginCallbackZod with Zod automatic type inference
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * import { FastifyPluginCallbackZod } from "fastify-type-provider-zod"
59
+ *
60
+ * const plugin: FastifyPluginCallbackZod = (fastify, options, done) => {
61
+ * done()
62
+ * }
63
+ * ```
64
+ */
65
+ export type FastifyPluginCallbackZod<Options extends FastifyPluginOptions = Record<never, never>, Server extends RawServerBase = RawServerDefault> = FastifyPluginCallback<Options, Server, ZodTypeProvider>;
66
+ /**
67
+ * FastifyPluginAsyncZod with Zod automatic type inference
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * import { FastifyPluginAsyncZod } from "fastify-type-provider-zod"
72
+ *
73
+ * const plugin: FastifyPluginAsyncZod = async (fastify, options) => {
74
+ * }
75
+ * ```
76
+ */
77
+ export type FastifyPluginAsyncZod<Options extends FastifyPluginOptions = Record<never, never>, Server extends RawServerBase = RawServerDefault> = FastifyPluginAsync<Options, Server, ZodTypeProvider>;
78
+ export {};
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serializerCompiler = exports.createSerializerCompiler = exports.validatorCompiler = exports.createJsonSchemaTransformObject = exports.jsonSchemaTransform = exports.createJsonSchemaTransform = void 0;
4
+ const errors_1 = require("./errors");
5
+ const ref_1 = require("./ref");
6
+ const zod_to_json_1 = require("./zod-to-json");
7
+ const defaultSkipList = [
8
+ '/documentation/',
9
+ '/documentation/initOAuth',
10
+ '/documentation/json',
11
+ '/documentation/uiConfig',
12
+ '/documentation/yaml',
13
+ '/documentation/*',
14
+ '/documentation/static/*',
15
+ ];
16
+ const createJsonSchemaTransform = ({ skipList }) => {
17
+ return ({ schema, url }) => {
18
+ if (!schema) {
19
+ return {
20
+ schema,
21
+ url,
22
+ };
23
+ }
24
+ const { response, headers, querystring, body, params, hide, ...rest } = schema;
25
+ const transformed = {};
26
+ if (skipList.includes(url) || hide) {
27
+ transformed.hide = true;
28
+ return { schema: transformed, url };
29
+ }
30
+ const zodSchemas = { headers, querystring, body, params };
31
+ for (const prop in zodSchemas) {
32
+ const zodSchema = zodSchemas[prop];
33
+ if (zodSchema) {
34
+ transformed[prop] = (0, zod_to_json_1.convertZodToJsonSchema)(zodSchema);
35
+ }
36
+ }
37
+ if (response) {
38
+ transformed.response = {};
39
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
+ for (const prop in response) {
41
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
42
+ const schema = resolveSchema(response[prop]);
43
+ const transformedResponse = (0, zod_to_json_1.convertZodToJsonSchema)(schema);
44
+ transformed.response[prop] = transformedResponse;
45
+ }
46
+ }
47
+ for (const prop in rest) {
48
+ const meta = rest[prop];
49
+ if (meta) {
50
+ transformed[prop] = meta;
51
+ }
52
+ }
53
+ return { schema: transformed, url };
54
+ };
55
+ };
56
+ exports.createJsonSchemaTransform = createJsonSchemaTransform;
57
+ exports.jsonSchemaTransform = (0, exports.createJsonSchemaTransform)({
58
+ skipList: defaultSkipList,
59
+ });
60
+ const createJsonSchemaTransformObject = ({ schemas }) => (input) => {
61
+ if ('swaggerObject' in input) {
62
+ console.warn('This package currently does not support component references for Swagger 2.0');
63
+ return input.swaggerObject;
64
+ }
65
+ return (0, ref_1.resolveRefs)(input.openapiObject, schemas);
66
+ };
67
+ exports.createJsonSchemaTransformObject = createJsonSchemaTransformObject;
68
+ const validatorCompiler = ({ schema, method, url }) => (data) => {
69
+ const result = schema.safeParse(data);
70
+ if (result.error) {
71
+ return { error: (0, errors_1.createValidationError)(result.error, method, url) };
72
+ }
73
+ return { value: result.data };
74
+ };
75
+ exports.validatorCompiler = validatorCompiler;
76
+ function resolveSchema(maybeSchema) {
77
+ if ('safeParse' in maybeSchema) {
78
+ return maybeSchema;
79
+ }
80
+ if ('properties' in maybeSchema) {
81
+ return maybeSchema.properties;
82
+ }
83
+ throw new errors_1.InvalidSchemaError(JSON.stringify(maybeSchema));
84
+ }
85
+ const createSerializerCompiler = (options) => ({ schema: maybeSchema, method, url }) => (data) => {
86
+ const schema = resolveSchema(maybeSchema);
87
+ const result = schema.safeParse(data);
88
+ if (result.error) {
89
+ throw new errors_1.ResponseSerializationError(result.error, method, url);
90
+ }
91
+ return JSON.stringify(result.data, options?.replacer);
92
+ };
93
+ exports.createSerializerCompiler = createSerializerCompiler;
94
+ exports.serializerCompiler = (0, exports.createSerializerCompiler)({});
@@ -0,0 +1,18 @@
1
+ import type { FastifySchemaValidationError } from 'fastify/types/schema';
2
+ import type { ZodError } from 'zod';
3
+ declare const ResponseSerializationError_base: import("@fastify/error").FastifyErrorConstructor<{
4
+ code: string;
5
+ }, [{
6
+ cause: ZodError;
7
+ }]>;
8
+ export declare class ResponseSerializationError extends ResponseSerializationError_base {
9
+ cause: ZodError;
10
+ method: string;
11
+ url: string;
12
+ constructor(cause: ZodError, method: string, url: string);
13
+ }
14
+ export declare const InvalidSchemaError: import("@fastify/error").FastifyErrorConstructor<{
15
+ code: string;
16
+ }, [string]>;
17
+ export declare const createValidationError: (error: ZodError, method: string, url: string) => FastifySchemaValidationError[];
18
+ export {};
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createValidationError = exports.InvalidSchemaError = exports.ResponseSerializationError = void 0;
7
+ const error_1 = __importDefault(require("@fastify/error"));
8
+ class ResponseSerializationError extends (0, error_1.default)('FST_ERR_RESPONSE_SERIALIZATION', "Response doesn't match the schema", 500) {
9
+ constructor(cause, method, url) {
10
+ super({ cause });
11
+ this.cause = cause;
12
+ this.method = method;
13
+ this.url = url;
14
+ }
15
+ }
16
+ exports.ResponseSerializationError = ResponseSerializationError;
17
+ exports.InvalidSchemaError = (0, error_1.default)('FST_ERR_INVALID_SCHEMA', 'Invalid schema passed: %s', 500);
18
+ const createValidationError = (error, method, url) => error.errors.map((issue) => ({
19
+ keyword: issue.code,
20
+ instancePath: `/${issue.path.join('/')}`,
21
+ schemaPath: `#/${issue.path.join('/')}/${issue.code}`,
22
+ params: {
23
+ issue,
24
+ zodError: error,
25
+ method,
26
+ url,
27
+ },
28
+ message: error.message,
29
+ }));
30
+ exports.createValidationError = createValidationError;
@@ -0,0 +1,3 @@
1
+ import type { OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';
2
+ import type { z } from 'zod';
3
+ export declare const resolveRefs: (openapiObject: Partial<OpenAPIV3.Document | OpenAPIV3_1.Document>, zodSchemas: Record<string, z.ZodTypeAny>) => any;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveRefs = void 0;
4
+ const zod_to_json_1 = require("./zod-to-json");
5
+ const createComponentMap = (schemas) => {
6
+ const map = new Map();
7
+ Object.entries(schemas).forEach(([key, value]) => map.set(JSON.stringify(value), key));
8
+ return map;
9
+ };
10
+ const createComponentReplacer = (componentMapVK, schemasObject) =>
11
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
+ function componentReplacer(key, value) {
13
+ if (typeof value !== 'object')
14
+ return value;
15
+ // Check if the parent is the schemas object, if so, return the value as is. This is where the schemas are defined.
16
+ if (this === schemasObject)
17
+ return value;
18
+ const stringifiedValue = JSON.stringify(value);
19
+ if (componentMapVK.has(stringifiedValue))
20
+ return { $ref: `#/components/schemas/${componentMapVK.get(stringifiedValue)}` };
21
+ if (value.nullable === true) {
22
+ const nonNullableValue = { ...value };
23
+ delete nonNullableValue.nullable;
24
+ const stringifiedNonNullableValue = JSON.stringify(nonNullableValue);
25
+ if (componentMapVK.has(stringifiedNonNullableValue))
26
+ return {
27
+ anyOf: [
28
+ { $ref: `#/components/schemas/${componentMapVK.get(stringifiedNonNullableValue)}` },
29
+ ],
30
+ nullable: true,
31
+ };
32
+ }
33
+ return value;
34
+ };
35
+ const resolveRefs = (openapiObject, zodSchemas) => {
36
+ const schemas = {};
37
+ for (const key in zodSchemas) {
38
+ schemas[key] = (0, zod_to_json_1.convertZodToJsonSchema)(zodSchemas[key]);
39
+ }
40
+ const document = {
41
+ ...openapiObject,
42
+ components: {
43
+ ...openapiObject.components,
44
+ schemas: {
45
+ ...openapiObject.components?.schemas,
46
+ ...schemas,
47
+ },
48
+ },
49
+ };
50
+ const componentMapVK = createComponentMap(schemas);
51
+ const componentReplacer = createComponentReplacer(componentMapVK, document.components.schemas);
52
+ // Using the componentReplacer function we deep check if the document has any schemas that are the same as the zod schemas provided
53
+ // When a match is found replace them with a $ref.
54
+ return JSON.parse(JSON.stringify(document, componentReplacer));
55
+ };
56
+ exports.resolveRefs = resolveRefs;
@@ -0,0 +1,7 @@
1
+ import type { z } from 'zod';
2
+ export declare const convertZodToJsonSchema: (zodSchema: z.ZodTypeAny) => object & {
3
+ $schema?: string | undefined;
4
+ definitions?: {
5
+ [key: string]: object;
6
+ };
7
+ };
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.convertZodToJsonSchema = void 0;
4
+ const zod_to_json_schema_1 = require("zod-to-json-schema");
5
+ const zodToJsonSchemaOptions = {
6
+ target: 'openApi3',
7
+ $refStrategy: 'none',
8
+ };
9
+ const convertZodToJsonSchema = (zodSchema) => {
10
+ return (0, zod_to_json_schema_1.zodToJsonSchema)(zodSchema, zodToJsonSchemaOptions);
11
+ };
12
+ exports.convertZodToJsonSchema = convertZodToJsonSchema;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bram-dc/fastify-type-provider-zod",
3
- "version": "3.1.1",
3
+ "version": "3.1.2",
4
4
  "description": "Zod Type Provider for Fastify@5",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",