@mandujs/core 0.41.2 → 0.43.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.
Files changed (88) hide show
  1. package/package.json +21 -4
  2. package/src/auth/__tests__/login.test.ts +420 -419
  3. package/src/auth/__tests__/reset.test.ts +296 -296
  4. package/src/brain/adapters/anthropic-oauth.ts +421 -420
  5. package/src/brain/adapters/index.ts +2 -1
  6. package/src/brain/adapters/ollama.ts +1 -1
  7. package/src/brain/adapters/openai-oauth.ts +534 -533
  8. package/src/brain/brain.ts +2 -1
  9. package/src/brain/redactor.ts +196 -196
  10. package/src/bundler/__tests__/cli-bench-utils.test.ts +149 -149
  11. package/src/bundler/__tests__/cold-start.test.ts +504 -504
  12. package/src/bundler/__tests__/fast-refresh.test.ts +607 -606
  13. package/src/bundler/__tests__/hdr.test.ts +1 -1
  14. package/src/bundler/analyzer.ts +958 -958
  15. package/src/bundler/build.ts +104 -14
  16. package/src/bundler/dev.ts +125 -0
  17. package/src/bundler/hmr-types.ts +1 -0
  18. package/src/bundler/plugins/__tests__/react-compiler-lint.test.ts +110 -0
  19. package/src/bundler/plugins/index.ts +14 -0
  20. package/src/bundler/plugins/react-compiler-lint.ts +253 -0
  21. package/src/bundler/plugins/react-compiler.ts +162 -0
  22. package/src/bundler/types.ts +12 -0
  23. package/src/change/integrity.ts +2 -1
  24. package/src/client/index.ts +10 -0
  25. package/src/client/island.ts +38 -11
  26. package/src/client/router.ts +6 -1
  27. package/src/config/mandu.ts +57 -0
  28. package/src/config/validate.ts +42 -0
  29. package/src/content/collection.ts +844 -809
  30. package/src/content/content-layer.ts +316 -314
  31. package/src/content/content.test.ts +433 -433
  32. package/src/content/digest.ts +133 -133
  33. package/src/content/generate-types.ts +168 -168
  34. package/src/content/index.ts +6 -1
  35. package/src/content/llms-txt.ts +277 -277
  36. package/src/contract/define.ts +474 -474
  37. package/src/contract/route-helpers.ts +2 -1
  38. package/src/contract/zod-utils.ts +158 -155
  39. package/src/db/index.ts +513 -513
  40. package/src/desktop/__tests__/smoke.test.ts +100 -100
  41. package/src/desktop/webview-fallback.ts +583 -583
  42. package/src/desktop/window.ts +3 -1
  43. package/src/dev-error-overlay/overlay-client.ts +300 -300
  44. package/src/devtools/ai/mcp-connector.ts +499 -498
  45. package/src/devtools/client/components/kitchen-root.tsx +7 -2
  46. package/src/email/resend.ts +163 -163
  47. package/src/guard/__tests__/tsgolint-bridge.test.ts +347 -0
  48. package/src/guard/ast-analyzer.ts +806 -806
  49. package/src/guard/graph.ts +898 -898
  50. package/src/guard/index.ts +16 -0
  51. package/src/guard/statistics.ts +578 -578
  52. package/src/guard/tsgolint-bridge.ts +512 -0
  53. package/src/i18n/locale-resolver.ts +214 -214
  54. package/src/id/__tests__/id.test.ts +120 -120
  55. package/src/intent/index.ts +321 -321
  56. package/src/island/index.ts +39 -23
  57. package/src/kitchen/api/contract-api.ts +15 -8
  58. package/src/kitchen/kitchen-ui.ts +2137 -2137
  59. package/src/lockfile/index.ts +3 -2
  60. package/src/middleware/oauth/__tests__/oauth.test.ts +575 -574
  61. package/src/middleware/rate-limit/__tests__/rate-limit.test.ts +642 -642
  62. package/src/middleware/secure/index.ts +417 -417
  63. package/src/observability/event-bus.ts +2 -2
  64. package/src/observability/metrics.ts +334 -334
  65. package/src/observability/tracing.ts +694 -694
  66. package/src/openapi/generator.ts +1 -1
  67. package/src/perf/user-marks.ts +553 -553
  68. package/src/plugins/registry.ts +387 -387
  69. package/src/resource/ddl/diff.ts +392 -392
  70. package/src/resource/ddl/snapshot.ts +448 -447
  71. package/src/resource/generator-schema.ts +477 -476
  72. package/src/resource/parser.ts +4 -2
  73. package/src/resource/schema.ts +1 -1
  74. package/src/router/fs-patterns.ts +422 -422
  75. package/src/runtime/fast-refresh-types.ts +126 -128
  76. package/src/runtime/image-handler.ts +206 -195
  77. package/src/runtime/router.test.ts +476 -476
  78. package/src/runtime/security.ts +155 -155
  79. package/src/runtime/server.ts +36 -19
  80. package/src/runtime/session-key.ts +328 -328
  81. package/src/scheduler/__tests__/scheduler.test.ts +514 -514
  82. package/src/seo/resolve/index.ts +353 -353
  83. package/src/spec/load.ts +1 -1
  84. package/src/testing/reporter.ts +676 -676
  85. package/src/testing/server.ts +196 -196
  86. package/src/testing/snapshot.ts +444 -444
  87. package/src/utils/__tests__/lru-cache.test.ts +186 -186
  88. package/src/utils/bun.ts +8 -8
@@ -99,7 +99,7 @@ export async function _loadWebviewBun(): Promise<WebviewBunModule> {
99
99
  "Then pin the version in package.json. Tested: ^2.4.0 (MIT).",
100
100
  "Docs: https://github.com/tr1ckydev/webview-bun",
101
101
  ].join("\n"),
102
- { cause: cause as Error },
102
+ { cause },
103
103
  );
104
104
  }
105
105
  }
@@ -353,6 +353,7 @@ export async function createWindow(
353
353
  `[@mandujs/core/desktop] Failed to bind handler "${name}": ${
354
354
  error instanceof Error ? error.message : String(error)
355
355
  }`,
356
+ { cause: error },
356
357
  );
357
358
  }
358
359
  }
@@ -419,6 +420,7 @@ export async function createWindow(
419
420
  `[@mandujs/core/desktop] navigate() failed: ${
420
421
  error instanceof Error ? error.message : String(error)
421
422
  }`,
423
+ { cause: error },
422
424
  );
423
425
  }
424
426
 
@@ -1,300 +1,300 @@
1
- /**
2
- * Phase 18.α — Dev Error Overlay client IIFE.
3
- *
4
- * This file EXPORTS a string (`OVERLAY_CLIENT_SCRIPT`) that is inlined
5
- * into the SSR `<head>` by the injector. It is NOT compiled as a
6
- * module; the whole body runs in parse order on every dev page load.
7
- *
8
- * Size target: < 10 KB gzipped (current ≈ 2 KB gz). No dependencies.
9
- * Only touches `window`, `document`, `navigator.clipboard`, and a tiny
10
- * WeakSet.
11
- *
12
- * Listeners installed:
13
- * - `window.onerror` → uncaught script errors
14
- * - `unhandledrejection` → Promise rejections
15
- * - custom event `__MANDU_ERROR__` → the server embeds a 500 payload
16
- * in the HTML, fires this event on DOMContentLoaded, and the
17
- * overlay picks it up. User code can also `dispatchEvent` it to
18
- * surface synthetic errors.
19
- *
20
- * Everything scoped in an IIFE — NO globals leak except the single
21
- * `__MANDU_OVERLAY_MOUNTED__` sentinel that prevents double-mount on
22
- * HMR.
23
- */
24
- import { OVERLAY_STYLES } from "./overlay-styles";
25
- import {
26
- OVERLAY_CUSTOM_EVENT,
27
- OVERLAY_MOUNTED_FLAG,
28
- OVERLAY_PAYLOAD_ELEMENT_ID,
29
- } from "./types";
30
-
31
- /**
32
- * Build the client-side IIFE body as a string. Parameterised by the
33
- * style block and the two sentinel names so tests can verify the exact
34
- * shape without re-declaring the constants.
35
- */
36
- function buildOverlayClientScript(): string {
37
- // The IIFE below references the constants through string interpolation,
38
- // NOT through imports — because it runs in the browser and has no
39
- // module loader.
40
- return `(function(){
41
- var MOUNTED=${JSON.stringify(OVERLAY_MOUNTED_FLAG)};
42
- var EVT=${JSON.stringify(OVERLAY_CUSTOM_EVENT)};
43
- var PAYLOAD_ID=${JSON.stringify(OVERLAY_PAYLOAD_ELEMENT_ID)};
44
- if(typeof window==="undefined"||typeof document==="undefined")return;
45
- if(window[MOUNTED]===true)return;
46
- window[MOUNTED]=true;
47
-
48
- var STYLE=${JSON.stringify(OVERLAY_STYLES)};
49
- var seen=new WeakSet();
50
-
51
- function parseFrames(stack){
52
- if(typeof stack!=="string"||stack.length===0)return [];
53
- var lines=stack.split("\\n");
54
- var out=[];
55
- for(var i=0;i<lines.length;i++){
56
- var raw=lines[i];
57
- var t=raw.trim();
58
- if(!t||t===stack.split("\\n")[0]&&/^[A-Z][a-zA-Z]*(?:Error)?:/.test(t))continue;
59
- // Chrome: " at fn (file:line:col)"
60
- // Firefox: "fn@file:line:col"
61
- var m=t.match(/^at\\s+(.+?)\\s+\\((.+):(\\d+):(\\d+)\\)$/);
62
- if(!m)m=t.match(/^at\\s+(.+):(\\d+):(\\d+)$/);
63
- if(m&&m.length===5){
64
- out.push({fn:m[1],file:m[2],line:parseInt(m[3],10),column:parseInt(m[4],10),raw:raw});
65
- continue;
66
- }
67
- if(m&&m.length===4){
68
- out.push({fn:"<anonymous>",file:m[1],line:parseInt(m[2],10),column:parseInt(m[3],10),raw:raw});
69
- continue;
70
- }
71
- var ff=t.match(/^(.*?)@(.+):(\\d+):(\\d+)$/);
72
- if(ff){
73
- out.push({fn:ff[1]||"<anonymous>",file:ff[2],line:parseInt(ff[3],10),column:parseInt(ff[4],10),raw:raw});
74
- continue;
75
- }
76
- out.push({fn:"<anonymous>",file:t,line:null,column:null,raw:raw});
77
- }
78
- return out;
79
- }
80
-
81
- function toPayload(err,kind){
82
- var name="Error",message="",stack="";
83
- if(err&&typeof err==="object"){
84
- name=err.name||"Error";
85
- message=typeof err.message==="string"?err.message:String(err.message||"");
86
- stack=typeof err.stack==="string"?err.stack:"";
87
- }else if(typeof err==="string"){
88
- message=err;
89
- }else if(err!=null){
90
- try{message=String(err);}catch(_){message="<unserializable error>";}
91
- }
92
- return {
93
- name:name,
94
- message:message,
95
- frames:parseFrames(stack),
96
- stack:stack,
97
- kind:kind,
98
- timestamp:Date.now(),
99
- url:typeof location!=="undefined"?location.pathname+location.search:undefined,
100
- userAgent:typeof navigator!=="undefined"?navigator.userAgent:undefined
101
- };
102
- }
103
-
104
- function esc(s){
105
- if(s==null)return "";
106
- return String(s).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;");
107
- }
108
-
109
- function fileHref(file,line,col){
110
- // vscode://file/<abs>:<line>:<col> — falls back gracefully when the
111
- // host OS has no handler. Relative paths get "//" prefix so the URL
112
- // still parses, even though the editor may refuse to jump.
113
- var p=file;
114
- if(!/^[a-zA-Z]:|^\\//.test(p))p="/"+p;
115
- var u="vscode://file"+p;
116
- if(line)u+=":"+line;
117
- if(col)u+=":"+col;
118
- return u;
119
- }
120
-
121
- function renderFrames(frames){
122
- if(!frames||frames.length===0)return '<li class="mandu-dev-overlay__frame"><span class="mandu-dev-overlay__frame-fn">&lt;no stack&gt;</span></li>';
123
- var items=[];
124
- for(var i=0;i<frames.length&&i<40;i++){
125
- var f=frames[i];
126
- var loc=esc(f.file)+(f.line?":"+f.line:"")+(f.column?":"+f.column:"");
127
- var href=f.file?fileHref(f.file,f.line,f.column):"";
128
- var locHtml=href?'<a class="mandu-dev-overlay__frame-link" href="'+esc(href)+'">'+loc+'</a>':loc;
129
- items.push('<li class="mandu-dev-overlay__frame"><span class="mandu-dev-overlay__frame-fn">'+esc(f.fn||"<anonymous>")+'</span><span class="mandu-dev-overlay__frame-loc">'+locHtml+'</span></li>');
130
- }
131
- return items.join("");
132
- }
133
-
134
- function ensureStyleTag(){
135
- if(document.getElementById("__mandu-dev-overlay-style"))return;
136
- var s=document.createElement("style");
137
- s.id="__mandu-dev-overlay-style";
138
- s.textContent=STYLE;
139
- (document.head||document.documentElement).appendChild(s);
140
- }
141
-
142
- function copyForAI(payload,btn){
143
- var text="# Mandu dev error snapshot\\n\\n"
144
- +"- kind: "+payload.kind+"\\n"
145
- +"- name: "+payload.name+"\\n"
146
- +"- message: "+payload.message+"\\n"
147
- +"- url: "+(payload.url||"")+"\\n"
148
- +"- routeId: "+(payload.routeId||"")+"\\n"
149
- +"- timestamp: "+new Date(payload.timestamp).toISOString()+"\\n\\n"
150
- +"## Stack\\n\\n\`\`\`\\n"+payload.stack+"\\n\`\`\`\\n";
151
- var done=function(){
152
- var prev=btn.textContent;
153
- btn.textContent="Copied!";
154
- setTimeout(function(){btn.textContent=prev;},1500);
155
- };
156
- if(navigator.clipboard&&navigator.clipboard.writeText){
157
- navigator.clipboard.writeText(text).then(done,function(){
158
- fallbackCopy(text);done();
159
- });
160
- }else{
161
- fallbackCopy(text);done();
162
- }
163
- }
164
-
165
- function fallbackCopy(text){
166
- try{
167
- var ta=document.createElement("textarea");
168
- ta.value=text;ta.style.position="fixed";ta.style.left="-9999px";
169
- document.body.appendChild(ta);ta.select();
170
- try{document.execCommand("copy");}catch(_){}
171
- document.body.removeChild(ta);
172
- }catch(_){}
173
- }
174
-
175
- function mount(payload){
176
- if(seen.has(payload))return;
177
- seen.add(payload);
178
- ensureStyleTag();
179
- var root=document.getElementById("__mandu-dev-overlay-root");
180
- if(!root){
181
- root=document.createElement("div");
182
- root.id="__mandu-dev-overlay-root";
183
- root.className="mandu-dev-overlay";
184
- root.setAttribute("role","dialog");
185
- root.setAttribute("aria-modal","true");
186
- root.setAttribute("aria-label","Mandu dev error overlay");
187
- (document.body||document.documentElement).appendChild(root);
188
- }
189
- var kindLabel=({ssr:"SSR render failed",window:"Uncaught error",unhandledrejection:"Unhandled promise rejection",manual:"Error"})[payload.kind]||"Error";
190
- var meta="";
191
- if(payload.routeId||payload.url){
192
- meta='<div class="mandu-dev-overlay__meta">'
193
- +(payload.routeId?'<div class="mandu-dev-overlay__meta-item"><span class="mandu-dev-overlay__meta-label">Route</span><span class="mandu-dev-overlay__meta-value">'+esc(payload.routeId)+'</span></div>':'')
194
- +(payload.url?'<div class="mandu-dev-overlay__meta-item"><span class="mandu-dev-overlay__meta-label">URL</span><span class="mandu-dev-overlay__meta-value">'+esc(payload.url)+'</span></div>':'')
195
- +'<div class="mandu-dev-overlay__meta-item"><span class="mandu-dev-overlay__meta-label">Time</span><span class="mandu-dev-overlay__meta-value">'+esc(new Date(payload.timestamp).toLocaleTimeString())+'</span></div>'
196
- +'</div>';
197
- }
198
- root.innerHTML='<div class="mandu-dev-overlay__panel">'
199
- +'<div class="mandu-dev-overlay__header">'
200
- +'<div class="mandu-dev-overlay__title">'
201
- +'<span class="mandu-dev-overlay__kind">'+esc(kindLabel)+'</span>'
202
- +'<span class="mandu-dev-overlay__name">'+esc(payload.name)+'</span>'
203
- +'</div>'
204
- +'<div class="mandu-dev-overlay__actions">'
205
- +'<button type="button" class="mandu-dev-overlay__btn mandu-dev-overlay__btn--primary" data-action="copy">Copy for AI</button>'
206
- +'<button type="button" class="mandu-dev-overlay__btn" data-action="close" aria-label="Close overlay">Close</button>'
207
- +'</div>'
208
- +'</div>'
209
- +'<div class="mandu-dev-overlay__body">'
210
- +'<p class="mandu-dev-overlay__message">'+esc(payload.message||"(no message)")+'</p>'
211
- +meta
212
- +'<h3 class="mandu-dev-overlay__section-title">Stack frames</h3>'
213
- +'<ol class="mandu-dev-overlay__frames">'+renderFrames(payload.frames)+'</ol>'
214
- +(payload.stack?'<h3 class="mandu-dev-overlay__section-title" style="margin-top:16px">Raw stack</h3><pre class="mandu-dev-overlay__stack">'+esc(payload.stack)+'</pre>':'')
215
- +'</div>'
216
- +'<div class="mandu-dev-overlay__footer">Dev-only overlay. Press <code>Esc</code> to dismiss. Never shipped in production builds.</div>'
217
- +'</div>';
218
- root.hidden=false;
219
-
220
- var onClick=function(e){
221
- var t=e.target;
222
- if(!t||!t.getAttribute)return;
223
- var a=t.getAttribute("data-action");
224
- if(a==="close")hide();
225
- else if(a==="copy")copyForAI(payload,t);
226
- };
227
- root.onclick=onClick;
228
- }
229
-
230
- function hide(){
231
- var root=document.getElementById("__mandu-dev-overlay-root");
232
- if(root)root.hidden=true;
233
- }
234
-
235
- function handle(err,kind,extra){
236
- try{
237
- var p=toPayload(err,kind);
238
- if(extra&&typeof extra==="object"){
239
- if(extra.routeId)p.routeId=extra.routeId;
240
- if(extra.url)p.url=extra.url;
241
- }
242
- mount(p);
243
- }catch(_){
244
- // overlay must never throw — silent drop.
245
- }
246
- }
247
-
248
- window.addEventListener("error",function(ev){
249
- if(ev&&ev.error)handle(ev.error,"window");
250
- else if(ev)handle(ev.message||"Script error",(\"window\"));
251
- });
252
- window.addEventListener("unhandledrejection",function(ev){
253
- handle(ev&&ev.reason,"unhandled-rejection");
254
- });
255
- window.addEventListener(EVT,function(ev){
256
- var d=ev&&ev.detail;
257
- if(!d)return;
258
- if(d.name||d.message||d.stack){
259
- var p={
260
- name:d.name||"Error",
261
- message:d.message||"",
262
- frames:d.frames||parseFrames(d.stack||""),
263
- stack:d.stack||"",
264
- kind:d.kind||"manual",
265
- timestamp:d.timestamp||Date.now(),
266
- routeId:d.routeId,
267
- url:d.url||(typeof location!=="undefined"?location.pathname+location.search:undefined),
268
- userAgent:typeof navigator!=="undefined"?navigator.userAgent:undefined
269
- };
270
- mount(p);
271
- }
272
- });
273
- document.addEventListener("keydown",function(e){
274
- if(e.key==="Escape")hide();
275
- });
276
-
277
- function readEmbedded(){
278
- var el=document.getElementById(PAYLOAD_ID);
279
- if(!el)return;
280
- try{
281
- var data=JSON.parse(el.textContent||"null");
282
- if(data&&typeof data==="object")mount(data);
283
- }catch(_){}
284
- }
285
- if(document.readyState==="loading"){
286
- document.addEventListener("DOMContentLoaded",readEmbedded);
287
- }else{
288
- readEmbedded();
289
- }
290
-
291
- // Public surface (tests + user code)
292
- window.__MANDU_DEV_OVERLAY__={show:function(e){handle(e,"manual");},hide:hide};
293
- })();`;
294
- }
295
-
296
- /** The serialized IIFE. Computed once at module-load. */
297
- export const OVERLAY_CLIENT_SCRIPT = buildOverlayClientScript();
298
-
299
- /** @internal test-only accessor so tests can recompute / inspect the script. */
300
- export const _testOnly_buildOverlayClientScript = buildOverlayClientScript;
1
+ /**
2
+ * Phase 18.α — Dev Error Overlay client IIFE.
3
+ *
4
+ * This file EXPORTS a string (`OVERLAY_CLIENT_SCRIPT`) that is inlined
5
+ * into the SSR `<head>` by the injector. It is NOT compiled as a
6
+ * module; the whole body runs in parse order on every dev page load.
7
+ *
8
+ * Size target: < 10 KB gzipped (current ≈ 2 KB gz). No dependencies.
9
+ * Only touches `window`, `document`, `navigator.clipboard`, and a tiny
10
+ * WeakSet.
11
+ *
12
+ * Listeners installed:
13
+ * - `window.onerror` → uncaught script errors
14
+ * - `unhandledrejection` → Promise rejections
15
+ * - custom event `__MANDU_ERROR__` → the server embeds a 500 payload
16
+ * in the HTML, fires this event on DOMContentLoaded, and the
17
+ * overlay picks it up. User code can also `dispatchEvent` it to
18
+ * surface synthetic errors.
19
+ *
20
+ * Everything scoped in an IIFE — NO globals leak except the single
21
+ * `__MANDU_OVERLAY_MOUNTED__` sentinel that prevents double-mount on
22
+ * HMR.
23
+ */
24
+ import { OVERLAY_STYLES } from "./overlay-styles";
25
+ import {
26
+ OVERLAY_CUSTOM_EVENT,
27
+ OVERLAY_MOUNTED_FLAG,
28
+ OVERLAY_PAYLOAD_ELEMENT_ID,
29
+ } from "./types";
30
+
31
+ /**
32
+ * Build the client-side IIFE body as a string. Parameterised by the
33
+ * style block and the two sentinel names so tests can verify the exact
34
+ * shape without re-declaring the constants.
35
+ */
36
+ function buildOverlayClientScript(): string {
37
+ // The IIFE below references the constants through string interpolation,
38
+ // NOT through imports — because it runs in the browser and has no
39
+ // module loader.
40
+ return `(function(){
41
+ var MOUNTED=${JSON.stringify(OVERLAY_MOUNTED_FLAG)};
42
+ var EVT=${JSON.stringify(OVERLAY_CUSTOM_EVENT)};
43
+ var PAYLOAD_ID=${JSON.stringify(OVERLAY_PAYLOAD_ELEMENT_ID)};
44
+ if(typeof window==="undefined"||typeof document==="undefined")return;
45
+ if(window[MOUNTED]===true)return;
46
+ window[MOUNTED]=true;
47
+
48
+ var STYLE=${JSON.stringify(OVERLAY_STYLES)};
49
+ var seen=new WeakSet();
50
+
51
+ function parseFrames(stack){
52
+ if(typeof stack!=="string"||stack.length===0)return [];
53
+ var lines=stack.split("\\n");
54
+ var out=[];
55
+ for(var i=0;i<lines.length;i++){
56
+ var raw=lines[i];
57
+ var t=raw.trim();
58
+ if(!t||t===stack.split("\\n")[0]&&/^[A-Z][a-zA-Z]*(?:Error)?:/.test(t))continue;
59
+ // Chrome: " at fn (file:line:col)"
60
+ // Firefox: "fn@file:line:col"
61
+ var m=t.match(/^at\\s+(.+?)\\s+\\((.+):(\\d+):(\\d+)\\)$/);
62
+ if(!m)m=t.match(/^at\\s+(.+):(\\d+):(\\d+)$/);
63
+ if(m&&m.length===5){
64
+ out.push({fn:m[1],file:m[2],line:parseInt(m[3],10),column:parseInt(m[4],10),raw:raw});
65
+ continue;
66
+ }
67
+ if(m&&m.length===4){
68
+ out.push({fn:"<anonymous>",file:m[1],line:parseInt(m[2],10),column:parseInt(m[3],10),raw:raw});
69
+ continue;
70
+ }
71
+ var ff=t.match(/^(.*?)@(.+):(\\d+):(\\d+)$/);
72
+ if(ff){
73
+ out.push({fn:ff[1]||"<anonymous>",file:ff[2],line:parseInt(ff[3],10),column:parseInt(ff[4],10),raw:raw});
74
+ continue;
75
+ }
76
+ out.push({fn:"<anonymous>",file:t,line:null,column:null,raw:raw});
77
+ }
78
+ return out;
79
+ }
80
+
81
+ function toPayload(err,kind){
82
+ var name="Error",message="",stack="";
83
+ if(err&&typeof err==="object"){
84
+ name=err.name||"Error";
85
+ message=typeof err.message==="string"?err.message:String(err.message||"");
86
+ stack=typeof err.stack==="string"?err.stack:"";
87
+ }else if(typeof err==="string"){
88
+ message=err;
89
+ }else if(err!=null){
90
+ try{message=String(err);}catch(_){message="<unserializable error>";}
91
+ }
92
+ return {
93
+ name:name,
94
+ message:message,
95
+ frames:parseFrames(stack),
96
+ stack:stack,
97
+ kind:kind,
98
+ timestamp:Date.now(),
99
+ url:typeof location!=="undefined"?location.pathname+location.search:undefined,
100
+ userAgent:typeof navigator!=="undefined"?navigator.userAgent:undefined
101
+ };
102
+ }
103
+
104
+ function esc(s){
105
+ if(s==null)return "";
106
+ return String(s).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;");
107
+ }
108
+
109
+ function fileHref(file,line,col){
110
+ // vscode://file/<abs>:<line>:<col> — falls back gracefully when the
111
+ // host OS has no handler. Relative paths get "//" prefix so the URL
112
+ // still parses, even though the editor may refuse to jump.
113
+ var p=file;
114
+ if(!/^[a-zA-Z]:|^\\//.test(p))p="/"+p;
115
+ var u="vscode://file"+p;
116
+ if(line)u+=":"+line;
117
+ if(col)u+=":"+col;
118
+ return u;
119
+ }
120
+
121
+ function renderFrames(frames){
122
+ if(!frames||frames.length===0)return '<li class="mandu-dev-overlay__frame"><span class="mandu-dev-overlay__frame-fn">&lt;no stack&gt;</span></li>';
123
+ var items=[];
124
+ for(var i=0;i<frames.length&&i<40;i++){
125
+ var f=frames[i];
126
+ var loc=esc(f.file)+(f.line?":"+f.line:"")+(f.column?":"+f.column:"");
127
+ var href=f.file?fileHref(f.file,f.line,f.column):"";
128
+ var locHtml=href?'<a class="mandu-dev-overlay__frame-link" href="'+esc(href)+'">'+loc+'</a>':loc;
129
+ items.push('<li class="mandu-dev-overlay__frame"><span class="mandu-dev-overlay__frame-fn">'+esc(f.fn||"<anonymous>")+'</span><span class="mandu-dev-overlay__frame-loc">'+locHtml+'</span></li>');
130
+ }
131
+ return items.join("");
132
+ }
133
+
134
+ function ensureStyleTag(){
135
+ if(document.getElementById("__mandu-dev-overlay-style"))return;
136
+ var s=document.createElement("style");
137
+ s.id="__mandu-dev-overlay-style";
138
+ s.textContent=STYLE;
139
+ (document.head||document.documentElement).appendChild(s);
140
+ }
141
+
142
+ function copyForAI(payload,btn){
143
+ var text="# Mandu dev error snapshot\\n\\n"
144
+ +"- kind: "+payload.kind+"\\n"
145
+ +"- name: "+payload.name+"\\n"
146
+ +"- message: "+payload.message+"\\n"
147
+ +"- url: "+(payload.url||"")+"\\n"
148
+ +"- routeId: "+(payload.routeId||"")+"\\n"
149
+ +"- timestamp: "+new Date(payload.timestamp).toISOString()+"\\n\\n"
150
+ +"## Stack\\n\\n\`\`\`\\n"+payload.stack+"\\n\`\`\`\\n";
151
+ var done=function(){
152
+ var prev=btn.textContent;
153
+ btn.textContent="Copied!";
154
+ setTimeout(function(){btn.textContent=prev;},1500);
155
+ };
156
+ if(navigator.clipboard&&navigator.clipboard.writeText){
157
+ navigator.clipboard.writeText(text).then(done,function(){
158
+ fallbackCopy(text);done();
159
+ });
160
+ }else{
161
+ fallbackCopy(text);done();
162
+ }
163
+ }
164
+
165
+ function fallbackCopy(text){
166
+ try{
167
+ var ta=document.createElement("textarea");
168
+ ta.value=text;ta.style.position="fixed";ta.style.left="-9999px";
169
+ document.body.appendChild(ta);ta.select();
170
+ try{document.execCommand("copy");}catch(_){}
171
+ document.body.removeChild(ta);
172
+ }catch(_){}
173
+ }
174
+
175
+ function mount(payload){
176
+ if(seen.has(payload))return;
177
+ seen.add(payload);
178
+ ensureStyleTag();
179
+ var root=document.getElementById("__mandu-dev-overlay-root");
180
+ if(!root){
181
+ root=document.createElement("div");
182
+ root.id="__mandu-dev-overlay-root";
183
+ root.className="mandu-dev-overlay";
184
+ root.setAttribute("role","dialog");
185
+ root.setAttribute("aria-modal","true");
186
+ root.setAttribute("aria-label","Mandu dev error overlay");
187
+ (document.body||document.documentElement).appendChild(root);
188
+ }
189
+ var kindLabel=({ssr:"SSR render failed",window:"Uncaught error",unhandledrejection:"Unhandled promise rejection",manual:"Error"})[payload.kind]||"Error";
190
+ var meta="";
191
+ if(payload.routeId||payload.url){
192
+ meta='<div class="mandu-dev-overlay__meta">'
193
+ +(payload.routeId?'<div class="mandu-dev-overlay__meta-item"><span class="mandu-dev-overlay__meta-label">Route</span><span class="mandu-dev-overlay__meta-value">'+esc(payload.routeId)+'</span></div>':'')
194
+ +(payload.url?'<div class="mandu-dev-overlay__meta-item"><span class="mandu-dev-overlay__meta-label">URL</span><span class="mandu-dev-overlay__meta-value">'+esc(payload.url)+'</span></div>':'')
195
+ +'<div class="mandu-dev-overlay__meta-item"><span class="mandu-dev-overlay__meta-label">Time</span><span class="mandu-dev-overlay__meta-value">'+esc(new Date(payload.timestamp).toLocaleTimeString())+'</span></div>'
196
+ +'</div>';
197
+ }
198
+ root.innerHTML='<div class="mandu-dev-overlay__panel">'
199
+ +'<div class="mandu-dev-overlay__header">'
200
+ +'<div class="mandu-dev-overlay__title">'
201
+ +'<span class="mandu-dev-overlay__kind">'+esc(kindLabel)+'</span>'
202
+ +'<span class="mandu-dev-overlay__name">'+esc(payload.name)+'</span>'
203
+ +'</div>'
204
+ +'<div class="mandu-dev-overlay__actions">'
205
+ +'<button type="button" class="mandu-dev-overlay__btn mandu-dev-overlay__btn--primary" data-action="copy">Copy for AI</button>'
206
+ +'<button type="button" class="mandu-dev-overlay__btn" data-action="close" aria-label="Close overlay">Close</button>'
207
+ +'</div>'
208
+ +'</div>'
209
+ +'<div class="mandu-dev-overlay__body">'
210
+ +'<p class="mandu-dev-overlay__message">'+esc(payload.message||"(no message)")+'</p>'
211
+ +meta
212
+ +'<h3 class="mandu-dev-overlay__section-title">Stack frames</h3>'
213
+ +'<ol class="mandu-dev-overlay__frames">'+renderFrames(payload.frames)+'</ol>'
214
+ +(payload.stack?'<h3 class="mandu-dev-overlay__section-title" style="margin-top:16px">Raw stack</h3><pre class="mandu-dev-overlay__stack">'+esc(payload.stack)+'</pre>':'')
215
+ +'</div>'
216
+ +'<div class="mandu-dev-overlay__footer">Dev-only overlay. Press <code>Esc</code> to dismiss. Never shipped in production builds.</div>'
217
+ +'</div>';
218
+ root.hidden=false;
219
+
220
+ var onClick=function(e){
221
+ var t=e.target;
222
+ if(!t||!t.getAttribute)return;
223
+ var a=t.getAttribute("data-action");
224
+ if(a==="close")hide();
225
+ else if(a==="copy")copyForAI(payload,t);
226
+ };
227
+ root.onclick=onClick;
228
+ }
229
+
230
+ function hide(){
231
+ var root=document.getElementById("__mandu-dev-overlay-root");
232
+ if(root)root.hidden=true;
233
+ }
234
+
235
+ function handle(err,kind,extra){
236
+ try{
237
+ var p=toPayload(err,kind);
238
+ if(extra&&typeof extra==="object"){
239
+ if(extra.routeId)p.routeId=extra.routeId;
240
+ if(extra.url)p.url=extra.url;
241
+ }
242
+ mount(p);
243
+ }catch(_){
244
+ // overlay must never throw — silent drop.
245
+ }
246
+ }
247
+
248
+ window.addEventListener("error",function(ev){
249
+ if(ev&&ev.error)handle(ev.error,"window");
250
+ else if(ev)handle(ev.message||"Script error",(\"window\"));
251
+ });
252
+ window.addEventListener("unhandledrejection",function(ev){
253
+ handle(ev&&ev.reason,"unhandled-rejection");
254
+ });
255
+ window.addEventListener(EVT,function(ev){
256
+ var d=ev&&ev.detail;
257
+ if(!d)return;
258
+ if(d.name||d.message||d.stack){
259
+ var p={
260
+ name:d.name||"Error",
261
+ message:d.message||"",
262
+ frames:d.frames||parseFrames(d.stack||""),
263
+ stack:d.stack||"",
264
+ kind:d.kind||"manual",
265
+ timestamp:d.timestamp||Date.now(),
266
+ routeId:d.routeId,
267
+ url:d.url||(typeof location!=="undefined"?location.pathname+location.search:undefined),
268
+ userAgent:typeof navigator!=="undefined"?navigator.userAgent:undefined
269
+ };
270
+ mount(p);
271
+ }
272
+ });
273
+ document.addEventListener("keydown",function(e){
274
+ if(e.key==="Escape")hide();
275
+ });
276
+
277
+ function readEmbedded(){
278
+ var el=document.getElementById(PAYLOAD_ID);
279
+ if(!el)return;
280
+ try{
281
+ var data=JSON.parse(el.textContent||"null");
282
+ if(data&&typeof data==="object")mount(data);
283
+ }catch(_){}
284
+ }
285
+ if(document.readyState==="loading"){
286
+ document.addEventListener("DOMContentLoaded",readEmbedded);
287
+ }else{
288
+ readEmbedded();
289
+ }
290
+
291
+ // Public surface (tests + user code)
292
+ window.__MANDU_DEV_OVERLAY__={show:function(e){handle(e,"manual");},hide:hide};
293
+ })();`;
294
+ }
295
+
296
+ /** The serialized IIFE. Computed once at module-load. */
297
+ export const OVERLAY_CLIENT_SCRIPT = buildOverlayClientScript();
298
+
299
+ /** @internal test-only accessor so tests can recompute / inspect the script. */
300
+ export const _testOnly_buildOverlayClientScript = buildOverlayClientScript;