@solidjs/start 2.0.0-beta.9 → 2.0.0-rc.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +149 -1
- package/dist/config/app-root-alias.d.ts +7 -0
- package/dist/config/app-root-alias.js +58 -0
- package/dist/config/constants.d.ts +2 -0
- package/dist/config/constants.js +2 -0
- package/dist/config/env.js +13 -10
- package/dist/config/fs-routes/index.js +3 -3
- package/dist/config/fs-routes/tree-shake.d.ts +27 -0
- package/dist/config/fs-routes/tree-shake.js +226 -33
- package/dist/config/index.d.ts +154 -5
- package/dist/config/index.js +23 -10
- package/dist/config/lazy.js +7 -2
- package/dist/config/manifest.d.ts +3 -0
- package/dist/config/manifest.js +26 -4
- package/dist/directives/remove-unused-variables.js +15 -3
- package/dist/directives/xxhash32.js +5 -13
- package/dist/fns/client.js +14 -5
- package/dist/fns/error-handler.d.ts +34 -0
- package/dist/fns/error-handler.js +10 -0
- package/dist/fns/handler.d.ts +1 -1
- package/dist/fns/handler.js +58 -12
- package/dist/fns/plugins.d.ts +34 -0
- package/dist/fns/plugins.js +33 -0
- package/dist/fns/serialization.d.ts +15 -0
- package/dist/fns/serialization.js +36 -6
- package/dist/middleware/index.js +4 -1
- package/dist/server/StartServer.jsx +1 -1
- package/dist/server/assets/render.jsx +1 -1
- package/dist/server/collect-styles.d.ts +3 -1
- package/dist/server/collect-styles.js +8 -5
- package/dist/server/fetchEvent.d.ts +10 -0
- package/dist/server/fetchEvent.js +10 -0
- package/dist/server/handler.d.ts +3 -4
- package/dist/server/handler.js +22 -56
- package/dist/server/index.d.ts +3 -1
- package/dist/server/index.jsx +1 -0
- package/dist/server/manifest/dev-client-manifest.js +1 -1
- package/dist/server/manifest/dev-ssr-manifest.js +1 -1
- package/dist/server/spa/StartServer.jsx +1 -1
- package/dist/server/spa/handler.d.ts +2 -3
- package/dist/server/spa/handler.js +2 -2
- package/dist/server/strip-path-base.d.ts +1 -0
- package/dist/server/strip-path-base.js +10 -0
- package/dist/server/types.d.ts +12 -1
- package/dist/server/web-stream.d.ts +9 -0
- package/dist/server/web-stream.js +29 -0
- package/dist/shared/ErrorBoundary.jsx +3 -3
- package/dist/shared/clientOnly.js +3 -1
- package/dist/shared/{dev-overlay → dev-toolbar/error-viewer}/CodeView.jsx +3 -3
- package/dist/shared/dev-toolbar/error-viewer/create-stack-frame.js +90 -0
- package/dist/shared/{dev-overlay/DevOverlayDialog.d.ts → dev-toolbar/error-viewer/index.d.ts} +3 -2
- package/dist/shared/{dev-overlay/DevOverlayDialog.jsx → dev-toolbar/error-viewer/index.jsx} +66 -77
- package/dist/shared/dev-toolbar/error-viewer/styles.css +224 -0
- package/dist/shared/dev-toolbar/functions/BlobViewer.css +4 -0
- package/dist/shared/dev-toolbar/functions/BlobViewer.d.ts +6 -0
- package/dist/shared/dev-toolbar/functions/BlobViewer.jsx +37 -0
- package/dist/shared/dev-toolbar/functions/FormDataViewer.d.ts +5 -0
- package/dist/shared/dev-toolbar/functions/FormDataViewer.jsx +23 -0
- package/dist/shared/dev-toolbar/functions/HeadersViewer.css +8 -0
- package/dist/shared/dev-toolbar/functions/HeadersViewer.d.ts +6 -0
- package/dist/shared/dev-toolbar/functions/HeadersViewer.jsx +15 -0
- package/dist/shared/dev-toolbar/functions/HexViewer.css +34 -0
- package/dist/shared/dev-toolbar/functions/HexViewer.d.ts +11 -0
- package/dist/shared/dev-toolbar/functions/HexViewer.jsx +70 -0
- package/dist/shared/dev-toolbar/functions/SerovalValue.css +5 -0
- package/dist/shared/dev-toolbar/functions/SerovalValue.d.ts +7 -0
- package/dist/shared/dev-toolbar/functions/SerovalValue.jsx +10 -0
- package/dist/shared/dev-toolbar/functions/SerovalViewer.css +70 -0
- package/dist/shared/dev-toolbar/functions/SerovalViewer.d.ts +6 -0
- package/dist/shared/dev-toolbar/functions/SerovalViewer.jsx +796 -0
- package/dist/shared/dev-toolbar/functions/URLSearchParamsViewer.d.ts +5 -0
- package/dist/shared/dev-toolbar/functions/URLSearchParamsViewer.jsx +22 -0
- package/dist/shared/dev-toolbar/functions/index.d.ts +13 -0
- package/dist/shared/dev-toolbar/functions/index.jsx +216 -0
- package/dist/shared/dev-toolbar/functions/styles.css +109 -0
- package/dist/shared/dev-toolbar/functions/tracker.d.ts +19 -0
- package/dist/shared/dev-toolbar/functions/tracker.js +29 -0
- package/dist/shared/{dev-overlay → dev-toolbar}/icons.d.ts +9 -0
- package/dist/shared/{dev-overlay → dev-toolbar}/icons.jsx +19 -1
- package/dist/shared/dev-toolbar/index.css +88 -0
- package/dist/shared/dev-toolbar/index.d.ts +6 -0
- package/dist/shared/dev-toolbar/index.jsx +179 -0
- package/dist/shared/ui/Badge.css +33 -0
- package/dist/shared/ui/Badge.d.ts +7 -0
- package/dist/shared/ui/Badge.jsx +7 -0
- package/dist/shared/ui/Button.css +32 -0
- package/dist/shared/ui/Button.d.ts +4 -0
- package/dist/shared/ui/Button.jsx +4 -0
- package/dist/shared/ui/Cascade.css +29 -0
- package/dist/shared/ui/Cascade.d.ts +4 -0
- package/dist/shared/ui/Cascade.jsx +4 -0
- package/dist/shared/ui/Dialog.css +25 -0
- package/dist/shared/ui/Dialog.d.ts +5 -0
- package/dist/shared/ui/Dialog.jsx +5 -0
- package/dist/shared/ui/IconButton.css +39 -0
- package/dist/shared/ui/IconButton.d.ts +4 -0
- package/dist/shared/ui/IconButton.jsx +4 -0
- package/dist/shared/ui/Placeholder.css +12 -0
- package/dist/shared/ui/Placeholder.d.ts +6 -0
- package/dist/shared/ui/Placeholder.jsx +4 -0
- package/dist/shared/ui/Section.css +18 -0
- package/dist/shared/ui/Section.d.ts +9 -0
- package/dist/shared/ui/Section.jsx +10 -0
- package/dist/shared/ui/Select.css +37 -0
- package/dist/shared/ui/Select.d.ts +4 -0
- package/dist/shared/ui/Select.jsx +4 -0
- package/dist/shared/ui/Table.css +22 -0
- package/dist/shared/ui/Table.d.ts +11 -0
- package/dist/shared/ui/Table.jsx +13 -0
- package/dist/shared/ui/Tabs.css +51 -0
- package/dist/shared/ui/Tabs.d.ts +6 -0
- package/dist/shared/ui/Tabs.jsx +6 -0
- package/dist/shared/ui/Text.css +73 -0
- package/dist/shared/ui/Text.d.ts +12 -0
- package/dist/shared/ui/Text.jsx +17 -0
- package/package.json +36 -29
- package/dist/shared/dev-overlay/createStackFrame.js +0 -56
- package/dist/shared/dev-overlay/index.d.ts +0 -5
- package/dist/shared/dev-overlay/index.jsx +0 -39
- package/dist/shared/dev-overlay/styles.css +0 -292
- /package/dist/shared/{dev-overlay → dev-toolbar/error-viewer}/CodeView.d.ts +0 -0
- /package/dist/shared/{dev-overlay/createStackFrame.d.ts → dev-toolbar/error-viewer/create-stack-frame.d.ts} +0 -0
- /package/dist/shared/{dev-overlay → dev-toolbar/error-viewer}/download.d.ts +0 -0
- /package/dist/shared/{dev-overlay → dev-toolbar/error-viewer}/download.js +0 -0
- /package/dist/shared/{dev-overlay → dev-toolbar/error-viewer}/get-source-map.d.ts +0 -0
- /package/dist/shared/{dev-overlay → dev-toolbar/error-viewer}/get-source-map.js +0 -0
|
@@ -2,14 +2,12 @@
|
|
|
2
2
|
import ErrorStackParser from "error-stack-parser";
|
|
3
3
|
import * as htmlToImage from "html-to-image";
|
|
4
4
|
import { createMemo, createSignal, ErrorBoundary, For, Show, Suspense } from "solid-js";
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
import info from "../../../package.json" with { type: "json" };
|
|
5
|
+
import IconButton from "../../ui/IconButton.jsx";
|
|
6
|
+
import { Select, SelectOption } from "../../ui/Select.jsx";
|
|
7
|
+
import { ArrowLeftIcon, ArrowRightIcon, CameraIcon, DiscordIcon, GithubIcon, RefreshIcon, ViewCompiledIcon, ViewOriginalIcon, } from "../icons.jsx";
|
|
9
8
|
import { CodeView } from "./CodeView.jsx";
|
|
10
|
-
import { createStackFrame } from "./
|
|
9
|
+
import { createStackFrame } from "./create-stack-frame.js";
|
|
11
10
|
import download from "./download.js";
|
|
12
|
-
import { ArrowLeftIcon, ArrowRightIcon, CameraIcon, DiscordIcon, GithubIcon, RefreshIcon, SolidStartIcon, ViewCompiledIcon, ViewOriginalIcon, } from "./icons.jsx";
|
|
13
11
|
import "./styles.css";
|
|
14
12
|
export function classNames(...classes) {
|
|
15
13
|
return classes.filter(Boolean).join(" ");
|
|
@@ -25,9 +23,9 @@ function ErrorInfo(props) {
|
|
|
25
23
|
}
|
|
26
24
|
return { message: e.toString() };
|
|
27
25
|
});
|
|
28
|
-
return (<span data-start-
|
|
29
|
-
<span data-start-
|
|
30
|
-
<span data-start-
|
|
26
|
+
return (<span data-start-error-viewer-error-info>
|
|
27
|
+
<span data-start-error-viewer-error-info-name>{error().name}</span>
|
|
28
|
+
<span data-start-error-viewer-error-info-message>{error().message}</span>
|
|
31
29
|
</span>);
|
|
32
30
|
}
|
|
33
31
|
function getFileName(source) {
|
|
@@ -46,23 +44,23 @@ function getFilePath(source) {
|
|
|
46
44
|
return `${getFileName(source.source)}${line}${column}`;
|
|
47
45
|
}
|
|
48
46
|
function CodeFallback() {
|
|
49
|
-
return (<div data-start-
|
|
47
|
+
return (<div data-start-error-viewer-stack-frames-code-fallback>
|
|
50
48
|
<span>Source not available.</span>
|
|
51
49
|
</div>);
|
|
52
50
|
}
|
|
53
51
|
function StackFramesContent(props) {
|
|
54
52
|
const stackframes = ErrorStackParser.parse(props.error);
|
|
55
53
|
const [selectedFrame, setSelectedFrame] = createSignal(stackframes[0]);
|
|
56
|
-
return (<div data-start-
|
|
57
|
-
<div data-start-
|
|
54
|
+
return (<div data-start-error-viewer-stack-frames-content>
|
|
55
|
+
<div data-start-error-viewer-stack-frames-code>
|
|
58
56
|
<ErrorBoundary fallback={null}>
|
|
59
57
|
{(() => {
|
|
60
58
|
const data = createStackFrame(selectedFrame(), () => props.isCompiled);
|
|
61
59
|
return (<Suspense fallback={<CodeFallback />}>
|
|
62
60
|
<Show when={data()} keyed fallback={<CodeFallback />}>
|
|
63
61
|
{source => (<>
|
|
64
|
-
<span data-start-
|
|
65
|
-
<div data-start-
|
|
62
|
+
<span data-start-error-viewer-stack-frames-code-source>{source.source}</span>
|
|
63
|
+
<div data-start-error-viewer-stack-frames-code-container>
|
|
66
64
|
<CodeView fileName={source.source} line={source.line} content={source.content}/>
|
|
67
65
|
</div>
|
|
68
66
|
</>)}
|
|
@@ -71,13 +69,13 @@ function StackFramesContent(props) {
|
|
|
71
69
|
})()}
|
|
72
70
|
</ErrorBoundary>
|
|
73
71
|
</div>
|
|
74
|
-
<Select data-start-
|
|
72
|
+
<Select data-start-error-viewer-stack-frames value={selectedFrame()} onChange={setSelectedFrame}>
|
|
75
73
|
<For each={stackframes}>
|
|
76
|
-
{current => (<ErrorBoundary fallback={<
|
|
77
|
-
<span data-start-
|
|
74
|
+
{current => (<ErrorBoundary fallback={<SelectOption value={current} disabled data-start-error-viewer-stack-frame>
|
|
75
|
+
<span data-start-error-viewer-stack-frame-function>
|
|
78
76
|
{current.functionName ?? "<anonymous>"}
|
|
79
77
|
</span>
|
|
80
|
-
<span data-start-
|
|
78
|
+
<span data-start-error-viewer-stack-frame-file>
|
|
81
79
|
{getFilePath({
|
|
82
80
|
source: current.getFileName(),
|
|
83
81
|
content: "",
|
|
@@ -86,16 +84,18 @@ function StackFramesContent(props) {
|
|
|
86
84
|
name: current.getFunctionName(),
|
|
87
85
|
})}
|
|
88
86
|
</span>
|
|
89
|
-
</
|
|
87
|
+
</SelectOption>}>
|
|
90
88
|
{(() => {
|
|
91
89
|
const data = createStackFrame(current, () => props.isCompiled);
|
|
92
90
|
return (<Suspense>
|
|
93
91
|
<Show when={data()} keyed>
|
|
94
|
-
{source => (<SelectOption data-start-
|
|
95
|
-
<span data-start-
|
|
92
|
+
{source => (<SelectOption data-start-error-viewer-stack-frame value={current}>
|
|
93
|
+
<span data-start-error-viewer-stack-frame-function>
|
|
96
94
|
{source.name ?? "<anonymous>"}
|
|
97
95
|
</span>
|
|
98
|
-
<span data-start-
|
|
96
|
+
<span data-start-error-viewer-stack-frame-file>
|
|
97
|
+
{getFilePath(source)}
|
|
98
|
+
</span>
|
|
99
99
|
</SelectOption>)}
|
|
100
100
|
</Show>
|
|
101
101
|
</Suspense>);
|
|
@@ -112,7 +112,7 @@ function StackFrames(props) {
|
|
|
112
112
|
}
|
|
113
113
|
const ISSUE_THREAD = "https://github.com/solidjs/solid-start/issues/new";
|
|
114
114
|
const DISCORD_INVITE = "https://discord.com/invite/solidjs";
|
|
115
|
-
export default function
|
|
115
|
+
export default function ErrorViewer(props) {
|
|
116
116
|
const [currentPage, setCurrentPage] = createSignal(1);
|
|
117
117
|
const [isCompiled, setIsCompiled] = createSignal(false);
|
|
118
118
|
const length = createMemo(() => props.errors.length);
|
|
@@ -164,63 +164,52 @@ export default function DevOverlayDialog(props) {
|
|
|
164
164
|
function redirectToDiscord() {
|
|
165
165
|
window.open(DISCORD_INVITE, "_blank").focus();
|
|
166
166
|
}
|
|
167
|
-
return (<
|
|
168
|
-
<
|
|
169
|
-
<div>
|
|
170
|
-
<
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
<span>{info.version}</span>
|
|
167
|
+
return (<Show when={props.show}>
|
|
168
|
+
<div data-start-dev-toolbar-panel>
|
|
169
|
+
<div ref={setPanel} data-start-error-viewer>
|
|
170
|
+
<div data-start-error-viewer-navbar>
|
|
171
|
+
<div data-start-error-viewer-navbar-left>
|
|
172
|
+
<Show when={props.errors.length > 1}>
|
|
173
|
+
<div data-start-error-viewer-pagination>
|
|
174
|
+
<IconButton data-start-error-viewer-button onClick={goPrev} type="button">
|
|
175
|
+
<ArrowLeftIcon title="Go Previous"/>
|
|
176
|
+
</IconButton>
|
|
177
|
+
<div data-start-error-viewer-page-counter>
|
|
178
|
+
{`${truncated()} of ${props.errors.length}`}
|
|
180
179
|
</div>
|
|
181
|
-
<
|
|
182
|
-
<
|
|
183
|
-
|
|
184
|
-
<ArrowLeftIcon title="Go Previous"/>
|
|
185
|
-
</button>
|
|
186
|
-
<div data-start-dev-overlay-page-counter>
|
|
187
|
-
{`${truncated()} of ${props.errors.length}`}
|
|
188
|
-
</div>
|
|
189
|
-
<button data-start-dev-overlay-button onClick={goNext} type="button">
|
|
190
|
-
<ArrowRightIcon title="Go Next"/>
|
|
191
|
-
</button>
|
|
192
|
-
</div>
|
|
193
|
-
</Show>
|
|
194
|
-
</div>
|
|
195
|
-
<div data-start-dev-overlay-controls>
|
|
196
|
-
<button data-start-dev-overlay-button onClick={redirectToGithub} type="button">
|
|
197
|
-
<GithubIcon title="Create an issue thread on Github"/>
|
|
198
|
-
</button>
|
|
199
|
-
<button data-start-dev-overlay-button onClick={redirectToDiscord} type="button">
|
|
200
|
-
<DiscordIcon title="Join our Discord Channel"/>
|
|
201
|
-
</button>
|
|
202
|
-
<button data-start-dev-overlay-button onClick={downloadScreenshot} type="button">
|
|
203
|
-
<CameraIcon title="Capture Error Overlay"/>
|
|
204
|
-
</button>
|
|
205
|
-
<button data-start-dev-overlay-button onClick={toggleIsCompiled} type="button">
|
|
206
|
-
<Show when={isCompiled()} fallback={<ViewOriginalIcon title="View Original Source"/>}>
|
|
207
|
-
<ViewCompiledIcon title="View Compiled Source"/>
|
|
208
|
-
</Show>
|
|
209
|
-
</button>
|
|
210
|
-
<button data-start-dev-overlay-button onClick={props.resetError} type="button">
|
|
211
|
-
<RefreshIcon title="Reset Error"/>
|
|
212
|
-
</button>
|
|
180
|
+
<IconButton data-start-error-viewer-button onClick={goNext} type="button">
|
|
181
|
+
<ArrowRightIcon title="Go Next"/>
|
|
182
|
+
</IconButton>
|
|
213
183
|
</div>
|
|
214
|
-
</div>
|
|
215
|
-
<Show when={props.errors[truncated() - 1]} keyed>
|
|
216
|
-
{current => (<div data-start-dev-overlay-content>
|
|
217
|
-
<ErrorInfo error={current}/>
|
|
218
|
-
<StackFrames error={current} isCompiled={isCompiled()}/>
|
|
219
|
-
</div>)}
|
|
220
184
|
</Show>
|
|
221
185
|
</div>
|
|
222
|
-
|
|
186
|
+
<div data-start-error-viewer-controls>
|
|
187
|
+
<IconButton data-start-error-viewer-button onClick={redirectToGithub} type="button">
|
|
188
|
+
<GithubIcon title="Create an issue thread on Github"/>
|
|
189
|
+
</IconButton>
|
|
190
|
+
<IconButton data-start-error-viewer-button onClick={redirectToDiscord} type="button">
|
|
191
|
+
<DiscordIcon title="Join our Discord Channel"/>
|
|
192
|
+
</IconButton>
|
|
193
|
+
<IconButton data-start-error-viewer-button onClick={downloadScreenshot} type="button">
|
|
194
|
+
<CameraIcon title="Capture Error Overlay"/>
|
|
195
|
+
</IconButton>
|
|
196
|
+
<IconButton data-start-error-viewer-button onClick={toggleIsCompiled} type="button">
|
|
197
|
+
<Show when={isCompiled()} fallback={<ViewOriginalIcon title="View Original Source"/>}>
|
|
198
|
+
<ViewCompiledIcon title="View Compiled Source"/>
|
|
199
|
+
</Show>
|
|
200
|
+
</IconButton>
|
|
201
|
+
<IconButton data-start-error-viewer-button onClick={props.resetError} type="button">
|
|
202
|
+
<RefreshIcon title="Reset Error"/>
|
|
203
|
+
</IconButton>
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
<Show when={props.errors[truncated() - 1]} keyed>
|
|
207
|
+
{current => (<div data-start-error-viewer-content>
|
|
208
|
+
<ErrorInfo error={current}/>
|
|
209
|
+
<StackFrames error={current} isCompiled={isCompiled()}/>
|
|
210
|
+
</div>)}
|
|
211
|
+
</Show>
|
|
223
212
|
</div>
|
|
224
|
-
</
|
|
225
|
-
</
|
|
213
|
+
</div>
|
|
214
|
+
</Show>);
|
|
226
215
|
}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
[data-start-error-viewer] {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
|
|
5
|
+
width: 100%;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
[data-start-error-viewer-navbar] {
|
|
9
|
+
display: flex;
|
|
10
|
+
flex-direction: row;
|
|
11
|
+
align-items: center;
|
|
12
|
+
justify-content: space-between;
|
|
13
|
+
gap: 0.5rem;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
[data-start-error-viewer-pagination] {
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-direction: row;
|
|
19
|
+
align-items: center;
|
|
20
|
+
justify-content: center;
|
|
21
|
+
gap: 0.5rem;
|
|
22
|
+
border-radius: 9999px;
|
|
23
|
+
color: rgb(249 250 251);
|
|
24
|
+
background-color: rgb(17 24 39);
|
|
25
|
+
padding: 0.25rem;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
[data-start-error-viewer-button] {
|
|
29
|
+
/* empty */
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
[data-start-error-viewer-button]:hover {
|
|
33
|
+
color: rgb(229 231 235);
|
|
34
|
+
background-color: rgb(55 65 81);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
[data-start-error-viewer-button]:focus {
|
|
38
|
+
outline: 2px solid transparent;
|
|
39
|
+
outline-offset: 2px;
|
|
40
|
+
outline-color: rgb(229 231 235);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
[data-start-error-viewer-button]:focus-visible {
|
|
44
|
+
box-shadow: 0 0 0 calc(3px) rgb(17 24 39 / 0.75);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
[data-start-error-viewer-button]:active {
|
|
48
|
+
color: rgb(243 244 246);
|
|
49
|
+
background-color: rgb(31 41 55);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
[data-start-error-viewer-button] > svg {
|
|
53
|
+
height: 1.5rem;
|
|
54
|
+
width: 1.5rem;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
[data-start-error-viewer-page-counter] {
|
|
58
|
+
font-size: 0.875rem;
|
|
59
|
+
line-height: 1.25rem;
|
|
60
|
+
font-weight: 600;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
[data-start-error-viewer-navbar-left] {
|
|
64
|
+
display: flex;
|
|
65
|
+
flex-direction: row;
|
|
66
|
+
gap: 0.5rem;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
[data-start-error-viewer-controls] {
|
|
70
|
+
display: flex;
|
|
71
|
+
flex-direction: row;
|
|
72
|
+
align-items: center;
|
|
73
|
+
justify-content: center;
|
|
74
|
+
gap: 0.25rem;
|
|
75
|
+
border-radius: 9999px;
|
|
76
|
+
color: rgb(249 250 251);
|
|
77
|
+
padding: 0.25rem;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
[data-start-error-viewer-content] {
|
|
81
|
+
display: flex;
|
|
82
|
+
flex-direction: column;
|
|
83
|
+
gap: 0.75rem;
|
|
84
|
+
padding: 1rem;
|
|
85
|
+
|
|
86
|
+
border-top-width: 1px;
|
|
87
|
+
border-top-style: solid;
|
|
88
|
+
border-top-color: oklch(87% 0.065 274.039);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
[data-start-error-viewer-error-info] {
|
|
92
|
+
display: flex;
|
|
93
|
+
flex-direction: column;
|
|
94
|
+
gap: 0.25rem;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
[data-start-error-viewer-error-info-name] {
|
|
98
|
+
font-weight: 700;
|
|
99
|
+
color: rgb(249 250 251);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
[data-start-error-viewer-error-info-message] {
|
|
103
|
+
font-size: 1.5rem;
|
|
104
|
+
line-height: 2rem;
|
|
105
|
+
color: rgb(239 68 68);
|
|
106
|
+
font-weight: 700;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
[data-start-error-viewer-stack-frames-content] {
|
|
110
|
+
display: flex;
|
|
111
|
+
flex-direction: column;
|
|
112
|
+
gap: 0.75rem;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
[data-start-error-viewer-stack-frames] {
|
|
116
|
+
flex: 1 1 0%;
|
|
117
|
+
max-height: 16rem;
|
|
118
|
+
overflow-y: auto;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
[data-start-error-viewer-stack-frame] {
|
|
122
|
+
display: flex;
|
|
123
|
+
flex-direction: row;
|
|
124
|
+
align-items: center;
|
|
125
|
+
justify-content: space-between;
|
|
126
|
+
gap: 1rem;
|
|
127
|
+
color: rgb(249 250 251);
|
|
128
|
+
cursor: default;
|
|
129
|
+
user-select: none;
|
|
130
|
+
padding-top: 0.5rem;
|
|
131
|
+
padding-bottom: 0.5rem;
|
|
132
|
+
padding-left: 1rem;
|
|
133
|
+
padding-right: 1rem;
|
|
134
|
+
font-size: 0.875rem;
|
|
135
|
+
line-height: 1.25rem;
|
|
136
|
+
outline: none;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
[data-start-error-viewer-stack-frame][tc-active],
|
|
140
|
+
[data-start-error-viewer-stack-frame][tc-selected],
|
|
141
|
+
[data-start-error-viewer-stack-frame]:focus {
|
|
142
|
+
color: rgb(219 234 254);
|
|
143
|
+
background-color: rgb(30 58 138);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
[data-start-error-viewer-stack-frame-function] {
|
|
147
|
+
font-weight: 700;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
[data-start-error-viewer-stack-frame-file] {
|
|
151
|
+
white-space: nowrap;
|
|
152
|
+
font-size: 0.75rem;
|
|
153
|
+
/* 12px */
|
|
154
|
+
line-height: 1rem;
|
|
155
|
+
/* 16px */
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
[data-start-error-viewer-stack-frames-code] {
|
|
159
|
+
padding: 0.5rem 1rem;
|
|
160
|
+
gap: 0.25rem;
|
|
161
|
+
flex: 1 1 0%;
|
|
162
|
+
display: flex;
|
|
163
|
+
flex-direction: column;
|
|
164
|
+
align-items: center;
|
|
165
|
+
justify-content: center;
|
|
166
|
+
border-radius: 0.5rem;
|
|
167
|
+
background-color: rgb(17 24 39);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
[data-start-error-viewer-stack-frames-code-fallback] {
|
|
171
|
+
display: flex;
|
|
172
|
+
align-items: center;
|
|
173
|
+
justify-content: center;
|
|
174
|
+
color: rgb(249 250 251);
|
|
175
|
+
min-height: 16rem;
|
|
176
|
+
font-size: 0.875rem;
|
|
177
|
+
line-height: 1.25rem;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
[data-start-error-viewer-stack-frames-code-source] {
|
|
181
|
+
font-size: 0.875rem;
|
|
182
|
+
line-height: 1.25rem;
|
|
183
|
+
color: rgb(249 250 251);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
[data-start-error-viewer-stack-frames-code-container] {
|
|
187
|
+
width: 100%;
|
|
188
|
+
overflow: hidden;
|
|
189
|
+
min-width: 100%;
|
|
190
|
+
max-height: 16rem;
|
|
191
|
+
border-top-width: 1px;
|
|
192
|
+
border-top-style: solid;
|
|
193
|
+
border-top-color: oklch(87% 0.065 274.039);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
[data-start-error-viewer-code-view] {
|
|
197
|
+
overflow: auto;
|
|
198
|
+
min-width: 100%;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
[data-start-error-viewer-code-view] > .shiki {
|
|
202
|
+
float: left;
|
|
203
|
+
min-width: 100%;
|
|
204
|
+
overflow-x: auto;
|
|
205
|
+
font-size: 0.75rem;
|
|
206
|
+
line-height: 1rem;
|
|
207
|
+
counter-reset: step;
|
|
208
|
+
counter-increment: step calc(var(--error-viewer-code-view-start, 1) - 1);
|
|
209
|
+
background-color: transparent !important;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
[data-start-error-viewer-code-view] > .shiki .line::before {
|
|
213
|
+
content: counter(step);
|
|
214
|
+
counter-increment: step;
|
|
215
|
+
width: 1rem;
|
|
216
|
+
margin-right: 1.5rem;
|
|
217
|
+
display: inline-block;
|
|
218
|
+
text-align: right;
|
|
219
|
+
color: rgba(115, 138, 148, 0.4);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
[data-start-error-viewer-error-line] {
|
|
223
|
+
background-color: rgba(239, 68, 68, 0.4);
|
|
224
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { createMemo, createResource, onCleanup, Show, Suspense } from "solid-js";
|
|
2
|
+
import { Badge } from "../../ui/Badge.jsx";
|
|
3
|
+
import Button from "../../ui/Button.jsx";
|
|
4
|
+
import "./BlobViewer.css";
|
|
5
|
+
function DocumentIcon(props) {
|
|
6
|
+
return (<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" {...props}>
|
|
7
|
+
<title>{props.title}</title>
|
|
8
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"/>
|
|
9
|
+
</svg>);
|
|
10
|
+
}
|
|
11
|
+
function BlobViewerInner(props) {
|
|
12
|
+
const fileURL = createMemo(() => URL.createObjectURL(props.source));
|
|
13
|
+
onCleanup(() => {
|
|
14
|
+
URL.revokeObjectURL(fileURL());
|
|
15
|
+
});
|
|
16
|
+
function openFileInNewTab() {
|
|
17
|
+
const link = document.createElement("a");
|
|
18
|
+
link.href = fileURL();
|
|
19
|
+
link.target = "_blank"; // Open in a new tab
|
|
20
|
+
link.style.display = "none"; // Hide the link
|
|
21
|
+
document.body.appendChild(link);
|
|
22
|
+
link.click();
|
|
23
|
+
document.body.removeChild(link);
|
|
24
|
+
}
|
|
25
|
+
return (<Button data-start-blob-viewer onClick={() => openFileInNewTab()}>
|
|
26
|
+
{props.source instanceof File ? (<Badge type="info">
|
|
27
|
+
<DocumentIcon title={props.source.name}/>
|
|
28
|
+
{props.source.name}
|
|
29
|
+
</Badge>) : (<Badge type="info">{props.source.type}</Badge>)}
|
|
30
|
+
</Button>);
|
|
31
|
+
}
|
|
32
|
+
export function BlobViewer(props) {
|
|
33
|
+
const [data] = createResource(() => props.source);
|
|
34
|
+
return (<Suspense>
|
|
35
|
+
<Show when={data()}>{current => <BlobViewerInner source={current()}/>}</Show>
|
|
36
|
+
</Suspense>);
|
|
37
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createResource, For, Show, Suspense } from "solid-js";
|
|
2
|
+
import { Section } from "../../ui/Section.jsx";
|
|
3
|
+
import { BlobViewer } from "./BlobViewer.jsx";
|
|
4
|
+
import { PropertySeparator, SerovalValue } from "./SerovalValue.jsx";
|
|
5
|
+
function FormDataViewerInner(props) {
|
|
6
|
+
return (<Section title="FormData" options={{ size: "sm" }}>
|
|
7
|
+
<div data-start-form-data-viewer data-start-properties>
|
|
8
|
+
<For each={Array.from(props.source.entries())}>
|
|
9
|
+
{([key, value]) => (<div data-start-property>
|
|
10
|
+
<SerovalValue value={`"${key}"`}/>
|
|
11
|
+
<PropertySeparator />
|
|
12
|
+
{typeof value === "string" ? (<SerovalValue value={`"${JSON.stringify(value)}"`}/>) : (<BlobViewer source={value}/>)}
|
|
13
|
+
</div>)}
|
|
14
|
+
</For>
|
|
15
|
+
</div>
|
|
16
|
+
</Section>);
|
|
17
|
+
}
|
|
18
|
+
export function FormDataViewer(props) {
|
|
19
|
+
const [data] = createResource(() => props.source);
|
|
20
|
+
return (<Suspense>
|
|
21
|
+
<Show when={data()}>{current => <FormDataViewerInner source={current()}/>}</Show>
|
|
22
|
+
</Suspense>);
|
|
23
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { For } from "solid-js";
|
|
2
|
+
import { PropertySeparator, SerovalValue } from "./SerovalValue.jsx";
|
|
3
|
+
import "./HeadersViewer.css";
|
|
4
|
+
import { Text } from "../../ui/Text.jsx";
|
|
5
|
+
export function HeadersViewer(props) {
|
|
6
|
+
return (<div data-start-headers-viewer data-start-properties>
|
|
7
|
+
<For each={Array.from(props.headers.entries())}>
|
|
8
|
+
{([key, value]) => (<div data-start-property>
|
|
9
|
+
<Text options={{ size: "xs", weight: "semibold", wrap: "nowrap" }}>{key}</Text>
|
|
10
|
+
<PropertySeparator />
|
|
11
|
+
<SerovalValue value={value}/>
|
|
12
|
+
</div>)}
|
|
13
|
+
</For>
|
|
14
|
+
</div>);
|
|
15
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[data-start-hex-viewer] {
|
|
2
|
+
display: flex;
|
|
3
|
+
border: 1px oklch(87% 0.065 274.039) solid;
|
|
4
|
+
overflow: auto;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
[data-start-hex-viewer-bytes] {
|
|
8
|
+
flex: 1;
|
|
9
|
+
display: flex;
|
|
10
|
+
flex-direction: column;
|
|
11
|
+
gap: 0.5rem;
|
|
12
|
+
padding: 0.5rem;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
[data-start-hex-viewer-text] {
|
|
16
|
+
flex: 1;
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-direction: column;
|
|
19
|
+
gap: 0.5rem;
|
|
20
|
+
padding: 0.5rem;
|
|
21
|
+
border-left: 1px oklch(87% 0.065 274.039) solid;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
[data-start-hex-row] {
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
gap: 1rem;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
[data-start-hex-text] {
|
|
31
|
+
display: flex;
|
|
32
|
+
align-items: center;
|
|
33
|
+
justify-content: start;
|
|
34
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type JSX } from "solid-js";
|
|
2
|
+
import "./HexViewer.css";
|
|
3
|
+
interface HexViewerInnerProps {
|
|
4
|
+
bytes: Uint8Array;
|
|
5
|
+
}
|
|
6
|
+
export declare function HexViewerInner(props: HexViewerInnerProps): JSX.Element;
|
|
7
|
+
export interface HexViewerProps {
|
|
8
|
+
bytes: Uint8Array | Promise<Uint8Array>;
|
|
9
|
+
}
|
|
10
|
+
export declare function HexViewer(props: HexViewerProps): JSX.Element;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { createMemo, createResource, For, Show, Suspense } from "solid-js";
|
|
2
|
+
import { Text } from "../../ui/Text.jsx";
|
|
3
|
+
import "./HexViewer.css";
|
|
4
|
+
function toHex(num, digits = 2) {
|
|
5
|
+
return num.toString(16).padStart(digits, "0").toUpperCase();
|
|
6
|
+
}
|
|
7
|
+
function HexChunk(props) {
|
|
8
|
+
const content = createMemo(() => {
|
|
9
|
+
const byte1 = props.bytes[0] || 0;
|
|
10
|
+
const byte2 = props.bytes[1] || 0;
|
|
11
|
+
const byte3 = props.bytes[2] || 0;
|
|
12
|
+
const byte4 = props.bytes[3] || 0;
|
|
13
|
+
return `${toHex(byte1)} ${toHex(byte2)} ${toHex(byte3)} ${toHex(byte4)}`;
|
|
14
|
+
});
|
|
15
|
+
return (<Text data-start-hex-chunk options={{ size: "xs", weight: "bold", wrap: "nowrap" }}>
|
|
16
|
+
{content()}
|
|
17
|
+
</Text>);
|
|
18
|
+
}
|
|
19
|
+
function HexRow(props) {
|
|
20
|
+
const chunk1 = createMemo(() => props.bytes.subarray(0, 4));
|
|
21
|
+
const chunk2 = createMemo(() => props.bytes.subarray(4, 8));
|
|
22
|
+
const chunk3 = createMemo(() => props.bytes.subarray(8, 12));
|
|
23
|
+
const chunk4 = createMemo(() => props.bytes.subarray(12, 16));
|
|
24
|
+
return (<div data-start-hex-row>
|
|
25
|
+
<HexChunk bytes={chunk1()}/>
|
|
26
|
+
<HexChunk bytes={chunk2()}/>
|
|
27
|
+
<HexChunk bytes={chunk3()}/>
|
|
28
|
+
<HexChunk bytes={chunk4()}/>
|
|
29
|
+
</div>);
|
|
30
|
+
}
|
|
31
|
+
function replaceString(string) {
|
|
32
|
+
const result = string.codePointAt(0);
|
|
33
|
+
if (result == null) {
|
|
34
|
+
return string;
|
|
35
|
+
}
|
|
36
|
+
return String.fromCodePoint(result + 0x2400);
|
|
37
|
+
}
|
|
38
|
+
function HexText(props) {
|
|
39
|
+
const text = createMemo(() => {
|
|
40
|
+
const decoder = new TextDecoder();
|
|
41
|
+
const result = decoder.decode(props.bytes).replaceAll(/[\x00-\x1F]/g, replaceString);
|
|
42
|
+
return result;
|
|
43
|
+
});
|
|
44
|
+
return (<div data-start-hex-text>
|
|
45
|
+
<Text options={{ size: "xs", weight: "bold", wrap: "nowrap" }}>{text()}</Text>
|
|
46
|
+
</div>);
|
|
47
|
+
}
|
|
48
|
+
export function HexViewerInner(props) {
|
|
49
|
+
const rows = createMemo(() => {
|
|
50
|
+
const arrays = [];
|
|
51
|
+
for (let i = 0, len = props.bytes.length; i < len; i += 16) {
|
|
52
|
+
arrays.push(props.bytes.subarray(i, i + 16));
|
|
53
|
+
}
|
|
54
|
+
return arrays;
|
|
55
|
+
});
|
|
56
|
+
return (<div data-start-hex-viewer>
|
|
57
|
+
<div data-start-hex-viewer-bytes>
|
|
58
|
+
<For each={rows()}>{current => <HexRow bytes={current}/>}</For>
|
|
59
|
+
</div>
|
|
60
|
+
<div data-start-hex-viewer-text>
|
|
61
|
+
<For each={rows()}>{current => <HexText bytes={current}/>}</For>
|
|
62
|
+
</div>
|
|
63
|
+
</div>);
|
|
64
|
+
}
|
|
65
|
+
export function HexViewer(props) {
|
|
66
|
+
const [data] = createResource(() => props.bytes);
|
|
67
|
+
return (<Suspense>
|
|
68
|
+
<Show when={data()}>{current => <HexViewerInner bytes={current()}/>}</Show>
|
|
69
|
+
</Suspense>);
|
|
70
|
+
}
|