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.
Files changed (39) hide show
  1. package/.github/workflows/publish.yml +1 -1
  2. package/AUTH.md +16 -14
  3. package/CHANGELOG.md +46 -11
  4. package/README.md +5 -5
  5. package/nuxt-base-template/README.md +11 -11
  6. package/nuxt-base-template/app/components/Modal/ModalBackupCodes.vue +2 -1
  7. package/nuxt-base-template/app/components/Upload/TusFileUpload.vue +7 -7
  8. package/nuxt-base-template/app/interfaces/user.interface.ts +5 -12
  9. package/nuxt-base-template/app/layouts/default.vue +1 -1
  10. package/nuxt-base-template/app/middleware/admin.global.ts +27 -7
  11. package/nuxt-base-template/app/middleware/auth.global.ts +23 -6
  12. package/nuxt-base-template/app/middleware/guest.global.ts +22 -7
  13. package/nuxt-base-template/app/pages/app/index.vue +4 -18
  14. package/nuxt-base-template/app/pages/app/settings/security.vue +2 -2
  15. package/nuxt-base-template/app/pages/auth/2fa.vue +39 -8
  16. package/nuxt-base-template/app/pages/auth/forgot-password.vue +2 -1
  17. package/nuxt-base-template/app/pages/auth/login.vue +14 -21
  18. package/nuxt-base-template/app/pages/auth/register.vue +5 -8
  19. package/nuxt-base-template/app/pages/auth/reset-password.vue +2 -1
  20. package/nuxt-base-template/docs/pages/docs.vue +1 -1
  21. package/nuxt-base-template/nuxt.config.ts +38 -1
  22. package/nuxt-base-template/package-lock.json +136 -2905
  23. package/nuxt-base-template/package.json +1 -0
  24. package/nuxt-base-template/server/api/iam/[...path].ts +12 -4
  25. package/package.json +2 -2
  26. package/nuxt-base-template/app/components/Transition/TransitionFade.vue +0 -27
  27. package/nuxt-base-template/app/components/Transition/TransitionFadeScale.vue +0 -27
  28. package/nuxt-base-template/app/components/Transition/TransitionSlide.vue +0 -12
  29. package/nuxt-base-template/app/components/Transition/TransitionSlideBottom.vue +0 -12
  30. package/nuxt-base-template/app/components/Transition/TransitionSlideRevert.vue +0 -12
  31. package/nuxt-base-template/app/composables/use-better-auth.ts +0 -415
  32. package/nuxt-base-template/app/composables/use-file.ts +0 -71
  33. package/nuxt-base-template/app/composables/use-share.ts +0 -38
  34. package/nuxt-base-template/app/composables/use-tus-upload.ts +0 -278
  35. package/nuxt-base-template/app/composables/use-tw.ts +0 -1
  36. package/nuxt-base-template/app/interfaces/upload.interface.ts +0 -58
  37. package/nuxt-base-template/app/lib/auth-client.ts +0 -232
  38. package/nuxt-base-template/app/plugins/auth-interceptor.client.ts +0 -143
  39. 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 } = useBetterAuth();
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 official Better Auth signIn.passkey() method
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 official Better Auth client method
65
- // This calls: GET /passkey/generate-authenticate-options → POST /passkey/verify-authentication
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.error) {
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.message || 'Passkey-Anmeldung fehlgeschlagen',
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.data?.user) {
80
- setUser(result.data.user as any);
81
- } else if (result.data?.session) {
82
- // Passkey auth returns session without user - fetch user via session validation
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 : ('data' in result ? result.data?.user : null);
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 useBetterAuth
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 } = useBetterAuth();
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
- const { error } = await authClient.passkey.addPasskey({
140
- name: 'Mein Gerät',
141
- });
137
+ // Use registerPasskey from composable which properly handles challengeId
138
+ const result = await registerPasskey('Mein Gerät');
142
139
 
143
- if (error) {
140
+ if (!result.success) {
144
141
  toast.add({
145
142
  color: 'error',
146
- description: error.message || 'Passkey konnte nicht hinzugefügt werden',
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
- import { authClient } from '~/lib/auth-client';
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 } = useShare();
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
  });