weifuwu 0.2.3 → 0.2.4
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 +34 -0
- package/dist/index.js +87 -21
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -407,6 +407,40 @@ const app = new Router()
|
|
|
407
407
|
serve(app.handler(), { port: 3000 })
|
|
408
408
|
```
|
|
409
409
|
|
|
410
|
+
## Graceful shutdown
|
|
411
|
+
|
|
412
|
+
```ts
|
|
413
|
+
import { serve } from 'weifuwu'
|
|
414
|
+
import type { Server } from 'weifuwu'
|
|
415
|
+
|
|
416
|
+
const ac = new AbortController()
|
|
417
|
+
let server: Server
|
|
418
|
+
|
|
419
|
+
process.on('SIGTERM', () => {
|
|
420
|
+
console.log('shutting down…')
|
|
421
|
+
ac.abort()
|
|
422
|
+
server.stop()
|
|
423
|
+
})
|
|
424
|
+
|
|
425
|
+
server = serve((req, ctx) => new Response('Hello'), {
|
|
426
|
+
port: 3000,
|
|
427
|
+
signal: ac.signal,
|
|
428
|
+
})
|
|
429
|
+
await server.ready
|
|
430
|
+
console.log(`listening on :${server.port}`)
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### Using with WebSocket
|
|
434
|
+
|
|
435
|
+
```ts
|
|
436
|
+
const app = new Router().ws('/chat', { … })
|
|
437
|
+
const server = serve(app.handler(), {
|
|
438
|
+
port: 3000,
|
|
439
|
+
signal: ac.signal,
|
|
440
|
+
websocket: app.websocketHandler(),
|
|
441
|
+
})
|
|
442
|
+
```
|
|
443
|
+
|
|
410
444
|
## Error handling
|
|
411
445
|
|
|
412
446
|
```ts
|
package/dist/index.js
CHANGED
|
@@ -365,7 +365,7 @@ var Router = class _Router {
|
|
|
365
365
|
for (let i = 0; i < segments.length; i++) {
|
|
366
366
|
pathMws.push(...node.pathMws);
|
|
367
367
|
if (node.wildcard) {
|
|
368
|
-
const h = node.handlers.get(
|
|
368
|
+
const h = node.handlers.get("*") || node.handlers.get(method);
|
|
369
369
|
if (h) {
|
|
370
370
|
wildcardHandler = h;
|
|
371
371
|
wildcardMws = node.middlewares.get(method) || node.middlewares.get("*") || [];
|
|
@@ -676,6 +676,20 @@ function scanPages(dir) {
|
|
|
676
676
|
layouts,
|
|
677
677
|
routePath: rPath
|
|
678
678
|
});
|
|
679
|
+
} else {
|
|
680
|
+
const rPath = join(current, "route.ts");
|
|
681
|
+
if (existsSync(rPath)) {
|
|
682
|
+
let relPath = relative(dir, rPath).replace(sep, "/");
|
|
683
|
+
relPath = relPath.replace(/\/route\.tsx?$/, "");
|
|
684
|
+
const route = filePathToRoute(relPath);
|
|
685
|
+
pages.push({
|
|
686
|
+
route,
|
|
687
|
+
entryPath: "",
|
|
688
|
+
layouts: [],
|
|
689
|
+
routePath: rPath,
|
|
690
|
+
routeOnly: true
|
|
691
|
+
});
|
|
692
|
+
}
|
|
679
693
|
}
|
|
680
694
|
for (const d of dirs) walk(d);
|
|
681
695
|
}
|
|
@@ -821,26 +835,37 @@ ${scripts.join("\n")}`;
|
|
|
821
835
|
async function tsx(options) {
|
|
822
836
|
const pagesDir = resolve(options.dir);
|
|
823
837
|
const outDir = join(pagesDir, "..", ".weifuwu", "ssr");
|
|
824
|
-
const clientDir = join(pagesDir, "..", ".weifuwu", "client");
|
|
825
838
|
const pages = scanPages(pagesDir);
|
|
826
839
|
if (pages.length === 0) return new Router();
|
|
827
840
|
const allFiles = /* @__PURE__ */ new Set();
|
|
828
|
-
const loadMap = /* @__PURE__ */ new Map();
|
|
829
|
-
const layoutMap = /* @__PURE__ */ new Map();
|
|
830
841
|
for (const p of pages) {
|
|
831
|
-
allFiles.add(p.entryPath);
|
|
832
|
-
if (p.loadPath)
|
|
833
|
-
allFiles.add(p.loadPath);
|
|
834
|
-
loadMap.set(p.entryPath, p.loadPath);
|
|
835
|
-
}
|
|
842
|
+
if (p.entryPath) allFiles.add(p.entryPath);
|
|
843
|
+
if (p.loadPath) allFiles.add(p.loadPath);
|
|
836
844
|
for (const lp of p.layouts) allFiles.add(lp);
|
|
837
|
-
layoutMap.set(p.entryPath, [...p.layouts]);
|
|
838
845
|
if (p.routePath) allFiles.add(p.routePath);
|
|
839
846
|
}
|
|
847
|
+
const nfPath = join(pagesDir, "not-found.tsx");
|
|
848
|
+
const hasNotFound = existsSync(nfPath);
|
|
849
|
+
if (hasNotFound) {
|
|
850
|
+
allFiles.add(nfPath);
|
|
851
|
+
const rootLayouts = resolveLayouts(pagesDir, pagesDir);
|
|
852
|
+
for (const lp of rootLayouts) allFiles.add(lp);
|
|
853
|
+
}
|
|
840
854
|
mkdirSync(outDir, { recursive: true });
|
|
841
855
|
await compileAll([...allFiles], outDir, "node");
|
|
842
856
|
const router = new Router();
|
|
843
857
|
for (const p of pages) {
|
|
858
|
+
if (p.routeOnly && p.routePath) {
|
|
859
|
+
const rUrl = compiledUrl(p.routePath, outDir);
|
|
860
|
+
const modR = await import(rUrl);
|
|
861
|
+
const methods = ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"];
|
|
862
|
+
for (const method of methods) {
|
|
863
|
+
if (modR[method]) {
|
|
864
|
+
router.route(method, p.route, modR[method]);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
continue;
|
|
868
|
+
}
|
|
844
869
|
const url = compiledUrl(p.entryPath, outDir);
|
|
845
870
|
const mod = await import(url);
|
|
846
871
|
const Component = mod.default;
|
|
@@ -877,6 +902,36 @@ async function tsx(options) {
|
|
|
877
902
|
}
|
|
878
903
|
}
|
|
879
904
|
}
|
|
905
|
+
if (hasNotFound) {
|
|
906
|
+
const nfUrl = compiledUrl(nfPath, outDir);
|
|
907
|
+
const modNf = await import(nfUrl);
|
|
908
|
+
const NfComponent = modNf.default;
|
|
909
|
+
const nfLayouts = [];
|
|
910
|
+
const rootLayouts = resolveLayouts(pagesDir, pagesDir);
|
|
911
|
+
for (const lp of rootLayouts) {
|
|
912
|
+
const lUrl = compiledUrl(lp, outDir);
|
|
913
|
+
const modL = await import(lUrl);
|
|
914
|
+
nfLayouts.push(modL.default);
|
|
915
|
+
}
|
|
916
|
+
const handler = async (req, ctx) => {
|
|
917
|
+
let element = createElement(NfComponent, { params: ctx.params, query: ctx.query });
|
|
918
|
+
for (let i = nfLayouts.length - 1; i >= 0; i--) {
|
|
919
|
+
element = createElement(nfLayouts[i], { children: element });
|
|
920
|
+
}
|
|
921
|
+
element = createElement(TsxContext.Provider, {
|
|
922
|
+
value: { params: ctx.params, query: ctx.query, user: ctx.user, parsed: ctx.parsed }
|
|
923
|
+
}, element);
|
|
924
|
+
const stream = await renderToReadableStream(element);
|
|
925
|
+
const body = await readStream(stream);
|
|
926
|
+
const html = `<!DOCTYPE html>
|
|
927
|
+
${body}`;
|
|
928
|
+
return new Response(html, {
|
|
929
|
+
status: 404,
|
|
930
|
+
headers: { "content-type": "text/html; charset=utf-8" }
|
|
931
|
+
});
|
|
932
|
+
};
|
|
933
|
+
router.all("/*", handler);
|
|
934
|
+
}
|
|
880
935
|
return router;
|
|
881
936
|
}
|
|
882
937
|
|
|
@@ -941,25 +996,36 @@ function cors(options) {
|
|
|
941
996
|
function auth(options) {
|
|
942
997
|
return async (req, ctx, next) => {
|
|
943
998
|
const headerName = options.header ?? "Authorization";
|
|
944
|
-
|
|
945
|
-
|
|
999
|
+
let from = "header";
|
|
1000
|
+
let header = req.headers.get(headerName);
|
|
1001
|
+
let token = "";
|
|
1002
|
+
if (header) {
|
|
1003
|
+
token = header;
|
|
1004
|
+
if (headerName.toLowerCase() === "authorization") {
|
|
1005
|
+
const parts = header.split(" ");
|
|
1006
|
+
if (parts[0]?.toLowerCase() === "bearer") {
|
|
1007
|
+
token = parts.slice(1).join(" ");
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
} else {
|
|
1011
|
+
const url = new URL(req.url);
|
|
1012
|
+
const qsToken = url.searchParams.get("access_token");
|
|
1013
|
+
if (qsToken) {
|
|
1014
|
+
token = qsToken;
|
|
1015
|
+
from = "query";
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
if (!token) {
|
|
946
1019
|
return new Response("Unauthorized", {
|
|
947
1020
|
status: 401,
|
|
948
1021
|
headers: headerName.toLowerCase() === "authorization" ? { "WWW-Authenticate": "Bearer" } : void 0
|
|
949
1022
|
});
|
|
950
1023
|
}
|
|
951
|
-
let token = header;
|
|
952
|
-
if (headerName.toLowerCase() === "authorization") {
|
|
953
|
-
const parts = header.split(" ");
|
|
954
|
-
if (parts[0]?.toLowerCase() === "bearer") {
|
|
955
|
-
token = parts.slice(1).join(" ");
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
1024
|
if (options.proxy) {
|
|
959
1025
|
const proxyUrl = typeof options.proxy === "string" ? new URL(options.proxy) : options.proxy;
|
|
960
1026
|
const proxyHeaders = {};
|
|
961
|
-
if (
|
|
962
|
-
proxyHeaders[
|
|
1027
|
+
if (from === "header" && header) {
|
|
1028
|
+
proxyHeaders[headerName] = header;
|
|
963
1029
|
} else {
|
|
964
1030
|
proxyUrl.searchParams.set("access_token", token);
|
|
965
1031
|
}
|