bun-plugin-stx 0.2.77 → 0.2.79
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/serve.d.ts +30 -0
- package/dist/serve.js +131 -44
- package/package.json +1 -1
package/dist/serve.d.ts
CHANGED
|
@@ -12,6 +12,36 @@
|
|
|
12
12
|
* projects that nest routable views under `pages/`
|
|
13
13
|
*/
|
|
14
14
|
export declare function buildDynamicRouteRegexes(fileRouteBase: string): RegExp[];
|
|
15
|
+
/**
|
|
16
|
+
* Are we serving in production? In production the built-in 404 must not
|
|
17
|
+
* enumerate the app's route list (information disclosure) and must not
|
|
18
|
+
* inject the HMR client.
|
|
19
|
+
*
|
|
20
|
+
* Reuses the standard Stacks/Node signals — `NODE_ENV` / `APP_ENV`. serve.ts
|
|
21
|
+
* has no pre-existing prod/dev flag threaded through its options, so these
|
|
22
|
+
* env vars are the canonical signal (the same ones the wider stacks codebase
|
|
23
|
+
* keys production behaviour off of).
|
|
24
|
+
*/
|
|
25
|
+
export declare function isProductionServe(): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Render the built-in fallback 404 page.
|
|
28
|
+
*
|
|
29
|
+
* - In development (`isProduction: false`) it lists the discovered routes as
|
|
30
|
+
* clickable links — a genuinely useful dev affordance — and reflects the
|
|
31
|
+
* requested path (HTML-escaped).
|
|
32
|
+
* - In production (`isProduction: true`) it renders a clean, neutral, self-
|
|
33
|
+
* contained page with NO route list and NO reflected path, so nothing about
|
|
34
|
+
* the app's internal structure leaks to anonymous visitors.
|
|
35
|
+
*
|
|
36
|
+
* The page is a complete HTML document, styled inline (system font stack,
|
|
37
|
+
* centered, light + dark via `prefers-color-scheme`, no external assets).
|
|
38
|
+
* The caller is responsible for HMR injection (dev only) and the 404 status.
|
|
39
|
+
*/
|
|
40
|
+
export declare function render404Page(opts: {
|
|
41
|
+
path: string
|
|
42
|
+
routes?: string[]
|
|
43
|
+
isProduction: boolean
|
|
44
|
+
}): string;
|
|
15
45
|
export declare function bundleBrowserAsset(entrypoint: string): Promise<Response>;
|
|
16
46
|
/**
|
|
17
47
|
* Start the STX development server
|
package/dist/serve.js
CHANGED
|
@@ -8709,6 +8709,104 @@ function buildDynamicRouteRegexes(fileRouteBase) {
|
|
|
8709
8709
|
}
|
|
8710
8710
|
return patterns;
|
|
8711
8711
|
}
|
|
8712
|
+
function escapeHtml(input) {
|
|
8713
|
+
return input.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
8714
|
+
}
|
|
8715
|
+
function isProductionServe() {
|
|
8716
|
+
return process19.env.NODE_ENV === "production" || process19.env.APP_ENV === "production";
|
|
8717
|
+
}
|
|
8718
|
+
function render404Page(opts) {
|
|
8719
|
+
const { path, routes = [], isProduction } = opts;
|
|
8720
|
+
const baseStyles = `
|
|
8721
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
8722
|
+
body {
|
|
8723
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
8724
|
+
margin: 0;
|
|
8725
|
+
min-height: 100vh;
|
|
8726
|
+
display: flex;
|
|
8727
|
+
align-items: center;
|
|
8728
|
+
justify-content: center;
|
|
8729
|
+
padding: 2rem;
|
|
8730
|
+
background: #ffffff;
|
|
8731
|
+
color: #1a202c;
|
|
8732
|
+
line-height: 1.5;
|
|
8733
|
+
}
|
|
8734
|
+
main { max-width: 32rem; width: 100%; text-align: center; }
|
|
8735
|
+
.code { font-size: 3.5rem; font-weight: 700; letter-spacing: -0.02em; margin: 0; }
|
|
8736
|
+
h1 { font-size: 1.25rem; font-weight: 600; margin: 0.75rem 0 0.5rem; }
|
|
8737
|
+
p { margin: 0.5rem 0; color: #4a5568; }
|
|
8738
|
+
a { color: #4a5568; }
|
|
8739
|
+
.home {
|
|
8740
|
+
display: inline-block;
|
|
8741
|
+
margin-top: 1.5rem;
|
|
8742
|
+
padding: 0.6rem 1.25rem;
|
|
8743
|
+
border-radius: 0.5rem;
|
|
8744
|
+
background: #1a202c;
|
|
8745
|
+
color: #ffffff;
|
|
8746
|
+
text-decoration: none;
|
|
8747
|
+
font-weight: 500;
|
|
8748
|
+
font-size: 0.95rem;
|
|
8749
|
+
}
|
|
8750
|
+
.home:hover { opacity: 0.85; }
|
|
8751
|
+
@media (prefers-color-scheme: dark) {
|
|
8752
|
+
body { background: #0f1115; color: #e2e8f0; }
|
|
8753
|
+
p { color: #a0aec0; }
|
|
8754
|
+
a { color: #a0aec0; }
|
|
8755
|
+
.home { background: #e2e8f0; color: #0f1115; }
|
|
8756
|
+
}`;
|
|
8757
|
+
if (isProduction) {
|
|
8758
|
+
return `<!DOCTYPE html>
|
|
8759
|
+
<html lang="en">
|
|
8760
|
+
<head>
|
|
8761
|
+
<meta charset="utf-8">
|
|
8762
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
8763
|
+
<meta name="robots" content="noindex">
|
|
8764
|
+
<title>404 - Page Not Found</title>
|
|
8765
|
+
<style>${baseStyles}
|
|
8766
|
+
</style>
|
|
8767
|
+
</head>
|
|
8768
|
+
<body>
|
|
8769
|
+
<main>
|
|
8770
|
+
<p class="code">404</p>
|
|
8771
|
+
<h1>Page not found</h1>
|
|
8772
|
+
<p>The page you're looking for doesn't exist or may have moved.</p>
|
|
8773
|
+
<a class="home" href="/">Go to homepage</a>
|
|
8774
|
+
</main>
|
|
8775
|
+
</body>
|
|
8776
|
+
</html>`;
|
|
8777
|
+
}
|
|
8778
|
+
const routesList = routes.map((route) => `<li><a href="/${escapeHtml(route)}">/${escapeHtml(route)}</a></li>`).join(`
|
|
8779
|
+
`);
|
|
8780
|
+
return `<!DOCTYPE html>
|
|
8781
|
+
<html lang="en">
|
|
8782
|
+
<head>
|
|
8783
|
+
<meta charset="utf-8">
|
|
8784
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
8785
|
+
<title>404 - Not Found</title>
|
|
8786
|
+
<style>${baseStyles}
|
|
8787
|
+
main { max-width: 40rem; }
|
|
8788
|
+
.routes { list-style: none; padding: 0; margin: 2rem 0 0; text-align: left; }
|
|
8789
|
+
.routes li { margin: 0.35rem 0; }
|
|
8790
|
+
.routes a { color: #667eea; text-decoration: none; font-size: 1.05rem; }
|
|
8791
|
+
.routes a:hover { text-decoration: underline; }
|
|
8792
|
+
.dev-note { font-size: 0.85rem; margin-top: 1.5rem; opacity: 0.7; }
|
|
8793
|
+
@media (prefers-color-scheme: dark) { .routes a { color: #9aa8ff; } }
|
|
8794
|
+
</style>
|
|
8795
|
+
</head>
|
|
8796
|
+
<body>
|
|
8797
|
+
<main>
|
|
8798
|
+
<p class="code">404</p>
|
|
8799
|
+
<h1>Page not found</h1>
|
|
8800
|
+
<p>The page "${escapeHtml(path)}" doesn't exist.</p>
|
|
8801
|
+
<h2 style="font-size:1rem;margin-top:2rem;">Available pages</h2>
|
|
8802
|
+
<ul class="routes">${routesList ? `
|
|
8803
|
+
${routesList}
|
|
8804
|
+
` : ""}</ul>
|
|
8805
|
+
<p class="dev-note">This route list is shown in development only.</p>
|
|
8806
|
+
</main>
|
|
8807
|
+
</body>
|
|
8808
|
+
</html>`;
|
|
8809
|
+
}
|
|
8712
8810
|
var defaultStxConfig = {
|
|
8713
8811
|
partialsDir: "partials",
|
|
8714
8812
|
componentsDir: "components",
|
|
@@ -10124,53 +10222,40 @@ ${pageSetupScripts.join(`
|
|
|
10124
10222
|
if (path === "/favicon.ico") {
|
|
10125
10223
|
return new Response(null, { status: 204 });
|
|
10126
10224
|
}
|
|
10127
|
-
const
|
|
10128
|
-
const
|
|
10129
|
-
|
|
10130
|
-
|
|
10131
|
-
|
|
10132
|
-
|
|
10133
|
-
|
|
10134
|
-
|
|
10135
|
-
|
|
10225
|
+
const isProd = isProductionServe();
|
|
10226
|
+
for (const custom404 of ["/404", "/errors/404"]) {
|
|
10227
|
+
try {
|
|
10228
|
+
const customContent = await getRoute(custom404);
|
|
10229
|
+
if (customContent) {
|
|
10230
|
+
return new Response(isProd ? customContent : injectHmrClient(customContent), {
|
|
10231
|
+
status: 404,
|
|
10232
|
+
headers: { "Content-Type": "text/html; charset=utf-8" }
|
|
10233
|
+
});
|
|
10136
10234
|
}
|
|
10137
|
-
}
|
|
10138
|
-
let route2 = normalizedPath.replace(/\.(stx|md|html)$/, "");
|
|
10139
|
-
if (route2.startsWith("pages/")) {
|
|
10140
|
-
route2 = route2.slice(6);
|
|
10141
|
-
}
|
|
10142
|
-
availableRoutes.push(`<li><a href="/${route2}">/${route2}</a></li>`);
|
|
10235
|
+
} catch {}
|
|
10143
10236
|
}
|
|
10144
|
-
|
|
10145
|
-
|
|
10146
|
-
|
|
10147
|
-
|
|
10148
|
-
|
|
10149
|
-
|
|
10150
|
-
|
|
10151
|
-
|
|
10152
|
-
|
|
10153
|
-
|
|
10154
|
-
|
|
10155
|
-
|
|
10156
|
-
|
|
10157
|
-
|
|
10237
|
+
let availableRoutes;
|
|
10238
|
+
if (!isProd) {
|
|
10239
|
+
const files = await discoverFiles();
|
|
10240
|
+
availableRoutes = [];
|
|
10241
|
+
for (const filePath of files) {
|
|
10242
|
+
let normalizedPath = filePath.replace(/^\.\//, "").replace(/\\/g, "/");
|
|
10243
|
+
for (const pattern of patterns) {
|
|
10244
|
+
const normalizedPattern = pattern.replace(/\\/g, "/").replace(/\/$/, "");
|
|
10245
|
+
if (normalizedPath.startsWith(`${normalizedPattern}/`)) {
|
|
10246
|
+
normalizedPath = normalizedPath.slice(normalizedPattern.length + 1);
|
|
10247
|
+
break;
|
|
10248
|
+
}
|
|
10249
|
+
}
|
|
10250
|
+
let route2 = normalizedPath.replace(/\.(stx|md|html)$/, "");
|
|
10251
|
+
if (route2.startsWith("pages/")) {
|
|
10252
|
+
route2 = route2.slice(6);
|
|
10253
|
+
}
|
|
10254
|
+
availableRoutes.push(route2);
|
|
10255
|
+
}
|
|
10158
10256
|
}
|
|
10159
|
-
|
|
10160
|
-
|
|
10161
|
-
li { margin: 0.5rem 0; }
|
|
10162
|
-
a { color: #667eea; text-decoration: none; font-size: 1.1rem; }
|
|
10163
|
-
a:hover { text-decoration: underline; }
|
|
10164
|
-
</style>
|
|
10165
|
-
</head>
|
|
10166
|
-
<body>
|
|
10167
|
-
<h1>404 - Page Not Found</h1>
|
|
10168
|
-
<p>The page "${path}" doesn't exist.</p>
|
|
10169
|
-
<h2>Available pages:</h2>
|
|
10170
|
-
<ul>${routesList}</ul>
|
|
10171
|
-
</body>
|
|
10172
|
-
</html>
|
|
10173
|
-
`), {
|
|
10257
|
+
const notFoundHtml = render404Page({ path, routes: availableRoutes, isProduction: isProd });
|
|
10258
|
+
return new Response(isProd ? notFoundHtml : injectHmrClient(notFoundHtml), {
|
|
10174
10259
|
status: 404,
|
|
10175
10260
|
headers: { "Content-Type": "text/html; charset=utf-8" }
|
|
10176
10261
|
});
|
|
@@ -10255,6 +10340,8 @@ if (import.meta.main) {
|
|
|
10255
10340
|
}
|
|
10256
10341
|
export {
|
|
10257
10342
|
serve,
|
|
10343
|
+
render404Page,
|
|
10344
|
+
isProductionServe,
|
|
10258
10345
|
bundleBrowserAsset,
|
|
10259
10346
|
buildDynamicRouteRegexes
|
|
10260
10347
|
};
|
package/package.json
CHANGED