bxo 0.0.5-dev.52 โ 0.0.5-dev.54
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/package.json +1 -1
- package/src/core/bxo.ts +3 -2
- package/src/utils/index.ts +8 -25
- package/tests/unit/utils.test.ts +12 -51
- package/REFACTOR_README.md +0 -209
package/package.json
CHANGED
package/src/core/bxo.ts
CHANGED
|
@@ -80,6 +80,7 @@ export default class BXO {
|
|
|
80
80
|
// It's a middleware plugin
|
|
81
81
|
this.middleware.push(plugin);
|
|
82
82
|
}
|
|
83
|
+
this.updateRequestHandler();
|
|
83
84
|
return this;
|
|
84
85
|
}
|
|
85
86
|
|
|
@@ -189,8 +190,8 @@ export default class BXO {
|
|
|
189
190
|
// Update the request handler with current routes and configuration
|
|
190
191
|
private updateRequestHandler(): void {
|
|
191
192
|
this.requestHandler = new RequestHandler(
|
|
192
|
-
this.
|
|
193
|
-
this.
|
|
193
|
+
this.getAllRoutes(),
|
|
194
|
+
this.getAllWSRoutes(),
|
|
194
195
|
this.plugins,
|
|
195
196
|
this.middleware,
|
|
196
197
|
this.hooks,
|
package/src/utils/index.ts
CHANGED
|
@@ -90,22 +90,13 @@ export async function parseRequestBody(request: Request): Promise<any> {
|
|
|
90
90
|
}
|
|
91
91
|
} else if (contentType?.includes('multipart/form-data') || contentType?.includes('application/x-www-form-urlencoded')) {
|
|
92
92
|
const formData = await request.formData();
|
|
93
|
-
// Convert FormData to a structured object
|
|
93
|
+
// Convert FormData to a structured object
|
|
94
94
|
const formBody: Record<string, any> = {};
|
|
95
95
|
|
|
96
96
|
for (const [key, value] of formData.entries()) {
|
|
97
97
|
if (value instanceof File) {
|
|
98
|
-
//
|
|
99
|
-
formBody[key] =
|
|
100
|
-
type: 'file',
|
|
101
|
-
name: value.name,
|
|
102
|
-
size: value.size,
|
|
103
|
-
lastModified: value.lastModified,
|
|
104
|
-
file: value, // Keep the actual File object for access
|
|
105
|
-
// Add convenience properties
|
|
106
|
-
filename: value.name,
|
|
107
|
-
mimetype: value.type || 'application/octet-stream'
|
|
108
|
-
};
|
|
98
|
+
// Return File instances directly
|
|
99
|
+
formBody[key] = value;
|
|
109
100
|
} else {
|
|
110
101
|
// Handle regular form fields
|
|
111
102
|
formBody[key] = value;
|
|
@@ -186,21 +177,13 @@ export function createRedirectResponse(
|
|
|
186
177
|
}
|
|
187
178
|
|
|
188
179
|
// Check if a value is a file upload
|
|
189
|
-
export function isFileUpload(value: any): value is {
|
|
190
|
-
|
|
191
|
-
file: File;
|
|
192
|
-
name: string;
|
|
193
|
-
size: number;
|
|
194
|
-
lastModified: number;
|
|
195
|
-
filename: string;
|
|
196
|
-
mimetype: string;
|
|
197
|
-
} {
|
|
198
|
-
return value && typeof value === 'object' && value.type === 'file' && value.file instanceof File;
|
|
180
|
+
export function isFileUpload(value: any): value is File {
|
|
181
|
+
return value instanceof File;
|
|
199
182
|
}
|
|
200
183
|
|
|
201
184
|
// Extract File object from upload value
|
|
202
185
|
export function getFileFromUpload(value: any): File | null {
|
|
203
|
-
return isFileUpload(value) ? value
|
|
186
|
+
return isFileUpload(value) ? value : null;
|
|
204
187
|
}
|
|
205
188
|
|
|
206
189
|
// Get file metadata without the File object
|
|
@@ -209,7 +192,7 @@ export function getFileInfo(value: any): { name: string; size: number; mimetype:
|
|
|
209
192
|
return {
|
|
210
193
|
name: value.name,
|
|
211
194
|
size: value.size,
|
|
212
|
-
mimetype: value.
|
|
195
|
+
mimetype: value.type || 'application/octet-stream',
|
|
213
196
|
lastModified: value.lastModified
|
|
214
197
|
};
|
|
215
198
|
}
|
|
@@ -240,7 +223,7 @@ export function getFileUploads(formData: Record<string, any>): Record<string, Fi
|
|
|
240
223
|
const files: Record<string, File> = {};
|
|
241
224
|
for (const [key, value] of Object.entries(formData)) {
|
|
242
225
|
if (isFileUpload(value)) {
|
|
243
|
-
files[key] = value
|
|
226
|
+
files[key] = value;
|
|
244
227
|
}
|
|
245
228
|
}
|
|
246
229
|
return files;
|
package/tests/unit/utils.test.ts
CHANGED
|
@@ -202,34 +202,17 @@ describe('Utility Functions', () => {
|
|
|
202
202
|
|
|
203
203
|
describe('File Upload Utilities', () => {
|
|
204
204
|
it('should identify file uploads correctly', () => {
|
|
205
|
-
const
|
|
206
|
-
type: 'file',
|
|
207
|
-
name: 'test.jpg',
|
|
208
|
-
size: 1024,
|
|
209
|
-
lastModified: 1234567890,
|
|
210
|
-
file: new File(['test'], 'test.jpg'),
|
|
211
|
-
filename: 'test.jpg',
|
|
212
|
-
mimetype: 'image/jpeg'
|
|
213
|
-
};
|
|
205
|
+
const file = new File(['test'], 'test.jpg', { type: 'image/jpeg' });
|
|
214
206
|
|
|
215
|
-
expect(isFileUpload(
|
|
207
|
+
expect(isFileUpload(file)).toBe(true);
|
|
216
208
|
expect(isFileUpload('not a file')).toBe(false);
|
|
217
209
|
expect(isFileUpload({ type: 'text' })).toBe(false);
|
|
218
210
|
});
|
|
219
211
|
|
|
220
212
|
it('should extract file from upload', () => {
|
|
221
|
-
const file = new File(['test'], 'test.jpg');
|
|
222
|
-
const fileUpload = {
|
|
223
|
-
type: 'file',
|
|
224
|
-
name: 'test.jpg',
|
|
225
|
-
size: 1024,
|
|
226
|
-
lastModified: 1234567890,
|
|
227
|
-
file,
|
|
228
|
-
filename: 'test.jpg',
|
|
229
|
-
mimetype: 'image/jpeg'
|
|
230
|
-
};
|
|
213
|
+
const file = new File(['test'], 'test.jpg', { type: 'image/jpeg' });
|
|
231
214
|
|
|
232
|
-
const result = getFileFromUpload(
|
|
215
|
+
const result = getFileFromUpload(file);
|
|
233
216
|
expect(result).toBe(file);
|
|
234
217
|
});
|
|
235
218
|
|
|
@@ -239,22 +222,14 @@ describe('Utility Functions', () => {
|
|
|
239
222
|
});
|
|
240
223
|
|
|
241
224
|
it('should get file info', () => {
|
|
242
|
-
const
|
|
243
|
-
type: 'file',
|
|
244
|
-
name: 'test.jpg',
|
|
245
|
-
size: 1024,
|
|
246
|
-
lastModified: 1234567890,
|
|
247
|
-
file: new File(['test'], 'test.jpg'),
|
|
248
|
-
filename: 'test.jpg',
|
|
249
|
-
mimetype: 'image/jpeg'
|
|
250
|
-
};
|
|
225
|
+
const file = new File(['test'], 'test.jpg', { type: 'image/jpeg' });
|
|
251
226
|
|
|
252
|
-
const result = getFileInfo(
|
|
227
|
+
const result = getFileInfo(file);
|
|
253
228
|
expect(result).toEqual({
|
|
254
229
|
name: 'test.jpg',
|
|
255
|
-
size:
|
|
230
|
+
size: 4,
|
|
256
231
|
mimetype: 'image/jpeg',
|
|
257
|
-
lastModified:
|
|
232
|
+
lastModified: expect.any(Number)
|
|
258
233
|
});
|
|
259
234
|
});
|
|
260
235
|
|
|
@@ -264,17 +239,10 @@ describe('Utility Functions', () => {
|
|
|
264
239
|
});
|
|
265
240
|
|
|
266
241
|
it('should get all file uploads from form data', () => {
|
|
242
|
+
const file = new File(['test'], 'avatar.jpg', { type: 'image/jpeg' });
|
|
267
243
|
const formData = {
|
|
268
244
|
name: 'john',
|
|
269
|
-
avatar:
|
|
270
|
-
type: 'file',
|
|
271
|
-
name: 'avatar.jpg',
|
|
272
|
-
size: 1024,
|
|
273
|
-
lastModified: 1234567890,
|
|
274
|
-
file: new File(['test'], 'avatar.jpg'),
|
|
275
|
-
filename: 'avatar.jpg',
|
|
276
|
-
mimetype: 'image/jpeg'
|
|
277
|
-
},
|
|
245
|
+
avatar: file,
|
|
278
246
|
email: 'john@example.com'
|
|
279
247
|
};
|
|
280
248
|
|
|
@@ -285,17 +253,10 @@ describe('Utility Functions', () => {
|
|
|
285
253
|
});
|
|
286
254
|
|
|
287
255
|
it('should get all non-file fields from form data', () => {
|
|
256
|
+
const file = new File(['test'], 'avatar.jpg', { type: 'image/jpeg' });
|
|
288
257
|
const formData = {
|
|
289
258
|
name: 'john',
|
|
290
|
-
avatar:
|
|
291
|
-
type: 'file',
|
|
292
|
-
name: 'avatar.jpg',
|
|
293
|
-
size: 1024,
|
|
294
|
-
lastModified: 1234567890,
|
|
295
|
-
file: new File(['test'], 'avatar.jpg'),
|
|
296
|
-
filename: 'avatar.jpg',
|
|
297
|
-
mimetype: 'image/jpeg'
|
|
298
|
-
},
|
|
259
|
+
avatar: file,
|
|
299
260
|
email: 'john@example.com'
|
|
300
261
|
};
|
|
301
262
|
|
package/REFACTOR_README.md
DELETED
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
# BXO Framework - Refactored Structure
|
|
2
|
-
|
|
3
|
-
The BXO framework has been completely refactored to be more modular, maintainable, and easier to understand. The functionality remains exactly the same, but the code is now organized into logical modules.
|
|
4
|
-
|
|
5
|
-
## ๐๏ธ New Directory Structure
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
src/
|
|
9
|
-
โโโ core/ # Core BXO class and main logic
|
|
10
|
-
โโโ types/ # TypeScript type definitions
|
|
11
|
-
โโโ utils/ # Utility functions and helpers
|
|
12
|
-
โโโ handlers/ # Request handling logic
|
|
13
|
-
โโโ plugins/ # Plugin system (existing)
|
|
14
|
-
โโโ middleware/ # Middleware system (existing)
|
|
15
|
-
โโโ index.ts # Main export file
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
## ๐ Module Breakdown
|
|
19
|
-
|
|
20
|
-
### `src/types/index.ts`
|
|
21
|
-
- All TypeScript interfaces and types
|
|
22
|
-
- Zod schema type utilities
|
|
23
|
-
- Context, Route, and Plugin interfaces
|
|
24
|
-
- File upload type definitions
|
|
25
|
-
|
|
26
|
-
### `src/utils/index.ts`
|
|
27
|
-
- Core utility functions for parsing requests
|
|
28
|
-
- Validation helpers
|
|
29
|
-
- Cookie handling utilities
|
|
30
|
-
- File upload utilities
|
|
31
|
-
|
|
32
|
-
### `src/utils/route-matcher.ts`
|
|
33
|
-
- Route matching logic for HTTP routes
|
|
34
|
-
- WebSocket route matching
|
|
35
|
-
- Wildcard and parameter handling
|
|
36
|
-
|
|
37
|
-
### `src/utils/context-factory.ts`
|
|
38
|
-
- Context object creation
|
|
39
|
-
- Validation integration
|
|
40
|
-
- Cookie management
|
|
41
|
-
|
|
42
|
-
### `src/utils/response-handler.ts`
|
|
43
|
-
- Response processing and formatting
|
|
44
|
-
- Error response creation
|
|
45
|
-
- File and Bun.file handling
|
|
46
|
-
|
|
47
|
-
### `src/utils/helpers.ts`
|
|
48
|
-
- Helper functions (error, file, redirect)
|
|
49
|
-
- Cookie options utilities
|
|
50
|
-
|
|
51
|
-
### `src/handlers/request-handler.ts`
|
|
52
|
-
- Main request processing logic
|
|
53
|
-
- Middleware and hook execution
|
|
54
|
-
- WebSocket upgrade handling
|
|
55
|
-
- Error handling
|
|
56
|
-
|
|
57
|
-
### `src/core/bxo.ts`
|
|
58
|
-
- Main BXO class
|
|
59
|
-
- Route registration methods
|
|
60
|
-
- Server lifecycle management
|
|
61
|
-
- Plugin system integration
|
|
62
|
-
|
|
63
|
-
## ๐ Migration Guide
|
|
64
|
-
|
|
65
|
-
### Before (Old Structure)
|
|
66
|
-
```typescript
|
|
67
|
-
import BXO from './index';
|
|
68
|
-
|
|
69
|
-
const app = new BXO();
|
|
70
|
-
app.get('/', () => 'Hello World');
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### After (New Structure)
|
|
74
|
-
```typescript
|
|
75
|
-
import BXO from './index'; // Still works exactly the same!
|
|
76
|
-
|
|
77
|
-
const app = new BXO();
|
|
78
|
-
app.get('/', () => 'Hello World');
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
**No changes needed in your existing code!** The API is completely backward compatible.
|
|
82
|
-
|
|
83
|
-
## โจ Benefits of Refactoring
|
|
84
|
-
|
|
85
|
-
### 1. **Better Separation of Concerns**
|
|
86
|
-
- Each module has a single responsibility
|
|
87
|
-
- Easier to understand what each part does
|
|
88
|
-
- Clear boundaries between different functionalities
|
|
89
|
-
|
|
90
|
-
### 2. **Improved Maintainability**
|
|
91
|
-
- Smaller, focused files are easier to modify
|
|
92
|
-
- Changes to one feature don't affect others
|
|
93
|
-
- Better testability with isolated modules
|
|
94
|
-
|
|
95
|
-
### 3. **Enhanced Readability**
|
|
96
|
-
- Code is organized logically
|
|
97
|
-
- Related functionality is grouped together
|
|
98
|
-
- Easier to find specific features
|
|
99
|
-
|
|
100
|
-
### 4. **Better Type Safety**
|
|
101
|
-
- Types are centralized and well-defined
|
|
102
|
-
- Easier to maintain type consistency
|
|
103
|
-
- Better IntelliSense support
|
|
104
|
-
|
|
105
|
-
### 5. **Easier Testing**
|
|
106
|
-
- Individual modules can be tested in isolation
|
|
107
|
-
- Mocking is simpler with clear interfaces
|
|
108
|
-
- Unit tests are more focused
|
|
109
|
-
|
|
110
|
-
## ๐งช Testing the Refactored Structure
|
|
111
|
-
|
|
112
|
-
Run the test file to verify everything works:
|
|
113
|
-
|
|
114
|
-
```bash
|
|
115
|
-
bun run test-refactored.ts
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
## ๐ Usage Examples
|
|
119
|
-
|
|
120
|
-
### Basic Usage (Unchanged)
|
|
121
|
-
```typescript
|
|
122
|
-
import BXO, { z } from './index';
|
|
123
|
-
|
|
124
|
-
const app = new BXO();
|
|
125
|
-
|
|
126
|
-
app.get('/', () => 'Hello World');
|
|
127
|
-
|
|
128
|
-
app.post('/users', async (ctx) => {
|
|
129
|
-
return { message: 'User created' };
|
|
130
|
-
}, {
|
|
131
|
-
body: z.object({
|
|
132
|
-
name: z.string(),
|
|
133
|
-
email: z.string().email()
|
|
134
|
-
})
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
app.start(3000);
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
### File Uploads (Unchanged)
|
|
141
|
-
```typescript
|
|
142
|
-
import { isFileUpload, saveUploadedFile } from './index';
|
|
143
|
-
|
|
144
|
-
app.post('/upload', async (ctx) => {
|
|
145
|
-
if (ctx.body.avatar && isFileUpload(ctx.body.avatar)) {
|
|
146
|
-
await saveUploadedFile(ctx.body.avatar, './uploads/avatar.jpg');
|
|
147
|
-
}
|
|
148
|
-
return { message: 'Upload successful' };
|
|
149
|
-
});
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
### WebSockets (Unchanged)
|
|
153
|
-
```typescript
|
|
154
|
-
app.ws('/chat', {
|
|
155
|
-
onOpen: (ws) => console.log('Connected'),
|
|
156
|
-
onMessage: (ws, message) => ws.send(`Echo: ${message}`)
|
|
157
|
-
});
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
## ๐ง Development
|
|
161
|
-
|
|
162
|
-
### Adding New Features
|
|
163
|
-
1. **New utility functions**: Add to `src/utils/`
|
|
164
|
-
2. **New types**: Add to `src/types/`
|
|
165
|
-
3. **New handlers**: Add to `src/handlers/`
|
|
166
|
-
4. **New core features**: Add to `src/core/`
|
|
167
|
-
|
|
168
|
-
### Modifying Existing Features
|
|
169
|
-
- **Route matching**: Edit `src/utils/route-matcher.ts`
|
|
170
|
-
- **Request parsing**: Edit `src/utils/index.ts`
|
|
171
|
-
- **Response handling**: Edit `src/utils/response-handler.ts`
|
|
172
|
-
- **Context creation**: Edit `src/utils/context-factory.ts`
|
|
173
|
-
|
|
174
|
-
## ๐ฆ Build and Distribution
|
|
175
|
-
|
|
176
|
-
The main `index.ts` file now simply re-exports everything from the new structure:
|
|
177
|
-
|
|
178
|
-
```typescript
|
|
179
|
-
// Re-export everything from the refactored source
|
|
180
|
-
export * from './src/index';
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
This means:
|
|
184
|
-
- โ
**Zero breaking changes** for existing users
|
|
185
|
-
- โ
**Same import syntax** as before
|
|
186
|
-
- โ
**All functionality preserved**
|
|
187
|
-
- โ
**Better internal organization**
|
|
188
|
-
|
|
189
|
-
## ๐ฏ Future Improvements
|
|
190
|
-
|
|
191
|
-
With this new structure, we can now easily:
|
|
192
|
-
|
|
193
|
-
1. **Add new modules** without cluttering the main file
|
|
194
|
-
2. **Implement better testing** with isolated components
|
|
195
|
-
3. **Add new features** in dedicated modules
|
|
196
|
-
4. **Improve performance** by optimizing specific modules
|
|
197
|
-
5. **Better documentation** with focused module descriptions
|
|
198
|
-
|
|
199
|
-
## ๐ค Contributing
|
|
200
|
-
|
|
201
|
-
When contributing to the framework:
|
|
202
|
-
|
|
203
|
-
1. **Identify the right module** for your changes
|
|
204
|
-
2. **Keep modules focused** on their specific responsibility
|
|
205
|
-
3. **Update types** if adding new interfaces
|
|
206
|
-
4. **Add tests** for new functionality
|
|
207
|
-
5. **Update documentation** for new features
|
|
208
|
-
|
|
209
|
-
The refactored structure makes it much easier to contribute and maintain the codebase!
|