alabjs 0.1.0
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/dist/adapters/cloudflare.d.ts +31 -0
- package/dist/adapters/cloudflare.d.ts.map +1 -0
- package/dist/adapters/cloudflare.js +30 -0
- package/dist/adapters/cloudflare.js.map +1 -0
- package/dist/adapters/deno.d.ts +22 -0
- package/dist/adapters/deno.d.ts.map +1 -0
- package/dist/adapters/deno.js +21 -0
- package/dist/adapters/deno.js.map +1 -0
- package/dist/adapters/web.d.ts +47 -0
- package/dist/adapters/web.d.ts.map +1 -0
- package/dist/adapters/web.js +212 -0
- package/dist/adapters/web.js.map +1 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +61 -0
- package/dist/cli.js.map +1 -0
- package/dist/client/hooks.d.ts +119 -0
- package/dist/client/hooks.d.ts.map +1 -0
- package/dist/client/hooks.js +220 -0
- package/dist/client/hooks.js.map +1 -0
- package/dist/client/hooks.test.d.ts +2 -0
- package/dist/client/hooks.test.d.ts.map +1 -0
- package/dist/client/hooks.test.js +45 -0
- package/dist/client/hooks.test.js.map +1 -0
- package/dist/client/index.d.ts +6 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +4 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/offline.d.ts +52 -0
- package/dist/client/offline.d.ts.map +1 -0
- package/dist/client/offline.js +90 -0
- package/dist/client/offline.js.map +1 -0
- package/dist/client/provider.d.ts +12 -0
- package/dist/client/provider.d.ts.map +1 -0
- package/dist/client/provider.js +10 -0
- package/dist/client/provider.js.map +1 -0
- package/dist/commands/build.d.ts +18 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +173 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/dev.d.ts +8 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +447 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/info.d.ts +6 -0
- package/dist/commands/info.d.ts.map +1 -0
- package/dist/commands/info.js +92 -0
- package/dist/commands/info.js.map +1 -0
- package/dist/commands/ssg.d.ts +8 -0
- package/dist/commands/ssg.d.ts.map +1 -0
- package/dist/commands/ssg.js +124 -0
- package/dist/commands/ssg.js.map +1 -0
- package/dist/commands/start.d.ts +7 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +26 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/test.d.ts +24 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +87 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/components/ErrorBoundary.d.ts +38 -0
- package/dist/components/ErrorBoundary.d.ts.map +1 -0
- package/dist/components/ErrorBoundary.js +46 -0
- package/dist/components/ErrorBoundary.js.map +1 -0
- package/dist/components/Font.d.ts +57 -0
- package/dist/components/Font.d.ts.map +1 -0
- package/dist/components/Font.js +33 -0
- package/dist/components/Font.js.map +1 -0
- package/dist/components/Image.d.ts +74 -0
- package/dist/components/Image.d.ts.map +1 -0
- package/dist/components/Image.js +85 -0
- package/dist/components/Image.js.map +1 -0
- package/dist/components/Link.d.ts +23 -0
- package/dist/components/Link.d.ts.map +1 -0
- package/dist/components/Link.js +48 -0
- package/dist/components/Link.js.map +1 -0
- package/dist/components/Script.d.ts +37 -0
- package/dist/components/Script.d.ts.map +1 -0
- package/dist/components/Script.js +70 -0
- package/dist/components/Script.js.map +1 -0
- package/dist/components/index.d.ts +10 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +6 -0
- package/dist/components/index.js.map +1 -0
- package/dist/i18n/i18n.test.d.ts +2 -0
- package/dist/i18n/i18n.test.d.ts.map +1 -0
- package/dist/i18n/i18n.test.js +132 -0
- package/dist/i18n/i18n.test.js.map +1 -0
- package/dist/i18n/index.d.ts +135 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +189 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/router/code-router.d.ts +204 -0
- package/dist/router/code-router.d.ts.map +1 -0
- package/dist/router/code-router.js +258 -0
- package/dist/router/code-router.js.map +1 -0
- package/dist/router/code-router.test.d.ts +2 -0
- package/dist/router/code-router.test.d.ts.map +1 -0
- package/dist/router/code-router.test.js +128 -0
- package/dist/router/code-router.test.js.map +1 -0
- package/dist/router/index.d.ts +4 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/router/index.js +2 -0
- package/dist/router/index.js.map +1 -0
- package/dist/router/manifest.d.ts +12 -0
- package/dist/router/manifest.d.ts.map +1 -0
- package/dist/router/manifest.js +2 -0
- package/dist/router/manifest.js.map +1 -0
- package/dist/server/app.d.ts +13 -0
- package/dist/server/app.d.ts.map +1 -0
- package/dist/server/app.js +407 -0
- package/dist/server/app.js.map +1 -0
- package/dist/server/cache.d.ts +99 -0
- package/dist/server/cache.d.ts.map +1 -0
- package/dist/server/cache.js +161 -0
- package/dist/server/cache.js.map +1 -0
- package/dist/server/cache.test.d.ts +2 -0
- package/dist/server/cache.test.d.ts.map +1 -0
- package/dist/server/cache.test.js +150 -0
- package/dist/server/cache.test.js.map +1 -0
- package/dist/server/csrf.d.ts +28 -0
- package/dist/server/csrf.d.ts.map +1 -0
- package/dist/server/csrf.js +66 -0
- package/dist/server/csrf.js.map +1 -0
- package/dist/server/csrf.test.d.ts +2 -0
- package/dist/server/csrf.test.d.ts.map +1 -0
- package/dist/server/csrf.test.js +154 -0
- package/dist/server/csrf.test.js.map +1 -0
- package/dist/server/image.d.ts +18 -0
- package/dist/server/image.d.ts.map +1 -0
- package/dist/server/image.js +97 -0
- package/dist/server/image.js.map +1 -0
- package/dist/server/index.d.ts +57 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +58 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/middleware.d.ts +53 -0
- package/dist/server/middleware.d.ts.map +1 -0
- package/dist/server/middleware.js +80 -0
- package/dist/server/middleware.js.map +1 -0
- package/dist/server/middleware.test.d.ts +2 -0
- package/dist/server/middleware.test.d.ts.map +1 -0
- package/dist/server/middleware.test.js +125 -0
- package/dist/server/middleware.test.js.map +1 -0
- package/dist/server/revalidate.d.ts +49 -0
- package/dist/server/revalidate.d.ts.map +1 -0
- package/dist/server/revalidate.js +62 -0
- package/dist/server/revalidate.js.map +1 -0
- package/dist/server/revalidate.test.d.ts +2 -0
- package/dist/server/revalidate.test.d.ts.map +1 -0
- package/dist/server/revalidate.test.js +93 -0
- package/dist/server/revalidate.test.js.map +1 -0
- package/dist/server/server-fn.test.d.ts +2 -0
- package/dist/server/server-fn.test.d.ts.map +1 -0
- package/dist/server/server-fn.test.js +105 -0
- package/dist/server/server-fn.test.js.map +1 -0
- package/dist/server/sitemap.d.ts +9 -0
- package/dist/server/sitemap.d.ts.map +1 -0
- package/dist/server/sitemap.js +26 -0
- package/dist/server/sitemap.js.map +1 -0
- package/dist/server/sitemap.test.d.ts +2 -0
- package/dist/server/sitemap.test.d.ts.map +1 -0
- package/dist/server/sitemap.test.js +61 -0
- package/dist/server/sitemap.test.js.map +1 -0
- package/dist/server/sse.d.ts +59 -0
- package/dist/server/sse.d.ts.map +1 -0
- package/dist/server/sse.js +91 -0
- package/dist/server/sse.js.map +1 -0
- package/dist/server/sse.test.d.ts +2 -0
- package/dist/server/sse.test.d.ts.map +1 -0
- package/dist/server/sse.test.js +68 -0
- package/dist/server/sse.test.js.map +1 -0
- package/dist/signals/index.d.ts +101 -0
- package/dist/signals/index.d.ts.map +1 -0
- package/dist/signals/index.js +149 -0
- package/dist/signals/index.js.map +1 -0
- package/dist/signals/signals.test.d.ts +2 -0
- package/dist/signals/signals.test.d.ts.map +1 -0
- package/dist/signals/signals.test.js +146 -0
- package/dist/signals/signals.test.js.map +1 -0
- package/dist/ssr/html.d.ts +27 -0
- package/dist/ssr/html.d.ts.map +1 -0
- package/dist/ssr/html.js +107 -0
- package/dist/ssr/html.js.map +1 -0
- package/dist/ssr/html.test.d.ts +2 -0
- package/dist/ssr/html.test.d.ts.map +1 -0
- package/dist/ssr/html.test.js +178 -0
- package/dist/ssr/html.test.js.map +1 -0
- package/dist/ssr/render.d.ts +46 -0
- package/dist/ssr/render.d.ts.map +1 -0
- package/dist/ssr/render.js +87 -0
- package/dist/ssr/render.js.map +1 -0
- package/dist/ssr/router-dev.d.ts +60 -0
- package/dist/ssr/router-dev.d.ts.map +1 -0
- package/dist/ssr/router-dev.js +205 -0
- package/dist/ssr/router-dev.js.map +1 -0
- package/dist/ssr/router-dev.test.d.ts +2 -0
- package/dist/ssr/router-dev.test.d.ts.map +1 -0
- package/dist/ssr/router-dev.test.js +189 -0
- package/dist/ssr/router-dev.test.js.map +1 -0
- package/dist/test/index.d.ts +93 -0
- package/dist/test/index.d.ts.map +1 -0
- package/dist/test/index.js +146 -0
- package/dist/test/index.js.map +1 -0
- package/dist/types/index.d.ts +117 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/napi.d.ts +15 -0
- package/dist/types/napi.d.ts.map +1 -0
- package/dist/types/napi.js +2 -0
- package/dist/types/napi.js.map +1 -0
- package/package.json +107 -0
- package/src/adapters/cloudflare.ts +30 -0
- package/src/adapters/deno.ts +21 -0
- package/src/adapters/web.ts +259 -0
- package/src/cli.ts +68 -0
- package/src/client/hooks.test.ts +54 -0
- package/src/client/hooks.ts +329 -0
- package/src/client/index.ts +5 -0
- package/src/client/offline-sw.ts +191 -0
- package/src/client/offline.ts +114 -0
- package/src/client/provider.tsx +14 -0
- package/src/commands/build.ts +201 -0
- package/src/commands/dev.ts +509 -0
- package/src/commands/info.ts +111 -0
- package/src/commands/ssg.ts +177 -0
- package/src/commands/start.ts +32 -0
- package/src/commands/test.ts +102 -0
- package/src/components/ErrorBoundary.tsx +73 -0
- package/src/components/Font.tsx +100 -0
- package/src/components/Image.tsx +141 -0
- package/src/components/Link.tsx +64 -0
- package/src/components/Script.tsx +97 -0
- package/src/components/index.ts +9 -0
- package/src/i18n/i18n.test.tsx +169 -0
- package/src/i18n/index.tsx +256 -0
- package/src/index.ts +10 -0
- package/src/router/code-router.test.ts +146 -0
- package/src/router/code-router.tsx +459 -0
- package/src/router/index.ts +18 -0
- package/src/router/manifest.ts +13 -0
- package/src/server/app.ts +466 -0
- package/src/server/cache.test.ts +192 -0
- package/src/server/cache.ts +195 -0
- package/src/server/csrf.test.ts +199 -0
- package/src/server/csrf.ts +80 -0
- package/src/server/image.ts +112 -0
- package/src/server/index.ts +144 -0
- package/src/server/middleware.test.ts +151 -0
- package/src/server/middleware.ts +95 -0
- package/src/server/revalidate.test.ts +106 -0
- package/src/server/revalidate.ts +75 -0
- package/src/server/server-fn.test.ts +127 -0
- package/src/server/sitemap.test.ts +68 -0
- package/src/server/sitemap.ts +30 -0
- package/src/server/sse.test.ts +81 -0
- package/src/server/sse.ts +110 -0
- package/src/signals/index.ts +177 -0
- package/src/signals/signals.test.ts +164 -0
- package/src/ssr/html.test.ts +200 -0
- package/src/ssr/html.ts +140 -0
- package/src/ssr/render.ts +144 -0
- package/src/ssr/router-dev.test.ts +230 -0
- package/src/ssr/router-dev.ts +229 -0
- package/src/test/index.ts +206 -0
- package/src/types/compiler.d.ts +25 -0
- package/src/types/index.ts +147 -0
- package/src/types/napi.ts +20 -0
- package/src/types/plugins.d.ts +3 -0
- package/tsconfig.json +11 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/vitest.config.ts +32 -0
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
import { createApp as createH3App, createRouter, defineEventHandler, getQuery, readBody } from "h3";
|
|
2
|
+
import { createServer } from "node:http";
|
|
3
|
+
import { resolve, dirname, join, extname } from "node:path";
|
|
4
|
+
import { existsSync, createReadStream, statSync } from "node:fs";
|
|
5
|
+
import { toNodeListener } from "h3";
|
|
6
|
+
import { renderToResponse } from "../ssr/render.js";
|
|
7
|
+
import { generateSitemap } from "./sitemap.js";
|
|
8
|
+
import { csrfMiddleware, setCsrfCookie } from "./csrf.js";
|
|
9
|
+
import { handleImageRequest } from "./image.js";
|
|
10
|
+
import { runMiddleware } from "./middleware.js";
|
|
11
|
+
import { checkRevalidateAuth, applyRevalidate } from "./revalidate.js";
|
|
12
|
+
/**
|
|
13
|
+
* Find layout file paths (relative to cwd root) for a given route.file, ordered outermost→innermost.
|
|
14
|
+
* Checks the compiled dist directory for the existence of each layout.
|
|
15
|
+
*/
|
|
16
|
+
function findProdLayoutFiles(routeFile, distDir) {
|
|
17
|
+
// routeFile is like "app/users/[id]/page.tsx"
|
|
18
|
+
const pageDir = dirname(routeFile);
|
|
19
|
+
const parts = pageDir.split("/");
|
|
20
|
+
const layouts = [];
|
|
21
|
+
for (let i = 1; i <= parts.length; i++) {
|
|
22
|
+
const dir = parts.slice(0, i).join("/");
|
|
23
|
+
const layoutRelPath = `${dir}/layout.tsx`;
|
|
24
|
+
if (existsSync(join(distDir, "server", layoutRelPath))) {
|
|
25
|
+
layouts.push(layoutRelPath);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return layouts;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Find nearest error.tsx for a given route.file, searching innermost→outermost.
|
|
32
|
+
*/
|
|
33
|
+
function findProdErrorFile(routeFile, distDir) {
|
|
34
|
+
let dir = dirname(routeFile);
|
|
35
|
+
while (dir.length > 0 && dir !== ".") {
|
|
36
|
+
const candidate = `${dir}/error.tsx`;
|
|
37
|
+
if (existsSync(join(distDir, "server", candidate)))
|
|
38
|
+
return candidate;
|
|
39
|
+
const parent = dirname(dir);
|
|
40
|
+
if (parent === dir)
|
|
41
|
+
break;
|
|
42
|
+
dir = parent;
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
function findProdLoadingFile(routeFile, distDir) {
|
|
47
|
+
let dir = dirname(routeFile);
|
|
48
|
+
while (dir.length > 0 && dir !== ".") {
|
|
49
|
+
const candidate = `${dir}/loading.tsx`;
|
|
50
|
+
if (existsSync(join(distDir, "server", candidate)))
|
|
51
|
+
return candidate;
|
|
52
|
+
const parent = dirname(dir);
|
|
53
|
+
if (parent === dir)
|
|
54
|
+
break;
|
|
55
|
+
dir = parent;
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Create and return an Alab HTTP application backed by H3.
|
|
61
|
+
*
|
|
62
|
+
* In production (`alab start`), this is the entry point.
|
|
63
|
+
* In development, Vite's dev server wraps the SSR logic directly via the
|
|
64
|
+
* dev command middleware — this function is not used in dev.
|
|
65
|
+
*/
|
|
66
|
+
export function createApp(manifest, distDir) {
|
|
67
|
+
const app = createH3App();
|
|
68
|
+
const router = createRouter();
|
|
69
|
+
const publicDir = resolve(distDir, "../../public");
|
|
70
|
+
// ─── Global middleware ───────────────────────────────────────────────────────
|
|
71
|
+
app.use(defineEventHandler((event) => {
|
|
72
|
+
const res = event.node.res;
|
|
73
|
+
res.setHeader("x-content-type-options", "nosniff");
|
|
74
|
+
res.setHeader("x-frame-options", "SAMEORIGIN");
|
|
75
|
+
res.setHeader("referrer-policy", "strict-origin-when-cross-origin");
|
|
76
|
+
res.setHeader("permissions-policy", "camera=(), microphone=(), geolocation=()");
|
|
77
|
+
res.setHeader("x-permitted-cross-domain-policies", "none");
|
|
78
|
+
// HSTS — only meaningful over HTTPS; set in production only.
|
|
79
|
+
res.setHeader("strict-transport-security", "max-age=31536000; includeSubDomains");
|
|
80
|
+
}));
|
|
81
|
+
// ─── User middleware (middleware.ts compiled to dist/server/middleware.ts) ───
|
|
82
|
+
const middlewareModulePath = `${distDir}/server/middleware.ts`;
|
|
83
|
+
if (existsSync(middlewareModulePath)) {
|
|
84
|
+
app.use(defineEventHandler(async (event) => {
|
|
85
|
+
const mod = await import(middlewareModulePath);
|
|
86
|
+
if (typeof mod.middleware !== "function")
|
|
87
|
+
return;
|
|
88
|
+
const req = event.node.req;
|
|
89
|
+
const res = event.node.res;
|
|
90
|
+
const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
|
|
91
|
+
const webReq = new Request(url.toString(), {
|
|
92
|
+
method: req.method ?? "GET",
|
|
93
|
+
headers: req.headers,
|
|
94
|
+
});
|
|
95
|
+
const middlewareRes = await runMiddleware(mod, webReq);
|
|
96
|
+
if (middlewareRes) {
|
|
97
|
+
res.statusCode = middlewareRes.status;
|
|
98
|
+
middlewareRes.headers.forEach((v, k) => res.setHeader(k, v));
|
|
99
|
+
res.end(Buffer.from(await middlewareRes.arrayBuffer()));
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
return undefined;
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
// CSRF protection (active in production, skipped in dev)
|
|
106
|
+
app.use(csrfMiddleware());
|
|
107
|
+
// ─── Static file serving ────────────────────────────────────────────────────
|
|
108
|
+
// Serves built client assets (JS/CSS from `.alabjs/dist/client/`) and files
|
|
109
|
+
// from the project's `public/` directory. Dynamic alab routes take priority
|
|
110
|
+
// via the router registered below; this handler only fires for real files.
|
|
111
|
+
const clientDir = resolve(distDir, "client");
|
|
112
|
+
const MIME_TYPES = {
|
|
113
|
+
".js": "application/javascript; charset=utf-8",
|
|
114
|
+
".mjs": "application/javascript; charset=utf-8",
|
|
115
|
+
".css": "text/css; charset=utf-8",
|
|
116
|
+
".html": "text/html; charset=utf-8",
|
|
117
|
+
".json": "application/json; charset=utf-8",
|
|
118
|
+
".svg": "image/svg+xml",
|
|
119
|
+
".png": "image/png",
|
|
120
|
+
".jpg": "image/jpeg",
|
|
121
|
+
".jpeg": "image/jpeg",
|
|
122
|
+
".gif": "image/gif",
|
|
123
|
+
".webp": "image/webp",
|
|
124
|
+
".ico": "image/x-icon",
|
|
125
|
+
".woff": "font/woff",
|
|
126
|
+
".woff2": "font/woff2",
|
|
127
|
+
".ttf": "font/ttf",
|
|
128
|
+
".txt": "text/plain; charset=utf-8",
|
|
129
|
+
".xml": "application/xml; charset=utf-8",
|
|
130
|
+
".map": "application/json; charset=utf-8",
|
|
131
|
+
};
|
|
132
|
+
app.use(defineEventHandler((event) => {
|
|
133
|
+
const req = event.node.req;
|
|
134
|
+
const res = event.node.res;
|
|
135
|
+
if (req.method !== "GET" && req.method !== "HEAD")
|
|
136
|
+
return;
|
|
137
|
+
const rawPath = (req.url ?? "/").split("?")[0] ?? "/";
|
|
138
|
+
// Decode and strip traversal attempts
|
|
139
|
+
let relPath;
|
|
140
|
+
try {
|
|
141
|
+
relPath = decodeURIComponent(rawPath);
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (relPath.includes(".."))
|
|
147
|
+
return;
|
|
148
|
+
const ext = extname(relPath).toLowerCase();
|
|
149
|
+
const contentType = MIME_TYPES[ext];
|
|
150
|
+
if (!contentType)
|
|
151
|
+
return; // skip extensionless paths (page routes)
|
|
152
|
+
// 1. Built client assets (JS chunks, CSS, source maps)
|
|
153
|
+
const clientCandidate = join(clientDir, relPath);
|
|
154
|
+
if (existsSync(clientCandidate)) {
|
|
155
|
+
const stat = statSync(clientCandidate);
|
|
156
|
+
if (stat.isFile()) {
|
|
157
|
+
res.setHeader("content-type", contentType);
|
|
158
|
+
res.setHeader("content-length", stat.size);
|
|
159
|
+
// Immutable cache for hashed assets; short TTL for others
|
|
160
|
+
const isHashed = /\.[a-f0-9]{8,}\.[a-z]+$/.test(relPath);
|
|
161
|
+
res.setHeader("cache-control", isHashed
|
|
162
|
+
? "public, max-age=31536000, immutable"
|
|
163
|
+
: "public, max-age=3600");
|
|
164
|
+
if (req.method === "HEAD") {
|
|
165
|
+
res.end();
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
createReadStream(clientCandidate).pipe(res);
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// 2. Public directory (favicons, fonts, open-graph images, etc.)
|
|
173
|
+
const publicCandidate = join(publicDir, relPath);
|
|
174
|
+
if (existsSync(publicCandidate)) {
|
|
175
|
+
const stat = statSync(publicCandidate);
|
|
176
|
+
if (stat.isFile()) {
|
|
177
|
+
res.setHeader("content-type", contentType);
|
|
178
|
+
res.setHeader("content-length", stat.size);
|
|
179
|
+
res.setHeader("cache-control", "public, max-age=3600");
|
|
180
|
+
if (req.method === "HEAD") {
|
|
181
|
+
res.end();
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
createReadStream(publicCandidate).pipe(res);
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return undefined;
|
|
189
|
+
}));
|
|
190
|
+
// ─── Built-in routes ────────────────────────────────────────────────────────
|
|
191
|
+
// Rust-powered image optimisation — resize + JPEG encode via `alab-napi`
|
|
192
|
+
router.get("/_alabjs/image", defineEventHandler((event) => {
|
|
193
|
+
return handleImageRequest(event.node.req, event.node.res, publicDir);
|
|
194
|
+
}));
|
|
195
|
+
// On-demand ISR revalidation
|
|
196
|
+
router.post("/_alabjs/revalidate", defineEventHandler(async (event) => {
|
|
197
|
+
const res = event.node.res;
|
|
198
|
+
res.setHeader("content-type", "application/json");
|
|
199
|
+
if (!checkRevalidateAuth(event.node.req.headers["authorization"])) {
|
|
200
|
+
res.statusCode = 401;
|
|
201
|
+
return JSON.stringify({ error: "Unauthorized. Set Authorization: Bearer <ALAB_REVALIDATE_SECRET>." });
|
|
202
|
+
}
|
|
203
|
+
const body = await readBody(event);
|
|
204
|
+
const result = applyRevalidate(body);
|
|
205
|
+
if ("error" in result) {
|
|
206
|
+
res.statusCode = result.status;
|
|
207
|
+
return JSON.stringify({ error: result.error });
|
|
208
|
+
}
|
|
209
|
+
return JSON.stringify(result);
|
|
210
|
+
}));
|
|
211
|
+
// Auto sitemap.xml from route manifest
|
|
212
|
+
router.get("/sitemap.xml", defineEventHandler((event) => {
|
|
213
|
+
const baseUrl = process.env["PUBLIC_URL"] ??
|
|
214
|
+
`http://localhost:${process.env["PORT"] ?? "3000"}`;
|
|
215
|
+
const xml = generateSitemap(manifest.routes, baseUrl);
|
|
216
|
+
event.node.res.setHeader("content-type", "application/xml; charset=utf-8");
|
|
217
|
+
event.node.res.setHeader("cache-control", "public, max-age=3600");
|
|
218
|
+
return xml;
|
|
219
|
+
}));
|
|
220
|
+
// ─── API routes (route.ts) ──────────────────────────────────────────────────
|
|
221
|
+
for (const route of manifest.routes) {
|
|
222
|
+
if (route.kind !== "api")
|
|
223
|
+
continue;
|
|
224
|
+
const h3ApiPath = route.path.replace(/\[([^\]]+)\]/g, ":$1");
|
|
225
|
+
const apiModulePath = `${distDir}/server/${route.file}`;
|
|
226
|
+
for (const method of ["get", "post", "put", "patch", "delete", "head"]) {
|
|
227
|
+
router[method](h3ApiPath, defineEventHandler(async (event) => {
|
|
228
|
+
const apiMod = await import(apiModulePath);
|
|
229
|
+
const handler = apiMod[method.toUpperCase()];
|
|
230
|
+
if (typeof handler !== "function") {
|
|
231
|
+
event.node.res.statusCode = 405;
|
|
232
|
+
const allowed = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"].filter(m => typeof apiMod[m] === "function").join(", ");
|
|
233
|
+
event.node.res.setHeader("allow", allowed);
|
|
234
|
+
event.node.res.end("Method Not Allowed");
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const req = event.node.req;
|
|
238
|
+
const chunks = [];
|
|
239
|
+
await new Promise((ok) => {
|
|
240
|
+
req.on("data", (c) => chunks.push(c));
|
|
241
|
+
req.on("end", ok);
|
|
242
|
+
});
|
|
243
|
+
const body = chunks.length ? Buffer.concat(chunks) : null;
|
|
244
|
+
const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
|
|
245
|
+
const webReq = new Request(url.toString(), {
|
|
246
|
+
method: method.toUpperCase(),
|
|
247
|
+
headers: req.headers,
|
|
248
|
+
body: body?.length ? body : null,
|
|
249
|
+
});
|
|
250
|
+
const webRes = await handler(webReq);
|
|
251
|
+
const nodeRes = event.node.res;
|
|
252
|
+
nodeRes.statusCode = webRes.status;
|
|
253
|
+
webRes.headers.forEach((v, k) => nodeRes.setHeader(k, v));
|
|
254
|
+
// SSE: pipe the ReadableStream body without buffering.
|
|
255
|
+
if ((webRes.headers.get("content-type") ?? "").startsWith("text/event-stream") &&
|
|
256
|
+
webRes.body) {
|
|
257
|
+
const reader = webRes.body.getReader();
|
|
258
|
+
nodeRes.on("close", () => { void reader.cancel(); });
|
|
259
|
+
try {
|
|
260
|
+
while (true) {
|
|
261
|
+
const { done, value } = await reader.read();
|
|
262
|
+
if (done || nodeRes.destroyed)
|
|
263
|
+
break;
|
|
264
|
+
nodeRes.write(value);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
catch { /* client disconnected */ }
|
|
268
|
+
finally {
|
|
269
|
+
nodeRes.end();
|
|
270
|
+
}
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
nodeRes.end(Buffer.from(await webRes.arrayBuffer()));
|
|
274
|
+
}));
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
// ─── Page routes ────────────────────────────────────────────────────────────
|
|
278
|
+
for (const route of manifest.routes) {
|
|
279
|
+
if (route.kind !== "page")
|
|
280
|
+
continue;
|
|
281
|
+
// Convert Alab path pattern `/users/[id]` → H3 pattern `/users/:id`
|
|
282
|
+
const h3Path = route.path.replace(/\[([^\]]+)\]/g, ":$1");
|
|
283
|
+
router.get(h3Path, defineEventHandler(async (event) => {
|
|
284
|
+
const res = event.node.res;
|
|
285
|
+
// HTML pages must not be cached by intermediaries — they contain
|
|
286
|
+
// user-specific CSRF tokens and may reflect auth state.
|
|
287
|
+
res.setHeader("cache-control", "no-store");
|
|
288
|
+
// Set CSRF cookie so the client can send it on mutations.
|
|
289
|
+
const csrfToken = setCsrfCookie(event);
|
|
290
|
+
const rawParams = (event.context.params ?? {});
|
|
291
|
+
const params = rawParams;
|
|
292
|
+
const rawQuery = getQuery(event);
|
|
293
|
+
const searchParams = {};
|
|
294
|
+
for (const [k, v] of Object.entries(rawQuery)) {
|
|
295
|
+
searchParams[k] = Array.isArray(v) ? v[0] ?? "" : v;
|
|
296
|
+
}
|
|
297
|
+
// Dynamically import the compiled page module from the dist directory.
|
|
298
|
+
const pageModulePath = `${distDir}/server/${route.file}`;
|
|
299
|
+
const mod = await import(pageModulePath);
|
|
300
|
+
const Page = mod.default;
|
|
301
|
+
if (typeof Page !== "function") {
|
|
302
|
+
res.statusCode = 500;
|
|
303
|
+
res.end(`[alabjs] Page has no default export: ${route.file}`);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
// Support both static metadata and dynamic generateMetadata (production fix)
|
|
307
|
+
const metadata = typeof mod.generateMetadata === "function"
|
|
308
|
+
? await mod.generateMetadata(params)
|
|
309
|
+
: (mod.metadata ?? {});
|
|
310
|
+
const ssrEnabled = mod.ssr === true;
|
|
311
|
+
// ── Layouts ──────────────────────────────────────────────────────────
|
|
312
|
+
const layoutRelPaths = findProdLayoutFiles(route.file, distDir);
|
|
313
|
+
const layoutMods = await Promise.all(layoutRelPaths.map((p) => import(`${distDir}/server/${p}`)));
|
|
314
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
315
|
+
const layouts = layoutMods.map((m) => m.default).filter((c) => typeof c === "function");
|
|
316
|
+
const layoutsJson = JSON.stringify(layoutRelPaths);
|
|
317
|
+
const loadingFile = findProdLoadingFile(route.file, distDir) ?? undefined;
|
|
318
|
+
// Inject CSRF token into the HTML head so client JS can read it.
|
|
319
|
+
const headExtra = `<meta name="csrf-token" content="${csrfToken.replace(/"/g, """)}" />`;
|
|
320
|
+
try {
|
|
321
|
+
renderToResponse(res, {
|
|
322
|
+
Page: Page,
|
|
323
|
+
layouts,
|
|
324
|
+
params,
|
|
325
|
+
searchParams,
|
|
326
|
+
metadata,
|
|
327
|
+
routeFile: route.file,
|
|
328
|
+
layoutsJson,
|
|
329
|
+
loadingFile,
|
|
330
|
+
ssr: ssrEnabled,
|
|
331
|
+
headExtra,
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
catch (err) {
|
|
335
|
+
// ── error.tsx fallback ────────────────────────────────────────────
|
|
336
|
+
const errorRelPath = findProdErrorFile(route.file, distDir);
|
|
337
|
+
if (errorRelPath) {
|
|
338
|
+
try {
|
|
339
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
340
|
+
const errorMod = await import(`${distDir}/server/${errorRelPath}`);
|
|
341
|
+
const ErrorPage = errorMod.default;
|
|
342
|
+
if (typeof ErrorPage === "function") {
|
|
343
|
+
renderToResponse(res, {
|
|
344
|
+
Page: ErrorPage,
|
|
345
|
+
params,
|
|
346
|
+
searchParams,
|
|
347
|
+
metadata: {},
|
|
348
|
+
routeFile: errorRelPath,
|
|
349
|
+
ssr: true,
|
|
350
|
+
headExtra,
|
|
351
|
+
});
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
catch (fallbackErr) {
|
|
356
|
+
console.warn(`[alabjs] error.tsx fallback also failed for ${route.file}:`, fallbackErr);
|
|
357
|
+
// fall through to plain error
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
361
|
+
console.error(`[alabjs] render error in ${route.file}:`, err);
|
|
362
|
+
res.statusCode = 500;
|
|
363
|
+
res.end(`[alabjs] Render error in ${route.file}: ${msg}`);
|
|
364
|
+
}
|
|
365
|
+
}));
|
|
366
|
+
}
|
|
367
|
+
app.use(router);
|
|
368
|
+
// ─── 404 / not-found fallback ────────────────────────────────────────────────
|
|
369
|
+
const notFoundPath = `${distDir}/server/app/not-found.tsx`;
|
|
370
|
+
app.use(defineEventHandler(async (event) => {
|
|
371
|
+
const res = event.node.res;
|
|
372
|
+
res.statusCode = 404;
|
|
373
|
+
if (existsSync(notFoundPath)) {
|
|
374
|
+
try {
|
|
375
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
376
|
+
const nfMod = await import(notFoundPath);
|
|
377
|
+
const NotFound = nfMod.default;
|
|
378
|
+
if (typeof NotFound === "function") {
|
|
379
|
+
renderToResponse(res, {
|
|
380
|
+
Page: NotFound,
|
|
381
|
+
params: {},
|
|
382
|
+
searchParams: {},
|
|
383
|
+
metadata: { title: "404 — Not Found" },
|
|
384
|
+
routeFile: "app/not-found.tsx",
|
|
385
|
+
ssr: true,
|
|
386
|
+
});
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
catch (notFoundErr) {
|
|
391
|
+
console.warn("[alabjs] not-found.tsx render failed:", notFoundErr);
|
|
392
|
+
// fall through to plain text 404
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
res.setHeader("content-type", "text/plain; charset=utf-8");
|
|
396
|
+
res.end("404 Not Found");
|
|
397
|
+
}));
|
|
398
|
+
return {
|
|
399
|
+
listen(port = 3000) {
|
|
400
|
+
const server = createServer(toNodeListener(app));
|
|
401
|
+
server.listen(port, () => {
|
|
402
|
+
console.log(` alab ready at http://localhost:${port}`);
|
|
403
|
+
});
|
|
404
|
+
},
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
//# sourceMappingURL=app.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/server/app.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alab in-process cache for server functions.
|
|
3
|
+
*
|
|
4
|
+
* Nothing is cached unless you explicitly opt in — no implicit layers.
|
|
5
|
+
* You own the key, the TTL, and the invalidation.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* // app/posts/[id]/page.server.ts
|
|
10
|
+
* export const getPost = defineServerFn(
|
|
11
|
+
* async ({ params }) => db.posts.findById(params.id),
|
|
12
|
+
* { cache: { ttl: 60, tags: ["posts", `post:${params.id}`] } },
|
|
13
|
+
* );
|
|
14
|
+
*
|
|
15
|
+
* // Invalidate from another server function or API route
|
|
16
|
+
* import { invalidateCache } from "alabjs/cache";
|
|
17
|
+
* await invalidateCache({ tags: ["posts"] });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
/** Sentinel value returned when a cache key has no valid entry. */
|
|
21
|
+
declare const CACHE_MISS: unique symbol;
|
|
22
|
+
export { CACHE_MISS };
|
|
23
|
+
/** Retrieve a cached value. Returns `CACHE_MISS` if absent or expired. */
|
|
24
|
+
export declare function getCached(key: string): unknown | typeof CACHE_MISS;
|
|
25
|
+
/** Store a value in the cache with a TTL (seconds) and optional tags. */
|
|
26
|
+
export declare function setCache(key: string, data: unknown, opts: {
|
|
27
|
+
ttl: number;
|
|
28
|
+
tags?: string[];
|
|
29
|
+
}): void;
|
|
30
|
+
/**
|
|
31
|
+
* Invalidate all cache entries that carry at least one of the given tags.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { invalidateCache } from "alabjs/cache";
|
|
36
|
+
* await invalidateCache({ tags: ["posts"] });
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function invalidateCache(opts: {
|
|
40
|
+
tags: string[];
|
|
41
|
+
}): void;
|
|
42
|
+
/**
|
|
43
|
+
* Invalidate a specific cache entry by its exact key.
|
|
44
|
+
* Prefer `invalidateCache({ tags })` for logical invalidation.
|
|
45
|
+
*/
|
|
46
|
+
export declare function invalidateCacheKey(key: string): void;
|
|
47
|
+
/**
|
|
48
|
+
* Retrieve a cached HTML page. Returns `null` if absent or fully expired
|
|
49
|
+
* (more than 2× TTL past — serves stale-while-revalidate window).
|
|
50
|
+
*/
|
|
51
|
+
export declare function getCachedPage(pathname: string): {
|
|
52
|
+
html: string;
|
|
53
|
+
stale: boolean;
|
|
54
|
+
} | null;
|
|
55
|
+
/** Store a rendered HTML page with a TTL (seconds). */
|
|
56
|
+
export declare function setCachedPage(pathname: string, html: string, ttl: number, tags?: string[]): void;
|
|
57
|
+
/** Mark a page as currently being revalidated to prevent concurrent regen. */
|
|
58
|
+
export declare function markPageRevalidating(pathname: string): void;
|
|
59
|
+
/** Check if a page is currently being revalidated in the background. */
|
|
60
|
+
export declare function isPageRevalidating(pathname: string): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Purge a specific page's cached HTML, forcing a fresh render on the next request.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* import { revalidatePath } from "alabjs/cache";
|
|
67
|
+
* await revalidatePath("/posts/1"); // next request regenerates the page
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare function revalidatePath(pathname: string): void;
|
|
71
|
+
/**
|
|
72
|
+
* Purge all cached pages whose pathname starts with the given prefix.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* await revalidatePath("/posts"); // clears /posts, /posts/1, /posts/2, ...
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export declare function revalidatePathPrefix(prefix: string): void;
|
|
80
|
+
/**
|
|
81
|
+
* Purge all server-function cache entries AND page HTML cache entries
|
|
82
|
+
* that carry at least one of the given tags.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```ts
|
|
86
|
+
* import { revalidateTag } from "alabjs/cache";
|
|
87
|
+
* revalidateTag({ tags: ["posts"] }); // clears both data and page caches
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export declare function revalidateTag(opts: {
|
|
91
|
+
tags: string[];
|
|
92
|
+
}): void;
|
|
93
|
+
/** Return a snapshot of all live cache entries (for the dev Cache Inspector). */
|
|
94
|
+
export declare function inspectCache(): Array<{
|
|
95
|
+
key: string;
|
|
96
|
+
tags: string[];
|
|
97
|
+
expiresIn: number;
|
|
98
|
+
}>;
|
|
99
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/server/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AASH,mEAAmE;AACnE,QAAA,MAAM,UAAU,EAAE,OAAO,MAAkC,CAAC;AAK5D,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,0EAA0E;AAC1E,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,UAAU,CAQlE;AAED,yEAAyE;AACzE,wBAAgB,QAAQ,CACtB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,OAAO,EACb,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GACrC,IAAI,CAMN;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAM9D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEpD;AAeD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAavF;AAED,uDAAuD;AACvD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAO,GAAG,IAAI,CAEpG;AAED,8EAA8E;AAC9E,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAG3D;AAED,wEAAwE;AACxE,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAErD;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAIzD;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAS5D;AAED,iFAAiF;AACjF,wBAAgB,YAAY,IAAI,KAAK,CAAC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CASD"}
|