wexts 1.0.1
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 +443 -0
- package/dist/chunk-2H7UOFLK.js +11 -0
- package/dist/chunk-2H7UOFLK.js.map +1 -0
- package/dist/chunk-2ZKONAXC.js +45 -0
- package/dist/chunk-2ZKONAXC.js.map +1 -0
- package/dist/chunk-57VDULE3.mjs +83 -0
- package/dist/chunk-57VDULE3.mjs.map +1 -0
- package/dist/chunk-6K3RXN4Y.mjs +45 -0
- package/dist/chunk-6K3RXN4Y.mjs.map +1 -0
- package/dist/chunk-6KN6UIHT.js +67 -0
- package/dist/chunk-6KN6UIHT.js.map +1 -0
- package/dist/chunk-A5OZK2TO.mjs +56 -0
- package/dist/chunk-A5OZK2TO.mjs.map +1 -0
- package/dist/chunk-ELVFG4US.js +83 -0
- package/dist/chunk-ELVFG4US.js.map +1 -0
- package/dist/chunk-H6XDQJ3N.mjs +11 -0
- package/dist/chunk-H6XDQJ3N.mjs.map +1 -0
- package/dist/chunk-HE3JQ62E.js +56 -0
- package/dist/chunk-HE3JQ62E.js.map +1 -0
- package/dist/chunk-HHXRAV67.mjs +229 -0
- package/dist/chunk-HHXRAV67.mjs.map +1 -0
- package/dist/chunk-J7J2LRG7.js +229 -0
- package/dist/chunk-J7J2LRG7.js.map +1 -0
- package/dist/chunk-LWNHEPTL.mjs +2 -0
- package/dist/chunk-LWNHEPTL.mjs.map +1 -0
- package/dist/chunk-MAVJYD6O.js +2 -0
- package/dist/chunk-MAVJYD6O.js.map +1 -0
- package/dist/chunk-QUV6QXTP.js +363 -0
- package/dist/chunk-QUV6QXTP.js.map +1 -0
- package/dist/chunk-WZBBQLFT.mjs +363 -0
- package/dist/chunk-WZBBQLFT.mjs.map +1 -0
- package/dist/chunk-XMPCR7N3.mjs +67 -0
- package/dist/chunk-XMPCR7N3.mjs.map +1 -0
- package/dist/cli/index.mjs +69 -0
- package/dist/cli/index.mjs.map +1 -0
- package/dist/client/index.js +11 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/index.mjs +11 -0
- package/dist/client/index.mjs.map +1 -0
- package/dist/codegen-J3XOZCQZ.js +14 -0
- package/dist/codegen-J3XOZCQZ.js.map +1 -0
- package/dist/codegen-ZZBQIGUQ.mjs +14 -0
- package/dist/codegen-ZZBQIGUQ.mjs.map +1 -0
- package/dist/dev-server-K5YZAZY2.mjs +14 -0
- package/dist/dev-server-K5YZAZY2.mjs.map +1 -0
- package/dist/dev-server-X453DBCE.js +14 -0
- package/dist/dev-server-X453DBCE.js.map +1 -0
- package/dist/index.js +274 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +274 -0
- package/dist/index.mjs.map +1 -0
- package/dist/nest/index.js +21 -0
- package/dist/nest/index.js.map +1 -0
- package/dist/nest/index.mjs +21 -0
- package/dist/nest/index.mjs.map +1 -0
- package/dist/next/index.js +14 -0
- package/dist/next/index.js.map +1 -0
- package/dist/next/index.mjs +14 -0
- package/dist/next/index.mjs.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/index.mjs +3 -0
- package/dist/types/index.mjs.map +1 -0
- package/package.json +104 -0
- package/templates/nestjs-api/.env.example +4 -0
- package/templates/nestjs-api/README.md +79 -0
- package/templates/nestjs-api/nest-cli.json +7 -0
- package/templates/nestjs-api/package.json +39 -0
- package/templates/nestjs-api/prisma/schema.prisma +29 -0
- package/templates/nestjs-api/src/app.module.ts +17 -0
- package/templates/nestjs-api/src/auth/auth.controller.ts +30 -0
- package/templates/nestjs-api/src/auth/auth.module.ts +26 -0
- package/templates/nestjs-api/src/auth/auth.service.ts +91 -0
- package/templates/nestjs-api/src/auth/dto/auth.dto.ts +22 -0
- package/templates/nestjs-api/src/auth/guards/jwt-auth.guard.ts +5 -0
- package/templates/nestjs-api/src/auth/strategies/jwt.strategy.ts +19 -0
- package/templates/nestjs-api/src/main.ts +32 -0
- package/templates/nestjs-api/src/prisma/prisma.module.ts +9 -0
- package/templates/nestjs-api/src/prisma/prisma.service.ts +14 -0
- package/templates/nestjs-api/src/todos/dto/todo.dto.ts +24 -0
- package/templates/nestjs-api/src/todos/todos.controller.ts +46 -0
- package/templates/nestjs-api/src/todos/todos.module.ts +9 -0
- package/templates/nestjs-api/src/todos/todos.service.ts +53 -0
- package/templates/nestjs-api/src/users/users.controller.ts +17 -0
- package/templates/nestjs-api/src/users/users.module.ts +10 -0
- package/templates/nestjs-api/src/users/users.service.ts +19 -0
- package/templates/nestjs-api/tsconfig.json +21 -0
- package/templates/nextjs-web/.env.local.example +1 -0
- package/templates/nextjs-web/README.md +68 -0
- package/templates/nextjs-web/app/dashboard/page.tsx +175 -0
- package/templates/nextjs-web/app/globals.css +28 -0
- package/templates/nextjs-web/app/layout.tsx +27 -0
- package/templates/nextjs-web/app/login/page.tsx +107 -0
- package/templates/nextjs-web/app/page.tsx +28 -0
- package/templates/nextjs-web/app/register/page.tsx +130 -0
- package/templates/nextjs-web/next.config.mjs +4 -0
- package/templates/nextjs-web/package.json +28 -0
- package/templates/nextjs-web/tailwind.config.ts +15 -0
- package/templates/nextjs-web/tsconfig.json +39 -0
package/README.md
ADDED
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
# Wexts Framework
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
**Wexts** (formerly wexts) is a powerful, production-ready full-stack framework that unifies **NestJS 10** and **Next.js 16** development. Build type-safe applications with automatic API client generation, shared types, and zero boilerplate.
|
|
7
|
+
|
|
8
|
+
## 🚀 Features
|
|
9
|
+
|
|
10
|
+
- **🔗 NestJS + Next.js Integration**: Seamless backend-frontend connection
|
|
11
|
+
- **📦 All-in-One SDK**: Core utilities, HTTP client, decorators, and hooks in one package
|
|
12
|
+
- **🎯 Type-Safe**: End-to-end TypeScript from database to UI
|
|
13
|
+
- **🛠️ CLI Tools**: Scaffold projects, generate code, manage development
|
|
14
|
+
- **⚡ Auto API Client**: Generate type-safe clients from NestJS controllers
|
|
15
|
+
- **🔐 Auth Built-in**: Ready-to-use authentication hooks for Next.js
|
|
16
|
+
- **📝 Configuration Management**: Environment-aware config loader
|
|
17
|
+
- **🎨 React Hooks**: `useFusion()`, `useAuth()` for seamless API integration
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 📦 Installation
|
|
22
|
+
|
|
23
|
+
### Global CLI
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install -g wexts
|
|
27
|
+
# or
|
|
28
|
+
yarn global add wexts
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Project Dependency
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install wexts
|
|
35
|
+
# or
|
|
36
|
+
yarn add wexts
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 🏁 Quick Start
|
|
42
|
+
|
|
43
|
+
### Create New Project
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
fusion create my-app --template monorepo
|
|
47
|
+
cd my-app
|
|
48
|
+
fusion dev
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
This creates:
|
|
52
|
+
- `apps/api/` - NestJS 10 backend
|
|
53
|
+
- `apps/web/` - Next.js 16 frontend
|
|
54
|
+
- `packages/types/` - Shared TypeScript definitions
|
|
55
|
+
- `packages/api-client/` - Auto-generated SDK
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## 📚 Usage
|
|
60
|
+
|
|
61
|
+
### NestJS Backend
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import { Controller, Get, Post, Body } from '@nestjs/common';
|
|
65
|
+
import { FusionController, FusionGet, FusionPost } from 'wexts/nest';
|
|
66
|
+
|
|
67
|
+
@FusionController('users')
|
|
68
|
+
@Controller('users')
|
|
69
|
+
export class UsersController {
|
|
70
|
+
@FusionGet()
|
|
71
|
+
async findAll() {
|
|
72
|
+
return this.usersService.findAll();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@FusionPost()
|
|
76
|
+
async create(@Body() createUserDto: CreateUserDto) {
|
|
77
|
+
return this.usersService.create(createUserDto);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Benefits**: The `@FusionController` and `@FusionRoute` decorators add metadata for automatic API client generation.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
### Next.js Frontend
|
|
87
|
+
|
|
88
|
+
#### Setup Provider
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
// app/layout.tsx
|
|
92
|
+
import { FusionProvider } from 'wexts/next';
|
|
93
|
+
|
|
94
|
+
export default function RootLayout({ children }) {
|
|
95
|
+
return (
|
|
96
|
+
<html lang="en">
|
|
97
|
+
<body>
|
|
98
|
+
<FusionProvider baseUrl={process.env.NEXT_PUBLIC_API_URL || '/api'}>
|
|
99
|
+
{children}
|
|
100
|
+
</FusionProvider>
|
|
101
|
+
</body>
|
|
102
|
+
</html>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
#### Use in Components
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
'use client';
|
|
111
|
+
import { useFusion, useAuth } from 'wexts/next';
|
|
112
|
+
import { useEffect, useState } from 'react';
|
|
113
|
+
|
|
114
|
+
export default function UsersPage() {
|
|
115
|
+
const { client } = useFusion();
|
|
116
|
+
const { user, isAuthenticated } = useAuth();
|
|
117
|
+
const [users, setUsers] = useState([]);
|
|
118
|
+
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
client.get<User[]>('/users').then(setUsers);
|
|
121
|
+
}, []);
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<div>
|
|
125
|
+
{isAuthenticated && <p>Welcome, {user.name}!</p>}
|
|
126
|
+
<ul>
|
|
127
|
+
{users.map(u => <li key={u.id}>{u.name}</li>)}
|
|
128
|
+
</ul>
|
|
129
|
+
</div>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
### HTTP Client
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
import { apiFetcher } from 'wexts/client';
|
|
140
|
+
|
|
141
|
+
// GET request
|
|
142
|
+
const users = await apiFetcher.get<User[]>('/users');
|
|
143
|
+
|
|
144
|
+
// POST request
|
|
145
|
+
const newUser = await apiFetcher.post('/users', {
|
|
146
|
+
name: 'John',
|
|
147
|
+
email: 'john@example.com'
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Automatic Bearer token from localStorage
|
|
151
|
+
// Token stored as 'fusion_token'
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
### Configuration
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
import { config } from 'wexts';
|
|
160
|
+
|
|
161
|
+
// Load from fusion.config.json or environment variables
|
|
162
|
+
const dbUrl = config.load('database');
|
|
163
|
+
const apiKey = config.load('apiKey', 'default-key');
|
|
164
|
+
|
|
165
|
+
// Set runtime config
|
|
166
|
+
config.set('feature_flags', { newUI: true });
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
### Logging
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
import { logger, createLogger, LogLevel } from 'wexts';
|
|
175
|
+
|
|
176
|
+
logger.info('Application started');
|
|
177
|
+
logger.error('Connection failed:', error);
|
|
178
|
+
logger.success('Build complete!');
|
|
179
|
+
|
|
180
|
+
// Custom logger
|
|
181
|
+
const apiLogger = createLogger({
|
|
182
|
+
prefix: '[API]',
|
|
183
|
+
level: LogLevel.DEBUG,
|
|
184
|
+
timestamp: true
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
apiLogger.debug('Detailed debug info');
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## 🛠 CLI Commands
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
# Create new project
|
|
196
|
+
fusion create <name> [--template monorepo|api|web]
|
|
197
|
+
|
|
198
|
+
# Start development servers
|
|
199
|
+
fusion dev [--port <port>]
|
|
200
|
+
|
|
201
|
+
# Build for production
|
|
202
|
+
fusion build
|
|
203
|
+
|
|
204
|
+
# Generate code
|
|
205
|
+
fusion generate controller <name>
|
|
206
|
+
fusion g module <name>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## 📖 API Reference
|
|
212
|
+
|
|
213
|
+
### Core Modules
|
|
214
|
+
|
|
215
|
+
#### `wexts` (Main)
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
import { Core, Config, Insight, Nest, Next } from 'wexts';
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
- **`Core`**: Process management, filesystem utilities
|
|
222
|
+
- **`Config`**: Configuration loader
|
|
223
|
+
- **`Insight`**: Logging and metrics
|
|
224
|
+
- **`Nest`**: NestJS decorators and helpers
|
|
225
|
+
- **`Next`**: Next.js providers and hooks
|
|
226
|
+
|
|
227
|
+
#### `wexts/client`
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
import { FusionFetcher, apiFetcher } from 'wexts/client';
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
- **`FusionFetcher`**: HTTP client class
|
|
234
|
+
- **`apiFetcher`**: Singleton instance
|
|
235
|
+
|
|
236
|
+
#### `wexts/nest`
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
import {
|
|
240
|
+
FusionController,
|
|
241
|
+
FusionGet,
|
|
242
|
+
FusionPost,
|
|
243
|
+
FusionPut,
|
|
244
|
+
FusionDelete
|
|
245
|
+
} from 'wexts/nest';
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
- NestJS decorators for API codegen
|
|
249
|
+
- Works alongside standard `@nestjs/common` decorators
|
|
250
|
+
|
|
251
|
+
#### `wexts/next`
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
import {
|
|
255
|
+
FusionProvider,
|
|
256
|
+
useFusion,
|
|
257
|
+
useAuth
|
|
258
|
+
} from 'wexts/next';
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
- **`FusionProvider`**: React Context provider for API client
|
|
262
|
+
- **`useFusion()`**: Access API client in components
|
|
263
|
+
- **`useAuth()`**: Authentication state management
|
|
264
|
+
|
|
265
|
+
#### `wexts/types`
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
import type { User, ApiResponse, FusionConfig } from 'wexts/types';
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
- Shared TypeScript type definitions
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## 🏗️ Project Structure
|
|
276
|
+
|
|
277
|
+
When you create a new project with `fusion create`, you get:
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
my-app/
|
|
281
|
+
├── apps/
|
|
282
|
+
│ ├── api/ # NestJS 10 backend
|
|
283
|
+
│ │ ├── src/
|
|
284
|
+
│ │ │ ├── main.ts
|
|
285
|
+
│ │ │ ├── app.module.ts
|
|
286
|
+
│ │ │ └── users/
|
|
287
|
+
│ │ │ ├── users.controller.ts
|
|
288
|
+
│ │ │ └── users.service.ts
|
|
289
|
+
│ │ └── package.json
|
|
290
|
+
│ │
|
|
291
|
+
│ └── web/ # Next.js 16 frontend
|
|
292
|
+
│ ├── app/
|
|
293
|
+
│ │ ├── layout.tsx
|
|
294
|
+
│ │ ├── page.tsx
|
|
295
|
+
│ │ └── users/
|
|
296
|
+
│ │ └── page.tsx
|
|
297
|
+
│ └── package.json
|
|
298
|
+
│
|
|
299
|
+
├── packages/
|
|
300
|
+
│ ├── types/ # Shared DTOs
|
|
301
|
+
│ │ └── src/
|
|
302
|
+
│ │ ├── user.ts
|
|
303
|
+
│ │ └── index.ts
|
|
304
|
+
│ │
|
|
305
|
+
│ └── api-client/ # Auto-generated SDK
|
|
306
|
+
│ └── src/
|
|
307
|
+
│ └── index.ts
|
|
308
|
+
│
|
|
309
|
+
├── turbo.json # TurboRepo config
|
|
310
|
+
├── package.json # Root package
|
|
311
|
+
└── fusion.config.json # Fusion configuration
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## ⚙️ Configuration
|
|
317
|
+
|
|
318
|
+
Create `fusion.config.json` in your project root:
|
|
319
|
+
|
|
320
|
+
```json
|
|
321
|
+
{
|
|
322
|
+
"database": "postgresql://localhost/mydb",
|
|
323
|
+
"apiPort": 5050,
|
|
324
|
+
"webPort": 3000,
|
|
325
|
+
"jwt": {
|
|
326
|
+
"secret": "your-secret-key",
|
|
327
|
+
"expiresIn": "7d"
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Access via:
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
import { config } from 'wexts';
|
|
336
|
+
|
|
337
|
+
const dbUrl = config.load('database');
|
|
338
|
+
const jwtConfig = config.load('jwt');
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**Environment Variables**: Prefix with `FUSION_`
|
|
342
|
+
|
|
343
|
+
```bash
|
|
344
|
+
FUSION_DATABASE=postgresql://localhost/mydb
|
|
345
|
+
FUSION_JWT__SECRET=your-secret-key
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## 🔐 Authentication Example
|
|
351
|
+
|
|
352
|
+
### Backend (NestJS)
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
import { Controller, Post, Body } from '@nestjs/common';
|
|
356
|
+
import { FusionPost } from 'wexts/nest';
|
|
357
|
+
|
|
358
|
+
@Controller('auth')
|
|
359
|
+
export class AuthController {
|
|
360
|
+
@FusionPost()
|
|
361
|
+
@Post('login')
|
|
362
|
+
async login(@Body() credentials: LoginDto) {
|
|
363
|
+
const token = await this.authService.validateUser(credentials);
|
|
364
|
+
return { token, user: { id: 1, email: credentials.email } };
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Frontend (Next.js)
|
|
370
|
+
|
|
371
|
+
```tsx
|
|
372
|
+
'use client';
|
|
373
|
+
import { useAuth } from 'wexts/next';
|
|
374
|
+
|
|
375
|
+
export default function LoginPage() {
|
|
376
|
+
const { login, user, isAuthenticated, loading } = useAuth();
|
|
377
|
+
|
|
378
|
+
const handleLogin = async (e: FormEvent) => {
|
|
379
|
+
e.preventDefault();
|
|
380
|
+
await login('user@example.com', 'password');
|
|
381
|
+
// Automatically redirects or updates UI
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
if (loading) return <p>Loading...</p>;
|
|
385
|
+
if (isAuthenticated) return <p>Welcome, {user.name}!</p>;
|
|
386
|
+
|
|
387
|
+
return (
|
|
388
|
+
<form onSubmit={handleLogin}>
|
|
389
|
+
<input type="email" required />
|
|
390
|
+
<input type="password" required />
|
|
391
|
+
<button type="submit">Login</button>
|
|
392
|
+
</form>
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
## 🚀 Deployment
|
|
400
|
+
|
|
401
|
+
### Build
|
|
402
|
+
|
|
403
|
+
```bash
|
|
404
|
+
fusion build
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Deploy API (NestJS)
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
cd apps/api
|
|
411
|
+
npm run build
|
|
412
|
+
npm run start:prod
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Deploy Web (Next.js)
|
|
416
|
+
|
|
417
|
+
```bash
|
|
418
|
+
cd apps/web
|
|
419
|
+
npm run build
|
|
420
|
+
npm start
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
## 📄 License
|
|
426
|
+
|
|
427
|
+
MIT © [wexts Team](https://github.com/ziadmustafa1/wexts)
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
## 🤝 Contributing
|
|
432
|
+
|
|
433
|
+
Contributions welcome! Please read our contributing guidelines.
|
|
434
|
+
|
|
435
|
+
## 📬 Support
|
|
436
|
+
|
|
437
|
+
- **GitHub**: [ziadmustafa1/wexts](https://github.com/ziadmustafa1/wexts)
|
|
438
|
+
- **Issues**: [Report bugs](https://github.com/ziadmustafa1/wexts/issues)
|
|
439
|
+
- **Discussions**: [Community forums](https://github.com/ziadmustafa1/wexts/discussions)
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
**Built with ❤️ by the wexts Team**
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var __defProp = Object.defineProperty;
|
|
3
|
+
var __export = (target, all) => {
|
|
4
|
+
for (var name in all)
|
|
5
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
exports.__export = __export;
|
|
11
|
+
//# sourceMappingURL=chunk-2H7UOFLK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["c:\\Users\\ziad\\Desktop\\FusionJS\\packages\\fusionjs\\dist\\chunk-2H7UOFLK.js"],"names":[],"mappings":"AAAA;AACA,6EAAI,UAAU,EAAE,MAAM,CAAC,cAAc;AACrC,IAAI,SAAS,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG;AAChC,EAAE,IAAI,CAAC,IAAI,KAAK,GAAG,GAAG;AACtB,IAAI,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;AACjE,CAAC;AACD;AACA;AACE;AACF,4BAAC","file":"C:\\Users\\ziad\\Desktop\\FusionJS\\packages\\fusionjs\\dist\\chunk-2H7UOFLK.js"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
3
|
+
// src/client/fetcher.ts
|
|
4
|
+
var FusionFetcher = class {
|
|
5
|
+
constructor(baseUrl = "/api") {
|
|
6
|
+
this.baseUrl = baseUrl;
|
|
7
|
+
}
|
|
8
|
+
async request(method, path, body) {
|
|
9
|
+
const headers = {
|
|
10
|
+
"Content-Type": "application/json"
|
|
11
|
+
};
|
|
12
|
+
if (typeof window !== "undefined") {
|
|
13
|
+
const token = localStorage.getItem("fusion_token");
|
|
14
|
+
if (token) headers["Authorization"] = `Bearer ${token}`;
|
|
15
|
+
}
|
|
16
|
+
const response = await fetch(`${this.baseUrl}${path}`, {
|
|
17
|
+
method,
|
|
18
|
+
headers,
|
|
19
|
+
body: body ? JSON.stringify(body) : void 0
|
|
20
|
+
});
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
throw new Error(`Fusion API Error: ${response.statusText}`);
|
|
23
|
+
}
|
|
24
|
+
return response.json();
|
|
25
|
+
}
|
|
26
|
+
get(path) {
|
|
27
|
+
return this.request("GET", path);
|
|
28
|
+
}
|
|
29
|
+
post(path, body) {
|
|
30
|
+
return this.request("POST", path, body);
|
|
31
|
+
}
|
|
32
|
+
put(path, body) {
|
|
33
|
+
return this.request("PUT", path, body);
|
|
34
|
+
}
|
|
35
|
+
delete(path) {
|
|
36
|
+
return this.request("DELETE", path);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
var apiFetcher = new FusionFetcher();
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
exports.FusionFetcher = FusionFetcher; exports.apiFetcher = apiFetcher;
|
|
45
|
+
//# sourceMappingURL=chunk-2ZKONAXC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["c:\\Users\\ziad\\Desktop\\FusionJS\\packages\\fusionjs\\dist\\chunk-2ZKONAXC.js"],"names":[],"mappings":"AAAA;AACA;AACA;AACA,IAAI,cAAc,EAAE,MAAM;AAC1B,EAAE,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE;AAChC,IAAI,IAAI,CAAC,QAAQ,EAAE,OAAO;AAC1B,EAAE;AACF,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE;AACpC,IAAI,MAAM,QAAQ,EAAE;AACpB,MAAM,cAAc,EAAE;AACtB,IAAI,CAAC;AACL,IAAI,GAAG,CAAC,OAAO,OAAO,IAAI,WAAW,EAAE;AACvC,MAAM,MAAM,MAAM,EAAE,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC;AACxD,MAAM,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"C:\\Users\\ziad\\Desktop\\FusionJS\\packages\\fusionjs\\dist\\chunk-2ZKONAXC.js","sourcesContent":[null]}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
FusionFetcher
|
|
4
|
+
} from "./chunk-6K3RXN4Y.mjs";
|
|
5
|
+
import {
|
|
6
|
+
__export
|
|
7
|
+
} from "./chunk-H6XDQJ3N.mjs";
|
|
8
|
+
|
|
9
|
+
// src/next/index.ts
|
|
10
|
+
var next_exports = {};
|
|
11
|
+
__export(next_exports, {
|
|
12
|
+
FusionProvider: () => FusionProvider,
|
|
13
|
+
useAuth: () => useAuth,
|
|
14
|
+
useFusion: () => useFusion
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// src/next/provider.tsx
|
|
18
|
+
import React, { createContext, useContext } from "react";
|
|
19
|
+
var FusionContext = createContext(null);
|
|
20
|
+
function FusionProvider({ children, baseUrl = "/api" }) {
|
|
21
|
+
const client = React.useMemo(() => new FusionFetcher(baseUrl), [baseUrl]);
|
|
22
|
+
return /* @__PURE__ */ React.createElement(FusionContext.Provider, { value: { client } }, children);
|
|
23
|
+
}
|
|
24
|
+
function useFusion() {
|
|
25
|
+
const context = useContext(FusionContext);
|
|
26
|
+
if (!context) {
|
|
27
|
+
throw new Error("useFusion must be used within FusionProvider");
|
|
28
|
+
}
|
|
29
|
+
return context;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// src/next/useAuth.ts
|
|
33
|
+
import { useState, useEffect } from "react";
|
|
34
|
+
function useAuth() {
|
|
35
|
+
const { client } = useFusion();
|
|
36
|
+
const [user, setUser] = useState(null);
|
|
37
|
+
const [loading, setLoading] = useState(true);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
const token = localStorage.getItem("fusion_token");
|
|
40
|
+
if (token) {
|
|
41
|
+
loadUser();
|
|
42
|
+
} else {
|
|
43
|
+
setLoading(false);
|
|
44
|
+
}
|
|
45
|
+
}, []);
|
|
46
|
+
const loadUser = async () => {
|
|
47
|
+
try {
|
|
48
|
+
const userData = await client.get("/auth/me");
|
|
49
|
+
setUser(userData);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
localStorage.removeItem("fusion_token");
|
|
52
|
+
} finally {
|
|
53
|
+
setLoading(false);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const login = async (email, password) => {
|
|
57
|
+
const response = await client.post("/auth/login", {
|
|
58
|
+
email,
|
|
59
|
+
password
|
|
60
|
+
});
|
|
61
|
+
localStorage.setItem("fusion_token", response.token);
|
|
62
|
+
setUser(response.user);
|
|
63
|
+
};
|
|
64
|
+
const logout = async () => {
|
|
65
|
+
localStorage.removeItem("fusion_token");
|
|
66
|
+
setUser(null);
|
|
67
|
+
};
|
|
68
|
+
return {
|
|
69
|
+
user,
|
|
70
|
+
loading,
|
|
71
|
+
login,
|
|
72
|
+
logout,
|
|
73
|
+
isAuthenticated: !!user
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export {
|
|
78
|
+
FusionProvider,
|
|
79
|
+
useFusion,
|
|
80
|
+
useAuth,
|
|
81
|
+
next_exports
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=chunk-57VDULE3.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/next/index.ts","../src/next/provider.tsx","../src/next/useAuth.ts"],"sourcesContent":["export * from './provider';\r\nexport * from './useAuth';\r\n","'use client';\r\n\r\nimport React, { createContext, useContext, ReactNode } from 'react';\r\nimport { FusionFetcher } from '../client/fetcher';\r\n\r\ninterface FusionContextType {\r\n client: FusionFetcher;\r\n}\r\n\r\nconst FusionContext = createContext<FusionContextType | null>(null);\r\n\r\nexport interface FusionProviderProps {\r\n children: ReactNode;\r\n baseUrl?: string;\r\n}\r\n\r\n/**\r\n * FusionProvider - Provides API client to React components\r\n * Usage:\r\n * ```tsx\r\n * <FusionProvider baseUrl=\"/api\">\r\n * <App />\r\n * </FusionProvider>\r\n * ```\r\n */\r\nexport function FusionProvider({ children, baseUrl = '/api' }: FusionProviderProps) {\r\n const client = React.useMemo(() => new FusionFetcher(baseUrl), [baseUrl]);\r\n\r\n return (\r\n <FusionContext.Provider value={{ client }}>\r\n {children}\r\n </FusionContext.Provider>\r\n );\r\n}\r\n\r\n/**\r\n * useFusion hook - Access API client in components\r\n * Usage:\r\n * ```tsx\r\n * const { client } = useFusion();\r\n * const data = await client.get('/users');\r\n * ```\r\n */\r\nexport function useFusion(): FusionContextType {\r\n const context = useContext(FusionContext);\r\n if (!context) {\r\n throw new Error('useFusion must be used within FusionProvider');\r\n }\r\n return context;\r\n}\r\n","'use client';\r\n\r\nimport { useState, useEffect } from 'react';\r\nimport { useFusion } from './provider';\r\n\r\nexport interface AuthUser {\r\n id: string;\r\n email: string;\r\n name?: string;\r\n}\r\n\r\nexport interface UseAuthReturn {\r\n user: AuthUser | null;\r\n loading: boolean;\r\n login: (email: string, password: string) => Promise<void>;\r\n logout: () => Promise<void>;\r\n isAuthenticated: boolean;\r\n}\r\n\r\n/**\r\n * useAuth hook - Authentication state management\r\n * Usage:\r\n * ```tsx\r\n * const { user, login, logout, isAuthenticated } = useAuth();\r\n * ```\r\n */\r\nexport function useAuth(): UseAuthReturn {\r\n const { client } = useFusion();\r\n const [user, setUser] = useState<AuthUser | null>(null);\r\n const [loading, setLoading] = useState(true);\r\n\r\n useEffect(() => {\r\n // Check for existing session\r\n const token = localStorage.getItem('fusion_token');\r\n if (token) {\r\n // Validate token and load user\r\n loadUser();\r\n } else {\r\n setLoading(false);\r\n }\r\n }, []);\r\n\r\n const loadUser = async () => {\r\n try {\r\n const userData = await client.get<AuthUser>('/auth/me');\r\n setUser(userData);\r\n } catch (error) {\r\n localStorage.removeItem('fusion_token');\r\n } finally {\r\n setLoading(false);\r\n }\r\n };\r\n\r\n const login = async (email: string, password: string) => {\r\n const response = await client.post<{ token: string; user: AuthUser }>('/auth/login', {\r\n email,\r\n password,\r\n });\r\n localStorage.setItem('fusion_token', response.token);\r\n setUser(response.user);\r\n };\r\n\r\n const logout = async () => {\r\n localStorage.removeItem('fusion_token');\r\n setUser(null);\r\n };\r\n\r\n return {\r\n user,\r\n loading,\r\n login,\r\n logout,\r\n isAuthenticated: !!user,\r\n };\r\n}\r\n"],"mappings":";;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,OAAO,SAAS,eAAe,kBAA6B;AAO5D,IAAM,gBAAgB,cAAwC,IAAI;AAgB3D,SAAS,eAAe,EAAE,UAAU,UAAU,OAAO,GAAwB;AAChF,QAAM,SAAS,MAAM,QAAQ,MAAM,IAAI,cAAc,OAAO,GAAG,CAAC,OAAO,CAAC;AAExE,SACI,oCAAC,cAAc,UAAd,EAAuB,OAAO,EAAE,OAAO,KACnC,QACL;AAER;AAUO,SAAS,YAA+B;AAC3C,QAAM,UAAU,WAAW,aAAa;AACxC,MAAI,CAAC,SAAS;AACV,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAClE;AACA,SAAO;AACX;;;AC/CA,SAAS,UAAU,iBAAiB;AAwB7B,SAAS,UAAyB;AACrC,QAAM,EAAE,OAAO,IAAI,UAAU;AAC7B,QAAM,CAAC,MAAM,OAAO,IAAI,SAA0B,IAAI;AACtD,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,IAAI;AAE3C,YAAU,MAAM;AAEZ,UAAM,QAAQ,aAAa,QAAQ,cAAc;AACjD,QAAI,OAAO;AAEP,eAAS;AAAA,IACb,OAAO;AACH,iBAAW,KAAK;AAAA,IACpB;AAAA,EACJ,GAAG,CAAC,CAAC;AAEL,QAAM,WAAW,YAAY;AACzB,QAAI;AACA,YAAM,WAAW,MAAM,OAAO,IAAc,UAAU;AACtD,cAAQ,QAAQ;AAAA,IACpB,SAAS,OAAO;AACZ,mBAAa,WAAW,cAAc;AAAA,IAC1C,UAAE;AACE,iBAAW,KAAK;AAAA,IACpB;AAAA,EACJ;AAEA,QAAM,QAAQ,OAAO,OAAe,aAAqB;AACrD,UAAM,WAAW,MAAM,OAAO,KAAwC,eAAe;AAAA,MACjF;AAAA,MACA;AAAA,IACJ,CAAC;AACD,iBAAa,QAAQ,gBAAgB,SAAS,KAAK;AACnD,YAAQ,SAAS,IAAI;AAAA,EACzB;AAEA,QAAM,SAAS,YAAY;AACvB,iBAAa,WAAW,cAAc;AACtC,YAAQ,IAAI;AAAA,EAChB;AAEA,SAAO;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,iBAAiB,CAAC,CAAC;AAAA,EACvB;AACJ;","names":[]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/client/fetcher.ts
|
|
4
|
+
var FusionFetcher = class {
|
|
5
|
+
constructor(baseUrl = "/api") {
|
|
6
|
+
this.baseUrl = baseUrl;
|
|
7
|
+
}
|
|
8
|
+
async request(method, path, body) {
|
|
9
|
+
const headers = {
|
|
10
|
+
"Content-Type": "application/json"
|
|
11
|
+
};
|
|
12
|
+
if (typeof window !== "undefined") {
|
|
13
|
+
const token = localStorage.getItem("fusion_token");
|
|
14
|
+
if (token) headers["Authorization"] = `Bearer ${token}`;
|
|
15
|
+
}
|
|
16
|
+
const response = await fetch(`${this.baseUrl}${path}`, {
|
|
17
|
+
method,
|
|
18
|
+
headers,
|
|
19
|
+
body: body ? JSON.stringify(body) : void 0
|
|
20
|
+
});
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
throw new Error(`Fusion API Error: ${response.statusText}`);
|
|
23
|
+
}
|
|
24
|
+
return response.json();
|
|
25
|
+
}
|
|
26
|
+
get(path) {
|
|
27
|
+
return this.request("GET", path);
|
|
28
|
+
}
|
|
29
|
+
post(path, body) {
|
|
30
|
+
return this.request("POST", path, body);
|
|
31
|
+
}
|
|
32
|
+
put(path, body) {
|
|
33
|
+
return this.request("PUT", path, body);
|
|
34
|
+
}
|
|
35
|
+
delete(path) {
|
|
36
|
+
return this.request("DELETE", path);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
var apiFetcher = new FusionFetcher();
|
|
40
|
+
|
|
41
|
+
export {
|
|
42
|
+
FusionFetcher,
|
|
43
|
+
apiFetcher
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=chunk-6K3RXN4Y.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client/fetcher.ts"],"sourcesContent":["// packages/api-client/src/fetcher.ts\r\n\r\nexport class FusionFetcher {\r\n private baseUrl: string;\r\n\r\n constructor(baseUrl: string = '/api') {\r\n this.baseUrl = baseUrl;\r\n }\r\n\r\n private async request<T>(method: string, path: string, body?: any): Promise<T> {\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n };\r\n\r\n // Automatically attach Fusion Token if present\r\n if (typeof window !== 'undefined') {\r\n const token = localStorage.getItem('fusion_token');\r\n if (token) headers['Authorization'] = `Bearer ${token}`;\r\n }\r\n\r\n const response = await fetch(`${this.baseUrl}${path}`, {\r\n method,\r\n headers,\r\n body: body ? JSON.stringify(body) : undefined,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`Fusion API Error: ${response.statusText}`);\r\n }\r\n\r\n return response.json();\r\n }\r\n\r\n get<T>(path: string) { return this.request<T>('GET', path); }\r\n post<T>(path: string, body: any) { return this.request<T>('POST', path, body); }\r\n put<T>(path: string, body: any) { return this.request<T>('PUT', path, body); }\r\n delete<T>(path: string) { return this.request<T>('DELETE', path); }\r\n}\r\n\r\nexport const apiFetcher = new FusionFetcher();\r\n"],"mappings":";;;AAEO,IAAM,gBAAN,MAAoB;AAAA,EAGvB,YAAY,UAAkB,QAAQ;AAClC,SAAK,UAAU;AAAA,EACnB;AAAA,EAEA,MAAc,QAAW,QAAgB,MAAc,MAAwB;AAC3E,UAAM,UAAkC;AAAA,MACpC,gBAAgB;AAAA,IACpB;AAGA,QAAI,OAAO,WAAW,aAAa;AAC/B,YAAM,QAAQ,aAAa,QAAQ,cAAc;AACjD,UAAI,MAAO,SAAQ,eAAe,IAAI,UAAU,KAAK;AAAA,IACzD;AAEA,UAAM,WAAW,MAAM,MAAM,GAAG,KAAK,OAAO,GAAG,IAAI,IAAI;AAAA,MACnD;AAAA,MACA;AAAA,MACA,MAAM,OAAO,KAAK,UAAU,IAAI,IAAI;AAAA,IACxC,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AACd,YAAM,IAAI,MAAM,qBAAqB,SAAS,UAAU,EAAE;AAAA,IAC9D;AAEA,WAAO,SAAS,KAAK;AAAA,EACzB;AAAA,EAEA,IAAO,MAAc;AAAE,WAAO,KAAK,QAAW,OAAO,IAAI;AAAA,EAAG;AAAA,EAC5D,KAAQ,MAAc,MAAW;AAAE,WAAO,KAAK,QAAW,QAAQ,MAAM,IAAI;AAAA,EAAG;AAAA,EAC/E,IAAO,MAAc,MAAW;AAAE,WAAO,KAAK,QAAW,OAAO,MAAM,IAAI;AAAA,EAAG;AAAA,EAC7E,OAAU,MAAc;AAAE,WAAO,KAAK,QAAW,UAAU,IAAI;AAAA,EAAG;AACtE;AAEO,IAAM,aAAa,IAAI,cAAc;","names":[]}
|