@vistagenic/vista 0.2.16 → 0.3.2

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 (153) hide show
  1. package/bin/vista.js +184 -177
  2. package/dist/ai/agent.d.ts +37 -0
  3. package/dist/ai/agent.js +385 -0
  4. package/dist/ai/embeddings.d.ts +11 -0
  5. package/dist/ai/embeddings.js +71 -0
  6. package/dist/ai/index.d.ts +10 -0
  7. package/dist/ai/index.js +26 -0
  8. package/dist/ai/memory.d.ts +16 -0
  9. package/dist/ai/memory.js +39 -0
  10. package/dist/ai/observability.d.ts +21 -0
  11. package/dist/ai/observability.js +69 -0
  12. package/dist/ai/providers/anthropic.d.ts +2 -0
  13. package/dist/ai/providers/anthropic.js +190 -0
  14. package/dist/ai/providers/base.d.ts +7 -0
  15. package/dist/ai/providers/base.js +85 -0
  16. package/dist/ai/providers/gemini.d.ts +2 -0
  17. package/dist/ai/providers/gemini.js +194 -0
  18. package/dist/ai/providers/index.d.ts +5 -0
  19. package/dist/ai/providers/index.js +21 -0
  20. package/dist/ai/providers/mock.d.ts +8 -0
  21. package/dist/ai/providers/mock.js +77 -0
  22. package/dist/ai/providers/openai.d.ts +2 -0
  23. package/dist/ai/providers/openai.js +211 -0
  24. package/dist/ai/rag.d.ts +35 -0
  25. package/dist/ai/rag.js +110 -0
  26. package/dist/ai/react/index.d.ts +1 -0
  27. package/dist/ai/react/index.js +17 -0
  28. package/dist/ai/react/react-server.d.ts +1 -0
  29. package/dist/ai/react/react-server.js +17 -0
  30. package/dist/ai/react/use-agent.d.ts +23 -0
  31. package/dist/ai/react/use-agent.js +138 -0
  32. package/dist/ai/stream.d.ts +24 -0
  33. package/dist/ai/stream.js +109 -0
  34. package/dist/ai/tool.d.ts +11 -0
  35. package/dist/ai/tool.js +47 -0
  36. package/dist/ai/types.d.ts +117 -0
  37. package/dist/ai/types.js +5 -0
  38. package/dist/auth/core.d.ts +140 -0
  39. package/dist/auth/core.js +165 -0
  40. package/dist/auth/index.d.ts +20 -8
  41. package/dist/auth/index.js +369 -16
  42. package/dist/auth/react-server.d.ts +1 -0
  43. package/dist/auth/react-server.js +10 -0
  44. package/dist/auth/react.d.ts +18 -0
  45. package/dist/auth/react.js +71 -0
  46. package/dist/bin/build-rsc.js +602 -604
  47. package/dist/bin/build.js +389 -388
  48. package/dist/bin/deploy-output.d.ts +2 -7
  49. package/dist/bin/deploy-output.js +3 -76
  50. package/dist/bin/deploy.d.ts +7 -0
  51. package/dist/bin/deploy.js +102 -0
  52. package/dist/bin/dev-error-overlay-snippet.js +778 -552
  53. package/dist/bin/devtools-indicator-snippet.js +387 -387
  54. package/dist/bin/generate.js +510 -248
  55. package/dist/build/manifest.d.ts +169 -139
  56. package/dist/build/manifest.js +423 -367
  57. package/dist/build/rsc/client-manifest.d.ts +62 -52
  58. package/dist/build/rsc/client-manifest.js +295 -193
  59. package/dist/build/rsc/client-reference-plugin.d.ts +37 -37
  60. package/dist/build/rsc/client-reference-plugin.js +160 -160
  61. package/dist/build/rsc/native-scanner.d.ts +135 -123
  62. package/dist/build/rsc/native-scanner.js +203 -170
  63. package/dist/build/rsc/react-client-reference-manifest.d.ts +28 -22
  64. package/dist/build/rsc/react-client-reference-manifest.js +240 -219
  65. package/dist/build/rsc/rsc-renderer.d.ts +99 -99
  66. package/dist/build/rsc/rsc-renderer.js +263 -263
  67. package/dist/build/rsc/server-component-loader.d.ts +19 -19
  68. package/dist/build/rsc/server-component-loader.js +91 -91
  69. package/dist/build/rsc/server-manifest.d.ts +17 -0
  70. package/dist/build/rsc/server-manifest.js +20 -0
  71. package/dist/build/standalone.js +337 -334
  72. package/dist/build/webpack/plugins/vista-flight-plugin.js +5 -5
  73. package/dist/client/dynamic.react-server.d.ts +2 -0
  74. package/dist/client/dynamic.react-server.js +23 -0
  75. package/dist/client/link.react-server.d.ts +2 -0
  76. package/dist/client/link.react-server.js +11 -0
  77. package/dist/client/navigation.react-server.d.ts +1 -0
  78. package/dist/client/navigation.react-server.js +17 -0
  79. package/dist/client/router.react-server.d.ts +1 -0
  80. package/dist/client/router.react-server.js +17 -0
  81. package/dist/client/rsc-router.react-server.d.ts +1 -0
  82. package/dist/client/rsc-router.react-server.js +17 -0
  83. package/dist/client/script.react-server.d.ts +2 -0
  84. package/dist/client/script.react-server.js +23 -0
  85. package/dist/components/client-island.d.ts +34 -34
  86. package/dist/components/client-island.js +75 -75
  87. package/dist/config.d.ts +17 -0
  88. package/dist/config.js +60 -1
  89. package/dist/deploy/adapters/cloudflare.d.ts +2 -0
  90. package/dist/deploy/adapters/cloudflare.js +124 -0
  91. package/dist/deploy/adapters/docker.d.ts +2 -0
  92. package/dist/deploy/adapters/docker.js +112 -0
  93. package/dist/deploy/adapters/index.d.ts +15 -0
  94. package/dist/deploy/adapters/index.js +24 -0
  95. package/dist/deploy/adapters/netlify.d.ts +2 -0
  96. package/dist/deploy/adapters/netlify.js +115 -0
  97. package/dist/deploy/adapters/render.d.ts +2 -0
  98. package/dist/deploy/adapters/render.js +95 -0
  99. package/dist/deploy/adapters/vercel.d.ts +7 -0
  100. package/dist/deploy/adapters/vercel.js +164 -0
  101. package/dist/deploy/cli-runner.d.ts +8 -0
  102. package/dist/deploy/cli-runner.js +58 -0
  103. package/dist/deploy/detect.d.ts +6 -0
  104. package/dist/deploy/detect.js +77 -0
  105. package/dist/deploy/index.d.ts +24 -0
  106. package/dist/deploy/index.js +112 -0
  107. package/dist/deploy/preflight.d.ts +8 -0
  108. package/dist/deploy/preflight.js +80 -0
  109. package/dist/deploy/types.d.ts +48 -0
  110. package/dist/deploy/types.js +2 -0
  111. package/dist/deploy/utils.d.ts +18 -0
  112. package/dist/deploy/utils.js +70 -0
  113. package/dist/dev-error.d.ts +14 -0
  114. package/dist/dev-error.js +1763 -705
  115. package/dist/index.d.ts +23 -21
  116. package/dist/index.js +61 -57
  117. package/dist/server/cookie-parse.d.ts +4 -0
  118. package/dist/server/cookie-parse.js +14 -0
  119. package/dist/server/engine.js +7 -26
  120. package/dist/server/index.d.ts +109 -102
  121. package/dist/server/index.js +315 -286
  122. package/dist/server/middleware-runner.d.ts +125 -57
  123. package/dist/server/middleware-runner.js +615 -218
  124. package/dist/server/middleware-security.d.ts +36 -0
  125. package/dist/server/middleware-security.js +183 -0
  126. package/dist/server/module-compile-hook.js +695 -662
  127. package/dist/server/route-handler-registry.d.ts +65 -0
  128. package/dist/server/route-handler-registry.js +195 -0
  129. package/dist/server/route-patterns.d.ts +67 -0
  130. package/dist/server/route-patterns.js +186 -0
  131. package/dist/server/rsc-engine.js +75 -92
  132. package/dist/server/rsc-module-system.d.ts +33 -33
  133. package/dist/server/rsc-module-system.js +87 -87
  134. package/dist/server/rsc-upstream.js +892 -888
  135. package/dist/server/static-generator.js +10 -10
  136. package/dist/server/typed-api-runtime.d.ts +18 -0
  137. package/dist/server/typed-api-runtime.js +635 -507
  138. package/dist/server/vista-import-map.js +134 -123
  139. package/dist/stack/index.d.ts +34 -32
  140. package/dist/stack/index.js +49 -45
  141. package/dist/stack/server/caller.d.ts +13 -0
  142. package/dist/stack/server/caller.js +42 -0
  143. package/dist/stack/server/executor.d.ts +40 -36
  144. package/dist/stack/server/executor.js +222 -174
  145. package/dist/stack/server/index.d.ts +11 -10
  146. package/dist/stack/server/index.js +24 -23
  147. package/dist/stack/server/procedure.d.ts +20 -18
  148. package/dist/stack/server/procedure.js +66 -58
  149. package/dist/stack/server/types.d.ts +113 -100
  150. package/dist/theme/react-server.d.ts +10 -0
  151. package/dist/theme/react-server.js +16 -0
  152. package/package.json +28 -3
  153. package/LICENSE +0 -21
package/dist/dev-error.js CHANGED
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.VistaDevErrorBoundary = exports.DevErrorBoundary = void 0;
7
+ exports.fromCaughtError = fromCaughtError;
7
8
  exports.renderErrorHTML = renderErrorHTML;
8
9
  exports.ErrorOverlay = ErrorOverlay;
9
10
  exports.VistaErrorOverlay = ErrorOverlay;
@@ -18,317 +19,614 @@ const constants_1 = require("./constants");
18
19
  // ============================================================================
19
20
  // Styles + runtime helpers
20
21
  // ============================================================================
21
- const OVERLAY_STYLES = `
22
- * { box-sizing: border-box; }
23
- html, body {
24
- margin: 0;
25
- min-height: 100%;
26
- background: #0c0d10;
27
- color: #e8ebf1;
28
- font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
29
- }
30
- body {
31
- line-height: 1.45;
32
- }
33
- .vista-error-page-root {
34
- min-height: 100vh;
35
- position: relative;
36
- display: flex;
37
- align-items: center;
38
- justify-content: center;
39
- padding: 24px;
40
- overflow: hidden;
41
- }
42
- .vista-error-page-root[data-embedded='true'] {
43
- position: fixed;
44
- inset: 0;
45
- z-index: 2147483646;
46
- }
47
- .vista-error-backdrop {
48
- position: absolute;
49
- inset: 0;
50
- background: radial-gradient(circle at top, rgba(255, 89, 60, 0.22), rgba(10, 11, 15, 0.94) 44%);
51
- backdrop-filter: blur(5px);
52
- }
53
- .vista-error-panel {
54
- position: relative;
55
- width: min(980px, 100%);
56
- max-height: min(86vh, 860px);
57
- display: flex;
58
- flex-direction: column;
59
- border-radius: 16px;
60
- overflow: hidden;
61
- border: 1px solid rgba(255, 255, 255, 0.14);
62
- background: linear-gradient(180deg, rgba(24, 27, 33, 0.97), rgba(9, 11, 15, 0.98));
63
- box-shadow: 0 34px 92px rgba(0, 0, 0, 0.54);
64
- animation: vista-overlay-in 170ms ease;
65
- }
66
- .vista-error-header {
67
- display: flex;
68
- justify-content: space-between;
69
- align-items: flex-start;
70
- gap: 14px;
71
- padding: 15px 17px;
72
- border-bottom: 1px solid rgba(255, 255, 255, 0.12);
73
- background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0));
74
- }
75
- .vista-error-head-left {
76
- min-width: 0;
77
- display: flex;
78
- flex-direction: column;
79
- gap: 8px;
80
- }
81
- .vista-error-top-row {
82
- display: flex;
83
- align-items: center;
84
- gap: 10px;
85
- }
86
- .vista-error-badge {
87
- display: inline-flex;
88
- align-items: center;
89
- gap: 7px;
90
- height: 24px;
91
- padding: 0 10px;
92
- border-radius: 999px;
93
- border: 1px solid rgba(248, 113, 113, 0.48);
94
- background: rgba(248, 113, 113, 0.14);
95
- color: #fecaca;
96
- font-size: 11px;
97
- font-weight: 700;
98
- letter-spacing: 0.07em;
99
- text-transform: uppercase;
100
- white-space: nowrap;
101
- }
102
- .vista-error-badge-dot {
103
- width: 7px;
104
- height: 7px;
105
- border-radius: 999px;
106
- background: #f87171;
107
- box-shadow: 0 0 0 3px rgba(248, 113, 113, 0.24);
108
- }
109
- .vista-error-pagination {
110
- display: inline-flex;
111
- align-items: center;
112
- gap: 6px;
113
- padding: 2px 3px;
114
- border-radius: 999px;
115
- border: 1px solid rgba(255, 255, 255, 0.18);
116
- background: rgba(255, 255, 255, 0.04);
117
- }
118
- .vista-error-page-btn {
119
- width: 22px;
120
- height: 22px;
121
- display: inline-flex;
122
- align-items: center;
123
- justify-content: center;
124
- border: none;
125
- border-radius: 999px;
126
- background: rgba(255, 255, 255, 0.13);
127
- color: #f8fafc;
128
- font-size: 11px;
129
- line-height: 1;
130
- cursor: pointer;
131
- }
132
- .vista-error-page-btn:disabled {
133
- opacity: 0.35;
134
- cursor: not-allowed;
135
- }
136
- .vista-error-page-btn:not(:disabled):hover {
137
- background: rgba(255, 255, 255, 0.24);
138
- }
139
- .vista-error-page-count {
140
- min-width: 56px;
141
- text-align: center;
142
- font-size: 11px;
143
- font-weight: 630;
144
- color: rgba(241, 245, 249, 0.95);
145
- font-variant-numeric: tabular-nums;
146
- }
147
- .vista-error-title {
148
- margin: 0;
149
- font-size: 18px;
150
- line-height: 1.32;
151
- font-weight: 640;
152
- color: #f8fafc;
153
- letter-spacing: 0.01em;
154
- word-break: break-word;
155
- }
156
- .vista-error-meta {
157
- margin: 0;
158
- font-size: 12px;
159
- color: rgba(226, 232, 240, 0.72);
160
- }
161
- .vista-error-controls {
162
- display: flex;
163
- align-items: center;
164
- gap: 8px;
165
- }
166
- .vista-error-btn {
167
- width: 30px;
168
- height: 30px;
169
- padding: 0;
170
- border-radius: 9px;
171
- border: 1px solid rgba(255, 255, 255, 0.22);
172
- background: rgba(255, 255, 255, 0.04);
173
- color: #e2e8f0;
174
- display: inline-flex;
175
- align-items: center;
176
- justify-content: center;
177
- cursor: pointer;
178
- transition: all 120ms ease;
179
- }
180
- .vista-error-btn:hover {
181
- background: rgba(255, 255, 255, 0.12);
182
- border-color: rgba(255, 255, 255, 0.38);
183
- }
184
- .vista-error-btn svg {
185
- width: 14px;
186
- height: 14px;
187
- display: block;
188
- }
189
- .vista-error-btn:focus-visible,
190
- .vista-error-page-btn:focus-visible,
191
- .vista-error-location:focus-visible {
192
- outline: 2px solid rgba(255, 255, 255, 0.7);
193
- outline-offset: 2px;
194
- }
195
- .vista-error-body {
196
- padding: 16px 17px 17px;
197
- overflow: auto;
198
- display: grid;
199
- grid-template-columns: 1fr;
200
- gap: 11px;
201
- }
202
- .vista-error-card {
203
- border: 1px solid rgba(255, 255, 255, 0.11);
204
- border-radius: 11px;
205
- background: rgba(255, 255, 255, 0.03);
206
- padding: 12px;
207
- }
208
- .vista-error-card-title {
209
- margin: 0 0 8px;
210
- font-size: 11px;
211
- letter-spacing: 0.08em;
212
- text-transform: uppercase;
213
- font-weight: 700;
214
- color: rgba(226, 232, 240, 0.76);
215
- }
216
- .vista-error-pre {
217
- margin: 0;
218
- white-space: pre-wrap;
219
- word-break: break-word;
220
- font-size: 12.5px;
221
- line-height: 1.58;
222
- color: #f1f5f9;
223
- font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
224
- }
225
- .vista-error-tok-error { color: #fca5a5; font-weight: 640; }
226
- .vista-error-tok-path { color: #93c5fd; }
227
- .vista-error-tok-string { color: #86efac; }
228
- .vista-error-tok-stack { color: #cbd5e1; }
229
- .vista-error-tok-line { color: #fbbf24; }
230
- .vista-error-tok-caret { color: #f87171; font-weight: 700; }
231
- .vista-error-location {
232
- width: 100%;
233
- display: inline-flex;
234
- align-items: center;
235
- justify-content: flex-start;
236
- border: 1px solid rgba(255, 255, 255, 0.16);
237
- background: rgba(255, 255, 255, 0.04);
238
- color: #93c5fd;
239
- border-radius: 8px;
240
- padding: 8px 10px;
241
- font-size: 12px;
242
- font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
243
- cursor: pointer;
244
- }
245
- .vista-error-location:hover {
246
- background: rgba(255, 255, 255, 0.1);
247
- }
248
- .vista-error-page-root[data-minimized='true'] .vista-error-backdrop,
249
- .vista-error-page-root[data-minimized='true'] .vista-error-panel {
250
- display: none;
251
- }
252
- .vista-error-minimized-trigger {
253
- position: fixed;
254
- left: 28px;
255
- bottom: 22px;
256
- z-index: 2147483647;
257
- height: 40px;
258
- border-radius: 999px;
259
- border: 1px solid rgba(248, 113, 113, 0.9);
260
- background: rgba(53, 11, 16, 0.95);
261
- color: #fecaca;
262
- box-shadow: 0 10px 24px rgba(248, 113, 113, 0.24);
263
- display: inline-flex;
264
- align-items: center;
265
- gap: 6px;
266
- padding: 0 10px;
267
- cursor: pointer;
268
- }
269
- .vista-error-minimized-trigger[hidden] {
270
- display: none;
271
- }
272
- .vista-error-minimized-logo {
273
- width: 14px;
274
- height: 14px;
275
- display: block;
276
- }
277
- .vista-error-minimized-close {
278
- font-size: 12px;
279
- line-height: 1;
280
- color: #fca5a5;
281
- }
282
- .vista-error-minimized-count {
283
- font-size: 11px;
284
- font-weight: 670;
285
- font-variant-numeric: tabular-nums;
286
- }
287
- @keyframes vista-overlay-in {
288
- from { opacity: 0; transform: translateY(6px) scale(0.99); }
289
- to { opacity: 1; transform: translateY(0) scale(1); }
290
- }
291
- @media (max-width: 860px) {
292
- .vista-error-page-root { padding: 12px; }
293
- .vista-error-header { flex-direction: column; }
294
- .vista-error-controls { width: 100%; justify-content: flex-end; }
295
- .vista-error-title { font-size: 16px; }
296
- .vista-error-minimized-trigger { left: 16px; bottom: 14px; }
297
- }
22
+ const OVERLAY_STYLES = `
23
+ * { box-sizing: border-box; }
24
+ html, body {
25
+ margin: 0;
26
+ height: 100%;
27
+ overflow: hidden;
28
+ background: #050505;
29
+ color: #ededed;
30
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
31
+ }
32
+ body { line-height: 1.5; }
33
+ .vista-error-page-root {
34
+ min-height: 100vh;
35
+ height: 100vh;
36
+ position: relative;
37
+ display: flex;
38
+ align-items: center;
39
+ justify-content: center;
40
+ padding: 20px;
41
+ overflow: hidden;
42
+ }
43
+ .vista-error-page-root[data-embedded='true'] {
44
+ position: fixed;
45
+ inset: 0;
46
+ z-index: 2147483646;
47
+ }
48
+ .vista-error-backdrop {
49
+ position: absolute;
50
+ inset: 0;
51
+ background: rgba(0, 0, 0, 0.72);
52
+ }
53
+ .vista-error-panel {
54
+ position: relative;
55
+ width: min(1180px, calc(100vw - 32px));
56
+ height: min(820px, calc(100vh - 32px));
57
+ display: flex;
58
+ flex-direction: column;
59
+ border-radius: 8px;
60
+ overflow: hidden;
61
+ background: #1e1e1e;
62
+ border: 1px solid #2b2b2b;
63
+ box-shadow: 0 24px 80px rgba(0, 0, 0, 0.62);
64
+ animation: vista-overlay-in 160ms ease;
65
+ }
66
+ .vista-ide-workbench {
67
+ display: flex;
68
+ flex: 1;
69
+ min-height: 0;
70
+ }
71
+ .vista-ide-activity {
72
+ width: 48px;
73
+ flex-shrink: 0;
74
+ display: flex;
75
+ flex-direction: column;
76
+ align-items: center;
77
+ padding-top: 8px;
78
+ background: #181818;
79
+ border-right: 1px solid #2b2b2b;
80
+ }
81
+ .vista-ide-activity-item {
82
+ width: 48px;
83
+ height: 40px;
84
+ display: inline-flex;
85
+ align-items: center;
86
+ justify-content: center;
87
+ color: #858585;
88
+ }
89
+ .vista-ide-activity-item.is-active {
90
+ color: #ffffff;
91
+ box-shadow: inset 2px 0 0 #0078d4;
92
+ }
93
+ .vista-ide-activity-item svg {
94
+ width: 22px;
95
+ height: 22px;
96
+ display: block;
97
+ }
98
+ .vista-ide-main {
99
+ display: flex;
100
+ flex-direction: column;
101
+ flex: 1;
102
+ min-width: 0;
103
+ min-height: 0;
104
+ }
105
+ .vista-ide-titlebar {
106
+ display: flex;
107
+ align-items: center;
108
+ justify-content: space-between;
109
+ gap: 12px;
110
+ height: 38px;
111
+ padding: 0 10px;
112
+ background: #181818;
113
+ border-bottom: 1px solid #2b2b2b;
114
+ flex-shrink: 0;
115
+ }
116
+ .vista-ide-traffic {
117
+ display: inline-flex;
118
+ align-items: center;
119
+ gap: 6px;
120
+ width: 54px;
121
+ }
122
+ .vista-ide-traffic span {
123
+ width: 10px;
124
+ height: 10px;
125
+ border-radius: 999px;
126
+ }
127
+ .vista-ide-traffic .is-close { background: #ff5f57; }
128
+ .vista-ide-traffic .is-min { background: #febc2e; }
129
+ .vista-ide-traffic .is-max { background: #28c840; }
130
+ .vista-ide-title {
131
+ min-width: 0;
132
+ flex: 1;
133
+ text-align: center;
134
+ color: #c6c6c6;
135
+ font-size: 12px;
136
+ font-weight: 500;
137
+ overflow: hidden;
138
+ text-overflow: ellipsis;
139
+ white-space: nowrap;
140
+ }
141
+ .vista-error-toolbar {
142
+ display: flex;
143
+ align-items: center;
144
+ gap: 8px;
145
+ flex-shrink: 0;
146
+ }
147
+ .vista-ide-tabbar {
148
+ display: flex;
149
+ align-items: stretch;
150
+ justify-content: space-between;
151
+ height: 35px;
152
+ background: #181818;
153
+ border-bottom: 1px solid #2b2b2b;
154
+ flex-shrink: 0;
155
+ }
156
+ .vista-ide-tabs {
157
+ display: flex;
158
+ min-width: 0;
159
+ overflow: hidden;
160
+ scrollbar-width: none;
161
+ }
162
+ .vista-ide-tabs::-webkit-scrollbar { display: none; }
163
+ .vista-ide-tab {
164
+ display: inline-flex;
165
+ align-items: center;
166
+ gap: 8px;
167
+ height: 35px;
168
+ padding: 0 14px;
169
+ border: 0;
170
+ border-right: 1px solid #2b2b2b;
171
+ background: #1e1e1e;
172
+ color: #cccccc;
173
+ font-size: 12px;
174
+ cursor: pointer;
175
+ box-shadow: inset 0 -1px 0 #0078d4;
176
+ }
177
+ .vista-ide-tab:hover { color: #fff; }
178
+ .vista-ide-tab.is-inactive {
179
+ background: #181818;
180
+ color: #8b8b8b;
181
+ box-shadow: none;
182
+ }
183
+ .vista-ide-tab-icon {
184
+ width: 14px;
185
+ height: 14px;
186
+ flex-shrink: 0;
187
+ }
188
+ .vista-ide-crumbs {
189
+ display: flex;
190
+ align-items: center;
191
+ gap: 6px;
192
+ height: 24px;
193
+ padding: 0 12px;
194
+ background: #1e1e1e;
195
+ border-bottom: 1px solid #2b2b2b;
196
+ color: #8b8b8b;
197
+ font-size: 11px;
198
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
199
+ white-space: nowrap;
200
+ overflow: hidden;
201
+ text-overflow: ellipsis;
202
+ }
203
+ .vista-error-code {
204
+ display: flex;
205
+ flex-direction: column;
206
+ flex: 1;
207
+ min-height: 0;
208
+ background: #1e1e1e;
209
+ overflow: hidden;
210
+ }
211
+ .vista-error-editor-host {
212
+ flex: 1;
213
+ min-height: 0;
214
+ overflow: auto;
215
+ }
216
+ .vista-error-editor {
217
+ margin: 0;
218
+ min-height: 100%;
219
+ padding: 8px 0 12px;
220
+ overflow: visible;
221
+ font-size: 13px;
222
+ line-height: 20px;
223
+ font-family: ui-monospace, SFMono-Regular, "Cascadia Code", Menlo, Consolas, monospace;
224
+ background: #1e1e1e;
225
+ }
226
+ .vista-error-editor-line {
227
+ display: grid;
228
+ grid-template-columns: 56px minmax(0, 1fr);
229
+ min-height: 20px;
230
+ }
231
+ .vista-error-editor-line.is-error {
232
+ background: rgba(248, 81, 73, 0.12);
233
+ }
234
+ .vista-error-editor-line.is-server {
235
+ background: rgba(248, 81, 73, 0.1);
236
+ }
237
+ .vista-error-editor-line.is-client {
238
+ background: rgba(63, 185, 80, 0.1);
239
+ }
240
+ .vista-ide-source-badge {
241
+ padding: 0 7px;
242
+ border-radius: 999px;
243
+ font-size: 10px;
244
+ font-weight: 600;
245
+ letter-spacing: 0.04em;
246
+ text-transform: uppercase;
247
+ background: rgba(255, 255, 255, 0.12);
248
+ }
249
+ .vista-ide-source-badge.is-server { background: #1f6feb; }
250
+ .vista-ide-source-badge.is-client { background: #238636; }
251
+ .vista-ide-source-badge.is-hydration { background: #9e6a03; }
252
+ .vista-error-hint {
253
+ margin: 8px 0 0;
254
+ color: #8b949e;
255
+ font-size: 12px;
256
+ line-height: 1.5;
257
+ }
258
+ .vista-error-hint[hidden] { display: none; }
259
+ .vista-error-problem-icon.is-hydration { background: #d29922; }
260
+ .vista-error-problem-icon.is-server { background: #58a6ff; }
261
+ .vista-error-kind.is-hydration { color: #d29922; }
262
+ .vista-error-kind.is-server { color: #58a6ff; }
263
+ .vista-error-gutter {
264
+ padding: 0 12px 0 0;
265
+ border-right: 1px solid #2b2b2b;
266
+ color: #6e7681;
267
+ text-align: right;
268
+ user-select: none;
269
+ font-variant-numeric: tabular-nums;
270
+ }
271
+ .vista-error-editor-line.is-error .vista-error-gutter { color: #f85149; font-weight: 600; }
272
+ .vista-error-source {
273
+ position: relative;
274
+ padding: 0 16px 0 12px;
275
+ color: #d4d4d4;
276
+ white-space: pre;
277
+ overflow: hidden;
278
+ }
279
+ .vista-error-squiggle {
280
+ position: absolute;
281
+ left: 12px;
282
+ bottom: 0;
283
+ height: 4px;
284
+ width: 3.2ch;
285
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='6' height='4' viewBox='0 0 6 4'%3E%3Cpath d='M0 3 Q1.5 0 3 3 T6 3' fill='none' stroke='%23f85149' stroke-width='1.4'/%3E%3C/svg%3E");
286
+ background-repeat: repeat-x;
287
+ background-size: 6px 4px;
288
+ pointer-events: none;
289
+ }
290
+ .vista-tok-kw { color: #c586c0; }
291
+ .vista-tok-str { color: #ce9178; }
292
+ .vista-tok-cmt { color: #6a9955; font-style: italic; }
293
+ .vista-tok-tag { color: #4ec9b0; }
294
+ .vista-tok-num { color: #b5cea8; }
295
+ .vista-ide-statusbar {
296
+ display: flex;
297
+ align-items: center;
298
+ justify-content: space-between;
299
+ gap: 12px;
300
+ height: 22px;
301
+ padding: 0 10px;
302
+ background: #007acc;
303
+ color: #ffffff;
304
+ font-size: 12px;
305
+ flex-shrink: 0;
306
+ }
307
+ .vista-ide-statusbar span { white-space: nowrap; }
308
+ .vista-ide-panel {
309
+ display: flex;
310
+ flex-direction: column;
311
+ background: #181818;
312
+ border-top: 1px solid #2b2b2b;
313
+ overflow: hidden;
314
+ flex: 0 0 auto;
315
+ max-height: 38%;
316
+ min-height: 148px;
317
+ }
318
+ .vista-ide-panel-tabs {
319
+ display: flex;
320
+ align-items: center;
321
+ gap: 16px;
322
+ height: 32px;
323
+ padding: 0 8px 0 12px;
324
+ border-bottom: 1px solid #2b2b2b;
325
+ color: #bbbbbb;
326
+ font-size: 11px;
327
+ font-weight: 600;
328
+ letter-spacing: 0.06em;
329
+ flex-shrink: 0;
330
+ }
331
+ .vista-ide-panel-tabs .is-active {
332
+ color: #ffffff;
333
+ box-shadow: inset 0 -1px 0 #ffffff;
334
+ padding-bottom: 8px;
335
+ }
336
+ .vista-ide-panel-toggle {
337
+ margin-left: auto;
338
+ }
339
+ .vista-ide-panel-toggle[hidden] { display: none; }
340
+ .vista-ide-panel-toggle .vista-ide-icon-restore { display: none; }
341
+ .vista-ide-main[data-panel-expanded='true'] .vista-ide-tabbar,
342
+ .vista-ide-main[data-panel-expanded='true'] .vista-ide-crumbs,
343
+ .vista-ide-main[data-panel-expanded='true'] .vista-error-code,
344
+ .vista-ide-main[data-panel-expanded='true'] .vista-ide-statusbar {
345
+ display: none;
346
+ }
347
+ .vista-ide-main[data-panel-expanded='true'] .vista-ide-panel {
348
+ flex: 1;
349
+ max-height: none;
350
+ min-height: 0;
351
+ border-top: 0;
352
+ }
353
+ .vista-ide-main[data-panel-expanded='true'] .vista-ide-icon-expand { display: none; }
354
+ .vista-ide-main[data-panel-expanded='true'] .vista-ide-icon-restore { display: block; }
355
+ .vista-ide-main[data-terminal='true'] .vista-ide-tabbar,
356
+ .vista-ide-main[data-terminal='true'] .vista-ide-crumbs,
357
+ .vista-ide-main[data-terminal='true'] .vista-error-code,
358
+ .vista-ide-main[data-terminal='true'] .vista-ide-statusbar {
359
+ display: none;
360
+ }
361
+ .vista-ide-main[data-terminal='true'] .vista-ide-panel {
362
+ flex: 1;
363
+ max-height: none;
364
+ min-height: 0;
365
+ border-top: 0;
366
+ }
367
+ .vista-ide-main[data-terminal='true'] .vista-ide-panel-toggle { display: none; }
368
+ .vista-error-body {
369
+ flex: 1;
370
+ min-height: 0;
371
+ overflow: auto;
372
+ padding: 10px 14px 14px;
373
+ }
374
+ .vista-error-editor-host,
375
+ .vista-error-body,
376
+ .vista-ide-panel {
377
+ scrollbar-width: thin;
378
+ scrollbar-color: rgba(255, 255, 255, 0.16) transparent;
379
+ }
380
+ .vista-error-editor-host::-webkit-scrollbar,
381
+ .vista-error-body::-webkit-scrollbar,
382
+ .vista-ide-panel::-webkit-scrollbar {
383
+ width: 6px;
384
+ height: 6px;
385
+ }
386
+ .vista-error-editor-host::-webkit-scrollbar-track,
387
+ .vista-error-body::-webkit-scrollbar-track,
388
+ .vista-ide-panel::-webkit-scrollbar-track,
389
+ .vista-error-editor-host::-webkit-scrollbar-corner,
390
+ .vista-error-body::-webkit-scrollbar-corner,
391
+ .vista-ide-panel::-webkit-scrollbar-corner {
392
+ background: transparent;
393
+ }
394
+ .vista-error-editor-host::-webkit-scrollbar-thumb,
395
+ .vista-error-body::-webkit-scrollbar-thumb,
396
+ .vista-ide-panel::-webkit-scrollbar-thumb {
397
+ background-color: rgba(255, 255, 255, 0.16);
398
+ border-radius: 999px;
399
+ }
400
+ .vista-error-editor-host::-webkit-scrollbar-thumb:hover,
401
+ .vista-error-body::-webkit-scrollbar-thumb:hover,
402
+ .vista-ide-panel::-webkit-scrollbar-thumb:hover {
403
+ background-color: rgba(255, 255, 255, 0.34);
404
+ }
405
+ .vista-error-kind {
406
+ margin: 0;
407
+ color: #f85149;
408
+ font-size: 12px;
409
+ font-weight: 600;
410
+ }
411
+ .vista-error-headline {
412
+ margin: 6px 0 0;
413
+ color: #e6edf3;
414
+ font-size: 13px;
415
+ font-weight: 500;
416
+ line-height: 1.5;
417
+ word-break: break-word;
418
+ }
419
+ .vista-error-detail {
420
+ margin: 6px 0 0;
421
+ color: #8b949e;
422
+ font-size: 12px;
423
+ line-height: 1.5;
424
+ white-space: pre-wrap;
425
+ word-break: break-word;
426
+ }
427
+ .vista-error-problem {
428
+ display: flex;
429
+ gap: 8px;
430
+ align-items: flex-start;
431
+ padding: 8px 2px 4px;
432
+ }
433
+ .vista-error-problem-icon {
434
+ width: 14px;
435
+ height: 14px;
436
+ margin-top: 2px;
437
+ border-radius: 999px;
438
+ background: #f85149;
439
+ flex-shrink: 0;
440
+ }
441
+ .vista-error-detail[hidden],
442
+ .vista-error-code[hidden],
443
+ .vista-error-stack[hidden] { display: none; }
444
+ .vista-error-stack { margin-top: 8px; }
445
+ .vista-error-stack-title {
446
+ margin: 0 0 6px;
447
+ color: #bbbbbb;
448
+ font-size: 11px;
449
+ font-weight: 600;
450
+ letter-spacing: 0.06em;
451
+ }
452
+ .vista-error-frames {
453
+ display: flex;
454
+ flex-direction: column;
455
+ }
456
+ .vista-error-frame {
457
+ display: flex;
458
+ flex-direction: column;
459
+ align-items: flex-start;
460
+ gap: 1px;
461
+ width: 100%;
462
+ margin: 0;
463
+ padding: 6px 8px;
464
+ border: 0;
465
+ border-radius: 0;
466
+ background: transparent;
467
+ color: inherit;
468
+ text-align: left;
469
+ cursor: pointer;
470
+ }
471
+ .vista-error-frame:hover { background: #2a2d2e; }
472
+ .vista-error-frame-name {
473
+ font-size: 12px;
474
+ font-weight: 500;
475
+ color: #e6edf3;
476
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
477
+ }
478
+ .vista-error-frame-loc {
479
+ font-size: 11px;
480
+ color: #8b949e;
481
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
482
+ }
483
+ .vista-error-pagination {
484
+ display: inline-flex;
485
+ align-items: center;
486
+ gap: 2px;
487
+ }
488
+ .vista-error-pagination[hidden] { display: none; }
489
+ .vista-error-page-btn {
490
+ width: 28px;
491
+ height: 28px;
492
+ display: inline-flex;
493
+ align-items: center;
494
+ justify-content: center;
495
+ border: 0;
496
+ border-radius: 6px;
497
+ background: transparent;
498
+ color: #a1a1a1;
499
+ font-size: 16px;
500
+ line-height: 1;
501
+ cursor: pointer;
502
+ }
503
+ .vista-error-page-btn:disabled { opacity: 0.28; cursor: default; }
504
+ .vista-error-page-btn:not(:disabled):hover { background: #2a2a2a; color: #ededed; }
505
+ .vista-error-page-count {
506
+ min-width: 36px;
507
+ padding: 0 4px;
508
+ text-align: center;
509
+ font-size: 13px;
510
+ font-weight: 500;
511
+ color: #a1a1a1;
512
+ font-variant-numeric: tabular-nums;
513
+ }
514
+ .vista-error-brand {
515
+ display: inline-flex;
516
+ align-items: center;
517
+ gap: 8px;
518
+ color: #a1a1a1;
519
+ font-size: 13px;
520
+ font-weight: 500;
521
+ white-space: nowrap;
522
+ }
523
+ .vista-error-brand-dot {
524
+ width: 8px;
525
+ height: 8px;
526
+ border-radius: 999px;
527
+ background: #22c55e;
528
+ box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.16);
529
+ }
530
+ .vista-error-toolbar-actions {
531
+ display: inline-flex;
532
+ align-items: center;
533
+ gap: 2px;
534
+ }
535
+ .vista-error-icon-btn {
536
+ width: 28px;
537
+ height: 28px;
538
+ padding: 0;
539
+ border: 0;
540
+ border-radius: 6px;
541
+ background: transparent;
542
+ color: #a1a1a1;
543
+ display: inline-flex;
544
+ align-items: center;
545
+ justify-content: center;
546
+ cursor: pointer;
547
+ }
548
+ .vista-error-icon-btn:hover { background: #2a2a2a; color: #ededed; }
549
+ .vista-ide-panel-tabs .vista-error-icon-btn:hover { background: #2a2a2a; }
550
+ .vista-error-icon-btn svg { width: 14px; height: 14px; display: block; }
551
+ .vista-error-icon-btn:focus-visible,
552
+ .vista-error-page-btn:focus-visible,
553
+ .vista-ide-tab:focus-visible {
554
+ outline: 2px solid #ededed;
555
+ outline-offset: 1px;
556
+ }
557
+ .vista-error-page-root[data-minimized='true'] .vista-error-backdrop,
558
+ .vista-error-page-root[data-minimized='true'] .vista-error-panel {
559
+ display: none;
560
+ }
561
+ .vista-error-minimized-trigger {
562
+ position: fixed;
563
+ left: 20px;
564
+ bottom: 20px;
565
+ z-index: 2147483647;
566
+ height: 36px;
567
+ border-radius: 999px;
568
+ border: 1px solid #262626;
569
+ background: #0a0a0a;
570
+ color: #ededed;
571
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
572
+ display: inline-flex;
573
+ align-items: center;
574
+ gap: 8px;
575
+ padding: 0 12px 0 10px;
576
+ cursor: pointer;
577
+ }
578
+ .vista-error-minimized-trigger[hidden] { display: none; }
579
+ .vista-error-minimized-logo { width: 13px; height: 13px; display: block; }
580
+ .vista-error-minimized-close { font-size: 14px; line-height: 1; color: #a1a1a1; }
581
+ .vista-error-minimized-count {
582
+ font-size: 12px;
583
+ font-weight: 600;
584
+ font-variant-numeric: tabular-nums;
585
+ color: #ff6369;
586
+ }
587
+ @keyframes vista-overlay-in {
588
+ from { opacity: 0; transform: translateY(8px) scale(0.98); }
589
+ to { opacity: 1; transform: translateY(0) scale(1); }
590
+ }
591
+ @media (max-width: 720px) {
592
+ .vista-error-page-root { padding: 16px 10px; }
593
+ .vista-error-headline { font-size: 14px; }
594
+ .vista-error-minimized-trigger { left: 12px; bottom: 12px; }
595
+ }
298
596
  `;
299
- const OVERLAY_SCRIPT = `
300
- function vistaReload() {
301
- window.location.reload();
302
- }
303
-
304
- function vistaOpenInEditor(file, line, column) {
305
- if (!file) return;
306
- var normalized = String(file).replace(/\\\\/g, '/');
307
- var lineNum = Number(line || 1);
308
- var colNum = Number(column || 1);
309
- window.location.href = 'vscode://file/' + normalized + ':' + lineNum + ':' + colNum;
310
- }
311
-
312
- function vistaCopyText(value) {
313
- var text = String(value || '');
314
- if (!text) return;
315
- if (navigator.clipboard && navigator.clipboard.writeText) {
316
- navigator.clipboard.writeText(text).catch(function () {});
317
- return;
318
- }
319
- var textarea = document.createElement('textarea');
320
- textarea.value = text;
321
- textarea.style.position = 'fixed';
322
- textarea.style.opacity = '0';
323
- textarea.style.pointerEvents = 'none';
324
- document.body.appendChild(textarea);
325
- textarea.focus();
326
- textarea.select();
327
- try {
328
- document.execCommand('copy');
329
- } catch (e) {}
330
- document.body.removeChild(textarea);
331
- }
597
+ const OVERLAY_SCRIPT = `
598
+ function vistaReload() {
599
+ window.location.reload();
600
+ }
601
+
602
+ function vistaOpenInEditor(file, line, column) {
603
+ if (!file) return;
604
+ var normalized = String(file).replace(/\\\\/g, '/');
605
+ var lineNum = Number(line || 1);
606
+ var colNum = Number(column || 1);
607
+ window.location.href = 'vscode://file/' + normalized + ':' + lineNum + ':' + colNum;
608
+ }
609
+
610
+ function vistaCopyText(value) {
611
+ var text = String(value || '');
612
+ if (!text) return;
613
+ if (navigator.clipboard && navigator.clipboard.writeText) {
614
+ navigator.clipboard.writeText(text).catch(function () {});
615
+ return;
616
+ }
617
+ var textarea = document.createElement('textarea');
618
+ textarea.value = text;
619
+ textarea.style.position = 'fixed';
620
+ textarea.style.opacity = '0';
621
+ textarea.style.pointerEvents = 'none';
622
+ document.body.appendChild(textarea);
623
+ textarea.focus();
624
+ textarea.select();
625
+ try {
626
+ document.execCommand('copy');
627
+ } catch (e) {}
628
+ document.body.removeChild(textarea);
629
+ }
332
630
  `;
333
631
  // ============================================================================
334
632
  // Helpers
@@ -346,16 +644,20 @@ function escapeForInlineScript(text) {
346
644
  }
347
645
  function colorizeLineHtml(line) {
348
646
  let escaped = escapeHtml(line);
647
+ const isActive = /^\s*>/.test(line);
349
648
  if (/^\s*\^+/.test(line)) {
350
649
  return `<span class="vista-error-tok-caret">${escaped}</span>`;
351
650
  }
352
651
  if (/^\s*at\s+/.test(line)) {
353
652
  return `<span class="vista-error-tok-stack">${escaped}</span>`;
354
653
  }
355
- const numbered = escaped.match(/^(\s*\d+)(\s*\|)(.*)$/);
654
+ const numbered = escaped.match(/^(\s*>?\s*\d+)(\s*\|)(.*)$/);
356
655
  if (numbered) {
357
656
  escaped = `<span class="vista-error-tok-line">${numbered[1]}</span>${numbered[2]}${numbered[3]}`;
358
657
  }
658
+ if (isActive) {
659
+ escaped = `<span class="vista-error-tok-active">${escaped}</span>`;
660
+ }
359
661
  escaped = escaped.replace(/((?:[A-Za-z]:)?[\\/\w.@%:-]+\.(?:tsx?|jsx?|mjs|cjs|css|json|mdx?)(?::\d+(?::\d+)?)?)/g, '<span class="vista-error-tok-path">$1</span>');
360
662
  escaped = escaped.replace(/(&quot;[^&]+&quot;|&#039;[^&]+&#039;|`[^`]+`)/g, '<span class="vista-error-tok-string">$1</span>');
361
663
  escaped = escaped.replace(/(TypeError:|ReferenceError:|SyntaxError:|Error:|Cannot find module|Module not found|Build Error|Runtime Error|Hydration Error)/g, '<span class="vista-error-tok-error">$1</span>');
@@ -367,6 +669,333 @@ function colorizeBlockHtml(value) {
367
669
  .map((line) => colorizeLineHtml(line))
368
670
  .join('\n');
369
671
  }
672
+ const SOURCE_KEYWORDS = /^(import|from|function|return|const|let|var|export|default|class|extends|if|else|async|await|new|type|interface|true|false|null|undefined|typeof|void|as|of|in|for|while|switch|case|break|continue|try|catch|finally|this)\b/;
673
+ function highlightSource(text) {
674
+ let html = '';
675
+ let i = 0;
676
+ while (i < text.length) {
677
+ const ch = text[i];
678
+ if (ch === "'" || ch === '"' || ch === '`') {
679
+ let j = i + 1;
680
+ while (j < text.length && text[j] !== ch) {
681
+ j += text[j] === '\\' ? 2 : 1;
682
+ }
683
+ html += `<span class="vista-tok-str">${escapeHtml(text.slice(i, Math.min(j + 1, text.length)))}</span>`;
684
+ i = j + 1;
685
+ continue;
686
+ }
687
+ if (ch === '/' && text[i + 1] === '/') {
688
+ html += `<span class="vista-tok-cmt">${escapeHtml(text.slice(i))}</span>`;
689
+ break;
690
+ }
691
+ if (ch === '<' && /[A-Za-z/]/.test(text[i + 1] || '')) {
692
+ const tag = text.slice(i).match(/^<\/?[A-Za-z][\w.-]*/);
693
+ if (tag) {
694
+ html += `<span class="vista-tok-tag">${escapeHtml(tag[0])}</span>`;
695
+ i += tag[0].length;
696
+ continue;
697
+ }
698
+ }
699
+ if (/[0-9]/.test(ch)) {
700
+ const num = text.slice(i).match(/^[0-9]+(?:\.[0-9]+)?/);
701
+ if (num) {
702
+ html += `<span class="vista-tok-num">${escapeHtml(num[0])}</span>`;
703
+ i += num[0].length;
704
+ continue;
705
+ }
706
+ }
707
+ if (/[A-Za-z_$]/.test(ch)) {
708
+ const ident = text.slice(i).match(/^[A-Za-z_$][\w$]*/);
709
+ if (ident) {
710
+ html += SOURCE_KEYWORDS.test(ident[0])
711
+ ? `<span class="vista-tok-kw">${escapeHtml(ident[0])}</span>`
712
+ : escapeHtml(ident[0]);
713
+ i += ident[0].length;
714
+ continue;
715
+ }
716
+ }
717
+ html += escapeHtml(ch);
718
+ i += 1;
719
+ }
720
+ return html;
721
+ }
722
+ function parseCodeFrameLines(codeFrame) {
723
+ const rawLines = String(codeFrame || '').split(/\r?\n/);
724
+ const rows = [];
725
+ for (let i = 0; i < rawLines.length; i += 1) {
726
+ const line = rawLines[i];
727
+ const numbered = line.match(/^(\s*>)?\s*(\d+)\s+\|(.*)$/);
728
+ if (numbered) {
729
+ let text = numbered[3];
730
+ if (text.startsWith(' '))
731
+ text = text.slice(1);
732
+ const row = {
733
+ n: Number(numbered[2]),
734
+ text,
735
+ error: Boolean(numbered[1] && numbered[1].includes('>')),
736
+ squiggleAt: -1,
737
+ };
738
+ const next = rawLines[i + 1] || '';
739
+ const caret = next.match(/\|(.*)$/);
740
+ if (caret && caret[1].includes('^')) {
741
+ let mark = caret[1];
742
+ if (mark.startsWith(' '))
743
+ mark = mark.slice(1);
744
+ row.squiggleAt = Math.max(0, mark.indexOf('^'));
745
+ row.error = true;
746
+ i += 1;
747
+ }
748
+ rows.push(row);
749
+ continue;
750
+ }
751
+ if (/^\s*\|?\s*\^/.test(line))
752
+ continue;
753
+ if (line.trim().length === 0)
754
+ continue;
755
+ rows.push({ n: null, text: line, error: false, squiggleAt: -1 });
756
+ }
757
+ return rows;
758
+ }
759
+ function fillEditorRows(rows, errorLine, errorColumn) {
760
+ const numbered = rows.filter((row) => typeof row.n === 'number');
761
+ if (numbered.length === 0)
762
+ return rows;
763
+ const min = Math.min(...numbered.map((row) => row.n));
764
+ const max = Math.max(...numbered.map((row) => row.n));
765
+ const byNumber = new Map(numbered.map((row) => [row.n, row]));
766
+ const filled = [];
767
+ for (let n = min; n <= max; n += 1) {
768
+ const existing = byNumber.get(n);
769
+ if (existing) {
770
+ if (existing.squiggleAt < 0 && errorLine === n && errorColumn) {
771
+ existing.squiggleAt = Math.max(0, errorColumn - 1);
772
+ existing.error = true;
773
+ }
774
+ filled.push(existing);
775
+ }
776
+ else {
777
+ filled.push({
778
+ n,
779
+ text: '',
780
+ error: errorLine === n,
781
+ squiggleAt: errorLine === n && errorColumn ? Math.max(0, errorColumn - 1) : -1,
782
+ });
783
+ }
784
+ }
785
+ return filled;
786
+ }
787
+ function renderIdeCodeHtml(codeFrame, errorLine, errorColumn) {
788
+ const rows = fillEditorRows(parseCodeFrameLines(codeFrame), errorLine, errorColumn);
789
+ const numbered = rows.filter((row) => typeof row.n === 'number');
790
+ if (numbered.length === 0) {
791
+ return renderLogHtml(codeFrame);
792
+ }
793
+ return `<div class="vista-error-editor">${rows
794
+ .map((row) => {
795
+ const squiggle = row.squiggleAt >= 0
796
+ ? `<span class="vista-error-squiggle" style="width:3.2ch;margin-left:${row.squiggleAt}ch"></span>`
797
+ : '';
798
+ return `<div class="vista-error-editor-line${row.error ? ' is-error' : ''}"><span class="vista-error-gutter">${row.n ?? ''}</span><span class="vista-error-source">${highlightSource(row.text)}${squiggle}</span></div>`;
799
+ })
800
+ .join('')}</div>`;
801
+ }
802
+ function renderLogHtml(text, lineClass = '') {
803
+ const lines = String(text || '').split(/\r?\n/);
804
+ if (lines.length === 1 && !lines[0]) {
805
+ return '<div class="vista-error-editor"><div class="vista-error-editor-line"><span class="vista-error-gutter"></span><span class="vista-error-source"></span></div></div>';
806
+ }
807
+ return `<div class="vista-error-editor">${lines
808
+ .map((line, index) => `<div class="vista-error-editor-line${lineClass}"><span class="vista-error-gutter">${index + 1}</span><span class="vista-error-source">${highlightSource(line)}</span></div>`)
809
+ .join('')}</div>`;
810
+ }
811
+ function renderLocationEditor(location) {
812
+ if (location.kind === 'server')
813
+ return renderLogHtml(location.codeFrame || '', ' is-server');
814
+ if (location.kind === 'client')
815
+ return renderLogHtml(location.codeFrame || '', ' is-client');
816
+ if (location.kind === 'log')
817
+ return renderLogHtml(location.codeFrame || location.file);
818
+ return renderIdeCodeHtml(location.codeFrame || '', location.line, location.column);
819
+ }
820
+ function tabLabel(location) {
821
+ if (location.kind === 'server')
822
+ return 'server';
823
+ if (location.kind === 'client')
824
+ return 'client';
825
+ return fileBasename(location.file);
826
+ }
827
+ function renderFileTabsHtml(related, activeIndex) {
828
+ return related
829
+ .map((location, index) => {
830
+ const name = tabLabel(location);
831
+ const inactive = index === activeIndex ? '' : ' is-inactive';
832
+ return `<button type="button" class="vista-ide-tab${inactive}" data-vista-file-tab="${index}"><svg class="vista-ide-tab-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true"><rect x="3" y="2" width="10" height="12" rx="1.5" stroke="#4fc1ff" stroke-width="1.4"/><path d="M6 6h4M6 9h4M6 12h2" stroke="#4fc1ff" stroke-width="1.2" stroke-linecap="round"/></svg><span>${escapeHtml(name)}</span></button>`;
833
+ })
834
+ .join('');
835
+ }
836
+ function isNoiseFile(file) {
837
+ const normalized = file.replace(/\\/g, '/');
838
+ return /node_modules\/|node:|webpack\/runtime|\/vista\/dist\//.test(normalized);
839
+ }
840
+ function parseLocationsFromText(text) {
841
+ const found = [];
842
+ const seen = new Set();
843
+ const pattern = /(?:ERROR in\s+)?((?:[A-Za-z]:)?[./\\]?[\w.@/-]+\.(?:tsx?|jsx?|mjs|cjs|css|json|mdx?))(?::(\d+)(?::(\d+))?)?/g;
844
+ let match;
845
+ while ((match = pattern.exec(text))) {
846
+ const file = match[1].replace(/\\/g, '/').replace(/^\.\//, '');
847
+ if (isNoiseFile(file))
848
+ continue;
849
+ const key = `${file}:${match[2] || ''}`;
850
+ if (seen.has(key) || seen.has(file))
851
+ continue;
852
+ seen.add(file);
853
+ seen.add(key);
854
+ found.push({
855
+ file,
856
+ line: match[2] ? Number(match[2]) : undefined,
857
+ column: match[3] ? Number(match[3]) : undefined,
858
+ kind: 'source',
859
+ });
860
+ if (found.length >= 8)
861
+ break;
862
+ }
863
+ return found;
864
+ }
865
+ function parseHydrationMismatch(message) {
866
+ const serverLines = [];
867
+ const clientLines = [];
868
+ for (const rawLine of String(message || '').split(/\r?\n/)) {
869
+ if (/^\s*-\s+(A |Variable |Date |External |Invalid |It can also|https?:)/i.test(rawLine))
870
+ continue;
871
+ if (/^\s*-\s+/.test(rawLine)) {
872
+ serverLines.push(rawLine.replace(/^\s*-\s?/, ''));
873
+ }
874
+ else if (/^\s*\+\s+/.test(rawLine)) {
875
+ clientLines.push(rawLine.replace(/^\s*\+\s?/, ''));
876
+ }
877
+ }
878
+ if (serverLines.length === 0 && clientLines.length === 0)
879
+ return null;
880
+ return { server: serverLines.join('\n'), client: clientLines.join('\n') };
881
+ }
882
+ function defaultHint(error) {
883
+ if (error.hint)
884
+ return error.hint;
885
+ if (error.type === 'hydration') {
886
+ return 'Server HTML did not match the client. Check Date.now(), Math.random(), invalid tag nesting, or a missing \'use client\'.';
887
+ }
888
+ if (error.source === 'server') {
889
+ return 'Thrown while rendering on the server. Open the first app frame in the call stack.';
890
+ }
891
+ if (error.type === 'build' && (error.related?.length || 0) > 1) {
892
+ return `${error.related.length} files are involved. Switch editor tabs to inspect each one.`;
893
+ }
894
+ return '';
895
+ }
896
+ function enrichError(error) {
897
+ const message = error.message || '';
898
+ const stack = error.stack || '';
899
+ let type = error.type;
900
+ let source = error.source;
901
+ if (type !== 'hydration' && /hydration|did not match|server rendered html|text content does not match/i.test(message)) {
902
+ type = 'hydration';
903
+ }
904
+ if (!source && /Flight SSR|Server Error|renderToString|rsc-engine|vista[\\/]server/i.test(`${message}\n${stack}`)) {
905
+ source = 'server';
906
+ }
907
+ const related = [];
908
+ const seen = new Set();
909
+ const add = (location) => {
910
+ const file = location.file.replace(/\\/g, '/').replace(/^\.\//, '');
911
+ if (!file || isNoiseFile(file))
912
+ return;
913
+ const kind = location.kind || 'source';
914
+ const key = kind === 'source' || kind === 'log' ? `${kind}:${file}` : `${kind}:${file}:${location.line || ''}`;
915
+ if (seen.has(key))
916
+ return;
917
+ seen.add(key);
918
+ related.push({ ...location, file, kind });
919
+ };
920
+ if (error.file) {
921
+ add({
922
+ file: error.file,
923
+ line: error.line,
924
+ column: error.column,
925
+ codeFrame: error.codeFrame,
926
+ kind: 'source',
927
+ });
928
+ }
929
+ for (const frame of parseStackFrames(stack)) {
930
+ if (!frame.file)
931
+ continue;
932
+ add({ file: frame.file, line: frame.line || undefined, column: frame.column || undefined, kind: 'source' });
933
+ }
934
+ for (const location of parseLocationsFromText(`${message}\n${stack}`)) {
935
+ add(location);
936
+ }
937
+ const mismatch = type === 'hydration' ? parseHydrationMismatch(message) : null;
938
+ if (mismatch) {
939
+ if (mismatch.server)
940
+ add({ file: 'server.html', codeFrame: mismatch.server, kind: 'server' });
941
+ if (mismatch.client)
942
+ add({ file: 'client.html', codeFrame: mismatch.client, kind: 'client' });
943
+ }
944
+ if (related.length === 0) {
945
+ add({
946
+ file: error.file || (type === 'build' ? 'build.log' : 'error.log'),
947
+ line: error.line,
948
+ column: error.column,
949
+ codeFrame: error.codeFrame || (error.stack ? error.stack : error.message),
950
+ kind: error.codeFrame ? 'source' : 'log',
951
+ });
952
+ }
953
+ else if (error.codeFrame && !related[0].codeFrame) {
954
+ related[0] = { ...related[0], codeFrame: error.codeFrame };
955
+ }
956
+ const primary = related.find((item) => item.kind === 'source') || related[0];
957
+ const next = {
958
+ ...error,
959
+ type,
960
+ source,
961
+ file: error.file || primary?.file,
962
+ line: error.line || primary?.line,
963
+ column: error.column || primary?.column,
964
+ related,
965
+ };
966
+ next.hint = defaultHint(next);
967
+ return next;
968
+ }
969
+ function parseStackFrames(stack) {
970
+ return parseStackTrace(stack).map((line) => {
971
+ const match = line.match(/^\s*at\s+(?:async\s+)?(?:(.+?)\s+\()?((?:[A-Za-z]:)?[^()\s]+):(\d+):(\d+)\)?\s*$/);
972
+ if (match) {
973
+ return {
974
+ name: (match[1] || '(anonymous)').replace(/^Object\./, ''),
975
+ file: match[2],
976
+ line: Number(match[3]),
977
+ column: Number(match[4]),
978
+ };
979
+ }
980
+ return { name: line.replace(/^\s*at\s+/, ''), file: '', line: 0, column: 0 };
981
+ });
982
+ }
983
+ function renderStackFramesHtml(stack) {
984
+ const frames = parseStackFrames(stack);
985
+ if (frames.length === 0)
986
+ return '';
987
+ return `<div class="vista-error-frames">${frames
988
+ .map((frame) => {
989
+ const loc = frame.file
990
+ ? `${frame.file.replace(/\\/g, '/')}${frame.line ? `:${frame.line}` : ''}${frame.column ? `:${frame.column}` : ''}`
991
+ : '';
992
+ const open = frame.file
993
+ ? ` data-vista-open-file="${escapeHtml(frame.file)}" data-vista-open-line="${frame.line || 1}" data-vista-open-col="${frame.column || 1}"`
994
+ : '';
995
+ return `<button type="button" class="vista-error-frame"${open}><span class="vista-error-frame-name">${escapeHtml(frame.name)}</span>${loc ? `<span class="vista-error-frame-loc">${escapeHtml(loc)}</span>` : ''}</button>`;
996
+ })
997
+ .join('')}</div>`;
998
+ }
370
999
  function parseStackTrace(stack) {
371
1000
  if (!stack)
372
1001
  return [];
@@ -376,43 +1005,125 @@ function parseStackTrace(stack) {
376
1005
  .filter((line) => line.trim().length > 0);
377
1006
  }
378
1007
  function normalizeError(error) {
379
- return {
1008
+ return enrichError({
380
1009
  type: error?.type === 'build' || error?.type === 'hydration' || error?.type === 'runtime'
381
1010
  ? error.type
382
1011
  : 'runtime',
1012
+ source: error?.source === 'server' || error?.source === 'client' ? error.source : undefined,
383
1013
  message: typeof error?.message === 'string' ? error.message : 'Unknown Error',
384
1014
  stack: typeof error?.stack === 'string' ? error.stack : undefined,
385
1015
  file: typeof error?.file === 'string' ? error.file : undefined,
386
1016
  line: typeof error?.line === 'number' ? error.line : undefined,
387
1017
  column: typeof error?.column === 'number' ? error.column : undefined,
388
1018
  codeFrame: typeof error?.codeFrame === 'string' ? error.codeFrame : undefined,
389
- };
1019
+ related: Array.isArray(error?.related) ? error.related : undefined,
1020
+ hint: typeof error?.hint === 'string' ? error.hint : undefined,
1021
+ });
390
1022
  }
391
1023
  function normalizeErrors(errors) {
392
1024
  if (!Array.isArray(errors) || errors.length === 0) {
393
- return [
394
- {
395
- type: 'runtime',
396
- message: 'Unknown Error',
397
- },
398
- ];
1025
+ return [normalizeError({ type: 'runtime', message: 'Unknown Error' })];
399
1026
  }
400
1027
  return errors.map((error) => normalizeError(error));
401
1028
  }
402
- function getErrorTypeLabel(type) {
403
- if (type === 'build')
1029
+ function locationHasCode(location) {
1030
+ if (!location)
1031
+ return false;
1032
+ if ((location.kind || 'source') !== 'source')
1033
+ return false;
1034
+ return Boolean(location.codeFrame && String(location.codeFrame).trim());
1035
+ }
1036
+ function hasCodeView(error) {
1037
+ const related = error.related || [];
1038
+ if (related.some(locationHasCode))
1039
+ return true;
1040
+ return Boolean(error.codeFrame && String(error.codeFrame).trim());
1041
+ }
1042
+ function getErrorTypeLabel(error) {
1043
+ if (error.type === 'build')
404
1044
  return 'Build Error';
405
- if (type === 'hydration')
1045
+ if (error.type === 'hydration')
406
1046
  return 'Hydration Error';
407
- return 'Runtime Error';
1047
+ if (error.source === 'server')
1048
+ return 'Server Error';
1049
+ return 'Unhandled Runtime Error';
1050
+ }
1051
+ function problemTone(error) {
1052
+ if (error.type === 'hydration')
1053
+ return 'hydration';
1054
+ if (error.source === 'server')
1055
+ return 'server';
1056
+ return '';
1057
+ }
1058
+ function sourceBadge(error) {
1059
+ if (error.type === 'hydration')
1060
+ return { label: 'Hydration', tone: 'hydration' };
1061
+ if (error.source === 'server')
1062
+ return { label: 'Server', tone: 'server' };
1063
+ if (error.source === 'client')
1064
+ return { label: 'Client', tone: 'client' };
1065
+ if (error.type === 'build')
1066
+ return { label: 'Build', tone: '' };
1067
+ return { label: 'Client', tone: 'client' };
1068
+ }
1069
+ function fromCaughtError(error, options) {
1070
+ const err = error instanceof Error ? error : new Error(String(error || 'Unknown Error'));
1071
+ return normalizeError({
1072
+ type: options?.type || 'runtime',
1073
+ source: options?.source,
1074
+ message: err.message || 'Unknown Error',
1075
+ stack: err.stack,
1076
+ });
408
1077
  }
409
- function getErrorTitle(message, fallback) {
410
- const lines = message
1078
+ function splitMessage(message) {
1079
+ const lines = String(message || '')
411
1080
  .split(/\r?\n/)
412
1081
  .map((line) => line.trim())
413
1082
  .filter(Boolean);
414
- const title = lines[0] || fallback;
415
- return title.length > 140 ? `${title.slice(0, 137)}...` : title;
1083
+ return {
1084
+ headline: lines[0] || 'Unknown Error',
1085
+ detail: lines.slice(1).join('\n'),
1086
+ };
1087
+ }
1088
+ function formatCodeHeader(error) {
1089
+ if (!error.file)
1090
+ return '';
1091
+ const file = error.file.replace(/\\/g, '/');
1092
+ if (!error.line)
1093
+ return file;
1094
+ return `${file} (${error.line}${error.column ? `:${error.column}` : ''})`;
1095
+ }
1096
+ function fileBasename(file) {
1097
+ if (!file)
1098
+ return 'untitled';
1099
+ const normalized = file.replace(/\\/g, '/');
1100
+ return normalized.split('/').filter(Boolean).pop() || normalized;
1101
+ }
1102
+ function fileBreadcrumb(file) {
1103
+ if (!file)
1104
+ return '';
1105
+ return file.replace(/\\/g, '/').split('/').filter(Boolean).join(' › ');
1106
+ }
1107
+ function languageFromFile(file) {
1108
+ const ext = (file || '').split('.').pop()?.toLowerCase();
1109
+ if (ext === 'tsx')
1110
+ return 'TypeScript React';
1111
+ if (ext === 'ts')
1112
+ return 'TypeScript';
1113
+ if (ext === 'jsx')
1114
+ return 'JavaScript React';
1115
+ if (ext === 'js' || ext === 'mjs' || ext === 'cjs')
1116
+ return 'JavaScript';
1117
+ if (ext === 'css')
1118
+ return 'CSS';
1119
+ if (ext === 'json')
1120
+ return 'JSON';
1121
+ return 'Plain Text';
1122
+ }
1123
+ function statusLine(error) {
1124
+ if (!error.line)
1125
+ return 'Ready';
1126
+ return `Ln ${error.line}, Col ${error.column || 1}`;
416
1127
  }
417
1128
  function formatLocation(error) {
418
1129
  if (!error.file)
@@ -423,7 +1134,7 @@ function formatLocation(error) {
423
1134
  return `${normalized}:${error.line}${error.column ? `:${error.column}` : ''}`;
424
1135
  }
425
1136
  function serializeErrorForCopy(error) {
426
- const label = getErrorTypeLabel(error.type);
1137
+ const label = getErrorTypeLabel(error);
427
1138
  const parts = [label, '', error.message || 'Unknown Error'];
428
1139
  if (error.file) {
429
1140
  parts.push('');
@@ -485,372 +1196,677 @@ function copyTextInBrowser(value) {
485
1196
  function renderErrorHTML(errors) {
486
1197
  const normalizedErrors = normalizeErrors(errors);
487
1198
  const firstError = normalizedErrors[0];
488
- const firstLabel = getErrorTypeLabel(firstError.type);
489
- const firstTitle = getErrorTitle(firstError.message || 'Unknown Error', firstLabel);
490
- const firstLocation = formatLocation(firstError);
1199
+ const firstLabel = getErrorTypeLabel(firstError);
1200
+ const firstParts = splitMessage(firstError.message || 'Unknown Error');
1201
+ const firstRelated = firstError.related && firstError.related.length > 0
1202
+ ? firstError.related
1203
+ : [
1204
+ {
1205
+ file: firstError.file || 'untitled',
1206
+ line: firstError.line,
1207
+ column: firstError.column,
1208
+ codeFrame: firstError.codeFrame,
1209
+ kind: 'source',
1210
+ },
1211
+ ];
1212
+ const firstLocationEntry = firstRelated[0];
1213
+ const firstLocation = formatCodeHeader(firstError) || formatLocation(firstError);
491
1214
  const firstStack = parseStackTrace(firstError.stack || '').join('\n');
492
- const firstCode = firstError.codeFrame || '';
493
- const firstMessageHtml = colorizeBlockHtml(firstError.message || 'Unknown Error');
494
- const firstCodeHtml = colorizeBlockHtml(firstCode);
495
- const firstStackHtml = colorizeBlockHtml(firstStack);
1215
+ const firstCodeHtml = renderLocationEditor(firstLocationEntry);
1216
+ const firstCrumbs = fileBreadcrumb(firstLocationEntry.file) || firstLocation || 'Source';
1217
+ const firstStatus = firstLocationEntry.line
1218
+ ? `Ln ${firstLocationEntry.line}, Col ${firstLocationEntry.column || 1}`
1219
+ : statusLine(firstError);
1220
+ const firstLang = firstLocationEntry.kind === 'server' || firstLocationEntry.kind === 'client'
1221
+ ? 'HTML'
1222
+ : firstLocationEntry.kind === 'log'
1223
+ ? 'Log'
1224
+ : languageFromFile(firstLocationEntry.file);
1225
+ const firstStackHtml = renderStackFramesHtml(firstStack);
1226
+ const firstTabsHtml = renderFileTabsHtml(firstRelated, 0);
1227
+ const firstTone = problemTone(firstError);
1228
+ const firstBadge = sourceBadge(firstError);
1229
+ const firstHint = firstError.hint || '';
1230
+ const firstTerminal = !hasCodeView(firstError);
1231
+ const firstTitleName = firstTerminal ? firstLabel : tabLabel(firstLocationEntry);
1232
+ const showPager = normalizedErrors.length > 1;
496
1233
  const serializedErrors = escapeForInlineScript(JSON.stringify(normalizedErrors));
497
- return `<!DOCTYPE html>
498
- <html lang="en">
499
- <head>
500
- <meta charset="utf-8" />
501
- <meta name="viewport" content="width=device-width, initial-scale=1" />
502
- <title>Error - Vista</title>
503
- <style>${OVERLAY_STYLES}</style>
504
- <script>${OVERLAY_SCRIPT}</script>
505
- <script>
506
- // Vista live-reload: auto-refresh error overlay when files change.
507
- (function() {
508
- function connect() {
509
- var es = new EventSource('${constants_1.SSE_ENDPOINT}');
510
- es.onmessage = function(e) {
511
- if (e.data && e.data !== 'connected') {
512
- window.location.reload();
513
- }
514
- };
515
- es.onerror = function() {
516
- es.close();
517
- setTimeout(connect, 1500);
518
- };
519
- }
520
- connect();
521
- })();
522
-
523
- (function() {
524
- var errors = ${serializedErrors};
525
- if (!Array.isArray(errors) || errors.length === 0) {
526
- errors = [{ type: 'runtime', message: 'Unknown Error' }];
527
- }
528
-
529
- var state = { index: 0, errors: errors };
530
- var typeNode;
531
- var titleNode;
532
- var metaNode;
533
- var messageNode;
534
- var locationWrap;
535
- var locationText;
536
- var locationButton;
537
- var codeWrap;
538
- var codeNode;
539
- var stackWrap;
540
- var stackNode;
541
- var paginationNode;
542
- var countNode;
543
- var prevButton;
544
- var nextButton;
545
- var copyButton;
546
- var rootNode;
547
- var panelNode;
548
- var backdropNode;
549
- var minimizedTrigger;
550
- var minimizedCount;
551
-
552
- function getLabel(type) {
553
- if (type === 'build') return 'Build Error';
554
- if (type === 'hydration') return 'Hydration Error';
555
- return 'Runtime Error';
556
- }
557
-
558
- function getTitle(message, fallback) {
559
- var lines = String(message || '')
560
- .split(/\\r?\\n/)
561
- .map(function(line) { return line.trim(); })
562
- .filter(function(line) { return line.length > 0; });
563
- var title = lines.length ? lines[0] : fallback;
564
- return title.length > 140 ? title.slice(0, 137) + '...' : title;
565
- }
566
-
567
- function pad2(value) {
568
- return value < 10 ? '0' + value : String(value);
569
- }
570
-
571
- function formatTimeNow() {
572
- var now = new Date();
573
- return pad2(now.getHours()) + ':' + pad2(now.getMinutes()) + ':' + pad2(now.getSeconds());
574
- }
575
-
576
- function currentError() {
577
- if (!state.errors || state.errors.length === 0) return null;
578
- var idx = state.index;
579
- if (idx < 0) idx = 0;
580
- if (idx > state.errors.length - 1) idx = state.errors.length - 1;
581
- return state.errors[idx];
582
- }
583
-
584
- function formatLocation(error) {
585
- if (!error || !error.file) return '';
586
- var file = String(error.file).replace(/\\\\/g, '/');
587
- var line = Number(error.line || 0);
588
- var column = Number(error.column || 0);
589
- if (!line) return file;
590
- return file + ':' + line + (column ? ':' + column : '');
591
- }
592
-
593
- function escapeHtml(value) {
594
- return String(value || '')
595
- .replace(/&/g, '&amp;')
596
- .replace(/</g, '&lt;')
597
- .replace(/>/g, '&gt;')
598
- .replace(/\"/g, '&quot;')
599
- .replace(/'/g, '&#039;');
600
- }
601
-
602
- function colorizeLine(line) {
603
- var escaped = escapeHtml(line);
604
-
605
- if (/^\\s*\\^+/.test(line)) {
606
- return '<span class=\"vista-error-tok-caret\">' + escaped + '</span>';
607
- }
608
- if (/^\\s*at\\s+/.test(line)) {
609
- return '<span class=\"vista-error-tok-stack\">' + escaped + '</span>';
610
- }
611
-
612
- var numbered = escaped.match(/^(\\s*\\d+)(\\s*\\|)(.*)$/);
613
- if (numbered) {
614
- escaped =
615
- '<span class=\"vista-error-tok-line\">' + numbered[1] + '</span>' + numbered[2] + numbered[3];
616
- }
617
-
618
- escaped = escaped.replace(
619
- /((?:[A-Za-z]:)?[\\\\/\\w.@%:-]+\\.(?:tsx?|jsx?|mjs|cjs|css|json|mdx?)(?::\\d+(?::\\d+)?)?)/g,
620
- '<span class=\"vista-error-tok-path\">$1</span>'
621
- );
622
- escaped = escaped.replace(
623
- /(&quot;[^&]+&quot;|&#039;[^&]+&#039;)/g,
624
- '<span class=\"vista-error-tok-string\">$1</span>'
625
- );
626
- escaped = escaped.replace(
627
- /(TypeError:|ReferenceError:|SyntaxError:|Error:|Cannot find module|Module not found|Build Error|Runtime Error|Hydration Error)/g,
628
- '<span class=\"vista-error-tok-error\">$1</span>'
629
- );
630
- return escaped;
631
- }
632
-
633
- function colorizeBlock(value) {
634
- return String(value || '')
635
- .split(/\\r?\\n/)
636
- .map(function(line) {
637
- return colorizeLine(line);
638
- })
639
- .join('\\n');
640
- }
641
-
642
- function minimizeOverlay() {
643
- if (!rootNode) return;
644
- rootNode.setAttribute('data-minimized', 'true');
645
- if (minimizedTrigger) minimizedTrigger.hidden = false;
646
- var indicator = window.__VISTA_DEVTOOLS_INDICATOR__;
647
- if (indicator && typeof indicator.setError === 'function') {
648
- indicator.setError('runtime-error', state.errors.length);
649
- }
650
- }
651
-
652
- function restoreOverlay() {
653
- if (!rootNode) return;
654
- rootNode.removeAttribute('data-minimized');
655
- if (minimizedTrigger) minimizedTrigger.hidden = true;
656
- var indicator = window.__VISTA_DEVTOOLS_INDICATOR__;
657
- if (indicator && typeof indicator.clearError === 'function') {
658
- indicator.clearError();
659
- }
660
- }
661
-
662
- function render() {
663
- var error = currentError();
664
- if (!error) return;
665
-
666
- var label = getLabel(error.type);
667
- var message = typeof error.message === 'string' ? error.message : String(error.message || 'Unknown Error');
668
- var title = getTitle(message, label);
669
- var location = formatLocation(error);
670
- var codeFrame = typeof error.codeFrame === 'string' ? error.codeFrame : '';
671
- var stack = typeof error.stack === 'string' ? error.stack.trim() : '';
672
-
673
- if (typeNode) typeNode.textContent = label;
674
- if (titleNode) titleNode.textContent = title;
675
- if (metaNode) {
676
- metaNode.textContent =
677
- 'Vista Dev Overlay | ' + formatTimeNow() + ' | ' + (state.index + 1) + ' of ' + state.errors.length;
678
- }
679
- if (messageNode) messageNode.innerHTML = colorizeBlock(message);
680
-
681
- if (locationWrap) locationWrap.hidden = location.length === 0;
682
- if (locationText) locationText.textContent = location;
683
-
684
- if (codeWrap) codeWrap.hidden = codeFrame.trim().length === 0;
685
- if (codeNode) codeNode.innerHTML = colorizeBlock(codeFrame);
686
-
687
- if (stackWrap) stackWrap.hidden = stack.length === 0;
688
- if (stackNode) stackNode.innerHTML = colorizeBlock(stack);
689
-
690
- if (paginationNode) paginationNode.hidden = state.errors.length <= 1;
691
- if (countNode) countNode.textContent = (state.index + 1) + ' / ' + state.errors.length;
692
- if (prevButton) prevButton.disabled = state.index <= 0;
693
- if (nextButton) nextButton.disabled = state.index >= state.errors.length - 1;
694
- if (minimizedCount) minimizedCount.textContent = String(state.errors.length);
695
- }
696
-
697
- function changeIndex(offset) {
698
- var next = state.index + offset;
699
- if (next < 0 || next > state.errors.length - 1) return;
700
- state.index = next;
701
- render();
702
- }
703
-
704
- function bind() {
705
- rootNode = document.querySelector('[data-vista-error-root]');
706
- panelNode = document.querySelector('[data-vista-error-panel]');
707
- backdropNode = document.querySelector('[data-vista-error-backdrop]');
708
- typeNode = document.querySelector('[data-vista-error-type]');
709
- titleNode = document.querySelector('[data-vista-error-title]');
710
- metaNode = document.querySelector('[data-vista-error-meta]');
711
- messageNode = document.querySelector('[data-vista-error-message]');
712
- locationWrap = document.querySelector('[data-vista-location-wrap]');
713
- locationText = document.querySelector('[data-vista-location-text]');
714
- locationButton = document.querySelector('[data-vista-location-trigger]');
715
- codeWrap = document.querySelector('[data-vista-code-wrap]');
716
- codeNode = document.querySelector('[data-vista-code]');
717
- stackWrap = document.querySelector('[data-vista-stack-wrap]');
718
- stackNode = document.querySelector('[data-vista-stack]');
719
- paginationNode = document.querySelector('[data-vista-pagination]');
720
- countNode = document.querySelector('[data-vista-count]');
721
- prevButton = document.querySelector('[data-vista-prev-btn]');
722
- nextButton = document.querySelector('[data-vista-next-btn]');
723
- copyButton = document.querySelector('[data-vista-copy-btn]');
724
- minimizedTrigger = document.querySelector('[data-vista-minimized-trigger]');
725
- minimizedCount = document.querySelector('[data-vista-minimized-count]');
726
-
727
- if (prevButton) {
728
- prevButton.addEventListener('click', function() { changeIndex(-1); });
729
- }
730
-
731
- if (nextButton) {
732
- nextButton.addEventListener('click', function() { changeIndex(1); });
733
- }
734
-
735
- if (copyButton) {
736
- copyButton.addEventListener('click', function() {
737
- var error = currentError();
738
- if (!error) return;
739
- var label = getLabel(error.type);
740
- var message = typeof error.message === 'string' ? error.message : String(error.message || 'Unknown Error');
741
- var text = label + '\\n\\n' + message;
742
- var location = formatLocation(error);
743
- if (location) text += '\\n\\nFile: ' + location;
744
- if (error.codeFrame) text += '\\n\\nCode Frame:\\n' + error.codeFrame;
745
- if (error.stack) text += '\\n\\nStack Trace:\\n' + error.stack;
746
- vistaCopyText(text);
747
- });
748
- }
749
-
750
- if (locationButton) {
751
- locationButton.addEventListener('click', function() {
752
- var error = currentError();
753
- if (!error || !error.file) return;
754
- vistaOpenInEditor(error.file, Number(error.line || 1), Number(error.column || 1));
755
- });
756
- }
757
-
758
- if (backdropNode) {
759
- backdropNode.addEventListener('click', function() {
760
- minimizeOverlay();
761
- });
762
- }
763
-
764
- if (panelNode) {
765
- panelNode.addEventListener('click', function(event) {
766
- event.stopPropagation();
767
- });
768
- }
769
-
770
- if (minimizedTrigger) {
771
- minimizedTrigger.addEventListener('click', function() {
772
- restoreOverlay();
773
- });
774
- }
775
-
776
- document.addEventListener('keydown', function(event) {
777
- if (event.key === 'ArrowLeft') {
778
- changeIndex(-1);
779
- } else if (event.key === 'ArrowRight') {
780
- changeIndex(1);
781
- } else if (event.key === 'Escape') {
782
- minimizeOverlay();
783
- }
784
- });
785
- }
786
-
787
- document.addEventListener('DOMContentLoaded', function() {
788
- bind();
789
- render();
790
- });
791
- })();
792
- </script>
793
- </head>
794
- <body>
795
- <div class="vista-error-page-root" data-vista-error-root>
796
- <div class="vista-error-backdrop" data-vista-error-backdrop></div>
797
- <section class="vista-error-panel" data-vista-error-panel role="dialog" aria-label="Vista Error Overlay" aria-modal="true">
798
- <header class="vista-error-header">
799
- <div class="vista-error-head-left">
800
- <div class="vista-error-top-row">
801
- <span class="vista-error-badge" data-vista-error-type>
802
- <span class="vista-error-badge-dot"></span>${escapeHtml(firstLabel)}
803
- </span>
804
- <div class="vista-error-pagination" data-vista-pagination${normalizedErrors.length <= 1 ? ' hidden' : ''}>
805
- <button type="button" class="vista-error-page-btn" data-vista-prev-btn aria-label="Previous error">&lt;</button>
806
- <span class="vista-error-page-count" data-vista-count>1 / ${normalizedErrors.length}</span>
807
- <button type="button" class="vista-error-page-btn" data-vista-next-btn aria-label="Next error">&gt;</button>
808
- </div>
809
- </div>
810
- <h2 class="vista-error-title" data-vista-error-title>${escapeHtml(firstTitle)}</h2>
811
- <p class="vista-error-meta" data-vista-error-meta>Vista Dev Overlay</p>
812
- </div>
813
- <div class="vista-error-controls">
814
- <button type="button" class="vista-error-btn" data-vista-copy-btn aria-label="Copy error">
815
- <svg viewBox="0 0 24 24" fill="none" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"><rect x="9" y="9" width="10" height="10" rx="2" stroke="currentColor" stroke-width="2"/><rect x="5" y="5" width="10" height="10" rx="2" stroke="currentColor" stroke-width="2"/></svg>
816
- </button>
817
- <button type="button" class="vista-error-btn" onclick="vistaReload()" aria-label="Reload page">
818
- <svg viewBox="0 0 24 24" fill="none" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"><path d="M20 12a8 8 0 1 1-2.34-5.66" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><path d="M20 4V10H14" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
819
- </button>
820
- </div>
821
- </header>
822
-
823
- <div class="vista-error-body">
824
- <section class="vista-error-card" data-vista-location-wrap${firstLocation ? '' : ' hidden'}>
825
- <h3 class="vista-error-card-title">Location</h3>
826
- <button type="button" class="vista-error-location" data-vista-location-trigger>
827
- <span data-vista-location-text>${escapeHtml(firstLocation)}</span>
828
- </button>
829
- </section>
830
-
831
- <section class="vista-error-card">
832
- <h3 class="vista-error-card-title">Message</h3>
833
- <pre class="vista-error-pre" data-vista-error-message>${firstMessageHtml}</pre>
834
- </section>
835
-
836
- <section class="vista-error-card" data-vista-code-wrap${firstCode ? '' : ' hidden'}>
837
- <h3 class="vista-error-card-title">Code Frame</h3>
838
- <pre class="vista-error-pre" data-vista-code>${firstCodeHtml}</pre>
839
- </section>
840
-
841
- <section class="vista-error-card" data-vista-stack-wrap${firstStack ? '' : ' hidden'}>
842
- <h3 class="vista-error-card-title">Stack Trace</h3>
843
- <pre class="vista-error-pre" data-vista-stack>${firstStackHtml}</pre>
844
- </section>
845
- </div>
846
- </section>
847
- <button type="button" class="vista-error-minimized-trigger" data-vista-minimized-trigger hidden aria-label="Reopen error overlay">
848
- <svg class="vista-error-minimized-logo" viewBox="0 0 168 177" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M81.872 176.988L-2.01405e-06 -2.68173e-06H30.5816L83.5576 121.604L136.774 -2.68173e-06H167.115L85.484 176.988H81.872Z" fill="white"/></svg>
849
- <span class="vista-error-minimized-close">×</span>
850
- <span class="vista-error-minimized-count" data-vista-minimized-count>${normalizedErrors.length}</span>
851
- </button>
852
- </div>
853
- </body>
1234
+ return `<!DOCTYPE html>
1235
+ <html lang="en">
1236
+ <head>
1237
+ <meta charset="utf-8" />
1238
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
1239
+ <title>Error - Vista</title>
1240
+ <style>${OVERLAY_STYLES}</style>
1241
+ <script>${OVERLAY_SCRIPT}</script>
1242
+ <script>
1243
+ // Vista live-reload: auto-refresh error overlay when files change.
1244
+ (function() {
1245
+ function connect() {
1246
+ var es = new EventSource('${constants_1.SSE_ENDPOINT}');
1247
+ es.onmessage = function(e) {
1248
+ if (e.data && e.data !== 'connected') {
1249
+ window.location.reload();
1250
+ }
1251
+ };
1252
+ es.onerror = function() {
1253
+ es.close();
1254
+ setTimeout(connect, 1500);
1255
+ };
1256
+ }
1257
+ connect();
1258
+ })();
1259
+
1260
+ (function() {
1261
+ var errors = ${serializedErrors};
1262
+ if (!Array.isArray(errors) || errors.length === 0) {
1263
+ errors = [{ type: 'runtime', message: 'Unknown Error' }];
1264
+ }
1265
+
1266
+ var state = { index: 0, fileTab: 0, errors: errors };
1267
+ var typeNode;
1268
+ var titleNode;
1269
+ var hintNode;
1270
+ var fileTabsNode;
1271
+ var sourceBadgeNode;
1272
+ var problemIconNode;
1273
+ var tabNameNodes;
1274
+ var crumbsNode;
1275
+ var statusLnNode;
1276
+ var statusLangNode;
1277
+ var locationButton;
1278
+ var codeWrap;
1279
+ var codeNode;
1280
+ var stackWrap;
1281
+ var stackNode;
1282
+ var paginationNode;
1283
+ var countNode;
1284
+ var prevButton;
1285
+ var nextButton;
1286
+ var copyButton;
1287
+ var rootNode;
1288
+ var panelNode;
1289
+ var backdropNode;
1290
+ var minimizedTrigger;
1291
+ var minimizedCount;
1292
+ var mainNode;
1293
+ var panelExpandButton;
1294
+
1295
+ function getLabel(error) {
1296
+ if (error.type === 'build') return 'Build Error';
1297
+ if (error.type === 'hydration') return 'Hydration Error';
1298
+ if (error.source === 'server') return 'Server Error';
1299
+ return 'Unhandled Runtime Error';
1300
+ }
1301
+
1302
+ function splitMessage(message) {
1303
+ var lines = String(message || '')
1304
+ .split(/\\r?\\n/)
1305
+ .map(function(line) { return line.trim(); })
1306
+ .filter(function(line) { return line.length > 0; });
1307
+ return {
1308
+ headline: lines.length ? lines[0] : 'Unknown Error',
1309
+ detail: lines.slice(1).join('\\n')
1310
+ };
1311
+ }
1312
+
1313
+ function formatCodeHeader(error) {
1314
+ if (!error || !error.file) return '';
1315
+ var file = String(error.file).replace(/\\\\/g, '/');
1316
+ var line = Number(error.line || 0);
1317
+ var column = Number(error.column || 0);
1318
+ if (!line) return file;
1319
+ return file + ' (' + line + (column ? ':' + column : '') + ')';
1320
+ }
1321
+
1322
+ function currentError() {
1323
+ if (!state.errors || state.errors.length === 0) return null;
1324
+ var idx = state.index;
1325
+ if (idx < 0) idx = 0;
1326
+ if (idx > state.errors.length - 1) idx = state.errors.length - 1;
1327
+ return state.errors[idx];
1328
+ }
1329
+
1330
+ function formatLocation(error) {
1331
+ if (!error || !error.file) return '';
1332
+ var file = String(error.file).replace(/\\\\/g, '/');
1333
+ var line = Number(error.line || 0);
1334
+ var column = Number(error.column || 0);
1335
+ if (!line) return file;
1336
+ return file + ':' + line + (column ? ':' + column : '');
1337
+ }
1338
+
1339
+ function escapeHtml(value) {
1340
+ return String(value || '')
1341
+ .replace(/&/g, '&amp;')
1342
+ .replace(/</g, '&lt;')
1343
+ .replace(/>/g, '&gt;')
1344
+ .replace(/\"/g, '&quot;')
1345
+ .replace(/'/g, '&#039;');
1346
+ }
1347
+
1348
+ function highlightSource(text) {
1349
+ var html = '';
1350
+ var i = 0;
1351
+ var keywords = /^(import|from|function|return|const|let|var|export|default|class|extends|if|else|async|await|new|type|interface|true|false|null|undefined|typeof|void|as|of|in|for|while|switch|case|break|continue|try|catch|finally|this)\\b/;
1352
+ while (i < text.length) {
1353
+ var ch = text.charAt(i);
1354
+ if (ch === String.fromCharCode(39) || ch === String.fromCharCode(34) || ch === String.fromCharCode(96)) {
1355
+ var j = i + 1;
1356
+ while (j < text.length && text.charAt(j) !== ch) {
1357
+ j += text.charAt(j) === '\\\\' ? 2 : 1;
1358
+ }
1359
+ html += '<span class=\"vista-tok-str\">' + escapeHtml(text.slice(i, Math.min(j + 1, text.length))) + '</span>';
1360
+ i = j + 1;
1361
+ continue;
1362
+ }
1363
+ if (ch === '/' && text.charAt(i + 1) === '/') {
1364
+ html += '<span class=\"vista-tok-cmt\">' + escapeHtml(text.slice(i)) + '</span>';
1365
+ break;
1366
+ }
1367
+ if (ch === '<' && /[A-Za-z\\/]/.test(text.charAt(i + 1) || '')) {
1368
+ var tag = text.slice(i).match(/^<\\/?[A-Za-z][\\w.-]*/);
1369
+ if (tag) {
1370
+ html += '<span class=\"vista-tok-tag\">' + escapeHtml(tag[0]) + '</span>';
1371
+ i += tag[0].length;
1372
+ continue;
1373
+ }
1374
+ }
1375
+ if (/[0-9]/.test(ch)) {
1376
+ var num = text.slice(i).match(/^[0-9]+(?:\\.[0-9]+)?/);
1377
+ if (num) {
1378
+ html += '<span class=\"vista-tok-num\">' + escapeHtml(num[0]) + '</span>';
1379
+ i += num[0].length;
1380
+ continue;
1381
+ }
1382
+ }
1383
+ if (/[A-Za-z_$]/.test(ch)) {
1384
+ var ident = text.slice(i).match(/^[A-Za-z_$][\\w$]*/);
1385
+ if (ident) {
1386
+ html += keywords.test(ident[0])
1387
+ ? '<span class=\"vista-tok-kw\">' + escapeHtml(ident[0]) + '</span>'
1388
+ : escapeHtml(ident[0]);
1389
+ i += ident[0].length;
1390
+ continue;
1391
+ }
1392
+ }
1393
+ html += escapeHtml(ch);
1394
+ i += 1;
1395
+ }
1396
+ return html;
1397
+ }
1398
+
1399
+ function renderIdeCode(codeFrame, errorLine, errorColumn) {
1400
+ var rawLines = String(codeFrame || '').split(/\\r?\\n/);
1401
+ var rows = [];
1402
+ for (var i = 0; i < rawLines.length; i += 1) {
1403
+ var line = rawLines[i];
1404
+ var numbered = line.match(/^(\\s*>)?\\s*(\\d+)\\s+\\|(.*)$/);
1405
+ if (!numbered) continue;
1406
+ var src = numbered[3];
1407
+ if (src.charAt(0) === ' ') src = src.slice(1);
1408
+ var isError = !!(numbered[1] && numbered[1].indexOf('>') !== -1);
1409
+ var squiggleAt = -1;
1410
+ var next = rawLines[i + 1] || '';
1411
+ var caret = next.match(/\\|(.*)$/);
1412
+ if (caret && caret[1].indexOf('^') !== -1) {
1413
+ var mark = caret[1];
1414
+ if (mark.charAt(0) === ' ') mark = mark.slice(1);
1415
+ squiggleAt = Math.max(0, mark.indexOf('^'));
1416
+ isError = true;
1417
+ i += 1;
1418
+ }
1419
+ rows.push({ n: Number(numbered[2]), text: src, error: isError, squiggleAt: squiggleAt });
1420
+ }
1421
+ if (!rows.length) return '';
1422
+ var min = rows[0].n;
1423
+ var max = rows[0].n;
1424
+ var byN = {};
1425
+ for (var r = 0; r < rows.length; r += 1) {
1426
+ byN[rows[r].n] = rows[r];
1427
+ if (rows[r].n < min) min = rows[r].n;
1428
+ if (rows[r].n > max) max = rows[r].n;
1429
+ }
1430
+ var html = '';
1431
+ for (var n = min; n <= max; n += 1) {
1432
+ var row = byN[n] || { n: n, text: '', error: Number(errorLine) === n, squiggleAt: -1 };
1433
+ if (row.squiggleAt < 0 && Number(errorLine) === n && errorColumn) {
1434
+ row.squiggleAt = Math.max(0, Number(errorColumn) - 1);
1435
+ row.error = true;
1436
+ }
1437
+ html += '<div class=\"vista-error-editor-line' + (row.error ? ' is-error' : '') + '\">';
1438
+ html += '<span class=\"vista-error-gutter\">' + row.n + '</span>';
1439
+ html += '<span class=\"vista-error-source\">' + highlightSource(row.text);
1440
+ if (row.squiggleAt >= 0) {
1441
+ html += '<span class=\"vista-error-squiggle\" style=\"width:3.2ch;margin-left:' + row.squiggleAt + 'ch\"></span>';
1442
+ }
1443
+ html += '</span></div>';
1444
+ }
1445
+ return '<div class=\"vista-error-editor\">' + html + '</div>';
1446
+ }
1447
+
1448
+ function renderLog(text, extraClass) {
1449
+ var lines = String(text || '').split(/\\r?\\n/);
1450
+ var html = '';
1451
+ for (var i = 0; i < lines.length; i += 1) {
1452
+ html += '<div class=\"vista-error-editor-line' + (extraClass || '') + '\">';
1453
+ html += '<span class=\"vista-error-gutter\">' + (i + 1) + '</span>';
1454
+ html += '<span class=\"vista-error-source\">' + highlightSource(lines[i]) + '</span></div>';
1455
+ }
1456
+ return '<div class=\"vista-error-editor\">' + html + '</div>';
1457
+ }
1458
+
1459
+ function relatedFor(error) {
1460
+ if (error.related && error.related.length) return error.related;
1461
+ return [{ file: error.file || 'untitled', line: error.line, column: error.column, codeFrame: error.codeFrame, kind: 'source' }];
1462
+ }
1463
+
1464
+ function locationHasCode(loc) {
1465
+ if (!loc) return false;
1466
+ if ((loc.kind || 'source') !== 'source') return false;
1467
+ return !!(loc.codeFrame && String(loc.codeFrame).trim());
1468
+ }
1469
+
1470
+ function hasCodeView(error) {
1471
+ var related = relatedFor(error);
1472
+ for (var i = 0; i < related.length; i += 1) {
1473
+ if (locationHasCode(related[i])) return true;
1474
+ }
1475
+ return !!(error.codeFrame && String(error.codeFrame).trim());
1476
+ }
1477
+
1478
+ function tabLabelFor(loc) {
1479
+ if (loc.kind === 'server') return 'server';
1480
+ if (loc.kind === 'client') return 'client';
1481
+ var file = String(loc.file || 'untitled').replace(/\\\\/g, '/');
1482
+ return file.split('/').filter(Boolean).pop() || file;
1483
+ }
1484
+
1485
+ function renderLocation(loc) {
1486
+ if (loc.kind === 'server') return renderLog(loc.codeFrame || '', ' is-server');
1487
+ if (loc.kind === 'client') return renderLog(loc.codeFrame || '', ' is-client');
1488
+ if (loc.kind === 'log') return renderLog(loc.codeFrame || loc.file || '');
1489
+ var frame = loc.codeFrame || '';
1490
+ var html = renderIdeCode(frame, loc.line, loc.column);
1491
+ return html || renderLog(frame);
1492
+ }
1493
+
1494
+ function renderFileTabs(related, active) {
1495
+ var html = '';
1496
+ for (var i = 0; i < related.length; i += 1) {
1497
+ html += '<button type=\"button\" class=\"vista-ide-tab' + (i === active ? '' : ' is-inactive') + '\" data-vista-file-tab=\"' + i + '\">';
1498
+ html += '<svg class=\"vista-ide-tab-icon\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\"><rect x=\"3\" y=\"2\" width=\"10\" height=\"12\" rx=\"1.5\" stroke=\"#4fc1ff\" stroke-width=\"1.4\"/><path d=\"M6 6h4M6 9h4M6 12h2\" stroke=\"#4fc1ff\" stroke-width=\"1.2\" stroke-linecap=\"round\"/></svg>';
1499
+ html += '<span>' + escapeHtml(tabLabelFor(related[i])) + '</span></button>';
1500
+ }
1501
+ return html;
1502
+ }
1503
+
1504
+ function langFor(loc) {
1505
+ if (loc.kind === 'server' || loc.kind === 'client') return 'HTML';
1506
+ if (loc.kind === 'log') return 'Log';
1507
+ var ext = String(loc.file || '').split('.').pop().toLowerCase();
1508
+ if (ext === 'tsx') return 'TypeScript React';
1509
+ if (ext === 'ts') return 'TypeScript';
1510
+ if (ext === 'jsx') return 'JavaScript React';
1511
+ if (ext === 'js' || ext === 'mjs' || ext === 'cjs') return 'JavaScript';
1512
+ return 'Plain Text';
1513
+ }
1514
+
1515
+ function renderStackFrames(stack) {
1516
+ var lines = String(stack || '').split(/\\r?\\n/).filter(function(line) { return line.trim().length > 0; });
1517
+ var html = '';
1518
+ for (var s = 0; s < lines.length; s += 1) {
1519
+ var line = lines[s];
1520
+ var match = line.match(/^\\s*at\\s+(?:async\\s+)?(?:(.+?)\\s+\\()?((?:[A-Za-z]:)?[^()\\s]+):(\\d+):(\\d+)\\)?\\s*$/);
1521
+ var name = line.replace(/^\\s*at\\s+/, '');
1522
+ var file = '';
1523
+ var ln = 1;
1524
+ var col = 1;
1525
+ var loc = '';
1526
+ if (match) {
1527
+ name = (match[1] || '(anonymous)').replace(/^Object\\./, '');
1528
+ file = match[2];
1529
+ ln = Number(match[3]);
1530
+ col = Number(match[4]);
1531
+ loc = file.replace(/\\\\/g, '/') + ':' + ln + ':' + col;
1532
+ }
1533
+ html += '<button type=\"button\" class=\"vista-error-frame\"';
1534
+ if (file) {
1535
+ html += ' data-vista-open-file=\"' + escapeHtml(file) + '\" data-vista-open-line=\"' + ln + '\" data-vista-open-col=\"' + col + '\"';
1536
+ }
1537
+ html += '><span class=\"vista-error-frame-name\">' + escapeHtml(name) + '</span>';
1538
+ if (loc) html += '<span class=\"vista-error-frame-loc\">' + escapeHtml(loc) + '</span>';
1539
+ html += '</button>';
1540
+ }
1541
+ return html ? '<div class=\"vista-error-frames\">' + html + '</div>' : '';
1542
+ }
1543
+
1544
+ function minimizeOverlay() {
1545
+ if (!rootNode) return;
1546
+ rootNode.setAttribute('data-minimized', 'true');
1547
+ if (minimizedTrigger) minimizedTrigger.hidden = false;
1548
+ var indicator = window.__VISTA_DEVTOOLS_INDICATOR__;
1549
+ if (indicator && typeof indicator.setError === 'function') {
1550
+ indicator.setError('runtime-error', state.errors.length);
1551
+ }
1552
+ }
1553
+
1554
+ function restoreOverlay() {
1555
+ if (!rootNode) return;
1556
+ rootNode.removeAttribute('data-minimized');
1557
+ if (minimizedTrigger) minimizedTrigger.hidden = true;
1558
+ var indicator = window.__VISTA_DEVTOOLS_INDICATOR__;
1559
+ if (indicator && typeof indicator.clearError === 'function') {
1560
+ indicator.clearError();
1561
+ }
1562
+ }
1563
+
1564
+ function render() {
1565
+ var error = currentError();
1566
+ if (!error) return;
1567
+
1568
+ var label = getLabel(error);
1569
+ var message = typeof error.message === 'string' ? error.message : String(error.message || 'Unknown Error');
1570
+ var parts = splitMessage(message);
1571
+ var stack = typeof error.stack === 'string' ? error.stack.trim() : '';
1572
+ var related = relatedFor(error);
1573
+ if (state.fileTab > related.length - 1) state.fileTab = 0;
1574
+ var loc = related[state.fileTab] || related[0];
1575
+ var terminal = !hasCodeView(error);
1576
+ var file = String((loc && loc.file) || error.file || '').replace(/\\\\/g, '/');
1577
+ var tabName = terminal ? label : (loc ? tabLabelFor(loc) : 'untitled');
1578
+ var crumbs = file ? file.split('/').filter(Boolean).join(' › ') : 'Source';
1579
+ var lang = loc ? langFor(loc) : 'Plain Text';
1580
+ var tone = error.type === 'hydration' ? 'hydration' : error.source === 'server' ? 'server' : '';
1581
+ var badge = error.type === 'hydration' ? 'Hydration' : error.source === 'server' ? 'Server' : error.type === 'build' ? 'Build' : 'Client';
1582
+ var badgeTone = error.type === 'hydration' ? 'hydration' : error.source === 'server' ? 'server' : error.source === 'client' || error.type !== 'build' ? 'client' : '';
1583
+ var hint = error.hint || '';
1584
+
1585
+ if (typeNode) {
1586
+ typeNode.textContent = label;
1587
+ typeNode.className = 'vista-error-kind' + (tone ? ' is-' + tone : '');
1588
+ }
1589
+ if (problemIconNode) {
1590
+ problemIconNode.className = 'vista-error-problem-icon' + (tone ? ' is-' + tone : '');
1591
+ }
1592
+ if (titleNode) titleNode.textContent = parts.headline;
1593
+ if (detailNode) {
1594
+ detailNode.textContent = parts.detail;
1595
+ detailNode.hidden = parts.detail.length === 0;
1596
+ }
1597
+ if (hintNode) {
1598
+ hintNode.textContent = hint;
1599
+ hintNode.hidden = hint.length === 0;
1600
+ }
1601
+
1602
+ if (tabNameNodes) {
1603
+ for (var t = 0; t < tabNameNodes.length; t += 1) tabNameNodes[t].textContent = tabName;
1604
+ }
1605
+ if (fileTabsNode) fileTabsNode.innerHTML = renderFileTabs(related, state.fileTab);
1606
+ if (crumbsNode) crumbsNode.textContent = crumbs;
1607
+ if (statusLnNode) statusLnNode.textContent = loc && loc.line ? ('Ln ' + loc.line + ', Col ' + (loc.column || 1)) : (error.line ? ('Ln ' + error.line + ', Col ' + (error.column || 1)) : 'Ready');
1608
+ if (statusLangNode) statusLangNode.textContent = lang;
1609
+ if (sourceBadgeNode) {
1610
+ sourceBadgeNode.textContent = badge;
1611
+ sourceBadgeNode.className = 'vista-ide-source-badge' + (badgeTone ? ' is-' + badgeTone : '');
1612
+ }
1613
+
1614
+ if (codeNode) codeNode.innerHTML = renderLocation(loc || { file: file, codeFrame: error.codeFrame, line: error.line, column: error.column, kind: 'source' });
1615
+
1616
+ if (stackWrap) stackWrap.hidden = stack.length === 0;
1617
+ if (stackNode) stackNode.innerHTML = renderStackFrames(stack);
1618
+
1619
+ if (countNode) countNode.textContent = (state.index + 1) + '/' + state.errors.length;
1620
+ if (paginationNode) paginationNode.hidden = state.errors.length <= 1;
1621
+ if (prevButton) prevButton.disabled = state.index <= 0;
1622
+ if (nextButton) nextButton.disabled = state.index >= state.errors.length - 1;
1623
+ if (minimizedCount) minimizedCount.textContent = String(state.errors.length);
1624
+ if (mainNode) {
1625
+ if (terminal) {
1626
+ mainNode.setAttribute('data-terminal', 'true');
1627
+ mainNode.removeAttribute('data-panel-expanded');
1628
+ } else {
1629
+ mainNode.removeAttribute('data-terminal');
1630
+ }
1631
+ }
1632
+ if (panelExpandButton) {
1633
+ panelExpandButton.hidden = terminal;
1634
+ if (terminal) {
1635
+ panelExpandButton.setAttribute('aria-pressed', 'false');
1636
+ panelExpandButton.setAttribute('aria-label', 'Expand problems panel');
1637
+ }
1638
+ }
1639
+ }
1640
+
1641
+ function changeIndex(offset) {
1642
+ var next = state.index + offset;
1643
+ if (next < 0 || next > state.errors.length - 1) return;
1644
+ state.index = next;
1645
+ state.fileTab = 0;
1646
+ render();
1647
+ }
1648
+
1649
+ function bind() {
1650
+ rootNode = document.querySelector('[data-vista-error-root]');
1651
+ panelNode = document.querySelector('[data-vista-error-panel]');
1652
+ backdropNode = document.querySelector('[data-vista-error-backdrop]');
1653
+ typeNode = document.querySelector('[data-vista-error-type]');
1654
+ titleNode = document.querySelector('[data-vista-error-title]');
1655
+ detailNode = document.querySelector('[data-vista-error-detail]');
1656
+ hintNode = document.querySelector('[data-vista-error-hint]');
1657
+ problemIconNode = document.querySelector('.vista-error-problem-icon');
1658
+ tabNameNodes = document.querySelectorAll('[data-vista-tab-name]');
1659
+ crumbsNode = document.querySelector('[data-vista-crumbs]');
1660
+ statusLnNode = document.querySelector('[data-vista-status-ln]');
1661
+ statusLangNode = document.querySelector('[data-vista-status-lang]');
1662
+ sourceBadgeNode = document.querySelector('[data-vista-source-badge]');
1663
+ fileTabsNode = document.querySelector('[data-vista-file-tabs]');
1664
+ codeWrap = document.querySelector('[data-vista-code-wrap]');
1665
+ codeNode = document.querySelector('[data-vista-code]');
1666
+ stackWrap = document.querySelector('[data-vista-stack-wrap]');
1667
+ stackNode = document.querySelector('[data-vista-stack]');
1668
+ paginationNode = document.querySelector('[data-vista-pagination]');
1669
+ countNode = document.querySelector('[data-vista-count]');
1670
+ prevButton = document.querySelector('[data-vista-prev-btn]');
1671
+ nextButton = document.querySelector('[data-vista-next-btn]');
1672
+ copyButton = document.querySelector('[data-vista-copy-btn]');
1673
+ minimizedTrigger = document.querySelector('[data-vista-minimized-trigger]');
1674
+ minimizedCount = document.querySelector('[data-vista-minimized-count]');
1675
+ mainNode = document.querySelector('[data-vista-ide-main]');
1676
+ panelExpandButton = document.querySelector('[data-vista-panel-expand]');
1677
+
1678
+ if (prevButton) {
1679
+ prevButton.addEventListener('click', function() { changeIndex(-1); });
1680
+ }
1681
+
1682
+ if (nextButton) {
1683
+ nextButton.addEventListener('click', function() { changeIndex(1); });
1684
+ }
1685
+
1686
+ if (copyButton) {
1687
+ copyButton.addEventListener('click', function() {
1688
+ var error = currentError();
1689
+ if (!error) return;
1690
+ var label = getLabel(error);
1691
+ var message = typeof error.message === 'string' ? error.message : String(error.message || 'Unknown Error');
1692
+ var text = label + '\\n\\n' + message;
1693
+ var location = formatLocation(error);
1694
+ if (location) text += '\\n\\nFile: ' + location;
1695
+ if (error.codeFrame) text += '\\n\\nCode Frame:\\n' + error.codeFrame;
1696
+ if (error.stack) text += '\\n\\nStack Trace:\\n' + error.stack;
1697
+ vistaCopyText(text);
1698
+ });
1699
+ }
1700
+
1701
+ if (fileTabsNode) {
1702
+ fileTabsNode.addEventListener('click', function(event) {
1703
+ var target = event.target && event.target.closest ? event.target.closest('[data-vista-file-tab]') : null;
1704
+ if (!target) return;
1705
+ var nextTab = Number(target.getAttribute('data-vista-file-tab') || 0);
1706
+ var error = currentError();
1707
+ var related = error ? relatedFor(error) : [];
1708
+ var loc = related[nextTab];
1709
+ if (nextTab === state.fileTab && loc && loc.kind === 'source' && loc.file && loc.file.indexOf('.html') === -1) {
1710
+ vistaOpenInEditor(loc.file, Number(loc.line || 1), Number(loc.column || 1));
1711
+ return;
1712
+ }
1713
+ state.fileTab = nextTab;
1714
+ render();
1715
+ });
1716
+ }
1717
+
1718
+ if (panelExpandButton && mainNode) {
1719
+ panelExpandButton.addEventListener('click', function() {
1720
+ if (mainNode.getAttribute('data-terminal') === 'true') return;
1721
+ var expanded = mainNode.getAttribute('data-panel-expanded') === 'true';
1722
+ if (expanded) {
1723
+ mainNode.removeAttribute('data-panel-expanded');
1724
+ panelExpandButton.setAttribute('aria-pressed', 'false');
1725
+ panelExpandButton.setAttribute('aria-label', 'Expand problems panel');
1726
+ } else {
1727
+ mainNode.setAttribute('data-panel-expanded', 'true');
1728
+ panelExpandButton.setAttribute('aria-pressed', 'true');
1729
+ panelExpandButton.setAttribute('aria-label', 'Restore problems panel');
1730
+ }
1731
+ });
1732
+ }
1733
+
1734
+ if (stackWrap) {
1735
+ stackWrap.addEventListener('click', function(event) {
1736
+ var target = event.target && event.target.closest ? event.target.closest('[data-vista-open-file]') : null;
1737
+ if (!target) return;
1738
+ vistaOpenInEditor(
1739
+ target.getAttribute('data-vista-open-file'),
1740
+ Number(target.getAttribute('data-vista-open-line') || 1),
1741
+ Number(target.getAttribute('data-vista-open-col') || 1)
1742
+ );
1743
+ });
1744
+ }
1745
+
1746
+ if (backdropNode) {
1747
+ backdropNode.addEventListener('click', function() {
1748
+ minimizeOverlay();
1749
+ });
1750
+ }
1751
+
1752
+ if (panelNode) {
1753
+ panelNode.addEventListener('click', function(event) {
1754
+ event.stopPropagation();
1755
+ });
1756
+ }
1757
+
1758
+ if (minimizedTrigger) {
1759
+ minimizedTrigger.addEventListener('click', function() {
1760
+ restoreOverlay();
1761
+ });
1762
+ }
1763
+
1764
+ document.addEventListener('keydown', function(event) {
1765
+ if (event.key === 'ArrowLeft') {
1766
+ changeIndex(-1);
1767
+ } else if (event.key === 'ArrowRight') {
1768
+ changeIndex(1);
1769
+ } else if (event.key === 'Escape') {
1770
+ if (mainNode && mainNode.getAttribute('data-panel-expanded') === 'true' && mainNode.getAttribute('data-terminal') !== 'true') {
1771
+ mainNode.removeAttribute('data-panel-expanded');
1772
+ if (panelExpandButton) {
1773
+ panelExpandButton.setAttribute('aria-pressed', 'false');
1774
+ panelExpandButton.setAttribute('aria-label', 'Expand problems panel');
1775
+ }
1776
+ return;
1777
+ }
1778
+ minimizeOverlay();
1779
+ }
1780
+ });
1781
+ }
1782
+
1783
+ document.addEventListener('DOMContentLoaded', function() {
1784
+ bind();
1785
+ render();
1786
+ });
1787
+ })();
1788
+ </script>
1789
+ </head>
1790
+ <body>
1791
+ <div class="vista-error-page-root" data-vista-error-root>
1792
+ <div class="vista-error-backdrop" data-vista-error-backdrop></div>
1793
+ <section class="vista-error-panel" data-vista-error-panel role="dialog" aria-label="Vista Error Overlay" aria-modal="true">
1794
+ <div class="vista-ide-titlebar">
1795
+ <div class="vista-ide-traffic" aria-hidden="true">
1796
+ <span class="is-close"></span><span class="is-min"></span><span class="is-max"></span>
1797
+ </div>
1798
+ <div class="vista-ide-title">Vista — <span data-vista-tab-name>${escapeHtml(firstTitleName)}</span></div>
1799
+ <div class="vista-error-toolbar">
1800
+ <button type="button" class="vista-error-icon-btn" data-vista-copy-btn aria-label="Copy error">
1801
+ <svg viewBox="0 0 24 24" fill="none" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"><rect x="9" y="9" width="10" height="10" rx="2" stroke="currentColor" stroke-width="1.6"/><rect x="5" y="5" width="10" height="10" rx="2" stroke="currentColor" stroke-width="1.6"/></svg>
1802
+ </button>
1803
+ <button type="button" class="vista-error-icon-btn" onclick="vistaReload()" aria-label="Reload page">
1804
+ <svg viewBox="0 0 24 24" fill="none" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"><path d="M20 12a8 8 0 1 1-2.34-5.66" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/><path d="M20 4V10H14" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>
1805
+ </button>
1806
+ <div class="vista-error-pagination" data-vista-pagination${showPager ? '' : ' hidden'}>
1807
+ <button type="button" class="vista-error-page-btn" data-vista-prev-btn aria-label="Previous error">‹</button>
1808
+ <span class="vista-error-page-count" data-vista-count>1/${normalizedErrors.length}</span>
1809
+ <button type="button" class="vista-error-page-btn" data-vista-next-btn aria-label="Next error">›</button>
1810
+ </div>
1811
+ </div>
1812
+ </div>
1813
+ <div class="vista-ide-workbench">
1814
+ <aside class="vista-ide-activity" aria-hidden="true">
1815
+ <span class="vista-ide-activity-item is-active">
1816
+ <svg viewBox="0 0 24 24" fill="none"><rect x="4" y="3" width="10" height="13" rx="1.2" stroke="currentColor" stroke-width="1.6"/><rect x="10" y="8" width="10" height="13" rx="1.2" stroke="currentColor" stroke-width="1.6"/></svg>
1817
+ </span>
1818
+ </aside>
1819
+ <div class="vista-ide-main" data-vista-ide-main${firstTerminal ? ' data-terminal="true"' : ''}>
1820
+ <div class="vista-ide-tabbar">
1821
+ <div class="vista-ide-tabs" data-vista-file-tabs>
1822
+ ${firstTabsHtml}
1823
+ </div>
1824
+ </div>
1825
+ <div class="vista-ide-crumbs" data-vista-crumbs>${escapeHtml(firstCrumbs || firstLocation || 'Source')}</div>
1826
+ <div class="vista-error-code" data-vista-code-wrap>
1827
+ <div class="vista-error-editor-host" data-vista-code>${firstCodeHtml}</div>
1828
+ </div>
1829
+ <div class="vista-ide-statusbar">
1830
+ <span data-vista-status-ln>${escapeHtml(firstStatus)}</span>
1831
+ <span data-vista-status-lang>${escapeHtml(firstLang)}</span>
1832
+ <span class="vista-ide-source-badge${firstBadge ? ` is-${firstBadge.tone}` : ''}" data-vista-source-badge>${escapeHtml(firstBadge ? firstBadge.label : 'Client')}</span>
1833
+ <span>UTF-8</span>
1834
+ </div>
1835
+ <div class="vista-ide-panel">
1836
+ <div class="vista-ide-panel-tabs">
1837
+ <span class="is-active">PROBLEMS</span>
1838
+ <span>CALL STACK</span>
1839
+ <button type="button" class="vista-error-icon-btn vista-ide-panel-toggle" data-vista-panel-expand aria-label="Expand problems panel" aria-pressed="false"${firstTerminal ? ' hidden' : ''}>
1840
+ <svg class="vista-ide-icon-expand" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3 6.5V3h3.5M13 6.5V3h-3.5M3 9.5V13h3.5M13 9.5V13h-3.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
1841
+ <svg class="vista-ide-icon-restore" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M6.5 3v3.5H3M9.5 3v3.5H13M6.5 13V9.5H3M9.5 13V9.5H13" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
1842
+ </button>
1843
+ </div>
1844
+ <div class="vista-error-body">
1845
+ <div class="vista-error-problem">
1846
+ <span class="vista-error-problem-icon${firstTone ? ` is-${firstTone}` : ''}" aria-hidden="true"></span>
1847
+ <div>
1848
+ <p class="vista-error-kind${firstTone ? ` is-${firstTone}` : ''}" data-vista-error-type>${escapeHtml(firstLabel)}</p>
1849
+ <h1 class="vista-error-headline" data-vista-error-title>${escapeHtml(firstParts.headline)}</h1>
1850
+ <p class="vista-error-detail" data-vista-error-detail${firstParts.detail ? '' : ' hidden'}>${escapeHtml(firstParts.detail)}</p>
1851
+ <p class="vista-error-hint" data-vista-error-hint${firstHint ? '' : ' hidden'}>${escapeHtml(firstHint)}</p>
1852
+ </div>
1853
+ </div>
1854
+ <div class="vista-error-stack" data-vista-stack-wrap${firstStack ? '' : ' hidden'}>
1855
+ <h2 class="vista-error-stack-title">CALL STACK</h2>
1856
+ <div class="vista-error-frames-host" data-vista-stack>${firstStackHtml}</div>
1857
+ </div>
1858
+ </div>
1859
+ </div>
1860
+ </div>
1861
+ </div>
1862
+ </section>
1863
+ <button type="button" class="vista-error-minimized-trigger" data-vista-minimized-trigger hidden aria-label="Reopen error overlay">
1864
+ <svg class="vista-error-minimized-logo" viewBox="0 0 168 177" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M81.872 176.988L-2.01405e-06 -2.68173e-06H30.5816L83.5576 121.604L136.774 -2.68173e-06H167.115L85.484 176.988H81.872Z" fill="white"/></svg>
1865
+ <span class="vista-error-minimized-close">×</span>
1866
+ <span class="vista-error-minimized-count" data-vista-minimized-count>${normalizedErrors.length}</span>
1867
+ </button>
1868
+ </div>
1869
+ </body>
854
1870
  </html>`;
855
1871
  }
856
1872
  // ============================================================================
@@ -860,33 +1876,59 @@ function ErrorOverlay({ errors }) {
860
1876
  const normalizedErrors = react_1.default.useMemo(() => normalizeErrors(errors), [errors]);
861
1877
  const [activeIndex, setActiveIndex] = react_1.default.useState(0);
862
1878
  const [isMinimized, setIsMinimized] = react_1.default.useState(false);
1879
+ const [panelExpanded, setPanelExpanded] = react_1.default.useState(false);
1880
+ const [fileTab, setFileTab] = react_1.default.useState(0);
863
1881
  react_1.default.useEffect(() => {
864
1882
  if (activeIndex > normalizedErrors.length - 1) {
865
1883
  setActiveIndex(0);
866
1884
  }
1885
+ setFileTab(0);
867
1886
  }, [activeIndex, normalizedErrors.length]);
868
1887
  const currentIndex = Math.max(0, Math.min(activeIndex, normalizedErrors.length - 1));
869
1888
  const error = normalizedErrors[currentIndex];
870
1889
  if (!error) {
871
1890
  return (0, jsx_runtime_1.jsx)("div", {});
872
1891
  }
873
- const label = getErrorTypeLabel(error.type);
874
- const title = getErrorTitle(error.message || 'Unknown Error', label);
875
- const location = formatLocation(error);
1892
+ const related = error.related && error.related.length > 0
1893
+ ? error.related
1894
+ : [
1895
+ {
1896
+ file: error.file || 'untitled',
1897
+ line: error.line,
1898
+ column: error.column,
1899
+ codeFrame: error.codeFrame,
1900
+ kind: 'source',
1901
+ },
1902
+ ];
1903
+ const activeLocation = related[Math.max(0, Math.min(fileTab, related.length - 1))] || related[0];
1904
+ const isTerminal = !hasCodeView(error);
1905
+ const label = getErrorTypeLabel(error);
1906
+ const tone = problemTone(error);
1907
+ const badge = sourceBadge(error);
1908
+ const parts = splitMessage(error.message || 'Unknown Error');
1909
+ const location = formatCodeHeader(error) || formatLocation(error);
876
1910
  const stackText = parseStackTrace(error.stack || '').join('\n');
877
- const codeFrame = error.codeFrame || '';
878
- const messageHtml = colorizeBlockHtml(error.message || 'Unknown Error');
879
- const codeHtml = colorizeBlockHtml(codeFrame);
880
- const stackHtml = colorizeBlockHtml(stackText);
1911
+ const codeHtml = renderLocationEditor(activeLocation);
1912
+ const stackHtml = renderStackFramesHtml(stackText);
1913
+ const tabName = tabLabel(activeLocation);
1914
+ const crumbs = fileBreadcrumb(activeLocation.file) || location || 'Source';
1915
+ const status = activeLocation.line
1916
+ ? `Ln ${activeLocation.line}, Col ${activeLocation.column || 1}`
1917
+ : statusLine(error);
1918
+ const language = activeLocation.kind === 'server' || activeLocation.kind === 'client'
1919
+ ? 'HTML'
1920
+ : activeLocation.kind === 'log'
1921
+ ? 'Log'
1922
+ : languageFromFile(activeLocation.file);
881
1923
  const minimizeOverlay = react_1.default.useCallback(() => {
882
1924
  setIsMinimized(true);
883
1925
  if (typeof window !== 'undefined') {
884
1926
  const indicator = window.__VISTA_DEVTOOLS_INDICATOR__;
885
1927
  if (indicator && typeof indicator.setError === 'function') {
886
- indicator.setError(title || 'Error', normalizedErrors.length);
1928
+ indicator.setError(parts.headline || 'Error', normalizedErrors.length);
887
1929
  }
888
1930
  }
889
- }, [normalizedErrors.length, title]);
1931
+ }, [normalizedErrors.length, parts.headline]);
890
1932
  const restoreOverlay = react_1.default.useCallback(() => {
891
1933
  setIsMinimized(false);
892
1934
  if (typeof window !== 'undefined') {
@@ -899,7 +1941,12 @@ function ErrorOverlay({ errors }) {
899
1941
  react_1.default.useEffect(() => {
900
1942
  const onKeyDown = (event) => {
901
1943
  if (event.key === 'Escape') {
902
- minimizeOverlay();
1944
+ if (panelExpanded && !isTerminal) {
1945
+ setPanelExpanded(false);
1946
+ }
1947
+ else {
1948
+ minimizeOverlay();
1949
+ }
903
1950
  }
904
1951
  else if (event.key === 'ArrowLeft') {
905
1952
  setActiveIndex((idx) => Math.max(0, idx - 1));
@@ -910,12 +1957,23 @@ function ErrorOverlay({ errors }) {
910
1957
  };
911
1958
  window.addEventListener('keydown', onKeyDown);
912
1959
  return () => window.removeEventListener('keydown', onKeyDown);
913
- }, [minimizeOverlay, normalizedErrors.length]);
914
- return ((0, jsx_runtime_1.jsxs)("div", { className: "vista-error-page-root", "data-embedded": "true", "data-minimized": isMinimized ? 'true' : undefined, children: [(0, jsx_runtime_1.jsx)("style", { children: OVERLAY_STYLES }), (0, jsx_runtime_1.jsx)("div", { className: "vista-error-backdrop", onClick: minimizeOverlay }), (0, jsx_runtime_1.jsxs)("section", { className: "vista-error-panel", role: "dialog", "aria-label": "Vista Error Overlay", "aria-modal": true, onClick: (event) => event.stopPropagation(), children: [(0, jsx_runtime_1.jsxs)("header", { className: "vista-error-header", children: [(0, jsx_runtime_1.jsxs)("div", { className: "vista-error-head-left", children: [(0, jsx_runtime_1.jsxs)("div", { className: "vista-error-top-row", children: [(0, jsx_runtime_1.jsxs)("span", { className: "vista-error-badge", children: [(0, jsx_runtime_1.jsx)("span", { className: "vista-error-badge-dot" }), label] }), normalizedErrors.length > 1 ? ((0, jsx_runtime_1.jsxs)("div", { className: "vista-error-pagination", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "vista-error-page-btn", onClick: () => setActiveIndex((idx) => Math.max(0, idx - 1)), disabled: currentIndex === 0, "aria-label": "Previous error", children: '<' }), (0, jsx_runtime_1.jsxs)("span", { className: "vista-error-page-count", children: [currentIndex + 1, " / ", normalizedErrors.length] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "vista-error-page-btn", onClick: () => setActiveIndex((idx) => Math.min(normalizedErrors.length - 1, idx + 1)), disabled: currentIndex >= normalizedErrors.length - 1, "aria-label": "Next error", children: '>' })] })) : null] }), (0, jsx_runtime_1.jsx)("h2", { className: "vista-error-title", children: title }), (0, jsx_runtime_1.jsx)("p", { className: "vista-error-meta", children: "Vista Dev Overlay" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "vista-error-controls", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "vista-error-btn", onClick: () => copyTextInBrowser(serializeErrorForCopy(error)), "aria-label": "Copy error", children: (0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", xmlns: "http://www.w3.org/2000/svg", children: [(0, jsx_runtime_1.jsx)("rect", { x: "9", y: "9", width: "10", height: "10", rx: "2", stroke: "currentColor", strokeWidth: "2" }), (0, jsx_runtime_1.jsx)("rect", { x: "5", y: "5", width: "10", height: "10", rx: "2", stroke: "currentColor", strokeWidth: "2" })] }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "vista-error-btn", onClick: () => {
1960
+ }, [minimizeOverlay, normalizedErrors.length, panelExpanded, isTerminal]);
1961
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "vista-error-page-root", "data-embedded": "true", "data-minimized": isMinimized ? 'true' : undefined, children: [(0, jsx_runtime_1.jsx)("style", { children: OVERLAY_STYLES }), (0, jsx_runtime_1.jsx)("div", { className: "vista-error-backdrop", onClick: minimizeOverlay }), (0, jsx_runtime_1.jsxs)("section", { className: "vista-error-panel", role: "dialog", "aria-label": "Vista Error Overlay", "aria-modal": true, onClick: (event) => event.stopPropagation(), children: [(0, jsx_runtime_1.jsxs)("div", { className: "vista-ide-titlebar", children: [(0, jsx_runtime_1.jsxs)("div", { className: "vista-ide-traffic", "aria-hidden": "true", children: [(0, jsx_runtime_1.jsx)("span", { className: "is-close" }), (0, jsx_runtime_1.jsx)("span", { className: "is-min" }), (0, jsx_runtime_1.jsx)("span", { className: "is-max" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "vista-ide-title", children: ["Vista \u2014 ", (0, jsx_runtime_1.jsx)("span", { children: isTerminal ? label : tabName })] }), (0, jsx_runtime_1.jsxs)("div", { className: "vista-error-toolbar", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "vista-error-icon-btn", onClick: () => copyTextInBrowser(serializeErrorForCopy(error)), "aria-label": "Copy error", children: (0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", xmlns: "http://www.w3.org/2000/svg", children: [(0, jsx_runtime_1.jsx)("rect", { x: "9", y: "9", width: "10", height: "10", rx: "2", stroke: "currentColor", strokeWidth: "1.6" }), (0, jsx_runtime_1.jsx)("rect", { x: "5", y: "5", width: "10", height: "10", rx: "2", stroke: "currentColor", strokeWidth: "1.6" })] }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "vista-error-icon-btn", onClick: () => {
915
1962
  if (typeof window !== 'undefined') {
916
1963
  window.location.reload();
917
1964
  }
918
- }, "aria-label": "Reload page", children: (0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", xmlns: "http://www.w3.org/2000/svg", children: [(0, jsx_runtime_1.jsx)("path", { d: "M20 12a8 8 0 1 1-2.34-5.66", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }), (0, jsx_runtime_1.jsx)("path", { d: "M20 4V10H14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })] }) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "vista-error-body", children: [location ? ((0, jsx_runtime_1.jsxs)("section", { className: "vista-error-card", children: [(0, jsx_runtime_1.jsx)("h3", { className: "vista-error-card-title", children: "Location" }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "vista-error-location", onClick: () => openInEditorFromBrowser(error.file, error.line, error.column), children: location })] })) : null, (0, jsx_runtime_1.jsxs)("section", { className: "vista-error-card", children: [(0, jsx_runtime_1.jsx)("h3", { className: "vista-error-card-title", children: "Message" }), (0, jsx_runtime_1.jsx)("pre", { className: "vista-error-pre", dangerouslySetInnerHTML: { __html: messageHtml } })] }), codeFrame ? ((0, jsx_runtime_1.jsxs)("section", { className: "vista-error-card", children: [(0, jsx_runtime_1.jsx)("h3", { className: "vista-error-card-title", children: "Code Frame" }), (0, jsx_runtime_1.jsx)("pre", { className: "vista-error-pre", dangerouslySetInnerHTML: { __html: codeHtml } })] })) : null, stackText ? ((0, jsx_runtime_1.jsxs)("section", { className: "vista-error-card", children: [(0, jsx_runtime_1.jsx)("h3", { className: "vista-error-card-title", children: "Stack Trace" }), (0, jsx_runtime_1.jsx)("pre", { className: "vista-error-pre", dangerouslySetInnerHTML: { __html: stackHtml } })] })) : null] })] }), isMinimized ? ((0, jsx_runtime_1.jsxs)("button", { type: "button", className: "vista-error-minimized-trigger", onClick: restoreOverlay, "aria-label": "Reopen error overlay", children: [(0, jsx_runtime_1.jsx)("svg", { className: "vista-error-minimized-logo", viewBox: "0 0 168 177", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: (0, jsx_runtime_1.jsx)("path", { d: "M81.872 176.988L-2.01405e-06 -2.68173e-06H30.5816L83.5576 121.604L136.774 -2.68173e-06H167.115L85.484 176.988H81.872Z", fill: "white" }) }), (0, jsx_runtime_1.jsx)("span", { className: "vista-error-minimized-close", children: "\u00D7" }), (0, jsx_runtime_1.jsx)("span", { className: "vista-error-minimized-count", children: normalizedErrors.length })] })) : null] }));
1965
+ }, "aria-label": "Reload page", children: (0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", xmlns: "http://www.w3.org/2000/svg", children: [(0, jsx_runtime_1.jsx)("path", { d: "M20 12a8 8 0 1 1-2.34-5.66", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" }), (0, jsx_runtime_1.jsx)("path", { d: "M20 4V10H14", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round" })] }) }), normalizedErrors.length > 1 ? ((0, jsx_runtime_1.jsxs)("div", { className: "vista-error-pagination", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "vista-error-page-btn", onClick: () => setActiveIndex((idx) => Math.max(0, idx - 1)), disabled: currentIndex === 0, "aria-label": "Previous error", children: "\u2039" }), (0, jsx_runtime_1.jsxs)("span", { className: "vista-error-page-count", children: [currentIndex + 1, "/", normalizedErrors.length] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "vista-error-page-btn", onClick: () => setActiveIndex((idx) => Math.min(normalizedErrors.length - 1, idx + 1)), disabled: currentIndex >= normalizedErrors.length - 1, "aria-label": "Next error", children: "\u203A" })] })) : null] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "vista-ide-workbench", children: [(0, jsx_runtime_1.jsx)("aside", { className: "vista-ide-activity", "aria-hidden": "true", children: (0, jsx_runtime_1.jsx)("span", { className: "vista-ide-activity-item is-active", children: (0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", children: [(0, jsx_runtime_1.jsx)("rect", { x: "4", y: "3", width: "10", height: "13", rx: "1.2", stroke: "currentColor", strokeWidth: "1.6" }), (0, jsx_runtime_1.jsx)("rect", { x: "10", y: "8", width: "10", height: "13", rx: "1.2", stroke: "currentColor", strokeWidth: "1.6" })] }) }) }), (0, jsx_runtime_1.jsxs)("div", { className: "vista-ide-main", "data-panel-expanded": !isTerminal && panelExpanded ? 'true' : undefined, "data-terminal": isTerminal ? 'true' : undefined, children: [(0, jsx_runtime_1.jsx)("div", { className: "vista-ide-tabbar", children: (0, jsx_runtime_1.jsx)("div", { className: "vista-ide-tabs", children: related.map((item, index) => ((0, jsx_runtime_1.jsxs)("button", { type: "button", className: `vista-ide-tab${index === fileTab ? '' : ' is-inactive'}`, onClick: () => {
1966
+ if (index === fileTab && item.kind === 'source' && item.file && !item.file.endsWith('.html')) {
1967
+ openInEditorFromBrowser(item.file, item.line, item.column);
1968
+ return;
1969
+ }
1970
+ setFileTab(index);
1971
+ }, children: [(0, jsx_runtime_1.jsxs)("svg", { className: "vista-ide-tab-icon", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: [(0, jsx_runtime_1.jsx)("rect", { x: "3", y: "2", width: "10", height: "12", rx: "1.5", stroke: "#4fc1ff", strokeWidth: "1.4" }), (0, jsx_runtime_1.jsx)("path", { d: "M6 6h4M6 9h4M6 12h2", stroke: "#4fc1ff", strokeWidth: "1.2", strokeLinecap: "round" })] }), (0, jsx_runtime_1.jsx)("span", { children: tabLabel(item) })] }, `${item.kind || 'source'}:${item.file}:${index}`))) }) }), (0, jsx_runtime_1.jsx)("div", { className: "vista-ide-crumbs", children: crumbs }), (0, jsx_runtime_1.jsx)("div", { className: "vista-error-code", children: (0, jsx_runtime_1.jsx)("div", { className: "vista-error-editor-host", dangerouslySetInnerHTML: { __html: codeHtml } }) }), (0, jsx_runtime_1.jsxs)("div", { className: "vista-ide-statusbar", children: [(0, jsx_runtime_1.jsx)("span", { children: status }), (0, jsx_runtime_1.jsx)("span", { children: language }), badge ? ((0, jsx_runtime_1.jsx)("span", { className: `vista-ide-source-badge${badge.tone ? ` is-${badge.tone}` : ''}`, children: badge.label })) : null, (0, jsx_runtime_1.jsx)("span", { children: "UTF-8" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "vista-ide-panel", children: [(0, jsx_runtime_1.jsxs)("div", { className: "vista-ide-panel-tabs", children: [(0, jsx_runtime_1.jsx)("span", { className: "is-active", children: "PROBLEMS" }), (0, jsx_runtime_1.jsx)("span", { children: "CALL STACK" }), !isTerminal ? ((0, jsx_runtime_1.jsxs)("button", { type: "button", className: "vista-error-icon-btn vista-ide-panel-toggle", onClick: () => setPanelExpanded((open) => !open), "aria-label": panelExpanded ? 'Restore problems panel' : 'Expand problems panel', "aria-pressed": panelExpanded, children: [(0, jsx_runtime_1.jsx)("svg", { className: "vista-ide-icon-expand", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: (0, jsx_runtime_1.jsx)("path", { d: "M3 6.5V3h3.5M13 6.5V3h-3.5M3 9.5V13h3.5M13 9.5V13h-3.5", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round", strokeLinejoin: "round" }) }), (0, jsx_runtime_1.jsx)("svg", { className: "vista-ide-icon-restore", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: (0, jsx_runtime_1.jsx)("path", { d: "M6.5 3v3.5H3M9.5 3v3.5H13M6.5 13V9.5H3M9.5 13V9.5H13", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round", strokeLinejoin: "round" }) })] })) : null] }), (0, jsx_runtime_1.jsxs)("div", { className: "vista-error-body", children: [(0, jsx_runtime_1.jsxs)("div", { className: "vista-error-problem", children: [(0, jsx_runtime_1.jsx)("span", { className: `vista-error-problem-icon${tone ? ` is-${tone}` : ''}`, "aria-hidden": "true" }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { className: `vista-error-kind${tone ? ` is-${tone}` : ''}`, children: label }), (0, jsx_runtime_1.jsx)("h1", { className: "vista-error-headline", children: parts.headline }), parts.detail ? (0, jsx_runtime_1.jsx)("p", { className: "vista-error-detail", children: parts.detail }) : null, error.hint ? (0, jsx_runtime_1.jsx)("p", { className: "vista-error-hint", children: error.hint }) : null] })] }), stackText ? ((0, jsx_runtime_1.jsxs)("div", { className: "vista-error-stack", children: [(0, jsx_runtime_1.jsx)("h2", { className: "vista-error-stack-title", children: "CALL STACK" }), (0, jsx_runtime_1.jsx)("div", { className: "vista-error-frames-host", dangerouslySetInnerHTML: { __html: stackHtml }, onClick: (event) => {
1972
+ const target = event.target.closest('[data-vista-open-file]');
1973
+ if (!target)
1974
+ return;
1975
+ openInEditorFromBrowser(target.getAttribute('data-vista-open-file') || undefined, Number(target.getAttribute('data-vista-open-line') || 1), Number(target.getAttribute('data-vista-open-col') || 1));
1976
+ } })] })) : null] })] })] })] })] }), isMinimized ? ((0, jsx_runtime_1.jsxs)("button", { type: "button", className: "vista-error-minimized-trigger", onClick: restoreOverlay, "aria-label": "Reopen error overlay", children: [(0, jsx_runtime_1.jsx)("svg", { className: "vista-error-minimized-logo", viewBox: "0 0 168 177", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: (0, jsx_runtime_1.jsx)("path", { d: "M81.872 176.988L-2.01405e-06 -2.68173e-06H30.5816L83.5576 121.604L136.774 -2.68173e-06H167.115L85.484 176.988H81.872Z", fill: "white" }) }), (0, jsx_runtime_1.jsx)("span", { className: "vista-error-minimized-close", children: "\u00D7" }), (0, jsx_runtime_1.jsx)("span", { className: "vista-error-minimized-count", children: normalizedErrors.length })] })) : null] }));
919
1977
  }
920
1978
  // ============================================================================
921
1979
  // Error Boundary (client-side)