@nauth-toolkit/core 0.1.0 → 0.1.3

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.
Files changed (184) hide show
  1. package/LICENSE +90 -0
  2. package/README.md +30 -0
  3. package/package.json +7 -2
  4. package/jest.config.js +0 -15
  5. package/jest.setup.ts +0 -6
  6. package/src/adapters/database-columns.ts +0 -165
  7. package/src/adapters/express.adapter.ts +0 -385
  8. package/src/adapters/fastify.adapter.ts +0 -416
  9. package/src/adapters/index.ts +0 -16
  10. package/src/adapters/storage.factory.ts +0 -143
  11. package/src/bootstrap.ts +0 -374
  12. package/src/dto/auth-challenge.dto.ts +0 -231
  13. package/src/dto/auth-response.dto.ts +0 -253
  14. package/src/dto/challenge-response.dto.ts +0 -234
  15. package/src/dto/change-password-request.dto.ts +0 -50
  16. package/src/dto/change-password-response.dto.ts +0 -29
  17. package/src/dto/change-password.dto.ts +0 -57
  18. package/src/dto/error-response.dto.ts +0 -136
  19. package/src/dto/get-available-methods.dto.ts +0 -55
  20. package/src/dto/get-challenge-data-response.dto.ts +0 -28
  21. package/src/dto/get-challenge-data.dto.ts +0 -69
  22. package/src/dto/get-client-info.dto.ts +0 -104
  23. package/src/dto/get-device-token-response.dto.ts +0 -25
  24. package/src/dto/get-events-by-type.dto.ts +0 -76
  25. package/src/dto/get-ip-address-response.dto.ts +0 -24
  26. package/src/dto/get-mfa-status.dto.ts +0 -94
  27. package/src/dto/get-risk-assessment-history.dto.ts +0 -39
  28. package/src/dto/get-session-id-response.dto.ts +0 -25
  29. package/src/dto/get-setup-data-response.dto.ts +0 -31
  30. package/src/dto/get-setup-data.dto.ts +0 -75
  31. package/src/dto/get-suspicious-activity.dto.ts +0 -42
  32. package/src/dto/get-user-agent-response.dto.ts +0 -23
  33. package/src/dto/get-user-auth-history.dto.ts +0 -95
  34. package/src/dto/get-user-by-email.dto.ts +0 -61
  35. package/src/dto/get-user-by-id.dto.ts +0 -46
  36. package/src/dto/get-user-devices.dto.ts +0 -53
  37. package/src/dto/get-user-response.dto.ts +0 -17
  38. package/src/dto/has-provider.dto.ts +0 -56
  39. package/src/dto/index.ts +0 -57
  40. package/src/dto/is-trusted-device-response.dto.ts +0 -34
  41. package/src/dto/list-providers-response.dto.ts +0 -23
  42. package/src/dto/login.dto.ts +0 -95
  43. package/src/dto/logout-all-response.dto.ts +0 -24
  44. package/src/dto/logout-all.dto.ts +0 -65
  45. package/src/dto/logout-response.dto.ts +0 -25
  46. package/src/dto/logout.dto.ts +0 -64
  47. package/src/dto/refresh-token.dto.ts +0 -36
  48. package/src/dto/remove-devices.dto.ts +0 -85
  49. package/src/dto/resend-code-response.dto.ts +0 -32
  50. package/src/dto/resend-code.dto.ts +0 -51
  51. package/src/dto/reset-password.dto.ts +0 -115
  52. package/src/dto/respond-challenge.dto.ts +0 -272
  53. package/src/dto/set-mfa-exemption.dto.ts +0 -112
  54. package/src/dto/set-must-change-password-response.dto.ts +0 -27
  55. package/src/dto/set-must-change-password.dto.ts +0 -46
  56. package/src/dto/set-preferred-method.dto.ts +0 -80
  57. package/src/dto/setup-mfa.dto.ts +0 -98
  58. package/src/dto/signup.dto.ts +0 -174
  59. package/src/dto/social-auth.dto.ts +0 -422
  60. package/src/dto/trust-device-response.dto.ts +0 -30
  61. package/src/dto/trust-device.dto.ts +0 -9
  62. package/src/dto/update-user-attributes-request.dto.ts +0 -51
  63. package/src/dto/user-response.dto.ts +0 -138
  64. package/src/dto/user-update.dto.ts +0 -222
  65. package/src/dto/verify-email.dto.ts +0 -313
  66. package/src/dto/verify-mfa-code.dto.ts +0 -103
  67. package/src/dto/verify-phone-by-sub.dto.ts +0 -78
  68. package/src/dto/verify-phone.dto.ts +0 -245
  69. package/src/entities/auth-audit.entity.ts +0 -232
  70. package/src/entities/challenge-session.entity.ts +0 -116
  71. package/src/entities/index.ts +0 -29
  72. package/src/entities/login-attempt.entity.ts +0 -64
  73. package/src/entities/mfa-device.entity.ts +0 -151
  74. package/src/entities/rate-limit.entity.ts +0 -44
  75. package/src/entities/session.entity.ts +0 -180
  76. package/src/entities/social-account.entity.ts +0 -96
  77. package/src/entities/storage-lock.entity.ts +0 -39
  78. package/src/entities/trusted-device.entity.ts +0 -112
  79. package/src/entities/user.entity.ts +0 -243
  80. package/src/entities/verification-token.entity.ts +0 -141
  81. package/src/enums/auth-audit-event-type.enum.ts +0 -360
  82. package/src/enums/error-codes.enum.ts +0 -420
  83. package/src/enums/mfa-method.enum.ts +0 -97
  84. package/src/enums/risk-factor.enum.ts +0 -111
  85. package/src/exceptions/nauth.exception.ts +0 -231
  86. package/src/handlers/auth.handler.ts +0 -260
  87. package/src/handlers/client-info.handler.ts +0 -101
  88. package/src/handlers/csrf.handler.ts +0 -156
  89. package/src/handlers/token-delivery.handler.ts +0 -118
  90. package/src/index.ts +0 -118
  91. package/src/interfaces/client-info.interface.ts +0 -85
  92. package/src/interfaces/config.interface.ts +0 -2135
  93. package/src/interfaces/entities.interface.ts +0 -226
  94. package/src/interfaces/index.ts +0 -15
  95. package/src/interfaces/logger.interface.ts +0 -283
  96. package/src/interfaces/mfa-provider.interface.ts +0 -154
  97. package/src/interfaces/oauth.interface.ts +0 -148
  98. package/src/interfaces/provider.interface.ts +0 -47
  99. package/src/interfaces/social-auth-provider.interface.ts +0 -131
  100. package/src/interfaces/storage-adapter.interface.ts +0 -82
  101. package/src/interfaces/template.interface.ts +0 -510
  102. package/src/interfaces/token-verifier.interface.ts +0 -110
  103. package/src/internal.ts +0 -178
  104. package/src/platform/interfaces.ts +0 -299
  105. package/src/schemas/auth-config.schema.ts +0 -646
  106. package/src/services/adaptive-mfa-decision.service.spec.ts +0 -1058
  107. package/src/services/adaptive-mfa-decision.service.ts +0 -457
  108. package/src/services/auth-audit.service.spec.ts +0 -675
  109. package/src/services/auth-audit.service.ts +0 -558
  110. package/src/services/auth-challenge-helper.service.spec.ts +0 -3227
  111. package/src/services/auth-challenge-helper.service.ts +0 -825
  112. package/src/services/auth-flow-context-builder.service.ts +0 -520
  113. package/src/services/auth-flow-rules.ts +0 -202
  114. package/src/services/auth-flow-state-definitions.ts +0 -190
  115. package/src/services/auth-flow-state-machine.service.ts +0 -207
  116. package/src/services/auth-flow-state-machine.types.ts +0 -316
  117. package/src/services/auth.service.spec.ts +0 -4195
  118. package/src/services/auth.service.ts +0 -3727
  119. package/src/services/challenge.service.spec.ts +0 -1363
  120. package/src/services/challenge.service.ts +0 -696
  121. package/src/services/client-info.service.spec.ts +0 -572
  122. package/src/services/client-info.service.ts +0 -374
  123. package/src/services/csrf.service.ts +0 -54
  124. package/src/services/email-verification.service.spec.ts +0 -1229
  125. package/src/services/email-verification.service.ts +0 -578
  126. package/src/services/geo-location.service.spec.ts +0 -603
  127. package/src/services/geo-location.service.ts +0 -599
  128. package/src/services/index.ts +0 -13
  129. package/src/services/jwt.service.spec.ts +0 -882
  130. package/src/services/jwt.service.ts +0 -621
  131. package/src/services/mfa-base.service.spec.ts +0 -246
  132. package/src/services/mfa-base.service.ts +0 -611
  133. package/src/services/mfa.service.spec.ts +0 -693
  134. package/src/services/mfa.service.ts +0 -960
  135. package/src/services/password.service.spec.ts +0 -166
  136. package/src/services/password.service.ts +0 -309
  137. package/src/services/phone-verification.service.spec.ts +0 -1120
  138. package/src/services/phone-verification.service.ts +0 -751
  139. package/src/services/risk-detection.service.spec.ts +0 -1292
  140. package/src/services/risk-detection.service.ts +0 -1012
  141. package/src/services/risk-scoring.service.spec.ts +0 -204
  142. package/src/services/risk-scoring.service.ts +0 -131
  143. package/src/services/session.service.spec.ts +0 -1293
  144. package/src/services/session.service.ts +0 -803
  145. package/src/services/social-account.service.spec.ts +0 -725
  146. package/src/services/social-auth-base.service.spec.ts +0 -418
  147. package/src/services/social-auth-base.service.ts +0 -581
  148. package/src/services/social-auth.service.spec.ts +0 -238
  149. package/src/services/social-auth.service.ts +0 -436
  150. package/src/services/social-provider-registry.service.spec.ts +0 -238
  151. package/src/services/social-provider-registry.service.ts +0 -122
  152. package/src/services/trusted-device.service.spec.ts +0 -505
  153. package/src/services/trusted-device.service.ts +0 -339
  154. package/src/storage/account-lockout-storage.service.spec.ts +0 -310
  155. package/src/storage/account-lockout-storage.service.ts +0 -89
  156. package/src/storage/index.ts +0 -3
  157. package/src/storage/memory-storage.adapter.ts +0 -443
  158. package/src/storage/rate-limit-storage.service.spec.ts +0 -247
  159. package/src/storage/rate-limit-storage.service.ts +0 -38
  160. package/src/templates/html-template.engine.spec.ts +0 -161
  161. package/src/templates/html-template.engine.ts +0 -688
  162. package/src/templates/index.ts +0 -7
  163. package/src/utils/common-passwords.spec.ts +0 -230
  164. package/src/utils/common-passwords.ts +0 -170
  165. package/src/utils/context-storage.ts +0 -188
  166. package/src/utils/cookie-names.util.ts +0 -67
  167. package/src/utils/cookies.util.ts +0 -94
  168. package/src/utils/index.ts +0 -12
  169. package/src/utils/ip-extractor.spec.ts +0 -330
  170. package/src/utils/ip-extractor.ts +0 -220
  171. package/src/utils/nauth-logger.spec.ts +0 -388
  172. package/src/utils/nauth-logger.ts +0 -215
  173. package/src/utils/pii-redactor.spec.ts +0 -130
  174. package/src/utils/pii-redactor.ts +0 -288
  175. package/src/utils/setup/get-repositories.ts +0 -140
  176. package/src/utils/setup/init-services.ts +0 -422
  177. package/src/utils/setup/init-social.ts +0 -189
  178. package/src/utils/setup/init-storage.ts +0 -94
  179. package/src/utils/setup/register-mfa.ts +0 -165
  180. package/src/utils/setup/run-nauth-migrations.ts +0 -61
  181. package/src/utils/token-delivery-policy.ts +0 -38
  182. package/src/validators/template.validator.ts +0 -219
  183. package/tsconfig.json +0 -37
  184. package/tsconfig.lint.json +0 -6
@@ -1,416 +0,0 @@
1
- /**
2
- * Fastify Framework Adapter
3
- *
4
- * Adapts NAuth to work with Fastify with proper AsyncLocalStorage support.
5
- *
6
- * **Context Management:**
7
- * - First hook (clientInfo) initializes AsyncLocalStorage context
8
- * - Context is stored on request object for subsequent hooks
9
- * - Each hook restores context using ContextStorage.enterStore()
10
- * - Route handlers MUST use wrapRouteHandler() for context access
11
- *
12
- * **Why Context Restoration is Needed:**
13
- * Unlike Express where middleware runs in a continuous call stack,
14
- * Fastify hooks run independently. Each hook invocation loses the
15
- * AsyncLocalStorage context, so we store it on the request and restore it.
16
- */
17
-
18
- import {
19
- NAuthAdapter,
20
- NAuthRequest,
21
- NAuthResponse,
22
- NAuthCookieOptions,
23
- NAuthRequestAttributes,
24
- NAuthMiddlewareHandler,
25
- NAuthResponseInterceptorHandler,
26
- NAuthRouteHandler,
27
- MiddlewareOptions,
28
- } from '../platform/interfaces';
29
- import { ContextStorage } from '../utils/context-storage';
30
-
31
- // Symbol for storing context on request (avoids property name collisions)
32
- const NAUTH_CONTEXT_STORE = Symbol.for('nauth.contextStore');
33
- const NAUTH_ATTRIBUTES = Symbol.for('nauth.attributes');
34
-
35
- // ============================================================================
36
- // Fastify Adapter
37
- // ============================================================================
38
-
39
- /**
40
- * Fastify Adapter Implementation
41
- *
42
- * Provides NAuth integration for Fastify applications.
43
- */
44
- export class FastifyAdapter implements NAuthAdapter {
45
- public readonly name = 'FastifyAdapter';
46
-
47
- /**
48
- * Register a middleware handler as Fastify hook
49
- *
50
- * Handles context initialization for first hook and restoration for subsequent hooks.
51
- */
52
- public registerMiddleware(name: string, handler: NAuthMiddlewareHandler, options?: MiddlewareOptions): FastifyHook {
53
- const initializesContext = options?.initializesContext || name === 'clientInfo';
54
-
55
- return async (request: FastifyRequest, reply: FastifyReply): Promise<void> => {
56
- // Ensure we have attribute storage
57
- this.ensureAttributes(request);
58
-
59
- const nauthReq = new FastifyRequestWrapper(request);
60
- const nauthRes = new FastifyResponseWrapper(reply);
61
-
62
- if (initializesContext) {
63
- // First hook - initialize context
64
- await ContextStorage.run(async () => {
65
- // Store context on request for subsequent hooks
66
- (request as FastifyRequestWithContext)[NAUTH_CONTEXT_STORE] = ContextStorage.getStore();
67
- await this.executeHandler(handler, nauthReq, nauthRes);
68
- });
69
- } else {
70
- // Subsequent hook - restore context
71
- const store = (request as FastifyRequestWithContext)[NAUTH_CONTEXT_STORE];
72
-
73
- if (store) {
74
- await ContextStorage.enterStore(store, async () => {
75
- await this.executeHandler(handler, nauthReq, nauthRes);
76
- });
77
- } else {
78
- // No context available - execute without context
79
- // This shouldn't happen if clientInfo runs first
80
- await this.executeHandler(handler, nauthReq, nauthRes);
81
- }
82
- }
83
- };
84
- }
85
-
86
- /**
87
- * Execute handler with proper async flow control
88
- */
89
- private async executeHandler(handler: NAuthMiddlewareHandler, req: NAuthRequest, res: NAuthResponse): Promise<void> {
90
- await new Promise<void>((resolve, reject) => {
91
- const result = handler(req, res, () => {
92
- resolve();
93
- });
94
-
95
- if (result instanceof Promise) {
96
- result.then(() => resolve()).catch(reject);
97
- }
98
- });
99
- }
100
-
101
- /**
102
- * Register a response interceptor using Fastify onSend hook
103
- *
104
- * The onSend hook receives the serialized payload before sending.
105
- */
106
- public registerResponseInterceptor(handler: NAuthResponseInterceptorHandler): FastifyOnSendHook {
107
- return async (request: FastifyRequest, reply: FastifyReply, payload: unknown): Promise<unknown> => {
108
- this.ensureAttributes(request);
109
-
110
- const nauthReq = new FastifyRequestWrapper(request);
111
- const nauthRes = new FastifyResponseWrapper(reply);
112
-
113
- // Restore context for interceptor
114
- const store = (request as FastifyRequestWithContext)[NAUTH_CONTEXT_STORE];
115
-
116
- if (!store) {
117
- // No context - pass through unchanged
118
- return payload;
119
- }
120
-
121
- return ContextStorage.enterStore(store, async () => {
122
- try {
123
- let parsedPayload = payload;
124
-
125
- // Parse JSON payload if needed (Fastify serializes before onSend)
126
- const contentType = reply.getHeader('content-type') as string | undefined;
127
- const isJson = contentType?.includes('application/json');
128
-
129
- if (isJson && typeof payload === 'string') {
130
- try {
131
- parsedPayload = JSON.parse(payload);
132
- } catch {
133
- // Not valid JSON, use as-is
134
- }
135
- }
136
-
137
- const modifiedBody = await handler(nauthReq, nauthRes, parsedPayload);
138
-
139
- // Re-serialize if we parsed it
140
- if (modifiedBody !== parsedPayload && isJson && typeof modifiedBody === 'object') {
141
- return JSON.stringify(modifiedBody);
142
- }
143
-
144
- return modifiedBody !== parsedPayload ? modifiedBody : payload;
145
- } catch {
146
- // On error, return original payload
147
- return payload;
148
- }
149
- });
150
- };
151
- }
152
-
153
- /**
154
- * Wrap a route handler to ensure context is available
155
- *
156
- * For Fastify, this is REQUIRED for route handlers to access ContextStorage.
157
- */
158
- public wrapRouteHandler<T>(handler: NAuthRouteHandler<T>): FastifyRouteHandler {
159
- return async (request: FastifyRequest, reply: FastifyReply): Promise<T | void> => {
160
- this.ensureAttributes(request);
161
-
162
- const nauthReq = new FastifyRequestWrapper(request);
163
- const nauthRes = new FastifyResponseWrapper(reply);
164
-
165
- // Restore context
166
- const store = (request as FastifyRequestWithContext)[NAUTH_CONTEXT_STORE];
167
-
168
- if (store) {
169
- return ContextStorage.enterStore(store, async () => {
170
- return handler(nauthReq, nauthRes);
171
- });
172
- }
173
-
174
- // No context - execute without (shouldn't happen with proper setup)
175
- return handler(nauthReq, nauthRes);
176
- };
177
- }
178
-
179
- /**
180
- * Ensure attribute storage exists on request
181
- */
182
- private ensureAttributes(request: FastifyRequest): void {
183
- if (!(request as FastifyRequestWithContext)[NAUTH_ATTRIBUTES]) {
184
- (request as FastifyRequestWithContext)[NAUTH_ATTRIBUTES] = {};
185
- }
186
- }
187
- }
188
-
189
- // ============================================================================
190
- // Fastify Request Wrapper
191
- // ============================================================================
192
-
193
- /**
194
- * Wraps Fastify request into NAuthRequest interface
195
- */
196
- class FastifyRequestWrapper implements NAuthRequest {
197
- constructor(private readonly request: FastifyRequest) {}
198
-
199
- get raw(): unknown {
200
- return this.request;
201
- }
202
-
203
- get method(): string {
204
- return this.request.method.toUpperCase();
205
- }
206
-
207
- get path(): string {
208
- // Fastify provides routeOptions.url for path, or extract from url
209
- return this.request.url.split('?')[0];
210
- }
211
-
212
- get url(): string {
213
- return this.request.url;
214
- }
215
-
216
- get body(): Record<string, unknown> {
217
- return (this.request.body as Record<string, unknown>) || {};
218
- }
219
-
220
- get query(): Record<string, unknown> {
221
- return (this.request.query as Record<string, unknown>) || {};
222
- }
223
-
224
- get params(): Record<string, string> {
225
- return (this.request.params as Record<string, string>) || {};
226
- }
227
-
228
- get headers(): Record<string, string | string[] | undefined> {
229
- return this.request.headers as Record<string, string | string[] | undefined>;
230
- }
231
-
232
- get cookies(): Record<string, string | undefined> {
233
- // Fastify with @fastify/cookie
234
- return ((this.request as FastifyRequestWithCookies).cookies as Record<string, string | undefined>) || {};
235
- }
236
-
237
- get ip(): string {
238
- return this.request.ip || '0.0.0.0';
239
- }
240
-
241
- get attributes(): NAuthRequestAttributes {
242
- // Return isolated storage
243
- return (this.request as FastifyRequestWithContext)[NAUTH_ATTRIBUTES] || {};
244
- }
245
-
246
- public getHeader(name: string): string | undefined {
247
- const val = this.request.headers[name.toLowerCase()];
248
- if (Array.isArray(val)) return val[0];
249
- return val;
250
- }
251
- }
252
-
253
- // ============================================================================
254
- // Fastify Response Wrapper
255
- // ============================================================================
256
-
257
- /**
258
- * Wraps Fastify reply into NAuthResponse interface
259
- */
260
- class FastifyResponseWrapper implements NAuthResponse {
261
- constructor(private readonly reply: FastifyReply) {}
262
-
263
- get raw(): unknown {
264
- return this.reply;
265
- }
266
-
267
- public status(code: number): this {
268
- this.reply.code(code);
269
- return this;
270
- }
271
-
272
- public header(name: string, value: string | string[]): this {
273
- this.reply.header(name, value);
274
- return this;
275
- }
276
-
277
- public setCookie(name: string, value: string, options?: NAuthCookieOptions): this {
278
- // Fastify with @fastify/cookie
279
- const replyWithCookies = this.reply as FastifyReplyWithCookies;
280
- if (typeof replyWithCookies.setCookie === 'function') {
281
- replyWithCookies.setCookie(name, value, this.convertCookieOptions(options));
282
- }
283
- return this;
284
- }
285
-
286
- public clearCookie(name: string, options?: NAuthCookieOptions): this {
287
- const replyWithCookies = this.reply as FastifyReplyWithCookies;
288
- if (typeof replyWithCookies.clearCookie === 'function') {
289
- replyWithCookies.clearCookie(name, this.convertCookieOptions(options));
290
- } else if (typeof replyWithCookies.setCookie === 'function') {
291
- // Fallback: set empty cookie with immediate expiry
292
- replyWithCookies.setCookie(name, '', {
293
- ...this.convertCookieOptions(options),
294
- maxAge: 0,
295
- expires: new Date(0),
296
- });
297
- }
298
- return this;
299
- }
300
-
301
- public send(body: unknown): void {
302
- this.reply.send(body);
303
- }
304
-
305
- public json(body: unknown): void {
306
- // Fastify auto-serializes objects
307
- this.reply.send(body);
308
- }
309
-
310
- public redirect(url: string, status?: number): void {
311
- if (status) {
312
- this.reply.redirect(status, url);
313
- } else {
314
- this.reply.redirect(url);
315
- }
316
- }
317
-
318
- public isSent(): boolean {
319
- return this.reply.sent;
320
- }
321
-
322
- /**
323
- * Convert NAuth cookie options to Fastify cookie options
324
- */
325
- private convertCookieOptions(options?: NAuthCookieOptions): Record<string, unknown> {
326
- if (!options) return {};
327
-
328
- return {
329
- httpOnly: options.httpOnly,
330
- secure: options.secure,
331
- sameSite: options.sameSite,
332
- domain: options.domain,
333
- path: options.path,
334
- maxAge: options.maxAge,
335
- expires: options.expires,
336
- };
337
- }
338
- }
339
-
340
- // ============================================================================
341
- // Fastify Type Definitions (minimal, for internal use)
342
- // ============================================================================
343
-
344
- interface FastifyRequest {
345
- method: string;
346
- url: string;
347
- body: unknown;
348
- query: unknown;
349
- params: unknown;
350
- headers: Record<string, string | string[] | undefined>;
351
- ip: string;
352
- }
353
-
354
- interface FastifyRequestWithCookies extends FastifyRequest {
355
- cookies?: Record<string, string>;
356
- }
357
-
358
- interface FastifyRequestWithContext extends FastifyRequest {
359
- [NAUTH_CONTEXT_STORE]?: Map<string, unknown>;
360
- [NAUTH_ATTRIBUTES]?: NAuthRequestAttributes;
361
- }
362
-
363
- interface FastifyReply {
364
- code(statusCode: number): this;
365
- header(name: string, value: string | string[]): this;
366
- send(payload?: unknown): this;
367
- redirect(url: string): this;
368
- redirect(statusCode: number, url: string): this;
369
- getHeader(name: string): string | undefined;
370
- sent: boolean;
371
- }
372
-
373
- interface FastifyReplyWithCookies extends FastifyReply {
374
- setCookie?(name: string, value: string, options?: Record<string, unknown>): this;
375
- clearCookie?(name: string, options?: Record<string, unknown>): this;
376
- }
377
-
378
- type FastifyHook = (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
379
- type FastifyOnSendHook = (request: FastifyRequest, reply: FastifyReply, payload: unknown) => Promise<unknown>;
380
- type FastifyRouteHandler = (request: FastifyRequest, reply: FastifyReply) => Promise<unknown>;
381
-
382
- // ============================================================================
383
- // Convenience Export
384
- // ============================================================================
385
-
386
- /**
387
- * Convenience function for wrapping Fastify route handlers
388
- *
389
- * @deprecated Use adapter.wrapRouteHandler() instead. This is kept for backward compatibility.
390
- *
391
- * @example
392
- * ```typescript
393
- * // Old way (deprecated):
394
- * fastify.get('/me', withNAuthContext(async (request, reply) => {...}));
395
- *
396
- * // New way (recommended):
397
- * const handler = nauth.adapter.wrapRouteHandler(async (req, res) => {...});
398
- * fastify.get('/me', handler);
399
- * ```
400
- */
401
- export function withNAuthContext<T>(
402
- handler: (request: FastifyRequest, reply: FastifyReply) => Promise<T>,
403
- ): (request: FastifyRequest, reply: FastifyReply) => Promise<T | void> {
404
- return async (request: FastifyRequest, reply: FastifyReply): Promise<T | void> => {
405
- const store = (request as FastifyRequestWithContext)[NAUTH_CONTEXT_STORE];
406
-
407
- if (store) {
408
- return ContextStorage.enterStore(store, async () => {
409
- return handler(request, reply);
410
- });
411
- }
412
-
413
- // No context - execute without
414
- return handler(request, reply);
415
- };
416
- }
@@ -1,16 +0,0 @@
1
- /**
2
- * Platform Adapters
3
- *
4
- * Framework-specific adapters that implement NAuthAdapter interface.
5
- */
6
-
7
- // Platform interfaces (for custom adapter development)
8
- export * from '../platform/interfaces';
9
-
10
- // Built-in adapters
11
- export { ExpressAdapter, ExpressMiddlewareType } from './express.adapter';
12
- export { FastifyAdapter } from './fastify.adapter';
13
-
14
- // Legacy export for backward compatibility (deprecated)
15
- // TODO: Remove in next major version
16
- export { withNAuthContext } from './fastify.adapter';
@@ -1,143 +0,0 @@
1
- /**
2
- * Storage Adapter Factory Functions
3
- *
4
- * Provides clean factory functions for creating storage adapters.
5
- * These factories handle proper initialization and simplify configuration.
6
- *
7
- * @example
8
- * ```typescript
9
- * import { createDatabaseStorageAdapter, createRedisStorageAdapter } from '@nauth-toolkit/express';
10
- *
11
- * export const authConfig = {
12
- * // Database adapter (uses existing TypeORM connection)
13
- * storageAdapter: createDatabaseStorageAdapter(),
14
- *
15
- * // Or Redis adapter
16
- * storageAdapter: createRedisStorageAdapter(process.env.REDIS_URL),
17
- * };
18
- * ```
19
- */
20
-
21
- import { StorageAdapter } from '../interfaces/storage-adapter.interface';
22
-
23
- /**
24
- * Create a database storage adapter
25
- *
26
- * Uses the existing TypeORM connection. Make sure storage entities are included
27
- * in your DataSource configuration:
28
- *
29
- * ```typescript
30
- * import { getNAuthStorageEntities } from '@nauth-toolkit/database-typeorm-postgres';
31
- * const dataSource = new DataSource({
32
- * entities: [...getNAuthEntities(), ...getNAuthStorageEntities()],
33
- * });
34
- * ```
35
- *
36
- * @returns DatabaseStorageAdapter instance
37
- *
38
- * @example
39
- * ```typescript
40
- * import { createDatabaseStorageAdapter } from '@nauth-toolkit/express';
41
- *
42
- * export const authConfig = {
43
- * storageAdapter: createDatabaseStorageAdapter(),
44
- * // ... other config
45
- * };
46
- * ```
47
- */
48
- export function createDatabaseStorageAdapter(): StorageAdapter {
49
- // Lazy import to avoid bundling if not used
50
- const { DatabaseStorageAdapter } = require('@nauth-toolkit/storage-database');
51
- return new DatabaseStorageAdapter(null, null, null);
52
- }
53
-
54
- /**
55
- * Create a Redis storage adapter
56
- *
57
- * Creates and connects a Redis client automatically using the `redis` package (node-redis).
58
- * The client connection is managed internally by the adapter.
59
- *
60
- * Supports both single-instance Redis and Redis Cluster configurations.
61
- *
62
- * @param url - Redis connection URL (default: 'redis://localhost:6379')
63
- * Supports authentication in URL format:
64
- * - redis://localhost:6379 (no auth)
65
- * - redis://:password@localhost:6379 (password only)
66
- * - redis://username:password@localhost:6379 (username + password)
67
- * - rediss://localhost:6379 (TLS/SSL, with optional auth)
68
- * @returns RedisStorageAdapter instance
69
- *
70
- * @example
71
- * ```typescript
72
- * import { createRedisStorageAdapter, createRedisClusterAdapter } from '@nauth-toolkit/express';
73
- *
74
- * export const authConfig = {
75
- * // Single-instance Redis
76
- * storageAdapter: createRedisStorageAdapter(process.env.REDIS_URL),
77
- *
78
- * // Or Redis Cluster (for production high-availability)
79
- * storageAdapter: createRedisClusterAdapter([
80
- * { url: 'redis://redis-node-1:6379' },
81
- * { url: 'redis://redis-node-2:6379' },
82
- * { url: 'redis://redis-node-3:6379' },
83
- * ]),
84
- * };
85
- * ```
86
- */
87
- export function createRedisStorageAdapter(url: string = 'redis://localhost:6379'): StorageAdapter {
88
- // Lazy import to avoid bundling if not used
89
- const { RedisStorageAdapter } = require('@nauth-toolkit/storage-redis');
90
- const { createClient } = require('redis');
91
-
92
- const redisClient = createClient({ url });
93
-
94
- // Don't connect here - let adapter.initialize() handle connection
95
- // This ensures proper error handling and allows initialize() to wait for connection
96
-
97
- return new RedisStorageAdapter(redisClient);
98
- }
99
-
100
- /**
101
- * Create a Redis Cluster storage adapter
102
- *
103
- * Creates and connects a Redis Cluster client automatically using the `redis` package (node-redis).
104
- * The cluster client handles automatic topology discovery, command routing, and failover.
105
- *
106
- * **Production Use:**
107
- * Use Redis Cluster for high-availability production deployments. The cluster automatically:
108
- * - Discovers cluster topology
109
- * - Routes commands to correct nodes based on key hash slots
110
- * - Handles node failures and redirects (MOVED/ASK errors)
111
- * - Provides high availability and horizontal scaling
112
- *
113
- * @param nodes - Array of cluster node URLs
114
- * @returns RedisStorageAdapter instance
115
- *
116
- * @example
117
- * ```typescript
118
- * import { createRedisClusterAdapter } from '@nauth-toolkit/express';
119
- *
120
- * export const authConfig = {
121
- * // Redis Cluster with 3 nodes
122
- * storageAdapter: createRedisClusterAdapter([
123
- * { url: 'redis://redis-node-1:6379' },
124
- * { url: 'redis://redis-node-2:6379' },
125
- * { url: 'redis://redis-node-3:6379' },
126
- * ]),
127
- * };
128
- * ```
129
- */
130
- export function createRedisClusterAdapter(nodes: Array<{ url: string }>): StorageAdapter {
131
- // Lazy import to avoid bundling if not used
132
- const { RedisStorageAdapter } = require('@nauth-toolkit/storage-redis');
133
- const { createCluster } = require('redis');
134
-
135
- const clusterClient = createCluster({
136
- rootNodes: nodes,
137
- });
138
-
139
- // Don't connect here - let adapter.initialize() handle connection
140
- // This ensures proper error handling and allows initialize() to wait for connection
141
-
142
- return new RedisStorageAdapter(clusterClient);
143
- }