mulguard 1.0.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.
Files changed (66) hide show
  1. package/README.md +368 -0
  2. package/dist/actions-CExpv_dD.js +1 -0
  3. package/dist/actions-DeCfLtHA.mjs +184 -0
  4. package/dist/client/hooks.d.ts +122 -0
  5. package/dist/client/index.d.ts +5 -0
  6. package/dist/client/index.js +1 -0
  7. package/dist/client/index.mjs +476 -0
  8. package/dist/client/provider.d.ts +25 -0
  9. package/dist/client/server-actions-helper.d.ts +22 -0
  10. package/dist/components/AccountPicker.d.ts +11 -0
  11. package/dist/components/OAuthButton.d.ts +11 -0
  12. package/dist/components/PassKeyButton.d.ts +11 -0
  13. package/dist/components/PassKeyRegister.d.ts +10 -0
  14. package/dist/components/TwoFactorSetup.d.ts +8 -0
  15. package/dist/components/TwoFactorVerify.d.ts +9 -0
  16. package/dist/core/account-picker/encryption.d.ts +22 -0
  17. package/dist/core/account-picker/index.d.ts +22 -0
  18. package/dist/core/auth/index.d.ts +40 -0
  19. package/dist/core/auth/oauth-providers.d.ts +69 -0
  20. package/dist/core/auth/oauth-state-store.d.ts +44 -0
  21. package/dist/core/auth/oauth.d.ts +20 -0
  22. package/dist/core/auth/passkey.d.ts +35 -0
  23. package/dist/core/auth/password.d.ts +22 -0
  24. package/dist/core/auth/signin-unified.d.ts +33 -0
  25. package/dist/core/auth/two-factor.d.ts +28 -0
  26. package/dist/core/client/index.d.ts +132 -0
  27. package/dist/core/client/token-refresh-manager.d.ts +48 -0
  28. package/dist/core/index.d.ts +10 -0
  29. package/dist/core/security/csrf.d.ts +46 -0
  30. package/dist/core/security/headers.d.ts +24 -0
  31. package/dist/core/security/index.d.ts +28 -0
  32. package/dist/core/security/rate-limit.d.ts +39 -0
  33. package/dist/core/security/validation.d.ts +53 -0
  34. package/dist/core/security/xss.d.ts +20 -0
  35. package/dist/core/session/index.d.ts +35 -0
  36. package/dist/core/types/auth.d.ts +131 -0
  37. package/dist/core/types/errors.d.ts +44 -0
  38. package/dist/core/types/index.d.ts +369 -0
  39. package/dist/core/utils/auth-helpers.d.ts +136 -0
  40. package/dist/core/utils/logger.d.ts +17 -0
  41. package/dist/handlers/api.d.ts +10 -0
  42. package/dist/handlers/route.d.ts +22 -0
  43. package/dist/index/index.js +1 -0
  44. package/dist/index/index.mjs +1633 -0
  45. package/dist/index.d.ts +21 -0
  46. package/dist/middleware/index.d.ts +28 -0
  47. package/dist/middleware/proxy.d.ts +53 -0
  48. package/dist/middleware/security.d.ts +9 -0
  49. package/dist/mulguard.d.ts +263 -0
  50. package/dist/oauth-state-CzIWQq3s.js +1 -0
  51. package/dist/oauth-state-LE-qeq-K.mjs +282 -0
  52. package/dist/server/actions.d.ts +86 -0
  53. package/dist/server/auth.d.ts +65 -0
  54. package/dist/server/cookies.d.ts +42 -0
  55. package/dist/server/helpers.d.ts +10 -0
  56. package/dist/server/index.d.ts +14 -0
  57. package/dist/server/index.js +1 -0
  58. package/dist/server/index.mjs +31 -0
  59. package/dist/server/middleware.d.ts +39 -0
  60. package/dist/server/oauth-state.d.ts +24 -0
  61. package/dist/server/session-helpers.d.ts +26 -0
  62. package/dist/server/session.d.ts +28 -0
  63. package/dist/server/utils.d.ts +10 -0
  64. package/dist/signin-unified-BS2gxaG1.mjs +30 -0
  65. package/dist/signin-unified-Cw41EFkc.js +1 -0
  66. package/package.json +73 -0
package/README.md ADDED
@@ -0,0 +1,368 @@
1
+ # Mukey - Modern Authentication Library
2
+
3
+ > Backend-first authentication library for Next.js and modern web applications
4
+
5
+ [![License](https://img.shields.io/badge/license-MUV-blue.svg)](LICENSE)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.3+-blue.svg)](https://www.typescriptlang.org/)
7
+
8
+ Mukey is a modern, secure authentication library designed for Next.js applications with a backend-first architecture. It provides a simple API similar to `better-auth` and `auth.js`, while maintaining full control over your backend authentication logic.
9
+
10
+ ## ✨ Features
11
+
12
+ - 🔐 **Multiple Auth Methods**
13
+ - Email/Password authentication
14
+ - OAuth 2.1 (Google, GitHub, etc.)
15
+ - PassKey/WebAuthn support
16
+ - Two-Factor Authentication (2FA/TOTP)
17
+
18
+ - 🎯 **Account Picker**
19
+ - Remember last logged-in users
20
+ - Quick re-login experience
21
+ - Encrypted local storage
22
+
23
+ - 🔒 **Security First**
24
+ - CSRF protection
25
+ - XSS prevention
26
+ - Input validation & sanitization
27
+ - Security headers
28
+ - Rate limiting utilities
29
+
30
+ - ⚡ **Next.js Optimized**
31
+ - Server Components support
32
+ - Client hooks (`useAuth`, `useSession`)
33
+ - Middleware integration
34
+ - API route handlers
35
+
36
+ - 🔌 **Backend-First**
37
+ - No database adapter required
38
+ - Works with your existing backend API
39
+ - Mulink integration support
40
+ - Full TypeScript support
41
+
42
+ ## 📦 Installation
43
+
44
+ ```bash
45
+ npm install mukey
46
+ ```
47
+
48
+ ## 🚀 Quick Start
49
+
50
+ ### 1. Create Auth Configuration
51
+
52
+ ```typescript
53
+ // lib/auth.ts
54
+ import { mukey } from 'mukey'
55
+ // import { apiClient } from '@mulink/client' // Optional: Use Mulink
56
+
57
+ export const auth = mukey({
58
+ // Option 1: Use Mulink API client
59
+ // apiClient: apiClient,
60
+
61
+ // Option 2: Use baseURL
62
+ baseURL: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001',
63
+
64
+ session: {
65
+ cookieName: '__mukey_session',
66
+ expiresIn: 60 * 60 * 24 * 7, // 7 days
67
+ },
68
+
69
+ providers: {
70
+ oauth: {
71
+ google: {
72
+ clientId: process.env.GOOGLE_CLIENT_ID!,
73
+ redirectUri: `${process.env.NEXT_PUBLIC_URL}/api/auth/callback/google`,
74
+ scopes: ['openid', 'profile', 'email'],
75
+ },
76
+ },
77
+ },
78
+
79
+ accountPicker: {
80
+ enabled: true,
81
+ maxAccounts: 3,
82
+ },
83
+ })
84
+ ```
85
+
86
+ ### 2. Server-Side Usage
87
+
88
+ ```typescript
89
+ // app/dashboard/page.tsx
90
+ import { getServerSession } from 'mukey/server'
91
+ import { auth } from '@/lib/auth'
92
+ import { redirect } from 'next/navigation'
93
+
94
+ export default async function DashboardPage() {
95
+ const session = await getServerSession(auth)
96
+
97
+ if (!session) {
98
+ redirect('/login')
99
+ }
100
+
101
+ return <div>Welcome, {session.user.name}!</div>
102
+ }
103
+ ```
104
+
105
+ ### 3. Client-Side Usage
106
+
107
+ ```typescript
108
+ // app/login/page.tsx
109
+ 'use client'
110
+
111
+ import { useAuth } from 'mukey/client'
112
+ import { auth } from '@/lib/auth'
113
+ import { useState } from 'react'
114
+
115
+ export default function LoginPage() {
116
+ const { signIn, session, isLoading } = useAuth(auth)
117
+ const [email, setEmail] = useState('')
118
+ const [password, setPassword] = useState('')
119
+
120
+ const handleSubmit = async (e: React.FormEvent) => {
121
+ e.preventDefault()
122
+ const result = await signIn.email({ email, password })
123
+ if (result.success) {
124
+ // Redirect to dashboard
125
+ }
126
+ }
127
+
128
+ if (isLoading) return <div>Loading...</div>
129
+ if (session) return <div>Already logged in</div>
130
+
131
+ return (
132
+ <form onSubmit={handleSubmit}>
133
+ <input
134
+ type="email"
135
+ value={email}
136
+ onChange={(e) => setEmail(e.target.value)}
137
+ placeholder="Email"
138
+ />
139
+ <input
140
+ type="password"
141
+ value={password}
142
+ onChange={(e) => setPassword(e.target.value)}
143
+ placeholder="Password"
144
+ />
145
+ <button type="submit">Sign In</button>
146
+ </form>
147
+ )
148
+ }
149
+ ```
150
+
151
+ ### 4. Middleware (Optional)
152
+
153
+ ```typescript
154
+ // middleware.ts
155
+ import { createAuthMiddleware } from 'mukey/middleware'
156
+ import { auth } from '@/lib/auth'
157
+
158
+ export default createAuthMiddleware(auth, {
159
+ protectedRoutes: ['/dashboard', '/profile'],
160
+ redirectTo: '/login',
161
+ redirectIfAuthenticated: '/dashboard',
162
+ })
163
+ ```
164
+
165
+ ## 📚 Documentation
166
+
167
+ - [Getting Started](./docs/GETTING_STARTED.md)
168
+ - [Authentication Methods](./docs/AUTH_METHODS.md)
169
+ - [Server-Side Usage](./docs/SERVER_USAGE.md)
170
+ - [Client-Side Usage](./docs/CLIENT_USAGE.md)
171
+ - [Security](./docs/SECURITY.md)
172
+ - [Backend Integration](./docs/BACKEND_INTEGRATION.md)
173
+ - [API Reference](./docs/API_REFERENCE.md)
174
+
175
+ ## 🔧 Configuration
176
+
177
+ ### Full Configuration Options
178
+
179
+ ```typescript
180
+ import { mukey } from 'mukey'
181
+
182
+ export const auth = mukey({
183
+ // API Client (from Mulink) or baseURL
184
+ apiClient: apiClient, // Optional
185
+ baseURL: 'http://localhost:3001', // Required if apiClient not provided
186
+
187
+ // Session configuration
188
+ session: {
189
+ cookieName: '__mukey_session',
190
+ expiresIn: 60 * 60 * 24 * 7, // 7 days in seconds
191
+ httpOnly: true,
192
+ secure: process.env.NODE_ENV === 'production',
193
+ sameSite: 'lax',
194
+ },
195
+
196
+ // OAuth providers
197
+ providers: {
198
+ oauth: {
199
+ google: {
200
+ clientId: '...',
201
+ redirectUri: '...',
202
+ scopes: ['openid', 'profile', 'email'],
203
+ name: 'Google',
204
+ },
205
+ github: {
206
+ clientId: '...',
207
+ redirectUri: '...',
208
+ scopes: ['user:email'],
209
+ },
210
+ },
211
+ },
212
+
213
+ // 2FA configuration
214
+ twoFactor: {
215
+ enabled: true,
216
+ },
217
+
218
+ // Account Picker
219
+ accountPicker: {
220
+ enabled: true,
221
+ maxAccounts: 3,
222
+ encryptStorage: true,
223
+ storageKey: '__mukey_accounts',
224
+ },
225
+
226
+ // Security
227
+ security: {
228
+ csrfProtection: true,
229
+ rateLimiting: {
230
+ maxAttempts: 5,
231
+ windowMs: 15 * 60 * 1000, // 15 minutes
232
+ },
233
+ },
234
+ })
235
+ ```
236
+
237
+ ## 🎨 Components
238
+
239
+ ### Account Picker
240
+
241
+ ```typescript
242
+ import { AccountPicker } from 'mukey'
243
+
244
+ <AccountPicker
245
+ auth={auth}
246
+ onSelectUser={(user) => {
247
+ // Pre-fill email or handle quick login
248
+ setEmail(user.email)
249
+ }}
250
+ onUseDifferentAccount={() => {
251
+ // Show full login form
252
+ }}
253
+ />
254
+ ```
255
+
256
+ ### OAuth Button
257
+
258
+ ```typescript
259
+ import { OAuthButton } from 'mukey'
260
+
261
+ <OAuthButton
262
+ auth={auth}
263
+ provider="google"
264
+ onSuccess={() => {
265
+ // Handle success
266
+ }}
267
+ />
268
+ ```
269
+
270
+ ### 2FA Setup
271
+
272
+ ```typescript
273
+ import { TwoFactorSetup } from 'mukey'
274
+
275
+ <TwoFactorSetup
276
+ auth={auth}
277
+ onSuccess={() => {
278
+ // 2FA enabled
279
+ }}
280
+ />
281
+ ```
282
+
283
+ ## 🔌 Backend Integration
284
+
285
+ Mukey expects your backend to provide the following endpoints:
286
+
287
+ ### Authentication Endpoints
288
+
289
+ - `POST /api/auth/sign-in` - Sign in with email/password
290
+ - `POST /api/auth/sign-up` - Register new user
291
+ - `POST /api/auth/sign-out` - Sign out
292
+ - `GET /api/auth/session` - Get current session
293
+ - `POST /api/auth/reset-password` - Request password reset
294
+ - `POST /api/auth/verify-email` - Verify email address
295
+
296
+ ### OAuth Endpoints
297
+
298
+ - `GET /api/auth/oauth/:provider` - Initiate OAuth flow
299
+ - `POST /api/auth/oauth/:provider/callback` - Handle OAuth callback
300
+
301
+ ### 2FA Endpoints
302
+
303
+ - `POST /api/auth/2fa/enable` - Enable 2FA
304
+ - `POST /api/auth/2fa/verify` - Verify 2FA code
305
+ - `POST /api/auth/2fa/disable` - Disable 2FA
306
+ - `POST /api/auth/2fa/regenerate` - Generate backup codes
307
+ - `GET /api/auth/2fa/status` - Check 2FA status
308
+
309
+ ### PassKey Endpoints
310
+
311
+ - `POST /api/auth/passkey/register` - Register PassKey
312
+ - `POST /api/auth/passkey/authenticate` - Authenticate with PassKey
313
+ - `GET /api/auth/passkey/list` - List registered PassKeys
314
+ - `DELETE /api/auth/passkey/:id` - Remove PassKey
315
+
316
+ See [Backend Integration Guide](./docs/BACKEND_INTEGRATION.md) for detailed API specifications.
317
+
318
+ ## 🔒 Security
319
+
320
+ Mukey implements multiple security features:
321
+
322
+ - **CSRF Protection** - Token-based CSRF protection
323
+ - **XSS Prevention** - Input sanitization and HTML escaping
324
+ - **Rate Limiting** - Client-side rate limit tracking
325
+ - **Security Headers** - Automatic security headers
326
+ - **Input Validation** - Comprehensive input validation
327
+ - **Secure Cookies** - HttpOnly, Secure, SameSite cookies
328
+
329
+ See [Security Guide](./docs/SECURITY.md) for more details.
330
+
331
+ ## 🧪 Testing
332
+
333
+ ```bash
334
+ # Run tests
335
+ npm test
336
+
337
+ # Watch mode
338
+ npm run test:watch
339
+
340
+ # Coverage
341
+ npm run test:coverage
342
+ ```
343
+
344
+ ## 🚀 CI/CD
345
+
346
+ This project uses GitHub Actions with npm Trusted Publisher for secure publishing.
347
+
348
+ - **CI**: Runs on every push/PR (lint, test, build)
349
+ - **Publishing**: Automatic publishing via Changesets or manual release
350
+ - **Security**: Uses OIDC (OpenID Connect) for authentication
351
+
352
+ See [README_CI.md](./README_CI.md) for setup instructions.
353
+
354
+ ## 📝 License
355
+
356
+ MUV License - See [LICENSE](./LICENSE) file for details.
357
+
358
+ ## 🤝 Contributing
359
+
360
+ Contributions are welcome! Please read our contributing guidelines first.
361
+
362
+ ## 📧 Support
363
+
364
+ For questions and support, please open an issue on GitHub.
365
+
366
+ ---
367
+
368
+ Made with ❤️ by the Mukey Team
@@ -0,0 +1 @@
1
+ "use strict";const O=require("next/headers");var r=(s=>(s.INVALID_CREDENTIALS="INVALID_CREDENTIALS",s.ACCOUNT_LOCKED="ACCOUNT_LOCKED",s.ACCOUNT_INACTIVE="ACCOUNT_INACTIVE",s.TWO_FA_REQUIRED="TWO_FA_REQUIRED",s.INVALID_TWO_FA_CODE="INVALID_TWO_FA_CODE",s.SESSION_EXPIRED="SESSION_EXPIRED",s.UNAUTHORIZED="UNAUTHORIZED",s.NETWORK_ERROR="NETWORK_ERROR",s.VALIDATION_ERROR="VALIDATION_ERROR",s.RATE_LIMITED="RATE_LIMITED",s.UNKNOWN_ERROR="UNKNOWN_ERROR",s))(r||{});async function R(s){var n;try{return(n=(await O.cookies()).get(s))==null?void 0:n.value}catch(e){const o=(e==null?void 0:e.message)||"";if(o.includes("cookies")||o.includes("request scope")||o.includes("outside")||o.includes("dynamic"))return;throw e}}async function u(s){try{return(await O.cookies()).set({name:s.name,value:s.value,maxAge:s.maxAge,expires:s.expires,httpOnly:s.httpOnly??!0,secure:s.secure,sameSite:s.sameSite??"lax",path:s.path??"/",domain:s.domain}),{success:!0}}catch(n){const e=(n==null?void 0:n.message)||"";if(e.includes("cookies")||e.includes("request scope")||e.includes("outside")||e.includes("dynamic")){const o=`Cannot set cookie "${s.name}" outside request scope. Make sure this is called from a Server Action or Route Handler.`;return process.env.NODE_ENV==="development"&&console.warn(`[Mulguard] ${o}`),{success:!1,error:e,warning:o}}throw n}}async function f(s,n){try{(await O.cookies()).set({name:s,value:"",maxAge:0,expires:new Date(0),httpOnly:!0,path:(n==null?void 0:n.path)??"/",domain:n==null?void 0:n.domain})}catch(e){const o=(e==null?void 0:e.message)||"";if(o.includes("cookies")||o.includes("request scope")||o.includes("outside")||o.includes("dynamic")){process.env.NODE_ENV==="development"&&console.warn(`[Mulguard] Cannot delete cookie "${s}" outside request scope`);return}throw e}}function l(s,n,e){const o=process.env.NODE_ENV==="production";return{name:s,value:n,maxAge:e.expiresIn,httpOnly:e.httpOnly??!0,secure:e.secure??o,sameSite:e.sameSite??"lax",path:e.path??"/"}}async function g(s,n){if(!s.verify2FA)return{success:!1,error:"2FA verification is not configured",errorCode:r.VALIDATION_ERROR};try{const e=await s.verify2FA(n,{skipCookieSave:!0});if(e.success&&e.session)try{const{cookieName:o,config:t}=s._getSessionConfig(),c=typeof e.session=="object"&&"token"in e.session?String(e.session.token):JSON.stringify(e.session),i=l(o,c,t),a=await u(i);a.success||process.env.NODE_ENV==="development"&&console.warn("[Mulguard] Failed to save session after 2FA verification:",a.error||a.warning)}catch(o){process.env.NODE_ENV==="development"&&console.warn("[Mulguard] Failed to save session cookie:",o)}return e}catch(e){return{success:!1,error:e instanceof Error?e.message:"2FA verification failed",errorCode:r.UNKNOWN_ERROR}}}async function N(s){var n;try{const e=await s.getSession(),o=e==null?void 0:e.user;s.signOut&&await s.signOut();const{cookieName:t,config:c}=s._getSessionConfig();await f(t,{path:c.path||"/"});const i=(n=s._getCallbacks)==null?void 0:n.call(s);return o&&(i!=null&&i.onSignOut)&&await i.onSignOut(o),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:"Sign out failed"}}}async function d(s,n){var e;if(!((e=s.signIn)!=null&&e.email))return{success:!1,error:"Email sign in is not configured",errorCode:r.VALIDATION_ERROR};try{const o=await s.signIn.email(n);if(o.success&&o.session)try{const{cookieName:t,config:c}=s._getSessionConfig(),i=typeof o.session=="object"&&"token"in o.session?String(o.session.token):JSON.stringify(o.session),a=l(t,i,c);await u(a)}catch(t){process.env.NODE_ENV==="development"&&console.warn("[Mulguard] Failed to save session cookie:",t)}return o}catch(o){return{success:!1,error:o instanceof Error?o.message:"Sign in failed",errorCode:r.UNKNOWN_ERROR}}}async function E(s,n){if(!s.signUp)return{success:!1,error:"Sign up is not configured",errorCode:r.VALIDATION_ERROR};try{const e=await s.signUp(n);if(e.success&&e.session)try{const{cookieName:o,config:t}=s._getSessionConfig(),c=typeof e.session=="object"&&"token"in e.session?String(e.session.token):JSON.stringify(e.session),i=l(o,c,t);await u(i)}catch(o){process.env.NODE_ENV==="development"&&console.warn("[Mulguard] Failed to save session cookie:",o)}return e}catch(e){return{success:!1,error:e instanceof Error?e.message:"Sign up failed",errorCode:r.UNKNOWN_ERROR}}}const _=Object.freeze(Object.defineProperty({__proto__:null,signInEmailAction:d,signOutAction:N,signUpAction:E,verify2FAAction:g},Symbol.toStringTag,{value:"Module"}));exports.AuthErrorCode=r;exports.actions=_;exports.buildCookieOptions=l;exports.deleteCookie=f;exports.getCookie=R;exports.setCookie=u;exports.signInEmailAction=d;exports.signOutAction=N;exports.signUpAction=E;exports.verify2FAAction=g;
@@ -0,0 +1,184 @@
1
+ import { cookies as u } from "next/headers";
2
+ var c = /* @__PURE__ */ ((s) => (s.INVALID_CREDENTIALS = "INVALID_CREDENTIALS", s.ACCOUNT_LOCKED = "ACCOUNT_LOCKED", s.ACCOUNT_INACTIVE = "ACCOUNT_INACTIVE", s.TWO_FA_REQUIRED = "TWO_FA_REQUIRED", s.INVALID_TWO_FA_CODE = "INVALID_TWO_FA_CODE", s.SESSION_EXPIRED = "SESSION_EXPIRED", s.UNAUTHORIZED = "UNAUTHORIZED", s.NETWORK_ERROR = "NETWORK_ERROR", s.VALIDATION_ERROR = "VALIDATION_ERROR", s.RATE_LIMITED = "RATE_LIMITED", s.UNKNOWN_ERROR = "UNKNOWN_ERROR", s))(c || {});
3
+ async function _(s) {
4
+ var o;
5
+ try {
6
+ return (o = (await u()).get(s)) == null ? void 0 : o.value;
7
+ } catch (e) {
8
+ const n = (e == null ? void 0 : e.message) || "";
9
+ if (n.includes("cookies") || n.includes("request scope") || n.includes("outside") || n.includes("dynamic"))
10
+ return;
11
+ throw e;
12
+ }
13
+ }
14
+ async function l(s) {
15
+ try {
16
+ return (await u()).set({
17
+ name: s.name,
18
+ value: s.value,
19
+ maxAge: s.maxAge,
20
+ expires: s.expires,
21
+ httpOnly: s.httpOnly ?? !0,
22
+ secure: s.secure,
23
+ sameSite: s.sameSite ?? "lax",
24
+ path: s.path ?? "/",
25
+ domain: s.domain
26
+ }), { success: !0 };
27
+ } catch (o) {
28
+ const e = (o == null ? void 0 : o.message) || "";
29
+ if (e.includes("cookies") || e.includes("request scope") || e.includes("outside") || e.includes("dynamic")) {
30
+ const n = `Cannot set cookie "${s.name}" outside request scope. Make sure this is called from a Server Action or Route Handler.`;
31
+ return process.env.NODE_ENV === "development" && console.warn(`[Mulguard] ${n}`), {
32
+ success: !1,
33
+ error: e,
34
+ warning: n
35
+ };
36
+ }
37
+ throw o;
38
+ }
39
+ }
40
+ async function O(s, o) {
41
+ try {
42
+ (await u()).set({
43
+ name: s,
44
+ value: "",
45
+ maxAge: 0,
46
+ expires: /* @__PURE__ */ new Date(0),
47
+ httpOnly: !0,
48
+ path: (o == null ? void 0 : o.path) ?? "/",
49
+ domain: o == null ? void 0 : o.domain
50
+ });
51
+ } catch (e) {
52
+ const n = (e == null ? void 0 : e.message) || "";
53
+ if (n.includes("cookies") || n.includes("request scope") || n.includes("outside") || n.includes("dynamic")) {
54
+ process.env.NODE_ENV === "development" && console.warn(`[Mulguard] Cannot delete cookie "${s}" outside request scope`);
55
+ return;
56
+ }
57
+ throw e;
58
+ }
59
+ }
60
+ function f(s, o, e) {
61
+ const n = process.env.NODE_ENV === "production";
62
+ return {
63
+ name: s,
64
+ value: o,
65
+ maxAge: e.expiresIn,
66
+ httpOnly: e.httpOnly ?? !0,
67
+ secure: e.secure ?? n,
68
+ sameSite: e.sameSite ?? "lax",
69
+ path: e.path ?? "/"
70
+ };
71
+ }
72
+ async function g(s, o) {
73
+ if (!s.verify2FA)
74
+ return {
75
+ success: !1,
76
+ error: "2FA verification is not configured",
77
+ errorCode: c.VALIDATION_ERROR
78
+ };
79
+ try {
80
+ const e = await s.verify2FA(o, { skipCookieSave: !0 });
81
+ if (e.success && e.session)
82
+ try {
83
+ const { cookieName: n, config: r } = s._getSessionConfig(), t = typeof e.session == "object" && "token" in e.session ? String(e.session.token) : JSON.stringify(e.session), i = f(n, t, r), a = await l(i);
84
+ a.success || process.env.NODE_ENV === "development" && console.warn("[Mulguard] Failed to save session after 2FA verification:", a.error || a.warning);
85
+ } catch (n) {
86
+ process.env.NODE_ENV === "development" && console.warn("[Mulguard] Failed to save session cookie:", n);
87
+ }
88
+ return e;
89
+ } catch (e) {
90
+ return {
91
+ success: !1,
92
+ error: e instanceof Error ? e.message : "2FA verification failed",
93
+ errorCode: c.UNKNOWN_ERROR
94
+ };
95
+ }
96
+ }
97
+ async function N(s) {
98
+ var o;
99
+ try {
100
+ const e = await s.getSession(), n = e == null ? void 0 : e.user;
101
+ s.signOut && await s.signOut();
102
+ const { cookieName: r, config: t } = s._getSessionConfig();
103
+ await O(r, {
104
+ path: t.path || "/"
105
+ });
106
+ const i = (o = s._getCallbacks) == null ? void 0 : o.call(s);
107
+ return n && (i != null && i.onSignOut) && await i.onSignOut(n), { success: !0 };
108
+ } catch (e) {
109
+ return {
110
+ success: !1,
111
+ error: e instanceof Error ? e.message : "Sign out failed"
112
+ };
113
+ }
114
+ }
115
+ async function d(s, o) {
116
+ var e;
117
+ if (!((e = s.signIn) != null && e.email))
118
+ return {
119
+ success: !1,
120
+ error: "Email sign in is not configured",
121
+ errorCode: c.VALIDATION_ERROR
122
+ };
123
+ try {
124
+ const n = await s.signIn.email(o);
125
+ if (n.success && n.session)
126
+ try {
127
+ const { cookieName: r, config: t } = s._getSessionConfig(), i = typeof n.session == "object" && "token" in n.session ? String(n.session.token) : JSON.stringify(n.session), a = f(r, i, t);
128
+ await l(a);
129
+ } catch (r) {
130
+ process.env.NODE_ENV === "development" && console.warn("[Mulguard] Failed to save session cookie:", r);
131
+ }
132
+ return n;
133
+ } catch (n) {
134
+ return {
135
+ success: !1,
136
+ error: n instanceof Error ? n.message : "Sign in failed",
137
+ errorCode: c.UNKNOWN_ERROR
138
+ };
139
+ }
140
+ }
141
+ async function E(s, o) {
142
+ if (!s.signUp)
143
+ return {
144
+ success: !1,
145
+ error: "Sign up is not configured",
146
+ errorCode: c.VALIDATION_ERROR
147
+ };
148
+ try {
149
+ const e = await s.signUp(o);
150
+ if (e.success && e.session)
151
+ try {
152
+ const { cookieName: n, config: r } = s._getSessionConfig(), t = typeof e.session == "object" && "token" in e.session ? String(e.session.token) : JSON.stringify(e.session), i = f(n, t, r);
153
+ await l(i);
154
+ } catch (n) {
155
+ process.env.NODE_ENV === "development" && console.warn("[Mulguard] Failed to save session cookie:", n);
156
+ }
157
+ return e;
158
+ } catch (e) {
159
+ return {
160
+ success: !1,
161
+ error: e instanceof Error ? e.message : "Sign up failed",
162
+ errorCode: c.UNKNOWN_ERROR
163
+ };
164
+ }
165
+ }
166
+ const m = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
167
+ __proto__: null,
168
+ signInEmailAction: d,
169
+ signOutAction: N,
170
+ signUpAction: E,
171
+ verify2FAAction: g
172
+ }, Symbol.toStringTag, { value: "Module" }));
173
+ export {
174
+ c as A,
175
+ d as a,
176
+ E as b,
177
+ l as c,
178
+ O as d,
179
+ f as e,
180
+ m as f,
181
+ _ as g,
182
+ N as s,
183
+ g as v
184
+ };
@@ -0,0 +1,122 @@
1
+ import { Session, AuthResult, EmailCredentials, RegisterData, RememberedUser, Verify2FAData } from '../core/types';
2
+ import { MulguardInstance } from '../mulguard';
3
+ export interface UseAuthReturn {
4
+ session: Session | null;
5
+ isLoading: boolean;
6
+ /**
7
+ * Unified sign in method - professional interface similar to auth.js
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * // OAuth providers
12
+ * await signIn('google')
13
+ * await signIn('github')
14
+ *
15
+ * // Credentials
16
+ * await signIn('credentials', { email: 'user@example.com', password: 'password' })
17
+ *
18
+ * // OTP
19
+ * await signIn('otp', { email: 'user@example.com', code: '123456' })
20
+ * ```
21
+ */
22
+ signIn(provider: 'google' | 'github' | 'apple' | 'facebook' | string): Promise<{
23
+ url: string;
24
+ state: string;
25
+ }>;
26
+ signIn(provider: 'credentials', credentials: EmailCredentials): Promise<AuthResult>;
27
+ signIn(provider: 'otp', options: {
28
+ email: string;
29
+ code?: string;
30
+ }): Promise<AuthResult>;
31
+ signIn(provider: 'passkey', options?: {
32
+ userId?: string;
33
+ }): Promise<AuthResult>;
34
+ /**
35
+ * Legacy sign in methods (for backward compatibility)
36
+ */
37
+ signInMethods: {
38
+ email(credentials: EmailCredentials): Promise<AuthResult>;
39
+ oauth(provider: string): Promise<{
40
+ url: string;
41
+ state: string;
42
+ }>;
43
+ passkey(options?: {
44
+ userId?: string;
45
+ }): Promise<AuthResult>;
46
+ otp(email: string, code?: string): Promise<AuthResult>;
47
+ };
48
+ signUp(data: RegisterData): Promise<AuthResult>;
49
+ signOut(): Promise<void>;
50
+ resetPassword(email: string): Promise<{
51
+ success: boolean;
52
+ error?: string;
53
+ }>;
54
+ verifyEmail(token: string): Promise<{
55
+ success: boolean;
56
+ error?: string;
57
+ }>;
58
+ verify2FA(data: Verify2FAData): Promise<AuthResult>;
59
+ }
60
+ export interface UseSessionReturn {
61
+ session: Session | null;
62
+ isLoading: boolean;
63
+ error: Error | null;
64
+ }
65
+ export interface UseAccountPickerReturn {
66
+ lastUsers: RememberedUser[];
67
+ isLoading: boolean;
68
+ rememberUser: (user: {
69
+ id: string;
70
+ email: string;
71
+ name: string;
72
+ avatar?: string;
73
+ }, provider?: 'email' | 'oauth' | 'passkey') => Promise<void>;
74
+ clearUser: (userId: string) => Promise<void>;
75
+ clearAll: () => Promise<void>;
76
+ refresh: () => Promise<void>;
77
+ }
78
+ /**
79
+ * Main authentication hook
80
+ *
81
+ * @example
82
+ * ```tsx
83
+ * import { useAuth } from 'mulguard/client'
84
+ * import { auth } from '@/auth'
85
+ *
86
+ * function LoginButton() {
87
+ * const { session, signIn, signOut } = useAuth(auth)
88
+ * // ...
89
+ * }
90
+ * ```
91
+ */
92
+ export declare function useAuth(auth: MulguardInstance): UseAuthReturn;
93
+ /**
94
+ * Session hook
95
+ *
96
+ * @example
97
+ * ```tsx
98
+ * import { useSession } from 'mulguard/client'
99
+ * import { auth } from '@/auth'
100
+ *
101
+ * function Profile() {
102
+ * const { session, isLoading } = useSession(auth)
103
+ * // ...
104
+ * }
105
+ * ```
106
+ */
107
+ export declare function useSession(auth: MulguardInstance): UseSessionReturn;
108
+ /**
109
+ * Account Picker hook
110
+ *
111
+ * @example
112
+ * ```tsx
113
+ * import { useAccountPicker } from 'mulguard/client'
114
+ * import { auth } from '@/auth'
115
+ *
116
+ * function AccountList() {
117
+ * const { lastUsers, clearUser } = useAccountPicker(auth)
118
+ * // ...
119
+ * }
120
+ * ```
121
+ */
122
+ export declare function useAccountPicker(auth: MulguardInstance): UseAccountPickerReturn;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Client-side hooks and utilities for Next.js
3
+ */
4
+ export * from './hooks';
5
+ export * from './provider';