wexts 3.0.2 → 4.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.
- 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-342VRT25.mjs +504 -0
- package/dist/chunk-342VRT25.mjs.map +1 -0
- package/dist/chunk-7HNQWJWV.js +504 -0
- package/dist/chunk-7HNQWJWV.js.map +1 -0
- package/dist/chunk-7QKLIVRF.js +94 -0
- package/dist/chunk-7QKLIVRF.js.map +1 -0
- package/dist/chunk-7SSCNCTW.mjs +137 -0
- package/dist/chunk-7SSCNCTW.mjs.map +1 -0
- package/dist/chunk-7TLSPR65.mjs +95 -0
- package/dist/chunk-7TLSPR65.mjs.map +1 -0
- package/dist/{chunk-FCEZDH42.mjs → chunk-7WULUGLH.mjs} +5 -3
- package/dist/chunk-7WULUGLH.mjs.map +1 -0
- package/dist/chunk-AVMQJWYD.js +95 -0
- package/dist/chunk-AVMQJWYD.js.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-O4II6N34.js +137 -0
- package/dist/chunk-O4II6N34.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 +22 -0
- package/dist/cli/index.d.ts +22 -0
- package/dist/cli/index.js +676 -292
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +678 -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 +5 -2
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +7 -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 +6 -3
- package/dist/codegen/index.js.map +1 -1
- package/dist/codegen/index.mjs +8 -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 +54 -7
- package/dist/index.d.ts +54 -7
- package/dist/index.js +70 -29
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +62 -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 +135 -5
- package/dist/next/index.js.map +1 -1
- package/dist/next/index.mjs +133 -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 +221 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/index.mjs +221 -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.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.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/nestjs-api/package-lock.json +0 -5623
- package/templates/nextjs-web/.env +0 -1
- package/templates/nextjs-web/package-lock.json +0 -3254
package/README.md
CHANGED
|
@@ -1,346 +1,49 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
## 🎯 Key Features
|
|
52
|
-
|
|
53
|
-
- 🔥 **Unified Runtime** - Single Node.js process for frontend + backend
|
|
54
|
-
- 🎨 **Zero URLs** - Call APIs without explicit URLs
|
|
55
|
-
- ⚡ **Type-Safe** - End-to-end TypeScript with auto-complete
|
|
56
|
-
- 🚀 **Production Ready** - Docker, Railway, Render, Vercel support
|
|
57
|
-
- 🔒 **Auth Built-in** - JWT authentication out of the box
|
|
58
|
-
- 📦 **Prisma ORM** - Database integration ready
|
|
59
|
-
- 🐳 **Docker Ready** - Complete Docker setup included
|
|
60
|
-
|
|
61
|
-
---
|
|
62
|
-
|
|
63
|
-
## 🚀 Quick Start
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
# Create new project
|
|
67
|
-
npx wexts create my-app
|
|
68
|
-
|
|
69
|
-
# Start development
|
|
70
|
-
cd my-app
|
|
71
|
-
pnpm install
|
|
72
|
-
pnpm run dev
|
|
73
|
-
|
|
74
|
-
# Open http://localhost:3000
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
**That's it!** Your unified server is running with:
|
|
78
|
-
- ✅ Next.js frontend
|
|
79
|
-
- ✅ NestJS backend API
|
|
80
|
-
- ✅ Smart routing
|
|
81
|
-
- ✅ Hot reload
|
|
82
|
-
|
|
83
|
-
---
|
|
84
|
-
|
|
85
|
-
## 💡 The Magic - Zero URLs!
|
|
86
|
-
|
|
87
|
-
### ❌ Without WEXTS
|
|
88
|
-
|
|
89
|
-
```typescript
|
|
90
|
-
// Hardcoded URLs everywhere
|
|
91
|
-
const response = await fetch('http://localhost:3001/api/users');
|
|
92
|
-
const users = await response.json();
|
|
93
|
-
|
|
94
|
-
// Problems:
|
|
95
|
-
// - No type safety
|
|
96
|
-
// - CORS issues
|
|
97
|
-
// - Environment management
|
|
98
|
-
// - Proxy configuration
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
### ✅ With WEXTS
|
|
102
|
-
|
|
103
|
-
```typescript
|
|
104
|
-
import { api } from '@/lib/api';
|
|
105
|
-
|
|
106
|
-
// Type-safe, zero URLs, works everywhere!
|
|
107
|
-
const users = await api.users.findAll();
|
|
108
|
-
// ✅ Auto-complete
|
|
109
|
-
// ✅ Type-safe
|
|
110
|
-
// ✅ No configuration
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
**The SDK automatically connects to your backend. No URLs needed!**
|
|
114
|
-
|
|
115
|
-
---
|
|
116
|
-
|
|
117
|
-
## 📖 Project Structure
|
|
118
|
-
|
|
119
|
-
```
|
|
120
|
-
my-app/
|
|
121
|
-
├── 🚀 server.ts # Unified server
|
|
122
|
-
├── apps/
|
|
123
|
-
│ ├── 🔙 api/ # NestJS Backend
|
|
124
|
-
│ │ ├── src/
|
|
125
|
-
│ │ │ ├── auth/ # JWT Authentication
|
|
126
|
-
│ │ │ └── prisma/ # Database ORM
|
|
127
|
-
│ │ └── prisma/schema.prisma
|
|
128
|
-
│ │
|
|
129
|
-
│ └── 🎨 web/ # Next.js Frontend
|
|
130
|
-
│ ├── app/ # App Router
|
|
131
|
-
│ └── lib/
|
|
132
|
-
│ └── api.ts # 🔥 Type-safe SDK
|
|
133
|
-
│
|
|
134
|
-
├── 🐳 Dockerfile # Production build
|
|
135
|
-
└── docker-compose.yml # Docker + PostgreSQL
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
---
|
|
139
|
-
|
|
140
|
-
## 🏗️ How It Works
|
|
141
|
-
|
|
142
|
-
```
|
|
143
|
-
┌─────────────────────────────────────────┐
|
|
144
|
-
│ Single Node.js Process │
|
|
145
|
-
│ │
|
|
146
|
-
│ ┌──────────┐ ┌──────────┐ │
|
|
147
|
-
│ │ Next.js │ │ NestJS │ │
|
|
148
|
-
│ │ Frontend │ │ Backend │ │
|
|
149
|
-
│ └──────────┘ └──────────┘ │
|
|
150
|
-
│ │
|
|
151
|
-
│ Smart Router Middleware │
|
|
152
|
-
│ ┌─────────────────────────────┐ │
|
|
153
|
-
│ │ /api/* → NestJS │ │
|
|
154
|
-
│ │ /* → Next.js │ │
|
|
155
|
-
│ └─────────────────────────────┘ │
|
|
156
|
-
└─────────────────────────────────────────┘
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
**No proxy. No CORS. Just works.** ✨
|
|
160
|
-
|
|
161
|
-
---
|
|
162
|
-
|
|
163
|
-
## 🔐 Built-in Authentication
|
|
164
|
-
|
|
165
|
-
```typescript
|
|
166
|
-
// Register
|
|
167
|
-
const { user, access_token } = await api.auth.register({
|
|
168
|
-
email: 'user@example.com',
|
|
169
|
-
password: 'secure123',
|
|
170
|
-
name: 'John Doe'
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
// Login
|
|
174
|
-
const { user, access_token } = await api.auth.login({
|
|
175
|
-
email: 'user@example.com',
|
|
176
|
-
password: 'secure123'
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
// Get current user
|
|
180
|
-
const user = await api.auth.me();
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
**Secure JWT authentication with httpOnly cookies included!**
|
|
184
|
-
|
|
185
|
-
---
|
|
186
|
-
|
|
187
|
-
## 🐳 Deploy Anywhere
|
|
188
|
-
|
|
189
|
-
### Docker (Recommended)
|
|
190
|
-
|
|
191
|
-
```bash
|
|
192
|
-
docker-compose up -d
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
**Includes PostgreSQL!** Your app is live at `http://localhost:3000`
|
|
196
|
-
|
|
197
|
-
### Railway (Easiest)
|
|
198
|
-
|
|
199
|
-
```bash
|
|
200
|
-
# Push to GitHub, connect Railway, done!
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
Railway auto-detects WEXTS configuration.
|
|
204
|
-
|
|
205
|
-
### Render / VPS
|
|
206
|
-
|
|
207
|
-
```bash
|
|
208
|
-
pnpm run build
|
|
209
|
-
pnpm start
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
**One build. One deployment. Works everywhere.**
|
|
213
|
-
|
|
214
|
-
---
|
|
215
|
-
|
|
216
|
-
## 📚 Full Example
|
|
217
|
-
|
|
218
|
-
```typescript
|
|
219
|
-
// Backend - apps/api/src/posts/posts.controller.ts
|
|
220
|
-
@Controller('posts')
|
|
221
|
-
@UseGuards(JwtAuthGuard)
|
|
222
|
-
export class PostsController {
|
|
223
|
-
@Get()
|
|
224
|
-
findAll() {
|
|
225
|
-
return this.postsService.findAll();
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
@Post()
|
|
229
|
-
create(@Body() dto: CreatePostDto) {
|
|
230
|
-
return this.postsService.create(dto);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// Frontend - apps/web/lib/api.ts
|
|
235
|
-
export const api = {
|
|
236
|
-
posts: {
|
|
237
|
-
findAll: () => request<Post[]>('GET', '/posts'),
|
|
238
|
-
create: (data) => request<Post>('POST', '/posts', data),
|
|
239
|
-
},
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
// Usage - apps/web/app/posts/page.tsx
|
|
243
|
-
import { api } from '@/lib/api';
|
|
244
|
-
|
|
245
|
-
export default async function PostsPage() {
|
|
246
|
-
const posts = await api.posts.findAll(); // Type-safe!
|
|
247
|
-
|
|
248
|
-
return (
|
|
249
|
-
<div>
|
|
250
|
-
{posts.map(post => (
|
|
251
|
-
<article key={post.id}>
|
|
252
|
-
<h2>{post.title}</h2>
|
|
253
|
-
<p>{post.content}</p>
|
|
254
|
-
</article>
|
|
255
|
-
))}
|
|
256
|
-
</div>
|
|
257
|
-
);
|
|
258
|
-
}
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
**Complete type safety from database to UI!**
|
|
262
|
-
|
|
263
|
-
---
|
|
264
|
-
|
|
265
|
-
## 🛠️ Commands
|
|
266
|
-
|
|
267
|
-
```bash
|
|
268
|
-
# Development
|
|
269
|
-
pnpm run dev # Start dev server
|
|
270
|
-
|
|
271
|
-
# Production
|
|
272
|
-
pnpm run build # Build everything
|
|
273
|
-
pnpm start # Start production server
|
|
274
|
-
|
|
275
|
-
# Database
|
|
276
|
-
cd apps/api
|
|
277
|
-
npx prisma migrate dev
|
|
278
|
-
npx prisma studio
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
---
|
|
282
|
-
|
|
283
|
-
## 📦 What's Included
|
|
284
|
-
|
|
285
|
-
- **Next.js 16** - Latest React framework with App Router
|
|
286
|
-
- **NestJS 11** - Modern Node.js framework
|
|
287
|
-
- **Prisma** - Type-safe database ORM
|
|
288
|
-
- **JWT Auth** - Secure authentication
|
|
289
|
-
- **TypeScript** - Full type safety
|
|
290
|
-
- **Tailwind CSS** - Utility-first CSS
|
|
291
|
-
- **Docker** - Production deployment
|
|
292
|
-
- **Examples** - Auth, CRUD, and more
|
|
293
|
-
|
|
294
|
-
---
|
|
295
|
-
|
|
296
|
-
## 🎯 Perfect For
|
|
297
|
-
|
|
298
|
-
✅ Full-stack applications
|
|
299
|
-
✅ SaaS products
|
|
300
|
-
✅ Admin dashboards
|
|
301
|
-
✅ API + Web combo
|
|
302
|
-
✅ Production-ready apps
|
|
303
|
-
✅ Rapid prototyping
|
|
304
|
-
|
|
305
|
-
---
|
|
306
|
-
|
|
307
|
-
## 📚 Documentation
|
|
308
|
-
|
|
309
|
-
- [Getting Started](https://github.com/ziadmustafa1/wexts/blob/main/docs/getting-started.md)
|
|
310
|
-
- [Architecture](https://github.com/ziadmustafa1/wexts/blob/main/docs/architecture.md)
|
|
311
|
-
- [API Reference](https://github.com/ziadmustafa1/wexts/blob/main/docs/api-reference.md)
|
|
312
|
-
- [Deployment](https://github.com/ziadmustafa1/wexts/blob/main/docs/deployment.md)
|
|
313
|
-
- [Examples](https://github.com/ziadmustafa1/wexts/tree/main/demo)
|
|
314
|
-
|
|
315
|
-
---
|
|
316
|
-
|
|
317
|
-
## 🤝 Contributing
|
|
318
|
-
|
|
319
|
-
Contributions are welcome! See [CONTRIBUTING.md](https://github.com/ziadmustafa1/wexts/blob/main/CONTRIBUTING.md)
|
|
320
|
-
|
|
321
|
-
---
|
|
322
|
-
|
|
323
|
-
## 📄 License
|
|
324
|
-
|
|
325
|
-
MIT © WEXTS Team
|
|
326
|
-
|
|
327
|
-
---
|
|
328
|
-
|
|
329
|
-
## 🙏 Built With
|
|
330
|
-
|
|
331
|
-
- [Next.js](https://nextjs.org/) - React framework
|
|
332
|
-
- [NestJS](https://nestjs.com/) - Node.js framework
|
|
333
|
-
- [Prisma](https://www.prisma.io/) - Database ORM
|
|
334
|
-
- [TypeScript](https://www.typescriptlang.org/) - Type safety
|
|
335
|
-
|
|
336
|
-
---
|
|
337
|
-
|
|
338
|
-
<div align="center">
|
|
339
|
-
|
|
340
|
-
**Stop managing separate servers. Start building with WEXTS.** 🚀
|
|
341
|
-
|
|
342
|
-
[GitHub](https://github.com/ziadmustafa1/wexts) • [npm](https://www.npmjs.com/package/wexts) • [Documentation](https://github.com/ziadmustafa1/wexts#readme)
|
|
343
|
-
|
|
344
|
-
Made with ❤️ for the TypeScript community
|
|
345
|
-
|
|
346
|
-
</div>
|
|
1
|
+
# Wexts Package
|
|
2
|
+
|
|
3
|
+
`wexts` is a production-focused toolkit for running Next.js + NestJS behind one Fastify production runtime with generated typed RPC.
|
|
4
|
+
|
|
5
|
+
## Stable In This Patch
|
|
6
|
+
|
|
7
|
+
- `wexts generate` creates a deterministic RPC manifest and typed client.
|
|
8
|
+
- `wexts start` starts the Fastify production runtime.
|
|
9
|
+
- `wexts doctor` and `wexts doctor --security` validate common release blockers.
|
|
10
|
+
- `wexts/next` exposes `FusionProvider`, `useFusion`, and `useWexts<T>()`.
|
|
11
|
+
- `wexts/client` exposes `createWextsRpcClient()`.
|
|
12
|
+
- `wexts/rpc` exposes RPC metadata types/decorators.
|
|
13
|
+
- `wexts/runtime` exposes the production runtime helpers.
|
|
14
|
+
|
|
15
|
+
## Canonical Example
|
|
16
|
+
|
|
17
|
+
Use `examples/hello-rpc` from the repository as the release-verified path.
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pnpm --filter wexts-example-hello-rpc generate
|
|
21
|
+
pnpm --filter wexts-example-hello-rpc build
|
|
22
|
+
pnpm --filter wexts-example-hello-rpc run doctor
|
|
23
|
+
pnpm --filter wexts-example-hello-rpc run doctor:security
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Production Runtime
|
|
27
|
+
|
|
28
|
+
Production runtime is single-port:
|
|
29
|
+
|
|
30
|
+
- `/health`
|
|
31
|
+
- `/api/health`
|
|
32
|
+
- `/rpc/:service/:method`
|
|
33
|
+
- optional Nest under `/api`
|
|
34
|
+
- optional Next frontend routes
|
|
35
|
+
|
|
36
|
+
Development mode currently runs separate web/API processes. Use `wexts start` for the supported single-port runtime path.
|
|
37
|
+
|
|
38
|
+
## Security
|
|
39
|
+
|
|
40
|
+
Use `@wexts/security` / Wexts Shield before runtime routes. It provides application-layer controls. It does not replace Cloudflare/WAF/provider DDoS protection, and its default memory rate limit store is single-process only.
|
|
41
|
+
|
|
42
|
+
## Deprecated Compatibility Paths
|
|
43
|
+
|
|
44
|
+
- `demo/`
|
|
45
|
+
- `packages/templates/nestjs-api`
|
|
46
|
+
- `packages/templates/nextjs-web`
|
|
47
|
+
- legacy Fusion controller codegen paths
|
|
48
|
+
|
|
49
|
+
These are retained for compatibility and should not be marketed as the recommended production structure.
|
package/bin/wexts.cjs
ADDED
package/dist/chunk-2KAQYLVN.js
CHANGED
|
File without changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["
|
|
1
|
+
{"version":3,"sources":["/Volumes/Projects/wexts/packages/dist/chunk-2KAQYLVN.js"],"names":[],"mappings":"AAAA","file":"/Volumes/Projects/wexts/packages/dist/chunk-2KAQYLVN.js"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2;
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2;
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkWCKSKU3Cjs = require('./chunk-WCKSKU3C.js');
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
@@ -30,7 +30,7 @@ var ProcessRunner = (_class = class {constructor() { _class.prototype.__init.cal
|
|
|
30
30
|
blue: pc.blue
|
|
31
31
|
}}
|
|
32
32
|
async run(configs) {
|
|
33
|
-
|
|
33
|
+
_chunkWCKSKU3Cjs.logger.info("\u{1F680} Starting development servers...\n");
|
|
34
34
|
for (const config of configs) {
|
|
35
35
|
this.startProcess(config);
|
|
36
36
|
}
|
|
@@ -41,7 +41,7 @@ var ProcessRunner = (_class = class {constructor() { _class.prototype.__init.cal
|
|
|
41
41
|
const { name, command, args, cwd, color, env } = config;
|
|
42
42
|
const colorFn = this.colors[color];
|
|
43
43
|
const prefix = colorFn(`[${name}]`);
|
|
44
|
-
|
|
44
|
+
_chunkWCKSKU3Cjs.logger.info(`${prefix} Starting...`);
|
|
45
45
|
const proc = _child_process.spawn.call(void 0, command, args, {
|
|
46
46
|
cwd,
|
|
47
47
|
stdio: "pipe",
|
|
@@ -66,18 +66,18 @@ var ProcessRunner = (_class = class {constructor() { _class.prototype.__init.cal
|
|
|
66
66
|
})]);
|
|
67
67
|
proc.on("exit", (code) => {
|
|
68
68
|
if (code !== 0 && code !== null) {
|
|
69
|
-
|
|
69
|
+
_chunkWCKSKU3Cjs.logger.error(`${prefix} Exited with code ${code}`);
|
|
70
70
|
}
|
|
71
71
|
this.processes.delete(name);
|
|
72
72
|
});
|
|
73
73
|
proc.on("error", (error) => {
|
|
74
|
-
|
|
74
|
+
_chunkWCKSKU3Cjs.logger.error(`${prefix} Error:`, error.message);
|
|
75
75
|
});
|
|
76
76
|
}
|
|
77
77
|
stopAll() {
|
|
78
|
-
|
|
78
|
+
_chunkWCKSKU3Cjs.logger.info("\n\u{1F6D1} Stopping all processes...");
|
|
79
79
|
for (const [name, proc] of this.processes.entries()) {
|
|
80
|
-
|
|
80
|
+
_chunkWCKSKU3Cjs.logger.info(`Stopping ${name}...`);
|
|
81
81
|
proc.kill("SIGTERM");
|
|
82
82
|
}
|
|
83
83
|
setTimeout(() => {
|
|
@@ -89,6 +89,71 @@ var ProcessRunner = (_class = class {constructor() { _class.prototype.__init.cal
|
|
|
89
89
|
}
|
|
90
90
|
}, _class);
|
|
91
91
|
|
|
92
|
+
// src/dev-server/dev-server.ts
|
|
93
|
+
var _path = require('path'); var path = _interopRequireWildcard(_path);
|
|
94
|
+
var _fs = require('fs'); var fs = _interopRequireWildcard(_fs);
|
|
95
|
+
var FusionDevServer = class {
|
|
96
|
+
static {
|
|
97
|
+
_chunkXE4OXN2Wjs.__name.call(void 0, this, "FusionDevServer");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
constructor() {
|
|
101
|
+
this.processRunner = new ProcessRunner();
|
|
102
|
+
}
|
|
103
|
+
async start(config) {
|
|
104
|
+
const { apiPath, webPath, webPort = 3e3, apiPort = 5050, useProxy = false } = config;
|
|
105
|
+
if (useProxy) {
|
|
106
|
+
throw new Error("The legacy dev proxy is disabled because it conflicts with the Next.js port. Use the production runtime for single-port serving.");
|
|
107
|
+
}
|
|
108
|
+
if (!fs.existsSync(apiPath)) {
|
|
109
|
+
throw new Error(`API path not found: ${apiPath}`);
|
|
110
|
+
}
|
|
111
|
+
if (!fs.existsSync(webPath)) {
|
|
112
|
+
throw new Error(`Web path not found: ${webPath}`);
|
|
113
|
+
}
|
|
114
|
+
const processes = [];
|
|
115
|
+
processes.push({
|
|
116
|
+
name: "API",
|
|
117
|
+
command: "npm",
|
|
118
|
+
args: [
|
|
119
|
+
"run",
|
|
120
|
+
"start:dev"
|
|
121
|
+
],
|
|
122
|
+
cwd: path.resolve(apiPath),
|
|
123
|
+
color: "cyan",
|
|
124
|
+
env: {
|
|
125
|
+
PORT: apiPort.toString()
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
processes.push({
|
|
129
|
+
name: "Web",
|
|
130
|
+
command: "npm",
|
|
131
|
+
args: [
|
|
132
|
+
"run",
|
|
133
|
+
"dev",
|
|
134
|
+
"--",
|
|
135
|
+
"-p",
|
|
136
|
+
webPort.toString()
|
|
137
|
+
],
|
|
138
|
+
cwd: path.resolve(webPath),
|
|
139
|
+
color: "green",
|
|
140
|
+
env: {
|
|
141
|
+
NEXT_PUBLIC_API_URL: `http://localhost:${apiPort}`
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
await this.processRunner.run(processes);
|
|
145
|
+
_chunkWCKSKU3Cjs.logger.info("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557");
|
|
146
|
+
_chunkWCKSKU3Cjs.logger.info("\u2551 Fusion Development Server Ready \u2551");
|
|
147
|
+
_chunkWCKSKU3Cjs.logger.info("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\n");
|
|
148
|
+
_chunkWCKSKU3Cjs.logger.info(`\u{1F310} Web: http://localhost:${webPort}`);
|
|
149
|
+
_chunkWCKSKU3Cjs.logger.info(`\u{1F50C} API: http://localhost:${apiPort}`);
|
|
150
|
+
_chunkWCKSKU3Cjs.logger.info("\n");
|
|
151
|
+
}
|
|
152
|
+
stop() {
|
|
153
|
+
this.processRunner.stopAll();
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
92
157
|
// src/dev-server/proxy.ts
|
|
93
158
|
var _http = require('http'); var _http2 = _interopRequireDefault(_http);
|
|
94
159
|
var _httpproxy = require('http-proxy'); var _httpproxy2 = _interopRequireDefault(_httpproxy);
|
|
@@ -107,7 +172,7 @@ var ProxyServer = (_class2 = class {constructor() { _class2.prototype.__init3.ca
|
|
|
107
172
|
ws: true
|
|
108
173
|
});
|
|
109
174
|
this.proxy.on("error", (err, req, res) => {
|
|
110
|
-
|
|
175
|
+
_chunkWCKSKU3Cjs.logger.error("Proxy error:", err.message);
|
|
111
176
|
if (res && "headersSent" in res && !res.headersSent) {
|
|
112
177
|
res.writeHead(502, {
|
|
113
178
|
"Content-Type": "text/plain"
|
|
@@ -119,7 +184,7 @@ var ProxyServer = (_class2 = class {constructor() { _class2.prototype.__init3.ca
|
|
|
119
184
|
if (_optionalChain([req, 'access', _7 => _7.url, 'optionalAccess', _8 => _8.startsWith, 'call', _9 => _9(apiPrefix)])) {
|
|
120
185
|
const newUrl = req.url.substring(apiPrefix.length) || "/";
|
|
121
186
|
req.url = newUrl;
|
|
122
|
-
|
|
187
|
+
_chunkWCKSKU3Cjs.logger.info(pc2.gray(`\u2192 ${req.method} ${apiPrefix}${newUrl}`));
|
|
123
188
|
this.proxy.web(req, res);
|
|
124
189
|
} else {
|
|
125
190
|
res.writeHead(404);
|
|
@@ -135,8 +200,8 @@ var ProxyServer = (_class2 = class {constructor() { _class2.prototype.__init3.ca
|
|
|
135
200
|
});
|
|
136
201
|
return new Promise((resolve2) => {
|
|
137
202
|
this.server.listen(port, () => {
|
|
138
|
-
|
|
139
|
-
|
|
203
|
+
_chunkWCKSKU3Cjs.logger.success(`\u2705 Proxy server running on port ${port}`);
|
|
204
|
+
_chunkWCKSKU3Cjs.logger.info(` Forwarding ${pc2.cyan(apiPrefix + "/*")} \u2192 ${pc2.cyan(apiTarget)}
|
|
140
205
|
`);
|
|
141
206
|
resolve2();
|
|
142
207
|
});
|
|
@@ -154,89 +219,10 @@ var ProxyServer = (_class2 = class {constructor() { _class2.prototype.__init3.ca
|
|
|
154
219
|
}
|
|
155
220
|
}, _class2);
|
|
156
221
|
|
|
157
|
-
// src/dev-server/dev-server.ts
|
|
158
|
-
var _path = require('path'); var path = _interopRequireWildcard(_path);
|
|
159
|
-
var _fs = require('fs'); var fs = _interopRequireWildcard(_fs);
|
|
160
|
-
var FusionDevServer = (_class3 = class {
|
|
161
|
-
static {
|
|
162
|
-
_chunkXE4OXN2Wjs.__name.call(void 0, this, "FusionDevServer");
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
__init5() {this.proxyServer = null}
|
|
166
|
-
constructor() {;_class3.prototype.__init5.call(this);
|
|
167
|
-
this.processRunner = new ProcessRunner();
|
|
168
|
-
}
|
|
169
|
-
async start(config) {
|
|
170
|
-
const { apiPath, webPath, webPort = 3e3, apiPort = 5050, useProxy = true } = config;
|
|
171
|
-
if (!fs.existsSync(apiPath)) {
|
|
172
|
-
throw new Error(`API path not found: ${apiPath}`);
|
|
173
|
-
}
|
|
174
|
-
if (!fs.existsSync(webPath)) {
|
|
175
|
-
throw new Error(`Web path not found: ${webPath}`);
|
|
176
|
-
}
|
|
177
|
-
const processes = [];
|
|
178
|
-
processes.push({
|
|
179
|
-
name: "API",
|
|
180
|
-
command: "npm",
|
|
181
|
-
args: [
|
|
182
|
-
"run",
|
|
183
|
-
"start:dev"
|
|
184
|
-
],
|
|
185
|
-
cwd: path.resolve(apiPath),
|
|
186
|
-
color: "cyan",
|
|
187
|
-
env: {
|
|
188
|
-
PORT: apiPort.toString()
|
|
189
|
-
}
|
|
190
|
-
});
|
|
191
|
-
processes.push({
|
|
192
|
-
name: "Web",
|
|
193
|
-
command: "npm",
|
|
194
|
-
args: [
|
|
195
|
-
"run",
|
|
196
|
-
"dev",
|
|
197
|
-
"--",
|
|
198
|
-
"-p",
|
|
199
|
-
webPort.toString()
|
|
200
|
-
],
|
|
201
|
-
cwd: path.resolve(webPath),
|
|
202
|
-
color: "green",
|
|
203
|
-
env: {
|
|
204
|
-
NEXT_PUBLIC_API_URL: useProxy ? `http://localhost:${webPort}/api` : `http://localhost:${apiPort}`
|
|
205
|
-
}
|
|
206
|
-
});
|
|
207
|
-
if (useProxy) {
|
|
208
|
-
this.proxyServer = new ProxyServer();
|
|
209
|
-
setTimeout(async () => {
|
|
210
|
-
await this.proxyServer.start({
|
|
211
|
-
port: webPort,
|
|
212
|
-
apiTarget: `http://localhost:${apiPort}`,
|
|
213
|
-
apiPrefix: "/api"
|
|
214
|
-
});
|
|
215
|
-
}, 3e3);
|
|
216
|
-
}
|
|
217
|
-
await this.processRunner.run(processes);
|
|
218
|
-
_chunk3OM7CHCAjs.logger.info("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557");
|
|
219
|
-
_chunk3OM7CHCAjs.logger.info("\u2551 Fusion Development Server Ready \u2551");
|
|
220
|
-
_chunk3OM7CHCAjs.logger.info("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D\n");
|
|
221
|
-
_chunk3OM7CHCAjs.logger.info(`\u{1F310} Web: http://localhost:${webPort}`);
|
|
222
|
-
_chunk3OM7CHCAjs.logger.info(`\u{1F50C} API: http://localhost:${apiPort}`);
|
|
223
|
-
if (useProxy) {
|
|
224
|
-
_chunk3OM7CHCAjs.logger.info(`\u{1F504} Proxy: Enabled (${webPort}/api \u2192 ${apiPort})`);
|
|
225
|
-
}
|
|
226
|
-
_chunk3OM7CHCAjs.logger.info("\n");
|
|
227
|
-
}
|
|
228
|
-
stop() {
|
|
229
|
-
this.processRunner.stopAll();
|
|
230
|
-
if (this.proxyServer) {
|
|
231
|
-
this.proxyServer.stop();
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}, _class3);
|
|
235
|
-
|
|
236
222
|
|
|
237
223
|
|
|
238
224
|
|
|
239
225
|
|
|
240
226
|
|
|
241
|
-
exports.ProcessRunner = ProcessRunner; exports.
|
|
242
|
-
//# sourceMappingURL=chunk-
|
|
227
|
+
exports.ProcessRunner = ProcessRunner; exports.FusionDevServer = FusionDevServer; exports.ProxyServer = ProxyServer; exports.dev_server_exports = dev_server_exports;
|
|
228
|
+
//# sourceMappingURL=chunk-2LJVUMXW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Volumes/Projects/wexts/packages/dist/chunk-2LJVUMXW.js","../src/dev-server/index.ts","../src/dev-server/process-runner.ts","../src/dev-server/dev-server.ts","../src/dev-server/proxy.ts"],"names":["ProcessRunner","processes","Map","colors","cyan","green","yellow","magenta","blue","run","configs","logger","info","config","startProcess","process","on","stopAll","name","command","args","cwd","color","env","colorFn","prefix","spawn","lines","forEach","log","error","code","exit","path","fs","FusionDevServer","processRunner","apiPath","useProxy","Error","existsSync","push","resolve","apiPort","toString","NEXT_PUBLIC_API_URL","httpProxy","pc","ProxyServer","port","apiTarget","changeOrigin","writeHead","server","url","newUrl","proxy","Promise","success","close"],"mappings":"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","file":"/Volumes/Projects/wexts/packages/dist/chunk-2LJVUMXW.js","sourcesContent":[null,"export * from './dev-server';\nexport * from './process-runner';\nexport * from './proxy';\n","import { spawn, ChildProcess } from 'child_process';\nimport { logger } from '../core/logger';\nimport * as pc from 'picocolors';\n\nexport interface ProcessConfig {\n name: string;\n command: string;\n args: string[];\n cwd: string;\n color: 'cyan' | 'green' | 'yellow' | 'magenta' | 'blue';\n env?: Record<string, string>;\n}\n\n/**\n * Run multiple processes concurrently with colored output\n */\nexport class ProcessRunner {\n private processes: Map<string, ChildProcess> = new Map();\n private colors = {\n cyan: pc.cyan,\n green: pc.green,\n yellow: pc.yellow,\n magenta: pc.magenta,\n blue: pc.blue,\n };\n\n async run(configs: ProcessConfig[]): Promise<void> {\n logger.info('🚀 Starting development servers...\\n');\n\n for (const config of configs) {\n this.startProcess(config);\n }\n\n // Handle graceful shutdown\n process.on('SIGINT', () => this.stopAll());\n process.on('SIGTERM', () => this.stopAll());\n }\n\n private startProcess(config: ProcessConfig): void {\n const { name, command, args, cwd, color, env } = config;\n\n const colorFn = this.colors[color];\n const prefix = colorFn(`[${name}]`);\n\n logger.info(`${prefix} Starting...`);\n\n const proc = spawn(command, args, {\n cwd,\n stdio: 'pipe',\n shell: true,\n env: { ...process.env, ...env },\n });\n\n this.processes.set(name, proc);\n\n // Handle stdout\n proc.stdout?.on('data', (data) => {\n const lines = data.toString().split('\\n').filter((l: string) => l.trim());\n lines.forEach((line: string) => {\n console.log(`${prefix} ${line}`);\n });\n });\n\n // Handle stderr\n proc.stderr?.on('data', (data) => {\n const lines = data.toString().split('\\n').filter((l: string) => l.trim());\n lines.forEach((line: string) => {\n console.error(`${prefix} ${pc.red(line)}`);\n });\n });\n\n // Handle exit\n proc.on('exit', (code) => {\n if (code !== 0 && code !== null) {\n logger.error(`${prefix} Exited with code ${code}`);\n }\n this.processes.delete(name);\n });\n\n // Handle errors\n proc.on('error', (error) => {\n logger.error(`${prefix} Error:`, error.message);\n });\n }\n\n stopAll(): void {\n logger.info('\\n🛑 Stopping all processes...');\n\n for (const [name, proc] of this.processes.entries()) {\n logger.info(`Stopping ${name}...`);\n proc.kill('SIGTERM');\n }\n\n setTimeout(() => {\n process.exit(0);\n }, 1000);\n }\n\n isRunning(name: string): boolean {\n return this.processes.has(name);\n }\n}\n","import { ProcessRunner, ProcessConfig } from './process-runner';\nimport { logger } from '../core/logger';\nimport * as path from 'path';\nimport * as fs from 'fs';\n\nexport interface DevServerConfig {\n apiPath: string;\n webPath: string;\n webPort?: number;\n apiPort?: number;\n useProxy?: boolean;\n}\n\n/**\n * Unified development server for Fusion projects\n */\nexport class FusionDevServer {\n private processRunner: ProcessRunner;\n\n constructor() {\n this.processRunner = new ProcessRunner();\n }\n\n async start(config: DevServerConfig): Promise<void> {\n const {\n apiPath,\n webPath,\n webPort = 3000,\n apiPort = 5050,\n useProxy = false,\n } = config;\n\n if (useProxy) {\n throw new Error('The legacy dev proxy is disabled because it conflicts with the Next.js port. Use the production runtime for single-port serving.');\n }\n\n // Validate paths\n if (!fs.existsSync(apiPath)) {\n throw new Error(`API path not found: ${apiPath}`);\n }\n if (!fs.existsSync(webPath)) {\n throw new Error(`Web path not found: ${webPath}`);\n }\n\n const processes: ProcessConfig[] = [];\n\n // Add API server\n processes.push({\n name: 'API',\n command: 'npm',\n args: ['run', 'start:dev'],\n cwd: path.resolve(apiPath),\n color: 'cyan',\n env: {\n PORT: apiPort.toString(),\n },\n });\n\n // Add Web server\n processes.push({\n name: 'Web',\n command: 'npm',\n args: ['run', 'dev', '--', '-p', webPort.toString()],\n cwd: path.resolve(webPath),\n color: 'green',\n env: {\n NEXT_PUBLIC_API_URL: `http://localhost:${apiPort}`,\n },\n });\n\n // Start processes\n await this.processRunner.run(processes);\n\n // Log info\n logger.info('╔═══════════════════════════════════════╗');\n logger.info('║ Fusion Development Server Ready ║');\n logger.info('╚═══════════════════════════════════════╝\\n');\n logger.info(`🌐 Web: http://localhost:${webPort}`);\n logger.info(`🔌 API: http://localhost:${apiPort}`);\n logger.info('\\n');\n }\n\n stop(): void {\n this.processRunner.stopAll();\n }\n}\n","import http from 'http';\nimport httpProxy from 'http-proxy';\nimport { logger } from '../core/logger';\nimport * as pc from 'picocolors';\n\nexport interface ProxyConfig {\n port: number;\n apiTarget: string;\n apiPrefix: string;\n}\n\n/**\n * Proxy server to forward API requests from Next.js to NestJS\n */\nexport class ProxyServer {\n private server: http.Server | null = null;\n private proxy: httpProxy | null = null;\n\n async start(config: ProxyConfig): Promise<void> {\n const { port, apiTarget, apiPrefix } = config;\n\n this.proxy = httpProxy.createProxyServer({\n target: apiTarget,\n changeOrigin: true,\n ws: true, // WebSocket support\n });\n\n // Handle proxy errors\n this.proxy.on('error', (err, req, res) => {\n logger.error('Proxy error:', err.message);\n if (res && 'headersSent' in res && !(res as any).headersSent) {\n (res as http.ServerResponse).writeHead(502, { 'Content-Type': 'text/plain' });\n (res as http.ServerResponse).end('Bad Gateway - API server unavailable');\n }\n });\n\n this.server = http.createServer((req, res) => {\n // Check if request is for API\n if (req.url?.startsWith(apiPrefix)) {\n // Remove prefix before forwarding\n const newUrl = req.url.substring(apiPrefix.length) || '/';\n req.url = newUrl;\n\n logger.info(pc.gray(`→ ${req.method} ${apiPrefix}${newUrl}`));\n this.proxy!.web(req, res);\n } else {\n // Not an API request - should not happen\n res.writeHead(404);\n res.end('Not Found');\n }\n });\n\n // Handle WebSocket upgrade\n this.server.on('upgrade', (req, socket, head) => {\n if (req.url?.startsWith(apiPrefix)) {\n const newUrl = req.url.substring(apiPrefix.length) || '/';\n req.url = newUrl;\n this.proxy!.ws(req, socket, head);\n }\n });\n\n return new Promise((resolve) => {\n this.server!.listen(port, () => {\n logger.success(`✅ Proxy server running on port ${port}`);\n logger.info(` Forwarding ${pc.cyan(apiPrefix + '/*')} → ${pc.cyan(apiTarget)}\\n`);\n resolve();\n });\n });\n }\n\n stop(): void {\n if (this.server) {\n this.server.close();\n this.server = null;\n }\n if (this.proxy) {\n this.proxy.close();\n this.proxy = null;\n }\n }\n}\n"]}
|