@a_jackie_z/fastify 1.1.3 → 1.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -398,6 +398,7 @@ Creates and configures a Fastify server instance with Zod support and optional p
398
398
  Starts the Fastify server. Handles errors and exits the process if the server fails to start.
399
399
 
400
400
  **Parameters:**
401
+
401
402
  - `fastify` - The Fastify server instance
402
403
  - `host` - The host to bind to (e.g., '0.0.0.0' or 'localhost')
403
404
  - `port` - The port number to listen on
@@ -408,6 +409,69 @@ const app = await createFastify()
408
409
  await runFastify(app, '0.0.0.0', 3000)
409
410
  ```
410
411
 
412
+ ## Fastify JWT Service
413
+
414
+ A typed helper for issuing and verifying access/refresh tokens alongside the Fastify JWT plugin.
415
+
416
+ **Options**
417
+ - `accessTokenExpiry` (string) — required access token lifetime (e.g., `15m`)
418
+ - `refreshTokenExpiry` (string) — required refresh token lifetime (e.g., `7d`)
419
+ - `renewalThreshold` (string) — renew refresh tokens when `exp` is within this window
420
+ - `accessTokenSchema` (ZodSchema) — optional, extends `baseAccessTokenPayloadSchema`
421
+ - `refreshTokenSchema` (ZodSchema) — optional, extends `baseRefreshTokenPayloadSchema`
422
+
423
+ **Basic usage**
424
+ ```typescript
425
+ import {
426
+ createFastify,
427
+ FastifyJwtService,
428
+ baseAccessTokenPayloadSchema,
429
+ baseRefreshTokenPayloadSchema,
430
+ } from '@a_jackie_z/fastify'
431
+ import { z } from 'zod'
432
+
433
+ const app = await createFastify({
434
+ jwt: { secret: 'your-secret', global: false },
435
+ })
436
+
437
+ const jwtService = new FastifyJwtService(app, {
438
+ accessTokenExpiry: '15m',
439
+ refreshTokenExpiry: '7d',
440
+ renewalThreshold: '1d',
441
+ })
442
+
443
+ const { accessToken, refreshToken } = jwtService.generateTokenPair('identity-123')
444
+
445
+ const accessPayload = jwtService.verifyAccessToken(accessToken)
446
+ const refreshPayload = jwtService.verifyRefreshToken(refreshToken)
447
+
448
+ if (jwtService.shouldRenewRefreshToken(refreshPayload.exp)) {
449
+ const renewedRefreshToken = jwtService.renewRefreshToken(refreshPayload.identityId)
450
+ }
451
+ ```
452
+
453
+ **Custom payloads**
454
+ ```typescript
455
+ const accessTokenSchema = baseAccessTokenPayloadSchema.extend({
456
+ roles: z.array(z.string()),
457
+ })
458
+
459
+ const refreshTokenSchema = baseRefreshTokenPayloadSchema.extend({
460
+ deviceId: z.string().optional(),
461
+ })
462
+
463
+ const jwtService = new FastifyJwtService<
464
+ z.infer<typeof accessTokenSchema>,
465
+ z.infer<typeof refreshTokenSchema>
466
+ >(app, {
467
+ accessTokenExpiry: '15m',
468
+ refreshTokenExpiry: '7d',
469
+ renewalThreshold: '1d',
470
+ accessTokenSchema,
471
+ refreshTokenSchema,
472
+ })
473
+ ```
474
+
411
475
  ## Usage Patterns
412
476
 
413
477
  ### Pattern 1: Global JWT with Selective Public Routes
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  // lib/fastify.ts
2
2
  import Fastify from "fastify";
3
3
  import {
4
+ jsonSchemaTransform,
4
5
  serializerCompiler,
5
6
  validatorCompiler
6
7
  } from "fastify-type-provider-zod";
@@ -25,7 +26,8 @@ async function createFastify(options) {
25
26
  version: options.swagger.version,
26
27
  description: options.swagger.description
27
28
  }
28
- }
29
+ },
30
+ transform: jsonSchemaTransform
29
31
  });
30
32
  let routePrefix = options.swagger.routePrefix || "/docs/";
31
33
  if (!routePrefix.startsWith("/")) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../lib/fastify.ts","../lib/jwt.service.ts","../lib/plugin.ts","../lib/plugins/healthPlugin.ts","../index.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 // Store Swagger route prefix for JWT bypass logic\n let swaggerRoutePrefix: string | undefined\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 swaggerRoutePrefix = routePrefix\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 // 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 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 { 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/jwt.service.ts'\nexport * from './lib/plugin.ts'\nexport * from './lib/plugins/healthPlugin.ts'\nexport * from 'fastify-type-provider-zod'\nexport type {\n FastifyRequest,\n FastifyReply,\n} from 'fastify'\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../lib/fastify.ts","../lib/jwt.service.ts","../lib/plugin.ts","../lib/plugins/healthPlugin.ts","../index.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 jsonSchemaTransform,\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 // Store Swagger route prefix for JWT bypass logic\n let swaggerRoutePrefix: string | undefined\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 transform: jsonSchemaTransform,\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 swaggerRoutePrefix = routePrefix\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 // 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 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 { 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/jwt.service.ts'\nexport * from './lib/plugin.ts'\nexport * from './lib/plugins/healthPlugin.ts'\nexport * from 'fastify-type-provider-zod'\nexport type {\n FastifyRequest,\n FastifyReply,\n} from 'fastify'\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.1.3",
3
+ "version": "1.1.5",
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>",