bini-router 1.0.12 → 1.0.14
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 +9 -10
- package/dist/index.cjs +115 -61
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +115 -61
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/Readme.md
CHANGED
|
@@ -352,21 +352,20 @@ server/index.ts
|
|
|
352
352
|
|
|
353
353
|
### 🔺 Vercel
|
|
354
354
|
|
|
355
|
-
|
|
356
|
-
pnpm add @hono/vercel
|
|
357
|
-
```
|
|
355
|
+
No extra package needed — Vercel runs a Hono app as a direct default export.
|
|
358
356
|
|
|
359
357
|
`vite build` auto-generates `api/index.ts`:
|
|
360
358
|
|
|
361
359
|
```ts
|
|
362
360
|
// ⚠️ Auto-generated — do not edit. Add routes in src/app/api/ only.
|
|
363
|
-
import {
|
|
364
|
-
import _route0 from '
|
|
365
|
-
import _route1 from '
|
|
366
|
-
|
|
367
|
-
app
|
|
368
|
-
|
|
369
|
-
export
|
|
361
|
+
import { Hono } from 'hono';
|
|
362
|
+
import _route0 from '../src/app/api/test';
|
|
363
|
+
import _route1 from '../src/app/api/users';
|
|
364
|
+
const app = new Hono();
|
|
365
|
+
app.route('/', _route0);
|
|
366
|
+
app.route('/', _route1);
|
|
367
|
+
export const runtime = 'edge';
|
|
368
|
+
export default app;
|
|
370
369
|
```
|
|
371
370
|
|
|
372
371
|
Add `vercel.json`:
|
package/dist/index.cjs
CHANGED
|
@@ -544,62 +544,115 @@ function scanApiRoutes(dir, baseRoute = "") {
|
|
|
544
544
|
}
|
|
545
545
|
return routes;
|
|
546
546
|
}
|
|
547
|
-
|
|
548
|
-
const
|
|
549
|
-
const
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
});
|
|
547
|
+
function matchRoute(pattern, pathname) {
|
|
548
|
+
const patParts = pattern.split("/").filter(Boolean);
|
|
549
|
+
const urlParts = pathname.split("/").filter(Boolean);
|
|
550
|
+
const isCatchAll = patParts[patParts.length - 1] === "*";
|
|
551
|
+
if (isCatchAll) {
|
|
552
|
+
const prefix = patParts.slice(0, -1);
|
|
553
|
+
if (urlParts.length < prefix.length) return null;
|
|
554
|
+
for (let i = 0; i < prefix.length; i++) {
|
|
555
|
+
if (prefix[i].startsWith(":")) continue;
|
|
556
|
+
if (prefix[i] !== urlParts[i]) return null;
|
|
557
|
+
}
|
|
558
|
+
return { "*": urlParts.slice(prefix.length).join("/") };
|
|
559
|
+
}
|
|
560
|
+
if (patParts.length !== urlParts.length) return null;
|
|
561
|
+
const params = {};
|
|
562
|
+
for (let i = 0; i < patParts.length; i++) {
|
|
563
|
+
if (patParts[i].startsWith(":")) {
|
|
564
|
+
params[patParts[i].slice(1)] = decodeURIComponent(urlParts[i]);
|
|
565
|
+
} else if (patParts[i] !== urlParts[i]) {
|
|
566
|
+
return null;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
return params;
|
|
570
|
+
}
|
|
571
|
+
var moduleCache = /* @__PURE__ */ new Map();
|
|
572
|
+
async function importHandler(filePath) {
|
|
573
|
+
const { pathToFileURL } = await import("url");
|
|
574
|
+
let mtime = 0;
|
|
575
|
+
try {
|
|
576
|
+
mtime = import_fs.default.statSync(filePath).mtimeMs;
|
|
577
|
+
} catch {
|
|
579
578
|
}
|
|
580
|
-
|
|
579
|
+
const cached = moduleCache.get(filePath);
|
|
580
|
+
if (cached && cached.mtime === mtime) return cached.handler;
|
|
581
|
+
const mod = await import(pathToFileURL(filePath).href + "?t=" + mtime);
|
|
582
|
+
const handler = mod.default ?? null;
|
|
583
|
+
moduleCache.set(filePath, { mtime, handler });
|
|
584
|
+
return handler;
|
|
581
585
|
}
|
|
582
586
|
async function handleApiRequest(req, res, next, apiDir, enableCors, getCache, setCache) {
|
|
583
587
|
try {
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
+
if (enableCors && req.method === "OPTIONS") {
|
|
589
|
+
res.statusCode = 204;
|
|
590
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
591
|
+
res.setHeader("Access-Control-Allow-Methods", "GET,POST,PUT,PATCH,DELETE,OPTIONS");
|
|
592
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type,Authorization");
|
|
593
|
+
res.setHeader("Access-Control-Max-Age", "86400");
|
|
594
|
+
res.end();
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
let cache = getCache();
|
|
598
|
+
if (!cache) {
|
|
599
|
+
cache = { routes: scanApiRoutes(apiDir, "/api") };
|
|
600
|
+
setCache(cache);
|
|
588
601
|
}
|
|
589
602
|
const host = req.headers.host ?? "localhost";
|
|
590
|
-
const url = `http://${host}
|
|
603
|
+
const url = `http://${host}${req.url}`;
|
|
604
|
+
const pathname = new URL(url).pathname;
|
|
591
605
|
const chunks = [];
|
|
592
606
|
for await (const chunk of req) chunks.push(chunk);
|
|
593
607
|
const body = chunks.length > 0 ? Buffer.concat(chunks) : void 0;
|
|
608
|
+
const method = req.method.toUpperCase();
|
|
594
609
|
const webReq = new Request(url, {
|
|
595
|
-
method
|
|
610
|
+
method,
|
|
596
611
|
headers: req.headers,
|
|
597
|
-
body: body?.length ? body : void 0
|
|
612
|
+
body: !["GET", "HEAD"].includes(method) && body?.length ? body : void 0
|
|
598
613
|
});
|
|
599
|
-
const
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
614
|
+
for (const route of cache.routes) {
|
|
615
|
+
const handler = await importHandler(route.filePath);
|
|
616
|
+
if (!handler) continue;
|
|
617
|
+
let webRes;
|
|
618
|
+
try {
|
|
619
|
+
if (typeof handler.fetch === "function") {
|
|
620
|
+
webRes = await handler.fetch(webReq.clone());
|
|
621
|
+
if (webRes.status === 404) continue;
|
|
622
|
+
} else if (typeof handler === "function") {
|
|
623
|
+
const params = matchRoute(route.routePath, pathname);
|
|
624
|
+
if (params === null) continue;
|
|
625
|
+
const existingHeaders = {};
|
|
626
|
+
webReq.headers.forEach((v, k) => {
|
|
627
|
+
existingHeaders[k] = v;
|
|
628
|
+
});
|
|
629
|
+
const reqWithParams = new Request(webReq.clone(), {
|
|
630
|
+
headers: { ...existingHeaders, "x-bini-params": JSON.stringify(params) }
|
|
631
|
+
});
|
|
632
|
+
webRes = await handler(reqWithParams);
|
|
633
|
+
} else {
|
|
634
|
+
continue;
|
|
635
|
+
}
|
|
636
|
+
} catch {
|
|
637
|
+
continue;
|
|
638
|
+
}
|
|
639
|
+
const finalHeaders = {};
|
|
640
|
+
webRes.headers.forEach((v, k) => {
|
|
641
|
+
finalHeaders[k] = v;
|
|
642
|
+
});
|
|
643
|
+
if (enableCors) {
|
|
644
|
+
finalHeaders["access-control-allow-origin"] = "*";
|
|
645
|
+
finalHeaders["access-control-allow-methods"] = "GET,POST,PUT,PATCH,DELETE,OPTIONS";
|
|
646
|
+
finalHeaders["access-control-allow-headers"] = "Content-Type,Authorization";
|
|
647
|
+
}
|
|
648
|
+
res.statusCode = webRes.status;
|
|
649
|
+
for (const [k, v] of Object.entries(finalHeaders)) res.setHeader(k, v);
|
|
650
|
+
res.end(Buffer.from(await webRes.arrayBuffer()));
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
res.statusCode = 404;
|
|
654
|
+
res.setHeader("Content-Type", "application/json");
|
|
655
|
+
res.end(JSON.stringify({ error: `No API handler found for ${req.url}` }));
|
|
603
656
|
} catch (e) {
|
|
604
657
|
next(e);
|
|
605
658
|
}
|
|
@@ -647,13 +700,12 @@ function buildProductionEntry(srcApiDir, platform, enableCors) {
|
|
|
647
700
|
lines = [
|
|
648
701
|
...header,
|
|
649
702
|
`import { Hono } from 'hono';`,
|
|
650
|
-
`import { handle } from '@hono/vercel';`,
|
|
651
703
|
...corsImport ? [corsImport] : [],
|
|
652
704
|
...imports,
|
|
653
705
|
...appSetup,
|
|
654
706
|
``,
|
|
655
|
-
`export const
|
|
656
|
-
`export default
|
|
707
|
+
`export const runtime = 'edge';`,
|
|
708
|
+
`export default app;`
|
|
657
709
|
];
|
|
658
710
|
} else if (platform === "cloudflare") {
|
|
659
711
|
outFile = import_path.default.join(cwd, "worker.ts");
|
|
@@ -791,6 +843,7 @@ function biniroute(options = {}) {
|
|
|
791
843
|
},
|
|
792
844
|
buildEnd() {
|
|
793
845
|
honoCache = null;
|
|
846
|
+
moduleCache.clear();
|
|
794
847
|
if (debounceTimer) {
|
|
795
848
|
clearTimeout(debounceTimer);
|
|
796
849
|
debounceTimer = null;
|
|
@@ -823,16 +876,17 @@ function biniroute(options = {}) {
|
|
|
823
876
|
});
|
|
824
877
|
if (import_fs.default.existsSync(apiDir)) {
|
|
825
878
|
server.watcher.add(apiDir);
|
|
826
|
-
const resetApi = () => {
|
|
879
|
+
const resetApi = (f) => {
|
|
827
880
|
honoCache = null;
|
|
881
|
+
if (f) moduleCache.delete(f);
|
|
828
882
|
server.ws.send({ type: "full-reload", path: "*" });
|
|
829
883
|
};
|
|
830
|
-
server.watcher.on("add", (f) => isApiFile(f) && resetApi());
|
|
831
|
-
server.watcher.on("unlink", (f) => isApiFile(f) && resetApi());
|
|
832
|
-
server.watcher.on("change", (f) => isApiFile(f) && resetApi());
|
|
833
|
-
server.middlewares.use(
|
|
834
|
-
"/api"
|
|
835
|
-
|
|
884
|
+
server.watcher.on("add", (f) => isApiFile(f) && resetApi(f));
|
|
885
|
+
server.watcher.on("unlink", (f) => isApiFile(f) && resetApi(f));
|
|
886
|
+
server.watcher.on("change", (f) => isApiFile(f) && resetApi(f));
|
|
887
|
+
server.middlewares.use((req, res, next) => {
|
|
888
|
+
if (!req.url?.startsWith("/api")) return next();
|
|
889
|
+
handleApiRequest(
|
|
836
890
|
req,
|
|
837
891
|
res,
|
|
838
892
|
next,
|
|
@@ -842,17 +896,17 @@ function biniroute(options = {}) {
|
|
|
842
896
|
(v) => {
|
|
843
897
|
honoCache = v;
|
|
844
898
|
}
|
|
845
|
-
)
|
|
846
|
-
);
|
|
899
|
+
);
|
|
900
|
+
});
|
|
847
901
|
}
|
|
848
902
|
},
|
|
849
903
|
async configurePreviewServer(server) {
|
|
850
904
|
addSpaFallback(server);
|
|
851
905
|
const apiDir = getApiDir();
|
|
852
906
|
if (!import_fs.default.existsSync(apiDir)) return;
|
|
853
|
-
server.middlewares.use(
|
|
854
|
-
"/api"
|
|
855
|
-
|
|
907
|
+
server.middlewares.use((req, res, next) => {
|
|
908
|
+
if (!req.url?.startsWith("/api")) return next();
|
|
909
|
+
handleApiRequest(
|
|
856
910
|
req,
|
|
857
911
|
res,
|
|
858
912
|
next,
|
|
@@ -862,8 +916,8 @@ function biniroute(options = {}) {
|
|
|
862
916
|
(v) => {
|
|
863
917
|
honoCache = v;
|
|
864
918
|
}
|
|
865
|
-
)
|
|
866
|
-
);
|
|
919
|
+
);
|
|
920
|
+
});
|
|
867
921
|
},
|
|
868
922
|
transformIndexHtml: {
|
|
869
923
|
order: "pre",
|