create-nuxt-base 1.1.2 → 2.0.0
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/.github/workflows/publish.yml +1 -1
- package/AUTH.md +16 -14
- package/CHANGELOG.md +46 -11
- package/README.md +5 -5
- package/nuxt-base-template/README.md +11 -11
- package/nuxt-base-template/app/components/Modal/ModalBackupCodes.vue +2 -1
- package/nuxt-base-template/app/components/Upload/TusFileUpload.vue +7 -7
- package/nuxt-base-template/app/interfaces/user.interface.ts +5 -12
- package/nuxt-base-template/app/layouts/default.vue +1 -1
- package/nuxt-base-template/app/middleware/admin.global.ts +27 -7
- package/nuxt-base-template/app/middleware/auth.global.ts +23 -6
- package/nuxt-base-template/app/middleware/guest.global.ts +22 -7
- package/nuxt-base-template/app/pages/app/index.vue +4 -18
- package/nuxt-base-template/app/pages/app/settings/security.vue +2 -2
- package/nuxt-base-template/app/pages/auth/2fa.vue +39 -8
- package/nuxt-base-template/app/pages/auth/forgot-password.vue +2 -1
- package/nuxt-base-template/app/pages/auth/login.vue +14 -21
- package/nuxt-base-template/app/pages/auth/register.vue +5 -8
- package/nuxt-base-template/app/pages/auth/reset-password.vue +2 -1
- package/nuxt-base-template/docs/pages/docs.vue +1 -1
- package/nuxt-base-template/nuxt.config.ts +38 -1
- package/nuxt-base-template/package-lock.json +136 -2905
- package/nuxt-base-template/package.json +1 -0
- package/nuxt-base-template/server/api/iam/[...path].ts +12 -4
- package/package.json +2 -2
- package/nuxt-base-template/app/components/Transition/TransitionFade.vue +0 -27
- package/nuxt-base-template/app/components/Transition/TransitionFadeScale.vue +0 -27
- package/nuxt-base-template/app/components/Transition/TransitionSlide.vue +0 -12
- package/nuxt-base-template/app/components/Transition/TransitionSlideBottom.vue +0 -12
- package/nuxt-base-template/app/components/Transition/TransitionSlideRevert.vue +0 -12
- package/nuxt-base-template/app/composables/use-better-auth.ts +0 -415
- package/nuxt-base-template/app/composables/use-file.ts +0 -71
- package/nuxt-base-template/app/composables/use-share.ts +0 -38
- package/nuxt-base-template/app/composables/use-tus-upload.ts +0 -278
- package/nuxt-base-template/app/composables/use-tw.ts +0 -1
- package/nuxt-base-template/app/interfaces/upload.interface.ts +0 -58
- package/nuxt-base-template/app/lib/auth-client.ts +0 -232
- package/nuxt-base-template/app/plugins/auth-interceptor.client.ts +0 -143
- package/nuxt-base-template/app/utils/crypto.ts +0 -44
|
@@ -7,13 +7,11 @@ import type { InferOutput } from 'valibot';
|
|
|
7
7
|
|
|
8
8
|
import * as v from 'valibot';
|
|
9
9
|
|
|
10
|
-
import { authClient } from '~/lib/auth-client';
|
|
11
|
-
|
|
12
10
|
// ============================================================================
|
|
13
11
|
// Composables
|
|
14
12
|
// ============================================================================
|
|
15
13
|
const toast = useToast();
|
|
16
|
-
const { signIn, setUser, isLoading, validateSession } =
|
|
14
|
+
const { signIn, setUser, isLoading, validateSession, authenticateWithPasskey } = useLtAuth();
|
|
17
15
|
|
|
18
16
|
// ============================================================================
|
|
19
17
|
// Page Meta
|
|
@@ -54,32 +52,30 @@ type Schema = InferOutput<typeof schema>;
|
|
|
54
52
|
|
|
55
53
|
/**
|
|
56
54
|
* Handle passkey authentication
|
|
57
|
-
* Uses
|
|
58
|
-
* @see https://www.better-auth.com/docs/plugins/passkey
|
|
55
|
+
* Uses authenticateWithPasskey from composable which supports JWT mode (challengeId)
|
|
59
56
|
*/
|
|
60
57
|
async function onPasskeyLogin(): Promise<void> {
|
|
61
58
|
passkeyLoading.value = true;
|
|
62
59
|
|
|
63
60
|
try {
|
|
64
|
-
// Use
|
|
65
|
-
|
|
66
|
-
const result = await authClient.signIn.passkey();
|
|
61
|
+
// Use composable method which handles challengeId for JWT mode
|
|
62
|
+
const result = await authenticateWithPasskey();
|
|
67
63
|
|
|
68
|
-
// Check for error in response
|
|
69
|
-
if (result.
|
|
64
|
+
// Check for error in response (authenticateWithPasskey returns { success, error?, user? })
|
|
65
|
+
if (!result.success) {
|
|
70
66
|
toast.add({
|
|
71
67
|
color: 'error',
|
|
72
|
-
description: result.error
|
|
68
|
+
description: result.error || 'Passkey-Anmeldung fehlgeschlagen',
|
|
73
69
|
title: 'Fehler',
|
|
74
70
|
});
|
|
75
71
|
return;
|
|
76
72
|
}
|
|
77
73
|
|
|
78
74
|
// Update auth state with user data if available
|
|
79
|
-
if (result.
|
|
80
|
-
setUser(result.
|
|
81
|
-
} else
|
|
82
|
-
// Passkey auth
|
|
75
|
+
if (result.user) {
|
|
76
|
+
setUser(result.user as any);
|
|
77
|
+
} else {
|
|
78
|
+
// Passkey auth may return success without user - fetch user via session validation
|
|
83
79
|
await validateSession();
|
|
84
80
|
}
|
|
85
81
|
|
|
@@ -129,10 +125,7 @@ async function onSubmit(payload: FormSubmitEvent<Schema>): Promise<void> {
|
|
|
129
125
|
// Check if 2FA is required
|
|
130
126
|
// Better-Auth native uses 'twoFactorRedirect', nest-server REST API uses 'requiresTwoFactor'
|
|
131
127
|
const resultData = 'data' in result ? result.data : result;
|
|
132
|
-
const requires2FA = resultData && (
|
|
133
|
-
('twoFactorRedirect' in resultData && resultData.twoFactorRedirect) ||
|
|
134
|
-
('requiresTwoFactor' in resultData && resultData.requiresTwoFactor)
|
|
135
|
-
);
|
|
128
|
+
const requires2FA = resultData && (('twoFactorRedirect' in resultData && resultData.twoFactorRedirect) || ('requiresTwoFactor' in resultData && resultData.requiresTwoFactor));
|
|
136
129
|
if (requires2FA) {
|
|
137
130
|
// Redirect to 2FA page
|
|
138
131
|
await navigateTo('/auth/2fa');
|
|
@@ -140,9 +133,9 @@ async function onSubmit(payload: FormSubmitEvent<Schema>): Promise<void> {
|
|
|
140
133
|
}
|
|
141
134
|
|
|
142
135
|
// Check if login was successful (user data in response)
|
|
143
|
-
const userData = 'user' in result ? result.user :
|
|
136
|
+
const userData = 'user' in result ? result.user : 'data' in result ? result.data?.user : null;
|
|
144
137
|
if (userData) {
|
|
145
|
-
// Auth state is already stored by
|
|
138
|
+
// Auth state is already stored by useLtAuth
|
|
146
139
|
// Navigate to app
|
|
147
140
|
await navigateTo('/app');
|
|
148
141
|
} else {
|
|
@@ -7,13 +7,11 @@ import type { InferOutput } from 'valibot';
|
|
|
7
7
|
|
|
8
8
|
import * as v from 'valibot';
|
|
9
9
|
|
|
10
|
-
import { authClient } from '~/lib/auth-client';
|
|
11
|
-
|
|
12
10
|
// ============================================================================
|
|
13
11
|
// Composables
|
|
14
12
|
// ============================================================================
|
|
15
13
|
const toast = useToast();
|
|
16
|
-
const { signUp, signIn } =
|
|
14
|
+
const { signUp, signIn, registerPasskey } = useLtAuth();
|
|
17
15
|
|
|
18
16
|
// ============================================================================
|
|
19
17
|
// Page Meta
|
|
@@ -136,14 +134,13 @@ async function addPasskey(): Promise<void> {
|
|
|
136
134
|
passkeyLoading.value = true;
|
|
137
135
|
|
|
138
136
|
try {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
});
|
|
137
|
+
// Use registerPasskey from composable which properly handles challengeId
|
|
138
|
+
const result = await registerPasskey('Mein Gerät');
|
|
142
139
|
|
|
143
|
-
if (
|
|
140
|
+
if (!result.success) {
|
|
144
141
|
toast.add({
|
|
145
142
|
color: 'error',
|
|
146
|
-
description: error
|
|
143
|
+
description: result.error || 'Passkey konnte nicht hinzugefügt werden',
|
|
147
144
|
title: 'Fehler',
|
|
148
145
|
});
|
|
149
146
|
// Still navigate to app even if passkey failed
|
|
@@ -7,7 +7,8 @@ import type { InferOutput } from 'valibot';
|
|
|
7
7
|
|
|
8
8
|
import * as v from 'valibot';
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
// Auth client from @lenne.tech/nuxt-extensions (auto-imported as ltAuthClient)
|
|
11
|
+
const authClient = ltAuthClient;
|
|
11
12
|
|
|
12
13
|
// ============================================================================
|
|
13
14
|
// Composables
|
|
@@ -182,7 +182,7 @@ async function handleFormSubmit(): Promise<void> {
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
async function handleShare(): Promise<void> {
|
|
185
|
-
const { share } =
|
|
185
|
+
const { share } = useLtShare();
|
|
186
186
|
await share('Nuxt Base Starter', 'Check out this Nuxt Base Starter Template!', window.location.href);
|
|
187
187
|
|
|
188
188
|
toast.add({
|
|
@@ -67,12 +67,36 @@ export default defineNuxtConfig({
|
|
|
67
67
|
dirs: ['./states', './stores', './forms', './interfaces', './base', './plugins'],
|
|
68
68
|
},
|
|
69
69
|
|
|
70
|
+
// ============================================================================
|
|
71
|
+
// lenne.tech Nuxt Extensions
|
|
72
|
+
// ============================================================================
|
|
73
|
+
ltExtensions: {
|
|
74
|
+
auth: {
|
|
75
|
+
enabled: true,
|
|
76
|
+
basePath: '/iam',
|
|
77
|
+
loginPath: '/auth/login',
|
|
78
|
+
twoFactorRedirectPath: '/auth/2fa',
|
|
79
|
+
enableAdmin: true,
|
|
80
|
+
enableTwoFactor: true,
|
|
81
|
+
enablePasskey: true,
|
|
82
|
+
interceptor: {
|
|
83
|
+
enabled: true,
|
|
84
|
+
publicPaths: ['/auth/login', '/auth/register', '/auth/forgot-password', '/auth/reset-password'],
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
tus: {
|
|
88
|
+
defaultEndpoint: '/files/upload',
|
|
89
|
+
defaultChunkSize: 5 * 1024 * 1024,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
|
|
70
93
|
// ============================================================================
|
|
71
94
|
// Nuxt Modules
|
|
72
95
|
// ============================================================================
|
|
73
96
|
modules: [
|
|
97
|
+
'@lenne.tech/nuxt-extensions', // Auth, Upload, Transitions
|
|
74
98
|
'@nuxt/test-utils/module', // E2E testing with Playwright
|
|
75
|
-
'@lenne.tech/bug.lt', // Bug reporting to Linear
|
|
99
|
+
// '@lenne.tech/bug.lt', // Bug reporting to Linear - TEMPORARILY DISABLED FOR TESTING
|
|
76
100
|
'@vueuse/nuxt', // Vue composition utilities
|
|
77
101
|
'dayjs-nuxt', // Date/time handling
|
|
78
102
|
'@nuxt/image', // Image optimization
|
|
@@ -158,5 +182,18 @@ export default defineNuxtConfig({
|
|
|
158
182
|
exclude: ['@tailwindcss/vite', 'lightningcss', '@vue/devtools-core', '@vue/devtools-kit', '@internationalized/date'],
|
|
159
183
|
},
|
|
160
184
|
plugins: [tailwindcss()],
|
|
185
|
+
server: {
|
|
186
|
+
proxy: {
|
|
187
|
+
'/api': {
|
|
188
|
+
target: 'http://localhost:3000',
|
|
189
|
+
changeOrigin: true,
|
|
190
|
+
rewrite: (path: string) => path.replace(/^\/api/, ''),
|
|
191
|
+
},
|
|
192
|
+
'/iam': {
|
|
193
|
+
target: 'http://localhost:3000',
|
|
194
|
+
changeOrigin: true,
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
},
|
|
161
198
|
},
|
|
162
199
|
});
|