wexts 3.0.1 → 4.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/README.md +49 -346
- package/bin/wexts.cjs +2 -0
- package/dist/chunk-2KAQYLVN.js +0 -0
- package/dist/chunk-2KAQYLVN.js.map +1 -1
- package/dist/{chunk-O42L6HOX.js → chunk-2LJVUMXW.js} +79 -93
- package/dist/chunk-2LJVUMXW.js.map +1 -0
- package/dist/chunk-7QKLIVRF.js +94 -0
- package/dist/chunk-7QKLIVRF.js.map +1 -0
- package/dist/{chunk-FCEZDH42.mjs → chunk-7WULUGLH.mjs} +5 -3
- package/dist/chunk-7WULUGLH.mjs.map +1 -0
- package/dist/{chunk-WF65EDRZ.js → chunk-BG56B4DE.js} +20 -2
- package/dist/chunk-BG56B4DE.js.map +1 -0
- package/dist/chunk-CLM5PNSG.mjs +496 -0
- package/dist/chunk-CLM5PNSG.mjs.map +1 -0
- package/dist/chunk-DNLGCKTT.js +31 -0
- package/dist/chunk-DNLGCKTT.js.map +1 -0
- package/dist/{chunk-VNNVLQLJ.mjs → chunk-JHOVXH3X.mjs} +2 -2
- package/dist/chunk-JHOVXH3X.mjs.map +1 -0
- package/dist/chunk-MXINIFPC.js +105 -0
- package/dist/chunk-MXINIFPC.js.map +1 -0
- package/dist/chunk-SE32ZPOZ.js +496 -0
- package/dist/chunk-SE32ZPOZ.js.map +1 -0
- package/dist/{chunk-STTOPUZ2.mjs → chunk-UAL54DVV.mjs} +21 -3
- package/dist/chunk-UAL54DVV.mjs.map +1 -0
- package/dist/{chunk-3OM7CHCA.js → chunk-WCKSKU3C.js} +1 -1
- package/dist/chunk-WCKSKU3C.js.map +1 -0
- package/dist/chunk-WU6FW77M.mjs +105 -0
- package/dist/chunk-WU6FW77M.mjs.map +1 -0
- package/dist/chunk-XE4OXN2W.js +0 -0
- package/dist/chunk-XE4OXN2W.js.map +1 -1
- package/dist/chunk-YBM3IJEA.mjs +94 -0
- package/dist/chunk-YBM3IJEA.mjs.map +1 -0
- package/dist/{chunk-KXYLEUSW.mjs → chunk-YN6WIWNQ.mjs} +69 -83
- package/dist/chunk-YN6WIWNQ.mjs.map +1 -0
- package/dist/chunk-YSLEF5C5.mjs +0 -0
- package/dist/chunk-YSLEF5C5.mjs.map +0 -0
- package/dist/chunk-ZX7QIN24.mjs +31 -0
- package/dist/chunk-ZX7QIN24.mjs.map +1 -0
- package/dist/cli/index.d.mts +10 -0
- package/dist/cli/index.d.ts +10 -0
- package/dist/cli/index.js +292 -292
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +294 -293
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/index.d.mts +10 -1
- package/dist/client/index.d.ts +10 -1
- package/dist/client/index.js +4 -2
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +6 -4
- package/dist/client/index.mjs.map +0 -0
- package/dist/codegen/index.d.mts +2 -1
- package/dist/codegen/index.d.ts +2 -1
- package/dist/codegen/index.js +5 -3
- package/dist/codegen/index.js.map +1 -1
- package/dist/codegen/index.mjs +7 -5
- package/dist/codegen/index.mjs.map +0 -0
- package/dist/decorators-BT1FFqN0.d.mts +29 -0
- package/dist/decorators-DvS58PqC.d.ts +29 -0
- package/dist/dev-server/index.d.mts +1 -1
- package/dist/dev-server/index.d.ts +1 -1
- package/dist/dev-server/index.js +3 -3
- package/dist/dev-server/index.js.map +1 -1
- package/dist/dev-server/index.mjs +3 -3
- package/dist/dev-server/index.mjs.map +0 -0
- package/dist/{index-SjUaHgFr.d.ts → index-7QeQEf37.d.ts} +27 -10
- package/dist/{index-tFGPFVfQ.d.mts → index-7RvU-jGE.d.mts} +0 -1
- package/dist/{index-tFGPFVfQ.d.ts → index-7RvU-jGE.d.ts} +0 -1
- package/dist/{index-SjUaHgFr.d.mts → index-8nzxy0NN.d.mts} +27 -10
- package/dist/index-Co5ZsLqq.d.ts +58 -0
- package/dist/index-D94W1__r.d.mts +58 -0
- package/dist/index-DQmyVp6F.d.mts +27 -0
- package/dist/index-KL_1BrQb.d.ts +27 -0
- package/dist/index.d.mts +17 -6
- package/dist/index.d.ts +17 -6
- package/dist/index.js +57 -30
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +48 -21
- package/dist/index.mjs.map +1 -1
- package/dist/nest/index.d.mts +3 -1
- package/dist/nest/index.d.ts +3 -1
- package/dist/nest/index.js +20 -2
- package/dist/nest/index.js.map +1 -1
- package/dist/nest/index.mjs +21 -3
- package/dist/nest/index.mjs.map +0 -0
- package/dist/next/index.d.mts +7 -2
- package/dist/next/index.d.ts +7 -2
- package/dist/next/index.js +72 -5
- package/dist/next/index.js.map +1 -1
- package/dist/next/index.mjs +70 -4
- package/dist/next/index.mjs.map +1 -1
- package/dist/rpc/index.d.mts +2 -0
- package/dist/rpc/index.d.ts +2 -0
- package/dist/rpc/index.js +23 -0
- package/dist/rpc/index.js.map +1 -0
- package/dist/rpc/index.mjs +23 -0
- package/dist/{chunk-7NSRDJ5C.mjs.map → rpc/index.mjs.map} +0 -0
- package/dist/runtime/index.d.mts +55 -0
- package/dist/runtime/index.d.ts +55 -0
- package/dist/runtime/index.js +213 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/index.mjs +213 -0
- package/dist/runtime/index.mjs.map +1 -0
- package/dist/types/index.d.mts +0 -0
- package/dist/types/index.d.ts +0 -0
- package/dist/types/index.js +0 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/index.mjs +1 -1
- package/dist/types/index.mjs.map +0 -0
- package/dist/types-7d_fC-C3.d.mts +32 -0
- package/dist/types-7d_fC-C3.d.ts +32 -0
- package/dist/vercel-builder/index.d.mts +58 -0
- package/dist/vercel-builder/index.d.ts +58 -0
- package/dist/vercel-builder/index.js +330 -0
- package/dist/vercel-builder/index.js.map +1 -0
- package/dist/vercel-builder/index.mjs +330 -0
- package/dist/vercel-builder/index.mjs.map +1 -0
- package/package.json +37 -16
- package/templates/.dockerignore +43 -43
- package/templates/.env.example +0 -0
- package/templates/Dockerfile +60 -60
- package/templates/Procfile +1 -1
- package/templates/README.md +67 -58
- package/templates/api-sdk.ts +115 -115
- package/templates/docker-compose.yml +34 -34
- package/templates/nestjs-api/.env.example +0 -0
- package/templates/nestjs-api/README.md +87 -79
- package/templates/nestjs-api/nest-cli.json +6 -6
- package/templates/nestjs-api/package-lock.json +5623 -5623
- package/templates/nestjs-api/package.json +40 -40
- package/templates/nestjs-api/prisma/dev.db +0 -0
- package/templates/nestjs-api/prisma/migrations/20251123205437_init/migration.sql +0 -0
- package/templates/nestjs-api/prisma/migrations/migration_lock.toml +0 -0
- package/templates/nestjs-api/prisma/schema.prisma +29 -29
- package/templates/nestjs-api/src/app.module.ts +17 -17
- package/templates/nestjs-api/src/auth/auth.controller.ts +27 -27
- package/templates/nestjs-api/src/auth/auth.module.ts +37 -29
- package/templates/nestjs-api/src/auth/auth.service.ts +86 -86
- package/templates/nestjs-api/src/auth/dto/auth.dto.ts +22 -22
- package/templates/nestjs-api/src/auth/guards/jwt-auth.guard.ts +5 -5
- package/templates/nestjs-api/src/auth/strategies/jwt.strategy.ts +27 -19
- package/templates/nestjs-api/src/main.ts +32 -32
- package/templates/nestjs-api/src/prisma/prisma.module.ts +9 -9
- package/templates/nestjs-api/src/prisma/prisma.service.ts +14 -14
- package/templates/nestjs-api/src/todos/dto/todo.dto.ts +24 -24
- package/templates/nestjs-api/src/todos/todos.controller.ts +39 -39
- package/templates/nestjs-api/src/todos/todos.module.ts +11 -11
- package/templates/nestjs-api/src/todos/todos.service.ts +53 -53
- package/templates/nestjs-api/src/users/users.controller.ts +14 -14
- package/templates/nestjs-api/src/users/users.module.ts +12 -12
- package/templates/nestjs-api/src/users/users.service.ts +19 -19
- package/templates/nestjs-api/tsconfig.json +39 -39
- package/templates/nextjs-web/README.md +76 -68
- package/templates/nextjs-web/app/actions/auth.ts +108 -108
- package/templates/nextjs-web/app/dashboard/error.tsx +39 -39
- package/templates/nextjs-web/app/dashboard/loading.tsx +14 -14
- package/templates/nextjs-web/app/dashboard/page.tsx +5 -5
- package/templates/nextjs-web/app/globals.css +93 -93
- package/templates/nextjs-web/app/layout.tsx +29 -29
- package/templates/nextjs-web/app/login/page.tsx +5 -5
- package/templates/nextjs-web/app/page.tsx +28 -28
- package/templates/nextjs-web/app/register/page.tsx +5 -5
- package/templates/nextjs-web/components/ui/button.tsx +56 -56
- package/templates/nextjs-web/components/ui/card.tsx +79 -79
- package/templates/nextjs-web/components/ui/input.tsx +25 -25
- package/templates/nextjs-web/components/ui/label.tsx +24 -24
- package/templates/nextjs-web/features/auth/LoginForm.tsx +140 -140
- package/templates/nextjs-web/features/auth/RegisterForm.tsx +159 -159
- package/templates/nextjs-web/features/auth/api.ts +35 -35
- package/templates/nextjs-web/features/auth/index.ts +3 -3
- package/templates/nextjs-web/features/dashboard/DashboardView.tsx +204 -204
- package/templates/nextjs-web/features/dashboard/api.ts +9 -9
- package/templates/nextjs-web/features/dashboard/components.tsx +74 -74
- package/templates/nextjs-web/features/dashboard/index.ts +3 -3
- package/templates/nextjs-web/hooks/index.ts +4 -4
- package/templates/nextjs-web/lib/api-client.ts +89 -89
- package/templates/nextjs-web/lib/api.ts +115 -115
- package/templates/nextjs-web/lib/axios-global-config.ts +17 -17
- package/templates/nextjs-web/lib/utils.ts +6 -6
- package/templates/nextjs-web/lib/wexts-client.ts +4 -4
- package/templates/nextjs-web/next-env.d.ts +6 -6
- package/templates/nextjs-web/next.config.ts +20 -20
- package/templates/nextjs-web/package-lock.json +3254 -3254
- package/templates/nextjs-web/package.json +37 -37
- package/templates/nextjs-web/postcss.config.js +6 -6
- package/templates/nextjs-web/tailwind.config.ts +69 -69
- package/templates/nextjs-web/tsconfig.json +1 -1
- package/templates/nixpacks.toml +11 -11
- package/templates/root-package.json +31 -31
- package/templates/server.ts +66 -66
- package/templates/tsconfig.json +30 -30
- package/dist/chunk-2MCBBWEA.js +0 -1
- package/dist/chunk-2MCBBWEA.js.map +0 -1
- package/dist/chunk-3OM7CHCA.js.map +0 -1
- package/dist/chunk-63MTCWU2.mjs +0 -361
- package/dist/chunk-63MTCWU2.mjs.map +0 -1
- package/dist/chunk-667BQCEM.js +0 -375
- package/dist/chunk-667BQCEM.js.map +0 -1
- package/dist/chunk-67IJ6H4J.mjs +0 -44
- package/dist/chunk-67IJ6H4J.mjs.map +0 -1
- package/dist/chunk-6SVQEGEX.mjs +0 -44
- package/dist/chunk-6SVQEGEX.mjs.map +0 -1
- package/dist/chunk-7NSRDJ5C.mjs +0 -1
- package/dist/chunk-ASDXAK6G.js +0 -44
- package/dist/chunk-ASDXAK6G.js.map +0 -1
- package/dist/chunk-CKZ4VSCB.mjs +0 -18
- package/dist/chunk-CKZ4VSCB.mjs.map +0 -1
- package/dist/chunk-DW6GOKMF.js +0 -57
- package/dist/chunk-DW6GOKMF.js.map +0 -1
- package/dist/chunk-EFZPSZWO.mjs +0 -1
- package/dist/chunk-EFZPSZWO.mjs.map +0 -1
- package/dist/chunk-FCEZDH42.mjs.map +0 -1
- package/dist/chunk-FYGXL4V7.js +0 -361
- package/dist/chunk-FYGXL4V7.js.map +0 -1
- package/dist/chunk-GKVPGKAH.js +0 -66
- package/dist/chunk-GKVPGKAH.js.map +0 -1
- package/dist/chunk-GWP6PNSP.js +0 -225
- package/dist/chunk-GWP6PNSP.js.map +0 -1
- package/dist/chunk-HQKTXE7E.mjs +0 -225
- package/dist/chunk-HQKTXE7E.mjs.map +0 -1
- package/dist/chunk-HSFLZUJN.mjs +0 -57
- package/dist/chunk-HSFLZUJN.mjs.map +0 -1
- package/dist/chunk-HU63F22V.js +0 -361
- package/dist/chunk-HU63F22V.js.map +0 -1
- package/dist/chunk-J5LGTIGS.mjs +0 -10
- package/dist/chunk-J5LGTIGS.mjs.map +0 -1
- package/dist/chunk-JMBD6DOP.js +0 -225
- package/dist/chunk-JMBD6DOP.js.map +0 -1
- package/dist/chunk-K7EIJSYQ.js +0 -1
- package/dist/chunk-K7EIJSYQ.js.map +0 -1
- package/dist/chunk-KXYLEUSW.mjs.map +0 -1
- package/dist/chunk-MTHKZO55.js +0 -44
- package/dist/chunk-MTHKZO55.js.map +0 -1
- package/dist/chunk-NNQFLD7O.mjs +0 -361
- package/dist/chunk-NNQFLD7O.mjs.map +0 -1
- package/dist/chunk-NU2UB242.js +0 -82
- package/dist/chunk-NU2UB242.js.map +0 -1
- package/dist/chunk-NULGSZFE.mjs +0 -57
- package/dist/chunk-NULGSZFE.mjs.map +0 -1
- package/dist/chunk-O42L6HOX.js.map +0 -1
- package/dist/chunk-ONXNE2A6.mjs +0 -375
- package/dist/chunk-ONXNE2A6.mjs.map +0 -1
- package/dist/chunk-OTBYRUBE.mjs +0 -225
- package/dist/chunk-OTBYRUBE.mjs.map +0 -1
- package/dist/chunk-OTSAVKLY.mjs +0 -66
- package/dist/chunk-OTSAVKLY.mjs.map +0 -1
- package/dist/chunk-PZ5AY32C.js +0 -10
- package/dist/chunk-PZ5AY32C.js.map +0 -1
- package/dist/chunk-QP2TMRLG.js +0 -57
- package/dist/chunk-QP2TMRLG.js.map +0 -1
- package/dist/chunk-RS23R3ZQ.mjs +0 -82
- package/dist/chunk-RS23R3ZQ.mjs.map +0 -1
- package/dist/chunk-STTOPUZ2.mjs.map +0 -1
- package/dist/chunk-VMT3LALB.mjs +0 -51
- package/dist/chunk-VMT3LALB.mjs.map +0 -1
- package/dist/chunk-VNNVLQLJ.mjs.map +0 -1
- package/dist/chunk-W3YRVEFQ.js +0 -66
- package/dist/chunk-W3YRVEFQ.js.map +0 -1
- package/dist/chunk-WF65EDRZ.js.map +0 -1
- package/dist/chunk-WMHVXEYQ.mjs +0 -66
- package/dist/chunk-WMHVXEYQ.mjs.map +0 -1
- package/dist/chunk-XVKTIYHY.js +0 -51
- package/dist/chunk-XVKTIYHY.js.map +0 -1
- package/dist/codegen-MRZDLCYI.js +0 -13
- package/dist/codegen-MRZDLCYI.js.map +0 -1
- package/dist/codegen-UI5HTMXE.mjs +0 -13
- package/dist/codegen-UI5HTMXE.mjs.map +0 -1
- package/dist/dev-server-JKRVBWPY.mjs +0 -13
- package/dist/dev-server-JKRVBWPY.mjs.map +0 -1
- package/dist/dev-server-TLL7UQMR.js +0 -13
- package/dist/dev-server-TLL7UQMR.js.map +0 -1
- package/dist/index-BsNaOUtH.d.mts +0 -44
- package/dist/index-BsNaOUtH.d.ts +0 -44
- package/dist/index-CrbXnXsO.d.ts +0 -62
- package/dist/index-kEbGExWM.d.mts +0 -62
- package/templates/nestjs-api/.env +0 -4
- package/templates/nextjs-web/.env +0 -1
|
@@ -1,108 +1,108 @@
|
|
|
1
|
-
'use server';
|
|
2
|
-
|
|
3
|
-
import { cookies } from 'next/headers';
|
|
4
|
-
import { redirect } from 'next/navigation';
|
|
5
|
-
import { api } from '@/lib/api';
|
|
6
|
-
|
|
7
|
-
export type ActionState = {
|
|
8
|
-
message?: string;
|
|
9
|
-
errors?: {
|
|
10
|
-
email?: string[];
|
|
11
|
-
password?: string[];
|
|
12
|
-
};
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export async function loginAction(prevState: ActionState, formData: FormData): Promise<ActionState> {
|
|
16
|
-
const email = formData.get('email') as string;
|
|
17
|
-
const password = formData.get('password') as string;
|
|
18
|
-
|
|
19
|
-
const errors: { email?: string[]; password?: string[] } = {};
|
|
20
|
-
|
|
21
|
-
if (!email || !email.includes('@')) {
|
|
22
|
-
errors.email = ['Invalid email address'];
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (!password || password.length < 6) {
|
|
26
|
-
errors.password = ['Password must be at least 6 characters'];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (Object.keys(errors).length > 0) {
|
|
30
|
-
return { errors };
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
try {
|
|
34
|
-
//
|
|
35
|
-
const data = await api.auth.login({ email, password });
|
|
36
|
-
|
|
37
|
-
// Store JWT token
|
|
38
|
-
if (data.access_token) {
|
|
39
|
-
const cookieStore = await cookies();
|
|
40
|
-
cookieStore.set('wexts_token', data.access_token, {
|
|
41
|
-
httpOnly: true,
|
|
42
|
-
secure: process.env.NODE_ENV === 'production',
|
|
43
|
-
maxAge: 60 * 60 * 24 * 7, // 1 week
|
|
44
|
-
path: '/',
|
|
45
|
-
});
|
|
46
|
-
} else {
|
|
47
|
-
return {
|
|
48
|
-
message: 'Login failed: No token received',
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
} catch (error: any) {
|
|
52
|
-
console.error('Login error:', error);
|
|
53
|
-
return {
|
|
54
|
-
message: error.message || 'Invalid credentials',
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
redirect('/dashboard');
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export async function registerAction(prevState: ActionState, formData: FormData): Promise<ActionState> {
|
|
62
|
-
const email = formData.get('email') as string;
|
|
63
|
-
const password = formData.get('password') as string;
|
|
64
|
-
const name = formData.get('name') as string;
|
|
65
|
-
|
|
66
|
-
const errors: { email?: string[]; password?: string[] } = {};
|
|
67
|
-
|
|
68
|
-
if (!email || !email.includes('@')) {
|
|
69
|
-
errors.email = ['Invalid email address'];
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (!password || password.length < 6) {
|
|
73
|
-
errors.password = ['Password must be at least 6 characters'];
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (Object.keys(errors).length > 0) {
|
|
77
|
-
return { errors };
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
try {
|
|
81
|
-
//
|
|
82
|
-
const data = await api.auth.register({ email, password, name });
|
|
83
|
-
|
|
84
|
-
// Store JWT token
|
|
85
|
-
if (data.access_token) {
|
|
86
|
-
const cookieStore = await cookies();
|
|
87
|
-
cookieStore.set('wexts_token', data.access_token, {
|
|
88
|
-
httpOnly: true,
|
|
89
|
-
secure: process.env.NODE_ENV === 'production',
|
|
90
|
-
maxAge: 60 * 60 * 24 * 7,
|
|
91
|
-
path: '/',
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
} catch (error: any) {
|
|
95
|
-
console.error('Register error:', error);
|
|
96
|
-
return {
|
|
97
|
-
message: error.message || 'Registration failed',
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
redirect('/dashboard');
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export async function logoutAction() {
|
|
105
|
-
const cookieStore = await cookies();
|
|
106
|
-
cookieStore.delete('wexts_token');
|
|
107
|
-
redirect('/login');
|
|
108
|
-
}
|
|
1
|
+
'use server';
|
|
2
|
+
|
|
3
|
+
import { cookies } from 'next/headers';
|
|
4
|
+
import { redirect } from 'next/navigation';
|
|
5
|
+
import { api } from '@/lib/api';
|
|
6
|
+
|
|
7
|
+
export type ActionState = {
|
|
8
|
+
message?: string;
|
|
9
|
+
errors?: {
|
|
10
|
+
email?: string[];
|
|
11
|
+
password?: string[];
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export async function loginAction(prevState: ActionState, formData: FormData): Promise<ActionState> {
|
|
16
|
+
const email = formData.get('email') as string;
|
|
17
|
+
const password = formData.get('password') as string;
|
|
18
|
+
|
|
19
|
+
const errors: { email?: string[]; password?: string[] } = {};
|
|
20
|
+
|
|
21
|
+
if (!email || !email.includes('@')) {
|
|
22
|
+
errors.email = ['Invalid email address'];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (!password || password.length < 6) {
|
|
26
|
+
errors.password = ['Password must be at least 6 characters'];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (Object.keys(errors).length > 0) {
|
|
30
|
+
return { errors };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
// Legacy SDK call retained for deprecated template compatibility.
|
|
35
|
+
const data = await api.auth.login({ email, password });
|
|
36
|
+
|
|
37
|
+
// Store JWT token
|
|
38
|
+
if (data.access_token) {
|
|
39
|
+
const cookieStore = await cookies();
|
|
40
|
+
cookieStore.set('wexts_token', data.access_token, {
|
|
41
|
+
httpOnly: true,
|
|
42
|
+
secure: process.env.NODE_ENV === 'production',
|
|
43
|
+
maxAge: 60 * 60 * 24 * 7, // 1 week
|
|
44
|
+
path: '/',
|
|
45
|
+
});
|
|
46
|
+
} else {
|
|
47
|
+
return {
|
|
48
|
+
message: 'Login failed: No token received',
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
} catch (error: any) {
|
|
52
|
+
console.error('Login error:', error);
|
|
53
|
+
return {
|
|
54
|
+
message: error.message || 'Invalid credentials',
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
redirect('/dashboard');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function registerAction(prevState: ActionState, formData: FormData): Promise<ActionState> {
|
|
62
|
+
const email = formData.get('email') as string;
|
|
63
|
+
const password = formData.get('password') as string;
|
|
64
|
+
const name = formData.get('name') as string;
|
|
65
|
+
|
|
66
|
+
const errors: { email?: string[]; password?: string[] } = {};
|
|
67
|
+
|
|
68
|
+
if (!email || !email.includes('@')) {
|
|
69
|
+
errors.email = ['Invalid email address'];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!password || password.length < 6) {
|
|
73
|
+
errors.password = ['Password must be at least 6 characters'];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (Object.keys(errors).length > 0) {
|
|
77
|
+
return { errors };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
// Legacy SDK call retained for deprecated template compatibility.
|
|
82
|
+
const data = await api.auth.register({ email, password, name });
|
|
83
|
+
|
|
84
|
+
// Store JWT token
|
|
85
|
+
if (data.access_token) {
|
|
86
|
+
const cookieStore = await cookies();
|
|
87
|
+
cookieStore.set('wexts_token', data.access_token, {
|
|
88
|
+
httpOnly: true,
|
|
89
|
+
secure: process.env.NODE_ENV === 'production',
|
|
90
|
+
maxAge: 60 * 60 * 24 * 7,
|
|
91
|
+
path: '/',
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
} catch (error: any) {
|
|
95
|
+
console.error('Register error:', error);
|
|
96
|
+
return {
|
|
97
|
+
message: error.message || 'Registration failed',
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
redirect('/dashboard');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export async function logoutAction() {
|
|
105
|
+
const cookieStore = await cookies();
|
|
106
|
+
cookieStore.delete('wexts_token');
|
|
107
|
+
redirect('/login');
|
|
108
|
+
}
|
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useEffect } from 'react';
|
|
4
|
-
import { Button } from '@/components/ui/button';
|
|
5
|
-
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
6
|
-
import { AlertTriangle } from 'lucide-react';
|
|
7
|
-
|
|
8
|
-
export default function DashboardError({
|
|
9
|
-
error,
|
|
10
|
-
reset,
|
|
11
|
-
}: {
|
|
12
|
-
error: Error & { digest?: string };
|
|
13
|
-
reset: () => void;
|
|
14
|
-
}) {
|
|
15
|
-
useEffect(() => {
|
|
16
|
-
console.error(error);
|
|
17
|
-
}, [error]);
|
|
18
|
-
|
|
19
|
-
return (
|
|
20
|
-
<div className="min-h-screen bg-background flex items-center justify-center p-8">
|
|
21
|
-
<Card className="glass border-destructive/20 max-w-md w-full">
|
|
22
|
-
<CardHeader>
|
|
23
|
-
<CardTitle className="text-destructive flex items-center gap-2">
|
|
24
|
-
<AlertTriangle className="w-5 h-5" />
|
|
25
|
-
Something went wrong
|
|
26
|
-
</CardTitle>
|
|
27
|
-
</CardHeader>
|
|
28
|
-
<CardContent className="space-y-4">
|
|
29
|
-
<p className="text-muted-foreground">
|
|
30
|
-
We encountered an error while loading your dashboard. Please try again.
|
|
31
|
-
</p>
|
|
32
|
-
<Button onClick={reset} className="w-full">
|
|
33
|
-
Try again
|
|
34
|
-
</Button>
|
|
35
|
-
</CardContent>
|
|
36
|
-
</Card>
|
|
37
|
-
</div>
|
|
38
|
-
);
|
|
39
|
-
}
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useEffect } from 'react';
|
|
4
|
+
import { Button } from '@/components/ui/button';
|
|
5
|
+
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
6
|
+
import { AlertTriangle } from 'lucide-react';
|
|
7
|
+
|
|
8
|
+
export default function DashboardError({
|
|
9
|
+
error,
|
|
10
|
+
reset,
|
|
11
|
+
}: {
|
|
12
|
+
error: Error & { digest?: string };
|
|
13
|
+
reset: () => void;
|
|
14
|
+
}) {
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
console.error(error);
|
|
17
|
+
}, [error]);
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<div className="min-h-screen bg-background flex items-center justify-center p-8">
|
|
21
|
+
<Card className="glass border-destructive/20 max-w-md w-full">
|
|
22
|
+
<CardHeader>
|
|
23
|
+
<CardTitle className="text-destructive flex items-center gap-2">
|
|
24
|
+
<AlertTriangle className="w-5 h-5" />
|
|
25
|
+
Something went wrong
|
|
26
|
+
</CardTitle>
|
|
27
|
+
</CardHeader>
|
|
28
|
+
<CardContent className="space-y-4">
|
|
29
|
+
<p className="text-muted-foreground">
|
|
30
|
+
We encountered an error while loading your dashboard. Please try again.
|
|
31
|
+
</p>
|
|
32
|
+
<Button onClick={reset} className="w-full">
|
|
33
|
+
Try again
|
|
34
|
+
</Button>
|
|
35
|
+
</CardContent>
|
|
36
|
+
</Card>
|
|
37
|
+
</div>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { Loader2 } from 'lucide-react';
|
|
2
|
-
|
|
3
|
-
export default function DashboardLoading() {
|
|
4
|
-
return (
|
|
5
|
-
<div className="min-h-screen bg-background flex items-center justify-center">
|
|
6
|
-
<div className="text-center space-y-4">
|
|
7
|
-
<div className="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-primary/10 text-primary animate-pulse">
|
|
8
|
-
<Loader2 className="w-8 h-8 animate-spin" />
|
|
9
|
-
</div>
|
|
10
|
-
<p className="text-muted-foreground animate-pulse">Loading dashboard...</p>
|
|
11
|
-
</div>
|
|
12
|
-
</div>
|
|
13
|
-
);
|
|
14
|
-
}
|
|
1
|
+
import { Loader2 } from 'lucide-react';
|
|
2
|
+
|
|
3
|
+
export default function DashboardLoading() {
|
|
4
|
+
return (
|
|
5
|
+
<div className="min-h-screen bg-background flex items-center justify-center">
|
|
6
|
+
<div className="text-center space-y-4">
|
|
7
|
+
<div className="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-primary/10 text-primary animate-pulse">
|
|
8
|
+
<Loader2 className="w-8 h-8 animate-spin" />
|
|
9
|
+
</div>
|
|
10
|
+
<p className="text-muted-foreground animate-pulse">Loading dashboard...</p>
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DashboardView } from '@/features/dashboard';
|
|
2
|
-
|
|
3
|
-
export default function DashboardPage() {
|
|
4
|
-
return <DashboardView />;
|
|
5
|
-
}
|
|
1
|
+
import { DashboardView } from '@/features/dashboard';
|
|
2
|
+
|
|
3
|
+
export default function DashboardPage() {
|
|
4
|
+
return <DashboardView />;
|
|
5
|
+
}
|
|
@@ -1,93 +1,93 @@
|
|
|
1
|
-
@tailwind base;
|
|
2
|
-
@tailwind components;
|
|
3
|
-
@tailwind utilities;
|
|
4
|
-
|
|
5
|
-
@layer base {
|
|
6
|
-
:root {
|
|
7
|
-
/* Brand Colors - Deep Violet & Electric Purple */
|
|
8
|
-
--background: 260 30% 98%;
|
|
9
|
-
--foreground: 260 40% 10%;
|
|
10
|
-
|
|
11
|
-
--primary: 265 89% 66%;
|
|
12
|
-
--primary-foreground: 210 40% 98%;
|
|
13
|
-
|
|
14
|
-
--secondary: 260 20% 90%;
|
|
15
|
-
--secondary-foreground: 260 40% 10%;
|
|
16
|
-
|
|
17
|
-
--muted: 260 20% 96%;
|
|
18
|
-
--muted-foreground: 260 20% 40%;
|
|
19
|
-
|
|
20
|
-
--accent: 265 89% 96%;
|
|
21
|
-
--accent-foreground: 265 89% 66%;
|
|
22
|
-
|
|
23
|
-
--destructive: 0 84% 60%;
|
|
24
|
-
--destructive-foreground: 210 40% 98%;
|
|
25
|
-
|
|
26
|
-
--border: 260 20% 90%;
|
|
27
|
-
--input: 260 20% 90%;
|
|
28
|
-
--ring: 265 89% 66%;
|
|
29
|
-
|
|
30
|
-
--radius: 1rem;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
.dark {
|
|
34
|
-
--background: 260 40% 5%;
|
|
35
|
-
--foreground: 210 40% 98%;
|
|
36
|
-
|
|
37
|
-
--primary: 265 89% 66%;
|
|
38
|
-
--primary-foreground: 210 40% 98%;
|
|
39
|
-
|
|
40
|
-
--secondary: 260 30% 15%;
|
|
41
|
-
--secondary-foreground: 210 40% 98%;
|
|
42
|
-
|
|
43
|
-
--muted: 260 30% 15%;
|
|
44
|
-
--muted-foreground: 215 20% 65%;
|
|
45
|
-
|
|
46
|
-
--accent: 260 30% 15%;
|
|
47
|
-
--accent-foreground: 210 40% 98%;
|
|
48
|
-
|
|
49
|
-
--destructive: 0 62% 30%;
|
|
50
|
-
--destructive-foreground: 210 40% 98%;
|
|
51
|
-
|
|
52
|
-
--border: 260 30% 15%;
|
|
53
|
-
--input: 260 30% 15%;
|
|
54
|
-
--ring: 265 89% 66%;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
@layer base {
|
|
59
|
-
* {
|
|
60
|
-
@apply border-border;
|
|
61
|
-
}
|
|
62
|
-
body {
|
|
63
|
-
@apply bg-background text-foreground antialiased;
|
|
64
|
-
font-feature-settings: "rlig" 1, "calt" 1;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
@layer utilities {
|
|
69
|
-
.glass {
|
|
70
|
-
@apply bg-white/10 backdrop-blur-lg border border-white/20 shadow-xl;
|
|
71
|
-
}
|
|
72
|
-
.glass-dark {
|
|
73
|
-
@apply bg-black/30 backdrop-blur-lg border border-white/10 shadow-xl;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
.text-gradient {
|
|
77
|
-
@apply bg-clip-text text-transparent bg-gradient-to-r from-violet-600 to-indigo-600 dark:from-violet-400 dark:to-indigo-400;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.animate-float {
|
|
81
|
-
animation: float 6s ease-in-out infinite;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
.animate-pulse-slow {
|
|
85
|
-
animation: pulse 4s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
@keyframes float {
|
|
90
|
-
0% { transform: translateY(0px); }
|
|
91
|
-
50% { transform: translateY(-20px); }
|
|
92
|
-
100% { transform: translateY(0px); }
|
|
93
|
-
}
|
|
1
|
+
@tailwind base;
|
|
2
|
+
@tailwind components;
|
|
3
|
+
@tailwind utilities;
|
|
4
|
+
|
|
5
|
+
@layer base {
|
|
6
|
+
:root {
|
|
7
|
+
/* Brand Colors - Deep Violet & Electric Purple */
|
|
8
|
+
--background: 260 30% 98%;
|
|
9
|
+
--foreground: 260 40% 10%;
|
|
10
|
+
|
|
11
|
+
--primary: 265 89% 66%;
|
|
12
|
+
--primary-foreground: 210 40% 98%;
|
|
13
|
+
|
|
14
|
+
--secondary: 260 20% 90%;
|
|
15
|
+
--secondary-foreground: 260 40% 10%;
|
|
16
|
+
|
|
17
|
+
--muted: 260 20% 96%;
|
|
18
|
+
--muted-foreground: 260 20% 40%;
|
|
19
|
+
|
|
20
|
+
--accent: 265 89% 96%;
|
|
21
|
+
--accent-foreground: 265 89% 66%;
|
|
22
|
+
|
|
23
|
+
--destructive: 0 84% 60%;
|
|
24
|
+
--destructive-foreground: 210 40% 98%;
|
|
25
|
+
|
|
26
|
+
--border: 260 20% 90%;
|
|
27
|
+
--input: 260 20% 90%;
|
|
28
|
+
--ring: 265 89% 66%;
|
|
29
|
+
|
|
30
|
+
--radius: 1rem;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.dark {
|
|
34
|
+
--background: 260 40% 5%;
|
|
35
|
+
--foreground: 210 40% 98%;
|
|
36
|
+
|
|
37
|
+
--primary: 265 89% 66%;
|
|
38
|
+
--primary-foreground: 210 40% 98%;
|
|
39
|
+
|
|
40
|
+
--secondary: 260 30% 15%;
|
|
41
|
+
--secondary-foreground: 210 40% 98%;
|
|
42
|
+
|
|
43
|
+
--muted: 260 30% 15%;
|
|
44
|
+
--muted-foreground: 215 20% 65%;
|
|
45
|
+
|
|
46
|
+
--accent: 260 30% 15%;
|
|
47
|
+
--accent-foreground: 210 40% 98%;
|
|
48
|
+
|
|
49
|
+
--destructive: 0 62% 30%;
|
|
50
|
+
--destructive-foreground: 210 40% 98%;
|
|
51
|
+
|
|
52
|
+
--border: 260 30% 15%;
|
|
53
|
+
--input: 260 30% 15%;
|
|
54
|
+
--ring: 265 89% 66%;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@layer base {
|
|
59
|
+
* {
|
|
60
|
+
@apply border-border;
|
|
61
|
+
}
|
|
62
|
+
body {
|
|
63
|
+
@apply bg-background text-foreground antialiased;
|
|
64
|
+
font-feature-settings: "rlig" 1, "calt" 1;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@layer utilities {
|
|
69
|
+
.glass {
|
|
70
|
+
@apply bg-white/10 backdrop-blur-lg border border-white/20 shadow-xl;
|
|
71
|
+
}
|
|
72
|
+
.glass-dark {
|
|
73
|
+
@apply bg-black/30 backdrop-blur-lg border border-white/10 shadow-xl;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.text-gradient {
|
|
77
|
+
@apply bg-clip-text text-transparent bg-gradient-to-r from-violet-600 to-indigo-600 dark:from-violet-400 dark:to-indigo-400;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.animate-float {
|
|
81
|
+
animation: float 6s ease-in-out infinite;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.animate-pulse-slow {
|
|
85
|
+
animation: pulse 4s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@keyframes float {
|
|
90
|
+
0% { transform: translateY(0px); }
|
|
91
|
+
50% { transform: translateY(-20px); }
|
|
92
|
+
100% { transform: translateY(0px); }
|
|
93
|
+
}
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import type { Metadata } from 'next';
|
|
2
|
-
import { Inter } from 'next/font/google';
|
|
3
|
-
import { WextsProvider } from '@/lib/wexts-client';
|
|
4
|
-
import { Toaster } from 'react-hot-toast';
|
|
5
|
-
import './globals.css';
|
|
6
|
-
|
|
7
|
-
const inter = Inter({ subsets: ['latin'] });
|
|
8
|
-
|
|
9
|
-
export const metadata: Metadata = {
|
|
10
|
-
title: 'wexts Web App',
|
|
11
|
-
description: 'Modern web application built with wexts',
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export default function RootLayout({
|
|
15
|
-
children,
|
|
16
|
-
}: {
|
|
17
|
-
children: React.ReactNode;
|
|
18
|
-
}) {
|
|
19
|
-
return (
|
|
20
|
-
<html lang="en">
|
|
21
|
-
<body className={inter.className}>
|
|
22
|
-
<WextsProvider baseUrl={process.env.NEXT_PUBLIC_API_URL || 'http://localhost:5050'}>
|
|
23
|
-
{children}
|
|
24
|
-
<Toaster position="top-center" />
|
|
25
|
-
</WextsProvider>
|
|
26
|
-
</body>
|
|
27
|
-
</html>
|
|
28
|
-
);
|
|
29
|
-
}
|
|
1
|
+
import type { Metadata } from 'next';
|
|
2
|
+
import { Inter } from 'next/font/google';
|
|
3
|
+
import { WextsProvider } from '@/lib/wexts-client';
|
|
4
|
+
import { Toaster } from 'react-hot-toast';
|
|
5
|
+
import './globals.css';
|
|
6
|
+
|
|
7
|
+
const inter = Inter({ subsets: ['latin'] });
|
|
8
|
+
|
|
9
|
+
export const metadata: Metadata = {
|
|
10
|
+
title: 'wexts Web App',
|
|
11
|
+
description: 'Modern web application built with wexts',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default function RootLayout({
|
|
15
|
+
children,
|
|
16
|
+
}: {
|
|
17
|
+
children: React.ReactNode;
|
|
18
|
+
}) {
|
|
19
|
+
return (
|
|
20
|
+
<html lang="en">
|
|
21
|
+
<body className={inter.className}>
|
|
22
|
+
<WextsProvider baseUrl={process.env.NEXT_PUBLIC_API_URL || 'http://localhost:5050'}>
|
|
23
|
+
{children}
|
|
24
|
+
<Toaster position="top-center" />
|
|
25
|
+
</WextsProvider>
|
|
26
|
+
</body>
|
|
27
|
+
</html>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { LoginForm } from '@/features/auth';
|
|
2
|
-
|
|
3
|
-
export default function LoginPage() {
|
|
4
|
-
return <LoginForm />;
|
|
5
|
-
}
|
|
1
|
+
import { LoginForm } from '@/features/auth';
|
|
2
|
+
|
|
3
|
+
export default function LoginPage() {
|
|
4
|
+
return <LoginForm />;
|
|
5
|
+
}
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useAuth } from '@/lib/wexts-client';
|
|
4
|
-
import { useRouter } from 'next/navigation';
|
|
5
|
-
import { useEffect } from 'react';
|
|
6
|
-
|
|
7
|
-
export default function Home() {
|
|
8
|
-
const { isAuthenticated, user, loading } = useAuth();
|
|
9
|
-
const router = useRouter();
|
|
10
|
-
|
|
11
|
-
useEffect(() => {
|
|
12
|
-
if (!loading && !isAuthenticated) {
|
|
13
|
-
router.push('/login');
|
|
14
|
-
} else if (!loading && isAuthenticated) {
|
|
15
|
-
router.push('/dashboard');
|
|
16
|
-
}
|
|
17
|
-
}, [isAuthenticated, loading, router]);
|
|
18
|
-
|
|
19
|
-
if (loading) {
|
|
20
|
-
return (
|
|
21
|
-
<div className="min-h-screen flex items-center justify-center">
|
|
22
|
-
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-violet-600"></div>
|
|
23
|
-
</div>
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useAuth } from '@/lib/wexts-client';
|
|
4
|
+
import { useRouter } from 'next/navigation';
|
|
5
|
+
import { useEffect } from 'react';
|
|
6
|
+
|
|
7
|
+
export default function Home() {
|
|
8
|
+
const { isAuthenticated, user, loading } = useAuth();
|
|
9
|
+
const router = useRouter();
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (!loading && !isAuthenticated) {
|
|
13
|
+
router.push('/login');
|
|
14
|
+
} else if (!loading && isAuthenticated) {
|
|
15
|
+
router.push('/dashboard');
|
|
16
|
+
}
|
|
17
|
+
}, [isAuthenticated, loading, router]);
|
|
18
|
+
|
|
19
|
+
if (loading) {
|
|
20
|
+
return (
|
|
21
|
+
<div className="min-h-screen flex items-center justify-center">
|
|
22
|
+
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-violet-600"></div>
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { RegisterForm } from '@/features/auth';
|
|
2
|
-
|
|
3
|
-
export default function RegisterPage() {
|
|
4
|
-
return <RegisterForm />;
|
|
5
|
-
}
|
|
1
|
+
import { RegisterForm } from '@/features/auth';
|
|
2
|
+
|
|
3
|
+
export default function RegisterPage() {
|
|
4
|
+
return <RegisterForm />;
|
|
5
|
+
}
|