@puzzle-ui/fullstack 0.5.0 → 0.5.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 +27 -520
- package/package.json +9 -4
package/README.md
CHANGED
|
@@ -1,559 +1,66 @@
|
|
|
1
1
|
# @puzzle-ui/fullstack
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[Documentation: https://puzzle-ui.com/docs/fullstack](https://puzzle-ui.com/docs/fullstack)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`@puzzle-ui/fullstack` connects Puzzle Auth to browser clients, React UI, server routes, and framework adapters. Use it when an application needs a ready-to-use browser auth client or Request/Response handlers; configure auth policy, storage, and sessions with the lower-level packages.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
## Installation
|
|
7
|
+
## Install
|
|
10
8
|
|
|
11
9
|
```bash
|
|
12
|
-
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Install React 19 and the appropriate framework peer dependencies in your application.
|
|
16
|
-
|
|
17
|
-
## Package architecture
|
|
18
|
-
|
|
19
|
-
```text
|
|
20
|
-
@puzzle-ui/fullstack
|
|
21
|
-
└── auth/
|
|
22
|
-
├── client/
|
|
23
|
-
│ ├── index.ts
|
|
24
|
-
│ ├── react.tsx
|
|
25
|
-
│ ├── messages.ts
|
|
26
|
-
│ ├── auth.css
|
|
27
|
-
│ └── passkeys.ts
|
|
28
|
-
├── server/
|
|
29
|
-
│ ├── index.ts
|
|
30
|
-
│ ├── mfa.ts
|
|
31
|
-
│ ├── lifecycle.ts
|
|
32
|
-
│ └── session.ts
|
|
33
|
-
├── shared/
|
|
34
|
-
│ └── index.ts
|
|
35
|
-
├── next/
|
|
36
|
-
│ └── index.ts
|
|
37
|
-
└── tanstack/
|
|
38
|
-
└── index.ts
|
|
10
|
+
npm install @puzzle-ui/fullstack react react-dom
|
|
39
11
|
```
|
|
40
12
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
| Import | Responsibility |
|
|
44
|
-
| ------------------------------------ | ----------------------------------------------------------- |
|
|
45
|
-
| `@puzzle-ui/fullstack/auth/client` | React provider, hooks, authentication UI and browser client |
|
|
46
|
-
| `@puzzle-ui/fullstack/auth/server` | Server handlers, sessions and authentication lifecycle |
|
|
47
|
-
| `@puzzle-ui/fullstack/auth/shared` | Serializable public contracts |
|
|
48
|
-
| `@puzzle-ui/fullstack/auth/next` | Next.js App Router adapter |
|
|
49
|
-
| `@puzzle-ui/fullstack/auth/tanstack` | TanStack Start adapter |
|
|
13
|
+
React and React DOM 19 are required peer dependencies. `next` (15 or 16) and `@tanstack/react-start` are optional peers for their respective adapters. On the server, configure the managers from `@puzzle-ui/auth` and `@puzzle-ui/session` with your storage backend. See the [Auth docs](https://puzzle-ui.com/docs/auth), [Storage docs](https://puzzle-ui.com/docs/storage), and [developer authentication guide](https://puzzle-ui.com/docs/developer/authentication).
|
|
50
14
|
|
|
51
15
|
## Client
|
|
52
16
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
Wrap the application in `AuthProvider`.
|
|
17
|
+
Wrap the application in `AuthProvider`, then use the hooks or exported forms below it:
|
|
56
18
|
|
|
57
19
|
```tsx
|
|
58
|
-
import { AuthProvider } from "@puzzle-ui/fullstack/auth/client";
|
|
20
|
+
import { AuthProvider, useAuth, useUser } from "@puzzle-ui/fullstack/auth/client";
|
|
59
21
|
|
|
60
22
|
export const Providers = ({ children }: { children: React.ReactNode }) => (
|
|
61
|
-
<AuthProvider
|
|
62
|
-
options={{
|
|
63
|
-
basePath: "/api/auth",
|
|
64
|
-
}}
|
|
65
|
-
locale="en"
|
|
66
|
-
>
|
|
67
|
-
{children}
|
|
68
|
-
</AuthProvider>
|
|
23
|
+
<AuthProvider options={{ basePath: "/api/auth" }}>{children}</AuthProvider>
|
|
69
24
|
);
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
The provider creates and shares one authentication client.
|
|
73
|
-
|
|
74
|
-
Authentication state is retrieved from the server. Session credentials are not stored in browser storage.
|
|
75
25
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
```tsx
|
|
79
|
-
import { useAuth, useSession, useUser } from "@puzzle-ui/fullstack/auth/client";
|
|
80
|
-
|
|
81
|
-
const Profile = () => {
|
|
26
|
+
export const Account = () => {
|
|
82
27
|
const user = useUser();
|
|
83
|
-
const
|
|
84
|
-
const auth = useAuth();
|
|
85
|
-
|
|
86
|
-
if (session.isLoading) return null;
|
|
87
|
-
|
|
88
|
-
if (!user) return null;
|
|
89
|
-
|
|
90
|
-
return (
|
|
91
|
-
<div>
|
|
92
|
-
<span>{user.email}</span>
|
|
93
|
-
<button onClick={() => void auth.signOut()}>Sign out</button>
|
|
94
|
-
</div>
|
|
95
|
-
);
|
|
96
|
-
};
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
### Authentication components
|
|
100
|
-
|
|
101
|
-
Available components:
|
|
102
|
-
|
|
103
|
-
- `SignInForm`
|
|
104
|
-
- `SignUpForm`
|
|
105
|
-
- `MfaChallengeForm`
|
|
106
|
-
- `RequiredMfaEnrollment`
|
|
107
|
-
- `PasswordResetRequestForm`
|
|
108
|
-
- `PasswordResetForm`
|
|
109
|
-
- `EmailVerificationForm`
|
|
110
|
-
- `EmailVerificationNotice`
|
|
111
|
-
- `ChangePasswordForm`
|
|
112
|
-
- `MfaSettings`
|
|
113
|
-
- `AuthScreen`
|
|
114
|
-
|
|
115
|
-
All components support className customization.
|
|
116
|
-
|
|
117
|
-
Redirects are opt-in through `redirectTo` and restricted to same-origin paths.
|
|
118
|
-
|
|
119
|
-
## Configurable authentication experience
|
|
120
|
-
|
|
121
|
-
`@puzzle-ui/fullstack` provides an optional `AuthExperience` component for building branded sign-in and sign-up pages without having to implement the standard authentication flow yourself.
|
|
122
|
-
|
|
123
|
-
The experience supports:
|
|
124
|
-
|
|
125
|
-
- Custom branding, including a logo, title, description and footer.
|
|
126
|
-
- Layout configuration, including content width and alignment.
|
|
127
|
-
- Configurable redirects after successful authentication.
|
|
128
|
-
- Custom registration fields with validation.
|
|
129
|
-
- Custom submit callbacks for integrating application-specific registration logic.
|
|
130
|
-
- Existing Puzzle authentication messages and form behavior.
|
|
131
|
-
|
|
132
|
-
### Basic usage
|
|
133
|
-
|
|
134
|
-
```tsx
|
|
135
|
-
import { AuthExperience } from "@puzzle-ui/fullstack/auth/client";
|
|
136
|
-
|
|
137
|
-
export const SignUpPage = () => (
|
|
138
|
-
<AuthExperience
|
|
139
|
-
mode="sign-up"
|
|
140
|
-
config={{
|
|
141
|
-
branding: {
|
|
142
|
-
title: "Create your account",
|
|
143
|
-
description: "Get started with your new account.",
|
|
144
|
-
},
|
|
145
|
-
layout: {
|
|
146
|
-
width: "md",
|
|
147
|
-
align: "center",
|
|
148
|
-
},
|
|
149
|
-
redirects: {
|
|
150
|
-
afterSignUp: "/dashboard",
|
|
151
|
-
},
|
|
152
|
-
fields: [
|
|
153
|
-
{
|
|
154
|
-
name: "company",
|
|
155
|
-
label: "Company",
|
|
156
|
-
type: "text",
|
|
157
|
-
required: true,
|
|
158
|
-
},
|
|
159
|
-
{
|
|
160
|
-
name: "role",
|
|
161
|
-
label: "Your role",
|
|
162
|
-
type: "select",
|
|
163
|
-
options: [
|
|
164
|
-
{ label: "Developer", value: "developer" },
|
|
165
|
-
{ label: "Designer", value: "designer" },
|
|
166
|
-
{ label: "Other", value: "other" },
|
|
167
|
-
],
|
|
168
|
-
},
|
|
169
|
-
],
|
|
170
|
-
}}
|
|
171
|
-
/>
|
|
172
|
-
);
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
### Custom registration handling
|
|
176
|
-
|
|
177
|
-
Custom fields are UI-only extensions. They are not automatically added to the authentication user model or persisted by the auth engine.
|
|
178
|
-
|
|
179
|
-
The experience uses Puzzle UI form fields, text inputs, text areas, checkboxes,
|
|
180
|
-
selects, buttons and typography. URL and number fields retain native inputs to
|
|
181
|
-
preserve their input types and string values, which `TextInput` does not support.
|
|
182
|
-
|
|
183
|
-
Use `onSubmit` to receive the standard registration input and custom field values. The callback can call `signUp` to execute the normal registration flow.
|
|
184
|
-
|
|
185
|
-
```tsx
|
|
186
|
-
import { AuthExperience } from "@puzzle-ui/fullstack/auth/client";
|
|
187
|
-
|
|
188
|
-
export const SignUpPage = () => (
|
|
189
|
-
<AuthExperience
|
|
190
|
-
mode="sign-up"
|
|
191
|
-
config={{
|
|
192
|
-
fields: [
|
|
193
|
-
{
|
|
194
|
-
name: "company",
|
|
195
|
-
label: "Company",
|
|
196
|
-
type: "text",
|
|
197
|
-
required: true,
|
|
198
|
-
},
|
|
199
|
-
],
|
|
200
|
-
}}
|
|
201
|
-
onSubmit={async ({ registration, fields, signUp }) => {
|
|
202
|
-
await signUp(registration);
|
|
203
|
-
|
|
204
|
-
// Handle application-specific values separately.
|
|
205
|
-
await saveCompanyInformation({
|
|
206
|
-
email: registration.email,
|
|
207
|
-
company: fields.company,
|
|
208
|
-
});
|
|
209
|
-
}}
|
|
210
|
-
/>
|
|
211
|
-
);
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
### Browser tests
|
|
215
|
-
|
|
216
|
-
Run the Fullstack authentication experience browser tests with:
|
|
217
|
-
|
|
218
|
-
```bash
|
|
219
|
-
bun run --filter @puzzle-ui/fullstack test:browser
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
### AuthScreen
|
|
223
|
-
|
|
224
|
-
```tsx
|
|
225
|
-
import { AuthScreen } from "@puzzle-ui/fullstack/auth/client";
|
|
226
|
-
|
|
227
|
-
export default function LoginPage() {
|
|
228
|
-
return <AuthScreen mode="sign-in" redirectTo="/dashboard" />;
|
|
229
|
-
}
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
### Registration
|
|
233
|
-
|
|
234
|
-
```tsx
|
|
235
|
-
import { AuthScreen } from "@puzzle-ui/fullstack/auth/client";
|
|
236
|
-
|
|
237
|
-
export default function RegisterPage() {
|
|
238
|
-
return <AuthScreen mode="sign-up" />;
|
|
239
|
-
}
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
### MFA management
|
|
243
|
-
|
|
244
|
-
```tsx
|
|
245
|
-
import { MfaSettings } from "@puzzle-ui/fullstack/auth/client";
|
|
246
|
-
|
|
247
|
-
export default function SecurityPage() {
|
|
248
|
-
return <MfaSettings />;
|
|
249
|
-
}
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
### Localization
|
|
253
|
-
|
|
254
|
-
Puzzle Fullstack includes English messages as its default locale and fallback.
|
|
255
|
-
|
|
256
|
-
Applications can define their own locale identifiers by extending the `AuthLocale` type. Every custom locale must provide a complete `AuthMessages` object. English messages are optional because the built-in English messages are used whenever no application-provided English messages are available.
|
|
257
|
-
|
|
258
|
-
For example, an application can add Dutch and German:
|
|
259
|
-
|
|
260
|
-
```tsx
|
|
261
|
-
import { AuthProvider } from "@puzzle-ui/fullstack/auth/client";
|
|
262
|
-
|
|
263
|
-
import {
|
|
264
|
-
getAuthLocale,
|
|
265
|
-
resolveAuthMessages,
|
|
266
|
-
type AuthLocale,
|
|
267
|
-
type AuthLocaleMessages,
|
|
268
|
-
} from "@puzzle-ui/fullstack/auth/client";
|
|
269
|
-
|
|
270
|
-
type AppLocale = AuthLocale<"nl" | "de">;
|
|
271
|
-
|
|
272
|
-
const appMessages: AuthLocaleMessages<"nl" | "de"> = {
|
|
273
|
-
nl: {
|
|
274
|
-
// Supply every AuthMessages field in Dutch.
|
|
275
|
-
// For example:
|
|
276
|
-
signIn: "Inloggen",
|
|
277
|
-
signUp: "Account aanmaken",
|
|
278
|
-
email: "E-mailadres",
|
|
279
|
-
password: "Wachtwoord",
|
|
280
|
-
name: "Naam",
|
|
281
|
-
confirmPassword: "Bevestig wachtwoord",
|
|
282
|
-
submit: "Doorgaan",
|
|
283
|
-
signingIn: "Inloggen...",
|
|
284
|
-
signingUp: "Account aanmaken...",
|
|
285
|
-
forgotPassword: "Wachtwoord vergeten?",
|
|
286
|
-
createAccount: "Account aanmaken",
|
|
287
|
-
existingAccount: "Heb je al een account?",
|
|
288
|
-
noAccount: "Nog geen account?",
|
|
289
|
-
mfaTitle: "Verifieer je identiteit",
|
|
290
|
-
mfaDescription: "Voer je authenticatiecode in om door te gaan.",
|
|
291
|
-
verificationCode: "Authenticatiecode",
|
|
292
|
-
recoveryCode: "Herstelcode",
|
|
293
|
-
verify: "Verifiëren",
|
|
294
|
-
verifying: "Verifiëren...",
|
|
295
|
-
useRecoveryCode: "Gebruik een herstelcode",
|
|
296
|
-
useAuthenticator: "Gebruik authenticator-app",
|
|
297
|
-
usePasskey: "Doorgaan met passkey",
|
|
298
|
-
passkeyUnavailable: "Passkeys zijn niet beschikbaar in deze browser.",
|
|
299
|
-
loading: "Laden...",
|
|
300
|
-
signOut: "Uitloggen",
|
|
301
|
-
unexpectedError: "Er is iets misgegaan. Probeer het opnieuw.",
|
|
302
|
-
invalidCredentials: "Het e-mailadres of wachtwoord is onjuist.",
|
|
303
|
-
passwordMismatch: "De wachtwoorden komen niet overeen.",
|
|
304
|
-
passwordRequired: "Een wachtwoord is verplicht.",
|
|
305
|
-
requestPasswordReset: "Wachtwoord herstellen aanvragen",
|
|
306
|
-
resetPassword: "Wachtwoord herstellen",
|
|
307
|
-
newPassword: "Nieuw wachtwoord",
|
|
308
|
-
sendResetLink: "Verstuur herstellink",
|
|
309
|
-
passwordResetSent: "De herstellink is verstuurd",
|
|
310
|
-
verificationSent: "Verificatiemail is verstuurd",
|
|
311
|
-
verifyEmail: "E-mailadres verifiëren",
|
|
312
|
-
changePassword: "Wachtwoord wijzigen",
|
|
313
|
-
passwordChanged: "Wachtwoord gewijzigd",
|
|
314
|
-
emailRequired: "Een e-mailadres is verplicht.",
|
|
315
|
-
nameRequired: "Een naam is verplicht.",
|
|
316
|
-
authenticated: "Je bent ingelogd.",
|
|
317
|
-
mfaSettings: "Beveiligingsinstellingen",
|
|
318
|
-
addTotp: "Authenticator toevoegen",
|
|
319
|
-
addPasskey: "Passkey toevoegen",
|
|
320
|
-
removeFactor: "Verwijderen",
|
|
321
|
-
recoveryCodes: "Herstelcodes",
|
|
322
|
-
saveRecoveryCodes: "Bewaar deze codes op een veilige plek.",
|
|
323
|
-
currentPassword: "Huidig wachtwoord",
|
|
324
|
-
totpSecret: "Authenticator-geheim",
|
|
325
|
-
verifyTotp: "Authenticator verifiëren",
|
|
326
|
-
cancel: "Annuleren",
|
|
327
|
-
},
|
|
328
|
-
// Optionally (partially)override messages for English:
|
|
329
|
-
en: {
|
|
330
|
-
signUp: "Create your account",
|
|
331
|
-
}
|
|
332
|
-
de: {
|
|
333
|
-
// Supply every AuthMessages field in German.
|
|
334
|
-
// The same complete set of fields as the Dutch example is required.
|
|
335
|
-
},
|
|
336
|
-
};
|
|
337
|
-
|
|
338
|
-
// The locale type can be used throughout the application.
|
|
339
|
-
const requestedLocale: string = "nl";
|
|
340
|
-
|
|
341
|
-
const locale: AppLocale = getAuthLocale(requestedLocale, appMessages);
|
|
342
|
-
|
|
343
|
-
// Resolve the complete message set before passing it to the provider.
|
|
344
|
-
// Built-in English messages are used for any missing English fallback.
|
|
345
|
-
const messages = resolveAuthMessages(locale, appMessages);
|
|
346
|
-
|
|
347
|
-
export const Providers = ({ children }: { children: React.ReactNode }) => (
|
|
348
|
-
<AuthProvider
|
|
349
|
-
locale={locale}
|
|
350
|
-
messages={messages}
|
|
351
|
-
options={{
|
|
352
|
-
basePath: "/api/auth",
|
|
353
|
-
}}
|
|
354
|
-
>
|
|
355
|
-
{children}
|
|
356
|
-
</AuthProvider>
|
|
357
|
-
);
|
|
358
|
-
```
|
|
359
|
-
|
|
360
|
-
The `AuthLocale` type accepts custom locale identifiers:
|
|
361
|
-
|
|
362
|
-
```ts
|
|
363
|
-
type AppLocale = AuthLocale<"nl" | "de" | "es">;
|
|
364
|
-
```
|
|
28
|
+
const { signOut } = useAuth();
|
|
365
29
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
```ts
|
|
369
|
-
const messages: AuthLocaleMessages<"nl" | "de"> = {
|
|
370
|
-
nl: dutchMessages,
|
|
371
|
-
de: germanMessages,
|
|
372
|
-
|
|
373
|
-
// Optional: English overrides.
|
|
374
|
-
// Without this property, Puzzle's built-in English messages are used.
|
|
375
|
-
// en: englishMessages,
|
|
30
|
+
return user ? <button onClick={() => void signOut()}>{user.email} · Sign out</button> : null;
|
|
376
31
|
};
|
|
377
32
|
```
|
|
378
33
|
|
|
379
|
-
The
|
|
380
|
-
|
|
381
|
-
```ts
|
|
382
|
-
const locale = getAuthLocale("nl-NL", messages);
|
|
383
|
-
// "en", because "nl-NL" is not a configured locale.
|
|
384
|
-
|
|
385
|
-
const dutchLocale = getAuthLocale("nl", messages);
|
|
386
|
-
// "nl"
|
|
387
|
-
|
|
388
|
-
const fallbackLocale = getAuthLocale("fr", messages);
|
|
389
|
-
// "en"
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
Locale identifiers are exact matches. If an application wants to support regional identifiers such as `nl-NL` or `en-GB`, it should declare and provide those locales explicitly.
|
|
393
|
-
|
|
394
|
-
Messages are resolved in this order:
|
|
34
|
+
The client provides auth state and actions, sign-in/sign-up and MFA components, `AuthExperience` for branded registration flows, locale helpers, and passkey browser helpers. Browser state is not an authorization boundary; protect server resources independently.
|
|
395
35
|
|
|
396
|
-
|
|
397
|
-
2. Optional application-provided English messages.
|
|
398
|
-
3. Messages for the selected custom locale.
|
|
399
|
-
4. Optional per-message overrides.
|
|
36
|
+
## Server and framework adapters
|
|
400
37
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
## Server
|
|
404
|
-
|
|
405
|
-
### Creating the server
|
|
38
|
+
Create one server instance from configured auth and session managers, then register its routes:
|
|
406
39
|
|
|
407
40
|
```ts
|
|
408
|
-
import { createAuthServer } from "@puzzle-ui/fullstack/auth/server";
|
|
409
|
-
|
|
410
|
-
import {
|
|
411
|
-
authManager,
|
|
412
|
-
mfaManager,
|
|
413
|
-
stepUpManager,
|
|
414
|
-
sessions,
|
|
415
|
-
cookie,
|
|
416
|
-
csrf,
|
|
417
|
-
} from "./auth-managers";
|
|
41
|
+
import { createAuthServer, createAuthRouteHandlers } from "@puzzle-ui/fullstack/auth/server";
|
|
418
42
|
|
|
419
43
|
export const authServer = createAuthServer({
|
|
420
|
-
auth
|
|
421
|
-
mfa
|
|
422
|
-
stepUp
|
|
44
|
+
auth,
|
|
45
|
+
mfa,
|
|
46
|
+
stepUp,
|
|
423
47
|
sessions,
|
|
424
48
|
cookie,
|
|
425
49
|
csrf,
|
|
426
50
|
resolveClientIp,
|
|
427
51
|
});
|
|
428
|
-
```
|
|
429
|
-
|
|
430
|
-
The supplied managers and providers must be initialized using their respective package contracts.
|
|
431
|
-
|
|
432
|
-
### Route handlers
|
|
433
|
-
|
|
434
|
-
`createAuthRouteHandlers` returns a map of paths and HTTP methods to Web Request handlers.
|
|
435
|
-
|
|
436
|
-
The default base path is `/api/auth`.
|
|
437
|
-
|
|
438
|
-
A custom base path can be configured.
|
|
439
|
-
|
|
440
|
-
### Lifecycle integration
|
|
441
|
-
|
|
442
|
-
The optional lifecycle integration provides:
|
|
443
52
|
|
|
444
|
-
|
|
445
|
-
- Email verification.
|
|
446
|
-
- Password reset requests.
|
|
447
|
-
- Password reset completion.
|
|
448
|
-
- Authenticated password changes.
|
|
449
|
-
|
|
450
|
-
Password reset requests use a generic public response to prevent account enumeration.
|
|
451
|
-
|
|
452
|
-
### Session security
|
|
453
|
-
|
|
454
|
-
- Session tokens remain in HttpOnly cookies.
|
|
455
|
-
- State-changing requests require CSRF protection.
|
|
456
|
-
- Authentication responses use no-store caching.
|
|
457
|
-
- Password changes invalidate existing sessions.
|
|
458
|
-
- MFA challenge tokens remain server-managed.
|
|
459
|
-
- Client-facing responses contain only public user data.
|
|
460
|
-
|
|
461
|
-
## Next.js App Router
|
|
462
|
-
|
|
463
|
-
```ts
|
|
464
|
-
// app/api/auth/[...auth]/route.ts
|
|
465
|
-
|
|
466
|
-
import { auth } from "@/lib/auth";
|
|
467
|
-
|
|
468
|
-
import { createNextAuthHandler } from "@puzzle-ui/fullstack/auth/next";
|
|
469
|
-
|
|
470
|
-
const handlers = createNextAuthHandler({
|
|
471
|
-
auth,
|
|
472
|
-
});
|
|
473
|
-
|
|
474
|
-
export const GET = handlers.GET;
|
|
475
|
-
export const POST = handlers.POST;
|
|
476
|
-
```
|
|
477
|
-
|
|
478
|
-
## TanStack Start
|
|
479
|
-
|
|
480
|
-
```ts
|
|
481
|
-
import { createTanStackAuthHandler } from "@puzzle-ui/fullstack/auth/tanstack";
|
|
482
|
-
|
|
483
|
-
import { auth } from "./auth";
|
|
484
|
-
|
|
485
|
-
export const authHandler = createTanStackAuthHandler({
|
|
486
|
-
auth,
|
|
487
|
-
});
|
|
488
|
-
```
|
|
489
|
-
|
|
490
|
-
Register the handler using the application's TanStack server route configuration.
|
|
491
|
-
|
|
492
|
-
## Runtime support
|
|
493
|
-
|
|
494
|
-
The package uses Web APIs for HTTP request and response handling.
|
|
495
|
-
|
|
496
|
-
Supported targets:
|
|
497
|
-
|
|
498
|
-
- Node.js
|
|
499
|
-
- Cloudflare Workers
|
|
500
|
-
- Bun development environments
|
|
501
|
-
- Browser authentication interfaces
|
|
502
|
-
|
|
503
|
-
Persistent sessions, tokens and authentication records must use durable storage.
|
|
504
|
-
|
|
505
|
-
## Build
|
|
506
|
-
|
|
507
|
-
```bash
|
|
508
|
-
bun run --filter @puzzle-ui/fullstack build
|
|
53
|
+
export const authRoutes = createAuthRouteHandlers(authServer);
|
|
509
54
|
```
|
|
510
55
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
```bash
|
|
514
|
-
bun run --filter @puzzle-ui/fullstack typecheck
|
|
515
|
-
```
|
|
516
|
-
|
|
517
|
-
## Tests
|
|
518
|
-
|
|
519
|
-
Tests run against the built package with Node's test runner. The test setup
|
|
520
|
-
ignores CSS imports so client components can be rendered without a browser.
|
|
521
|
-
|
|
522
|
-
```bash
|
|
523
|
-
bun run --filter @puzzle-ui/fullstack build
|
|
524
|
-
bun run --filter @puzzle-ui/fullstack test
|
|
525
|
-
```
|
|
526
|
-
|
|
527
|
-
The required TOTP and passkey enrollment end-to-end tests live in this package
|
|
528
|
-
because they exercise the HTTP handlers together with the auth managers:
|
|
529
|
-
|
|
530
|
-
```bash
|
|
531
|
-
node --test packages/fullstack/tests/auth-mfa.e2e.test.mjs
|
|
532
|
-
```
|
|
533
|
-
|
|
534
|
-
## Security boundaries
|
|
535
|
-
|
|
536
|
-
The package maintains separate public entry points for:
|
|
537
|
-
|
|
538
|
-
- Client functionality.
|
|
539
|
-
- Server functionality.
|
|
540
|
-
- Shared contracts.
|
|
541
|
-
- Framework integrations.
|
|
542
|
-
|
|
543
|
-
Client code must never import server implementations, database adapters, secrets or password hashing implementations.
|
|
544
|
-
|
|
545
|
-
Server functionality must never be re-exported from browser-facing entry points.
|
|
546
|
-
|
|
547
|
-
Framework adapters must delegate security policies and authentication operations to the underlying authentication packages.
|
|
548
|
-
|
|
549
|
-
## Scope
|
|
56
|
+
Use `@puzzle-ui/fullstack/auth/next` for Next.js `GET`/`POST` route handlers or `@puzzle-ui/fullstack/auth/tanstack` to create a TanStack Start Request dispatcher. Configure cookies, CSRF, storage and trusted proxy IP resolution in the server layer. Do not expose server managers to browser bundles.
|
|
550
57
|
|
|
551
|
-
|
|
58
|
+
## Entry points
|
|
552
59
|
|
|
553
|
-
|
|
60
|
+
- `@puzzle-ui/fullstack/auth/client` — browser client, React provider/hooks/components, auth experience, localization, and passkey helpers.
|
|
61
|
+
- `@puzzle-ui/fullstack/auth/server` — server handlers, route map, session and step-up helpers, lifecycle handlers, readiness checks.
|
|
62
|
+
- `@puzzle-ui/fullstack/auth/shared` — serializable public auth contracts (types only).
|
|
63
|
+
- `@puzzle-ui/fullstack/auth/next` — Next.js route-handler adapter.
|
|
64
|
+
- `@puzzle-ui/fullstack/auth/tanstack` — TanStack Start adapter.
|
|
554
65
|
|
|
555
|
-
|
|
556
|
-
- Framework-independent domain logic.
|
|
557
|
-
- Serializable shared contracts.
|
|
558
|
-
- Thin framework adapters.
|
|
559
|
-
- Explicit public exports.
|
|
66
|
+
There is no root package export; import a documented subpath. See the [full documentation](https://puzzle-ui.com/docs/fullstack) for API details and production guidance.
|
package/package.json
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@puzzle-ui/fullstack",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "First-party Puzzle Auth client, server and framework integration entry points.",
|
|
5
|
+
"homepage": "https://puzzle-ui.com",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/senorprogramador/puzzle.git"
|
|
9
|
+
},
|
|
5
10
|
"license": "MIT",
|
|
6
11
|
"publishConfig": {
|
|
7
12
|
"access": "public",
|
|
@@ -88,9 +93,9 @@
|
|
|
88
93
|
"vitest": "latest"
|
|
89
94
|
},
|
|
90
95
|
"dependencies": {
|
|
91
|
-
"@puzzle-ui/ui": "^0.5.
|
|
92
|
-
"@puzzle-ui/auth": "^0.5.
|
|
93
|
-
"@puzzle-ui/session": "^0.5.
|
|
96
|
+
"@puzzle-ui/ui": "^0.5.1",
|
|
97
|
+
"@puzzle-ui/auth": "^0.5.1",
|
|
98
|
+
"@puzzle-ui/session": "^0.5.1",
|
|
94
99
|
"@simplewebauthn/browser": "^14.0.0"
|
|
95
100
|
},
|
|
96
101
|
"peerDependencies": {
|