@a_jackie_z/fastify 1.0.1 → 1.1.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @a_jackie_z/fastify
2
2
 
3
- A collection of Fastify plugins and utilities for building robust web applications with built-in support for JWT authentication, rate limiting, Swagger documentation, and TypeBox validation.
3
+ A collection of Fastify plugins and utilities for building robust web applications with built-in support for JWT authentication, rate limiting, Swagger documentation, and Zod validation.
4
4
 
5
5
  ## Installation
6
6
 
@@ -14,7 +14,7 @@ npm install @a_jackie_z/fastify
14
14
 
15
15
  ```typescript
16
16
  import { createFastify, runFastify } from '@a_jackie_z/fastify'
17
- import { Type } from '@sinclair/typebox'
17
+ import { z } from 'zod'
18
18
 
19
19
  const app = await createFastify()
20
20
 
@@ -23,8 +23,8 @@ app.route({
23
23
  url: '/hello',
24
24
  schema: {
25
25
  response: {
26
- 200: Type.Object({
27
- message: Type.String(),
26
+ 200: z.object({
27
+ message: z.string(),
28
28
  }),
29
29
  },
30
30
  },
@@ -40,8 +40,8 @@ await runFastify(app, '0.0.0.0', 3000)
40
40
 
41
41
  - **JWT Authentication** - Built-in JWT support with global and route-level configuration
42
42
  - **Rate Limiting** - Global rate limiting for API protection
43
- - **Swagger Documentation** - Auto-generated API documentation with TypeBox schemas
44
- - **TypeBox Integration** - Type-safe request/response validation
43
+ - **Swagger Documentation** - Auto-generated API documentation with Zod schemas
44
+ - **Zod Integration** - Type-safe request/response validation
45
45
  - **Custom Logger Support** - Integrate any Fastify-compatible logger
46
46
  - **Health Check Plugin** - Ready-to-use health check endpoint
47
47
  - **Plugin Helper** - Utility for creating reusable Fastify plugins
@@ -52,7 +52,7 @@ await runFastify(app, '0.0.0.0', 3000)
52
52
 
53
53
  ```typescript
54
54
  import { createFastify, runFastify } from '@a_jackie_z/fastify'
55
- import { Type } from '@sinclair/typebox'
55
+ import { z } from 'zod'
56
56
 
57
57
  const app = await createFastify({
58
58
  // Optional: Integrate your logger
@@ -97,16 +97,16 @@ app.route({
97
97
  jwt: false, // Bypass JWT check for login
98
98
  },
99
99
  schema: {
100
- body: Type.Object({
101
- username: Type.String(),
102
- password: Type.String(),
100
+ body: z.object({
101
+ username: z.string(),
102
+ password: z.string(),
103
103
  }),
104
104
  response: {
105
- 200: Type.Object({
106
- token: Type.String(),
105
+ 200: z.object({
106
+ token: z.string(),
107
107
  }),
108
- 401: Type.Object({
109
- error: Type.String(),
108
+ 401: z.object({
109
+ error: z.string(),
110
110
  }),
111
111
  },
112
112
  },
@@ -140,8 +140,8 @@ app.route({
140
140
  },
141
141
  schema: {
142
142
  response: {
143
- 200: Type.Object({
144
- message: Type.String(),
143
+ 200: z.object({
144
+ message: z.string(),
145
145
  }),
146
146
  },
147
147
  },
@@ -160,9 +160,9 @@ app.route({
160
160
  // No config needed - global JWT setting applies
161
161
  schema: {
162
162
  response: {
163
- 200: Type.Object({
164
- message: Type.String(),
165
- user: Type.Unknown(),
163
+ 200: z.object({
164
+ message: z.string(),
165
+ user: z.unknown(),
166
166
  }),
167
167
  },
168
168
  },
@@ -191,12 +191,12 @@ app.route({
191
191
  },
192
192
  schema: {
193
193
  response: {
194
- 200: Type.Object({
195
- message: Type.String(),
194
+ 200: z.object({
195
+ message: z.string(),
196
196
  }),
197
- 403: Type.Object({
198
- error: Type.String(),
199
- message: Type.String(),
197
+ 403: z.object({
198
+ error: z.string(),
199
+ message: z.string(),
200
200
  }),
201
201
  },
202
202
  },
@@ -221,12 +221,12 @@ app.route({
221
221
  },
222
222
  },
223
223
  schema: {
224
- params: Type.Object({
225
- id: Type.String(),
224
+ params: z.object({
225
+ id: z.string(),
226
226
  }),
227
227
  response: {
228
- 200: Type.Object({
229
- message: Type.String(),
228
+ 200: z.object({
229
+ message: z.string(),
230
230
  }),
231
231
  },
232
232
  },
@@ -284,15 +284,15 @@ await runFastify(app, '0.0.0.0', 3000)
284
284
 
285
285
  ```typescript
286
286
  import { createFastify, runFastify, createFastifyPlugin } from '@a_jackie_z/fastify'
287
- import { Type } from '@sinclair/typebox'
287
+ import { z } from 'zod'
288
288
 
289
289
  // Create a reusable plugin
290
290
  const myPlugin = createFastifyPlugin((app) => {
291
291
  app.get('/plugin-route', {
292
292
  schema: {
293
293
  response: {
294
- 200: Type.Object({
295
- message: Type.String(),
294
+ 200: z.object({
295
+ message: z.string(),
296
296
  }),
297
297
  },
298
298
  },
@@ -309,26 +309,26 @@ await app.register(myPlugin)
309
309
  await runFastify(app, '0.0.0.0', 3000)
310
310
  ```
311
311
 
312
- ### 8. TypeBox Schema Validation
312
+ ### 8. Zod Schema Validation
313
313
 
314
314
  ```typescript
315
315
  app.route({
316
316
  method: 'POST',
317
317
  url: '/users',
318
318
  schema: {
319
- body: Type.Object({
320
- name: Type.String({ minLength: 1, maxLength: 100 }),
321
- email: Type.String({ format: 'email' }),
322
- age: Type.Optional(Type.Number({ minimum: 0, maximum: 150 })),
319
+ body: z.object({
320
+ name: z.string().min(1).max(100),
321
+ email: z.string().email(),
322
+ age: z.number().min(0).max(150).optional(),
323
323
  }),
324
324
  response: {
325
- 201: Type.Object({
326
- id: Type.String(),
327
- name: Type.String(),
328
- email: Type.String(),
325
+ 201: z.object({
326
+ id: z.string(),
327
+ name: z.string(),
328
+ email: z.string(),
329
329
  }),
330
- 400: Type.Object({
331
- error: Type.String(),
330
+ 400: z.object({
331
+ error: z.string(),
332
332
  }),
333
333
  },
334
334
  },
@@ -391,7 +391,7 @@ type JWTAuthorizationHandler = (
391
391
 
392
392
  ### `createFastify(options?: CreateFastifyOptions): Promise<FastifyServer>`
393
393
 
394
- Creates and configures a Fastify server instance with TypeBox support and optional plugins.
394
+ Creates and configures a Fastify server instance with Zod support and optional plugins.
395
395
 
396
396
  ### `runFastify(fastify: FastifyServer, host: string, port: number): Promise<void>`
397
397
 
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as fastify from 'fastify';
2
2
  import { FastifyRequest, FastifyReply, FastifyServerOptions, FastifyInstance, RawServerDefault, FastifyBaseLogger, FastifyContextConfig, FastifyPluginCallback } from 'fastify';
3
- import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox';
3
+ import { ZodTypeProvider } from 'fastify-type-provider-zod';
4
4
  import { RateLimitPluginOptions } from '@fastify/rate-limit';
5
5
  import { FastifyJWTOptions } from '@fastify/jwt';
6
6
  import { IncomingMessage, ServerResponse } from 'node:http';
@@ -38,7 +38,7 @@ interface CreateFastifyOptions {
38
38
  routePrefix?: string;
39
39
  };
40
40
  }
41
- type FastifyServer = FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse, FastifyBaseLogger, TypeBoxTypeProvider> & FastifyContextConfig;
41
+ type FastifyServer = FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse, FastifyBaseLogger, ZodTypeProvider> & FastifyContextConfig;
42
42
  declare function createFastify(options?: CreateFastifyOptions): Promise<FastifyServer>;
43
43
  declare function runFastify(fastify: FastifyServer, host: string, port: number): Promise<void>;
44
44
 
package/dist/index.js CHANGED
@@ -1,5 +1,9 @@
1
1
  // lib/fastify.ts
2
2
  import Fastify from "fastify";
3
+ import {
4
+ serializerCompiler,
5
+ validatorCompiler
6
+ } from "fastify-type-provider-zod";
3
7
  import fastifyRateLimit from "@fastify/rate-limit";
4
8
  import fastifyJwt from "@fastify/jwt";
5
9
  import fastifySwagger from "@fastify/swagger";
@@ -10,6 +14,8 @@ async function createFastify(options) {
10
14
  fastifyOptions.loggerInstance = options.logger;
11
15
  }
12
16
  const fastify = Fastify(fastifyOptions).withTypeProvider();
17
+ fastify.setValidatorCompiler(validatorCompiler);
18
+ fastify.setSerializerCompiler(serializerCompiler);
13
19
  if (options?.swagger) {
14
20
  await fastify.register(fastifySwagger, {
15
21
  openapi: {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../lib/fastify.ts","../lib/plugin.ts","../lib/plugins/healthPlugin.ts"],"sourcesContent":["import Fastify, {\n FastifyBaseLogger,\n FastifyContextConfig,\n FastifyInstance,\n FastifyReply,\n FastifyServerOptions,\n RawServerDefault,\n} from 'fastify'\nimport type { FastifyRequest } from 'fastify'\nimport { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'\nimport fastifyRateLimit, { RateLimitPluginOptions } from '@fastify/rate-limit'\nimport fastifyJwt, { FastifyJWTOptions } from '@fastify/jwt'\nimport fastifySwagger, { SwaggerOptions } from '@fastify/swagger'\nimport fastifySwaggerUI, { FastifySwaggerUiOptions } from '@fastify/swagger-ui'\nimport { IncomingMessage, ServerResponse } from 'node:http'\n\nexport type JWTAuthorizationHandler = <TUser = unknown>(\n request: FastifyRequest,\n reply: FastifyReply,\n user: TUser\n) => Promise<boolean> | boolean\n\nexport interface JWTRouteConfig {\n jwt?:\n | boolean // true = require JWT, false = bypass JWT\n | {\n required?: boolean // Default: true if global enabled\n authorize?: JWTAuthorizationHandler // Check JWT info before route processing\n }\n}\n\n// Extend Fastify types to include custom config\ndeclare module 'fastify' {\n interface FastifyContextConfig {\n jwt?:\n | boolean\n | {\n required?: boolean\n authorize?: JWTAuthorizationHandler\n }\n }\n}\n\nexport interface CreateFastifyOptions {\n logger?: FastifyServerOptions['loggerInstance'],\n rateLimit?: {\n global?: RateLimitPluginOptions\n }\n jwt?: {\n secret: string\n sign?: FastifyJWTOptions['sign']\n verify?: FastifyJWTOptions['verify']\n global?: boolean // Enable JWT check globally for all routes\n }\n swagger?: {\n title: string\n version: string\n description: string\n routePrefix?: string\n }\n}\n\nexport type FastifyServer = FastifyInstance<\n RawServerDefault,\n IncomingMessage,\n ServerResponse,\n FastifyBaseLogger,\n TypeBoxTypeProvider\n> & FastifyContextConfig\n\nexport async function createFastify(options?: CreateFastifyOptions): Promise<FastifyServer> {\n const fastifyOptions: FastifyServerOptions = {}\n\n if (options?.logger) {\n fastifyOptions.loggerInstance = options.logger\n }\n\n const fastify = Fastify(fastifyOptions).withTypeProvider<TypeBoxTypeProvider>()\n\n // Register Swagger first to capture all routes with TypeBox schemas\n if (options?.swagger) {\n await fastify.register(fastifySwagger, {\n openapi: {\n info: {\n title: options.swagger.title,\n version: options.swagger.version,\n description: options.swagger.description,\n },\n },\n } as SwaggerOptions)\n\n let routePrefix = options.swagger.routePrefix || '/docs/'\n\n if (!routePrefix.startsWith('/')) {\n routePrefix = '/' + routePrefix\n }\n\n if (!routePrefix.endsWith('/')) {\n routePrefix = routePrefix + '/'\n }\n\n await fastify.register(fastifySwaggerUI, { routePrefix } as FastifySwaggerUiOptions)\n }\n\n // Register JWT authentication\n if (options?.jwt) {\n const jwtOptions: FastifyJWTOptions = {\n secret: options.jwt.secret,\n }\n if (options.jwt.sign !== undefined) {\n jwtOptions.sign = options.jwt.sign\n }\n if (options.jwt.verify !== undefined) {\n jwtOptions.verify = options.jwt.verify\n }\n await fastify.register(fastifyJwt, jwtOptions)\n\n // Global JWT checking hook\n if (options.jwt.global) {\n fastify.addHook('onRequest', async (request, reply) => {\n const routeConfig = (request.routeOptions.config as JWTRouteConfig) || {}\n const jwtConfig = routeConfig.jwt\n\n // Check if route explicitly bypasses JWT\n if (jwtConfig === false) {\n return\n }\n\n // Check if route explicitly requires JWT or uses global setting\n const shouldVerify =\n jwtConfig === true ||\n (typeof jwtConfig === 'object' && jwtConfig.required !== false) ||\n (jwtConfig === undefined && options?.jwt?.global === true)\n\n if (shouldVerify) {\n try {\n await request.jwtVerify()\n\n // Custom authorization - check JWT info before route processing\n if (typeof jwtConfig === 'object' && jwtConfig.authorize) {\n const authorized = await jwtConfig.authorize(request, reply, request.user)\n if (!authorized) {\n reply.status(403).send({\n error: 'Forbidden',\n message: 'Authorization failed',\n })\n return\n }\n }\n } catch (err) {\n reply.status(401).send({\n error: 'Unauthorized',\n message: 'Invalid or missing JWT token',\n })\n }\n }\n })\n }\n }\n\n // Register Rate Limiting\n if (options?.rateLimit?.global) {\n await fastify.register(fastifyRateLimit, {\n global: true,\n ...options.rateLimit.global,\n })\n }\n\n return fastify\n}\n\nexport async function runFastify(fastify: FastifyServer, host: string, port: number) {\n try {\n await fastify.listen({ host, port })\n } catch (err) {\n fastify.log.error(err)\n process.exit(1)\n }\n}\n","import { FastifyPluginCallback } from 'fastify'\n\nexport function createFastifyPlugin(cb: FastifyPluginCallback) {\n return cb;\n}\n","import { createFastifyPlugin } from '../plugin.ts'\n\nexport const healthPlugin = createFastifyPlugin((app) => {\n app.get('/v1/health', {\n schema: {\n tags: ['health'],\n },\n handler: async () => {\n return {\n status: 200,\n message: 'ok',\n }\n },\n })\n})\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../lib/fastify.ts","../lib/plugin.ts","../lib/plugins/healthPlugin.ts"],"sourcesContent":["import Fastify, {\n FastifyBaseLogger,\n FastifyContextConfig,\n FastifyInstance,\n FastifyReply,\n FastifyServerOptions,\n RawServerDefault,\n} from 'fastify'\nimport type { FastifyRequest } from 'fastify'\nimport {\n serializerCompiler,\n validatorCompiler,\n ZodTypeProvider,\n} from 'fastify-type-provider-zod'\nimport fastifyRateLimit, { RateLimitPluginOptions } from '@fastify/rate-limit'\nimport fastifyJwt, { FastifyJWTOptions } from '@fastify/jwt'\nimport fastifySwagger, { SwaggerOptions } from '@fastify/swagger'\nimport fastifySwaggerUI, { FastifySwaggerUiOptions } from '@fastify/swagger-ui'\nimport { IncomingMessage, ServerResponse } from 'node:http'\n\nexport type JWTAuthorizationHandler = <TUser = unknown>(\n request: FastifyRequest,\n reply: FastifyReply,\n user: TUser\n) => Promise<boolean> | boolean\n\nexport interface JWTRouteConfig {\n jwt?:\n | boolean // true = require JWT, false = bypass JWT\n | {\n required?: boolean // Default: true if global enabled\n authorize?: JWTAuthorizationHandler // Check JWT info before route processing\n }\n}\n\n// Extend Fastify types to include custom config\ndeclare module 'fastify' {\n interface FastifyContextConfig {\n jwt?:\n | boolean\n | {\n required?: boolean\n authorize?: JWTAuthorizationHandler\n }\n }\n}\n\nexport interface CreateFastifyOptions {\n logger?: FastifyServerOptions['loggerInstance'],\n rateLimit?: {\n global?: RateLimitPluginOptions\n }\n jwt?: {\n secret: string\n sign?: FastifyJWTOptions['sign']\n verify?: FastifyJWTOptions['verify']\n global?: boolean // Enable JWT check globally for all routes\n }\n swagger?: {\n title: string\n version: string\n description: string\n routePrefix?: string\n }\n}\n\nexport type FastifyServer = FastifyInstance<\n RawServerDefault,\n IncomingMessage,\n ServerResponse,\n FastifyBaseLogger,\n ZodTypeProvider\n> & FastifyContextConfig\n\nexport async function createFastify(options?: CreateFastifyOptions): Promise<FastifyServer> {\n const fastifyOptions: FastifyServerOptions = {}\n\n if (options?.logger) {\n fastifyOptions.loggerInstance = options.logger\n }\n\n const fastify = Fastify(fastifyOptions).withTypeProvider<ZodTypeProvider>()\n\n // Set up Zod validation and serialization\n fastify.setValidatorCompiler(validatorCompiler)\n fastify.setSerializerCompiler(serializerCompiler)\n\n // Register Swagger first to capture all routes with Zod schemas\n if (options?.swagger) {\n await fastify.register(fastifySwagger, {\n openapi: {\n info: {\n title: options.swagger.title,\n version: options.swagger.version,\n description: options.swagger.description,\n },\n },\n } as SwaggerOptions)\n\n let routePrefix = options.swagger.routePrefix || '/docs/'\n\n if (!routePrefix.startsWith('/')) {\n routePrefix = '/' + routePrefix\n }\n\n if (!routePrefix.endsWith('/')) {\n routePrefix = routePrefix + '/'\n }\n\n await fastify.register(fastifySwaggerUI, { routePrefix } as FastifySwaggerUiOptions)\n }\n\n // Register JWT authentication\n if (options?.jwt) {\n const jwtOptions: FastifyJWTOptions = {\n secret: options.jwt.secret,\n }\n if (options.jwt.sign !== undefined) {\n jwtOptions.sign = options.jwt.sign\n }\n if (options.jwt.verify !== undefined) {\n jwtOptions.verify = options.jwt.verify\n }\n await fastify.register(fastifyJwt, jwtOptions)\n\n // Global JWT checking hook\n if (options.jwt.global) {\n fastify.addHook('onRequest', async (request, reply) => {\n const routeConfig = (request.routeOptions.config as JWTRouteConfig) || {}\n const jwtConfig = routeConfig.jwt\n\n // Check if route explicitly bypasses JWT\n if (jwtConfig === false) {\n return\n }\n\n // Check if route explicitly requires JWT or uses global setting\n const shouldVerify =\n jwtConfig === true ||\n (typeof jwtConfig === 'object' && jwtConfig.required !== false) ||\n (jwtConfig === undefined && options?.jwt?.global === true)\n\n if (shouldVerify) {\n try {\n await request.jwtVerify()\n\n // Custom authorization - check JWT info before route processing\n if (typeof jwtConfig === 'object' && jwtConfig.authorize) {\n const authorized = await jwtConfig.authorize(request, reply, request.user)\n if (!authorized) {\n reply.status(403).send({\n error: 'Forbidden',\n message: 'Authorization failed',\n })\n return\n }\n }\n } catch (err) {\n reply.status(401).send({\n error: 'Unauthorized',\n message: 'Invalid or missing JWT token',\n })\n }\n }\n })\n }\n }\n\n // Register Rate Limiting\n if (options?.rateLimit?.global) {\n await fastify.register(fastifyRateLimit, {\n global: true,\n ...options.rateLimit.global,\n })\n }\n\n return fastify\n}\n\nexport async function runFastify(fastify: FastifyServer, host: string, port: number) {\n try {\n await fastify.listen({ host, port })\n } catch (err) {\n fastify.log.error(err)\n process.exit(1)\n }\n}\n","import { FastifyPluginCallback } from 'fastify'\n\nexport function createFastifyPlugin(cb: FastifyPluginCallback) {\n return cb;\n}\n","import { createFastifyPlugin } from '../plugin.ts'\n\nexport const healthPlugin = createFastifyPlugin((app) => {\n app.get('/v1/health', {\n schema: {\n tags: ['health'],\n },\n handler: async () => {\n return {\n status: 200,\n message: 'ok',\n }\n },\n })\n})\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a_jackie_z/fastify",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "A collection of Fastify plugins and utilities for building robust web applications.",
5
5
  "license": "MIT",
6
6
  "author": "Sang Lu <connect.with.sang@gmail.com>",
@@ -24,10 +24,9 @@
24
24
  "@fastify/rate-limit": "^10.3.0",
25
25
  "@fastify/swagger": "^9.6.1",
26
26
  "@fastify/swagger-ui": "^5.2.4",
27
- "@fastify/type-provider-typebox": "^6.1.0",
28
- "@sinclair/typebox": "^0.34.47",
29
27
  "fastify": "^5.7.1",
30
- "typebox": "^1.0.79"
28
+ "fastify-type-provider-zod": "^6.1.0",
29
+ "zod": "^4.3.5"
31
30
  },
32
31
  "devDependencies": {
33
32
  "@types/node": "^25.0.9",