create-stackkit-app 0.4.0 → 0.4.2
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 +25 -11
- package/dist/lib/create-project.js +88 -8
- package/dist/lib/template-composer.js +1 -1
- package/modules/auth/better-auth-express/adapters/mongoose-mongodb.ts +13 -0
- package/modules/auth/better-auth-express/adapters/prisma-mongodb.ts +15 -0
- package/modules/auth/better-auth-express/adapters/prisma-postgresql.ts +15 -0
- package/modules/auth/better-auth-express/files/schemas/prisma-mongodb-schema.prisma +72 -0
- package/modules/auth/better-auth-express/files/schemas/prisma-postgresql-schema.prisma +72 -0
- package/modules/auth/better-auth-express/module.json +26 -3
- package/modules/auth/better-auth-nextjs/adapters/mongoose-mongodb.ts +24 -0
- package/modules/auth/better-auth-nextjs/adapters/prisma-mongodb.ts +26 -0
- package/modules/auth/better-auth-nextjs/adapters/prisma-postgresql.ts +26 -0
- package/modules/auth/better-auth-nextjs/files/schemas/prisma-mongodb-schema.prisma +72 -0
- package/modules/auth/better-auth-nextjs/files/schemas/prisma-postgresql-schema.prisma +72 -0
- package/modules/auth/better-auth-nextjs/module.json +26 -5
- package/modules/auth/better-auth-react/module.json +7 -5
- package/modules/auth/clerk-express/module.json +23 -8
- package/modules/auth/clerk-nextjs/module.json +51 -14
- package/modules/auth/clerk-react/module.json +17 -7
- package/modules/database/mongoose-mongodb/module.json +44 -6
- package/modules/database/prisma-mongodb/files/prisma/schema.prisma +1 -1
- package/modules/database/prisma-mongodb/module.json +28 -4
- package/modules/database/prisma-postgresql/files/prisma/schema.prisma +1 -1
- package/modules/database/prisma-postgresql/module.json +28 -4
- package/package.json +3 -3
- package/templates/express/.env.example +11 -0
- package/templates/express/eslint.config.cjs +42 -0
- package/templates/express/package.json +38 -0
- package/templates/express/src/app.ts +69 -0
- package/templates/express/src/config/env.ts +23 -0
- package/templates/express/src/middlewares/error.middleware.ts +18 -0
- package/templates/express/src/server.ts +8 -0
- package/templates/{bases/express-base → express}/template.json +1 -1
- package/templates/express/tsconfig.json +14 -0
- package/templates/{bases/nextjs-base → nextjs}/app/page.tsx +5 -5
- package/templates/{bases/nextjs-base → nextjs}/template.json +1 -1
- package/templates/react-vite/.env.example +2 -0
- package/templates/react-vite/README.md +85 -0
- package/templates/react-vite/eslint.config.js +23 -0
- package/templates/{bases/react-vite-base → react-vite}/index.html +2 -1
- package/templates/react-vite/package.json +45 -0
- package/templates/react-vite/public/vite.svg +1 -0
- package/templates/react-vite/src/api/client.ts +47 -0
- package/templates/react-vite/src/api/services/user.service.ts +26 -0
- package/templates/react-vite/src/assets/react.svg +1 -0
- package/templates/react-vite/src/components/ErrorBoundary.tsx +51 -0
- package/templates/react-vite/src/components/Layout.tsx +13 -0
- package/templates/react-vite/src/components/Loading.tsx +8 -0
- package/templates/react-vite/src/components/SEO.tsx +49 -0
- package/templates/react-vite/src/config/constants.ts +5 -0
- package/templates/react-vite/src/hooks/index.ts +64 -0
- package/templates/react-vite/src/index.css +1 -0
- package/templates/react-vite/src/lib/queryClient.ts +12 -0
- package/templates/react-vite/src/main.tsx +22 -0
- package/templates/react-vite/src/pages/About.tsx +74 -0
- package/templates/react-vite/src/pages/Home.tsx +45 -0
- package/templates/react-vite/src/pages/NotFound.tsx +24 -0
- package/templates/react-vite/src/pages/UserProfile.tsx +40 -0
- package/templates/react-vite/src/router.tsx +33 -0
- package/templates/react-vite/src/types/api.ts +20 -0
- package/templates/react-vite/src/utils/helpers.ts +51 -0
- package/templates/react-vite/src/utils/storage.ts +35 -0
- package/templates/react-vite/src/vite-env.d.ts +11 -0
- package/templates/react-vite/template.json +20 -0
- package/templates/{bases/react-vite-base/tsconfig.json → react-vite/tsconfig.app.json} +10 -3
- package/templates/react-vite/tsconfig.json +7 -0
- package/templates/react-vite/tsconfig.node.json +26 -0
- package/templates/react-vite/vite.config.ts +13 -0
- package/modules/auth/authjs-express/files/lib/auth.ts +0 -40
- package/modules/auth/authjs-express/files/routes/auth.ts +0 -12
- package/modules/auth/authjs-express/module.json +0 -39
- package/modules/auth/authjs-nextjs/files/api/auth/[...nextauth]/route.ts +0 -3
- package/modules/auth/authjs-nextjs/files/lib/auth.ts +0 -43
- package/modules/auth/authjs-nextjs/module.json +0 -38
- package/modules/auth/nextauth/files/app-router/api/auth/[...nextauth]/route.ts +0 -6
- package/modules/auth/nextauth/files/lib/auth.ts +0 -82
- package/modules/auth/nextauth/files/pages-router/api/auth/[...nextauth].ts +0 -4
- package/modules/auth/nextauth/module.json +0 -50
- package/modules/database/drizzle-postgresql/files/drizzle.config.ts +0 -10
- package/modules/database/drizzle-postgresql/files/lib/db.ts +0 -7
- package/modules/database/drizzle-postgresql/files/lib/schema.ts +0 -8
- package/modules/database/drizzle-postgresql/module.json +0 -34
- package/templates/bases/express-base/.env.example +0 -2
- package/templates/bases/express-base/package.json +0 -23
- package/templates/bases/express-base/src/index.ts +0 -27
- package/templates/bases/express-base/tsconfig.json +0 -17
- package/templates/bases/nextjs-base/package-lock.json +0 -6538
- package/templates/bases/react-vite-base/package.json +0 -27
- package/templates/bases/react-vite-base/src/App.css +0 -14
- package/templates/bases/react-vite-base/src/App.tsx +0 -23
- package/templates/bases/react-vite-base/src/index.css +0 -68
- package/templates/bases/react-vite-base/src/main.tsx +0 -10
- package/templates/bases/react-vite-base/src/vite-env.d.ts +0 -1
- package/templates/bases/react-vite-base/template.json +0 -5
- package/templates/bases/react-vite-base/vite.config.ts +0 -7
- /package/templates/{bases/nextjs-base → nextjs}/README.md +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/app/favicon.ico +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/app/globals.css +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/app/layout.tsx +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/eslint.config.mjs +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/next.config.ts +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/package.json +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/postcss.config.mjs +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/public/file.svg +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/public/globe.svg +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/public/next.svg +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/public/vercel.svg +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/public/window.svg +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/tsconfig.json +0 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { SEO } from '../components/SEO';
|
|
2
|
+
|
|
3
|
+
export default function Home() {
|
|
4
|
+
return (
|
|
5
|
+
<>
|
|
6
|
+
<SEO title="Home" />
|
|
7
|
+
<div className="flex min-h-screen items-center justify-center bg-black">
|
|
8
|
+
<main className="flex min-h-screen w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-black sm:items-start">
|
|
9
|
+
<div className="text-2xl font-bold text-white">Stackkit</div>
|
|
10
|
+
|
|
11
|
+
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
|
|
12
|
+
<h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-zinc-50">
|
|
13
|
+
To get started, edit the Home.tsx file.
|
|
14
|
+
</h1>
|
|
15
|
+
<p className="max-w-md text-lg leading-8 text-zinc-400">
|
|
16
|
+
This template includes React Router, TanStack Query, Axios, and Tailwind CSS. Check
|
|
17
|
+
out the{' '}
|
|
18
|
+
<a href="/about" className="font-medium text-zinc-50 hover:underline">
|
|
19
|
+
About
|
|
20
|
+
</a>{' '}
|
|
21
|
+
page to learn more about the included features.
|
|
22
|
+
</p>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
|
|
26
|
+
<a
|
|
27
|
+
className="flex h-12 w-full items-center justify-center rounded-full bg-white text-black px-5 transition-colors hover:bg-zinc-200 md:w-39.5"
|
|
28
|
+
href="https://react.dev"
|
|
29
|
+
target="_blank"
|
|
30
|
+
rel="noopener noreferrer"
|
|
31
|
+
>
|
|
32
|
+
Get Started
|
|
33
|
+
</a>
|
|
34
|
+
<a
|
|
35
|
+
className="flex h-12 w-full items-center justify-center rounded-full px-5 transition-colors hover:border-transparent bg-zinc-900 md:w-39.5 dark:text-white text-black"
|
|
36
|
+
href="/about"
|
|
37
|
+
>
|
|
38
|
+
Documentation
|
|
39
|
+
</a>
|
|
40
|
+
</div>
|
|
41
|
+
</main>
|
|
42
|
+
</div>
|
|
43
|
+
</>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Link } from 'react-router';
|
|
2
|
+
import { SEO } from '../components/SEO';
|
|
3
|
+
|
|
4
|
+
export default function NotFound() {
|
|
5
|
+
return (
|
|
6
|
+
<>
|
|
7
|
+
<SEO title="404 - Page Not Found" description="The page you're looking for doesn't exist" />
|
|
8
|
+
|
|
9
|
+
<div className="flex min-h-screen items-center justify-center bg-black">
|
|
10
|
+
<div className="text-center px-6">
|
|
11
|
+
<h1 className="text-8xl font-bold text-white mb-4">404</h1>
|
|
12
|
+
<h2 className="text-3xl font-semibold text-zinc-50 mb-4">Page Not Found</h2>
|
|
13
|
+
<p className="text-lg text-zinc-400 mb-8">The page you're looking for doesn't exist.</p>
|
|
14
|
+
<Link
|
|
15
|
+
to="/"
|
|
16
|
+
className="inline-flex h-12 items-center justify-center rounded-full bg-white text-black px-8 font-medium transition-colors hover:bg-zinc-200"
|
|
17
|
+
>
|
|
18
|
+
Go Home
|
|
19
|
+
</Link>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
</>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useQuery } from '@tanstack/react-query';
|
|
2
|
+
import { useLoaderData, useParams } from 'react-router';
|
|
3
|
+
import { userService } from '../api/services/user.service';
|
|
4
|
+
|
|
5
|
+
type User = { id?: string; name?: string; email?: string; avatar?: string; [key: string]: any };
|
|
6
|
+
|
|
7
|
+
export default function UserProfile() {
|
|
8
|
+
const loaderUser = useLoaderData() as User | undefined;
|
|
9
|
+
const { userId } = useParams();
|
|
10
|
+
|
|
11
|
+
const { data: user = loaderUser ?? {} } = useQuery({
|
|
12
|
+
queryKey: ['user', userId],
|
|
13
|
+
queryFn: async () => {
|
|
14
|
+
if (!userId) throw new Error('Missing user id');
|
|
15
|
+
return await userService.getUser(userId);
|
|
16
|
+
},
|
|
17
|
+
initialData: loaderUser,
|
|
18
|
+
staleTime: 1000 * 60,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<div className="min-h-screen bg-black text-white flex items-center justify-center">
|
|
23
|
+
<div className="max-w-xl p-8 bg-zinc-900 rounded-md shadow">
|
|
24
|
+
<div className="flex items-center gap-4">
|
|
25
|
+
{user.avatar ? (
|
|
26
|
+
<img src={user.avatar} alt={user.name} className="w-16 h-16 rounded-full" />
|
|
27
|
+
) : (
|
|
28
|
+
<div className="w-16 h-16 rounded-full bg-zinc-700 flex items-center justify-center text-xl">
|
|
29
|
+
{user.name?.[0] ?? 'U'}
|
|
30
|
+
</div>
|
|
31
|
+
)}
|
|
32
|
+
<div>
|
|
33
|
+
<h2 className="text-2xl font-semibold">{user.name}</h2>
|
|
34
|
+
<p className="text-sm text-zinc-400">{user.email}</p>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createBrowserRouter } from 'react-router';
|
|
2
|
+
import { userService } from './api/services/user.service';
|
|
3
|
+
import { ErrorBoundary } from './components/ErrorBoundary';
|
|
4
|
+
import Layout from './components/Layout';
|
|
5
|
+
import About from './pages/About';
|
|
6
|
+
import Home from './pages/Home';
|
|
7
|
+
import NotFound from './pages/NotFound';
|
|
8
|
+
import UserProfile from './pages/UserProfile';
|
|
9
|
+
|
|
10
|
+
export const router = createBrowserRouter([
|
|
11
|
+
{
|
|
12
|
+
path: '/',
|
|
13
|
+
Component: Layout,
|
|
14
|
+
errorElement: <ErrorBoundary />,
|
|
15
|
+
children: [
|
|
16
|
+
{ index: true, Component: Home },
|
|
17
|
+
{ path: 'about', Component: About },
|
|
18
|
+
{
|
|
19
|
+
path: 'users/:userId',
|
|
20
|
+
loader: async ({ params }) => {
|
|
21
|
+
const id = params.userId;
|
|
22
|
+
if (!id) throw new Response('Missing user id', { status: 400 });
|
|
23
|
+
const user = await userService.getUser(id);
|
|
24
|
+
return user;
|
|
25
|
+
},
|
|
26
|
+
Component: UserProfile,
|
|
27
|
+
},
|
|
28
|
+
{ path: '*', Component: NotFound },
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
export default router;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface ApiResponse<T = unknown> {
|
|
2
|
+
data: T;
|
|
3
|
+
message?: string;
|
|
4
|
+
status: number;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface PaginatedResponse<T> {
|
|
8
|
+
data: T[];
|
|
9
|
+
total: number;
|
|
10
|
+
page: number;
|
|
11
|
+
pageSize: number;
|
|
12
|
+
totalPages: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ApiError {
|
|
16
|
+
message: string;
|
|
17
|
+
code?: string;
|
|
18
|
+
status?: number;
|
|
19
|
+
errors?: Record<string, string[]>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export function cn(...classes: (string | boolean | undefined | null)[]): string {
|
|
2
|
+
return classes.filter(Boolean).join(' ');
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function formatDate(date: Date | string): string {
|
|
6
|
+
const d = typeof date === 'string' ? new Date(date) : date;
|
|
7
|
+
return d.toLocaleDateString('en-US', {
|
|
8
|
+
year: 'numeric',
|
|
9
|
+
month: 'long',
|
|
10
|
+
day: 'numeric',
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function truncate(str: string, maxLength: number): string {
|
|
15
|
+
if (str.length <= maxLength) return str;
|
|
16
|
+
return str.slice(0, maxLength) + '...';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function delay(ms: number): Promise<void> {
|
|
20
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function debounce<T extends (...args: never[]) => unknown>(
|
|
24
|
+
func: T,
|
|
25
|
+
wait: number
|
|
26
|
+
): (...args: Parameters<T>) => void {
|
|
27
|
+
let timeout: ReturnType<typeof setTimeout> | null = null;
|
|
28
|
+
|
|
29
|
+
return function executedFunction(...args: Parameters<T>) {
|
|
30
|
+
const later = () => {
|
|
31
|
+
timeout = null;
|
|
32
|
+
func(...args);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
if (timeout) clearTimeout(timeout);
|
|
36
|
+
timeout = setTimeout(later, wait);
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function capitalize(str: string): string {
|
|
41
|
+
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function slugify(str: string): string {
|
|
45
|
+
return str
|
|
46
|
+
.toLowerCase()
|
|
47
|
+
.trim()
|
|
48
|
+
.replace(/[^\w\s-]/g, '')
|
|
49
|
+
.replace(/[\s_-]+/g, '-')
|
|
50
|
+
.replace(/^-+|-+$/g, '');
|
|
51
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export const storage = {
|
|
2
|
+
get: <T>(key: string, defaultValue?: T): T | null => {
|
|
3
|
+
try {
|
|
4
|
+
const item = localStorage.getItem(key);
|
|
5
|
+
return item ? JSON.parse(item) : (defaultValue ?? null);
|
|
6
|
+
} catch (error) {
|
|
7
|
+
console.error('Error reading from localStorage:', error);
|
|
8
|
+
return defaultValue ?? null;
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
set: <T>(key: string, value: T): void => {
|
|
13
|
+
try {
|
|
14
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
15
|
+
} catch (error) {
|
|
16
|
+
console.error('Error writing to localStorage:', error);
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
remove: (key: string): void => {
|
|
21
|
+
try {
|
|
22
|
+
localStorage.removeItem(key);
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.error('Error removing from localStorage:', error);
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
clear: (): void => {
|
|
29
|
+
try {
|
|
30
|
+
localStorage.clear();
|
|
31
|
+
} catch (error) {
|
|
32
|
+
console.error('Error clearing localStorage:', error);
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-vite-base",
|
|
3
|
+
"displayName": "React (Vite)",
|
|
4
|
+
"framework": "react-vite",
|
|
5
|
+
"description": "Production-ready React 19 + Vite with TypeScript, Router, TanStack Query, and more",
|
|
6
|
+
"files": [
|
|
7
|
+
"src/",
|
|
8
|
+
"public/",
|
|
9
|
+
".env.example",
|
|
10
|
+
".gitignore",
|
|
11
|
+
"eslint.config.js",
|
|
12
|
+
"index.html",
|
|
13
|
+
"package.json",
|
|
14
|
+
"README.md",
|
|
15
|
+
"tsconfig.json",
|
|
16
|
+
"tsconfig.app.json",
|
|
17
|
+
"tsconfig.node.json",
|
|
18
|
+
"vite.config.ts"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
"
|
|
3
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
4
|
+
"target": "ES2022",
|
|
4
5
|
"useDefineForClassFields": true,
|
|
5
|
-
"lib": ["
|
|
6
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
6
7
|
"module": "ESNext",
|
|
8
|
+
"types": ["vite/client"],
|
|
7
9
|
"skipLibCheck": true,
|
|
10
|
+
|
|
11
|
+
/* Bundler mode */
|
|
8
12
|
"moduleResolution": "bundler",
|
|
9
13
|
"allowImportingTsExtensions": true,
|
|
10
|
-
"
|
|
14
|
+
"verbatimModuleSyntax": true,
|
|
11
15
|
"moduleDetection": "force",
|
|
12
16
|
"noEmit": true,
|
|
13
17
|
"jsx": "react-jsx",
|
|
18
|
+
|
|
19
|
+
/* Linting */
|
|
14
20
|
"strict": true,
|
|
15
21
|
"noUnusedLocals": true,
|
|
16
22
|
"noUnusedParameters": true,
|
|
23
|
+
"erasableSyntaxOnly": true,
|
|
17
24
|
"noFallthroughCasesInSwitch": true,
|
|
18
25
|
"noUncheckedSideEffectImports": true
|
|
19
26
|
},
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
|
4
|
+
"target": "ES2023",
|
|
5
|
+
"lib": ["ES2023"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"types": ["node"],
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
|
|
10
|
+
/* Bundler mode */
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"allowImportingTsExtensions": true,
|
|
13
|
+
"verbatimModuleSyntax": true,
|
|
14
|
+
"moduleDetection": "force",
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
|
|
17
|
+
/* Linting */
|
|
18
|
+
"strict": true,
|
|
19
|
+
"noUnusedLocals": true,
|
|
20
|
+
"noUnusedParameters": true,
|
|
21
|
+
"erasableSyntaxOnly": true,
|
|
22
|
+
"noFallthroughCasesInSwitch": true,
|
|
23
|
+
"noUncheckedSideEffectImports": true
|
|
24
|
+
},
|
|
25
|
+
"include": ["vite.config.ts"]
|
|
26
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import tailwindcss from '@tailwindcss/vite';
|
|
2
|
+
import react from '@vitejs/plugin-react';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { defineConfig } from 'vite';
|
|
5
|
+
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
plugins: [react(), tailwindcss()],
|
|
8
|
+
resolve: {
|
|
9
|
+
alias: {
|
|
10
|
+
'@': path.resolve(__dirname, './src'),
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
});
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import Credentials from '@auth/core/providers/credentials';
|
|
2
|
-
|
|
3
|
-
export const authConfig = {
|
|
4
|
-
secret: process.env.AUTH_SECRET,
|
|
5
|
-
trustHost: true,
|
|
6
|
-
providers: [
|
|
7
|
-
// GitHub OAuth Provider
|
|
8
|
-
// Uncomment and add GITHUB_ID and GITHUB_SECRET to .env
|
|
9
|
-
// GitHub({
|
|
10
|
-
// clientId: process.env.GITHUB_ID!,
|
|
11
|
-
// clientSecret: process.env.GITHUB_SECRET!,
|
|
12
|
-
// }),
|
|
13
|
-
|
|
14
|
-
// Google OAuth Provider
|
|
15
|
-
// Uncomment and add GOOGLE_ID and GOOGLE_SECRET to .env
|
|
16
|
-
// Google({
|
|
17
|
-
// clientId: process.env.GOOGLE_ID!,
|
|
18
|
-
// clientSecret: process.env.GOOGLE_SECRET!,
|
|
19
|
-
// }),
|
|
20
|
-
|
|
21
|
-
// Credentials Provider (email/password)
|
|
22
|
-
Credentials({
|
|
23
|
-
credentials: {
|
|
24
|
-
email: { label: 'Email', type: 'email' },
|
|
25
|
-
password: { label: 'Password', type: 'password' },
|
|
26
|
-
},
|
|
27
|
-
authorize: async (credentials) => {
|
|
28
|
-
// Add your own authentication logic here
|
|
29
|
-
if (credentials?.email === 'demo@example.com' && credentials?.password === 'demo') {
|
|
30
|
-
return {
|
|
31
|
-
id: '1',
|
|
32
|
-
name: 'Demo User',
|
|
33
|
-
email: 'demo@example.com',
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
return null;
|
|
37
|
-
},
|
|
38
|
-
}),
|
|
39
|
-
],
|
|
40
|
-
};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { Auth } from '@auth/core';
|
|
2
|
-
import { Router } from 'express';
|
|
3
|
-
import { authConfig } from '../lib/auth';
|
|
4
|
-
|
|
5
|
-
const router = Router();
|
|
6
|
-
|
|
7
|
-
router.all('/auth/*', async (req, res) => {
|
|
8
|
-
const response = await Auth(req, authConfig);
|
|
9
|
-
return res.status(response.status).json(response.body);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
export default router;
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "auth",
|
|
3
|
-
"displayName": "Auth.js (Express)",
|
|
4
|
-
"description": "Authentication with Auth.js for Express",
|
|
5
|
-
"category": "auth",
|
|
6
|
-
"supportedFrameworks": ["express"],
|
|
7
|
-
"dependencies": {
|
|
8
|
-
"@auth/express": "^0.7.6",
|
|
9
|
-
"@auth/core": "^0.37.4"
|
|
10
|
-
},
|
|
11
|
-
"envVars": [
|
|
12
|
-
{
|
|
13
|
-
"key": "AUTH_SECRET",
|
|
14
|
-
"value": "",
|
|
15
|
-
"description": "Secret for encrypting tokens. Generate with: openssl rand -base64 32",
|
|
16
|
-
"required": true
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
"key": "AUTH_TRUST_HOST",
|
|
20
|
-
"value": "true",
|
|
21
|
-
"description": "Trust the host header (required for Express)",
|
|
22
|
-
"required": true
|
|
23
|
-
}
|
|
24
|
-
],
|
|
25
|
-
"patches": [
|
|
26
|
-
{
|
|
27
|
-
"type": "create-file",
|
|
28
|
-
"description": "Create Auth.js configuration",
|
|
29
|
-
"source": "lib/auth.ts",
|
|
30
|
-
"destination": "src/lib/auth.ts"
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
"type": "create-file",
|
|
34
|
-
"description": "Create auth routes",
|
|
35
|
-
"source": "routes/auth.ts",
|
|
36
|
-
"destination": "src/routes/auth.ts"
|
|
37
|
-
}
|
|
38
|
-
]
|
|
39
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import NextAuth from 'next-auth';
|
|
2
|
-
import Credentials from 'next-auth/providers/credentials';
|
|
3
|
-
|
|
4
|
-
export const { handlers, signIn, signOut, auth } = NextAuth({
|
|
5
|
-
providers: [
|
|
6
|
-
// GitHub OAuth Provider
|
|
7
|
-
// Uncomment and add GITHUB_ID and GITHUB_SECRET to .env
|
|
8
|
-
// GitHub({
|
|
9
|
-
// clientId: process.env.GITHUB_ID!,
|
|
10
|
-
// clientSecret: process.env.GITHUB_SECRET!,
|
|
11
|
-
// }),
|
|
12
|
-
|
|
13
|
-
// Google OAuth Provider
|
|
14
|
-
// Uncomment and add GOOGLE_ID and GOOGLE_SECRET to .env
|
|
15
|
-
// Google({
|
|
16
|
-
// clientId: process.env.GOOGLE_ID!,
|
|
17
|
-
// clientSecret: process.env.GOOGLE_SECRET!,
|
|
18
|
-
// }),
|
|
19
|
-
|
|
20
|
-
// Credentials Provider (email/password)
|
|
21
|
-
Credentials({
|
|
22
|
-
credentials: {
|
|
23
|
-
email: { label: 'Email', type: 'email' },
|
|
24
|
-
password: { label: 'Password', type: 'password' },
|
|
25
|
-
},
|
|
26
|
-
authorize: async (credentials) => {
|
|
27
|
-
// Add your own authentication logic here
|
|
28
|
-
// This is just a demo - DO NOT use in production
|
|
29
|
-
if (credentials?.email === 'demo@example.com' && credentials?.password === 'demo') {
|
|
30
|
-
return {
|
|
31
|
-
id: '1',
|
|
32
|
-
name: 'Demo User',
|
|
33
|
-
email: 'demo@example.com',
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
return null;
|
|
37
|
-
},
|
|
38
|
-
}),
|
|
39
|
-
],
|
|
40
|
-
pages: {
|
|
41
|
-
signIn: '/auth/signin',
|
|
42
|
-
},
|
|
43
|
-
});
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "auth",
|
|
3
|
-
"displayName": "Auth.js v5 (Next.js)",
|
|
4
|
-
"description": "Modern authentication with Auth.js v5 (NextAuth successor)",
|
|
5
|
-
"category": "auth",
|
|
6
|
-
"supportedFrameworks": ["nextjs"],
|
|
7
|
-
"dependencies": {
|
|
8
|
-
"next-auth": "^5.0.0-beta.25"
|
|
9
|
-
},
|
|
10
|
-
"envVars": [
|
|
11
|
-
{
|
|
12
|
-
"key": "AUTH_SECRET",
|
|
13
|
-
"value": "",
|
|
14
|
-
"description": "Secret for encrypting tokens. Generate with: openssl rand -base64 32",
|
|
15
|
-
"required": true
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
"key": "AUTH_URL",
|
|
19
|
-
"value": "http://localhost:3000",
|
|
20
|
-
"description": "Canonical URL of your site (change in production)",
|
|
21
|
-
"required": false
|
|
22
|
-
}
|
|
23
|
-
],
|
|
24
|
-
"patches": [
|
|
25
|
-
{
|
|
26
|
-
"type": "create-file",
|
|
27
|
-
"description": "Create Auth.js configuration",
|
|
28
|
-
"source": "lib/auth.ts",
|
|
29
|
-
"destination": "{{lib}}/auth.ts"
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
"type": "create-file",
|
|
33
|
-
"description": "Create Auth.js API route",
|
|
34
|
-
"source": "api/auth/[...nextauth]/route.ts",
|
|
35
|
-
"destination": "{{router}}/api/auth/[...nextauth]/route.ts"
|
|
36
|
-
}
|
|
37
|
-
]
|
|
38
|
-
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { AuthOptions } from 'next-auth';
|
|
2
|
-
import CredentialsProvider from 'next-auth/providers/credentials';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* NextAuth.js Configuration
|
|
6
|
-
*
|
|
7
|
-
* Configure authentication providers and options here.
|
|
8
|
-
* See: https://next-auth.js.org/configuration/options
|
|
9
|
-
*/
|
|
10
|
-
export const authOptions: AuthOptions = {
|
|
11
|
-
providers: [
|
|
12
|
-
// GitHub OAuth Provider
|
|
13
|
-
// Uncomment and add GITHUB_ID and GITHUB_SECRET to .env
|
|
14
|
-
// GithubProvider({
|
|
15
|
-
// clientId: process.env.GITHUB_ID!,
|
|
16
|
-
// clientSecret: process.env.GITHUB_SECRET!,
|
|
17
|
-
// }),
|
|
18
|
-
|
|
19
|
-
// Google OAuth Provider
|
|
20
|
-
// Uncomment and add GOOGLE_ID and GOOGLE_SECRET to .env
|
|
21
|
-
// GoogleProvider({
|
|
22
|
-
// clientId: process.env.GOOGLE_ID!,
|
|
23
|
-
// clientSecret: process.env.GOOGLE_SECRET!,
|
|
24
|
-
// }),
|
|
25
|
-
|
|
26
|
-
// Credentials Provider (email/password)
|
|
27
|
-
// Replace with your own authentication logic
|
|
28
|
-
CredentialsProvider({
|
|
29
|
-
name: 'Credentials',
|
|
30
|
-
credentials: {
|
|
31
|
-
email: { label: 'Email', type: 'email', placeholder: 'user@example.com' },
|
|
32
|
-
password: { label: 'Password', type: 'password' },
|
|
33
|
-
},
|
|
34
|
-
async authorize(credentials) {
|
|
35
|
-
// Add your own authentication logic here
|
|
36
|
-
// This is just a demo - DO NOT use in production
|
|
37
|
-
if (credentials?.email === 'demo@example.com' && credentials?.password === 'demo') {
|
|
38
|
-
return {
|
|
39
|
-
id: '1',
|
|
40
|
-
name: 'Demo User',
|
|
41
|
-
email: 'demo@example.com',
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
return null;
|
|
45
|
-
},
|
|
46
|
-
}),
|
|
47
|
-
],
|
|
48
|
-
|
|
49
|
-
// Database adapter (optional)
|
|
50
|
-
// Uncomment to persist sessions in database
|
|
51
|
-
// adapter: PrismaAdapter(prisma),
|
|
52
|
-
|
|
53
|
-
session: {
|
|
54
|
-
strategy: 'jwt',
|
|
55
|
-
},
|
|
56
|
-
|
|
57
|
-
pages: {
|
|
58
|
-
signIn: '/auth/signin',
|
|
59
|
-
// signOut: '/auth/signout',
|
|
60
|
-
// error: '/auth/error',
|
|
61
|
-
// verifyRequest: '/auth/verify-request',
|
|
62
|
-
// newUser: '/auth/new-user'
|
|
63
|
-
},
|
|
64
|
-
|
|
65
|
-
callbacks: {
|
|
66
|
-
async jwt({ token, user }) {
|
|
67
|
-
if (user) {
|
|
68
|
-
token.id = user.id;
|
|
69
|
-
}
|
|
70
|
-
return token;
|
|
71
|
-
},
|
|
72
|
-
async session({ session, token }) {
|
|
73
|
-
if (session.user) {
|
|
74
|
-
session.user.id = token.id as string;
|
|
75
|
-
}
|
|
76
|
-
return session;
|
|
77
|
-
},
|
|
78
|
-
},
|
|
79
|
-
|
|
80
|
-
// Enable debug messages in development
|
|
81
|
-
debug: process.env.NODE_ENV === 'development',
|
|
82
|
-
};
|