create-n8-app 0.1.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 (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +132 -0
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.js +239 -0
  5. package/package.json +58 -0
  6. package/template/_env.example +34 -0
  7. package/template/_env.local +31 -0
  8. package/template/_eslintrc.json +3 -0
  9. package/template/_gitignore +46 -0
  10. package/template/_package.json +59 -0
  11. package/template/app/api/auth/[...nextauth]/route.ts +3 -0
  12. package/template/app/api/trpc/[trpc]/route.ts +19 -0
  13. package/template/app/auth/signin/page.tsx +39 -0
  14. package/template/app/globals.css +33 -0
  15. package/template/app/layout.tsx +28 -0
  16. package/template/app/page.tsx +68 -0
  17. package/template/app/providers.tsx +47 -0
  18. package/template/components/auth/user-button.tsx +46 -0
  19. package/template/components/ui/.gitkeep +2 -0
  20. package/template/components.json +21 -0
  21. package/template/drizzle/.gitkeep +1 -0
  22. package/template/drizzle.config.ts +10 -0
  23. package/template/hooks/.gitkeep +1 -0
  24. package/template/lib/auth.ts +44 -0
  25. package/template/lib/db.ts +10 -0
  26. package/template/lib/env.ts +76 -0
  27. package/template/lib/trpc.ts +4 -0
  28. package/template/lib/utils.ts +6 -0
  29. package/template/next-env.d.ts +5 -0
  30. package/template/next.config.ts +14 -0
  31. package/template/postcss.config.mjs +7 -0
  32. package/template/prettier.config.js +11 -0
  33. package/template/public/.gitkeep +1 -0
  34. package/template/server/api/root.ts +22 -0
  35. package/template/server/api/routers/example.ts +76 -0
  36. package/template/server/api/trpc.ts +67 -0
  37. package/template/server/db/schema.ts +95 -0
  38. package/template/stores/example-store.ts +121 -0
  39. package/template/tests/example.test.ts +22 -0
  40. package/template/tests/setup.ts +22 -0
  41. package/template/tsconfig.json +27 -0
  42. package/template/vitest.config.ts +30 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nate McGrady
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,132 @@
1
+ # create-n8-app
2
+
3
+ Create a new Next.js app with the N8 stack - a modern, full-stack template featuring:
4
+
5
+ - **Next.js 16** - App Router, Server Components, Server Actions, Turbopack
6
+ - **TypeScript** - Strict mode enabled
7
+ - **Tailwind CSS v4** - Modern CSS-first configuration
8
+ - **Shadcn/ui** - Beautiful, accessible components
9
+ - **Drizzle ORM** - Type-safe database queries
10
+ - **Neon** - Serverless PostgreSQL
11
+ - **tRPC** - End-to-end type safety
12
+ - **TanStack Query** - Powerful async state management
13
+ - **Zustand** - Lightweight global state
14
+ - **NextAuth.js** - Authentication with GitHub OAuth
15
+ - **Vitest** - Fast unit testing
16
+ - **Prettier** - Code formatting with Tailwind plugin
17
+
18
+ ## Usage
19
+
20
+ ```bash
21
+ # With npm
22
+ npm create n8-app@latest my-app
23
+
24
+ # With pnpm
25
+ pnpm create n8-app@latest my-app
26
+
27
+ # With yarn
28
+ yarn create n8-app my-app
29
+ ```
30
+
31
+ ## Options
32
+
33
+ ```bash
34
+ npm create n8-app@latest my-app --skip-install # Skip dependency installation
35
+ npm create n8-app@latest my-app --skip-git # Skip git initialization
36
+ ```
37
+
38
+ ## After Creation
39
+
40
+ 1. **Set up your database**
41
+ - Create a Neon project at [neon.tech](https://neon.tech)
42
+ - Copy the connection string to `.env.local`
43
+
44
+ 2. **Set up GitHub OAuth**
45
+ - Create an OAuth App at [github.com/settings/developers](https://github.com/settings/developers)
46
+ - Set callback URL to `http://localhost:3000/api/auth/callback/github`
47
+ - Copy Client ID and Secret to `.env.local`
48
+
49
+ 3. **Generate a secret**
50
+ ```bash
51
+ openssl rand -base64 32
52
+ ```
53
+ Add to `.env.local` as `AUTH_SECRET`
54
+
55
+ 4. **Run database migrations**
56
+ ```bash
57
+ pnpm db:generate
58
+ pnpm db:push
59
+ ```
60
+
61
+ 5. **Start developing**
62
+ ```bash
63
+ pnpm dev
64
+ ```
65
+
66
+ ## Project Structure
67
+
68
+ ```
69
+ my-app/
70
+ ├── app/ # Next.js App Router
71
+ │ ├── api/ # API routes (tRPC, auth)
72
+ │ ├── auth/ # Auth pages
73
+ │ ├── globals.css # Tailwind styles
74
+ │ ├── layout.tsx # Root layout
75
+ │ ├── page.tsx # Home page
76
+ │ └── providers.tsx # Client providers
77
+ ├── components/ # React components
78
+ │ ├── auth/ # Auth components
79
+ │ └── ui/ # Shadcn components
80
+ ├── hooks/ # Custom React hooks
81
+ ├── lib/ # Utility functions
82
+ │ ├── auth.ts # NextAuth config
83
+ │ ├── db.ts # Database client
84
+ │ ├── env.ts # Environment validation
85
+ │ ├── trpc.ts # tRPC client
86
+ │ └── utils.ts # Utilities
87
+ ├── server/ # Server-side code
88
+ │ ├── api/ # tRPC routers
89
+ │ └── db/ # Database schema
90
+ ├── stores/ # Zustand stores
91
+ ├── tests/ # Test files
92
+ ├── drizzle/ # Database migrations
93
+ └── public/ # Static assets
94
+ ```
95
+
96
+ ## Scripts
97
+
98
+ | Command | Description |
99
+ |---------|-------------|
100
+ | `pnpm dev` | Start development server with Turbopack |
101
+ | `pnpm build` | Build for production |
102
+ | `pnpm start` | Start production server |
103
+ | `pnpm lint` | Run ESLint |
104
+ | `pnpm format` | Format code with Prettier |
105
+ | `pnpm test` | Run tests with Vitest |
106
+ | `pnpm db:generate` | Generate Drizzle migrations |
107
+ | `pnpm db:push` | Push schema to database |
108
+ | `pnpm db:studio` | Open Drizzle Studio |
109
+
110
+ ## Development
111
+
112
+ ### Adding Shadcn Components
113
+
114
+ ```bash
115
+ npx shadcn@latest add button
116
+ npx shadcn@latest add card
117
+ npx shadcn@latest add input
118
+ ```
119
+
120
+ ### Creating tRPC Routes
121
+
122
+ Add new routers in `server/api/routers/` and register them in `server/api/root.ts`.
123
+
124
+ ### Using Zustand
125
+
126
+ See `stores/example-store.ts` for patterns. Remember:
127
+ - Use React Query for server data
128
+ - Use Zustand only for client state (UI, preferences, cart)
129
+
130
+ ## License
131
+
132
+ MIT
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/index.js ADDED
@@ -0,0 +1,239 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { Command } from "commander";
5
+
6
+ // src/create-project.ts
7
+ import fs2 from "fs-extra";
8
+ import path2 from "path";
9
+ import prompts from "prompts";
10
+ import chalk2 from "chalk";
11
+
12
+ // src/utils/copy-template.ts
13
+ import fs from "fs-extra";
14
+ import path from "path";
15
+ import { fileURLToPath } from "url";
16
+ var __filename = fileURLToPath(import.meta.url);
17
+ var __dirname = path.dirname(__filename);
18
+ async function copyTemplate(targetDir, projectName) {
19
+ const templateDir = path.resolve(__dirname, "..", "template");
20
+ if (!await fs.pathExists(templateDir)) {
21
+ throw new Error(`Template directory not found at: ${templateDir}`);
22
+ }
23
+ await fs.copy(templateDir, targetDir);
24
+ const filesToRename = [
25
+ { from: "_package.json", to: "package.json" },
26
+ { from: "_gitignore", to: ".gitignore" },
27
+ { from: "_env.example", to: ".env.example" },
28
+ { from: "_env.local", to: ".env.local" },
29
+ { from: "_eslintrc.json", to: ".eslintrc.json" }
30
+ ];
31
+ for (const { from, to } of filesToRename) {
32
+ const fromPath = path.join(targetDir, from);
33
+ const toPath = path.join(targetDir, to);
34
+ if (await fs.pathExists(fromPath)) {
35
+ await fs.rename(fromPath, toPath);
36
+ }
37
+ }
38
+ const packageJsonPath = path.join(targetDir, "package.json");
39
+ const packageJson = await fs.readJson(packageJsonPath);
40
+ packageJson.name = projectName;
41
+ await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
42
+ }
43
+
44
+ // src/utils/install-deps.ts
45
+ import { execa } from "execa";
46
+
47
+ // src/utils/logger.ts
48
+ import chalk from "chalk";
49
+ var logger = {
50
+ info: (message) => {
51
+ console.log(chalk.blue("\u2139"), message);
52
+ },
53
+ success: (message) => {
54
+ console.log(chalk.green("\u2714"), message);
55
+ },
56
+ warn: (message) => {
57
+ console.log(chalk.yellow("\u26A0"), message);
58
+ },
59
+ error: (message) => {
60
+ console.log(chalk.red("\u2716"), message);
61
+ },
62
+ step: (step, total, message) => {
63
+ console.log(chalk.cyan(`[${step}/${total}]`), message);
64
+ },
65
+ blank: () => {
66
+ console.log();
67
+ },
68
+ title: (message) => {
69
+ console.log();
70
+ console.log(chalk.bold.magenta(message));
71
+ console.log();
72
+ }
73
+ };
74
+
75
+ // src/utils/install-deps.ts
76
+ async function installDependencies(targetDir) {
77
+ logger.info("Installing dependencies with pnpm...");
78
+ try {
79
+ await execa("pnpm", ["install"], {
80
+ cwd: targetDir,
81
+ stdio: "inherit"
82
+ });
83
+ logger.success("Dependencies installed successfully");
84
+ } catch (error) {
85
+ logger.warn("pnpm not found, trying npm...");
86
+ try {
87
+ await execa("npm", ["install"], {
88
+ cwd: targetDir,
89
+ stdio: "inherit"
90
+ });
91
+ logger.success("Dependencies installed successfully with npm");
92
+ } catch {
93
+ throw new Error("Failed to install dependencies");
94
+ }
95
+ }
96
+ }
97
+ async function runShadcnInit(targetDir) {
98
+ logger.info("Initializing Shadcn/ui...");
99
+ try {
100
+ await execa("npx", ["shadcn@latest", "init", "-y", "-d"], {
101
+ cwd: targetDir,
102
+ stdio: "inherit"
103
+ });
104
+ logger.success("Shadcn/ui initialized successfully");
105
+ } catch (error) {
106
+ logger.warn('Shadcn/ui initialization skipped - you can run "npx shadcn@latest init" later');
107
+ }
108
+ }
109
+
110
+ // src/utils/git.ts
111
+ import { execa as execa2 } from "execa";
112
+ async function initGit(targetDir) {
113
+ logger.info("Initializing git repository...");
114
+ try {
115
+ await execa2("git", ["init"], {
116
+ cwd: targetDir,
117
+ stdio: "pipe"
118
+ });
119
+ await execa2("git", ["add", "-A"], {
120
+ cwd: targetDir,
121
+ stdio: "pipe"
122
+ });
123
+ await execa2("git", ["commit", "-m", "Initial commit from create-n8-app"], {
124
+ cwd: targetDir,
125
+ stdio: "pipe"
126
+ });
127
+ logger.success("Git repository initialized with initial commit");
128
+ } catch (error) {
129
+ logger.warn("Git initialization skipped - git may not be installed");
130
+ }
131
+ }
132
+
133
+ // src/helpers/get-package-manager.ts
134
+ function getPackageManager() {
135
+ const userAgent = process.env.npm_config_user_agent || "";
136
+ if (userAgent.startsWith("pnpm")) {
137
+ return "pnpm";
138
+ }
139
+ if (userAgent.startsWith("yarn")) {
140
+ return "yarn";
141
+ }
142
+ if (userAgent.startsWith("bun")) {
143
+ return "bun";
144
+ }
145
+ return "npm";
146
+ }
147
+
148
+ // src/create-project.ts
149
+ async function createProject(options) {
150
+ logger.title("\u{1F680} Create N8 App");
151
+ let projectName = options.projectName;
152
+ if (!projectName) {
153
+ const response = await prompts({
154
+ type: "text",
155
+ name: "projectName",
156
+ message: "What is your project named?",
157
+ initial: "my-n8-app",
158
+ validate: (value) => {
159
+ if (!value) return "Project name is required";
160
+ if (!/^[a-z0-9-]+$/.test(value)) {
161
+ return "Project name can only contain lowercase letters, numbers, and hyphens";
162
+ }
163
+ return true;
164
+ }
165
+ });
166
+ if (!response.projectName) {
167
+ logger.error("Project name is required");
168
+ process.exit(1);
169
+ }
170
+ projectName = response.projectName;
171
+ }
172
+ const targetDir = path2.resolve(process.cwd(), projectName);
173
+ if (await fs2.pathExists(targetDir)) {
174
+ const { overwrite } = await prompts({
175
+ type: "confirm",
176
+ name: "overwrite",
177
+ message: `Directory ${projectName} already exists. Overwrite?`,
178
+ initial: false
179
+ });
180
+ if (!overwrite) {
181
+ logger.error("Operation cancelled");
182
+ process.exit(1);
183
+ }
184
+ await fs2.remove(targetDir);
185
+ }
186
+ const totalSteps = options.skipInstall ? 2 : 4;
187
+ logger.step(1, totalSteps, "Creating project structure...");
188
+ await fs2.ensureDir(targetDir);
189
+ await copyTemplate(targetDir, projectName);
190
+ logger.success("Project structure created");
191
+ if (!options.skipGit) {
192
+ logger.step(2, totalSteps, "Initializing git...");
193
+ await initGit(targetDir);
194
+ }
195
+ if (!options.skipInstall) {
196
+ logger.step(options.skipGit ? 2 : 3, totalSteps, "Installing dependencies...");
197
+ await installDependencies(targetDir);
198
+ logger.step(options.skipGit ? 3 : 4, totalSteps, "Setting up Shadcn/ui...");
199
+ await runShadcnInit(targetDir);
200
+ }
201
+ const pm = getPackageManager();
202
+ const runCmd = pm === "npm" ? "npm run" : pm;
203
+ logger.blank();
204
+ logger.title("\u2705 Success! Your N8 app is ready.");
205
+ console.log(chalk2.dim(" Next steps:"));
206
+ console.log();
207
+ console.log(chalk2.cyan(` cd ${projectName}`));
208
+ if (options.skipInstall) {
209
+ console.log(chalk2.cyan(` ${pm} install`));
210
+ }
211
+ console.log(chalk2.cyan(` ${runCmd} dev`));
212
+ console.log();
213
+ console.log(chalk2.dim(" Don't forget to:"));
214
+ console.log(chalk2.dim(" \u2022 Set up your .env.local with database and auth credentials"));
215
+ console.log(chalk2.dim(' \u2022 Run "pnpm drizzle-kit generate" to create migrations'));
216
+ console.log(chalk2.dim(' \u2022 Add Shadcn components with "npx shadcn@latest add [component]"'));
217
+ console.log();
218
+ console.log(chalk2.bold(" Happy coding! \u{1F389}"));
219
+ console.log();
220
+ }
221
+
222
+ // src/index.ts
223
+ var program = new Command();
224
+ program.name("create-n8-app").description("Create a new Next.js app with the N8 stack").version("0.1.0").argument("[project-name]", "Name of the project").option("--skip-install", "Skip installing dependencies").option("--skip-git", "Skip initializing git repository").action(async (projectName, options) => {
225
+ try {
226
+ await createProject({
227
+ projectName,
228
+ skipInstall: options.skipInstall ?? false,
229
+ skipGit: options.skipGit ?? false
230
+ });
231
+ } catch (error) {
232
+ logger.error("Failed to create project");
233
+ if (error instanceof Error) {
234
+ logger.error(error.message);
235
+ }
236
+ process.exit(1);
237
+ }
238
+ });
239
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "create-n8-app",
3
+ "version": "0.1.0",
4
+ "description": "Create a Next.js app with the N8 stack - Next.js 16, Tailwind v4, Shadcn/ui, Drizzle, tRPC, TanStack Query, Zustand, NextAuth, and more",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-n8-app": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "template"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsup src/index.ts --format esm --dts",
15
+ "dev": "tsup src/index.ts --format esm --watch",
16
+ "prepublishOnly": "pnpm build"
17
+ },
18
+ "keywords": [
19
+ "create",
20
+ "nextjs",
21
+ "next",
22
+ "react",
23
+ "typescript",
24
+ "tailwind",
25
+ "shadcn",
26
+ "drizzle",
27
+ "trpc",
28
+ "tanstack-query",
29
+ "zustand",
30
+ "nextauth",
31
+ "starter",
32
+ "template",
33
+ "scaffold"
34
+ ],
35
+ "author": "Nate McG",
36
+ "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "https://github.com/natemcgrady/create-n8-app"
40
+ },
41
+ "devDependencies": {
42
+ "@types/fs-extra": "^11.0.4",
43
+ "@types/node": "^22.10.0",
44
+ "@types/prompts": "^2.4.9",
45
+ "tsup": "^8.3.5",
46
+ "typescript": "^5.7.2"
47
+ },
48
+ "dependencies": {
49
+ "chalk": "^5.3.0",
50
+ "commander": "^12.1.0",
51
+ "execa": "^9.5.1",
52
+ "fs-extra": "^11.2.0",
53
+ "prompts": "^2.4.2"
54
+ },
55
+ "engines": {
56
+ "node": ">=18.0.0"
57
+ }
58
+ }
@@ -0,0 +1,34 @@
1
+ # =============================================================================
2
+ # N8 Stack Environment Variables
3
+ # =============================================================================
4
+ # Copy this file to .env.local and fill in your values
5
+ # Never commit .env.local to version control!
6
+
7
+ # =============================================================================
8
+ # Database (Neon)
9
+ # =============================================================================
10
+ # Get your connection string from: https://neon.tech
11
+ DATABASE_URL="postgresql://user:password@host/database?sslmode=require"
12
+
13
+ # =============================================================================
14
+ # Authentication (NextAuth.js / Auth.js)
15
+ # =============================================================================
16
+ # Generate a secret with: openssl rand -base64 32
17
+ AUTH_SECRET="your-secret-here-at-least-32-characters"
18
+
19
+ # GitHub OAuth
20
+ # Create an OAuth App at: https://github.com/settings/developers
21
+ # Set callback URL to: http://localhost:3000/api/auth/callback/github
22
+ AUTH_GITHUB_ID="your-github-client-id"
23
+ AUTH_GITHUB_SECRET="your-github-client-secret"
24
+
25
+ # =============================================================================
26
+ # Public Variables (exposed to browser)
27
+ # =============================================================================
28
+ NEXT_PUBLIC_APP_URL="http://localhost:3000"
29
+
30
+ # =============================================================================
31
+ # AI (Optional)
32
+ # =============================================================================
33
+ # Get your API key from: https://platform.openai.com
34
+ OPENAI_API_KEY="sk-..."
@@ -0,0 +1,31 @@
1
+ # =============================================================================
2
+ # N8 Stack Environment Variables
3
+ # =============================================================================
4
+ # Fill in your values below
5
+
6
+ # =============================================================================
7
+ # Database (Neon)
8
+ # =============================================================================
9
+ DATABASE_URL="postgresql://user:password@host/database?sslmode=require"
10
+
11
+ # =============================================================================
12
+ # Authentication (NextAuth.js / Auth.js)
13
+ # =============================================================================
14
+ AUTH_SECRET="change-me-generate-with-openssl-rand-base64-32"
15
+ AUTH_GITHUB_ID=""
16
+ AUTH_GITHUB_SECRET=""
17
+
18
+ # =============================================================================
19
+ # Public Variables
20
+ # =============================================================================
21
+ NEXT_PUBLIC_APP_URL="http://localhost:3000"
22
+
23
+ # =============================================================================
24
+ # AI (Optional)
25
+ # =============================================================================
26
+ # OPENAI_API_KEY=""
27
+
28
+ # =============================================================================
29
+ # Skip validation during initial setup
30
+ # =============================================================================
31
+ SKIP_ENV_VALIDATION="true"
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": ["next/core-web-vitals", "next/typescript"]
3
+ }
@@ -0,0 +1,46 @@
1
+ # Dependencies
2
+ node_modules
3
+ .pnpm-store
4
+
5
+ # Next.js
6
+ .next
7
+ out
8
+
9
+ # Production
10
+ build
11
+ dist
12
+
13
+ # Debug
14
+ npm-debug.log*
15
+ yarn-debug.log*
16
+ yarn-error.log*
17
+
18
+ # Local env files
19
+ .env
20
+ .env.local
21
+ .env.development.local
22
+ .env.test.local
23
+ .env.production.local
24
+
25
+ # Vercel
26
+ .vercel
27
+
28
+ # TypeScript
29
+ *.tsbuildinfo
30
+ next-env.d.ts
31
+
32
+ # Testing
33
+ coverage
34
+
35
+ # IDE
36
+ .idea
37
+ .vscode
38
+ *.swp
39
+ *.swo
40
+
41
+ # OS
42
+ .DS_Store
43
+ Thumbs.db
44
+
45
+ # Drizzle
46
+ drizzle/*.sql
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "my-n8-app",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev --turbopack",
7
+ "build": "next build",
8
+ "start": "next start",
9
+ "lint": "next lint",
10
+ "format": "prettier --write .",
11
+ "format:check": "prettier --check .",
12
+ "test": "vitest",
13
+ "test:run": "vitest run",
14
+ "db:generate": "drizzle-kit generate",
15
+ "db:migrate": "drizzle-kit migrate",
16
+ "db:push": "drizzle-kit push",
17
+ "db:studio": "drizzle-kit studio"
18
+ },
19
+ "dependencies": {
20
+ "@auth/drizzle-adapter": "^1.7.0",
21
+ "@neondatabase/serverless": "^0.10.4",
22
+ "@tanstack/react-query": "^5.62.0",
23
+ "@trpc/client": "^11.0.0-rc.660",
24
+ "@trpc/react-query": "^11.0.0-rc.660",
25
+ "@trpc/server": "^11.0.0-rc.660",
26
+ "ai": "^4.0.0",
27
+ "@ai-sdk/openai": "^1.0.0",
28
+ "drizzle-orm": "^0.36.4",
29
+ "next": "^15.1.0",
30
+ "next-auth": "^5.0.0-beta.25",
31
+ "react": "^19.0.0",
32
+ "react-dom": "^19.0.0",
33
+ "zod": "^3.23.8",
34
+ "zustand": "^5.0.2",
35
+ "superjson": "^2.2.2",
36
+ "clsx": "^2.1.1",
37
+ "tailwind-merge": "^2.6.0",
38
+ "lucide-react": "^0.468.0"
39
+ },
40
+ "devDependencies": {
41
+ "@tailwindcss/postcss": "^4.0.0",
42
+ "@types/node": "^22.10.0",
43
+ "@types/react": "^19.0.0",
44
+ "@types/react-dom": "^19.0.0",
45
+ "@vitejs/plugin-react": "^4.3.4",
46
+ "drizzle-kit": "^0.28.1",
47
+ "jsdom": "^25.0.1",
48
+ "postcss": "^8.4.49",
49
+ "prettier": "^3.4.2",
50
+ "prettier-plugin-tailwindcss": "^0.6.9",
51
+ "tailwindcss": "^4.0.0",
52
+ "typescript": "^5.7.2",
53
+ "vitest": "^2.1.8",
54
+ "@testing-library/react": "^16.1.0",
55
+ "@testing-library/jest-dom": "^6.6.3",
56
+ "eslint": "^9.16.0",
57
+ "eslint-config-next": "^15.1.0"
58
+ }
59
+ }
@@ -0,0 +1,3 @@
1
+ import { handlers } from '@/lib/auth'
2
+
3
+ export const { GET, POST } = handlers
@@ -0,0 +1,19 @@
1
+ import { fetchRequestHandler } from '@trpc/server/adapters/fetch'
2
+ import { appRouter } from '@/server/api/root'
3
+ import { createTRPCContext } from '@/server/api/trpc'
4
+
5
+ const handler = (req: Request) =>
6
+ fetchRequestHandler({
7
+ endpoint: '/api/trpc',
8
+ req,
9
+ router: appRouter,
10
+ createContext: () => createTRPCContext({ headers: req.headers }),
11
+ onError:
12
+ process.env.NODE_ENV === 'development'
13
+ ? ({ path, error }) => {
14
+ console.error(`❌ tRPC failed on ${path ?? '<no-path>'}: ${error.message}`)
15
+ }
16
+ : undefined,
17
+ })
18
+
19
+ export { handler as GET, handler as POST }