stackkit 0.2.6 → 0.2.8

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 (84) hide show
  1. package/README.md +87 -12
  2. package/dist/cli/create.js +1 -2
  3. package/dist/cli/list.js +73 -83
  4. package/dist/index.js +25 -44
  5. package/dist/lib/constants.d.ts +110 -0
  6. package/dist/lib/constants.js +112 -0
  7. package/dist/lib/env/env-editor.js +41 -47
  8. package/dist/lib/fs/files.d.ts +0 -1
  9. package/dist/lib/fs/files.js +12 -40
  10. package/dist/lib/generation/code-generator.d.ts +4 -1
  11. package/dist/lib/generation/code-generator.js +36 -10
  12. package/dist/lib/pm/package-manager.d.ts +1 -1
  13. package/dist/lib/pm/package-manager.js +130 -14
  14. package/dist/lib/ui/logger.d.ts +8 -1
  15. package/dist/lib/ui/logger.js +60 -3
  16. package/dist/lib/utils/fs-helpers.d.ts +12 -0
  17. package/dist/lib/utils/fs-helpers.js +61 -0
  18. package/dist/lib/utils/json-loader.d.ts +6 -0
  19. package/dist/lib/utils/json-loader.js +34 -0
  20. package/dist/lib/utils/module-loader.d.ts +9 -0
  21. package/dist/lib/utils/module-loader.js +98 -0
  22. package/dist/lib/utils/package-root.d.ts +1 -0
  23. package/dist/lib/utils/package-root.js +75 -2
  24. package/dist/lib/utils/path-resolver.d.ts +9 -0
  25. package/dist/lib/utils/path-resolver.js +44 -0
  26. package/modules/auth/authjs/files/nextjs/api/auth/[...nextauth]/route.ts +3 -0
  27. package/modules/auth/authjs/files/nextjs/proxy.ts +1 -0
  28. package/modules/auth/authjs/files/shared/lib/auth.ts +119 -0
  29. package/modules/auth/authjs/files/{prisma → shared/prisma}/schema.prisma +11 -1
  30. package/modules/auth/authjs/generator.json +18 -8
  31. package/modules/auth/better-auth/files/express/middlewares/authorize.ts +54 -0
  32. package/modules/auth/better-auth/files/express/types/express.d.ts +16 -0
  33. package/modules/auth/better-auth/files/nextjs/lib/auth/auth-guards.ts +31 -0
  34. package/modules/auth/better-auth/files/nextjs/proxy.ts +34 -0
  35. package/modules/auth/better-auth/files/{lib → shared/lib}/auth-client.ts +1 -1
  36. package/modules/auth/better-auth/files/{lib → shared/lib}/auth.ts +46 -20
  37. package/modules/auth/better-auth/files/{prisma → shared/prisma}/schema.prisma +11 -2
  38. package/modules/auth/better-auth/generator.json +74 -19
  39. package/modules/database/mongoose/generator.json +16 -2
  40. package/modules/database/prisma/files/lib/prisma.ts +1 -1
  41. package/modules/database/prisma/files/prisma/schema.prisma +1 -2
  42. package/modules/database/prisma/generator.json +8 -1
  43. package/package.json +2 -2
  44. package/templates/express/env.example +2 -1
  45. package/templates/express/package.json +3 -4
  46. package/templates/express/src/app.ts +18 -25
  47. package/templates/express/src/config/cors.ts +12 -0
  48. package/templates/express/src/config/helmet.ts +5 -0
  49. package/templates/express/src/config/logger.ts +6 -0
  50. package/templates/express/src/config/rate-limit.ts +11 -0
  51. package/templates/express/src/{features → modules}/health/health.route.ts +1 -1
  52. package/templates/express/src/routes/index.ts +12 -0
  53. package/templates/express/src/shared/errors/api-error.ts +14 -0
  54. package/templates/express/src/shared/errors/error-codes.ts +9 -0
  55. package/templates/express/src/shared/logger/logger.ts +20 -0
  56. package/templates/express/src/{middlewares → shared/middlewares}/error.middleware.ts +1 -1
  57. package/templates/express/src/shared/middlewares/not-found.middleware.ts +9 -0
  58. package/templates/express/src/shared/utils/async-handler.ts +9 -0
  59. package/templates/express/src/shared/utils/pagination.ts +6 -0
  60. package/templates/express/src/shared/utils/response.ts +9 -0
  61. package/templates/express/tsconfig.json +9 -3
  62. package/templates/react/src/app/layouts/dashboard-layout.tsx +8 -0
  63. package/templates/react/src/app/layouts/public-layout.tsx +5 -0
  64. package/templates/react/src/app/providers.tsx +20 -0
  65. package/templates/react/src/app/router.tsx +21 -0
  66. package/templates/react/src/{pages/About.tsx → features/about/pages/about.tsx} +1 -1
  67. package/templates/react/src/{pages/Home.tsx → features/home/pages/home.tsx} +1 -1
  68. package/templates/react/src/main.tsx +2 -2
  69. package/templates/react/src/{api/client.ts → shared/api/http.ts} +1 -1
  70. package/templates/react/src/{pages/NotFound.tsx → shared/pages/not-found.tsx} +1 -1
  71. package/dist/lib/git-utils.d.ts +0 -1
  72. package/dist/lib/git-utils.js +0 -29
  73. package/modules/auth/authjs/files/api/auth/[...nextauth]/route.ts +0 -2
  74. package/modules/auth/authjs/files/lib/auth.ts +0 -22
  75. /package/modules/auth/better-auth/files/{api → nextjs/api}/auth/[...all]/route.ts +0 -0
  76. /package/modules/auth/better-auth/files/{lib → shared/lib/email}/email-service.ts +0 -0
  77. /package/modules/auth/better-auth/files/{lib → shared/lib/email}/email-templates.ts +0 -0
  78. /package/templates/express/src/{features → modules}/health/health.controller.ts +0 -0
  79. /package/templates/express/src/{features → modules}/health/health.service.ts +0 -0
  80. /package/templates/react/src/{components/ErrorBoundary.tsx → shared/components/error-boundary.tsx} +0 -0
  81. /package/templates/react/src/{components/Layout.tsx → shared/components/layout.tsx} +0 -0
  82. /package/templates/react/src/{components/Loading.tsx → shared/components/loading.tsx} +0 -0
  83. /package/templates/react/src/{components/SEO.tsx → shared/components/seo.tsx} +0 -0
  84. /package/templates/react/src/{lib/queryClient.ts → shared/lib/query-client.ts} +0 -0
@@ -6,12 +6,26 @@
6
6
  {
7
7
  "type": "create-file",
8
8
  "source": "lib/mongoose.ts",
9
- "destination": "lib/mongoose.ts"
9
+ "destination": "server/database/mongoose.ts",
10
+ "condition": { "framework": ["nextjs"] }
11
+ },
12
+ {
13
+ "type": "create-file",
14
+ "source": "lib/mongoose.ts",
15
+ "destination": "src/database/mongoose.ts",
16
+ "condition": { "framework": ["express"] }
17
+ },
18
+ {
19
+ "type": "create-file",
20
+ "source": "models/health.ts",
21
+ "destination": "src/modules/health/health.model.ts",
22
+ "condition": { "framework": ["express"] }
10
23
  },
11
24
  {
12
25
  "type": "create-file",
13
26
  "source": "models/health.ts",
14
- "destination": "models/health.ts"
27
+ "destination": "server/database/models/health.model.ts",
28
+ "condition": { "framework": ["nextjs"] }
15
29
  },
16
30
  {
17
31
  "type": "patch-file",
@@ -1,5 +1,5 @@
1
+ import { PrismaClient } from "@prisma/client";
1
2
  import 'dotenv/config';
2
- import { PrismaClient } from './generated/prisma/client'
3
3
 
4
4
  const globalForPrisma = globalThis as unknown as {
5
5
  prisma: PrismaClient | undefined
@@ -1,6 +1,5 @@
1
1
  generator client {
2
- provider = "prisma-client"
3
- output = "../lib/generated/prisma"
2
+ provider = "prisma-client-js"
4
3
  }
5
4
 
6
5
  datasource db {
@@ -16,7 +16,14 @@
16
16
  {
17
17
  "type": "create-file",
18
18
  "source": "lib/prisma.ts",
19
- "destination": "lib/prisma.ts"
19
+ "destination": "server/database/prisma.ts",
20
+ "condition": { "framework": ["nextjs"] }
21
+ },
22
+ {
23
+ "type": "create-file",
24
+ "source": "lib/prisma.ts",
25
+ "destination": "src/database/prisma.ts",
26
+ "condition": { "framework": ["express"] }
20
27
  },
21
28
  {
22
29
  "type": "add-dependency",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stackkit",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "Production-ready CLI to create and extend JavaScript or TypeScript apps with modular stacks.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -80,4 +80,4 @@
80
80
  "@types/validate-npm-package-name": "^4.0.2",
81
81
  "typescript": "^5.3.3"
82
82
  }
83
- }
83
+ }
@@ -1,2 +1,3 @@
1
1
  PORT=3000
2
- NODE_ENV=development
2
+ NODE_ENV=development
3
+ CORS_ORIGIN="http://localhost:3000"
@@ -8,15 +8,15 @@
8
8
  "build": "tsc",
9
9
  "lint": "eslint src --ext .ts",
10
10
  "lint:fix": "eslint src --ext .ts --fix",
11
- "start": "node dist/server.js",
12
- "start:prod": "cross-env NODE_ENV=production node dist/server.js"
11
+ "start": "node dist/server.js"
13
12
  },
14
13
  "dependencies": {
15
14
  "cors": "^2.8.5",
16
15
  "dotenv": "^17.2.3",
17
16
  "express": "^5.2.1",
18
17
  "helmet": "^8.1.0",
19
- "morgan": "^1.10.1"
18
+ "morgan": "^1.10.1",
19
+ "express-rate-limit": "^6.10.0"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@types/cors": "^2.8.19",
@@ -25,7 +25,6 @@
25
25
  "@types/node": "^25.0.8",
26
26
  "@typescript-eslint/eslint-plugin": "^8.53.0",
27
27
  "@typescript-eslint/parser": "^8.53.0",
28
- "cross-env": "^10.1.0",
29
28
  "eslint": "^9.39.2",
30
29
  "tsx": "^4.21.0",
31
30
  "typescript": "^5.9.3"
@@ -1,28 +1,26 @@
1
- import cors from "cors";
2
- import express, { Application, NextFunction, Request, Response } from "express";
3
- import helmet from "helmet";
4
- import morgan from "morgan";
5
- import { env } from "./config/env";
6
- import { authRoutes } from "./features/health/health.route";
7
- import { errorHandler } from "./middlewares/error.middleware";
1
+ import express, { Application, Request, Response } from "express";
2
+ import { cors } from "./config/cors";
3
+ import { helmet } from "./config/helmet";
4
+ import { logger } from "./config/logger";
5
+ import { limiter } from "./config/rate-limit";
6
+ import { apiRoutes } from "./routes";
7
+ import { errorHandler } from "./shared/middlewares/error.middleware";
8
+ import { notFound } from "./shared/middlewares/not-found.middleware";
8
9
 
9
10
  // app initialization
10
11
  const app: Application = express();
11
12
  app.use(express.json());
12
13
 
13
- // security headers
14
- app.use(helmet());
14
+ app.use(helmet);
15
+ app.use(logger);
16
+ app.use(cors);
17
+ app.use(limiter);
15
18
 
16
- // logging
17
- if (env.isProduction) {
18
- app.use(morgan("combined"));
19
- } else {
20
- app.use(morgan("dev"));
19
+ // trust proxy when behind proxies (load balancers)
20
+ if (process.env.NODE_ENV === "production") {
21
+ app.set("trust proxy", 1);
21
22
  }
22
23
 
23
- // cors configuration
24
- app.use(cors());
25
-
26
24
  // Home page route
27
25
  app.get("/", (_req: Request, res: Response) => {
28
26
  res.status(200).json({
@@ -34,16 +32,11 @@ app.get("/", (_req: Request, res: Response) => {
34
32
  });
35
33
  });
36
34
 
37
- // routes
38
- app.use("/api/health", authRoutes);
35
+ // API routes
36
+ app.use("/api", apiRoutes);
39
37
 
40
38
  // unhandled routes
41
- app.use((req: Request, _res: Response, next: NextFunction) => {
42
- const error: any = new Error(`Can't find ${req.originalUrl} on this server!`);
43
- error.status = 404;
44
-
45
- next(error);
46
- });
39
+ app.use(notFound);
47
40
 
48
41
  // Global error handler
49
42
  app.use(errorHandler);
@@ -0,0 +1,12 @@
1
+ import createCors from "cors";
2
+ import { env } from "./env";
3
+
4
+ const origin = env.isProduction
5
+ ? process.env.CORS_ORIGIN
6
+ ? process.env.CORS_ORIGIN.split(",").map((s) => s.trim())
7
+ : false
8
+ : true;
9
+
10
+ const cors = createCors({ origin });
11
+
12
+ export { cors };
@@ -0,0 +1,5 @@
1
+ import createHelmet from "helmet";
2
+
3
+ const helmet = createHelmet();
4
+
5
+ export { helmet };
@@ -0,0 +1,6 @@
1
+ import morgan from "morgan";
2
+ import { env } from "./env";
3
+
4
+ const logger = env.isProduction ? morgan("combined") : morgan("dev");
5
+
6
+ export { logger };
@@ -0,0 +1,11 @@
1
+ import rateLimit from "express-rate-limit";
2
+ import { env } from "./env";
3
+
4
+ const limiter = rateLimit({
5
+ windowMs: 15 * 60 * 1000, // 15 minutes
6
+ max: env.isProduction ? 100 : 1000, // limit each IP
7
+ standardHeaders: true,
8
+ legacyHeaders: false,
9
+ });
10
+
11
+ export { limiter };
@@ -6,4 +6,4 @@ const router = Router();
6
6
  // demo route
7
7
  router.get("/", healthController.health);
8
8
 
9
- export const authRoutes = router;
9
+ export const healthRoutes = router;
@@ -0,0 +1,12 @@
1
+ import { Router } from "express";
2
+ import { healthRoutes } from "../modules/health/health.route";
3
+ const router = Router();
4
+
5
+ // versioned API
6
+ const v1 = Router();
7
+
8
+ v1.use("/health", healthRoutes);
9
+
10
+ router.use("/v1", v1);
11
+
12
+ export const apiRoutes = router;
@@ -0,0 +1,14 @@
1
+ export default class ApiError extends Error {
2
+ statusCode: number;
3
+ isOperational: boolean;
4
+
5
+ constructor(statusCode: number, message: string, isOperational = true) {
6
+ super(message);
7
+ this.statusCode = statusCode;
8
+ this.isOperational = isOperational;
9
+ Object.setPrototypeOf(this, ApiError.prototype);
10
+ if (Error.captureStackTrace) {
11
+ Error.captureStackTrace(this, this.constructor);
12
+ }
13
+ }
14
+ }
@@ -0,0 +1,9 @@
1
+ const ERROR_CODES = {
2
+ VALIDATION: "VALIDATION_ERROR",
3
+ NOT_FOUND: "NOT_FOUND",
4
+ UNAUTHORIZED: "UNAUTHORIZED",
5
+ FORBIDDEN: "FORBIDDEN",
6
+ INTERNAL: "INTERNAL_ERROR",
7
+ } as const;
8
+
9
+ export default ERROR_CODES;
@@ -0,0 +1,20 @@
1
+ function ts() {
2
+ return new Date().toISOString();
3
+ }
4
+
5
+ export const info = (msg: string, meta?: any) => {
6
+ console.log(`${ts()} INFO: ${msg}` + (meta ? ` ${JSON.stringify(meta)}` : ""));
7
+ };
8
+ export const warn = (msg: string, meta?: any) => {
9
+ console.warn(`${ts()} WARN: ${msg}` + (meta ? ` ${JSON.stringify(meta)}` : ""));
10
+ };
11
+ export const error = (msg: string, meta?: any) => {
12
+ console.error(`${ts()} ERROR: ${msg}` + (meta ? ` ${JSON.stringify(meta)}` : ""));
13
+ };
14
+ export const debug = (msg: string, meta?: any) => {
15
+ if (process.env.NODE_ENV !== "production") {
16
+ console.debug(`${ts()} DEBUG: ${msg}` + (meta ? ` ${JSON.stringify(meta)}` : ""));
17
+ }
18
+ };
19
+
20
+ export default { info, warn, error, debug };
@@ -1,5 +1,5 @@
1
1
  import { NextFunction, Request, Response } from "express";
2
- import { env } from "../config/env";
2
+ import { env } from "../../config/env";
3
3
 
4
4
  export const errorHandler = (err: any, _req: Request, res: Response, _: NextFunction) => {
5
5
  const statusCode = err.status || 500;
@@ -0,0 +1,9 @@
1
+ import { Request, Response } from "express";
2
+
3
+ export function notFound(req: Request, res: Response) {
4
+ res.status(404).json({
5
+ message: `Can't find ${req.originalUrl} on this server!`,
6
+ path: req.originalUrl,
7
+ date: Date(),
8
+ });
9
+ }
@@ -0,0 +1,9 @@
1
+ import { NextFunction, Request, Response } from "express";
2
+
3
+ export default function asyncHandler(
4
+ fn: (req: Request, res: Response, next: NextFunction) => Promise<any>,
5
+ ) {
6
+ return (req: Request, res: Response, next: NextFunction) => {
7
+ fn(req, res, next).catch(next);
8
+ };
9
+ }
@@ -0,0 +1,6 @@
1
+ export function getPagination(query: any) {
2
+ const page = Math.max(1, parseInt(String(query.page || "1"), 10) || 1);
3
+ const limit = Math.min(100, parseInt(String(query.limit || "10"), 10) || 10);
4
+ const skip = (page - 1) * limit;
5
+ return { page, limit, skip, take: limit };
6
+ }
@@ -0,0 +1,9 @@
1
+ import { Response } from "express";
2
+
3
+ export function success(res: Response, data: any, message = "Success", meta?: any) {
4
+ return res.json({ success: true, message, data, meta });
5
+ }
6
+
7
+ export function fail(res: Response, status = 500, message = "Error", details?: any) {
8
+ return res.status(status).json({ success: false, message, details });
9
+ }
@@ -1,9 +1,15 @@
1
1
  {
2
2
  "compilerOptions": {
3
+ "sourceMap": true,
4
+ "outDir": "dist",
5
+ "strict": true,
6
+ "target": "ES2020",
7
+ "lib": ["ES2020", "DOM"],
8
+ "skipLibCheck": true,
9
+ "types": ["node"],
10
+ "esModuleInterop": true,
3
11
  "module": "ESNext",
4
12
  "moduleResolution": "node",
5
- "target": "ES2023",
6
- "strict": true,
7
- "esModuleInterop": true
13
+ "resolveJsonModule": true
8
14
  }
9
15
  }
@@ -0,0 +1,8 @@
1
+ export default function DashboardLayout({ children }: { children: React.ReactNode }) {
2
+ return (
3
+ <div className="dashboard-layout">
4
+ <aside>Sidebar</aside>
5
+ <main>{children}</main>
6
+ </div>
7
+ );
8
+ }
@@ -0,0 +1,5 @@
1
+ import Layout from "../../shared/components/layout";
2
+
3
+ export default function PublicLayout() {
4
+ return <Layout />;
5
+ }
@@ -0,0 +1,20 @@
1
+ import { QueryClientProvider } from "@tanstack/react-query";
2
+ import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
3
+ import { Toaster } from "react-hot-toast";
4
+ import { SEOProvider } from "../shared/components/seo";
5
+ import { queryClient } from "../shared/lib/query-client";
6
+ import type { ReactNode } from "react";
7
+
8
+ export function Providers({ children }: { children: ReactNode }) {
9
+ return (
10
+ <SEOProvider>
11
+ <QueryClientProvider client={queryClient}>
12
+ {children}
13
+ <Toaster position="top-right" />
14
+ <ReactQueryDevtools initialIsOpen={false} />
15
+ </QueryClientProvider>
16
+ </SEOProvider>
17
+ );
18
+ }
19
+
20
+ export default Providers;
@@ -0,0 +1,21 @@
1
+ import { createBrowserRouter } from "react-router";
2
+ import { ErrorBoundary } from "../shared/components/error-boundary";
3
+ import PublicLayout from "./layouts/public-layout";
4
+ import Home from "../features/home/pages/home";
5
+ import About from "../features/about/pages/about";
6
+ import NotFound from "../shared/pages/not-found";
7
+
8
+ export const router = createBrowserRouter([
9
+ {
10
+ path: "/",
11
+ Component: PublicLayout,
12
+ errorElement: <ErrorBoundary />,
13
+ children: [
14
+ { index: true, Component: Home },
15
+ { path: "about", Component: About },
16
+ { path: "*", Component: NotFound },
17
+ ],
18
+ },
19
+ ]);
20
+
21
+ export default router;
@@ -1,4 +1,4 @@
1
- import { SEO } from "../components/SEO";
1
+ import { SEO } from "../../../shared/components/seo";
2
2
 
3
3
  export default function About() {
4
4
  return (
@@ -1,4 +1,4 @@
1
- import { SEO } from "../components/SEO";
1
+ import { SEO } from "../../../shared/components/seo";
2
2
 
3
3
  export default function Home() {
4
4
  return (
@@ -4,10 +4,10 @@ import { StrictMode } from "react";
4
4
  import { createRoot } from "react-dom/client";
5
5
  import { Toaster } from "react-hot-toast";
6
6
  import { RouterProvider } from "react-router";
7
- import { SEOProvider } from "./components/SEO";
8
7
  import "./index.css";
9
- import { queryClient } from "./lib/queryClient";
10
8
  import { router } from "./router";
9
+ import { queryClient } from "./shared/lib/query-client";
10
+ import { SEOProvider } from "./shared/components/seo";
11
11
 
12
12
  createRoot(document.getElementById("root")!).render(
13
13
  <StrictMode>
@@ -14,7 +14,7 @@ api.interceptors.request.use(
14
14
  (config) => {
15
15
  const token = localStorage.getItem("auth_token");
16
16
  if (token) {
17
- config.headers.Authorization = `Bearer ${token}`;
17
+ (config.headers as Record<string, string>).Authorization = `Bearer ${token}`;
18
18
  }
19
19
  return config;
20
20
  },
@@ -1,5 +1,5 @@
1
1
  import { Link } from "react-router";
2
- import { SEO } from "../components/SEO";
2
+ import { SEO } from "../components/seo";
3
3
 
4
4
  export default function NotFound() {
5
5
  return (
@@ -1 +0,0 @@
1
- export declare function initGit(cwd: string): Promise<void>;
@@ -1,29 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.initGit = initGit;
4
- const child_process_1 = require("child_process");
5
- async function initGit(cwd) {
6
- try {
7
- (0, child_process_1.execSync)("git --version", { stdio: "pipe" });
8
- }
9
- catch {
10
- throw new Error("Git is not installed or not available in PATH");
11
- }
12
- try {
13
- (0, child_process_1.execSync)("git status", { cwd, stdio: "pipe" });
14
- return;
15
- }
16
- catch {
17
- // Not a git repo, proceed with initialization
18
- }
19
- (0, child_process_1.execSync)("git init", { cwd, stdio: "pipe" });
20
- (0, child_process_1.execSync)("git add .", { cwd, stdio: "pipe" });
21
- try {
22
- (0, child_process_1.execSync)("git diff --cached --quiet", { cwd, stdio: "pipe" });
23
- return;
24
- }
25
- catch {
26
- // Files are staged, proceed with commit
27
- }
28
- (0, child_process_1.execSync)('git commit -m "Initial commit"', { cwd, stdio: "pipe" });
29
- }
@@ -1,2 +0,0 @@
1
- import { handlers } from "@/auth"
2
- export const { GET, POST } = handlers
@@ -1,22 +0,0 @@
1
- import NextAuth from "next-auth"
2
- import { PrismaAdapter } from "@auth/prisma-adapter"
3
- import { prisma } from "./prisma";
4
- import Google from "next-auth/providers/google"
5
- import { encode, decode } from 'next-auth/jwt';
6
-
7
- export const { handlers, signIn, signOut, auth } = NextAuth({
8
- adapter: PrismaAdapter(prisma),
9
- providers: [
10
- Google({
11
- clientId: process.env.AUTH_GOOGLE_ID,
12
- clientSecret: process.env.AUTH_GOOGLE_SECRET,
13
- }),
14
- ],
15
- session: { strategy: "jwt" },
16
- secret: process.env.AUTH_SECRET,
17
- jwt: { encode, decode },
18
- pages: {
19
- signIn: '/sign-in',
20
- error: '/error',
21
- },
22
- })