owebjs 1.3.0 → 1.3.2
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 +261 -4
- package/dist/index.d.ts +7 -2
- package/dist/structures/Oweb.js +17 -7
- package/dist/utils/assignRoutes.js +101 -20
- package/dist/utils/utils.js +14 -1
- package/dist/utils/{watchRoutes.js → watcher.js} +4 -4
- package/dist/uws_darwin_arm64_108.node +0 -0
- package/dist/uws_darwin_arm64_83.node +0 -0
- package/dist/uws_darwin_arm64_93.node +0 -0
- package/dist/uws_darwin_x64_108.node +0 -0
- package/dist/uws_darwin_x64_83.node +0 -0
- package/dist/uws_darwin_x64_93.node +0 -0
- package/dist/uws_linux_arm64_108.node +0 -0
- package/dist/uws_linux_arm64_83.node +0 -0
- package/dist/uws_linux_arm64_93.node +0 -0
- package/dist/uws_linux_x64_108.node +0 -0
- package/dist/uws_linux_x64_83.node +0 -0
- package/dist/uws_linux_x64_93.node +0 -0
- package/dist/uws_win32_x64_108.node +0 -0
- package/dist/uws_win32_x64_83.node +0 -0
- package/dist/uws_win32_x64_93.node +0 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,13 +1,270 @@
|
|
|
1
1
|
# Oweb
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A flexible and modern web framework built on top of Fastify, designed for creating scalable and maintainable web applications with file-based routing and hot module replacement.
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<img src="https://img.shields.io/npm/v/owebjs" alt="npm version">
|
|
7
|
+
<img src="https://img.shields.io/npm/l/owebjs" alt="license">
|
|
8
|
+
<img src="https://img.shields.io/npm/dt/owebjs" alt="downloads">
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **File-based Routing**: Automatically generate routes based on your file structure
|
|
14
|
+
- **Hot Module Replacement (HMR)**: Update your routes without restarting the server
|
|
15
|
+
- **Middleware Support**: Use hooks to add middleware functionality
|
|
16
|
+
- **Error Handling**: Global and route-specific error handling
|
|
17
|
+
- **TypeScript Support**: Built with TypeScript for better developer experience
|
|
18
|
+
- **Plugin System**: Extend functionality with plugins
|
|
19
|
+
- **uWebSockets.js Support**: Optional high-performance WebSocket server
|
|
4
20
|
|
|
5
21
|
## Installation
|
|
6
22
|
|
|
23
|
+
```bash
|
|
24
|
+
npm install owebjs
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
import Oweb from 'owebjs';
|
|
31
|
+
|
|
32
|
+
// Create and setup the app
|
|
33
|
+
const app = await new Oweb().setup();
|
|
34
|
+
|
|
35
|
+
// Load routes from a directory
|
|
36
|
+
await app.loadRoutes({
|
|
37
|
+
directory: 'routes',
|
|
38
|
+
hmr: {
|
|
39
|
+
enabled: true, // Enable hot module replacement
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Start the server
|
|
44
|
+
await app.start({ port: 3000 });
|
|
45
|
+
console.log('Server running at http://localhost:3000');
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Creating Routes
|
|
49
|
+
|
|
50
|
+
Routes are automatically generated based on your file structure. Create a file in your routes directory:
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
// routes/hello.js
|
|
54
|
+
import { Route } from 'owebjs';
|
|
55
|
+
|
|
56
|
+
export default class extends Route {
|
|
57
|
+
async handle(req, res) {
|
|
58
|
+
res.send({ message: 'Hello, World!' });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
This will create a GET route at `/hello`.
|
|
64
|
+
|
|
65
|
+
### Dynamic Routes
|
|
66
|
+
|
|
67
|
+
Use brackets to create dynamic route parameters:
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
// routes/users/[id].js
|
|
71
|
+
import { Route } from 'owebjs';
|
|
72
|
+
|
|
73
|
+
export default class extends Route {
|
|
74
|
+
async handle(req, res) {
|
|
75
|
+
res.send({ userId: req.params.id });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
This will create a GET route at `/users/:id`.
|
|
81
|
+
|
|
82
|
+
### Parameter Validation with Matchers
|
|
83
|
+
|
|
84
|
+
Use matchers to validate dynamic route parameters:
|
|
85
|
+
|
|
86
|
+
```javascript
|
|
87
|
+
// routes/users/[id=integer].js
|
|
88
|
+
import { Route } from 'owebjs';
|
|
89
|
+
|
|
90
|
+
export default class extends Route {
|
|
91
|
+
async handle(req, res) {
|
|
92
|
+
res.send({ userId: req.params.id });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
// matchers/integer.js
|
|
99
|
+
export default function (val) {
|
|
100
|
+
return !isNaN(val);
|
|
101
|
+
}
|
|
7
102
|
```
|
|
8
|
-
|
|
103
|
+
|
|
104
|
+
Then configure Oweb to use your matchers directory:
|
|
105
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
await app.loadRoutes({
|
|
108
|
+
directory: 'routes',
|
|
109
|
+
matchersDirectory: 'matchers', // Directory containing custom matchers
|
|
110
|
+
hmr: {
|
|
111
|
+
enabled: true,
|
|
112
|
+
matchersDirectory: 'matchers', // Optional: Enable HMR for matchers
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Now you can use your custom matchers in route filenames with the syntax `[paramName=matcherName]`.
|
|
118
|
+
|
|
119
|
+
### HTTP Methods
|
|
120
|
+
|
|
121
|
+
Specify the HTTP method in the filename:
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
// routes/api/users.post.js
|
|
125
|
+
import { Route } from 'owebjs';
|
|
126
|
+
|
|
127
|
+
export default class extends Route {
|
|
128
|
+
async handle(req, res) {
|
|
129
|
+
// Create a new user
|
|
130
|
+
const user = req.body;
|
|
131
|
+
res.status(201).send({ id: 1, ...user });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
9
134
|
```
|
|
10
135
|
|
|
11
|
-
##
|
|
136
|
+
## Middleware (Hooks)
|
|
12
137
|
|
|
13
|
-
|
|
138
|
+
Create hooks to add middleware functionality:
|
|
139
|
+
|
|
140
|
+
```javascript
|
|
141
|
+
// routes/_hooks.js
|
|
142
|
+
import { Hook } from 'owebjs';
|
|
143
|
+
|
|
144
|
+
export default class extends Hook {
|
|
145
|
+
handle(req, res, done) {
|
|
146
|
+
console.log(`${req.method} ${req.url}`);
|
|
147
|
+
done(); // Continue to the next hook or route handler
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Hooks are applied to all routes in the current directory and its subdirectories.
|
|
153
|
+
|
|
154
|
+
## Error Handling
|
|
155
|
+
|
|
156
|
+
### Global Error Handler
|
|
157
|
+
|
|
158
|
+
```javascript
|
|
159
|
+
app.setInternalErrorHandler((req, res, error) => {
|
|
160
|
+
console.error(error);
|
|
161
|
+
res.status(500).send({
|
|
162
|
+
error: 'Internal Server Error',
|
|
163
|
+
message: error.message,
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Route-specific Error Handler
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
import { Route } from 'owebjs';
|
|
172
|
+
|
|
173
|
+
export default class extends Route {
|
|
174
|
+
async handle(req, res) {
|
|
175
|
+
throw new Error('Something went wrong');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
handleError(req, res, error) {
|
|
179
|
+
res.status(500).send({
|
|
180
|
+
error: 'Route Error',
|
|
181
|
+
message: error.message,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Plugins
|
|
188
|
+
|
|
189
|
+
Oweb supports Fastify plugins and comes with some built-in plugins:
|
|
190
|
+
|
|
191
|
+
### Using Fastify Plugins
|
|
192
|
+
|
|
193
|
+
```javascript
|
|
194
|
+
import Oweb from 'owebjs';
|
|
195
|
+
import fastifyMultipart from '@fastify/multipart';
|
|
196
|
+
|
|
197
|
+
const app = await new Oweb().setup();
|
|
198
|
+
|
|
199
|
+
// Register Fastify plugin
|
|
200
|
+
await app.register(fastifyMultipart, {
|
|
201
|
+
limits: {
|
|
202
|
+
fileSize: 10 * 1024 * 1024, // 10MB
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Using Built-in Plugins
|
|
208
|
+
|
|
209
|
+
```javascript
|
|
210
|
+
import { Route } from 'owebjs';
|
|
211
|
+
import { ChunkUpload } from 'owebjs/dist/plugins';
|
|
212
|
+
|
|
213
|
+
export default class extends Route {
|
|
214
|
+
async handle(req, res) {
|
|
215
|
+
const file = await req.file();
|
|
216
|
+
const buffer = await file.toBuffer();
|
|
217
|
+
|
|
218
|
+
await ChunkUpload(
|
|
219
|
+
{
|
|
220
|
+
buffer,
|
|
221
|
+
fileName: file.filename,
|
|
222
|
+
currentChunk: +req.query.currentChunk,
|
|
223
|
+
totalChunks: +req.query.totalChunks,
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
path: './uploads',
|
|
227
|
+
maxChunkSize: 5 * 1024 * 1024, // 5MB
|
|
228
|
+
},
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
return res.status(204).send();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Advanced Configuration
|
|
237
|
+
|
|
238
|
+
### uWebSockets.js Support
|
|
239
|
+
|
|
240
|
+
```javascript
|
|
241
|
+
const app = await new Oweb({ uWebSocketsEnabled: true }).setup();
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Custom Route Options
|
|
245
|
+
|
|
246
|
+
```javascript
|
|
247
|
+
import { Route } from 'owebjs';
|
|
248
|
+
|
|
249
|
+
export default class extends Route {
|
|
250
|
+
constructor() {
|
|
251
|
+
super({
|
|
252
|
+
schema: {
|
|
253
|
+
body: {
|
|
254
|
+
type: 'object',
|
|
255
|
+
required: ['username', 'password'],
|
|
256
|
+
properties: {
|
|
257
|
+
username: { type: 'string' },
|
|
258
|
+
password: { type: 'string' },
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
async handle(req, res) {
|
|
266
|
+
// Body is validated according to the schema
|
|
267
|
+
res.send({ success: true });
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
```
|
package/dist/index.d.ts
CHANGED
|
@@ -24,11 +24,13 @@ interface OwebOptions extends FastifyServerOptions {
|
|
|
24
24
|
}
|
|
25
25
|
interface LoadRoutesOptions {
|
|
26
26
|
directory: string;
|
|
27
|
+
matchersDirectory?: string;
|
|
27
28
|
hmr?: {
|
|
28
29
|
/**
|
|
29
30
|
* The directory to watch for changes. If not specified, it will use the routes directory.
|
|
30
31
|
*/
|
|
31
32
|
directory?: string;
|
|
33
|
+
matchersDirectory?: string;
|
|
32
34
|
enabled: boolean;
|
|
33
35
|
};
|
|
34
36
|
}
|
|
@@ -39,6 +41,7 @@ declare class _FastifyInstance {
|
|
|
39
41
|
declare class Oweb extends _FastifyInstance {
|
|
40
42
|
_options: OwebOptions;
|
|
41
43
|
private hmrDirectory;
|
|
44
|
+
private hmrMatchersDirectory;
|
|
42
45
|
routes: Map<string, any>;
|
|
43
46
|
constructor(options?: OwebOptions);
|
|
44
47
|
/**
|
|
@@ -49,11 +52,13 @@ declare class Oweb extends _FastifyInstance {
|
|
|
49
52
|
/**
|
|
50
53
|
* Loads routes from a directory.
|
|
51
54
|
* @param options.directory The directory to load routes from.
|
|
55
|
+
* @param options.matchersDirectory The directory to load matchers from.
|
|
52
56
|
* @param options.hmr Configuration for Hot Module Replacement.
|
|
53
57
|
* @param options.hmr.enabled Whether to enable HMR. HMR is disabled if NODE_ENV is set to production.
|
|
54
|
-
* @param options.hmr.directory The directory to watch for changes. If not specified, it will use the routes directory.
|
|
58
|
+
* @param options.hmr.directory The directory to watch for route changes. If not specified, it will use the routes directory.
|
|
59
|
+
* @param options.hmr.matchersDirectory The directory to watch for matcher changes. If not specified, it will use the matchers directory.
|
|
55
60
|
*/
|
|
56
|
-
loadRoutes({ directory, hmr }: LoadRoutesOptions): Promise<void>;
|
|
61
|
+
loadRoutes({ directory, matchersDirectory, hmr }: LoadRoutesOptions): Promise<void>;
|
|
57
62
|
/**
|
|
58
63
|
*
|
|
59
64
|
* Watches for changes in the routes directory
|
package/dist/structures/Oweb.js
CHANGED
|
@@ -2,8 +2,8 @@ import {
|
|
|
2
2
|
__name
|
|
3
3
|
} from "../chunk-SHUYVCID.js";
|
|
4
4
|
import Fastify from "fastify";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { applyMatcherHMR, applyRouteHMR, assignRoutes } from '../utils/assignRoutes.js';
|
|
6
|
+
import { watchDirectory } from '../utils/watcher.js';
|
|
7
7
|
import { info, success, warn } from '../utils/logger.js';
|
|
8
8
|
let _FastifyInstance = class _FastifyInstance2 {
|
|
9
9
|
static {
|
|
@@ -16,6 +16,7 @@ class Oweb extends _FastifyInstance {
|
|
|
16
16
|
}
|
|
17
17
|
_options = {};
|
|
18
18
|
hmrDirectory;
|
|
19
|
+
hmrMatchersDirectory;
|
|
19
20
|
routes = /* @__PURE__ */ new Map();
|
|
20
21
|
constructor(options) {
|
|
21
22
|
super();
|
|
@@ -60,28 +61,37 @@ class Oweb extends _FastifyInstance {
|
|
|
60
61
|
/**
|
|
61
62
|
* Loads routes from a directory.
|
|
62
63
|
* @param options.directory The directory to load routes from.
|
|
64
|
+
* @param options.matchersDirectory The directory to load matchers from.
|
|
63
65
|
* @param options.hmr Configuration for Hot Module Replacement.
|
|
64
66
|
* @param options.hmr.enabled Whether to enable HMR. HMR is disabled if NODE_ENV is set to production.
|
|
65
|
-
* @param options.hmr.directory The directory to watch for changes. If not specified, it will use the routes directory.
|
|
67
|
+
* @param options.hmr.directory The directory to watch for route changes. If not specified, it will use the routes directory.
|
|
68
|
+
* @param options.hmr.matchersDirectory The directory to watch for matcher changes. If not specified, it will use the matchers directory.
|
|
66
69
|
*/
|
|
67
|
-
loadRoutes({ directory, hmr }) {
|
|
70
|
+
loadRoutes({ directory, matchersDirectory, hmr }) {
|
|
68
71
|
if (hmr && !hmr.directory) hmr.directory = directory;
|
|
72
|
+
if (hmr && !hmr.matchersDirectory) hmr.matchersDirectory = matchersDirectory;
|
|
69
73
|
if (hmr?.enabled) {
|
|
70
74
|
this.hmrDirectory = hmr.directory;
|
|
75
|
+
this.hmrMatchersDirectory = hmr.matchersDirectory;
|
|
71
76
|
success(`Hot Module Replacement enabled. Watching changes in ${hmr.directory}`, "HMR");
|
|
72
77
|
} else {
|
|
73
78
|
warn('Hot Module Replacement is disabled. Use "await app.loadRoutes({ hmr: { enabled: true, directory: path } })" to enable it.', "HMR");
|
|
74
79
|
}
|
|
75
|
-
return assignRoutes(this, directory);
|
|
80
|
+
return assignRoutes(this, directory, matchersDirectory);
|
|
76
81
|
}
|
|
77
82
|
/**
|
|
78
83
|
*
|
|
79
84
|
* Watches for changes in the routes directory
|
|
80
85
|
*/
|
|
81
86
|
watch() {
|
|
82
|
-
|
|
83
|
-
|
|
87
|
+
watchDirectory(this.hmrDirectory, true, (op, path, content) => {
|
|
88
|
+
applyRouteHMR(this, op, this.hmrDirectory, path, content);
|
|
84
89
|
});
|
|
90
|
+
if (this.hmrMatchersDirectory) {
|
|
91
|
+
watchDirectory(this.hmrMatchersDirectory, true, (op, path, content) => {
|
|
92
|
+
applyMatcherHMR(this, op, this.hmrMatchersDirectory, path, content);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
85
95
|
}
|
|
86
96
|
/**
|
|
87
97
|
*
|
|
@@ -9,7 +9,9 @@ import { walk } from './walk.js';
|
|
|
9
9
|
import { success, warn } from './logger.js';
|
|
10
10
|
import { match } from "path-to-regexp";
|
|
11
11
|
import generateFunctionFromTypescript from './generateFunctionFromTypescript.js';
|
|
12
|
+
import { readdirSync } from "node:fs";
|
|
12
13
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
let matcherOverrides = {};
|
|
13
15
|
let routeFunctions = {};
|
|
14
16
|
const temporaryRequests = {
|
|
15
17
|
get: {},
|
|
@@ -21,7 +23,41 @@ const temporaryRequests = {
|
|
|
21
23
|
};
|
|
22
24
|
let routesCache = [];
|
|
23
25
|
const compiledRoutes = {};
|
|
24
|
-
|
|
26
|
+
function removeExtension(filePath) {
|
|
27
|
+
const lastDotIndex = filePath.lastIndexOf(".");
|
|
28
|
+
if (lastDotIndex !== -1) {
|
|
29
|
+
return filePath.substring(0, lastDotIndex);
|
|
30
|
+
}
|
|
31
|
+
return filePath;
|
|
32
|
+
}
|
|
33
|
+
__name(removeExtension, "removeExtension");
|
|
34
|
+
const applyMatcherHMR = /* @__PURE__ */ __name(async (oweb, op, workingDir, filePath, content) => {
|
|
35
|
+
let def;
|
|
36
|
+
const fileName = path.basename(filePath);
|
|
37
|
+
if (op === "delete-file") {
|
|
38
|
+
delete matcherOverrides[removeExtension(fileName)];
|
|
39
|
+
success(`Matcher ${filePath} removed in 0ms`, "HMR");
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (filePath.endsWith(".ts")) {
|
|
43
|
+
const start = Date.now();
|
|
44
|
+
def = content.length ? await generateFunctionFromTypescript(content, filePath) : void 0;
|
|
45
|
+
const end = Date.now() - start;
|
|
46
|
+
success(`Matcher ${filePath} compiled and reloaded in ${end}ms`, "HMR");
|
|
47
|
+
} else {
|
|
48
|
+
const start = Date.now();
|
|
49
|
+
const newFilePath = filePath.replaceAll("\\", "/");
|
|
50
|
+
const packageURL = new URL(path.resolve(newFilePath), `file://${__dirname}`).pathname.replaceAll("\\", "/");
|
|
51
|
+
const cacheBuster = `?t=${Date.now()}`;
|
|
52
|
+
def = (await import(packageURL + cacheBuster)).default;
|
|
53
|
+
const end = Date.now() - start;
|
|
54
|
+
success(`Matcher ${filePath} reloaded in ${end}ms`, "HMR");
|
|
55
|
+
}
|
|
56
|
+
if (def) {
|
|
57
|
+
matcherOverrides[removeExtension(fileName)] = def;
|
|
58
|
+
}
|
|
59
|
+
}, "applyMatcherHMR");
|
|
60
|
+
const applyRouteHMR = /* @__PURE__ */ __name(async (oweb, op, workingDir, path2, content) => {
|
|
25
61
|
if (path2.endsWith("hooks.js") || path2.endsWith("hooks.ts")) {
|
|
26
62
|
warn(`Hot Module Replacement is not supported for hooks. Restart the server for changes to take effect.`, "HMR");
|
|
27
63
|
return;
|
|
@@ -65,7 +101,7 @@ const applyHMR = /* @__PURE__ */ __name(async (oweb, op, workingDir, path2, cont
|
|
|
65
101
|
const end = Date.now() - start;
|
|
66
102
|
success(`Route ${f.method.toUpperCase()}:${f.url} removed in ${end}ms`, "HMR");
|
|
67
103
|
}
|
|
68
|
-
}, "
|
|
104
|
+
}, "applyRouteHMR");
|
|
69
105
|
const generateRoutes = /* @__PURE__ */ __name(async (files) => {
|
|
70
106
|
const routes = [];
|
|
71
107
|
for (const file of files) {
|
|
@@ -78,6 +114,7 @@ const generateRoutes = /* @__PURE__ */ __name(async (files) => {
|
|
|
78
114
|
routes.push({
|
|
79
115
|
url: route.url,
|
|
80
116
|
method: route.method,
|
|
117
|
+
matchers: route.matchers,
|
|
81
118
|
fn: compiledRoutes[file.filePath],
|
|
82
119
|
fileInfo: file
|
|
83
120
|
});
|
|
@@ -89,6 +126,7 @@ const generateRoutes = /* @__PURE__ */ __name(async (files) => {
|
|
|
89
126
|
routes.push({
|
|
90
127
|
url: route.url,
|
|
91
128
|
method: route.method,
|
|
129
|
+
matchers: route.matchers,
|
|
92
130
|
fn: routeFuncs,
|
|
93
131
|
fileInfo: file
|
|
94
132
|
});
|
|
@@ -100,7 +138,18 @@ function inner(oweb, route) {
|
|
|
100
138
|
return;
|
|
101
139
|
}
|
|
102
140
|
const routeFunc = new route.fn();
|
|
141
|
+
const matchers = route.matchers;
|
|
103
142
|
return function(req, res) {
|
|
143
|
+
const checkMatchers = /* @__PURE__ */ __name(() => {
|
|
144
|
+
for (const matcher of matchers) {
|
|
145
|
+
const param = req.params[matcher.paramName];
|
|
146
|
+
const fun = matcherOverrides[matcher.matcherName];
|
|
147
|
+
if (fun) {
|
|
148
|
+
return fun(param);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return true;
|
|
152
|
+
}, "checkMatchers");
|
|
104
153
|
const handle = /* @__PURE__ */ __name(() => {
|
|
105
154
|
if (routeFunc.handle.constructor.name == "AsyncFunction") {
|
|
106
155
|
routeFunc.handle(req, res).catch((error) => {
|
|
@@ -127,16 +176,32 @@ function inner(oweb, route) {
|
|
|
127
176
|
const hookFun = route.fileInfo.hooks[index];
|
|
128
177
|
hookFun.prototype.handle(req, res, () => {
|
|
129
178
|
if (index + 1 == route.fileInfo.hooks.length) {
|
|
130
|
-
|
|
179
|
+
if (!checkMatchers()) {
|
|
180
|
+
send404(req, res);
|
|
181
|
+
} else {
|
|
182
|
+
handle();
|
|
183
|
+
}
|
|
131
184
|
}
|
|
132
185
|
});
|
|
133
186
|
}
|
|
134
187
|
} else {
|
|
135
|
-
|
|
188
|
+
if (!checkMatchers()) {
|
|
189
|
+
send404(req, res);
|
|
190
|
+
} else {
|
|
191
|
+
handle();
|
|
192
|
+
}
|
|
136
193
|
}
|
|
137
194
|
};
|
|
138
195
|
}
|
|
139
196
|
__name(inner, "inner");
|
|
197
|
+
function send404(req, res) {
|
|
198
|
+
return res.status(404).send({
|
|
199
|
+
message: `Route ${req.method}:${req.url} not found`,
|
|
200
|
+
error: "Not Found",
|
|
201
|
+
statusCode: 404
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
__name(send404, "send404");
|
|
140
205
|
function assignSpecificRoute(oweb, route) {
|
|
141
206
|
if (!route.fn) return;
|
|
142
207
|
const routeFunc = new route.fn();
|
|
@@ -145,16 +210,39 @@ function assignSpecificRoute(oweb, route) {
|
|
|
145
210
|
if (routeFunctions[route.fileInfo.filePath]) {
|
|
146
211
|
return routeFunctions[route.fileInfo.filePath](req, res);
|
|
147
212
|
} else {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
213
|
+
const vals = temporaryRequests[req.method.toLowerCase()];
|
|
214
|
+
const keys = Object.keys(vals);
|
|
215
|
+
if (!vals || !keys.length) {
|
|
216
|
+
return send404(req, res);
|
|
217
|
+
}
|
|
218
|
+
const f = keys.find((tempName) => {
|
|
219
|
+
const matcher = match(tempName);
|
|
220
|
+
return matcher(req.url);
|
|
152
221
|
});
|
|
222
|
+
if (f && vals[f]) {
|
|
223
|
+
return vals[f](req, res);
|
|
224
|
+
} else {
|
|
225
|
+
return send404(req, res);
|
|
226
|
+
}
|
|
153
227
|
}
|
|
154
228
|
});
|
|
155
229
|
}
|
|
156
230
|
__name(assignSpecificRoute, "assignSpecificRoute");
|
|
157
|
-
|
|
231
|
+
async function loadMatchers(directoryPath) {
|
|
232
|
+
const files = readdirSync(directoryPath);
|
|
233
|
+
for (const file of files) {
|
|
234
|
+
const filePath = path.join(directoryPath, file).replaceAll("\\", "/");
|
|
235
|
+
const fileName = path.basename(filePath);
|
|
236
|
+
const packageURL = new URL(path.resolve(filePath), `file://${__dirname}`).pathname.replaceAll("\\", "/");
|
|
237
|
+
const def = await import(packageURL);
|
|
238
|
+
matcherOverrides[removeExtension(fileName)] = def.default;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
__name(loadMatchers, "loadMatchers");
|
|
242
|
+
const assignRoutes = /* @__PURE__ */ __name(async (oweb, directory, matchersDirectory) => {
|
|
243
|
+
if (matchersDirectory) {
|
|
244
|
+
loadMatchers(matchersDirectory);
|
|
245
|
+
}
|
|
158
246
|
const files = await walk(directory);
|
|
159
247
|
const routes = await generateRoutes(files);
|
|
160
248
|
routesCache = routes;
|
|
@@ -162,11 +250,7 @@ const assignRoutes = /* @__PURE__ */ __name(async (oweb, directory) => {
|
|
|
162
250
|
const vals = temporaryRequests[req.method.toLowerCase()];
|
|
163
251
|
const keys = Object.keys(vals);
|
|
164
252
|
if (!vals || !keys.length) {
|
|
165
|
-
return res
|
|
166
|
-
message: `Route ${req.method}:${req.url} not found`,
|
|
167
|
-
error: "Not Found",
|
|
168
|
-
statusCode: 404
|
|
169
|
-
});
|
|
253
|
+
return send404(req, res);
|
|
170
254
|
}
|
|
171
255
|
const f = keys.find((tempName) => {
|
|
172
256
|
const matcher = match(tempName);
|
|
@@ -175,11 +259,7 @@ const assignRoutes = /* @__PURE__ */ __name(async (oweb, directory) => {
|
|
|
175
259
|
if (f && vals[f]) {
|
|
176
260
|
return vals[f](req, res);
|
|
177
261
|
} else {
|
|
178
|
-
return res
|
|
179
|
-
message: `Route ${req.method}:${req.url} not found`,
|
|
180
|
-
error: "Not Found",
|
|
181
|
-
statusCode: 404
|
|
182
|
-
});
|
|
262
|
+
return send404(req, res);
|
|
183
263
|
}
|
|
184
264
|
});
|
|
185
265
|
for (const route of routes) {
|
|
@@ -187,7 +267,8 @@ const assignRoutes = /* @__PURE__ */ __name(async (oweb, directory) => {
|
|
|
187
267
|
}
|
|
188
268
|
}, "assignRoutes");
|
|
189
269
|
export {
|
|
190
|
-
|
|
270
|
+
applyMatcherHMR,
|
|
271
|
+
applyRouteHMR,
|
|
191
272
|
assignRoutes,
|
|
192
273
|
generateRoutes
|
|
193
274
|
};
|
package/dist/utils/utils.js
CHANGED
|
@@ -28,6 +28,18 @@ const buildRouteURL = /* @__PURE__ */ __name((path) => {
|
|
|
28
28
|
let method = "get";
|
|
29
29
|
const paramURL = convertParamSyntax(normalizedPath);
|
|
30
30
|
let url = convertCatchallSyntax(paramURL);
|
|
31
|
+
const matcherSplit = url.split("/");
|
|
32
|
+
const matcherFilter = matcherSplit.filter((x) => x.startsWith(":"));
|
|
33
|
+
const matchers = matcherFilter.map((x) => {
|
|
34
|
+
const split = x.split("=");
|
|
35
|
+
return {
|
|
36
|
+
paramName: split[0].slice(1),
|
|
37
|
+
matcherName: split[1]
|
|
38
|
+
};
|
|
39
|
+
}).filter((x) => x.matcherName);
|
|
40
|
+
for (const matcher of matchers) {
|
|
41
|
+
url = url.replace(`:${matcher.paramName}=${matcher.matcherName}`, `:${matcher.paramName}`);
|
|
42
|
+
}
|
|
31
43
|
for (const m of [
|
|
32
44
|
".DELETE",
|
|
33
45
|
".POST",
|
|
@@ -43,7 +55,8 @@ const buildRouteURL = /* @__PURE__ */ __name((path) => {
|
|
|
43
55
|
}
|
|
44
56
|
return {
|
|
45
57
|
url,
|
|
46
|
-
method
|
|
58
|
+
method,
|
|
59
|
+
matchers
|
|
47
60
|
};
|
|
48
61
|
}, "buildRouteURL");
|
|
49
62
|
export {
|
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
} from "../chunk-SHUYVCID.js";
|
|
4
4
|
import chokidar from "chokidar";
|
|
5
5
|
import { readFileSync } from "fs";
|
|
6
|
-
function
|
|
6
|
+
function watchDirectory(dir, ignoreInitial = true, onUpdate) {
|
|
7
7
|
const watcher = chokidar.watch(dir, {
|
|
8
8
|
ignored: /([/\\]\.)|(node_modules)|(dist)/,
|
|
9
9
|
persistent: true,
|
|
10
|
-
ignoreInitial
|
|
10
|
+
ignoreInitial,
|
|
11
11
|
awaitWriteFinish: {
|
|
12
12
|
stabilityThreshold: 150,
|
|
13
13
|
pollInterval: 50
|
|
@@ -25,7 +25,7 @@ function watchRoutes(dir, onUpdate) {
|
|
|
25
25
|
onUpdate("delete-file", filePath, "");
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
|
-
__name(
|
|
28
|
+
__name(watchDirectory, "watchDirectory");
|
|
29
29
|
export {
|
|
30
|
-
|
|
30
|
+
watchDirectory
|
|
31
31
|
};
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "owebjs",
|
|
3
|
-
"version": "1.3.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.3.2",
|
|
4
|
+
"description": "A flexible and modern web framework built on top of Fastify",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"exports": {
|