owebjs 1.5.5-dev → 1.5.8-dev
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/0http.js +8 -0
- package/README.md +477 -270
- package/benchmark.txt +191 -0
- package/dist/index.d.ts +4 -0
- package/dist/structures/Oweb.js +67 -8
- package/dist/utils/assignRoutes.js +298 -180
- package/dist/utils/walk.js +5 -6
- package/dist/utils/watcher.js +21 -9
- package/dist/uwebsocket/request.js +59 -26
- package/dist/uwebsocket/response.js +34 -12
- package/dist/uwebsocket/responseSocket.js +5 -1
- package/dist/uwebsocket/server.js +84 -53
- package/express.js +14 -0
- package/fasti.js +14 -0
- package/package.json +6 -4
- package/purehttp.js +19 -0
- package/uws.js +16 -0
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
__name
|
|
3
3
|
} from "../chunk-SHUYVCID.js";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import {
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
6
6
|
import { buildRoutePath, buildRouteURL } from './utils.js';
|
|
7
7
|
import { walk } from './walk.js';
|
|
8
8
|
import { error, success, warn } from './logger.js';
|
|
@@ -13,27 +13,51 @@ import { WebSocketRoute } from '../structures/WebSocketRoute.js';
|
|
|
13
13
|
import { FastifyWebSocketAdapter } from '../structures/FastifyWebSocketAdapter.js';
|
|
14
14
|
import { formatSSE } from './utils.js';
|
|
15
15
|
const websocketRoutes = {};
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
let matcherOverrides = {};
|
|
19
|
-
let routeFunctions = {
|
|
16
|
+
const WS_REGISTRY_KEY = "ws:registered-routes";
|
|
17
|
+
const createMethodMap = /* @__PURE__ */ __name(() => ({
|
|
20
18
|
get: {},
|
|
21
19
|
post: {},
|
|
22
20
|
put: {},
|
|
23
21
|
delete: {},
|
|
24
22
|
patch: {},
|
|
25
23
|
options: {}
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
put: {},
|
|
31
|
-
delete: {},
|
|
32
|
-
patch: {},
|
|
33
|
-
options: {}
|
|
34
|
-
};
|
|
24
|
+
}), "createMethodMap");
|
|
25
|
+
let matcherOverrides = {};
|
|
26
|
+
let routeFunctions = createMethodMap();
|
|
27
|
+
let temporaryRequests = createMethodMap();
|
|
35
28
|
let routesCache = [];
|
|
36
|
-
|
|
29
|
+
let compiledRoutes = {};
|
|
30
|
+
function normalizeFsPath(filePath) {
|
|
31
|
+
return path.resolve(filePath).replaceAll("\\", "/").toLowerCase();
|
|
32
|
+
}
|
|
33
|
+
__name(normalizeFsPath, "normalizeFsPath");
|
|
34
|
+
async function importFreshModule(filePath, source) {
|
|
35
|
+
const resolvedHref = pathToFileURL(path.resolve(filePath)).href;
|
|
36
|
+
const cacheBuster = `?t=${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
37
|
+
if (source?.length && !/['"]\.\.?\//.test(source)) {
|
|
38
|
+
const stampedSource = `${source}
|
|
39
|
+
//# sourceURL=${resolvedHref}${cacheBuster}`;
|
|
40
|
+
const dataUrl = `data:text/javascript;base64,${Buffer.from(stampedSource, "utf-8").toString("base64")}`;
|
|
41
|
+
try {
|
|
42
|
+
return await import(dataUrl);
|
|
43
|
+
} catch {
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return import(resolvedHref + cacheBuster);
|
|
47
|
+
}
|
|
48
|
+
__name(importFreshModule, "importFreshModule");
|
|
49
|
+
function resetRuntimeCaches(oweb) {
|
|
50
|
+
matcherOverrides = {};
|
|
51
|
+
routeFunctions = createMethodMap();
|
|
52
|
+
temporaryRequests = createMethodMap();
|
|
53
|
+
routesCache = [];
|
|
54
|
+
compiledRoutes = {};
|
|
55
|
+
for (const key of Object.keys(websocketRoutes)) {
|
|
56
|
+
delete websocketRoutes[key];
|
|
57
|
+
}
|
|
58
|
+
oweb._internalKV.delete(WS_REGISTRY_KEY);
|
|
59
|
+
}
|
|
60
|
+
__name(resetRuntimeCaches, "resetRuntimeCaches");
|
|
37
61
|
function removeExtension(filePath) {
|
|
38
62
|
const lastDotIndex = filePath.lastIndexOf(".");
|
|
39
63
|
if (lastDotIndex !== -1) {
|
|
@@ -91,8 +115,7 @@ const applyMatcherHMR = /* @__PURE__ */ __name(async (oweb, op, workingDir, fall
|
|
|
91
115
|
success(`Matcher ${filePath} compiled and reloaded in ${end}ms`, "HMR");
|
|
92
116
|
} else {
|
|
93
117
|
const start = Date.now();
|
|
94
|
-
const
|
|
95
|
-
const packageURL = new URL(path.resolve(newFilePath), `file://${__dirname}`).pathname.replaceAll("\\", "/");
|
|
118
|
+
const packageURL = pathToFileURL(path.resolve(filePath)).href;
|
|
96
119
|
const cacheBuster = `?t=${Date.now()}`;
|
|
97
120
|
def = (await import(packageURL + cacheBuster)).default;
|
|
98
121
|
const end = Date.now() - start;
|
|
@@ -103,6 +126,7 @@ const applyMatcherHMR = /* @__PURE__ */ __name(async (oweb, op, workingDir, fall
|
|
|
103
126
|
}
|
|
104
127
|
}, "applyMatcherHMR");
|
|
105
128
|
const applyRouteHMR = /* @__PURE__ */ __name(async (oweb, op, workingDir, fallbackDir, path2, content) => {
|
|
129
|
+
const normalizedChangedPath = normalizeFsPath(path2);
|
|
106
130
|
if (path2.endsWith("hooks.js") || path2.endsWith("hooks.ts")) {
|
|
107
131
|
warn(`Hot Module Replacement is not supported for hooks. Restart the server for changes to take effect.`, "HMR");
|
|
108
132
|
return;
|
|
@@ -118,14 +142,30 @@ const applyRouteHMR = /* @__PURE__ */ __name(async (oweb, op, workingDir, fallba
|
|
|
118
142
|
const files = await walk(workingDir, [], fallbackDir);
|
|
119
143
|
const routes = await generateRoutes(files, path2);
|
|
120
144
|
routesCache = routes;
|
|
121
|
-
const f = routes.find((x) => x.fileInfo.filePath
|
|
122
|
-
if (f
|
|
145
|
+
const f = routes.find((x) => normalizeFsPath(x.fileInfo.filePath) === normalizedChangedPath);
|
|
146
|
+
if (!f) {
|
|
147
|
+
warn(`HMR could not resolve route metadata for file ${path2}`, "HMR");
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (!path2.endsWith(".ts") && content.length) {
|
|
151
|
+
const fresh = await importFreshModule(path2, content);
|
|
152
|
+
if (fresh?.default) {
|
|
153
|
+
f.fn = fresh.default;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (f.fn?.prototype instanceof WebSocketRoute) {
|
|
123
157
|
assignSpecificRoute(oweb, f);
|
|
124
158
|
const end2 = Date.now() - start;
|
|
125
159
|
success(`WebSocket Route ${f.url} created in ${end2}ms`, "HMR");
|
|
126
160
|
return;
|
|
127
161
|
}
|
|
128
|
-
|
|
162
|
+
const method = f.method.toLowerCase();
|
|
163
|
+
const nextHandler = inner(oweb, f);
|
|
164
|
+
if (routeFunctions[method][f.url]) {
|
|
165
|
+
routeFunctions[method][f.url] = nextHandler;
|
|
166
|
+
} else {
|
|
167
|
+
temporaryRequests[method][f.url] = nextHandler;
|
|
168
|
+
}
|
|
129
169
|
const end = Date.now() - start;
|
|
130
170
|
success(`Route ${f.method.toUpperCase()}:${f.url} created in ${end}ms`, "HMR");
|
|
131
171
|
} else if (op === "modify-file") {
|
|
@@ -133,17 +173,31 @@ const applyRouteHMR = /* @__PURE__ */ __name(async (oweb, op, workingDir, fallba
|
|
|
133
173
|
const files = await walk(workingDir, [], fallbackDir);
|
|
134
174
|
const routes = await generateRoutes(files, path2);
|
|
135
175
|
routesCache = routes;
|
|
136
|
-
const f = routes.find((x) => x.fileInfo.filePath
|
|
137
|
-
if (f
|
|
176
|
+
const f = routes.find((x) => normalizeFsPath(x.fileInfo.filePath) === normalizedChangedPath);
|
|
177
|
+
if (!f) {
|
|
178
|
+
warn(`HMR could not resolve route metadata for file ${path2}`, "HMR");
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (!path2.endsWith(".ts") && content.length) {
|
|
182
|
+
const fresh = await importFreshModule(path2, content);
|
|
183
|
+
if (fresh?.default) {
|
|
184
|
+
f.fn = fresh.default;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (f.fn?.prototype instanceof WebSocketRoute) {
|
|
138
188
|
websocketRoutes[f.url] = new f.fn();
|
|
139
189
|
const end2 = Date.now() - start;
|
|
140
190
|
success(`WebSocket Route ${f.url} reloaded in ${end2}ms`, "HMR");
|
|
141
191
|
return;
|
|
142
192
|
}
|
|
143
|
-
|
|
144
|
-
|
|
193
|
+
const method = f.method.toLowerCase();
|
|
194
|
+
const nextHandler = inner(oweb, f);
|
|
195
|
+
if (routeFunctions[method][f.url]) {
|
|
196
|
+
routeFunctions[method][f.url] = nextHandler;
|
|
197
|
+
} else if (f.url in temporaryRequests[method]) {
|
|
198
|
+
temporaryRequests[method][f.url] = nextHandler;
|
|
145
199
|
} else {
|
|
146
|
-
routeFunctions[
|
|
200
|
+
routeFunctions[method][f.url] = nextHandler;
|
|
147
201
|
}
|
|
148
202
|
const end = Date.now() - start;
|
|
149
203
|
success(`Route ${f.method.toUpperCase()}:${f.url} reloaded in ${end}ms`, "HMR");
|
|
@@ -176,8 +230,7 @@ const generateRoutes = /* @__PURE__ */ __name(async (files, onlyGenerateFn) => {
|
|
|
176
230
|
const routes = [];
|
|
177
231
|
for (const file of files) {
|
|
178
232
|
const parsedFile = path.parse(file.rel);
|
|
179
|
-
const
|
|
180
|
-
const packageURL = new URL(path.resolve(filePath), `file://${__dirname}`).pathname.replaceAll("\\", "/");
|
|
233
|
+
const packageURL = pathToFileURL(path.resolve(file.filePath)).href;
|
|
181
234
|
const routePath = buildRoutePath(parsedFile);
|
|
182
235
|
const route = buildRouteURL(routePath);
|
|
183
236
|
if (compiledRoutes[file.filePath]) {
|
|
@@ -191,7 +244,7 @@ const generateRoutes = /* @__PURE__ */ __name(async (files, onlyGenerateFn) => {
|
|
|
191
244
|
continue;
|
|
192
245
|
}
|
|
193
246
|
let routeFuncs;
|
|
194
|
-
if (!(onlyGenerateFn && file.filePath !== onlyGenerateFn)) {
|
|
247
|
+
if (!(onlyGenerateFn && normalizeFsPath(file.filePath) !== normalizeFsPath(onlyGenerateFn))) {
|
|
195
248
|
const cacheBuster = `?t=${Date.now()}`;
|
|
196
249
|
const def = await import(packageURL + cacheBuster);
|
|
197
250
|
routeFuncs = def.default;
|
|
@@ -212,141 +265,186 @@ function inner(oweb, route) {
|
|
|
212
265
|
}
|
|
213
266
|
const routeFunc = new route.fn();
|
|
214
267
|
const matchers = route.matchers;
|
|
268
|
+
const hooks = route.fileInfo.hooks;
|
|
269
|
+
const hasHooks = hooks.length > 0;
|
|
270
|
+
const hasMatchers = matchers.length > 0;
|
|
215
271
|
const isParametric = route.url.includes(":") || route.url.includes("*");
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
272
|
+
const handleIsAsync = routeFunc.handle.constructor.name === "AsyncFunction";
|
|
273
|
+
const hasRouteErrorHandler = typeof routeFunc?.handleError === "function";
|
|
274
|
+
const hmrEnabled = !!oweb._internalKV.get("hmr");
|
|
275
|
+
const checkMatchers = /* @__PURE__ */ __name((req) => {
|
|
276
|
+
if (!hasMatchers) return true;
|
|
277
|
+
for (const matcher of matchers) {
|
|
278
|
+
const param = req.params[matcher.paramName];
|
|
279
|
+
const fun = matcherOverrides[matcher.matcherName];
|
|
280
|
+
if (fun) {
|
|
281
|
+
return fun(param);
|
|
223
282
|
}
|
|
224
283
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
284
|
+
return true;
|
|
285
|
+
}, "checkMatchers");
|
|
286
|
+
const handleError = /* @__PURE__ */ __name((req, res, err) => {
|
|
287
|
+
const normalizedError = err instanceof Error ? err : new Error(String(err));
|
|
288
|
+
if (hasRouteErrorHandler) {
|
|
289
|
+
routeFunc.handleError(req, res, normalizedError);
|
|
290
|
+
} else {
|
|
291
|
+
oweb._options.OWEB_INTERNAL_ERROR_HANDLER(req, res, normalizedError);
|
|
292
|
+
}
|
|
293
|
+
}, "handleError");
|
|
294
|
+
const streamResult = /* @__PURE__ */ __name(async (req, res, result, isAsyncIterable) => {
|
|
295
|
+
const iterator = isAsyncIterable ? result[Symbol.asyncIterator]() : result[Symbol.iterator]();
|
|
296
|
+
let firstChunk;
|
|
297
|
+
try {
|
|
298
|
+
firstChunk = await iterator.next();
|
|
299
|
+
} catch (err) {
|
|
300
|
+
handleError(req, res, err);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
if (res.sent) return;
|
|
304
|
+
if (firstChunk.done) {
|
|
305
|
+
if (firstChunk.value !== void 0) res.send(firstChunk.value);
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
const rawObj = res.raw;
|
|
309
|
+
const uwsRes = rawObj.res && typeof rawObj.res.cork === "function" ? rawObj.res : null;
|
|
310
|
+
const corkedOp = /* @__PURE__ */ __name((op) => {
|
|
311
|
+
if (uwsRes) uwsRes.cork(op);
|
|
312
|
+
else op();
|
|
313
|
+
}, "corkedOp");
|
|
314
|
+
corkedOp(() => {
|
|
315
|
+
const headers = {
|
|
316
|
+
...res.getHeaders(),
|
|
317
|
+
"Content-Type": "text/event-stream",
|
|
318
|
+
"Cache-Control": "no-cache",
|
|
319
|
+
Connection: "keep-alive"
|
|
320
|
+
};
|
|
321
|
+
res.raw.writeHead(200, headers);
|
|
322
|
+
if (res.raw.flushHeaders) res.raw.flushHeaders();
|
|
323
|
+
});
|
|
324
|
+
let aborted = false;
|
|
325
|
+
const onAborted = /* @__PURE__ */ __name(() => {
|
|
326
|
+
aborted = true;
|
|
327
|
+
}, "onAborted");
|
|
328
|
+
if (res.raw.on) {
|
|
329
|
+
res.raw.on("close", onAborted);
|
|
330
|
+
res.raw.on("aborted", onAborted);
|
|
331
|
+
} else if (rawObj["onAborted"]) {
|
|
332
|
+
rawObj["onAborted"](onAborted);
|
|
333
|
+
}
|
|
334
|
+
try {
|
|
335
|
+
corkedOp(() => {
|
|
336
|
+
res.raw.write(formatSSE(firstChunk.value));
|
|
337
|
+
});
|
|
338
|
+
while (true) {
|
|
339
|
+
if (aborted || res.raw.destroyed) break;
|
|
340
|
+
const chunk = await iterator.next();
|
|
341
|
+
if (chunk.done) break;
|
|
342
|
+
corkedOp(() => {
|
|
343
|
+
res.raw.write(formatSSE(chunk.value));
|
|
344
|
+
});
|
|
232
345
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
result = await routeFunc.handle(req, res);
|
|
240
|
-
} else {
|
|
241
|
-
result = routeFunc.handle(req, res);
|
|
242
|
-
if (result instanceof Promise) {
|
|
243
|
-
result = await result;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
} catch (error2) {
|
|
247
|
-
if (routeFunc?.handleError) {
|
|
248
|
-
routeFunc.handleError(req, res, error2);
|
|
249
|
-
} else {
|
|
250
|
-
oweb._options.OWEB_INTERNAL_ERROR_HANDLER(req, res, error2);
|
|
251
|
-
}
|
|
252
|
-
return;
|
|
346
|
+
} catch (err) {
|
|
347
|
+
error("Error while streaming response for " + route.method.toUpperCase() + ":" + route.url + " - " + err.message, "SSE");
|
|
348
|
+
} finally {
|
|
349
|
+
if (res.raw.off) {
|
|
350
|
+
res.raw.off("close", onAborted);
|
|
351
|
+
res.raw.off("aborted", onAborted);
|
|
253
352
|
}
|
|
254
|
-
if (res.
|
|
255
|
-
const isIterable = result && typeof result[Symbol.iterator] === "function";
|
|
256
|
-
const isAsyncIterable = result && typeof result[Symbol.asyncIterator] === "function";
|
|
257
|
-
if (isIterable || isAsyncIterable) {
|
|
258
|
-
const iterator = isAsyncIterable ? result[Symbol.asyncIterator]() : result[Symbol.iterator]();
|
|
259
|
-
let firstChunk;
|
|
260
|
-
try {
|
|
261
|
-
firstChunk = await iterator.next();
|
|
262
|
-
} catch (err) {
|
|
263
|
-
if (routeFunc?.handleError) routeFunc.handleError(req, res, err);
|
|
264
|
-
else oweb._options.OWEB_INTERNAL_ERROR_HANDLER(req, res, err);
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
|
-
if (res.sent) return;
|
|
268
|
-
if (firstChunk.done) {
|
|
269
|
-
if (firstChunk.value !== void 0) res.send(firstChunk.value);
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
const rawObj = res.raw;
|
|
273
|
-
const uwsRes = rawObj.res && typeof rawObj.res.cork === "function" ? rawObj.res : null;
|
|
274
|
-
const corkedOp = /* @__PURE__ */ __name((op) => {
|
|
275
|
-
if (uwsRes) uwsRes.cork(op);
|
|
276
|
-
else op();
|
|
277
|
-
}, "corkedOp");
|
|
353
|
+
if (!aborted && !res.raw.destroyed) {
|
|
278
354
|
corkedOp(() => {
|
|
279
|
-
|
|
280
|
-
...res.getHeaders(),
|
|
281
|
-
"Content-Type": "text/event-stream",
|
|
282
|
-
"Cache-Control": "no-cache",
|
|
283
|
-
Connection: "keep-alive"
|
|
284
|
-
};
|
|
285
|
-
res.raw.writeHead(200, headers);
|
|
286
|
-
if (res.raw.flushHeaders) res.raw.flushHeaders();
|
|
355
|
+
res.raw.end();
|
|
287
356
|
});
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}, "streamResult");
|
|
360
|
+
const finalizeResult = /* @__PURE__ */ __name((req, res, result) => {
|
|
361
|
+
if (res.sent) return;
|
|
362
|
+
const isIterable = result && typeof result[Symbol.iterator] === "function";
|
|
363
|
+
const isAsyncIterable = result && typeof result[Symbol.asyncIterator] === "function";
|
|
364
|
+
if (isIterable || isAsyncIterable) {
|
|
365
|
+
streamResult(req, res, result, isAsyncIterable);
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
if (!res.sent && result !== void 0) {
|
|
369
|
+
res.send(result);
|
|
370
|
+
}
|
|
371
|
+
}, "finalizeResult");
|
|
372
|
+
const executeRoute = handleIsAsync ? async (req, res) => {
|
|
373
|
+
try {
|
|
374
|
+
const result = await routeFunc.handle(req, res);
|
|
375
|
+
finalizeResult(req, res, result);
|
|
376
|
+
} catch (error2) {
|
|
377
|
+
handleError(req, res, error2);
|
|
378
|
+
}
|
|
379
|
+
} : (req, res) => {
|
|
380
|
+
let result;
|
|
381
|
+
try {
|
|
382
|
+
result = routeFunc.handle(req, res);
|
|
383
|
+
} catch (error2) {
|
|
384
|
+
handleError(req, res, error2);
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
if (result instanceof Promise) {
|
|
388
|
+
result.then((resolved) => {
|
|
389
|
+
finalizeResult(req, res, resolved);
|
|
390
|
+
}).catch((error2) => {
|
|
391
|
+
handleError(req, res, error2);
|
|
392
|
+
});
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
finalizeResult(req, res, result);
|
|
396
|
+
};
|
|
397
|
+
const isSimpleRoute = !hmrEnabled && !hasHooks && !hasMatchers && !isParametric;
|
|
398
|
+
if (isSimpleRoute) {
|
|
399
|
+
return function(req, res) {
|
|
400
|
+
executeRoute(req, res);
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
const runHooks = /* @__PURE__ */ __name((req, res) => {
|
|
404
|
+
let hookIndex = 0;
|
|
405
|
+
const runNextHook = /* @__PURE__ */ __name((hookErr) => {
|
|
406
|
+
if (hookErr) {
|
|
407
|
+
handleError(req, res, hookErr);
|
|
323
408
|
return;
|
|
324
409
|
}
|
|
325
|
-
if (
|
|
326
|
-
|
|
410
|
+
if (res.sent) return;
|
|
411
|
+
if (hookIndex >= hooks.length) {
|
|
412
|
+
executeRoute(req, res);
|
|
413
|
+
return;
|
|
327
414
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
}
|
|
341
|
-
});
|
|
415
|
+
const hookFun = hooks[hookIndex++];
|
|
416
|
+
const hookInstance = typeof hookFun === "function" ? new hookFun() : hookFun;
|
|
417
|
+
let doneCalled = false;
|
|
418
|
+
const done = /* @__PURE__ */ __name((doneErr) => {
|
|
419
|
+
if (doneCalled) return;
|
|
420
|
+
doneCalled = true;
|
|
421
|
+
runNextHook(doneErr);
|
|
422
|
+
}, "done");
|
|
423
|
+
try {
|
|
424
|
+
hookInstance.handle(req, res, done);
|
|
425
|
+
} catch (err) {
|
|
426
|
+
done(err);
|
|
342
427
|
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
428
|
+
}, "runNextHook");
|
|
429
|
+
runNextHook();
|
|
430
|
+
}, "runHooks");
|
|
431
|
+
return function(req, res) {
|
|
432
|
+
if (hmrEnabled && isParametric) {
|
|
433
|
+
const currentPath = req.raw.url.split("?")[0];
|
|
434
|
+
const method = req.method.toLowerCase();
|
|
435
|
+
const specificHandler = temporaryRequests[method]?.[currentPath];
|
|
436
|
+
if (specificHandler) {
|
|
437
|
+
return specificHandler(req, res);
|
|
348
438
|
}
|
|
349
439
|
}
|
|
440
|
+
if (!checkMatchers(req)) {
|
|
441
|
+
return send404(req, res);
|
|
442
|
+
}
|
|
443
|
+
if (!hasHooks) {
|
|
444
|
+
executeRoute(req, res);
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
runHooks(req, res);
|
|
350
448
|
};
|
|
351
449
|
}
|
|
352
450
|
__name(inner, "inner");
|
|
@@ -358,11 +456,21 @@ function send404(req, res) {
|
|
|
358
456
|
});
|
|
359
457
|
}
|
|
360
458
|
__name(send404, "send404");
|
|
459
|
+
function getRegisteredWebSocketsForApp(oweb) {
|
|
460
|
+
let wsRegistry = oweb._internalKV.get(WS_REGISTRY_KEY);
|
|
461
|
+
if (!wsRegistry) {
|
|
462
|
+
wsRegistry = /* @__PURE__ */ new Set();
|
|
463
|
+
oweb._internalKV.set(WS_REGISTRY_KEY, wsRegistry);
|
|
464
|
+
}
|
|
465
|
+
return wsRegistry;
|
|
466
|
+
}
|
|
467
|
+
__name(getRegisteredWebSocketsForApp, "getRegisteredWebSocketsForApp");
|
|
361
468
|
function assignSpecificRoute(oweb, route) {
|
|
362
469
|
if (!route?.fn) return;
|
|
363
470
|
if (route?.fn?.prototype instanceof WebSocketRoute) {
|
|
364
471
|
const wsInstance = new route.fn();
|
|
365
472
|
websocketRoutes[route.url] = wsInstance;
|
|
473
|
+
const registeredWebSockets = getRegisteredWebSocketsForApp(oweb);
|
|
366
474
|
if (!registeredWebSockets.has(route.url)) {
|
|
367
475
|
registeredWebSockets.add(route.url);
|
|
368
476
|
if (oweb._options.uWebSocketsEnabled && oweb.uServer) {
|
|
@@ -461,27 +569,34 @@ function assignSpecificRoute(oweb, route) {
|
|
|
461
569
|
return;
|
|
462
570
|
}
|
|
463
571
|
const routeFunc = new route.fn();
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
return send404(req, res);
|
|
473
|
-
}
|
|
474
|
-
const f = keys.find((tempName) => {
|
|
475
|
-
const matcher = match(tempName);
|
|
476
|
-
return matcher(req.url);
|
|
477
|
-
});
|
|
478
|
-
if (f && vals[f]) {
|
|
479
|
-
return vals[f](req, res);
|
|
572
|
+
const routeHandler = inner(oweb, route);
|
|
573
|
+
if (!routeHandler) return;
|
|
574
|
+
const hmrEnabled = !!oweb._internalKV.get("hmr");
|
|
575
|
+
if (hmrEnabled) {
|
|
576
|
+
routeFunctions[route.method][route.url] = routeHandler;
|
|
577
|
+
oweb[route.method](route.url, routeFunc._options || {}, function(req, res) {
|
|
578
|
+
if (routeFunctions[route.method][route.url]) {
|
|
579
|
+
return routeFunctions[route.method][route.url](req, res);
|
|
480
580
|
} else {
|
|
481
|
-
|
|
581
|
+
const vals = temporaryRequests[route.method];
|
|
582
|
+
const keys = Object.keys(vals);
|
|
583
|
+
if (!vals || !keys.length) {
|
|
584
|
+
return send404(req, res);
|
|
585
|
+
}
|
|
586
|
+
const f = keys.find((tempName) => {
|
|
587
|
+
const matcher = match(tempName);
|
|
588
|
+
return matcher(req.url);
|
|
589
|
+
});
|
|
590
|
+
if (f && vals[f]) {
|
|
591
|
+
return vals[f](req, res);
|
|
592
|
+
} else {
|
|
593
|
+
return send404(req, res);
|
|
594
|
+
}
|
|
482
595
|
}
|
|
483
|
-
}
|
|
484
|
-
|
|
596
|
+
});
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
oweb[route.method](route.url, routeFunc._options || {}, routeHandler);
|
|
485
600
|
}
|
|
486
601
|
__name(assignSpecificRoute, "assignSpecificRoute");
|
|
487
602
|
async function loadMatchers(directoryPath) {
|
|
@@ -490,17 +605,18 @@ async function loadMatchers(directoryPath) {
|
|
|
490
605
|
".ts"
|
|
491
606
|
].includes(path.extname(f)));
|
|
492
607
|
for (const file of files) {
|
|
493
|
-
const filePath = path.join(directoryPath, file)
|
|
608
|
+
const filePath = path.join(directoryPath, file);
|
|
494
609
|
const fileName = path.basename(filePath);
|
|
495
|
-
const packageURL =
|
|
610
|
+
const packageURL = pathToFileURL(path.resolve(filePath)).href;
|
|
496
611
|
const def = await import(packageURL);
|
|
497
612
|
matcherOverrides[removeExtension(fileName)] = def.default;
|
|
498
613
|
}
|
|
499
614
|
}
|
|
500
615
|
__name(loadMatchers, "loadMatchers");
|
|
501
616
|
const assignRoutes = /* @__PURE__ */ __name(async (oweb, directory, matchersDirectory) => {
|
|
617
|
+
resetRuntimeCaches(oweb);
|
|
502
618
|
if (matchersDirectory) {
|
|
503
|
-
loadMatchers(matchersDirectory);
|
|
619
|
+
await loadMatchers(matchersDirectory);
|
|
504
620
|
}
|
|
505
621
|
const files = await walk(directory);
|
|
506
622
|
const routes = await generateRoutes(files);
|
|
@@ -522,14 +638,16 @@ const assignRoutes = /* @__PURE__ */ __name(async (oweb, directory, matchersDire
|
|
|
522
638
|
}
|
|
523
639
|
}
|
|
524
640
|
__name(fallbackHandle, "fallbackHandle");
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
641
|
+
if (oweb._internalKV.get("hmr")) {
|
|
642
|
+
for (const element of [
|
|
643
|
+
"get",
|
|
644
|
+
"post",
|
|
645
|
+
"put",
|
|
646
|
+
"patch",
|
|
647
|
+
"delete"
|
|
648
|
+
]) {
|
|
649
|
+
oweb[element]("*", fallbackHandle);
|
|
650
|
+
}
|
|
533
651
|
}
|
|
534
652
|
for (const route of routes) {
|
|
535
653
|
assignSpecificRoute(oweb, route);
|
package/dist/utils/walk.js
CHANGED
|
@@ -2,11 +2,10 @@ import {
|
|
|
2
2
|
__name
|
|
3
3
|
} from "../chunk-SHUYVCID.js";
|
|
4
4
|
import { readdirSync, statSync } from "node:fs";
|
|
5
|
-
import {
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { mergePaths } from './utils.js';
|
|
8
8
|
import { warn } from './logger.js';
|
|
9
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
9
|
const isParentOrGrandparent = /* @__PURE__ */ __name((parentFolderPath, childFolderPath) => {
|
|
11
10
|
if (childFolderPath.startsWith(parentFolderPath)) {
|
|
12
11
|
const relativePath = path.relative(parentFolderPath, childFolderPath);
|
|
@@ -15,8 +14,7 @@ const isParentOrGrandparent = /* @__PURE__ */ __name((parentFolderPath, childFol
|
|
|
15
14
|
}
|
|
16
15
|
return false;
|
|
17
16
|
}, "isParentOrGrandparent");
|
|
18
|
-
const hookPaths = /* @__PURE__ */ new Set()
|
|
19
|
-
const walk = /* @__PURE__ */ __name(async (directory, tree = [], fallbackDir) => {
|
|
17
|
+
const walk = /* @__PURE__ */ __name(async (directory, tree = [], fallbackDir, hookPaths = /* @__PURE__ */ new Set()) => {
|
|
20
18
|
const results = [];
|
|
21
19
|
const readDirPriority = readdirSync(directory);
|
|
22
20
|
readDirPriority.sort((a, b) => {
|
|
@@ -40,7 +38,7 @@ const walk = /* @__PURE__ */ __name(async (directory, tree = [], fallbackDir) =>
|
|
|
40
38
|
results.push(...await walk(filePath, [
|
|
41
39
|
...tree,
|
|
42
40
|
fileName
|
|
43
|
-
], fallbackDir));
|
|
41
|
+
], fallbackDir, hookPaths));
|
|
44
42
|
} else {
|
|
45
43
|
if (![
|
|
46
44
|
".js",
|
|
@@ -76,7 +74,8 @@ const walk = /* @__PURE__ */ __name(async (directory, tree = [], fallbackDir) =>
|
|
|
76
74
|
rootWalkDir = path.dirname(rootWalkDir);
|
|
77
75
|
}
|
|
78
76
|
const relHook = path.relative(rootWalkDir, hookPath);
|
|
79
|
-
const
|
|
77
|
+
const fallbackRoot = path.isAbsolute(fallbackDir) ? fallbackDir : path.join(process.cwd(), fallbackDir);
|
|
78
|
+
const targetDir = path.join(fallbackRoot, relHook);
|
|
80
79
|
targetFile = path.join(targetDir, "_hooks.js");
|
|
81
80
|
} else {
|
|
82
81
|
targetFile = path.join(hookPath, "_hooks.js");
|