@a_jackie_z/fastify 1.1.7 → 1.1.8

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
@@ -43,6 +43,8 @@ await runFastify(app, '0.0.0.0', 3000)
43
43
  ## Features
44
44
 
45
45
  - **JWT Authentication** - Built-in JWT support with global and route-level configuration
46
+ - **Service JWT Tokens** - Service-to-service authentication with `generateServiceToken()` for microservice communication
47
+ - **Dual JWT Support** - User JWT (client identity) and Service JWT (gateway authentication) in the same request
46
48
  - **Rate Limiting** - Global rate limiting for API protection
47
49
  - **Swagger Documentation** - Auto-generated API documentation with Zod schemas and bearer authentication
48
50
  - **Zod Integration** - Type-safe request/response validation
@@ -519,6 +521,7 @@ interface JWTRouteConfig {
519
521
  | boolean // true = require JWT, false = bypass JWT
520
522
  | {
521
523
  required?: boolean // Default: true if global enabled
524
+ requireService?: boolean // Require service JWT token in X-Service-Authorization header
522
525
  authorize?: JWTAuthorizationHandler // Custom authorization logic
523
526
  }
524
527
  }
@@ -754,103 +757,123 @@ const jwtService = new FastifyJwtService<
754
757
  })
755
758
  ```
756
759
 
757
- ## Usage Patterns
760
+ ## Service-to-Service Authentication
758
761
 
759
- ### Pattern 1: Global JWT with Selective Public Routes
762
+ For microservices architecture, the package now supports service JWT tokens for secure service-to-service communication. This allows the gateway to authenticate requests to backend services.
763
+
764
+ ### Service JWT Token Options
765
+
766
+ When initializing `FastifyJwtService`, add `serviceTokenExpiry`:
760
767
 
761
768
  ```typescript
762
- const app = await createFastify({
763
- jwt: {
764
- secret: 'your-secret',
765
- global: true, // All routes require JWT by default
766
- },
769
+ const jwtService = new FastifyJwtService(app, {
770
+ accessTokenExpiry: '15m',
771
+ refreshTokenExpiry: '7d',
772
+ renewalThreshold: '1d',
773
+ serviceTokenExpiry: '1h', // NEW: Service token lifetime
767
774
  })
775
+ ```
768
776
 
769
- // Public routes explicitly bypass JWT
770
- app.route({
771
- method: 'POST',
772
- url: '/auth/login',
773
- config: { jwt: false },
774
- handler: async () => { /* ... */ },
775
- })
777
+ ### Generate Service Token
776
778
 
777
- // Protected routes don't need config
778
- app.route({
779
- method: 'GET',
780
- url: '/data',
781
- handler: async () => { /* ... */ },
782
- })
779
+ ```typescript
780
+ // Generate a token for service-to-service communication
781
+ const serviceToken = jwtService.generateServiceToken('gateway')
782
+ // Returns a JWT token with payload: { serviceId: 'gateway', type: 'service', exp: <timestamp> }
783
783
  ```
784
784
 
785
- ### Pattern 2: Opt-In JWT Protection
785
+ ### Require Service Token on Route
786
+
787
+ Protect a route to require service JWT authentication in the `X-Service-Authorization` header:
786
788
 
787
789
  ```typescript
788
- const app = await createFastify({
789
- jwt: {
790
- secret: 'your-secret',
791
- global: false, // JWT not required by default
790
+ app.route({
791
+ method: 'PATCH',
792
+ url: '/v1/credentials/change-password',
793
+ config: {
794
+ jwt: {
795
+ requireService: true, // NEW: Require service JWT token
796
+ },
797
+ },
798
+ handler: async (request, reply) => {
799
+ // Both user JWT and service JWT are validated
800
+ const user = request.user // User info from client JWT
801
+ return reply.send(formatSuccess(200, { success: true }))
792
802
  },
793
803
  })
804
+ ```
794
805
 
795
- // Unprotected by default
796
- app.route({
797
- method: 'GET',
798
- url: '/public',
799
- handler: async () => { /* ... */ },
800
- })
806
+ ### Service Token Flow
801
807
 
802
- // Explicitly require JWT
803
- app.route({
804
- method: 'GET',
805
- url: '/protected',
806
- config: { jwt: true },
807
- handler: async () => { /* ... */ },
808
+ In a gateway-to-service architecture:
809
+
810
+ ```typescript
811
+ // Gateway generates service token
812
+ const serviceToken = jwtService.generateServiceToken('gateway')
813
+
814
+ // Gateway forwards request with both tokens:
815
+ fetch('http://auth-service.local/v1/credentials/change-password', {
816
+ method: 'PATCH',
817
+ headers: {
818
+ 'Authorization': `Bearer ${userJwtToken}`, // User identity
819
+ 'X-Service-Authorization': `Bearer ${serviceToken}`, // Gateway authentication
820
+ },
821
+ body: JSON.stringify(data),
808
822
  })
823
+
824
+ // Backend service validates both:
825
+ // 1. X-Service-Authorization header - confirms request from authorized gateway
826
+ // 2. Authorization header - identifies which user is making the request
809
827
  ```
810
828
 
811
- ### Pattern 3: Multi-Tier Authorization
829
+ ### Complete Example: Gateway with Service Authentication
812
830
 
813
831
  ```typescript
832
+ import { createFastify, FastifyJwtService } from '@a_jackie_z/fastify'
833
+
814
834
  const app = await createFastify({
815
835
  jwt: {
816
- secret: 'your-secret',
836
+ secret: 'shared-secret-key', // Shared with backend services
817
837
  global: true,
818
838
  },
819
839
  })
820
840
 
821
- // Tier 1: Any authenticated user
822
- app.route({
823
- method: 'GET',
824
- url: '/user/profile',
825
- handler: async (request) => {
826
- return request.user
827
- },
841
+ const jwtService = new FastifyJwtService(app, {
842
+ accessTokenExpiry: '15m',
843
+ refreshTokenExpiry: '7d',
844
+ renewalThreshold: '1d',
845
+ serviceTokenExpiry: '1h',
828
846
  })
829
847
 
830
- // Tier 2: Admin users only
848
+ // Forward request to backend service
831
849
  app.route({
832
- method: 'GET',
833
- url: '/admin/users',
834
- config: {
835
- jwt: {
836
- authorize: async (_req, _reply, user) => user?.role === 'admin',
837
- },
850
+ method: 'PATCH',
851
+ url: '/auth/v1/credentials/change-password',
852
+ config: { jwt: true }, // Require user JWT
853
+ handler: async (request, reply) => {
854
+ // Extract user token from request
855
+ const userToken = request.headers.authorization?.replace('Bearer ', '')
856
+
857
+ // Generate service token for gateway
858
+ const serviceToken = jwtService.generateServiceToken('gateway')
859
+
860
+ // Forward to backend service
861
+ const response = await fetch('http://auth-service:8200/v1/credentials/change-password', {
862
+ method: 'PATCH',
863
+ headers: {
864
+ 'Authorization': `Bearer ${userToken}`, // Forward user token
865
+ 'X-Service-Authorization': `Bearer ${serviceToken}`, // Add service token
866
+ 'Content-Type': 'application/json',
867
+ },
868
+ body: JSON.stringify(request.body),
869
+ })
870
+
871
+ const data = await response.json()
872
+ return reply.status(response.status).send(data)
838
873
  },
839
- handler: async () => { /* ... */ },
840
874
  })
841
875
 
842
- // Tier 3: Super admin with specific permission
843
- app.route({
844
- method: 'DELETE',
845
- url: '/admin/system',
846
- config: {
847
- jwt: {
848
- authorize: async (_req, _reply, user) =>
849
- user?.role === 'admin' && user?.permissions?.includes('system:delete'),
850
- },
851
- },
852
- handler: async () => { /* ... */ },
853
- })
876
+ await runFastify(app, '0.0.0.0', 3000)
854
877
  ```
855
878
 
856
879
  ## Testing Your API
package/dist/index.d.ts CHANGED
@@ -12,6 +12,7 @@ type JWTAuthorizationHandler = <TUser = unknown>(request: FastifyRequest, reply:
12
12
  interface JWTRouteConfig {
13
13
  jwt?: boolean | {
14
14
  required?: boolean;
15
+ requireService?: boolean;
15
16
  authorize?: JWTAuthorizationHandler;
16
17
  };
17
18
  }
@@ -19,6 +20,7 @@ declare module 'fastify' {
19
20
  interface FastifyContextConfig {
20
21
  jwt?: boolean | {
21
22
  required?: boolean;
23
+ requireService?: boolean;
22
24
  authorize?: JWTAuthorizationHandler;
23
25
  };
24
26
  }
@@ -96,11 +98,20 @@ declare const baseRefreshTokenPayloadSchema: z.ZodObject<{
96
98
  type: z.ZodLiteral<"refresh">;
97
99
  exp: z.ZodNumber;
98
100
  }, z.core.$strip>;
101
+ /**
102
+ * Service-to-service authentication token payload schema
103
+ */
104
+ declare const serviceAccessTokenPayloadSchema: z.ZodObject<{
105
+ serviceId: z.ZodString;
106
+ type: z.ZodLiteral<"service">;
107
+ exp: z.ZodNumber;
108
+ }, z.core.$strip>;
99
109
  /**
100
110
  * Inferred types from base schemas
101
111
  */
102
112
  type BaseAccessTokenPayload = z.infer<typeof baseAccessTokenPayloadSchema>;
103
113
  type BaseRefreshTokenPayload = z.infer<typeof baseRefreshTokenPayloadSchema>;
114
+ type ServiceAccessTokenPayload = z.infer<typeof serviceAccessTokenPayloadSchema>;
104
115
  /**
105
116
  * Token pair interface
106
117
  */
@@ -115,6 +126,7 @@ interface FastifyJwtServiceOptions {
115
126
  accessTokenExpiry: string;
116
127
  refreshTokenExpiry: string;
117
128
  renewalThreshold: string;
129
+ serviceTokenExpiry: string;
118
130
  accessTokenSchema?: z.ZodSchema;
119
131
  refreshTokenSchema?: z.ZodSchema;
120
132
  }
@@ -149,6 +161,7 @@ declare class FastifyJwtService<TAccess extends BaseAccessTokenPayload = BaseAcc
149
161
  private readonly accessTokenExpiry;
150
162
  private readonly refreshTokenExpiry;
151
163
  private readonly renewalThreshold;
164
+ private readonly serviceTokenExpiry;
152
165
  private readonly accessTokenSchema;
153
166
  private readonly refreshTokenSchema;
154
167
  constructor(app: FastifyServer, options: FastifyJwtServiceOptions);
@@ -164,6 +177,12 @@ declare class FastifyJwtService<TAccess extends BaseAccessTokenPayload = BaseAcc
164
177
  * Generate both access and refresh tokens
165
178
  */
166
179
  generateTokenPair(identityId: string): TokenPair;
180
+ /**
181
+ * Generate a service-to-service authentication token
182
+ * @param serviceId - The identifier of the service (e.g., 'gateway', 'auth-service')
183
+ * @returns JWT token valid for service-to-service communication
184
+ */
185
+ generateServiceToken(serviceId: string): string;
167
186
  /**
168
187
  * Verify and decode an access token
169
188
  */
@@ -198,4 +217,4 @@ interface CreateErrorOptions {
198
217
  declare function createError(options: CreateErrorOptions): FastifyError;
199
218
  declare function setupErrorHandler(fastify: FastifyInstance): void;
200
219
 
201
- export { type BaseAccessTokenPayload, type BaseRefreshTokenPayload, type CreateErrorOptions, type CreateFastifyOptions, type ErrorResponse, FastifyJwtService, type FastifyJwtServiceOptions, type FastifyServer, type JWTAuthorizationHandler, type JWTRouteConfig, type SuccessResponse, type TokenPair, type ValidationDetail, baseAccessTokenPayloadSchema, baseRefreshTokenPayloadSchema, createError, createFastify, createFastifyPlugin, errorResponseSchema, formatError, formatSuccess, healthPlugin, runFastify, setupErrorHandler, successResponseSchema };
220
+ export { type BaseAccessTokenPayload, type BaseRefreshTokenPayload, type CreateErrorOptions, type CreateFastifyOptions, type ErrorResponse, FastifyJwtService, type FastifyJwtServiceOptions, type FastifyServer, type JWTAuthorizationHandler, type JWTRouteConfig, type ServiceAccessTokenPayload, type SuccessResponse, type TokenPair, type ValidationDetail, baseAccessTokenPayloadSchema, baseRefreshTokenPayloadSchema, createError, createFastify, createFastifyPlugin, errorResponseSchema, formatError, formatSuccess, healthPlugin, runFastify, serviceAccessTokenPayloadSchema, setupErrorHandler, successResponseSchema };
package/dist/index.js CHANGED
@@ -198,6 +198,33 @@ async function setupJWT(fastify, options, swaggerRoutePrefix) {
198
198
  if (shouldVerify) {
199
199
  try {
200
200
  await request.jwtVerify();
201
+ if (typeof jwtConfig === "object" && jwtConfig.requireService) {
202
+ const serviceAuthHeader = request.headers["x-service-authorization"];
203
+ if (!serviceAuthHeader) {
204
+ return reply.status(401).send(
205
+ formatError(401, "Unauthorized", "Missing service authorization token")
206
+ );
207
+ }
208
+ const serviceToken = typeof serviceAuthHeader === "string" ? serviceAuthHeader.replace("Bearer ", "") : serviceAuthHeader[0]?.replace("Bearer ", "");
209
+ if (!serviceToken) {
210
+ return reply.status(401).send(
211
+ formatError(401, "Unauthorized", "Invalid service authorization header format")
212
+ );
213
+ }
214
+ try {
215
+ const servicePayload = fastify.jwt.verify(serviceToken);
216
+ if (servicePayload.type !== "service") {
217
+ return reply.status(401).send(
218
+ formatError(401, "Unauthorized", "Invalid service token type")
219
+ );
220
+ }
221
+ request.serviceUser = servicePayload;
222
+ } catch (err) {
223
+ return reply.status(401).send(
224
+ formatError(401, "Unauthorized", "Invalid service authorization token")
225
+ );
226
+ }
227
+ }
201
228
  if (typeof jwtConfig === "object" && jwtConfig.authorize) {
202
229
  const authorized = await jwtConfig.authorize(request, reply, request.user);
203
230
  if (!authorized) {
@@ -258,18 +285,25 @@ var baseRefreshTokenPayloadSchema = z2.object({
258
285
  type: z2.literal("refresh"),
259
286
  exp: z2.number()
260
287
  });
288
+ var serviceAccessTokenPayloadSchema = z2.object({
289
+ serviceId: z2.string(),
290
+ type: z2.literal("service"),
291
+ exp: z2.number()
292
+ });
261
293
  var FastifyJwtService = class {
262
294
  constructor(app, options) {
263
295
  this.app = app;
264
296
  this.accessTokenExpiry = options.accessTokenExpiry;
265
297
  this.refreshTokenExpiry = options.refreshTokenExpiry;
266
298
  this.renewalThreshold = options.renewalThreshold;
299
+ this.serviceTokenExpiry = options.serviceTokenExpiry;
267
300
  this.accessTokenSchema = options.accessTokenSchema ?? baseAccessTokenPayloadSchema;
268
301
  this.refreshTokenSchema = options.refreshTokenSchema ?? baseRefreshTokenPayloadSchema;
269
302
  }
270
303
  accessTokenExpiry;
271
304
  refreshTokenExpiry;
272
305
  renewalThreshold;
306
+ serviceTokenExpiry;
273
307
  accessTokenSchema;
274
308
  refreshTokenSchema;
275
309
  /**
@@ -307,6 +341,20 @@ var FastifyJwtService = class {
307
341
  refreshToken: this.generateRefreshToken(identityId)
308
342
  };
309
343
  }
344
+ /**
345
+ * Generate a service-to-service authentication token
346
+ * @param serviceId - The identifier of the service (e.g., 'gateway', 'auth-service')
347
+ * @returns JWT token valid for service-to-service communication
348
+ */
349
+ generateServiceToken(serviceId) {
350
+ const payload = {
351
+ serviceId,
352
+ type: "service"
353
+ };
354
+ return this.app.jwt.sign(payload, {
355
+ expiresIn: this.serviceTokenExpiry
356
+ });
357
+ }
310
358
  /**
311
359
  * Verify and decode an access token
312
360
  */
@@ -430,6 +478,7 @@ export {
430
478
  formatSuccess,
431
479
  healthPlugin,
432
480
  runFastify,
481
+ serviceAccessTokenPayloadSchema,
433
482
  setupErrorHandler,
434
483
  successResponseSchema
435
484
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../lib/fastify.ts","../lib/response.ts","../lib/error-handler.ts","../lib/swagger-setup.ts","../lib/jwt-setup.ts","../lib/jwt.service.ts","../lib/plugin.ts","../lib/plugins/healthPlugin.ts","../index.ts"],"sourcesContent":["import Fastify, { FastifyServerOptions } from 'fastify'\nimport { serializerCompiler, validatorCompiler, ZodTypeProvider } from 'fastify-type-provider-zod'\nimport fastifyRateLimit from '@fastify/rate-limit'\nimport { setupErrorHandler } from './error-handler.ts'\nimport { setupSwagger, setupSwaggerSecurityHook } from './swagger-setup.ts'\nimport { setupJWT } from './jwt-setup.ts'\nimport type { CreateFastifyOptions, FastifyServer } from './types.ts'\n\n// Re-export types and utilities from other modules\nexport * from './response.ts'\nexport * from './types.ts'\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 // Set up error handler for standardized error responses\n setupErrorHandler(fastify)\n\n // Register Swagger first to capture all routes with Zod schemas\n const swaggerRoutePrefix = await setupSwagger(fastify, options || {})\n\n // Auto-inject security requirements for JWT-protected routes\n setupSwaggerSecurityHook(fastify, options || {}, swaggerRoutePrefix)\n\n // Register JWT authentication\n await setupJWT(fastify, options || {}, swaggerRoutePrefix)\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 { z } from 'zod'\n\n// Response Types\nexport interface ValidationDetail {\n field: string\n message: string\n}\n\nexport interface SuccessResponse<T> {\n status: number\n success: true\n data: T\n}\n\nexport interface ErrorResponse {\n status: number\n success: false\n error: string\n message: string\n details?: ValidationDetail[]\n}\n\n// Response Formatters\nexport function formatSuccess<T>(status: number, data: T): SuccessResponse<T> {\n return {\n status,\n success: true,\n data,\n }\n}\n\nexport function formatError(\n status: number,\n error: string,\n message: string,\n details?: ValidationDetail[]\n): ErrorResponse {\n const response: ErrorResponse = {\n status,\n success: false,\n error,\n message,\n }\n if (details && details.length > 0) {\n response.details = details\n }\n return response\n}\n\n// Zod Schema Helpers for Standardized Responses\nexport const successResponseSchema = <T extends z.ZodTypeAny>(dataSchema: T) => z.object({\n status: z.number(),\n success: z.literal(true),\n data: dataSchema,\n})\n\nexport const errorResponseSchema = z.object({\n status: z.number(),\n success: z.literal(false),\n error: z.string(),\n message: z.string(),\n details: z.array(z.object({\n field: z.string(),\n message: z.string(),\n })).optional(),\n})\n","import type { FastifyError, FastifyInstance } from 'fastify'\nimport { formatError, type ValidationDetail } from './response.ts'\n\nexport interface CreateErrorOptions {\n statusCode?: number\n message: string\n name?: string\n}\n\nexport function createError(options: CreateErrorOptions): FastifyError {\n const {\n statusCode = 500,\n message,\n name = 'Error',\n } = options\n\n const error = new Error(message) as FastifyError\n error.statusCode = statusCode\n error.name = name\n return error\n}\n\nexport function setupErrorHandler(fastify: FastifyInstance): void {\n fastify.setErrorHandler((error: FastifyError, request, reply) => {\n // Log all errors\n fastify.log.error({\n err: error,\n url: request.url,\n method: request.method,\n }, 'Request error')\n\n // Handle Zod validation errors\n if (error.validation) {\n const details: ValidationDetail[] = error.validation.map((issue: any) => {\n // Build field path from dataPath or instancePath\n const field = issue.instancePath || issue.dataPath || issue.params?.missingProperty || 'unknown'\n const cleanField = field.startsWith('/') ? field.slice(1).replace(/\\//g, '.') : field\n\n return {\n field: cleanField || 'unknown',\n message: issue.message || 'Validation failed',\n }\n })\n\n return reply.status(400).send(\n formatError(400, 'Validation Error', 'Request validation failed', details)\n )\n }\n\n // Handle rate limit errors\n if (error.statusCode === 429) {\n return reply.status(429).send(\n formatError(429, 'Too Many Requests', 'Rate limit exceeded')\n )\n }\n\n // Handle authentication errors\n if (error.statusCode === 401) {\n return reply.status(401).send(\n formatError(401, 'Unauthorized', error.message || 'Authentication required')\n )\n }\n\n // Handle authorization errors\n if (error.statusCode === 403) {\n return reply.status(403).send(\n formatError(403, 'Forbidden', error.message || 'Access denied')\n )\n }\n\n // Handle not found errors\n if (error.statusCode === 404) {\n return reply.status(404).send(\n formatError(404, 'Not Found', error.message || 'Resource not found')\n )\n }\n\n // Handle all other errors as internal server errors\n const statusCode = error.statusCode || 500\n return reply.status(statusCode).send(\n formatError(\n statusCode,\n statusCode === 500 ? 'Internal Server Error' : error.name || 'Error',\n error.message || 'An unexpected error occurred'\n )\n )\n })\n}\n","import type { FastifyInstance } from 'fastify'\nimport fastifySwagger, { SwaggerOptions } from '@fastify/swagger'\nimport fastifySwaggerUI, { FastifySwaggerUiOptions } from '@fastify/swagger-ui'\nimport { jsonSchemaTransform } from 'fastify-type-provider-zod'\nimport type { CreateFastifyOptions, JWTRouteConfig } from './types.ts'\n\nexport async function setupSwagger(\n fastify: FastifyInstance,\n options: CreateFastifyOptions\n): Promise<string | undefined> {\n if (!options.swagger) {\n return undefined\n }\n\n const openApiConfig: any = {\n openapi: {\n info: {\n title: options.swagger.title,\n version: options.swagger.version,\n description: options.swagger.description,\n },\n },\n transform: jsonSchemaTransform,\n }\n\n // Add bearer auth security scheme if JWT is enabled\n if (options.jwt) {\n openApiConfig.openapi.components = {\n securitySchemes: {\n bearerAuth: {\n type: 'http',\n scheme: 'bearer',\n bearerFormat: 'JWT',\n },\n },\n }\n }\n\n await fastify.register(fastifySwagger, openApiConfig 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 return routePrefix\n}\n\nexport function setupSwaggerSecurityHook(\n fastify: FastifyInstance,\n options: CreateFastifyOptions,\n swaggerRoutePrefix: string | undefined\n): void {\n if (!options.jwt || !options.swagger) {\n return\n }\n\n // Auto-inject security requirements for JWT-protected routes\n fastify.addHook('onRoute', (routeOptions) => {\n // Skip Swagger routes\n if (swaggerRoutePrefix && routeOptions.url.startsWith(swaggerRoutePrefix)) {\n return\n }\n\n const routeConfig = (routeOptions.config as JWTRouteConfig) || {}\n const jwtConfig = routeConfig.jwt\n\n // Skip if JWT is explicitly bypassed\n if (jwtConfig === false) {\n return\n }\n\n // Determine if route requires JWT\n const requiresJWT =\n jwtConfig === true ||\n (typeof jwtConfig === 'object' && jwtConfig.required !== false) ||\n (jwtConfig === undefined && options.jwt?.global === true)\n\n // Inject security requirement if JWT is required\n if (requiresJWT) {\n if (!routeOptions.schema) {\n routeOptions.schema = {}\n }\n if (!routeOptions.schema.security) {\n routeOptions.schema.security = [{ bearerAuth: [] }]\n }\n }\n })\n}\n","import type { FastifyInstance } from 'fastify'\nimport fastifyJwt, { FastifyJWTOptions } from '@fastify/jwt'\nimport { formatError } from './response.ts'\nimport type { CreateFastifyOptions, JWTRouteConfig } from './types.ts'\n\nexport async function setupJWT(\n fastify: FastifyInstance,\n options: CreateFastifyOptions,\n swaggerRoutePrefix: string | undefined\n): Promise<void> {\n if (!options.jwt) {\n return\n }\n\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 // Skip JWT verification for Swagger documentation routes\n if (swaggerRoutePrefix && request.url.startsWith(swaggerRoutePrefix)) {\n return\n }\n\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 return reply.status(403).send(\n formatError(403, 'Forbidden', 'Authorization failed')\n )\n }\n }\n } catch (err) {\n return reply.status(401).send(\n formatError(401, 'Unauthorized', 'Invalid or missing JWT token')\n )\n }\n }\n })\n }\n}\n","import { z } from 'zod'\nimport { FastifyServer } from './fastify.ts'\n\n/**\n * Base access token payload schema\n */\nexport const baseAccessTokenPayloadSchema = z.object({\n identityId: z.string(),\n type: z.literal('access'),\n exp: z.number(),\n})\n\n/**\n * Base refresh token payload schema\n */\nexport const baseRefreshTokenPayloadSchema = z.object({\n identityId: z.string(),\n type: z.literal('refresh'),\n exp: z.number(),\n})\n\n/**\n * Inferred types from base schemas\n */\nexport type BaseAccessTokenPayload = z.infer<typeof baseAccessTokenPayloadSchema>\nexport type BaseRefreshTokenPayload = z.infer<typeof baseRefreshTokenPayloadSchema>\n\n/**\n * Token pair interface\n */\nexport interface TokenPair {\n accessToken: string\n refreshToken: string\n}\n\n/**\n * FastifyJwtService configuration options\n */\nexport interface FastifyJwtServiceOptions {\n accessTokenExpiry: string\n refreshTokenExpiry: string\n renewalThreshold: string\n accessTokenSchema?: z.ZodSchema\n refreshTokenSchema?: z.ZodSchema\n}\n\n/**\n * Generic JWT service for Fastify applications\n *\n * @template TAccess - Access token payload type extending BaseAccessTokenPayload\n * @template TRefresh - Refresh token payload type extending BaseRefreshTokenPayload\n *\n * @example\n * // Using base schemas\n * const jwtService = new FastifyJwtService(app, {\n * accessTokenExpiry: '15m',\n * refreshTokenExpiry: '7d',\n * renewalThreshold: '1d',\n * })\n *\n * @example\n * // Using extended schemas\n * const customAccessSchema = baseAccessTokenPayloadSchema.extend({\n * roles: z.array(z.string())\n * })\n * const jwtService = new FastifyJwtService(app, {\n * accessTokenExpiry: '15m',\n * refreshTokenExpiry: '7d',\n * renewalThreshold: '1d',\n * accessTokenSchema: customAccessSchema,\n * })\n */\nexport class FastifyJwtService<\n TAccess extends BaseAccessTokenPayload = BaseAccessTokenPayload,\n TRefresh extends BaseRefreshTokenPayload = BaseRefreshTokenPayload\n> {\n private readonly accessTokenExpiry: string\n private readonly refreshTokenExpiry: string\n private readonly renewalThreshold: string\n private readonly accessTokenSchema: z.ZodSchema<TAccess>\n private readonly refreshTokenSchema: z.ZodSchema<TRefresh>\n\n constructor(\n private readonly app: FastifyServer,\n options: FastifyJwtServiceOptions\n ) {\n this.accessTokenExpiry = options.accessTokenExpiry\n this.refreshTokenExpiry = options.refreshTokenExpiry\n this.renewalThreshold = options.renewalThreshold\n this.accessTokenSchema = (options.accessTokenSchema ?? baseAccessTokenPayloadSchema) as z.ZodSchema<TAccess>\n this.refreshTokenSchema = (options.refreshTokenSchema ?? baseRefreshTokenPayloadSchema) as z.ZodSchema<TRefresh>\n }\n\n /**\n * Generate an access token for the given identity\n */\n generateAccessToken(identityId: string, extraPayload?: Partial<Omit<TAccess, 'identityId' | 'type' | 'exp'>>): string {\n const payload = {\n identityId,\n type: 'access' as const,\n ...extraPayload,\n }\n\n return this.app.jwt.sign(payload, {\n expiresIn: this.accessTokenExpiry,\n })\n }\n\n /**\n * Generate a refresh token for the given identity\n */\n generateRefreshToken(identityId: string, extraPayload?: Partial<Omit<TRefresh, 'identityId' | 'type' | 'exp'>>): string {\n const payload = {\n identityId,\n type: 'refresh' as const,\n ...extraPayload,\n }\n\n return this.app.jwt.sign(payload, {\n expiresIn: this.refreshTokenExpiry,\n })\n }\n\n /**\n * Generate both access and refresh tokens\n */\n generateTokenPair(identityId: string): TokenPair {\n return {\n accessToken: this.generateAccessToken(identityId),\n refreshToken: this.generateRefreshToken(identityId),\n }\n }\n\n /**\n * Verify and decode an access token\n */\n verifyAccessToken(token: string): TAccess {\n try {\n const payload = this.app.jwt.verify(token) as unknown\n const validated = this.accessTokenSchema.parse(payload)\n\n if (validated.type !== 'access') {\n throw new Error('Invalid token type')\n }\n\n return validated\n } catch (error) {\n if (error instanceof z.ZodError) {\n throw new Error('Invalid token payload')\n }\n throw error\n }\n }\n\n /**\n * Verify and decode a refresh token\n */\n verifyRefreshToken(token: string): TRefresh {\n try {\n const payload = this.app.jwt.verify(token) as unknown\n const validated = this.refreshTokenSchema.parse(payload)\n\n if (validated.type !== 'refresh') {\n throw new Error('Invalid token type')\n }\n\n return validated\n } catch (error) {\n if (error instanceof z.ZodError) {\n throw new Error('Invalid token payload')\n }\n throw error\n }\n }\n\n /**\n * Renew a refresh token for the given identity\n */\n renewRefreshToken(identityId: string): string {\n return this.generateRefreshToken(identityId)\n }\n\n /**\n * Check if a refresh token should be renewed based on its expiry\n */\n shouldRenewRefreshToken(exp: number): boolean {\n const now = Math.floor(Date.now() / 1000)\n const threshold = this.parseTimespan(this.renewalThreshold)\n return (exp - now) < threshold\n }\n\n /**\n * Parse timespan string to seconds\n */\n private parseTimespan(timespan: string): number {\n const match = timespan.match(/^(\\d+)([smhd])$/)\n if (!match || !match[1] || !match[2]) {\n throw new Error(`Invalid timespan format: ${timespan}`)\n }\n\n const value = parseInt(match[1]!, 10)\n const unit = match[2]!\n\n switch (unit) {\n case 's':\n return value\n case 'm':\n return value * 60\n case 'h':\n return value * 3600\n case 'd':\n return value * 86400\n default:\n throw new Error(`Unknown timespan unit: ${unit}`)\n }\n }\n}\n","import { FastifyPluginCallback } from 'fastify'\nimport { FastifyServer } from './fastify.ts'\nimport { ZodTypeProvider } from 'fastify-type-provider-zod'\n\nexport function createFastifyPlugin(cb: FastifyPluginCallback) {\n return function createFastifyPluginWrapper(\n fastify: FastifyServer,\n options: Parameters<FastifyPluginCallback>[1],\n done: Parameters<FastifyPluginCallback>[2],\n ) {\n const server = fastify.withTypeProvider<ZodTypeProvider>()\n let doneCalled = false\n\n const doneWrapper = (err?: Error) => {\n done(err)\n doneCalled = true\n }\n\n cb(server, options, doneWrapper)\n\n if (!doneCalled) {\n done()\n }\n }\n}\n","import { createFastifyPlugin } from '../plugin.ts'\nimport { FastifyServer } from '../fastify.ts'\n\nexport const healthPlugin = createFastifyPlugin((app: FastifyServer) => {\n app.get('/v1/health', {\n schema: {\n tags: ['health'],\n },\n config: {\n jwt: false,\n },\n handler: async () => {\n return {\n status: 200,\n message: 'ok',\n }\n },\n })\n})\n","export * from './lib/fastify.ts'\nexport * from './lib/response.ts'\nexport * from './lib/types.ts'\nexport * from './lib/jwt.service.ts'\nexport * from './lib/plugin.ts'\nexport * from './lib/plugins/healthPlugin.ts'\nexport * from './lib/error-handler.ts'\nexport * from 'fastify-type-provider-zod'\nexport type { FastifyErrorCodes, FastifyRequest, FastifyReply } from 'fastify'\n"],"mappings":"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","names":["z"]}
1
+ {"version":3,"sources":["../lib/fastify.ts","../lib/response.ts","../lib/error-handler.ts","../lib/swagger-setup.ts","../lib/jwt-setup.ts","../lib/jwt.service.ts","../lib/plugin.ts","../lib/plugins/healthPlugin.ts","../index.ts"],"sourcesContent":["import Fastify, { FastifyServerOptions } from 'fastify'\nimport { serializerCompiler, validatorCompiler, ZodTypeProvider } from 'fastify-type-provider-zod'\nimport fastifyRateLimit from '@fastify/rate-limit'\nimport { setupErrorHandler } from './error-handler.ts'\nimport { setupSwagger, setupSwaggerSecurityHook } from './swagger-setup.ts'\nimport { setupJWT } from './jwt-setup.ts'\nimport type { CreateFastifyOptions, FastifyServer } from './types.ts'\n\n// Re-export types and utilities from other modules\nexport * from './response.ts'\nexport * from './types.ts'\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 // Set up error handler for standardized error responses\n setupErrorHandler(fastify)\n\n // Register Swagger first to capture all routes with Zod schemas\n const swaggerRoutePrefix = await setupSwagger(fastify, options || {})\n\n // Auto-inject security requirements for JWT-protected routes\n setupSwaggerSecurityHook(fastify, options || {}, swaggerRoutePrefix)\n\n // Register JWT authentication\n await setupJWT(fastify, options || {}, swaggerRoutePrefix)\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 { z } from 'zod'\n\n// Response Types\nexport interface ValidationDetail {\n field: string\n message: string\n}\n\nexport interface SuccessResponse<T> {\n status: number\n success: true\n data: T\n}\n\nexport interface ErrorResponse {\n status: number\n success: false\n error: string\n message: string\n details?: ValidationDetail[]\n}\n\n// Response Formatters\nexport function formatSuccess<T>(status: number, data: T): SuccessResponse<T> {\n return {\n status,\n success: true,\n data,\n }\n}\n\nexport function formatError(\n status: number,\n error: string,\n message: string,\n details?: ValidationDetail[]\n): ErrorResponse {\n const response: ErrorResponse = {\n status,\n success: false,\n error,\n message,\n }\n if (details && details.length > 0) {\n response.details = details\n }\n return response\n}\n\n// Zod Schema Helpers for Standardized Responses\nexport const successResponseSchema = <T extends z.ZodTypeAny>(dataSchema: T) => z.object({\n status: z.number(),\n success: z.literal(true),\n data: dataSchema,\n})\n\nexport const errorResponseSchema = z.object({\n status: z.number(),\n success: z.literal(false),\n error: z.string(),\n message: z.string(),\n details: z.array(z.object({\n field: z.string(),\n message: z.string(),\n })).optional(),\n})\n","import type { FastifyError, FastifyInstance } from 'fastify'\nimport { formatError, type ValidationDetail } from './response.ts'\n\nexport interface CreateErrorOptions {\n statusCode?: number\n message: string\n name?: string\n}\n\nexport function createError(options: CreateErrorOptions): FastifyError {\n const {\n statusCode = 500,\n message,\n name = 'Error',\n } = options\n\n const error = new Error(message) as FastifyError\n error.statusCode = statusCode\n error.name = name\n return error\n}\n\nexport function setupErrorHandler(fastify: FastifyInstance): void {\n fastify.setErrorHandler((error: FastifyError, request, reply) => {\n // Log all errors\n fastify.log.error({\n err: error,\n url: request.url,\n method: request.method,\n }, 'Request error')\n\n // Handle Zod validation errors\n if (error.validation) {\n const details: ValidationDetail[] = error.validation.map((issue: any) => {\n // Build field path from dataPath or instancePath\n const field = issue.instancePath || issue.dataPath || issue.params?.missingProperty || 'unknown'\n const cleanField = field.startsWith('/') ? field.slice(1).replace(/\\//g, '.') : field\n\n return {\n field: cleanField || 'unknown',\n message: issue.message || 'Validation failed',\n }\n })\n\n return reply.status(400).send(\n formatError(400, 'Validation Error', 'Request validation failed', details)\n )\n }\n\n // Handle rate limit errors\n if (error.statusCode === 429) {\n return reply.status(429).send(\n formatError(429, 'Too Many Requests', 'Rate limit exceeded')\n )\n }\n\n // Handle authentication errors\n if (error.statusCode === 401) {\n return reply.status(401).send(\n formatError(401, 'Unauthorized', error.message || 'Authentication required')\n )\n }\n\n // Handle authorization errors\n if (error.statusCode === 403) {\n return reply.status(403).send(\n formatError(403, 'Forbidden', error.message || 'Access denied')\n )\n }\n\n // Handle not found errors\n if (error.statusCode === 404) {\n return reply.status(404).send(\n formatError(404, 'Not Found', error.message || 'Resource not found')\n )\n }\n\n // Handle all other errors as internal server errors\n const statusCode = error.statusCode || 500\n return reply.status(statusCode).send(\n formatError(\n statusCode,\n statusCode === 500 ? 'Internal Server Error' : error.name || 'Error',\n error.message || 'An unexpected error occurred'\n )\n )\n })\n}\n","import type { FastifyInstance } from 'fastify'\nimport fastifySwagger, { SwaggerOptions } from '@fastify/swagger'\nimport fastifySwaggerUI, { FastifySwaggerUiOptions } from '@fastify/swagger-ui'\nimport { jsonSchemaTransform } from 'fastify-type-provider-zod'\nimport type { CreateFastifyOptions, JWTRouteConfig } from './types.ts'\n\nexport async function setupSwagger(\n fastify: FastifyInstance,\n options: CreateFastifyOptions\n): Promise<string | undefined> {\n if (!options.swagger) {\n return undefined\n }\n\n const openApiConfig: any = {\n openapi: {\n info: {\n title: options.swagger.title,\n version: options.swagger.version,\n description: options.swagger.description,\n },\n },\n transform: jsonSchemaTransform,\n }\n\n // Add bearer auth security scheme if JWT is enabled\n if (options.jwt) {\n openApiConfig.openapi.components = {\n securitySchemes: {\n bearerAuth: {\n type: 'http',\n scheme: 'bearer',\n bearerFormat: 'JWT',\n },\n },\n }\n }\n\n await fastify.register(fastifySwagger, openApiConfig 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 return routePrefix\n}\n\nexport function setupSwaggerSecurityHook(\n fastify: FastifyInstance,\n options: CreateFastifyOptions,\n swaggerRoutePrefix: string | undefined\n): void {\n if (!options.jwt || !options.swagger) {\n return\n }\n\n // Auto-inject security requirements for JWT-protected routes\n fastify.addHook('onRoute', (routeOptions) => {\n // Skip Swagger routes\n if (swaggerRoutePrefix && routeOptions.url.startsWith(swaggerRoutePrefix)) {\n return\n }\n\n const routeConfig = (routeOptions.config as JWTRouteConfig) || {}\n const jwtConfig = routeConfig.jwt\n\n // Skip if JWT is explicitly bypassed\n if (jwtConfig === false) {\n return\n }\n\n // Determine if route requires JWT\n const requiresJWT =\n jwtConfig === true ||\n (typeof jwtConfig === 'object' && jwtConfig.required !== false) ||\n (jwtConfig === undefined && options.jwt?.global === true)\n\n // Inject security requirement if JWT is required\n if (requiresJWT) {\n if (!routeOptions.schema) {\n routeOptions.schema = {}\n }\n if (!routeOptions.schema.security) {\n routeOptions.schema.security = [{ bearerAuth: [] }]\n }\n }\n })\n}\n","import type { FastifyInstance } from 'fastify'\nimport fastifyJwt, { FastifyJWTOptions } from '@fastify/jwt'\nimport { formatError } from './response.ts'\nimport type { CreateFastifyOptions, JWTRouteConfig } from './types.ts'\n\nexport async function setupJWT(\n fastify: FastifyInstance,\n options: CreateFastifyOptions,\n swaggerRoutePrefix: string | undefined\n): Promise<void> {\n if (!options.jwt) {\n return\n }\n\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 // Skip JWT verification for Swagger documentation routes\n if (swaggerRoutePrefix && request.url.startsWith(swaggerRoutePrefix)) {\n return\n }\n\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 // Check if route requires service JWT token\n if (typeof jwtConfig === 'object' && jwtConfig.requireService) {\n const serviceAuthHeader = request.headers['x-service-authorization']\n if (!serviceAuthHeader) {\n return reply.status(401).send(\n formatError(401, 'Unauthorized', 'Missing service authorization token')\n )\n }\n\n const serviceToken = typeof serviceAuthHeader === 'string'\n ? serviceAuthHeader.replace('Bearer ', '')\n : serviceAuthHeader[0]?.replace('Bearer ', '')\n\n if (!serviceToken) {\n return reply.status(401).send(\n formatError(401, 'Unauthorized', 'Invalid service authorization header format')\n )\n }\n\n try {\n const servicePayload = fastify.jwt.verify(serviceToken) as any\n if (servicePayload.type !== 'service') {\n return reply.status(401).send(\n formatError(401, 'Unauthorized', 'Invalid service token type')\n )\n }\n // Store service info in request for potential use\n (request as any).serviceUser = servicePayload\n } catch (err) {\n return reply.status(401).send(\n formatError(401, 'Unauthorized', 'Invalid service authorization token')\n )\n }\n }\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 return reply.status(403).send(\n formatError(403, 'Forbidden', 'Authorization failed')\n )\n }\n }\n } catch (err) {\n return reply.status(401).send(\n formatError(401, 'Unauthorized', 'Invalid or missing JWT token')\n )\n }\n }\n })\n }\n}\n","import { z } from 'zod'\nimport { FastifyServer } from './fastify.ts'\n\n/**\n * Base access token payload schema\n */\nexport const baseAccessTokenPayloadSchema = z.object({\n identityId: z.string(),\n type: z.literal('access'),\n exp: z.number(),\n})\n\n/**\n * Base refresh token payload schema\n */\nexport const baseRefreshTokenPayloadSchema = z.object({\n identityId: z.string(),\n type: z.literal('refresh'),\n exp: z.number(),\n})\n\n/**\n * Service-to-service authentication token payload schema\n */\nexport const serviceAccessTokenPayloadSchema = z.object({\n serviceId: z.string(),\n type: z.literal('service'),\n exp: z.number(),\n})\n\n/**\n * Inferred types from base schemas\n */\nexport type BaseAccessTokenPayload = z.infer<typeof baseAccessTokenPayloadSchema>\nexport type BaseRefreshTokenPayload = z.infer<typeof baseRefreshTokenPayloadSchema>\nexport type ServiceAccessTokenPayload = z.infer<typeof serviceAccessTokenPayloadSchema>\n\n/**\n * Token pair interface\n */\nexport interface TokenPair {\n accessToken: string\n refreshToken: string\n}\n\n/**\n * FastifyJwtService configuration options\n */\nexport interface FastifyJwtServiceOptions {\n accessTokenExpiry: string\n refreshTokenExpiry: string\n renewalThreshold: string\n serviceTokenExpiry: string\n accessTokenSchema?: z.ZodSchema\n refreshTokenSchema?: z.ZodSchema\n}\n\n/**\n * Generic JWT service for Fastify applications\n *\n * @template TAccess - Access token payload type extending BaseAccessTokenPayload\n * @template TRefresh - Refresh token payload type extending BaseRefreshTokenPayload\n *\n * @example\n * // Using base schemas\n * const jwtService = new FastifyJwtService(app, {\n * accessTokenExpiry: '15m',\n * refreshTokenExpiry: '7d',\n * renewalThreshold: '1d',\n * })\n *\n * @example\n * // Using extended schemas\n * const customAccessSchema = baseAccessTokenPayloadSchema.extend({\n * roles: z.array(z.string())\n * })\n * const jwtService = new FastifyJwtService(app, {\n * accessTokenExpiry: '15m',\n * refreshTokenExpiry: '7d',\n * renewalThreshold: '1d',\n * accessTokenSchema: customAccessSchema,\n * })\n */\nexport class FastifyJwtService<\n TAccess extends BaseAccessTokenPayload = BaseAccessTokenPayload,\n TRefresh extends BaseRefreshTokenPayload = BaseRefreshTokenPayload\n> {\n private readonly accessTokenExpiry: string\n private readonly refreshTokenExpiry: string\n private readonly renewalThreshold: string\n private readonly serviceTokenExpiry: string\n private readonly accessTokenSchema: z.ZodSchema<TAccess>\n private readonly refreshTokenSchema: z.ZodSchema<TRefresh>\n\n constructor(\n private readonly app: FastifyServer,\n options: FastifyJwtServiceOptions\n ) {\n this.accessTokenExpiry = options.accessTokenExpiry\n this.refreshTokenExpiry = options.refreshTokenExpiry\n this.renewalThreshold = options.renewalThreshold\n this.serviceTokenExpiry = options.serviceTokenExpiry\n this.accessTokenSchema = (options.accessTokenSchema ?? baseAccessTokenPayloadSchema) as z.ZodSchema<TAccess>\n this.refreshTokenSchema = (options.refreshTokenSchema ?? baseRefreshTokenPayloadSchema) as z.ZodSchema<TRefresh>\n }\n\n /**\n * Generate an access token for the given identity\n */\n generateAccessToken(identityId: string, extraPayload?: Partial<Omit<TAccess, 'identityId' | 'type' | 'exp'>>): string {\n const payload = {\n identityId,\n type: 'access' as const,\n ...extraPayload,\n }\n\n return this.app.jwt.sign(payload, {\n expiresIn: this.accessTokenExpiry,\n })\n }\n\n /**\n * Generate a refresh token for the given identity\n */\n generateRefreshToken(identityId: string, extraPayload?: Partial<Omit<TRefresh, 'identityId' | 'type' | 'exp'>>): string {\n const payload = {\n identityId,\n type: 'refresh' as const,\n ...extraPayload,\n }\n\n return this.app.jwt.sign(payload, {\n expiresIn: this.refreshTokenExpiry,\n })\n }\n\n /**\n * Generate both access and refresh tokens\n */\n generateTokenPair(identityId: string): TokenPair {\n return {\n accessToken: this.generateAccessToken(identityId),\n refreshToken: this.generateRefreshToken(identityId),\n }\n }\n\n /**\n * Generate a service-to-service authentication token\n * @param serviceId - The identifier of the service (e.g., 'gateway', 'auth-service')\n * @returns JWT token valid for service-to-service communication\n */\n generateServiceToken(serviceId: string): string {\n const payload = {\n serviceId,\n type: 'service' as const,\n }\n\n return this.app.jwt.sign(payload, {\n expiresIn: this.serviceTokenExpiry,\n })\n }\n\n /**\n * Verify and decode an access token\n */\n verifyAccessToken(token: string): TAccess {\n try {\n const payload = this.app.jwt.verify(token) as unknown\n const validated = this.accessTokenSchema.parse(payload)\n\n if (validated.type !== 'access') {\n throw new Error('Invalid token type')\n }\n\n return validated\n } catch (error) {\n if (error instanceof z.ZodError) {\n throw new Error('Invalid token payload')\n }\n throw error\n }\n }\n\n /**\n * Verify and decode a refresh token\n */\n verifyRefreshToken(token: string): TRefresh {\n try {\n const payload = this.app.jwt.verify(token) as unknown\n const validated = this.refreshTokenSchema.parse(payload)\n\n if (validated.type !== 'refresh') {\n throw new Error('Invalid token type')\n }\n\n return validated\n } catch (error) {\n if (error instanceof z.ZodError) {\n throw new Error('Invalid token payload')\n }\n throw error\n }\n }\n\n /**\n * Renew a refresh token for the given identity\n */\n renewRefreshToken(identityId: string): string {\n return this.generateRefreshToken(identityId)\n }\n\n /**\n * Check if a refresh token should be renewed based on its expiry\n */\n shouldRenewRefreshToken(exp: number): boolean {\n const now = Math.floor(Date.now() / 1000)\n const threshold = this.parseTimespan(this.renewalThreshold)\n return (exp - now) < threshold\n }\n\n /**\n * Parse timespan string to seconds\n */\n private parseTimespan(timespan: string): number {\n const match = timespan.match(/^(\\d+)([smhd])$/)\n if (!match || !match[1] || !match[2]) {\n throw new Error(`Invalid timespan format: ${timespan}`)\n }\n\n const value = parseInt(match[1]!, 10)\n const unit = match[2]!\n\n switch (unit) {\n case 's':\n return value\n case 'm':\n return value * 60\n case 'h':\n return value * 3600\n case 'd':\n return value * 86400\n default:\n throw new Error(`Unknown timespan unit: ${unit}`)\n }\n }\n}\n","import { FastifyPluginCallback } from 'fastify'\nimport { FastifyServer } from './fastify.ts'\nimport { ZodTypeProvider } from 'fastify-type-provider-zod'\n\nexport function createFastifyPlugin(cb: FastifyPluginCallback) {\n return function createFastifyPluginWrapper(\n fastify: FastifyServer,\n options: Parameters<FastifyPluginCallback>[1],\n done: Parameters<FastifyPluginCallback>[2],\n ) {\n const server = fastify.withTypeProvider<ZodTypeProvider>()\n let doneCalled = false\n\n const doneWrapper = (err?: Error) => {\n done(err)\n doneCalled = true\n }\n\n cb(server, options, doneWrapper)\n\n if (!doneCalled) {\n done()\n }\n }\n}\n","import { createFastifyPlugin } from '../plugin.ts'\nimport { FastifyServer } from '../fastify.ts'\n\nexport const healthPlugin = createFastifyPlugin((app: FastifyServer) => {\n app.get('/v1/health', {\n schema: {\n tags: ['health'],\n },\n config: {\n jwt: false,\n },\n handler: async () => {\n return {\n status: 200,\n message: 'ok',\n }\n },\n })\n})\n","export * from './lib/fastify.ts'\nexport * from './lib/response.ts'\nexport * from './lib/types.ts'\nexport * from './lib/jwt.service.ts'\nexport * from './lib/plugin.ts'\nexport * from './lib/plugins/healthPlugin.ts'\nexport * from './lib/error-handler.ts'\nexport * from 'fastify-type-provider-zod'\nexport type { FastifyErrorCodes, FastifyRequest, FastifyReply } from 'fastify'\n"],"mappings":"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","names":["z"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a_jackie_z/fastify",
3
- "version": "1.1.7",
3
+ "version": "1.1.8",
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>",