@a_jackie_z/fastify 1.3.3 → 1.4.1
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 +70 -11
- package/dist/index.d.ts +19 -90
- package/dist/index.js +38 -62
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -5,15 +5,22 @@ A collection of Fastify plugins and utilities for building robust web applicatio
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
+
# For server-side Fastify applications
|
|
8
9
|
npm install @a_jackie_z/fastify
|
|
10
|
+
|
|
11
|
+
# For frontend applications (types and schemas only)
|
|
12
|
+
npm install @a_jackie_z/fastify-types
|
|
9
13
|
```
|
|
10
14
|
|
|
15
|
+
> **Note:** If you're building a frontend application (React, Vue, etc.) and only need API types and response schemas, install `@a_jackie_z/fastify-types` instead. It's frontend-compatible and has no Node.js dependencies.
|
|
16
|
+
|
|
11
17
|
## Quick Start
|
|
12
18
|
|
|
13
19
|
### Basic Setup
|
|
14
20
|
|
|
15
21
|
```typescript
|
|
16
|
-
import { createFastify, runFastify
|
|
22
|
+
import { createFastify, runFastify } from '@a_jackie_z/fastify'
|
|
23
|
+
import { formatSuccess } from '@a_jackie_z/fastify-types'
|
|
17
24
|
import { z } from 'zod'
|
|
18
25
|
|
|
19
26
|
const app = await createFastify()
|
|
@@ -40,6 +47,38 @@ app.route({
|
|
|
40
47
|
await runFastify(app, '0.0.0.0', 3000)
|
|
41
48
|
```
|
|
42
49
|
|
|
50
|
+
## Package Architecture
|
|
51
|
+
|
|
52
|
+
This package is split into two complementary packages for better frontend compatibility:
|
|
53
|
+
|
|
54
|
+
### `@a_jackie_z/fastify` (Server Package)
|
|
55
|
+
**For:** Node.js server applications
|
|
56
|
+
**Includes:**
|
|
57
|
+
- Fastify server creation and configuration (`createFastify`, `runFastify`)
|
|
58
|
+
- JWT service with token generation/verification (`FastifyJwtService`)
|
|
59
|
+
- Server-side crypto utilities (`generateId`, `generateSessionToken`)
|
|
60
|
+
- Fastify plugins and middleware
|
|
61
|
+
- Server-specific types (`CreateFastifyOptions`, `FastifyServer`)
|
|
62
|
+
|
|
63
|
+
### `@a_jackie_z/fastify-types` (Types Package)
|
|
64
|
+
**For:** Frontend applications (React, Vue, etc.) and API contracts
|
|
65
|
+
**Includes:**
|
|
66
|
+
- Response types (`SuccessResponse`, `ErrorResponse`, `ValidationDetail`)
|
|
67
|
+
- Response formatters (`formatSuccess`, `formatError`)
|
|
68
|
+
- Zod schemas (`successResponseSchema`, `errorResponseSchema`)
|
|
69
|
+
- JWT configuration types (`TokenTypeConfig`, `SignTokenOptions`)
|
|
70
|
+
- Error utilities (`createError`, `HTTP_STATUS_CODES`)
|
|
71
|
+
- No Node.js dependencies - browser compatible
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
// Server code
|
|
75
|
+
import { createFastify, generateId } from '@a_jackie_z/fastify'
|
|
76
|
+
import { formatSuccess } from '@a_jackie_z/fastify-types'
|
|
77
|
+
|
|
78
|
+
// Frontend code
|
|
79
|
+
import { successResponseSchema, type SuccessResponse } from '@a_jackie_z/fastify-types'
|
|
80
|
+
```
|
|
81
|
+
|
|
43
82
|
## Features
|
|
44
83
|
|
|
45
84
|
- **Dynamic JWT Authentication** - Flexible multi-token-type JWT system with per-type configuration
|
|
@@ -147,6 +186,9 @@ The JWT system supports **dynamic token types** where each type can have its own
|
|
|
147
186
|
Each token type is configured independently:
|
|
148
187
|
|
|
149
188
|
```typescript
|
|
189
|
+
// TokenTypeConfig is available in @a_jackie_z/fastify-types
|
|
190
|
+
import type { TokenTypeConfig } from '@a_jackie_z/fastify-types'
|
|
191
|
+
|
|
150
192
|
interface TokenTypeConfig {
|
|
151
193
|
headerName: string // Header to extract token from
|
|
152
194
|
expiresIn: string // Token expiration (e.g., '15m', '7d', '1h')
|
|
@@ -229,7 +271,7 @@ app.get('/public', { config: { jwtTypes: false } }, handler)
|
|
|
229
271
|
### 2. Authentication Flow - Login Route
|
|
230
272
|
|
|
231
273
|
```typescript
|
|
232
|
-
import { formatSuccess, formatError } from '@a_jackie_z/fastify'
|
|
274
|
+
import { formatSuccess, formatError } from '@a_jackie_z/fastify-types'
|
|
233
275
|
|
|
234
276
|
app.route({
|
|
235
277
|
method: 'POST',
|
|
@@ -620,7 +662,7 @@ All responses should follow a consistent format using the provided utility funct
|
|
|
620
662
|
#### Success Response Format
|
|
621
663
|
|
|
622
664
|
```typescript
|
|
623
|
-
import { formatSuccess } from '@a_jackie_z/fastify'
|
|
665
|
+
import { formatSuccess } from '@a_jackie_z/fastify-types'
|
|
624
666
|
|
|
625
667
|
app.route({
|
|
626
668
|
method: 'GET',
|
|
@@ -656,7 +698,7 @@ app.route({
|
|
|
656
698
|
#### Error Response Format
|
|
657
699
|
|
|
658
700
|
```typescript
|
|
659
|
-
import { formatError } from '@a_jackie_z/fastify'
|
|
701
|
+
import { formatError } from '@a_jackie_z/fastify-types'
|
|
660
702
|
|
|
661
703
|
app.route({
|
|
662
704
|
method: 'DELETE',
|
|
@@ -801,11 +843,13 @@ config: { jwtTypes: ['access', 'service'] }
|
|
|
801
843
|
|
|
802
844
|
## API Reference
|
|
803
845
|
|
|
804
|
-
### `
|
|
846
|
+
### Server Functions (`@a_jackie_z/fastify`)
|
|
847
|
+
|
|
848
|
+
#### `createFastify(options?: CreateFastifyOptions): Promise<FastifyServer>`
|
|
805
849
|
|
|
806
850
|
Creates and configures a Fastify server instance with Zod support and optional plugins.
|
|
807
851
|
|
|
808
|
-
|
|
852
|
+
#### `runFastify(fastify: FastifyServer, host: string, port: number): Promise<void>`
|
|
809
853
|
|
|
810
854
|
Starts the Fastify server. Handles errors and exits the process if the server fails to start.
|
|
811
855
|
|
|
@@ -821,7 +865,22 @@ const app = await createFastify()
|
|
|
821
865
|
await runFastify(app, '0.0.0.0', 3000)
|
|
822
866
|
```
|
|
823
867
|
|
|
824
|
-
|
|
868
|
+
#### Server-Side Crypto Utilities
|
|
869
|
+
|
|
870
|
+
```typescript
|
|
871
|
+
import { generateId, generateSessionToken, generateSecureString } from '@a_jackie_z/fastify'
|
|
872
|
+
|
|
873
|
+
// Generate 16-character alphanumeric ID
|
|
874
|
+
const id = generateId() // "A1b2C3d4E5f6G7h8"
|
|
875
|
+
|
|
876
|
+
// Generate 64-character hex session token
|
|
877
|
+
const token = generateSessionToken() // "abc123...def789"
|
|
878
|
+
|
|
879
|
+
// Generate custom secure string
|
|
880
|
+
const customId = generateSecureString(8, '0123456789') // "42875391"
|
|
881
|
+
```
|
|
882
|
+
|
|
883
|
+
### Response Formatting Functions (`@a_jackie_z/fastify-types`)
|
|
825
884
|
|
|
826
885
|
#### `formatSuccess<T>(status: number, data: T): SuccessResponse<T>`
|
|
827
886
|
|
|
@@ -875,7 +934,7 @@ return reply.status(404).send(
|
|
|
875
934
|
// Returns: { status: 404, success: false, error: 'Not Found', message: 'User not found' }
|
|
876
935
|
```
|
|
877
936
|
|
|
878
|
-
### Response Type Interfaces
|
|
937
|
+
### Response Type Interfaces (`@a_jackie_z/fastify-types`)
|
|
879
938
|
|
|
880
939
|
#### `SuccessResponse<T>`
|
|
881
940
|
```typescript
|
|
@@ -905,7 +964,7 @@ interface ValidationDetail {
|
|
|
905
964
|
}
|
|
906
965
|
```
|
|
907
966
|
|
|
908
|
-
### Zod Schema Helpers
|
|
967
|
+
### Zod Schema Helpers (`@a_jackie_z/fastify-types`)
|
|
909
968
|
|
|
910
969
|
For defining response schemas with Zod validation:
|
|
911
970
|
|
|
@@ -921,7 +980,7 @@ Creates a Zod schema for standardized success responses.
|
|
|
921
980
|
**Example:**
|
|
922
981
|
```typescript
|
|
923
982
|
import { z } from 'zod'
|
|
924
|
-
import { successResponseSchema } from '@a_jackie_z/fastify'
|
|
983
|
+
import { successResponseSchema } from '@a_jackie_z/fastify-types'
|
|
925
984
|
|
|
926
985
|
const userSchema = z.object({
|
|
927
986
|
id: z.string(),
|
|
@@ -948,7 +1007,7 @@ Zod schema for standardized error responses. Matches `ErrorResponse` interface.
|
|
|
948
1007
|
|
|
949
1008
|
**Example:**
|
|
950
1009
|
```typescript
|
|
951
|
-
import { errorResponseSchema } from '@a_jackie_z/fastify'
|
|
1010
|
+
import { errorResponseSchema } from '@a_jackie_z/fastify-types'
|
|
952
1011
|
|
|
953
1012
|
const myRouteSchema = {
|
|
954
1013
|
response: {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import * as fastify from 'fastify';
|
|
2
|
-
import { FastifyServerOptions, FastifyInstance, RawServerDefault, FastifyBaseLogger, FastifyContextConfig, FastifyPluginCallback
|
|
2
|
+
import { FastifyServerOptions, FastifyInstance, RawServerDefault, FastifyBaseLogger, FastifyContextConfig, FastifyPluginCallback } from 'fastify';
|
|
3
3
|
export { FastifyErrorCodes, FastifyReply, FastifyRequest } from 'fastify';
|
|
4
4
|
import { RateLimitPluginOptions } from '@fastify/rate-limit';
|
|
5
5
|
import { ZodTypeProvider } from 'fastify-type-provider-zod';
|
|
6
6
|
export * from 'fastify-type-provider-zod';
|
|
7
7
|
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
8
|
-
import {
|
|
9
|
-
import { z } from 'zod';
|
|
8
|
+
import { TokenTypeConfig } from '@a_jackie_z/fastify-types';
|
|
10
9
|
|
|
11
10
|
interface FastifyJwtServiceOptions {
|
|
12
11
|
secrets: Record<string, string>;
|
|
@@ -42,53 +41,6 @@ declare class FastifyJwtService {
|
|
|
42
41
|
getTokenTypeNames(): string[];
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
interface SignTokenOptions {
|
|
46
|
-
algorithm?: Algorithm;
|
|
47
|
-
iss?: string;
|
|
48
|
-
aud?: string;
|
|
49
|
-
header?: {
|
|
50
|
-
typ?: string;
|
|
51
|
-
cty?: string;
|
|
52
|
-
[key: string]: any;
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
interface VerifyTokenOptions {
|
|
56
|
-
allowedIss?: string[];
|
|
57
|
-
debug?: boolean;
|
|
58
|
-
expectedHeader?: {
|
|
59
|
-
typ?: string;
|
|
60
|
-
cty?: string;
|
|
61
|
-
[key: string]: any;
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Sign a JWT token with kid, expiration, and optional JWT header parameters
|
|
66
|
-
*/
|
|
67
|
-
declare function signToken(payload: Record<string, any>, secret: string, kid: string, expiresIn: string, options?: SignTokenOptions): string;
|
|
68
|
-
/**
|
|
69
|
-
* Verify a JWT token with kid-based secret selection and optional issuer validation
|
|
70
|
-
*/
|
|
71
|
-
declare function verifyToken(token: string, secrets: Record<string, string>, options?: VerifyTokenOptions): JwtPayload;
|
|
72
|
-
/**
|
|
73
|
-
* Extract token from header value with Bearer prefix stripping
|
|
74
|
-
* All JWT tokens must use Bearer prefix format: "Bearer <token>"
|
|
75
|
-
*/
|
|
76
|
-
declare function extractTokenFromHeader(headerValue: string | string[] | undefined, headerName: string, debug?: boolean): string | null;
|
|
77
|
-
|
|
78
|
-
interface TokenTypeConfig {
|
|
79
|
-
headerName: string;
|
|
80
|
-
expiresIn: string;
|
|
81
|
-
payloadSchema?: z.ZodSchema<any>;
|
|
82
|
-
algorithm?: Algorithm;
|
|
83
|
-
iss?: string;
|
|
84
|
-
aud?: string;
|
|
85
|
-
allowedIss?: string[];
|
|
86
|
-
header?: {
|
|
87
|
-
typ?: string;
|
|
88
|
-
cty?: string;
|
|
89
|
-
[key: string]: any;
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
44
|
declare module 'fastify' {
|
|
93
45
|
interface FastifyContextConfig {
|
|
94
46
|
jwtTypes?: string[] | false;
|
|
@@ -102,6 +54,8 @@ declare module 'fastify' {
|
|
|
102
54
|
}
|
|
103
55
|
interface CreateFastifyOptions {
|
|
104
56
|
logger?: FastifyServerOptions['loggerInstance'];
|
|
57
|
+
requestTimeout?: number;
|
|
58
|
+
bodyLimit?: number;
|
|
105
59
|
rateLimit?: {
|
|
106
60
|
global?: RateLimitPluginOptions;
|
|
107
61
|
};
|
|
@@ -121,39 +75,20 @@ interface CreateFastifyOptions {
|
|
|
121
75
|
}
|
|
122
76
|
type FastifyServer = FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse, FastifyBaseLogger, ZodTypeProvider> & FastifyContextConfig;
|
|
123
77
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
details?: ValidationDetail[];
|
|
139
|
-
}
|
|
140
|
-
declare function formatSuccess<T>(status: number, data: T): SuccessResponse<T>;
|
|
141
|
-
declare function formatError(status: number, error: string, message: string, details?: ValidationDetail[]): ErrorResponse;
|
|
142
|
-
declare const successResponseSchema: <T extends z.ZodTypeAny>(dataSchema: T) => z.ZodObject<{
|
|
143
|
-
status: z.ZodNumber;
|
|
144
|
-
success: z.ZodLiteral<true>;
|
|
145
|
-
data: T;
|
|
146
|
-
}, z.core.$strip>;
|
|
147
|
-
declare const errorResponseSchema: z.ZodObject<{
|
|
148
|
-
status: z.ZodNumber;
|
|
149
|
-
success: z.ZodLiteral<false>;
|
|
150
|
-
error: z.ZodString;
|
|
151
|
-
message: z.ZodString;
|
|
152
|
-
details: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
153
|
-
field: z.ZodString;
|
|
154
|
-
message: z.ZodString;
|
|
155
|
-
}, z.core.$strip>>>;
|
|
156
|
-
}, z.core.$strip>;
|
|
78
|
+
/**
|
|
79
|
+
* Generate a random 16-character alphanumeric ID
|
|
80
|
+
*/
|
|
81
|
+
declare function generateId(): string;
|
|
82
|
+
/**
|
|
83
|
+
* Generate a secure session token (64-character hex string)
|
|
84
|
+
*/
|
|
85
|
+
declare function generateSessionToken(): string;
|
|
86
|
+
/**
|
|
87
|
+
* Generate a secure random string with specified length
|
|
88
|
+
* @param length - Length of the string to generate
|
|
89
|
+
* @param alphabet - Alphabet to use (defaults to alphanumeric)
|
|
90
|
+
*/
|
|
91
|
+
declare function generateSecureString(length: number, alphabet?: string): string;
|
|
157
92
|
|
|
158
93
|
declare function createFastify(options?: CreateFastifyOptions): Promise<FastifyServer>;
|
|
159
94
|
declare function runFastify(fastify: FastifyServer, host: string, port: number): Promise<void>;
|
|
@@ -170,12 +105,6 @@ declare function createFastifyPlugin(cb: FastifyPluginCallback): (fastify: Fasti
|
|
|
170
105
|
|
|
171
106
|
declare const healthPlugin: (fastify: FastifyServer, options: Parameters<fastify.FastifyPluginCallback>[1], done: Parameters<fastify.FastifyPluginCallback>[2]) => void;
|
|
172
107
|
|
|
173
|
-
interface CreateErrorOptions {
|
|
174
|
-
statusCode?: number;
|
|
175
|
-
message: string;
|
|
176
|
-
name?: string;
|
|
177
|
-
}
|
|
178
|
-
declare function createError(options: CreateErrorOptions): FastifyError;
|
|
179
108
|
declare function setupErrorHandler(fastify: FastifyInstance): void;
|
|
180
109
|
|
|
181
|
-
export { type
|
|
110
|
+
export { type CreateFastifyOptions, FastifyJwtService, type FastifyJwtServiceOptions, type FastifyServer, createFastify, createFastifyPlugin, generateId, generateSecureString, generateSessionToken, healthPlugin, parseJwtSecrets, runFastify, setupErrorHandler };
|
package/dist/index.js
CHANGED
|
@@ -3,55 +3,8 @@ import Fastify from "fastify";
|
|
|
3
3
|
import { serializerCompiler, validatorCompiler } from "fastify-type-provider-zod";
|
|
4
4
|
import fastifyRateLimit from "@fastify/rate-limit";
|
|
5
5
|
|
|
6
|
-
// lib/response.ts
|
|
7
|
-
import { z } from "zod";
|
|
8
|
-
function formatSuccess(status, data) {
|
|
9
|
-
return {
|
|
10
|
-
status,
|
|
11
|
-
success: true,
|
|
12
|
-
data
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
function formatError(status, error, message, details) {
|
|
16
|
-
const response = {
|
|
17
|
-
status,
|
|
18
|
-
success: false,
|
|
19
|
-
error,
|
|
20
|
-
message
|
|
21
|
-
};
|
|
22
|
-
if (details && details.length > 0) {
|
|
23
|
-
response.details = details;
|
|
24
|
-
}
|
|
25
|
-
return response;
|
|
26
|
-
}
|
|
27
|
-
var successResponseSchema = (dataSchema) => z.object({
|
|
28
|
-
status: z.number(),
|
|
29
|
-
success: z.literal(true),
|
|
30
|
-
data: dataSchema
|
|
31
|
-
});
|
|
32
|
-
var errorResponseSchema = z.object({
|
|
33
|
-
status: z.number(),
|
|
34
|
-
success: z.literal(false),
|
|
35
|
-
error: z.string(),
|
|
36
|
-
message: z.string(),
|
|
37
|
-
details: z.array(z.object({
|
|
38
|
-
field: z.string(),
|
|
39
|
-
message: z.string()
|
|
40
|
-
})).optional()
|
|
41
|
-
});
|
|
42
|
-
|
|
43
6
|
// lib/error-handler.ts
|
|
44
|
-
|
|
45
|
-
const {
|
|
46
|
-
statusCode = 500,
|
|
47
|
-
message,
|
|
48
|
-
name = "Error"
|
|
49
|
-
} = options;
|
|
50
|
-
const error = new Error(message);
|
|
51
|
-
error.statusCode = statusCode;
|
|
52
|
-
error.name = name;
|
|
53
|
-
return error;
|
|
54
|
-
}
|
|
7
|
+
import { formatError } from "@a_jackie_z/fastify-types";
|
|
55
8
|
function setupErrorHandler(fastify) {
|
|
56
9
|
fastify.setErrorHandler((error, request, reply) => {
|
|
57
10
|
fastify.log.error({
|
|
@@ -446,6 +399,7 @@ async function registerJWT(fastify, options) {
|
|
|
446
399
|
}
|
|
447
400
|
|
|
448
401
|
// lib/jwt/hooks.ts
|
|
402
|
+
import { formatError as formatError2 } from "@a_jackie_z/fastify-types";
|
|
449
403
|
function createVerificationHook(options) {
|
|
450
404
|
return async (request, reply) => {
|
|
451
405
|
const { jwtService, swaggerRoutePrefix, requiredTypes, debug } = options;
|
|
@@ -472,7 +426,7 @@ function createVerificationHook(options) {
|
|
|
472
426
|
const tokenTypeConfig = jwtService.getTokenTypeConfig(typeName);
|
|
473
427
|
if (!tokenTypeConfig) {
|
|
474
428
|
const errorMsg = debug ? `Unknown token type "${typeName}" in route configuration. Available types: ${jwtService.getTokenTypeNames().join(", ")}` : `Unknown token type "${typeName}"`;
|
|
475
|
-
return reply.status(500).send(
|
|
429
|
+
return reply.status(500).send(formatError2(500, "Internal Server Error", errorMsg));
|
|
476
430
|
}
|
|
477
431
|
const headerName = tokenTypeConfig.headerName.toLowerCase();
|
|
478
432
|
const headerValue = request.headers[headerName];
|
|
@@ -481,18 +435,18 @@ function createVerificationHook(options) {
|
|
|
481
435
|
token = jwtService.extractTokenFromHeader(headerValue, typeName);
|
|
482
436
|
} catch (err) {
|
|
483
437
|
const errorMsg = debug && err instanceof Error ? err.message : `Invalid ${headerName} header format`;
|
|
484
|
-
return reply.status(401).send(
|
|
438
|
+
return reply.status(401).send(formatError2(401, "Unauthorized", errorMsg));
|
|
485
439
|
}
|
|
486
440
|
if (!token) {
|
|
487
441
|
const errorMsg = debug ? `Missing or invalid ${headerName} header for token type "${typeName}"` : `Missing or invalid ${headerName} header`;
|
|
488
|
-
return reply.status(401).send(
|
|
442
|
+
return reply.status(401).send(formatError2(401, "Unauthorized", errorMsg));
|
|
489
443
|
}
|
|
490
444
|
try {
|
|
491
445
|
const payload = jwtService.verifyToken(typeName, token);
|
|
492
446
|
request.jwtPayloads.set(typeName, payload);
|
|
493
447
|
} catch (err) {
|
|
494
448
|
const errorMsg = debug && err instanceof Error ? `Token verification failed for type "${typeName}": ${err.message}` : `Invalid or expired ${typeName} token`;
|
|
495
|
-
return reply.status(401).send(
|
|
449
|
+
return reply.status(401).send(formatError2(401, "Unauthorized", errorMsg));
|
|
496
450
|
}
|
|
497
451
|
}
|
|
498
452
|
};
|
|
@@ -522,9 +476,36 @@ async function setupJWT(fastify, options, swaggerRoutePrefix) {
|
|
|
522
476
|
fastify.addHook("onRequest", createVerificationHook(hookOptions));
|
|
523
477
|
}
|
|
524
478
|
|
|
479
|
+
// lib/crypto-utils.ts
|
|
480
|
+
import { randomBytes } from "crypto";
|
|
481
|
+
var ID_ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
482
|
+
var ID_LENGTH = 16;
|
|
483
|
+
function generateId() {
|
|
484
|
+
const bytes = randomBytes(ID_LENGTH);
|
|
485
|
+
let result = "";
|
|
486
|
+
for (let i = 0; i < ID_LENGTH; i++) {
|
|
487
|
+
result += ID_ALPHABET[bytes[i] % ID_ALPHABET.length];
|
|
488
|
+
}
|
|
489
|
+
return result;
|
|
490
|
+
}
|
|
491
|
+
function generateSessionToken() {
|
|
492
|
+
return randomBytes(32).toString("hex");
|
|
493
|
+
}
|
|
494
|
+
function generateSecureString(length, alphabet = ID_ALPHABET) {
|
|
495
|
+
const bytes = randomBytes(length);
|
|
496
|
+
let result = "";
|
|
497
|
+
for (let i = 0; i < length; i++) {
|
|
498
|
+
result += alphabet[bytes[i] % alphabet.length];
|
|
499
|
+
}
|
|
500
|
+
return result;
|
|
501
|
+
}
|
|
502
|
+
|
|
525
503
|
// lib/fastify.ts
|
|
526
504
|
async function createFastify(options) {
|
|
527
|
-
const fastifyOptions = {
|
|
505
|
+
const fastifyOptions = {
|
|
506
|
+
...options?.requestTimeout ? { requestTimeout: options.requestTimeout } : {},
|
|
507
|
+
...options?.bodyLimit ? { bodyLimit: options.bodyLimit } : {}
|
|
508
|
+
};
|
|
528
509
|
if (options?.logger) {
|
|
529
510
|
fastifyOptions.loggerInstance = options.logger;
|
|
530
511
|
}
|
|
@@ -628,19 +609,14 @@ var healthPlugin = createFastifyPlugin((app) => {
|
|
|
628
609
|
export * from "fastify-type-provider-zod";
|
|
629
610
|
export {
|
|
630
611
|
FastifyJwtService,
|
|
631
|
-
createError,
|
|
632
612
|
createFastify,
|
|
633
613
|
createFastifyPlugin,
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
formatSuccess,
|
|
614
|
+
generateId,
|
|
615
|
+
generateSecureString,
|
|
616
|
+
generateSessionToken,
|
|
638
617
|
healthPlugin,
|
|
639
618
|
parseJwtSecrets,
|
|
640
619
|
runFastify,
|
|
641
|
-
setupErrorHandler
|
|
642
|
-
signToken,
|
|
643
|
-
successResponseSchema,
|
|
644
|
-
verifyToken
|
|
620
|
+
setupErrorHandler
|
|
645
621
|
};
|
|
646
622
|
//# sourceMappingURL=index.js.map
|
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/core.ts","../lib/jwt/service.ts","../lib/jwt/register.ts","../lib/jwt/hooks.ts","../lib/jwt/setup.ts","../lib/jwt/utils.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 } 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 security schemes for each token type if JWT is enabled\n if (options.jwt && options.jwt.tokenTypes) {\n const securitySchemes: any = {}\n\n for (const [typeName, typeConfig] of Object.entries(options.jwt.tokenTypes)) {\n const headerName = typeConfig.headerName.toLowerCase()\n\n // Use bearer auth for 'authorization' header, apiKey for custom headers\n if (headerName === 'authorization') {\n securitySchemes[typeName] = {\n type: 'http',\n scheme: 'bearer',\n bearerFormat: 'JWT',\n description: `JWT token for ${typeName} authentication`,\n }\n } else {\n securitySchemes[typeName] = {\n type: 'apiKey',\n in: 'header',\n name: typeConfig.headerName,\n description: `JWT token for ${typeName} authentication`,\n }\n }\n }\n\n openApiConfig.openapi.components = {\n securitySchemes,\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 any) || {}\n const jwtTypes = routeConfig.jwtTypes\n\n // Skip if JWT is explicitly bypassed\n if (jwtTypes === false) {\n return\n }\n\n // Determine which token types are required\n // Start with global requiredTypes (always checked)\n let requiredTypes: string[] = []\n\n if (options.jwt?.requiredTypes && options.jwt.requiredTypes.length > 0) {\n requiredTypes = [...options.jwt.requiredTypes]\n }\n\n // Add route-specific types if specified\n if (Array.isArray(jwtTypes) && jwtTypes.length > 0) {\n // Combine both, removing duplicates\n requiredTypes = [...new Set([...requiredTypes, ...jwtTypes])]\n }\n\n // Inject security requirement if JWT types are required\n if (requiredTypes.length > 0) {\n if (!routeOptions.schema) {\n routeOptions.schema = {}\n }\n if (!routeOptions.schema.security) {\n routeOptions.schema.security = requiredTypes.map(typeName => ({ [typeName]: [] }))\n }\n }\n })\n}\n","import jwt, { Algorithm, JwtPayload, SignOptions, VerifyOptions } from 'jsonwebtoken'\n\nexport interface SignTokenOptions {\n algorithm?: Algorithm\n iss?: string\n aud?: string\n header?: {\n typ?: string\n cty?: string\n [key: string]: any\n }\n}\n\nexport interface VerifyTokenOptions {\n allowedIss?: string[]\n debug?: boolean\n expectedHeader?: {\n typ?: string\n cty?: string\n [key: string]: any\n }\n}\n\n/**\n * Sign a JWT token with kid, expiration, and optional JWT header parameters\n */\nexport function signToken(\n payload: Record<string, any>,\n secret: string,\n kid: string,\n expiresIn: string,\n options?: SignTokenOptions\n): string {\n const signOptions: SignOptions = {\n expiresIn: expiresIn as any,\n keyid: kid,\n }\n\n if (options?.algorithm) {\n signOptions.algorithm = options.algorithm\n }\n if (options?.iss) {\n signOptions.issuer = options.iss\n }\n if (options?.aud) {\n signOptions.audience = options.aud\n }\n\n // Apply custom header configuration\n if (options?.header) {\n const headerConfig: Record<string, any> = {}\n\n // Add standard JWT headers\n if (options.header.typ !== undefined) {\n headerConfig.typ = options.header.typ\n }\n if (options.header.cty !== undefined) {\n headerConfig.cty = options.header.cty\n }\n\n // Add custom header claims (exclude typ and cty as they're already handled)\n for (const [key, value] of Object.entries(options.header)) {\n if (key !== 'typ' && key !== 'cty') {\n headerConfig[key] = value\n }\n }\n\n // Only set header if we have custom fields\n if (Object.keys(headerConfig).length > 0) {\n signOptions.header = headerConfig as any\n }\n }\n\n return jwt.sign(payload, secret, signOptions)\n}\n\n/**\n * Verify a JWT token with kid-based secret selection and optional issuer validation\n */\nexport function verifyToken(\n token: string,\n secrets: Record<string, string>,\n options?: VerifyTokenOptions\n): JwtPayload {\n const debug = options?.debug ?? false\n\n try {\n // Decode header to extract kid\n const parts = token.split('.')\n if (parts.length !== 3 || !parts[0]) {\n throw new Error(debug ? 'Malformed JWT token: Token must have 3 parts separated by dots' : 'Malformed token')\n }\n\n const headerPart = parts[0]\n let header: any\n try {\n header = JSON.parse(Buffer.from(headerPart, 'base64').toString())\n } catch {\n throw new Error(debug ? 'Malformed JWT token: Invalid base64 encoding in header' : 'Malformed token')\n }\n\n const kid = header.kid\n if (!kid) {\n throw new Error(\n debug\n ? 'Missing kid in JWT token header. Ensure the token was signed with a kid parameter.'\n : 'Missing kid in token header'\n )\n }\n\n // Validate expected header claims if configured\n if (options?.expectedHeader) {\n // Validate typ (token type)\n if (options.expectedHeader.typ !== undefined && header.typ !== options.expectedHeader.typ) {\n throw new Error(\n debug\n ? `Invalid JWT header 'typ': expected \"${options.expectedHeader.typ}\", got \"${header.typ || 'undefined'}\"`\n : 'Invalid JWT header typ'\n )\n }\n\n // Validate cty (content type)\n if (options.expectedHeader.cty !== undefined && header.cty !== options.expectedHeader.cty) {\n throw new Error(\n debug\n ? `Invalid JWT header 'cty': expected \"${options.expectedHeader.cty}\", got \"${header.cty || 'undefined'}\"`\n : 'Invalid JWT header cty'\n )\n }\n\n // Validate custom header claims\n for (const [key, expectedValue] of Object.entries(options.expectedHeader)) {\n if (key !== 'typ' && key !== 'cty' && expectedValue !== undefined) {\n if (header[key] !== expectedValue) {\n throw new Error(\n debug\n ? `Invalid JWT header '${key}': expected \"${expectedValue}\", got \"${header[key] || 'undefined'}\"`\n : `Invalid JWT header ${key}`\n )\n }\n }\n }\n }\n\n const secret = secrets[kid]\n if (!secret) {\n const availableKeys = Object.keys(secrets).join(', ')\n throw new Error(\n debug\n ? `Unknown key ID \"${kid}\" in JWT token. Available keys: ${availableKeys}`\n : `Unknown key ID \"${kid}\"`\n )\n }\n\n // Verify token with the secret\n const verifyOptions: VerifyOptions = {\n complete: false,\n }\n\n const decoded = jwt.verify(token, secret, verifyOptions) as JwtPayload\n\n // Validate issuer if allowedIss is configured\n if (options?.allowedIss && options.allowedIss.length > 0) {\n const tokenIss = decoded.iss\n if (!tokenIss) {\n throw new Error(\n debug\n ? `Token missing issuer (iss) claim. Expected one of: ${options.allowedIss.join(', ')}`\n : 'Token missing issuer claim'\n )\n }\n if (!options.allowedIss.includes(tokenIss)) {\n throw new Error(\n debug\n ? `Invalid token issuer \"${tokenIss}\". Expected one of: ${options.allowedIss.join(', ')}`\n : `Invalid token issuer \"${tokenIss}\"`\n )\n }\n }\n\n return decoded\n } catch (error) {\n if (error instanceof jwt.TokenExpiredError) {\n if (debug) {\n const expDate = new Date(error.expiredAt).toISOString()\n const now = Math.floor(Date.now() / 1000)\n const exp = Math.floor(error.expiredAt.getTime() / 1000)\n const diff = now - exp\n throw new Error(`Token expired at ${expDate} (${diff} seconds ago)`)\n }\n throw new Error('Token has expired')\n }\n\n if (error instanceof jwt.JsonWebTokenError) {\n if (debug) {\n if (error.message.includes('signature')) {\n throw new Error('Invalid token signature: Token was signed with a different secret or has been tampered with')\n }\n if (error.message.includes('malformed')) {\n throw new Error('Malformed token: Token structure is invalid or corrupted')\n }\n throw new Error(`Token verification failed: ${error.message}`)\n }\n throw new Error('Invalid token')\n }\n\n throw error\n }\n}\n\n/**\n * Extract token from header value with Bearer prefix stripping\n * All JWT tokens must use Bearer prefix format: \"Bearer <token>\"\n */\nexport function extractTokenFromHeader(\n headerValue: string | string[] | undefined,\n headerName: string,\n debug?: boolean\n): string | null {\n if (!headerValue) {\n return null\n }\n\n const value = typeof headerValue === 'string' ? headerValue : headerValue[0]\n if (!value) {\n return null\n }\n\n // All JWT tokens must use \"Bearer <token>\" format\n const match = value.match(/^Bearer\\s+(\\S+)$/i)\n if (!match || !match[1]) {\n if (debug && value) {\n throw new Error(`Invalid ${headerName} header format. Expected: \"Bearer <token>\"`)\n }\n return null\n }\n\n return match[1]\n}\n\n","import { signToken, verifyToken, extractTokenFromHeader, type SignTokenOptions, type VerifyTokenOptions } from './core.ts'\nimport type { TokenTypeConfig } from '../types.ts'\n\nexport interface FastifyJwtServiceOptions {\n secrets: Record<string, string>\n defaultKeyId: string\n tokenTypes: Record<string, TokenTypeConfig>\n debug?: boolean\n}\n\nexport class FastifyJwtService {\n private readonly secrets: Record<string, string>\n private readonly defaultKeyId: string\n private readonly tokenTypes: Record<string, TokenTypeConfig>\n private readonly debug: boolean\n\n constructor(options: FastifyJwtServiceOptions) {\n this.secrets = options.secrets\n this.defaultKeyId = options.defaultKeyId\n this.tokenTypes = options.tokenTypes\n this.debug = options.debug ?? false\n }\n\n /**\n * Generate a token for a specific type\n */\n generateToken(typeName: string, payload: Record<string, any>): string {\n const tokenType = this.tokenTypes[typeName]\n if (!tokenType) {\n throw new Error(\n this.debug\n ? `Unknown token type \"${typeName}\". Available types: ${Object.keys(this.tokenTypes).join(', ')}`\n : `Unknown token type \"${typeName}\"`\n )\n }\n\n const signOptions: SignTokenOptions = {}\n if (tokenType.algorithm) signOptions.algorithm = tokenType.algorithm\n if (tokenType.iss) signOptions.iss = tokenType.iss\n if (tokenType.aud) signOptions.aud = tokenType.aud\n if (tokenType.header) signOptions.header = tokenType.header\n\n const secret = this.secrets[this.defaultKeyId]\n if (!secret) {\n throw new Error(`Default key ID \"${this.defaultKeyId}\" not found in secrets`)\n }\n\n return signToken(payload, secret, this.defaultKeyId, tokenType.expiresIn, signOptions)\n }\n\n /**\n * Verify a token for a specific type\n */\n verifyToken(typeName: string, token: string): any {\n const tokenType = this.tokenTypes[typeName]\n if (!tokenType) {\n throw new Error(\n this.debug\n ? `Unknown token type \"${typeName}\". Available types: ${Object.keys(this.tokenTypes).join(', ')}`\n : `Unknown token type \"${typeName}\"`\n )\n }\n\n const verifyOptions: VerifyTokenOptions = {\n debug: this.debug,\n }\n\n if (tokenType.allowedIss && tokenType.allowedIss.length > 0) {\n verifyOptions.allowedIss = tokenType.allowedIss\n }\n\n if (tokenType.header) {\n verifyOptions.expectedHeader = tokenType.header\n }\n\n const decoded = verifyToken(token, this.secrets, verifyOptions)\n\n // Validate payload with Zod schema if provided\n if (tokenType.payloadSchema) {\n try {\n return tokenType.payloadSchema.parse(decoded)\n } catch (error) {\n if (this.debug && error instanceof Error) {\n throw new Error(`Token payload validation failed: ${error.message}`)\n }\n throw new Error('Invalid token payload')\n }\n }\n\n return decoded\n }\n\n /**\n * Extract token from header value\n */\n extractTokenFromHeader(headerValue: string | string[] | undefined, typeName: string): string | null {\n const tokenType = this.tokenTypes[typeName]\n if (!tokenType) {\n throw new Error(\n this.debug\n ? `Unknown token type \"${typeName}\". Available types: ${Object.keys(this.tokenTypes).join(', ')}`\n : `Unknown token type \"${typeName}\"`\n )\n }\n\n return extractTokenFromHeader(headerValue, tokenType.headerName, this.debug)\n }\n\n /**\n * Get token type configuration\n */\n getTokenTypeConfig(typeName: string): TokenTypeConfig | undefined {\n return this.tokenTypes[typeName]\n }\n\n /**\n * Get all configured token type names\n */\n getTokenTypeNames(): string[] {\n return Object.keys(this.tokenTypes)\n }\n}\n\n","import type { FastifyInstance } from 'fastify'\nimport { FastifyJwtService, type FastifyJwtServiceOptions } from './service.ts'\n\nexport async function registerJWT(\n fastify: FastifyInstance,\n options: FastifyJwtServiceOptions\n): Promise<FastifyJwtService> {\n const { secrets, defaultKeyId, tokenTypes } = options\n\n // Validate that defaultKeyId exists in secrets\n if (!secrets[defaultKeyId]) {\n throw new Error(`Default key ID \"${defaultKeyId}\" not found in JWT secrets`)\n }\n\n // Validate that at least one token type is configured\n if (!tokenTypes || Object.keys(tokenTypes).length === 0) {\n throw new Error('At least one token type must be configured')\n }\n\n // Validate token types configuration\n for (const [typeName, config] of Object.entries(tokenTypes)) {\n if (!config.headerName) {\n throw new Error(`Token type \"${typeName}\" is missing required field: headerName`)\n }\n if (!config.expiresIn) {\n throw new Error(`Token type \"${typeName}\" is missing required field: expiresIn`)\n }\n }\n\n // Create JWT service\n const jwtService = new FastifyJwtService(options)\n\n // Decorate Fastify instance\n fastify.decorate('jwtService', jwtService)\n\n return jwtService\n}\n","import type { FastifyReply, FastifyRequest } from 'fastify'\nimport { formatError } from '../response.ts'\nimport type { FastifyJwtService } from './service.ts'\n\ninterface HookOptions {\n jwtService: FastifyJwtService\n swaggerRoutePrefix?: string\n requiredTypes?: string[]\n debug?: boolean\n}\n\nexport function createVerificationHook(options: HookOptions) {\n return async (request: FastifyRequest, reply: FastifyReply) => {\n const { jwtService, swaggerRoutePrefix, requiredTypes, debug } = options\n\n // Skip Swagger routes\n if (swaggerRoutePrefix && request.url.startsWith(swaggerRoutePrefix)) {\n return\n }\n\n const routeConfig = (request.routeOptions.config as any) || {}\n const jwtTypes = routeConfig.jwtTypes\n\n // If jwtTypes is explicitly false, skip verification\n if (jwtTypes === false) {\n return\n }\n\n // Determine which token types to verify\n // Always include requiredTypes first (checked for all routes)\n let typesToVerify: string[] = []\n\n if (requiredTypes && requiredTypes.length > 0) {\n typesToVerify = [...requiredTypes]\n }\n\n // Add route-specific types if specified\n if (Array.isArray(jwtTypes) && jwtTypes.length > 0) {\n // Combine both, removing duplicates\n typesToVerify = [...new Set([...typesToVerify, ...jwtTypes])]\n }\n\n // If no types to verify, route is public\n if (typesToVerify.length === 0) {\n return\n }\n\n // Initialize jwtPayloads map on request\n request.jwtPayloads = new Map()\n\n // Verify each required token type\n for (const typeName of typesToVerify) {\n const tokenTypeConfig = jwtService.getTokenTypeConfig(typeName)\n if (!tokenTypeConfig) {\n const errorMsg = debug\n ? `Unknown token type \"${typeName}\" in route configuration. Available types: ${jwtService.getTokenTypeNames().join(', ')}`\n : `Unknown token type \"${typeName}\"`\n return reply.status(500).send(formatError(500, 'Internal Server Error', errorMsg))\n }\n\n // Extract token from configured header\n const headerName = tokenTypeConfig.headerName.toLowerCase()\n const headerValue = request.headers[headerName]\n\n let token: string | null = null\n try {\n token = jwtService.extractTokenFromHeader(headerValue, typeName)\n } catch (err) {\n const errorMsg = debug && err instanceof Error\n ? err.message\n : `Invalid ${headerName} header format`\n return reply.status(401).send(formatError(401, 'Unauthorized', errorMsg))\n }\n\n if (!token) {\n const errorMsg = debug\n ? `Missing or invalid ${headerName} header for token type \"${typeName}\"`\n : `Missing or invalid ${headerName} header`\n return reply.status(401).send(formatError(401, 'Unauthorized', errorMsg))\n }\n\n // Verify token\n try {\n const payload = jwtService.verifyToken(typeName, token)\n request.jwtPayloads.set(typeName, payload)\n } catch (err) {\n const errorMsg = debug && err instanceof Error\n ? `Token verification failed for type \"${typeName}\": ${err.message}`\n : `Invalid or expired ${typeName} token`\n return reply.status(401).send(formatError(401, 'Unauthorized', errorMsg))\n }\n }\n }\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { CreateFastifyOptions } from '../types.ts'\nimport { registerJWT } from './register.ts'\nimport { createVerificationHook } from './hooks.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 jwtService = await registerJWT(fastify, {\n secrets: options.jwt.secrets,\n defaultKeyId: options.jwt.defaultKeyId,\n tokenTypes: options.jwt.tokenTypes,\n debug: options.jwt.debug ?? false,\n })\n\n // Add verification hook for JWT verification (always add when JWT configured)\n const hookOptions: Parameters<typeof createVerificationHook>[0] = {\n jwtService,\n debug: options.jwt.debug ?? false,\n }\n\n if (options.jwt.requiredTypes !== undefined) {\n hookOptions.requiredTypes = options.jwt.requiredTypes\n }\n\n if (swaggerRoutePrefix !== undefined) {\n hookOptions.swaggerRoutePrefix = swaggerRoutePrefix\n }\n\n fastify.addHook('onRequest', createVerificationHook(hookOptions))\n}\n","/**\n * Parse JWT secrets from environment variable format\n * @param secretsString - Secrets in format: \"key1=secret1|key2=secret2\"\n * @returns Record mapping key IDs to their secrets\n * @throws Error if format is invalid, empty, contains duplicates, or has empty values\n */\nexport function parseJwtSecrets(secretsString: string): Record<string, string> {\n if (!secretsString || secretsString.trim().length === 0) {\n throw new Error('JWT secrets string cannot be empty')\n }\n\n const secrets: Record<string, string> = {}\n const pairs = secretsString.split('|')\n\n if (pairs.length === 0) {\n throw new Error('JWT secrets string must contain at least one key=secret pair')\n }\n\n for (const pair of pairs) {\n const trimmedPair = pair.trim()\n if (!trimmedPair) {\n continue // Skip empty pairs from trailing/leading separators\n }\n\n const separatorIndex = trimmedPair.indexOf('=')\n if (separatorIndex === -1) {\n throw new Error(`Invalid JWT secret format: \"${pair}\". Expected format: key=secret`)\n }\n\n const keyId = trimmedPair.substring(0, separatorIndex).trim()\n const secret = trimmedPair.substring(separatorIndex + 1).trim()\n\n if (!keyId) {\n throw new Error(`Empty key ID in JWT secret pair: \"${pair}\"`)\n }\n\n if (!secret) {\n throw new Error(`Empty secret for key ID \"${keyId}\"`)\n }\n\n if (secrets[keyId]) {\n throw new Error(`Duplicate key ID \"${keyId}\" in JWT secrets`)\n }\n\n secrets[keyId] = secret\n }\n\n if (Object.keys(secrets).length === 0) {\n throw new Error('JWT secrets string must contain at least one valid key=secret pair')\n }\n\n return secrets\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/jwt/core.ts'\nexport { parseJwtSecrets } from './lib/jwt/utils.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":[]}
|
|
1
|
+
{"version":3,"sources":["../lib/fastify.ts","../lib/error-handler.ts","../lib/swagger-setup.ts","../lib/jwt/core.ts","../lib/jwt/service.ts","../lib/jwt/register.ts","../lib/jwt/hooks.ts","../lib/jwt/setup.ts","../lib/crypto-utils.ts","../lib/jwt/utils.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 server-specific utilities\nexport * from './crypto-utils.ts'\n\n\nexport async function createFastify(options?: CreateFastifyOptions): Promise<FastifyServer> {\n const fastifyOptions: FastifyServerOptions = {\n ...options?.requestTimeout ? {requestTimeout: options.requestTimeout} : {},\n ...options?.bodyLimit ? {bodyLimit: options.bodyLimit} : {},\n }\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 type { FastifyError, FastifyInstance } from 'fastify'\nimport { formatError, type ValidationDetail } from '@a_jackie_z/fastify-types'\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 } 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 security schemes for each token type if JWT is enabled\n if (options.jwt && options.jwt.tokenTypes) {\n const securitySchemes: any = {}\n\n for (const [typeName, typeConfig] of Object.entries(options.jwt.tokenTypes)) {\n const headerName = typeConfig.headerName.toLowerCase()\n\n // Use bearer auth for 'authorization' header, apiKey for custom headers\n if (headerName === 'authorization') {\n securitySchemes[typeName] = {\n type: 'http',\n scheme: 'bearer',\n bearerFormat: 'JWT',\n description: `JWT token for ${typeName} authentication`,\n }\n } else {\n securitySchemes[typeName] = {\n type: 'apiKey',\n in: 'header',\n name: typeConfig.headerName,\n description: `JWT token for ${typeName} authentication`,\n }\n }\n }\n\n openApiConfig.openapi.components = {\n securitySchemes,\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 any) || {}\n const jwtTypes = routeConfig.jwtTypes\n\n // Skip if JWT is explicitly bypassed\n if (jwtTypes === false) {\n return\n }\n\n // Determine which token types are required\n // Start with global requiredTypes (always checked)\n let requiredTypes: string[] = []\n\n if (options.jwt?.requiredTypes && options.jwt.requiredTypes.length > 0) {\n requiredTypes = [...options.jwt.requiredTypes]\n }\n\n // Add route-specific types if specified\n if (Array.isArray(jwtTypes) && jwtTypes.length > 0) {\n // Combine both, removing duplicates\n requiredTypes = [...new Set([...requiredTypes, ...jwtTypes])]\n }\n\n // Inject security requirement if JWT types are required\n if (requiredTypes.length > 0) {\n if (!routeOptions.schema) {\n routeOptions.schema = {}\n }\n if (!routeOptions.schema.security) {\n routeOptions.schema.security = requiredTypes.map(typeName => ({ [typeName]: [] }))\n }\n }\n })\n}\n","import jwt, { JwtPayload, SignOptions, VerifyOptions } from 'jsonwebtoken'\nimport type { SignTokenOptions, VerifyTokenOptions } from '@a_jackie_z/fastify-types'\n\n/**\n * Sign a JWT token with kid, expiration, and optional JWT header parameters\n */\nexport function signToken(\n payload: Record<string, any>,\n secret: string,\n kid: string,\n expiresIn: string,\n options?: SignTokenOptions\n): string {\n const signOptions: SignOptions = {\n expiresIn: expiresIn as any,\n keyid: kid,\n }\n\n if (options?.algorithm) {\n signOptions.algorithm = options.algorithm\n }\n if (options?.iss) {\n signOptions.issuer = options.iss\n }\n if (options?.aud) {\n signOptions.audience = options.aud\n }\n\n // Apply custom header configuration\n if (options?.header) {\n const headerConfig: Record<string, any> = {}\n\n // Add standard JWT headers\n if (options.header.typ !== undefined) {\n headerConfig.typ = options.header.typ\n }\n if (options.header.cty !== undefined) {\n headerConfig.cty = options.header.cty\n }\n\n // Add custom header claims (exclude typ and cty as they're already handled)\n for (const [key, value] of Object.entries(options.header)) {\n if (key !== 'typ' && key !== 'cty') {\n headerConfig[key] = value\n }\n }\n\n // Only set header if we have custom fields\n if (Object.keys(headerConfig).length > 0) {\n signOptions.header = headerConfig as any\n }\n }\n\n return jwt.sign(payload, secret, signOptions)\n}\n\n/**\n * Verify a JWT token with kid-based secret selection and optional issuer validation\n */\nexport function verifyToken(\n token: string,\n secrets: Record<string, string>,\n options?: VerifyTokenOptions\n): JwtPayload {\n const debug = options?.debug ?? false\n\n try {\n // Decode header to extract kid\n const parts = token.split('.')\n if (parts.length !== 3 || !parts[0]) {\n throw new Error(debug ? 'Malformed JWT token: Token must have 3 parts separated by dots' : 'Malformed token')\n }\n\n const headerPart = parts[0]\n let header: any\n try {\n header = JSON.parse(Buffer.from(headerPart, 'base64').toString())\n } catch {\n throw new Error(debug ? 'Malformed JWT token: Invalid base64 encoding in header' : 'Malformed token')\n }\n\n const kid = header.kid\n if (!kid) {\n throw new Error(\n debug\n ? 'Missing kid in JWT token header. Ensure the token was signed with a kid parameter.'\n : 'Missing kid in token header'\n )\n }\n\n // Validate expected header claims if configured\n if (options?.expectedHeader) {\n // Validate typ (token type)\n if (options.expectedHeader.typ !== undefined && header.typ !== options.expectedHeader.typ) {\n throw new Error(\n debug\n ? `Invalid JWT header 'typ': expected \"${options.expectedHeader.typ}\", got \"${header.typ || 'undefined'}\"`\n : 'Invalid JWT header typ'\n )\n }\n\n // Validate cty (content type)\n if (options.expectedHeader.cty !== undefined && header.cty !== options.expectedHeader.cty) {\n throw new Error(\n debug\n ? `Invalid JWT header 'cty': expected \"${options.expectedHeader.cty}\", got \"${header.cty || 'undefined'}\"`\n : 'Invalid JWT header cty'\n )\n }\n\n // Validate custom header claims\n for (const [key, expectedValue] of Object.entries(options.expectedHeader)) {\n if (key !== 'typ' && key !== 'cty' && expectedValue !== undefined) {\n if (header[key] !== expectedValue) {\n throw new Error(\n debug\n ? `Invalid JWT header '${key}': expected \"${expectedValue}\", got \"${header[key] || 'undefined'}\"`\n : `Invalid JWT header ${key}`\n )\n }\n }\n }\n }\n\n const secret = secrets[kid]\n if (!secret) {\n const availableKeys = Object.keys(secrets).join(', ')\n throw new Error(\n debug\n ? `Unknown key ID \"${kid}\" in JWT token. Available keys: ${availableKeys}`\n : `Unknown key ID \"${kid}\"`\n )\n }\n\n // Verify token with the secret\n const verifyOptions: VerifyOptions = {\n complete: false,\n }\n\n const decoded = jwt.verify(token, secret, verifyOptions) as JwtPayload\n\n // Validate issuer if allowedIss is configured\n if (options?.allowedIss && options.allowedIss.length > 0) {\n const tokenIss = decoded.iss\n if (!tokenIss) {\n throw new Error(\n debug\n ? `Token missing issuer (iss) claim. Expected one of: ${options.allowedIss.join(', ')}`\n : 'Token missing issuer claim'\n )\n }\n if (!options.allowedIss.includes(tokenIss)) {\n throw new Error(\n debug\n ? `Invalid token issuer \"${tokenIss}\". Expected one of: ${options.allowedIss.join(', ')}`\n : `Invalid token issuer \"${tokenIss}\"`\n )\n }\n }\n\n return decoded\n } catch (error) {\n if (error instanceof jwt.TokenExpiredError) {\n if (debug) {\n const expDate = new Date(error.expiredAt).toISOString()\n const now = Math.floor(Date.now() / 1000)\n const exp = Math.floor(error.expiredAt.getTime() / 1000)\n const diff = now - exp\n throw new Error(`Token expired at ${expDate} (${diff} seconds ago)`)\n }\n throw new Error('Token has expired')\n }\n\n if (error instanceof jwt.JsonWebTokenError) {\n if (debug) {\n if (error.message.includes('signature')) {\n throw new Error('Invalid token signature: Token was signed with a different secret or has been tampered with')\n }\n if (error.message.includes('malformed')) {\n throw new Error('Malformed token: Token structure is invalid or corrupted')\n }\n throw new Error(`Token verification failed: ${error.message}`)\n }\n throw new Error('Invalid token')\n }\n\n throw error\n }\n}\n\n/**\n * Extract token from header value with Bearer prefix stripping\n * All JWT tokens must use Bearer prefix format: \"Bearer <token>\"\n */\nexport function extractTokenFromHeader(\n headerValue: string | string[] | undefined,\n headerName: string,\n debug?: boolean\n): string | null {\n if (!headerValue) {\n return null\n }\n\n const value = typeof headerValue === 'string' ? headerValue : headerValue[0]\n if (!value) {\n return null\n }\n\n // All JWT tokens must use \"Bearer <token>\" format\n const match = value.match(/^Bearer\\s+(\\S+)$/i)\n if (!match || !match[1]) {\n if (debug && value) {\n throw new Error(`Invalid ${headerName} header format. Expected: \"Bearer <token>\"`)\n }\n return null\n }\n\n return match[1]\n}\n\n","import { signToken, verifyToken, extractTokenFromHeader } from './core.ts'\nimport type { TokenTypeConfig, SignTokenOptions, VerifyTokenOptions } from '@a_jackie_z/fastify-types'\n\nexport interface FastifyJwtServiceOptions {\n secrets: Record<string, string>\n defaultKeyId: string\n tokenTypes: Record<string, TokenTypeConfig>\n debug?: boolean\n}\n\nexport class FastifyJwtService {\n private readonly secrets: Record<string, string>\n private readonly defaultKeyId: string\n private readonly tokenTypes: Record<string, TokenTypeConfig>\n private readonly debug: boolean\n\n constructor(options: FastifyJwtServiceOptions) {\n this.secrets = options.secrets\n this.defaultKeyId = options.defaultKeyId\n this.tokenTypes = options.tokenTypes\n this.debug = options.debug ?? false\n }\n\n /**\n * Generate a token for a specific type\n */\n generateToken(typeName: string, payload: Record<string, any>): string {\n const tokenType = this.tokenTypes[typeName]\n if (!tokenType) {\n throw new Error(\n this.debug\n ? `Unknown token type \"${typeName}\". Available types: ${Object.keys(this.tokenTypes).join(', ')}`\n : `Unknown token type \"${typeName}\"`\n )\n }\n\n const signOptions: SignTokenOptions = {}\n if (tokenType.algorithm) signOptions.algorithm = tokenType.algorithm\n if (tokenType.iss) signOptions.iss = tokenType.iss\n if (tokenType.aud) signOptions.aud = tokenType.aud\n if (tokenType.header) signOptions.header = tokenType.header\n\n const secret = this.secrets[this.defaultKeyId]\n if (!secret) {\n throw new Error(`Default key ID \"${this.defaultKeyId}\" not found in secrets`)\n }\n\n return signToken(payload, secret, this.defaultKeyId, tokenType.expiresIn, signOptions)\n }\n\n /**\n * Verify a token for a specific type\n */\n verifyToken(typeName: string, token: string): any {\n const tokenType = this.tokenTypes[typeName]\n if (!tokenType) {\n throw new Error(\n this.debug\n ? `Unknown token type \"${typeName}\". Available types: ${Object.keys(this.tokenTypes).join(', ')}`\n : `Unknown token type \"${typeName}\"`\n )\n }\n\n const verifyOptions: VerifyTokenOptions = {\n debug: this.debug,\n }\n\n if (tokenType.allowedIss && tokenType.allowedIss.length > 0) {\n verifyOptions.allowedIss = tokenType.allowedIss\n }\n\n if (tokenType.header) {\n verifyOptions.expectedHeader = tokenType.header\n }\n\n const decoded = verifyToken(token, this.secrets, verifyOptions)\n\n // Validate payload with Zod schema if provided\n if (tokenType.payloadSchema) {\n try {\n return tokenType.payloadSchema.parse(decoded)\n } catch (error) {\n if (this.debug && error instanceof Error) {\n throw new Error(`Token payload validation failed: ${error.message}`)\n }\n throw new Error('Invalid token payload')\n }\n }\n\n return decoded\n }\n\n /**\n * Extract token from header value\n */\n extractTokenFromHeader(headerValue: string | string[] | undefined, typeName: string): string | null {\n const tokenType = this.tokenTypes[typeName]\n if (!tokenType) {\n throw new Error(\n this.debug\n ? `Unknown token type \"${typeName}\". Available types: ${Object.keys(this.tokenTypes).join(', ')}`\n : `Unknown token type \"${typeName}\"`\n )\n }\n\n return extractTokenFromHeader(headerValue, tokenType.headerName, this.debug)\n }\n\n /**\n * Get token type configuration\n */\n getTokenTypeConfig(typeName: string): TokenTypeConfig | undefined {\n return this.tokenTypes[typeName]\n }\n\n /**\n * Get all configured token type names\n */\n getTokenTypeNames(): string[] {\n return Object.keys(this.tokenTypes)\n }\n}\n\n","import type { FastifyInstance } from 'fastify'\nimport { FastifyJwtService, type FastifyJwtServiceOptions } from './service.ts'\n\nexport async function registerJWT(\n fastify: FastifyInstance,\n options: FastifyJwtServiceOptions\n): Promise<FastifyJwtService> {\n const { secrets, defaultKeyId, tokenTypes } = options\n\n // Validate that defaultKeyId exists in secrets\n if (!secrets[defaultKeyId]) {\n throw new Error(`Default key ID \"${defaultKeyId}\" not found in JWT secrets`)\n }\n\n // Validate that at least one token type is configured\n if (!tokenTypes || Object.keys(tokenTypes).length === 0) {\n throw new Error('At least one token type must be configured')\n }\n\n // Validate token types configuration\n for (const [typeName, config] of Object.entries(tokenTypes)) {\n if (!config.headerName) {\n throw new Error(`Token type \"${typeName}\" is missing required field: headerName`)\n }\n if (!config.expiresIn) {\n throw new Error(`Token type \"${typeName}\" is missing required field: expiresIn`)\n }\n }\n\n // Create JWT service\n const jwtService = new FastifyJwtService(options)\n\n // Decorate Fastify instance\n fastify.decorate('jwtService', jwtService)\n\n return jwtService\n}\n","import type { FastifyReply, FastifyRequest } from 'fastify'\nimport type { FastifyJwtService } from './service.ts'\nimport { formatError } from '@a_jackie_z/fastify-types'\n\ninterface HookOptions {\n jwtService: FastifyJwtService\n swaggerRoutePrefix?: string\n requiredTypes?: string[]\n debug?: boolean\n}\n\nexport function createVerificationHook(options: HookOptions) {\n return async (request: FastifyRequest, reply: FastifyReply) => {\n const { jwtService, swaggerRoutePrefix, requiredTypes, debug } = options\n\n // Skip Swagger routes\n if (swaggerRoutePrefix && request.url.startsWith(swaggerRoutePrefix)) {\n return\n }\n\n const routeConfig = (request.routeOptions.config as any) || {}\n const jwtTypes = routeConfig.jwtTypes\n\n // If jwtTypes is explicitly false, skip verification\n if (jwtTypes === false) {\n return\n }\n\n // Determine which token types to verify\n // Always include requiredTypes first (checked for all routes)\n let typesToVerify: string[] = []\n\n if (requiredTypes && requiredTypes.length > 0) {\n typesToVerify = [...requiredTypes]\n }\n\n // Add route-specific types if specified\n if (Array.isArray(jwtTypes) && jwtTypes.length > 0) {\n // Combine both, removing duplicates\n typesToVerify = [...new Set([...typesToVerify, ...jwtTypes])]\n }\n\n // If no types to verify, route is public\n if (typesToVerify.length === 0) {\n return\n }\n\n // Initialize jwtPayloads map on request\n request.jwtPayloads = new Map()\n\n // Verify each required token type\n for (const typeName of typesToVerify) {\n const tokenTypeConfig = jwtService.getTokenTypeConfig(typeName)\n if (!tokenTypeConfig) {\n const errorMsg = debug\n ? `Unknown token type \"${typeName}\" in route configuration. Available types: ${jwtService.getTokenTypeNames().join(', ')}`\n : `Unknown token type \"${typeName}\"`\n return reply.status(500).send(formatError(500, 'Internal Server Error', errorMsg))\n }\n\n // Extract token from configured header\n const headerName = tokenTypeConfig.headerName.toLowerCase()\n const headerValue = request.headers[headerName]\n\n let token: string | null = null\n try {\n token = jwtService.extractTokenFromHeader(headerValue, typeName)\n } catch (err) {\n const errorMsg = debug && err instanceof Error\n ? err.message\n : `Invalid ${headerName} header format`\n return reply.status(401).send(formatError(401, 'Unauthorized', errorMsg))\n }\n\n if (!token) {\n const errorMsg = debug\n ? `Missing or invalid ${headerName} header for token type \"${typeName}\"`\n : `Missing or invalid ${headerName} header`\n return reply.status(401).send(formatError(401, 'Unauthorized', errorMsg))\n }\n\n // Verify token\n try {\n const payload = jwtService.verifyToken(typeName, token)\n request.jwtPayloads.set(typeName, payload)\n } catch (err) {\n const errorMsg = debug && err instanceof Error\n ? `Token verification failed for type \"${typeName}\": ${err.message}`\n : `Invalid or expired ${typeName} token`\n return reply.status(401).send(formatError(401, 'Unauthorized', errorMsg))\n }\n }\n }\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { CreateFastifyOptions } from '../types.ts'\nimport { registerJWT } from './register.ts'\nimport { createVerificationHook } from './hooks.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 jwtService = await registerJWT(fastify, {\n secrets: options.jwt.secrets,\n defaultKeyId: options.jwt.defaultKeyId,\n tokenTypes: options.jwt.tokenTypes,\n debug: options.jwt.debug ?? false,\n })\n\n // Add verification hook for JWT verification (always add when JWT configured)\n const hookOptions: Parameters<typeof createVerificationHook>[0] = {\n jwtService,\n debug: options.jwt.debug ?? false,\n }\n\n if (options.jwt.requiredTypes !== undefined) {\n hookOptions.requiredTypes = options.jwt.requiredTypes\n }\n\n if (swaggerRoutePrefix !== undefined) {\n hookOptions.swaggerRoutePrefix = swaggerRoutePrefix\n }\n\n fastify.addHook('onRequest', createVerificationHook(hookOptions))\n}\n","import { randomBytes } from 'node:crypto'\n\n/**\n * Server-side crypto utilities for generating secure IDs and tokens\n * These functions require Node.js crypto module and are not frontend-compatible\n */\n\nconst ID_ALPHABET = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'\nconst ID_LENGTH = 16\n\n/**\n * Generate a random 16-character alphanumeric ID\n */\nexport function generateId(): string {\n const bytes = randomBytes(ID_LENGTH)\n let result = ''\n for (let i = 0; i < ID_LENGTH; i++) {\n result += ID_ALPHABET[bytes[i]! % ID_ALPHABET.length]\n }\n return result\n}\n\n/**\n * Generate a secure session token (64-character hex string)\n */\nexport function generateSessionToken(): string {\n return randomBytes(32).toString('hex')\n}\n\n/**\n * Generate a secure random string with specified length\n * @param length - Length of the string to generate\n * @param alphabet - Alphabet to use (defaults to alphanumeric)\n */\nexport function generateSecureString(length: number, alphabet = ID_ALPHABET): string {\n const bytes = randomBytes(length)\n let result = ''\n for (let i = 0; i < length; i++) {\n result += alphabet[bytes[i]! % alphabet.length]\n }\n return result\n}\n","/**\n * Parse JWT secrets from environment variable format\n * @param secretsString - Secrets in format: \"key1=secret1|key2=secret2\"\n * @returns Record mapping key IDs to their secrets\n * @throws Error if format is invalid, empty, contains duplicates, or has empty values\n */\nexport function parseJwtSecrets(secretsString: string): Record<string, string> {\n if (!secretsString || secretsString.trim().length === 0) {\n throw new Error('JWT secrets string cannot be empty')\n }\n\n const secrets: Record<string, string> = {}\n const pairs = secretsString.split('|')\n\n if (pairs.length === 0) {\n throw new Error('JWT secrets string must contain at least one key=secret pair')\n }\n\n for (const pair of pairs) {\n const trimmedPair = pair.trim()\n if (!trimmedPair) {\n continue // Skip empty pairs from trailing/leading separators\n }\n\n const separatorIndex = trimmedPair.indexOf('=')\n if (separatorIndex === -1) {\n throw new Error(`Invalid JWT secret format: \"${pair}\". Expected format: key=secret`)\n }\n\n const keyId = trimmedPair.substring(0, separatorIndex).trim()\n const secret = trimmedPair.substring(separatorIndex + 1).trim()\n\n if (!keyId) {\n throw new Error(`Empty key ID in JWT secret pair: \"${pair}\"`)\n }\n\n if (!secret) {\n throw new Error(`Empty secret for key ID \"${keyId}\"`)\n }\n\n if (secrets[keyId]) {\n throw new Error(`Duplicate key ID \"${keyId}\" in JWT secrets`)\n }\n\n secrets[keyId] = secret\n }\n\n if (Object.keys(secrets).length === 0) {\n throw new Error('JWT secrets string must contain at least one valid key=secret pair')\n }\n\n return secrets\n}\n","import { FastifyPluginCallback } from 'fastify'\nimport type { FastifyServer } from './types.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 type { FastifyServer } from '../types.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/types.ts'\nexport * from './lib/crypto-utils.ts'\nexport * from './lib/jwt/service.ts'\nexport { parseJwtSecrets } from './lib/jwt/utils.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":";AAAA,OAAO,aAAuC;AAC9C,SAAS,oBAAoB,yBAA0C;AACvE,OAAO,sBAAsB;;;ACD7B,SAAS,mBAA0C;AAE5C,SAAS,kBAAkB,SAAgC;AAChE,UAAQ,gBAAgB,CAAC,OAAqB,SAAS,UAAU;AAE/D,YAAQ,IAAI,MAAM;AAAA,MAChB,KAAK;AAAA,MACL,KAAK,QAAQ;AAAA,MACb,QAAQ,QAAQ;AAAA,IAClB,GAAG,eAAe;AAGlB,QAAI,MAAM,YAAY;AACpB,YAAM,UAA8B,MAAM,WAAW,IAAI,CAAC,UAAe;AAEvE,cAAM,QAAQ,MAAM,gBAAgB,MAAM,YAAY,MAAM,QAAQ,mBAAmB;AACvF,cAAM,aAAa,MAAM,WAAW,GAAG,IAAI,MAAM,MAAM,CAAC,EAAE,QAAQ,OAAO,GAAG,IAAI;AAEhF,eAAO;AAAA,UACL,OAAO,cAAc;AAAA,UACrB,SAAS,MAAM,WAAW;AAAA,QAC5B;AAAA,MACF,CAAC;AAED,aAAO,MAAM,OAAO,GAAG,EAAE;AAAA,QACvB,YAAY,KAAK,oBAAoB,6BAA6B,OAAO;AAAA,MAC3E;AAAA,IACF;AAGA,QAAI,MAAM,eAAe,KAAK;AAC5B,aAAO,MAAM,OAAO,GAAG,EAAE;AAAA,QACvB,YAAY,KAAK,qBAAqB,qBAAqB;AAAA,MAC7D;AAAA,IACF;AAGA,QAAI,MAAM,eAAe,KAAK;AAC5B,aAAO,MAAM,OAAO,GAAG,EAAE;AAAA,QACvB,YAAY,KAAK,gBAAgB,MAAM,WAAW,yBAAyB;AAAA,MAC7E;AAAA,IACF;AAGA,QAAI,MAAM,eAAe,KAAK;AAC5B,aAAO,MAAM,OAAO,GAAG,EAAE;AAAA,QACvB,YAAY,KAAK,aAAa,MAAM,WAAW,eAAe;AAAA,MAChE;AAAA,IACF;AAGA,QAAI,MAAM,eAAe,KAAK;AAC5B,aAAO,MAAM,OAAO,GAAG,EAAE;AAAA,QACvB,YAAY,KAAK,aAAa,MAAM,WAAW,oBAAoB;AAAA,MACrE;AAAA,IACF;AAGA,UAAM,aAAa,MAAM,cAAc;AACvC,WAAO,MAAM,OAAO,UAAU,EAAE;AAAA,MAC9B;AAAA,QACE;AAAA,QACA,eAAe,MAAM,0BAA0B,MAAM,QAAQ;AAAA,QAC7D,MAAM,WAAW;AAAA,MACnB;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;ACnEA,OAAO,oBAAwC;AAC/C,OAAO,sBAAmD;AAC1D,SAAS,2BAA2B;AAGpC,eAAsB,aACpB,SACA,SAC6B;AAC7B,MAAI,CAAC,QAAQ,SAAS;AACpB,WAAO;AAAA,EACT;AAEA,QAAM,gBAAqB;AAAA,IACzB,SAAS;AAAA,MACP,MAAM;AAAA,QACJ,OAAO,QAAQ,QAAQ;AAAA,QACvB,SAAS,QAAQ,QAAQ;AAAA,QACzB,aAAa,QAAQ,QAAQ;AAAA,MAC/B;AAAA,IACF;AAAA,IACA,WAAW;AAAA,EACb;AAGA,MAAI,QAAQ,OAAO,QAAQ,IAAI,YAAY;AACzC,UAAM,kBAAuB,CAAC;AAE9B,eAAW,CAAC,UAAU,UAAU,KAAK,OAAO,QAAQ,QAAQ,IAAI,UAAU,GAAG;AAC3E,YAAM,aAAa,WAAW,WAAW,YAAY;AAGrD,UAAI,eAAe,iBAAiB;AAClC,wBAAgB,QAAQ,IAAI;AAAA,UAC1B,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,cAAc;AAAA,UACd,aAAa,iBAAiB,QAAQ;AAAA,QACxC;AAAA,MACF,OAAO;AACL,wBAAgB,QAAQ,IAAI;AAAA,UAC1B,MAAM;AAAA,UACN,IAAI;AAAA,UACJ,MAAM,WAAW;AAAA,UACjB,aAAa,iBAAiB,QAAQ;AAAA,QACxC;AAAA,MACF;AAAA,IACF;AAEA,kBAAc,QAAQ,aAAa;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AAEA,QAAM,QAAQ,SAAS,gBAAgB,aAA+B;AAEtE,MAAI,cAAc,QAAQ,QAAQ,eAAe;AAEjD,MAAI,CAAC,YAAY,WAAW,GAAG,GAAG;AAChC,kBAAc,MAAM;AAAA,EACtB;AAEA,MAAI,CAAC,YAAY,SAAS,GAAG,GAAG;AAC9B,kBAAc,cAAc;AAAA,EAC9B;AAEA,QAAM,QAAQ,SAAS,kBAAkB,EAAE,YAAY,CAA4B;AAEnF,SAAO;AACT;AAEO,SAAS,yBACd,SACA,SACA,oBACM;AACN,MAAI,CAAC,QAAQ,OAAO,CAAC,QAAQ,SAAS;AACpC;AAAA,EACF;AAGA,UAAQ,QAAQ,WAAW,CAAC,iBAAiB;AAE3C,QAAI,sBAAsB,aAAa,IAAI,WAAW,kBAAkB,GAAG;AACzE;AAAA,IACF;AAEA,UAAM,cAAe,aAAa,UAAkB,CAAC;AACrD,UAAM,WAAW,YAAY;AAG7B,QAAI,aAAa,OAAO;AACtB;AAAA,IACF;AAIA,QAAI,gBAA0B,CAAC;AAE/B,QAAI,QAAQ,KAAK,iBAAiB,QAAQ,IAAI,cAAc,SAAS,GAAG;AACtE,sBAAgB,CAAC,GAAG,QAAQ,IAAI,aAAa;AAAA,IAC/C;AAGA,QAAI,MAAM,QAAQ,QAAQ,KAAK,SAAS,SAAS,GAAG;AAElD,sBAAgB,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAG,eAAe,GAAG,QAAQ,CAAC,CAAC;AAAA,IAC9D;AAGA,QAAI,cAAc,SAAS,GAAG;AAC5B,UAAI,CAAC,aAAa,QAAQ;AACxB,qBAAa,SAAS,CAAC;AAAA,MACzB;AACA,UAAI,CAAC,aAAa,OAAO,UAAU;AACjC,qBAAa,OAAO,WAAW,cAAc,IAAI,eAAa,EAAE,CAAC,QAAQ,GAAG,CAAC,EAAE,EAAE;AAAA,MACnF;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;ACxHA,OAAO,SAAqD;AAMrD,SAAS,UACd,SACA,QACA,KACA,WACA,SACQ;AACR,QAAM,cAA2B;AAAA,IAC/B;AAAA,IACA,OAAO;AAAA,EACT;AAEA,MAAI,SAAS,WAAW;AACtB,gBAAY,YAAY,QAAQ;AAAA,EAClC;AACA,MAAI,SAAS,KAAK;AAChB,gBAAY,SAAS,QAAQ;AAAA,EAC/B;AACA,MAAI,SAAS,KAAK;AAChB,gBAAY,WAAW,QAAQ;AAAA,EACjC;AAGA,MAAI,SAAS,QAAQ;AACnB,UAAM,eAAoC,CAAC;AAG3C,QAAI,QAAQ,OAAO,QAAQ,QAAW;AACpC,mBAAa,MAAM,QAAQ,OAAO;AAAA,IACpC;AACA,QAAI,QAAQ,OAAO,QAAQ,QAAW;AACpC,mBAAa,MAAM,QAAQ,OAAO;AAAA,IACpC;AAGA,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,MAAM,GAAG;AACzD,UAAI,QAAQ,SAAS,QAAQ,OAAO;AAClC,qBAAa,GAAG,IAAI;AAAA,MACtB;AAAA,IACF;AAGA,QAAI,OAAO,KAAK,YAAY,EAAE,SAAS,GAAG;AACxC,kBAAY,SAAS;AAAA,IACvB;AAAA,EACF;AAEA,SAAO,IAAI,KAAK,SAAS,QAAQ,WAAW;AAC9C;AAKO,SAAS,YACd,OACA,SACA,SACY;AACZ,QAAM,QAAQ,SAAS,SAAS;AAEhC,MAAI;AAEF,UAAM,QAAQ,MAAM,MAAM,GAAG;AAC7B,QAAI,MAAM,WAAW,KAAK,CAAC,MAAM,CAAC,GAAG;AACnC,YAAM,IAAI,MAAM,QAAQ,mEAAmE,iBAAiB;AAAA,IAC9G;AAEA,UAAM,aAAa,MAAM,CAAC;AAC1B,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,MAAM,OAAO,KAAK,YAAY,QAAQ,EAAE,SAAS,CAAC;AAAA,IAClE,QAAQ;AACN,YAAM,IAAI,MAAM,QAAQ,2DAA2D,iBAAiB;AAAA,IACtG;AAEA,UAAM,MAAM,OAAO;AACnB,QAAI,CAAC,KAAK;AACR,YAAM,IAAI;AAAA,QACR,QACI,uFACA;AAAA,MACN;AAAA,IACF;AAGA,QAAI,SAAS,gBAAgB;AAE3B,UAAI,QAAQ,eAAe,QAAQ,UAAa,OAAO,QAAQ,QAAQ,eAAe,KAAK;AACzF,cAAM,IAAI;AAAA,UACR,QACI,uCAAuC,QAAQ,eAAe,GAAG,WAAW,OAAO,OAAO,WAAW,MACrG;AAAA,QACN;AAAA,MACF;AAGA,UAAI,QAAQ,eAAe,QAAQ,UAAa,OAAO,QAAQ,QAAQ,eAAe,KAAK;AACzF,cAAM,IAAI;AAAA,UACR,QACI,uCAAuC,QAAQ,eAAe,GAAG,WAAW,OAAO,OAAO,WAAW,MACrG;AAAA,QACN;AAAA,MACF;AAGA,iBAAW,CAAC,KAAK,aAAa,KAAK,OAAO,QAAQ,QAAQ,cAAc,GAAG;AACzE,YAAI,QAAQ,SAAS,QAAQ,SAAS,kBAAkB,QAAW;AACjE,cAAI,OAAO,GAAG,MAAM,eAAe;AACjC,kBAAM,IAAI;AAAA,cACR,QACI,uBAAuB,GAAG,gBAAgB,aAAa,WAAW,OAAO,GAAG,KAAK,WAAW,MAC5F,sBAAsB,GAAG;AAAA,YAC/B;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,SAAS,QAAQ,GAAG;AAC1B,QAAI,CAAC,QAAQ;AACX,YAAM,gBAAgB,OAAO,KAAK,OAAO,EAAE,KAAK,IAAI;AACpD,YAAM,IAAI;AAAA,QACR,QACI,mBAAmB,GAAG,mCAAmC,aAAa,KACtE,mBAAmB,GAAG;AAAA,MAC5B;AAAA,IACF;AAGA,UAAM,gBAA+B;AAAA,MACnC,UAAU;AAAA,IACZ;AAEA,UAAM,UAAU,IAAI,OAAO,OAAO,QAAQ,aAAa;AAGvD,QAAI,SAAS,cAAc,QAAQ,WAAW,SAAS,GAAG;AACxD,YAAM,WAAW,QAAQ;AACzB,UAAI,CAAC,UAAU;AACb,cAAM,IAAI;AAAA,UACR,QACI,sDAAsD,QAAQ,WAAW,KAAK,IAAI,CAAC,KACnF;AAAA,QACN;AAAA,MACF;AACA,UAAI,CAAC,QAAQ,WAAW,SAAS,QAAQ,GAAG;AAC1C,cAAM,IAAI;AAAA,UACR,QACI,yBAAyB,QAAQ,uBAAuB,QAAQ,WAAW,KAAK,IAAI,CAAC,KACrF,yBAAyB,QAAQ;AAAA,QACvC;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,QAAI,iBAAiB,IAAI,mBAAmB;AAC1C,UAAI,OAAO;AACT,cAAM,UAAU,IAAI,KAAK,MAAM,SAAS,EAAE,YAAY;AACtD,cAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,cAAM,MAAM,KAAK,MAAM,MAAM,UAAU,QAAQ,IAAI,GAAI;AACvD,cAAM,OAAO,MAAM;AACnB,cAAM,IAAI,MAAM,oBAAoB,OAAO,KAAK,IAAI,eAAe;AAAA,MACrE;AACA,YAAM,IAAI,MAAM,mBAAmB;AAAA,IACrC;AAEA,QAAI,iBAAiB,IAAI,mBAAmB;AAC1C,UAAI,OAAO;AACT,YAAI,MAAM,QAAQ,SAAS,WAAW,GAAG;AACvC,gBAAM,IAAI,MAAM,6FAA6F;AAAA,QAC/G;AACA,YAAI,MAAM,QAAQ,SAAS,WAAW,GAAG;AACvC,gBAAM,IAAI,MAAM,0DAA0D;AAAA,QAC5E;AACA,cAAM,IAAI,MAAM,8BAA8B,MAAM,OAAO,EAAE;AAAA,MAC/D;AACA,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAEA,UAAM;AAAA,EACR;AACF;AAMO,SAAS,uBACd,aACA,YACA,OACe;AACf,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,OAAO,gBAAgB,WAAW,cAAc,YAAY,CAAC;AAC3E,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAGA,QAAM,QAAQ,MAAM,MAAM,mBAAmB;AAC7C,MAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG;AACvB,QAAI,SAAS,OAAO;AAClB,YAAM,IAAI,MAAM,WAAW,UAAU,4CAA4C;AAAA,IACnF;AACA,WAAO;AAAA,EACT;AAEA,SAAO,MAAM,CAAC;AAChB;;;AChNO,IAAM,oBAAN,MAAwB;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,SAAmC;AAC7C,SAAK,UAAU,QAAQ;AACvB,SAAK,eAAe,QAAQ;AAC5B,SAAK,aAAa,QAAQ;AAC1B,SAAK,QAAQ,QAAQ,SAAS;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,UAAkB,SAAsC;AACpE,UAAM,YAAY,KAAK,WAAW,QAAQ;AAC1C,QAAI,CAAC,WAAW;AACd,YAAM,IAAI;AAAA,QACR,KAAK,QACD,uBAAuB,QAAQ,uBAAuB,OAAO,KAAK,KAAK,UAAU,EAAE,KAAK,IAAI,CAAC,KAC7F,uBAAuB,QAAQ;AAAA,MACrC;AAAA,IACF;AAEA,UAAM,cAAgC,CAAC;AACvC,QAAI,UAAU,UAAW,aAAY,YAAY,UAAU;AAC3D,QAAI,UAAU,IAAK,aAAY,MAAM,UAAU;AAC/C,QAAI,UAAU,IAAK,aAAY,MAAM,UAAU;AAC/C,QAAI,UAAU,OAAQ,aAAY,SAAS,UAAU;AAErD,UAAM,SAAS,KAAK,QAAQ,KAAK,YAAY;AAC7C,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,mBAAmB,KAAK,YAAY,wBAAwB;AAAA,IAC9E;AAEA,WAAO,UAAU,SAAS,QAAQ,KAAK,cAAc,UAAU,WAAW,WAAW;AAAA,EACvF;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,UAAkB,OAAoB;AAChD,UAAM,YAAY,KAAK,WAAW,QAAQ;AAC1C,QAAI,CAAC,WAAW;AACd,YAAM,IAAI;AAAA,QACR,KAAK,QACD,uBAAuB,QAAQ,uBAAuB,OAAO,KAAK,KAAK,UAAU,EAAE,KAAK,IAAI,CAAC,KAC7F,uBAAuB,QAAQ;AAAA,MACrC;AAAA,IACF;AAEA,UAAM,gBAAoC;AAAA,MACxC,OAAO,KAAK;AAAA,IACd;AAEA,QAAI,UAAU,cAAc,UAAU,WAAW,SAAS,GAAG;AAC3D,oBAAc,aAAa,UAAU;AAAA,IACvC;AAEA,QAAI,UAAU,QAAQ;AACpB,oBAAc,iBAAiB,UAAU;AAAA,IAC3C;AAEA,UAAM,UAAU,YAAY,OAAO,KAAK,SAAS,aAAa;AAG9D,QAAI,UAAU,eAAe;AAC3B,UAAI;AACF,eAAO,UAAU,cAAc,MAAM,OAAO;AAAA,MAC9C,SAAS,OAAO;AACd,YAAI,KAAK,SAAS,iBAAiB,OAAO;AACxC,gBAAM,IAAI,MAAM,oCAAoC,MAAM,OAAO,EAAE;AAAA,QACrE;AACA,cAAM,IAAI,MAAM,uBAAuB;AAAA,MACzC;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,uBAAuB,aAA4C,UAAiC;AAClG,UAAM,YAAY,KAAK,WAAW,QAAQ;AAC1C,QAAI,CAAC,WAAW;AACd,YAAM,IAAI;AAAA,QACR,KAAK,QACD,uBAAuB,QAAQ,uBAAuB,OAAO,KAAK,KAAK,UAAU,EAAE,KAAK,IAAI,CAAC,KAC7F,uBAAuB,QAAQ;AAAA,MACrC;AAAA,IACF;AAEA,WAAO,uBAAuB,aAAa,UAAU,YAAY,KAAK,KAAK;AAAA,EAC7E;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAmB,UAA+C;AAChE,WAAO,KAAK,WAAW,QAAQ;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,oBAA8B;AAC5B,WAAO,OAAO,KAAK,KAAK,UAAU;AAAA,EACpC;AACF;;;ACtHA,eAAsB,YACpB,SACA,SAC4B;AAC5B,QAAM,EAAE,SAAS,cAAc,WAAW,IAAI;AAG9C,MAAI,CAAC,QAAQ,YAAY,GAAG;AAC1B,UAAM,IAAI,MAAM,mBAAmB,YAAY,4BAA4B;AAAA,EAC7E;AAGA,MAAI,CAAC,cAAc,OAAO,KAAK,UAAU,EAAE,WAAW,GAAG;AACvD,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D;AAGA,aAAW,CAAC,UAAU,MAAM,KAAK,OAAO,QAAQ,UAAU,GAAG;AAC3D,QAAI,CAAC,OAAO,YAAY;AACtB,YAAM,IAAI,MAAM,eAAe,QAAQ,yCAAyC;AAAA,IAClF;AACA,QAAI,CAAC,OAAO,WAAW;AACrB,YAAM,IAAI,MAAM,eAAe,QAAQ,wCAAwC;AAAA,IACjF;AAAA,EACF;AAGA,QAAM,aAAa,IAAI,kBAAkB,OAAO;AAGhD,UAAQ,SAAS,cAAc,UAAU;AAEzC,SAAO;AACT;;;AClCA,SAAS,eAAAA,oBAAmB;AASrB,SAAS,uBAAuB,SAAsB;AAC3D,SAAO,OAAO,SAAyB,UAAwB;AAC7D,UAAM,EAAE,YAAY,oBAAoB,eAAe,MAAM,IAAI;AAGjE,QAAI,sBAAsB,QAAQ,IAAI,WAAW,kBAAkB,GAAG;AACpE;AAAA,IACF;AAEA,UAAM,cAAe,QAAQ,aAAa,UAAkB,CAAC;AAC7D,UAAM,WAAW,YAAY;AAG7B,QAAI,aAAa,OAAO;AACtB;AAAA,IACF;AAIA,QAAI,gBAA0B,CAAC;AAE/B,QAAI,iBAAiB,cAAc,SAAS,GAAG;AAC7C,sBAAgB,CAAC,GAAG,aAAa;AAAA,IACnC;AAGA,QAAI,MAAM,QAAQ,QAAQ,KAAK,SAAS,SAAS,GAAG;AAElD,sBAAgB,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAG,eAAe,GAAG,QAAQ,CAAC,CAAC;AAAA,IAC9D;AAGA,QAAI,cAAc,WAAW,GAAG;AAC9B;AAAA,IACF;AAGA,YAAQ,cAAc,oBAAI,IAAI;AAG9B,eAAW,YAAY,eAAe;AACpC,YAAM,kBAAkB,WAAW,mBAAmB,QAAQ;AAC9D,UAAI,CAAC,iBAAiB;AACpB,cAAM,WAAW,QACb,uBAAuB,QAAQ,8CAA8C,WAAW,kBAAkB,EAAE,KAAK,IAAI,CAAC,KACtH,uBAAuB,QAAQ;AACnC,eAAO,MAAM,OAAO,GAAG,EAAE,KAAKA,aAAY,KAAK,yBAAyB,QAAQ,CAAC;AAAA,MACnF;AAGA,YAAM,aAAa,gBAAgB,WAAW,YAAY;AAC1D,YAAM,cAAc,QAAQ,QAAQ,UAAU;AAE9C,UAAI,QAAuB;AAC3B,UAAI;AACF,gBAAQ,WAAW,uBAAuB,aAAa,QAAQ;AAAA,MACjE,SAAS,KAAK;AACZ,cAAM,WAAW,SAAS,eAAe,QACrC,IAAI,UACJ,WAAW,UAAU;AACzB,eAAO,MAAM,OAAO,GAAG,EAAE,KAAKA,aAAY,KAAK,gBAAgB,QAAQ,CAAC;AAAA,MAC1E;AAEA,UAAI,CAAC,OAAO;AACV,cAAM,WAAW,QACb,sBAAsB,UAAU,2BAA2B,QAAQ,MACnE,sBAAsB,UAAU;AACpC,eAAO,MAAM,OAAO,GAAG,EAAE,KAAKA,aAAY,KAAK,gBAAgB,QAAQ,CAAC;AAAA,MAC1E;AAGA,UAAI;AACF,cAAM,UAAU,WAAW,YAAY,UAAU,KAAK;AACtD,gBAAQ,YAAY,IAAI,UAAU,OAAO;AAAA,MAC3C,SAAS,KAAK;AACZ,cAAM,WAAW,SAAS,eAAe,QACrC,uCAAuC,QAAQ,MAAM,IAAI,OAAO,KAChE,sBAAsB,QAAQ;AAClC,eAAO,MAAM,OAAO,GAAG,EAAE,KAAKA,aAAY,KAAK,gBAAgB,QAAQ,CAAC;AAAA,MAC1E;AAAA,IACF;AAAA,EACF;AACF;;;ACxFA,eAAsB,SACpB,SACA,SACA,oBACe;AACf,MAAI,CAAC,QAAQ,KAAK;AAChB;AAAA,EACF;AAEA,QAAM,aAAa,MAAM,YAAY,SAAS;AAAA,IAC5C,SAAS,QAAQ,IAAI;AAAA,IACrB,cAAc,QAAQ,IAAI;AAAA,IAC1B,YAAY,QAAQ,IAAI;AAAA,IACxB,OAAO,QAAQ,IAAI,SAAS;AAAA,EAC9B,CAAC;AAGD,QAAM,cAA4D;AAAA,IAChE;AAAA,IACA,OAAO,QAAQ,IAAI,SAAS;AAAA,EAC9B;AAEA,MAAI,QAAQ,IAAI,kBAAkB,QAAW;AAC3C,gBAAY,gBAAgB,QAAQ,IAAI;AAAA,EAC1C;AAEA,MAAI,uBAAuB,QAAW;AACpC,gBAAY,qBAAqB;AAAA,EACnC;AAEA,UAAQ,QAAQ,aAAa,uBAAuB,WAAW,CAAC;AAClE;;;ACpCA,SAAS,mBAAmB;AAO5B,IAAM,cAAc;AACpB,IAAM,YAAY;AAKX,SAAS,aAAqB;AACnC,QAAM,QAAQ,YAAY,SAAS;AACnC,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,cAAU,YAAY,MAAM,CAAC,IAAK,YAAY,MAAM;AAAA,EACtD;AACA,SAAO;AACT;AAKO,SAAS,uBAA+B;AAC7C,SAAO,YAAY,EAAE,EAAE,SAAS,KAAK;AACvC;AAOO,SAAS,qBAAqB,QAAgB,WAAW,aAAqB;AACnF,QAAM,QAAQ,YAAY,MAAM;AAChC,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,cAAU,SAAS,MAAM,CAAC,IAAK,SAAS,MAAM;AAAA,EAChD;AACA,SAAO;AACT;;;AR7BA,eAAsB,cAAc,SAAwD;AAC1F,QAAM,iBAAuC;AAAA,IAC3C,GAAG,SAAS,iBAAiB,EAAC,gBAAgB,QAAQ,eAAc,IAAI,CAAC;AAAA,IACzE,GAAG,SAAS,YAAY,EAAC,WAAW,QAAQ,UAAS,IAAI,CAAC;AAAA,EAC5D;AAEA,MAAI,SAAS,QAAQ;AACnB,mBAAe,iBAAiB,QAAQ;AAAA,EAC1C;AAEA,QAAM,UAAU,QAAQ,cAAc,EAAE,iBAAkC;AAG1E,UAAQ,qBAAqB,iBAAiB;AAC9C,UAAQ,sBAAsB,kBAAkB;AAGhD,oBAAkB,OAAO;AAGzB,QAAM,qBAAqB,MAAM,aAAa,SAAS,WAAW,CAAC,CAAC;AAGpE,2BAAyB,SAAS,WAAW,CAAC,GAAG,kBAAkB;AAGnE,QAAM,SAAS,SAAS,WAAW,CAAC,GAAG,kBAAkB;AAGzD,MAAI,SAAS,WAAW,QAAQ;AAC9B,UAAM,QAAQ,SAAS,kBAAkB;AAAA,MACvC,QAAQ;AAAA,MACR,GAAG,QAAQ,UAAU;AAAA,IACvB,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEA,eAAsB,WAAW,SAAwB,MAAc,MAAc;AACnF,MAAI;AACF,UAAM,QAAQ,OAAO,EAAE,MAAM,KAAK,CAAC;AAAA,EACrC,SAAS,KAAK;AACZ,YAAQ,IAAI,MAAM,GAAG;AACrB,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;;;ASpDO,SAAS,gBAAgB,eAA+C;AAC7E,MAAI,CAAC,iBAAiB,cAAc,KAAK,EAAE,WAAW,GAAG;AACvD,UAAM,IAAI,MAAM,oCAAoC;AAAA,EACtD;AAEA,QAAM,UAAkC,CAAC;AACzC,QAAM,QAAQ,cAAc,MAAM,GAAG;AAErC,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,IAAI,MAAM,8DAA8D;AAAA,EAChF;AAEA,aAAW,QAAQ,OAAO;AACxB,UAAM,cAAc,KAAK,KAAK;AAC9B,QAAI,CAAC,aAAa;AAChB;AAAA,IACF;AAEA,UAAM,iBAAiB,YAAY,QAAQ,GAAG;AAC9C,QAAI,mBAAmB,IAAI;AACzB,YAAM,IAAI,MAAM,+BAA+B,IAAI,gCAAgC;AAAA,IACrF;AAEA,UAAM,QAAQ,YAAY,UAAU,GAAG,cAAc,EAAE,KAAK;AAC5D,UAAM,SAAS,YAAY,UAAU,iBAAiB,CAAC,EAAE,KAAK;AAE9D,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,qCAAqC,IAAI,GAAG;AAAA,IAC9D;AAEA,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,4BAA4B,KAAK,GAAG;AAAA,IACtD;AAEA,QAAI,QAAQ,KAAK,GAAG;AAClB,YAAM,IAAI,MAAM,qBAAqB,KAAK,kBAAkB;AAAA,IAC9D;AAEA,YAAQ,KAAK,IAAI;AAAA,EACnB;AAEA,MAAI,OAAO,KAAK,OAAO,EAAE,WAAW,GAAG;AACrC,UAAM,IAAI,MAAM,oEAAoE;AAAA,EACtF;AAEA,SAAO;AACT;;;AChDO,SAAS,oBAAoB,IAA2B;AAC7D,SAAO,SAAS,2BACd,SACA,SACA,MACA;AACA,UAAM,SAAS,QAAQ,iBAAkC;AACzD,QAAI,aAAa;AAEjB,UAAM,cAAc,CAAC,QAAgB;AACnC,WAAK,GAAG;AACR,mBAAa;AAAA,IACf;AAEA,OAAG,QAAQ,SAAS,WAAW;AAE/B,QAAI,CAAC,YAAY;AACf,WAAK;AAAA,IACP;AAAA,EACF;AACF;;;ACrBO,IAAM,eAAe,oBAAoB,CAAC,QAAuB;AACtE,MAAI,IAAI,cAAc;AAAA,IACpB,QAAQ;AAAA,MACN,MAAM,CAAC,QAAQ;AAAA,IACjB;AAAA,IACA,QAAQ;AAAA,MACN,KAAK;AAAA,IACP;AAAA,IACA,SAAS,YAAY;AACnB,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF,CAAC;AACH,CAAC;;;ACVD,cAAc;","names":["formatError"]}
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@a_jackie_z/fastify",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
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>",
|
|
7
7
|
"repository": {
|
|
8
|
-
"url": "https://github.com/a-jackie-z/fastify"
|
|
8
|
+
"url": "git+https://github.com/a-jackie-z/fastify.git"
|
|
9
9
|
},
|
|
10
10
|
"type": "module",
|
|
11
11
|
"main": "./dist/index.js",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"build": "tsup"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
+
"@a_jackie_z/fastify-types": "^1.0.1",
|
|
26
27
|
"@fastify/rate-limit": "^10.3.0",
|
|
27
28
|
"@fastify/swagger": "^9.6.1",
|
|
28
29
|
"@fastify/swagger-ui": "^5.2.5",
|