bosia 0.5.10 → 0.5.11
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/package.json +1 -1
- package/src/core/dev-error-page.ts +78 -0
- package/src/core/devErrorReport.ts +2 -2
- package/src/core/html.ts +1 -1
- package/src/core/renderer.ts +6 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bosia",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A fast, batteries-included fullstack framework — SSR · Svelte 5 Runes · Bun · ElysiaJS. File-based routing inspired by SvelteKit. No Node.js, no Vite, no adapters.",
|
|
6
6
|
"keywords": [
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { safeJsonForScript } from "./html.ts";
|
|
2
|
+
import { getOverlayScript } from "./plugins/inspector/overlay.ts";
|
|
3
|
+
|
|
4
|
+
export interface DevServerError {
|
|
5
|
+
id: string;
|
|
6
|
+
ts: number;
|
|
7
|
+
source: string;
|
|
8
|
+
message: string;
|
|
9
|
+
stack?: string;
|
|
10
|
+
file?: string;
|
|
11
|
+
line?: number;
|
|
12
|
+
col?: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Minimal HTML shown when the dev proxy can't reach the app server (initial
|
|
17
|
+
* build failure, crash loop, port conflict). Mounts the same inspector overlay
|
|
18
|
+
* so the red error badge appears identical to the in-app experience, pre-seeds
|
|
19
|
+
* the buffered errors that fired before the page loaded, and subscribes to the
|
|
20
|
+
* dev SSE channel so it auto-reloads when the next build succeeds.
|
|
21
|
+
*/
|
|
22
|
+
export function renderDevErrorPage(buffered: DevServerError[]): string {
|
|
23
|
+
const overlay = getOverlayScript({ endpoint: "/__bosia/locate", errorsEnabled: true });
|
|
24
|
+
const seed = safeJsonForScript(buffered);
|
|
25
|
+
|
|
26
|
+
return `<!DOCTYPE html>
|
|
27
|
+
<html lang="en">
|
|
28
|
+
<head>
|
|
29
|
+
<meta charset="UTF-8">
|
|
30
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
31
|
+
<title>Dev server error — Bosia</title>
|
|
32
|
+
<style>
|
|
33
|
+
html,body{margin:0;padding:0;height:100%;background:#0a0a0a;color:#e5e5e5;font:14px/1.5 ui-sans-serif,system-ui,-apple-system,sans-serif}
|
|
34
|
+
.wrap{min-height:100%;display:flex;align-items:center;justify-content:center;padding:24px;box-sizing:border-box}
|
|
35
|
+
.card{max-width:540px;text-align:center}
|
|
36
|
+
.dot{display:inline-block;width:10px;height:10px;background:#dc2626;border-radius:50%;margin-right:8px;vertical-align:middle;animation:p 1.4s ease-in-out infinite}
|
|
37
|
+
@keyframes p{0%,100%{opacity:1}50%{opacity:.3}}
|
|
38
|
+
h1{font-size:18px;font-weight:600;margin:0 0 8px}
|
|
39
|
+
p{margin:0;color:#a3a3a3;font-size:13px}
|
|
40
|
+
code{font-family:ui-monospace,monospace;color:#fafafa;background:#1f1f1f;padding:1px 6px;border-radius:3px}
|
|
41
|
+
</style>
|
|
42
|
+
</head>
|
|
43
|
+
<body>
|
|
44
|
+
<div class="wrap">
|
|
45
|
+
<div class="card">
|
|
46
|
+
<h1><span class="dot"></span>Dev server error</h1>
|
|
47
|
+
<p>See the red badge in the bottom-right for details. This page will reload automatically when the next build succeeds.</p>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
<script type="application/json" id="__bosia-dev-errors__">${seed}</script>
|
|
51
|
+
${overlay}
|
|
52
|
+
<script>
|
|
53
|
+
(function(){
|
|
54
|
+
function seed(){
|
|
55
|
+
var node=document.getElementById("__bosia-dev-errors__");
|
|
56
|
+
if(!node||!window.__BOSIA_PUSH_ERROR__)return false;
|
|
57
|
+
try{
|
|
58
|
+
var list=JSON.parse(node.textContent||"[]");
|
|
59
|
+
for(var i=0;i<list.length;i++)window.__BOSIA_PUSH_ERROR__(list[i]);
|
|
60
|
+
}catch(_){}
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
if(!seed()){
|
|
64
|
+
var tries=0;
|
|
65
|
+
var iv=setInterval(function(){tries++;if(seed()||tries>20)clearInterval(iv)},50);
|
|
66
|
+
}
|
|
67
|
+
!function r(){
|
|
68
|
+
try{
|
|
69
|
+
var e=new EventSource("/__bosia/sse");
|
|
70
|
+
e.addEventListener("reload",function(){location.reload()});
|
|
71
|
+
e.onerror=function(){e.close();setTimeout(r,2000)};
|
|
72
|
+
}catch(_){setTimeout(r,2000)}
|
|
73
|
+
}();
|
|
74
|
+
})();
|
|
75
|
+
</script>
|
|
76
|
+
</body>
|
|
77
|
+
</html>`;
|
|
78
|
+
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// is a safe no-op otherwise.
|
|
7
7
|
|
|
8
8
|
interface DevReportInput {
|
|
9
|
-
source?: "
|
|
9
|
+
source?: "server" | "uncaught" | "rejection";
|
|
10
10
|
message: string;
|
|
11
11
|
stack?: string;
|
|
12
12
|
}
|
|
@@ -22,7 +22,7 @@ export function reportDevErrorFromCatch(err: unknown): void {
|
|
|
22
22
|
const e = err as Error | undefined;
|
|
23
23
|
try {
|
|
24
24
|
fn({
|
|
25
|
-
source: "
|
|
25
|
+
source: "server",
|
|
26
26
|
message: e?.message ?? String(err),
|
|
27
27
|
stack: e?.stack,
|
|
28
28
|
});
|
package/src/core/html.ts
CHANGED
|
@@ -160,7 +160,7 @@ export function buildHtml(
|
|
|
160
160
|
` <script${n}>try{var t=localStorage.getItem('theme');if(t==='dark'||(!t&&window.matchMedia('(prefers-color-scheme: dark)').matches))document.documentElement.classList.add('dark');else document.documentElement.classList.remove('dark')}catch(_){}</script>\n` +
|
|
161
161
|
` ${fallbackTitle}${head}` +
|
|
162
162
|
headCloseInterpolated +
|
|
163
|
-
`\n${SPINNER}` +
|
|
163
|
+
(body ? "" : `\n${SPINNER}`) +
|
|
164
164
|
`\n <div id="app">${body}</div>${scripts}${bodyEnd}` +
|
|
165
165
|
tailInterpolated
|
|
166
166
|
);
|
package/src/core/renderer.ts
CHANGED
|
@@ -42,6 +42,7 @@ async function pluginRenderFragments(
|
|
|
42
42
|
} catch (err) {
|
|
43
43
|
if (isDev) console.error(`Plugin "${p.name}" render.${hook} failed:`, err);
|
|
44
44
|
else console.error(`Plugin "${p.name}" render.${hook} failed:`, (err as Error).message);
|
|
45
|
+
if (isDev) reportDevErrorFromCatch(err);
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
48
|
return out;
|
|
@@ -481,6 +482,7 @@ export async function loadMetadata(
|
|
|
481
482
|
} catch (err) {
|
|
482
483
|
if (isDev) console.error("Metadata load error:", err);
|
|
483
484
|
else console.error("Metadata load error:", (err as Error).message ?? err);
|
|
485
|
+
if (isDev) reportDevErrorFromCatch(err);
|
|
484
486
|
}
|
|
485
487
|
return null;
|
|
486
488
|
}
|
|
@@ -524,6 +526,7 @@ export async function renderSSRStream(
|
|
|
524
526
|
}
|
|
525
527
|
if (isDev) console.error("Metadata load error:", err);
|
|
526
528
|
else console.error("Metadata load error:", (err as Error).message ?? err);
|
|
529
|
+
if (isDev) reportDevErrorFromCatch(err);
|
|
527
530
|
// Continue with null metadata — don't break the page for a metadata failure
|
|
528
531
|
}
|
|
529
532
|
|
|
@@ -651,6 +654,7 @@ export async function renderSSRStream(
|
|
|
651
654
|
} catch (err) {
|
|
652
655
|
if (isDev) console.error("SSR render error:", err);
|
|
653
656
|
else console.error("SSR render error:", (err as Error).message ?? err);
|
|
657
|
+
if (isDev) reportDevErrorFromCatch(err);
|
|
654
658
|
// Render-phase errors fall through to deepest boundary like a page error.
|
|
655
659
|
return renderErrorPage(
|
|
656
660
|
500,
|
|
@@ -910,6 +914,7 @@ export async function renderErrorPage(
|
|
|
910
914
|
"Nested error page render failed:",
|
|
911
915
|
(err as Error).message ?? err,
|
|
912
916
|
);
|
|
917
|
+
if (isDev) reportDevErrorFromCatch(err);
|
|
913
918
|
// fall through to global / text fallback
|
|
914
919
|
}
|
|
915
920
|
}
|
|
@@ -944,6 +949,7 @@ export async function renderErrorPage(
|
|
|
944
949
|
} catch (err) {
|
|
945
950
|
if (isDev) console.error("Error page render failed:", err);
|
|
946
951
|
else console.error("Error page render failed:", (err as Error).message ?? err);
|
|
952
|
+
if (isDev) reportDevErrorFromCatch(err);
|
|
947
953
|
}
|
|
948
954
|
}
|
|
949
955
|
return new Response(message, {
|