@solidjs/start 0.4.10 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/api-handler.ts +64 -0
- package/config/fs-router.js +39 -14
- package/config/index.d.ts +2 -1
- package/config/index.js +52 -24
- package/config/{server-fns-runtime.jsx → server-fns-runtime.ts} +4 -1
- package/config/{server-handler.js → server-handler.ts} +71 -38
- package/config/{server-runtime.jsx → server-runtime.ts} +50 -27
- package/{server/middleware.ts → middleware/index.ts} +12 -46
- package/package.json +12 -12
- package/server/StartServer.tsx +3 -3
- package/server/fetchEvent.ts +115 -0
- package/{entry/index.ts → server/handler.ts} +17 -19
- package/server/index.tsx +2 -2
- package/server/{page-event.tsx → pageEvent.ts} +5 -36
- package/{entry/spa/index.ts → server/spa/handler.ts} +2 -2
- package/server/spa/index.tsx +1 -2
- package/server/types.ts +14 -4
- package/shared/FileRoutes.tsx +2 -2
- package/shared/GET.ts +5 -0
- package/shared/HttpHeader.tsx +18 -1
- package/shared/HttpStatusCode.tsx +3 -1
- package/shared/dev-overlay/DevOverlayDialog.tsx +51 -49
- package/shared/dev-overlay/createStackFrame.ts +9 -1
- package/shared/dev-overlay/styles.css +5 -1
- package/shared/index.tsx +2 -1
- package/shared/routes.ts +1 -132
|
@@ -1,59 +1,25 @@
|
|
|
1
1
|
import {
|
|
2
|
-
defineMiddleware,
|
|
3
|
-
getRequestIP,
|
|
4
2
|
H3Event,
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
defineMiddleware,
|
|
4
|
+
sendWebResponse
|
|
7
5
|
} from "vinxi/server";
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
const h3EventSymbol = Symbol("h3Event");
|
|
11
|
-
const fetchEventSymbol = Symbol("fetchEvent");
|
|
12
|
-
const eventTraps = {
|
|
13
|
-
get(target, prop) {
|
|
14
|
-
if (prop === fetchEventSymbol) return target;
|
|
15
|
-
return target[prop] ?? target[h3EventSymbol][prop];
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export function createFetchEvent(event: H3Event): FetchEvent {
|
|
20
|
-
const request = toWebRequest(event);
|
|
21
|
-
return new Proxy(
|
|
22
|
-
{
|
|
23
|
-
request: request,
|
|
24
|
-
clientAddress: getRequestIP(event),
|
|
25
|
-
locals: {},
|
|
26
|
-
// @ts-ignore
|
|
27
|
-
[h3EventSymbol]: event
|
|
28
|
-
},
|
|
29
|
-
eventTraps
|
|
30
|
-
) as unknown as FetchEvent;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function cloneEvent<T extends FetchEvent>(fetchEvent: T): T {
|
|
34
|
-
return new Proxy({ ...fetchEvent[fetchEventSymbol] }, eventTraps);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function getFetchEvent(h3Event: H3Event): FetchEvent {
|
|
38
|
-
if (!h3Event[fetchEventSymbol]) {
|
|
39
|
-
const fetchEvent = createFetchEvent(h3Event);
|
|
40
|
-
h3Event[fetchEventSymbol] = fetchEvent;
|
|
41
|
-
// @ts-ignore
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return h3Event[fetchEventSymbol];
|
|
45
|
-
}
|
|
6
|
+
import { getFetchEvent } from "../server/fetchEvent";
|
|
7
|
+
import type { FetchEvent } from "../server/types";
|
|
46
8
|
|
|
47
9
|
/** Function responsible for receiving an observable [operation]{@link Operation} and returning a [result]{@link OperationResult}. */
|
|
48
10
|
|
|
49
11
|
export type MiddlewareFn = (event: FetchEvent) => Promise<unknown> | unknown;
|
|
50
12
|
/** This composes an array of Exchanges into a single ExchangeIO function */
|
|
51
13
|
|
|
52
|
-
type RequestMiddleware = (event: FetchEvent) => Response | Promise<Response> | void | Promise<void>;
|
|
14
|
+
export type RequestMiddleware = (event: FetchEvent) => Response | Promise<Response> | void | Promise<void>;
|
|
15
|
+
|
|
16
|
+
// copy-pasted from h3/dist/index.d.ts
|
|
17
|
+
type EventHandlerResponse<T = any> = T | Promise<T>;
|
|
18
|
+
type ResponseMiddlewareResponseParam = { body?: Awaited<EventHandlerResponse> };
|
|
53
19
|
|
|
54
|
-
type ResponseMiddleware = (
|
|
20
|
+
export type ResponseMiddleware = (
|
|
55
21
|
event: FetchEvent,
|
|
56
|
-
response:
|
|
22
|
+
response: ResponseMiddlewareResponseParam
|
|
57
23
|
) => Response | Promise<Response> | void | Promise<void>;
|
|
58
24
|
|
|
59
25
|
function wrapRequestMiddleware(onRequest: RequestMiddleware) {
|
|
@@ -69,7 +35,7 @@ function wrapRequestMiddleware(onRequest: RequestMiddleware) {
|
|
|
69
35
|
}
|
|
70
36
|
|
|
71
37
|
function wrapResponseMiddleware(onBeforeResponse: ResponseMiddleware) {
|
|
72
|
-
return async (h3Event: H3Event, response:
|
|
38
|
+
return async (h3Event: H3Event, response: ResponseMiddlewareResponseParam) => {
|
|
73
39
|
const fetchEvent = getFetchEvent(h3Event);
|
|
74
40
|
const mwResponse = await onBeforeResponse(fetchEvent, response);
|
|
75
41
|
if (!mwResponse) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidjs/start",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": "Ryan Carniato",
|
|
6
6
|
"publishConfig": {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"client",
|
|
11
11
|
"config",
|
|
12
|
-
"
|
|
12
|
+
"middleware",
|
|
13
13
|
"server",
|
|
14
14
|
"shared",
|
|
15
15
|
"*.d.ts"
|
|
@@ -18,8 +18,7 @@
|
|
|
18
18
|
"exports": {
|
|
19
19
|
".": "./shared/index.tsx",
|
|
20
20
|
"./config": "./config/index.js",
|
|
21
|
-
"./
|
|
22
|
-
"./entry/spa": "./entry/spa/index.ts",
|
|
21
|
+
"./middleware": "./middleware/index.ts",
|
|
23
22
|
"./server": "./server/index.tsx",
|
|
24
23
|
"./server/spa": "./server/spa/index.tsx",
|
|
25
24
|
"./client": "./client/index.tsx",
|
|
@@ -31,8 +30,8 @@
|
|
|
31
30
|
".": [
|
|
32
31
|
"./shared/index.tsx"
|
|
33
32
|
],
|
|
34
|
-
"./
|
|
35
|
-
"./
|
|
33
|
+
"./middleware": [
|
|
34
|
+
"./middleware/index.ts"
|
|
36
35
|
],
|
|
37
36
|
"./server": [
|
|
38
37
|
"./server/index.tsx"
|
|
@@ -43,23 +42,24 @@
|
|
|
43
42
|
}
|
|
44
43
|
},
|
|
45
44
|
"devDependencies": {
|
|
46
|
-
"solid-js": "^1.8.
|
|
47
|
-
"vinxi": "^0.1
|
|
45
|
+
"solid-js": "^1.8.12",
|
|
46
|
+
"vinxi": "^0.2.1"
|
|
48
47
|
},
|
|
49
48
|
"dependencies": {
|
|
50
|
-
"@vinxi/plugin-directives": "^0.
|
|
51
|
-
"@vinxi/server-components": "^0.
|
|
52
|
-
"@vinxi/server-functions": "^0.1
|
|
49
|
+
"@vinxi/plugin-directives": "^0.2.0",
|
|
50
|
+
"@vinxi/server-components": "^0.2.0",
|
|
51
|
+
"@vinxi/server-functions": "^0.2.1",
|
|
53
52
|
"defu": "^6.1.2",
|
|
54
53
|
"error-stack-parser": "^2.1.4",
|
|
55
54
|
"html-to-image": "^1.11.11",
|
|
55
|
+
"radix3": "^1.1.0",
|
|
56
56
|
"seroval": "^1.0.2",
|
|
57
57
|
"seroval-plugins": "^1.0.2",
|
|
58
58
|
"shikiji": "^0.9.12",
|
|
59
59
|
"source-map-js": "^1.0.2",
|
|
60
60
|
"terracotta": "^1.0.4",
|
|
61
61
|
"vite-plugin-inspect": "^0.7.33",
|
|
62
|
-
"vite-plugin-solid": "^2.
|
|
62
|
+
"vite-plugin-solid": "^2.9.1"
|
|
63
63
|
},
|
|
64
64
|
"scripts": {
|
|
65
65
|
"typecheck": "tsc --noEmit --checkJs false --skipLibCheck"
|
package/server/StartServer.tsx
CHANGED
|
@@ -35,9 +35,9 @@ export function StartServer(props: { document: Component<DocumentComponentProps>
|
|
|
35
35
|
|
|
36
36
|
let assets = [];
|
|
37
37
|
Promise.resolve().then(async () => {
|
|
38
|
-
if (context.
|
|
39
|
-
const matches = [...context.
|
|
40
|
-
while (matches.length && (!matches[0].
|
|
38
|
+
if (context.router && context.router.matches) {
|
|
39
|
+
const matches = [...context.router.matches];
|
|
40
|
+
while (matches.length && (!matches[0].info || !matches[0].info.filesystem))
|
|
41
41
|
matches.shift();
|
|
42
42
|
const matched = matches.length && matchRoute(matches, context.routes);
|
|
43
43
|
if (matched) {
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import {
|
|
2
|
+
H3Event,
|
|
3
|
+
HTTPEventSymbol,
|
|
4
|
+
appendResponseHeader,
|
|
5
|
+
getRequestIP,
|
|
6
|
+
getResponseHeader,
|
|
7
|
+
getResponseHeaders,
|
|
8
|
+
getResponseStatus,
|
|
9
|
+
getResponseStatusText,
|
|
10
|
+
removeResponseHeader,
|
|
11
|
+
setHeader,
|
|
12
|
+
setResponseHeader,
|
|
13
|
+
setResponseStatus,
|
|
14
|
+
toWebRequest
|
|
15
|
+
} from "vinxi/server";
|
|
16
|
+
import type { FetchEvent, ResponseStub } from "./types";
|
|
17
|
+
|
|
18
|
+
const fetchEventSymbol = Symbol("fetchEvent");
|
|
19
|
+
|
|
20
|
+
export function createFetchEvent(event: H3Event): FetchEvent {
|
|
21
|
+
const request = toWebRequest(event);
|
|
22
|
+
return {
|
|
23
|
+
request: request,
|
|
24
|
+
response: createResponseStub(event),
|
|
25
|
+
clientAddress: getRequestIP(event),
|
|
26
|
+
locals: {},
|
|
27
|
+
nativeEvent: event,
|
|
28
|
+
[HTTPEventSymbol]: event
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function cloneEvent<T extends FetchEvent>(fetchEvent: T): T {
|
|
33
|
+
return {
|
|
34
|
+
...fetchEvent,
|
|
35
|
+
[HTTPEventSymbol]: fetchEvent[HTTPEventSymbol]
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function getFetchEvent(h3Event: H3Event): FetchEvent {
|
|
40
|
+
if (!h3Event[fetchEventSymbol]) {
|
|
41
|
+
const fetchEvent = createFetchEvent(h3Event);
|
|
42
|
+
h3Event[fetchEventSymbol] = fetchEvent;
|
|
43
|
+
// @ts-ignore
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return h3Event[fetchEventSymbol];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function mergeResponseHeaders(h3Event, headers) {
|
|
50
|
+
for (const [key, value] of headers.entries()) {
|
|
51
|
+
setHeader(h3Event, key, value);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
class HeaderProxy {
|
|
56
|
+
constructor(private event: H3Event) {}
|
|
57
|
+
get(key: string) {
|
|
58
|
+
const h = getResponseHeader(this.event, key);
|
|
59
|
+
return Array.isArray(h) ? h.join(", ") : h;
|
|
60
|
+
}
|
|
61
|
+
has(key: string) {
|
|
62
|
+
return this.get(key) !== undefined;
|
|
63
|
+
}
|
|
64
|
+
set(key: string, value: string) {
|
|
65
|
+
return setResponseHeader(this.event, key, value);
|
|
66
|
+
}
|
|
67
|
+
delete(key: string) {
|
|
68
|
+
return removeResponseHeader(this.event, key);
|
|
69
|
+
}
|
|
70
|
+
append(key: string, value: string) {
|
|
71
|
+
appendResponseHeader(this.event, key, value);
|
|
72
|
+
}
|
|
73
|
+
getSetCookie() {
|
|
74
|
+
const cookies = getResponseHeader(this.event, "Set-Cookie");
|
|
75
|
+
return Array.isArray(cookies) ? cookies : [cookies];
|
|
76
|
+
}
|
|
77
|
+
forEach(fn: (value: string, key: string, object: Headers) => void) {
|
|
78
|
+
return this.entries().forEach(([key, value]) => fn(value, key, this));
|
|
79
|
+
}
|
|
80
|
+
entries() {
|
|
81
|
+
return getResponseHeaders(this.event).map(([key, value]) => [
|
|
82
|
+
key,
|
|
83
|
+
Array.isArray(value) ? value.join(", ") : value
|
|
84
|
+
]);
|
|
85
|
+
}
|
|
86
|
+
keys() {
|
|
87
|
+
return getResponseHeaders(this.event).map(([key]) => key);
|
|
88
|
+
}
|
|
89
|
+
values() {
|
|
90
|
+
return getResponseHeaders(this.event).map(([key, value]) =>
|
|
91
|
+
Array.isArray(value) ? value.join(", ") : value
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
[Symbol.iterator]() {
|
|
95
|
+
return this.entries()[Symbol.iterator]();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function createResponseStub(event: H3Event): ResponseStub {
|
|
100
|
+
return {
|
|
101
|
+
get status() {
|
|
102
|
+
return getResponseStatus(event);
|
|
103
|
+
},
|
|
104
|
+
set status(v) {
|
|
105
|
+
setResponseStatus(event, v);
|
|
106
|
+
},
|
|
107
|
+
get statusText() {
|
|
108
|
+
return getResponseStatusText(event);
|
|
109
|
+
},
|
|
110
|
+
set statusText(v) {
|
|
111
|
+
setResponseStatus(event, getResponseStatus(), v);
|
|
112
|
+
},
|
|
113
|
+
headers: new HeaderProxy(event)
|
|
114
|
+
};
|
|
115
|
+
}
|
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
import { sharedConfig } from "solid-js";
|
|
2
|
-
import { renderToStream } from "solid-js/web";
|
|
2
|
+
import { renderToStream, renderToString } from "solid-js/web";
|
|
3
3
|
/* @ts-ignore */
|
|
4
4
|
import { provideRequestEvent } from "solid-js/web/storage";
|
|
5
5
|
import {
|
|
6
6
|
EventHandlerObject,
|
|
7
7
|
EventHandlerRequest,
|
|
8
8
|
H3Event,
|
|
9
|
-
HTTPMethod,
|
|
10
9
|
eventHandler,
|
|
11
10
|
sendRedirect,
|
|
12
11
|
setHeader,
|
|
13
12
|
setResponseStatus
|
|
14
13
|
} from "vinxi/server";
|
|
15
|
-
import { getFetchEvent } from "
|
|
16
|
-
import { createPageEvent } from "
|
|
17
|
-
import {
|
|
18
|
-
import { matchAPIRoute } from "../shared/routes";
|
|
14
|
+
import { getFetchEvent } from "./fetchEvent";
|
|
15
|
+
import { createPageEvent } from "./pageEvent";
|
|
16
|
+
import { FetchEvent, PageEvent } from "./types";
|
|
19
17
|
|
|
20
18
|
export function createBaseHandler(
|
|
21
19
|
fn: (context: PageEvent) => unknown,
|
|
@@ -35,21 +33,21 @@ export function createBaseHandler(
|
|
|
35
33
|
onBeforeResponse: options.onBeforeResponse,
|
|
36
34
|
handler: (e: H3Event<EventHandlerRequest> & { startEvent: FetchEvent }) => {
|
|
37
35
|
const event = getFetchEvent(e);
|
|
36
|
+
const mode = import.meta.env.START_SSR;
|
|
38
37
|
|
|
39
38
|
return provideRequestEvent(event, async () => {
|
|
40
|
-
//
|
|
41
|
-
const match = matchAPIRoute(new URL(event.request.url).pathname, event.request.method as HTTPMethod)
|
|
42
|
-
if (match) {
|
|
43
|
-
const mod = await match.handler.import();
|
|
44
|
-
const fn = mod[event.request.method];
|
|
45
|
-
(event as APIEvent).params = match.params;
|
|
46
|
-
sharedConfig.context = { event } as any;
|
|
47
|
-
return await fn(event);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// render stream
|
|
51
|
-
const doAsync = import.meta.env.START_SSR === "async";
|
|
39
|
+
// render
|
|
52
40
|
const context = await createPageEvent(event);
|
|
41
|
+
if (mode === "sync") {
|
|
42
|
+
const html = renderToString(() => {
|
|
43
|
+
(sharedConfig.context as any).event = context;
|
|
44
|
+
return fn(context);
|
|
45
|
+
}, options);
|
|
46
|
+
if (context.response && context.response.headers.get("Location")) {
|
|
47
|
+
return sendRedirect(event, context.response.headers.get("Location"));
|
|
48
|
+
}
|
|
49
|
+
return html;
|
|
50
|
+
}
|
|
53
51
|
let cloned = { ...options };
|
|
54
52
|
if (cloned.onCompleteAll) {
|
|
55
53
|
const og = cloned.onCompleteAll;
|
|
@@ -72,7 +70,7 @@ export function createBaseHandler(
|
|
|
72
70
|
if (context.response && context.response.headers.get("Location")) {
|
|
73
71
|
return sendRedirect(event, context.response.headers.get("Location"));
|
|
74
72
|
}
|
|
75
|
-
if (
|
|
73
|
+
if (mode === "async") return stream;
|
|
76
74
|
// fix cloudflare streaming
|
|
77
75
|
const { writable, readable } = new TransformStream();
|
|
78
76
|
stream.pipeTo(writable);
|
package/server/index.tsx
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
-
appendResponseHeader,
|
|
3
2
|
getCookie,
|
|
4
|
-
|
|
5
|
-
removeResponseHeader,
|
|
6
|
-
setCookie,
|
|
7
|
-
setResponseHeader,
|
|
8
|
-
setResponseStatus
|
|
3
|
+
setCookie
|
|
9
4
|
} from "vinxi/server";
|
|
10
5
|
import { createRoutes } from "../shared/FileRoutes";
|
|
11
6
|
import { FetchEvent, PageEvent } from "./types";
|
|
@@ -27,7 +22,7 @@ function initFromFlash(ctx: FetchEvent) {
|
|
|
27
22
|
export async function createPageEvent(ctx: FetchEvent) {
|
|
28
23
|
const clientManifest = import.meta.env.MANIFEST["client"];
|
|
29
24
|
const serverManifest = import.meta.env.MANIFEST["ssr"];
|
|
30
|
-
|
|
25
|
+
ctx.response.headers.set("Cache-Control", "no-cache");
|
|
31
26
|
// const prevPath = ctx.request.headers.get("x-solid-referrer");
|
|
32
27
|
// const mutation = ctx.request.headers.get("x-solid-mutation") === "true";
|
|
33
28
|
const pageEvent: PageEvent = Object.assign(ctx, {
|
|
@@ -40,36 +35,10 @@ export async function createPageEvent(ctx: FetchEvent) {
|
|
|
40
35
|
)
|
|
41
36
|
: [])
|
|
42
37
|
],
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
components: {
|
|
46
|
-
status: props => {
|
|
47
|
-
setResponseStatus(ctx, props.code, props.text);
|
|
48
|
-
return () => setResponseStatus(ctx, 200);
|
|
49
|
-
},
|
|
50
|
-
header: props => {
|
|
51
|
-
if (props.append) {
|
|
52
|
-
appendResponseHeader(ctx, props.name, props.value);
|
|
53
|
-
} else {
|
|
54
|
-
setResponseHeader(ctx, props.name, props.value);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return () => {
|
|
58
|
-
const value = getResponseHeader(ctx, props.name);
|
|
59
|
-
|
|
60
|
-
// Todo: review this logic still the same in H3
|
|
61
|
-
// H3 supports arrays so its possible there is no need to split..
|
|
62
|
-
// typeof check here is to guard but ultimately may be unneeded
|
|
63
|
-
if (value && typeof value === "string") {
|
|
64
|
-
const values = value.split(", ");
|
|
65
|
-
const index = values.indexOf(props.value);
|
|
66
|
-
index !== -1 && values.splice(index, 1);
|
|
67
|
-
if (values.length) setResponseHeader(ctx, props.name, values.join(", "));
|
|
68
|
-
else removeResponseHeader(ctx, props.name);
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
}
|
|
38
|
+
router: {
|
|
39
|
+
submission: initFromFlash(ctx)
|
|
72
40
|
},
|
|
41
|
+
routes: createRoutes(),
|
|
73
42
|
// prevUrl: prevPath || "",
|
|
74
43
|
// mutation: mutation,
|
|
75
44
|
// $type: FETCH_EVENT,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createBaseHandler } from "
|
|
2
|
-
import { FetchEvent, PageEvent } from "
|
|
1
|
+
import { createBaseHandler } from "../handler";
|
|
2
|
+
import { FetchEvent, PageEvent } from "../types";
|
|
3
3
|
|
|
4
4
|
export function createHandler(
|
|
5
5
|
fn: (context: PageEvent) => unknown,
|
package/server/spa/index.tsx
CHANGED
package/server/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { JSX } from "solid-js";
|
|
2
|
-
import type
|
|
2
|
+
import { HTTPEventSymbol, type EventHandlerRequest, type H3Event } from "vinxi/server";
|
|
3
3
|
|
|
4
4
|
// export const FETCH_EVENT = "$FETCH";
|
|
5
5
|
|
|
@@ -16,10 +16,21 @@ export type ContextMatches = {
|
|
|
16
16
|
params: unknown;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
-
export interface
|
|
19
|
+
export interface ResponseStub {
|
|
20
|
+
status?: number;
|
|
21
|
+
statusText?: string;
|
|
22
|
+
headers: Headers;
|
|
23
|
+
}
|
|
24
|
+
export interface FetchEvent {
|
|
20
25
|
request: Request;
|
|
26
|
+
response: ResponseStub;
|
|
21
27
|
clientAddress: string;
|
|
22
|
-
locals:
|
|
28
|
+
locals: RequestEventLocals;
|
|
29
|
+
nativeEvent: H3Event<EventHandlerRequest>;
|
|
30
|
+
[HTTPEventSymbol]: H3Event<EventHandlerRequest>;
|
|
31
|
+
}
|
|
32
|
+
export interface RequestEventLocals {
|
|
33
|
+
[key: string | symbol]: any;
|
|
23
34
|
}
|
|
24
35
|
export interface PageEvent extends FetchEvent {
|
|
25
36
|
manifest: any;
|
|
@@ -29,7 +40,6 @@ export interface PageEvent extends FetchEvent {
|
|
|
29
40
|
// $type: typeof FETCH_EVENT;
|
|
30
41
|
$islands: Set<string>;
|
|
31
42
|
// mutation: boolean;
|
|
32
|
-
response?: Response;
|
|
33
43
|
}
|
|
34
44
|
|
|
35
45
|
export interface APIEvent extends FetchEvent {
|
package/shared/FileRoutes.tsx
CHANGED
|
@@ -10,8 +10,8 @@ export function createRoutes() {
|
|
|
10
10
|
return {
|
|
11
11
|
...route,
|
|
12
12
|
...(route.$$route ? route.$$route.require().route : undefined),
|
|
13
|
-
|
|
14
|
-
...(route.$$route ? route.$$route.require().route.
|
|
13
|
+
info: {
|
|
14
|
+
...(route.$$route ? route.$$route.require().route.info : {}),
|
|
15
15
|
filesystem: true
|
|
16
16
|
},
|
|
17
17
|
component: lazyRoute(
|
package/shared/GET.ts
ADDED
package/shared/HttpHeader.tsx
CHANGED
|
@@ -4,7 +4,24 @@ import { getRequestEvent, isServer } from "solid-js/web";
|
|
|
4
4
|
export function HttpHeader(props: { name: string; value: string; append?: boolean }) {
|
|
5
5
|
if (isServer) {
|
|
6
6
|
const event = getRequestEvent();
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
if (props.append) event.response.headers.append(props.name, props.value);
|
|
9
|
+
else event.response.headers.set(props.name, props.value);
|
|
10
|
+
|
|
11
|
+
onCleanup(() => {
|
|
12
|
+
if (event.nativeEvent.handled) return;
|
|
13
|
+
const value = event.response.headers.get(props.name);
|
|
14
|
+
if (!value) return;
|
|
15
|
+
if (!value.includes(", ")) {
|
|
16
|
+
if (value === props.value) event.response.headers.delete(props.name);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const values = value.split(", ");
|
|
20
|
+
const index = values.indexOf(props.value);
|
|
21
|
+
index !== -1 && values.splice(index, 1);
|
|
22
|
+
if (values.length) event.response.headers.set(props.name, values.join(","));
|
|
23
|
+
else event.response.headers.delete(props.name);
|
|
24
|
+
});
|
|
8
25
|
}
|
|
9
26
|
|
|
10
27
|
return null;
|
|
@@ -4,7 +4,9 @@ import { getRequestEvent, isServer } from "solid-js/web";
|
|
|
4
4
|
export function HttpStatusCode(props: { code: number, text?: string }) {
|
|
5
5
|
if (isServer) {
|
|
6
6
|
const event = getRequestEvent();
|
|
7
|
-
|
|
7
|
+
event.response.status = props.code;
|
|
8
|
+
event.response.statusText = props.text;
|
|
9
|
+
onCleanup(() => !event.nativeEvent.handled && (event.response.status = 200));
|
|
8
10
|
}
|
|
9
11
|
return null;
|
|
10
12
|
}
|
|
@@ -190,7 +190,7 @@ export default function DevOverlayDialog(props: DevOverlayDialogProps): JSX.Elem
|
|
|
190
190
|
if (current) {
|
|
191
191
|
htmlToImage.toPng(current, {
|
|
192
192
|
style: {
|
|
193
|
-
transform: 'scale(
|
|
193
|
+
transform: 'scale(0.75)',
|
|
194
194
|
},
|
|
195
195
|
}).then((url) => {
|
|
196
196
|
download(url, 'start-screenshot.png');
|
|
@@ -216,59 +216,61 @@ export default function DevOverlayDialog(props: DevOverlayDialogProps): JSX.Elem
|
|
|
216
216
|
<Dialog class="dev-overlay" isOpen>
|
|
217
217
|
<div>
|
|
218
218
|
<DialogOverlay class="dev-overlay-background"/>
|
|
219
|
-
<DialogPanel ref={setPanel} class="dev-overlay-panel">
|
|
220
|
-
<div class="dev-overlay-
|
|
221
|
-
<div class="dev-overlay-navbar
|
|
222
|
-
<div class="dev-overlay-
|
|
223
|
-
<div>
|
|
224
|
-
<
|
|
225
|
-
|
|
226
|
-
<span>{info.version as string}</span>
|
|
227
|
-
</div>
|
|
228
|
-
<Show when={props.errors.length > 1}>
|
|
229
|
-
<div class="dev-overlay-pagination">
|
|
230
|
-
<button class="dev-overlay-button" onClick={goPrev} type="button">
|
|
231
|
-
<ArrowLeftIcon title="Go Previous" />
|
|
232
|
-
</button>
|
|
233
|
-
<div class="dev-overlay-page-counter">
|
|
234
|
-
{`${truncated()} of ${props.errors.length}`}
|
|
219
|
+
<DialogPanel ref={setPanel} class="dev-overlay-panel-container">
|
|
220
|
+
<div class="dev-overlay-panel">
|
|
221
|
+
<div class="dev-overlay-navbar">
|
|
222
|
+
<div class="dev-overlay-navbar-left">
|
|
223
|
+
<div class="dev-overlay-version">
|
|
224
|
+
<div>
|
|
225
|
+
<SolidStartIcon title="Solid Start Version" />
|
|
235
226
|
</div>
|
|
236
|
-
<
|
|
237
|
-
<ArrowRightIcon title="Go Next" />
|
|
238
|
-
</button>
|
|
227
|
+
<span>{info.version as string}</span>
|
|
239
228
|
</div>
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
<button class="dev-overlay-button" onClick={toggleIsCompiled} type="button">
|
|
253
|
-
<Show when={isCompiled()} fallback={(
|
|
254
|
-
<ViewOriginalIcon title="View Original Source" />
|
|
255
|
-
)}>
|
|
256
|
-
<ViewCompiledIcon title="View Compiled Source" />
|
|
229
|
+
<Show when={props.errors.length > 1}>
|
|
230
|
+
<div class="dev-overlay-pagination">
|
|
231
|
+
<button class="dev-overlay-button" onClick={goPrev} type="button">
|
|
232
|
+
<ArrowLeftIcon title="Go Previous" />
|
|
233
|
+
</button>
|
|
234
|
+
<div class="dev-overlay-page-counter">
|
|
235
|
+
{`${truncated()} of ${props.errors.length}`}
|
|
236
|
+
</div>
|
|
237
|
+
<button class="dev-overlay-button" onClick={goNext} type="button">
|
|
238
|
+
<ArrowRightIcon title="Go Next" />
|
|
239
|
+
</button>
|
|
240
|
+
</div>
|
|
257
241
|
</Show>
|
|
258
|
-
</
|
|
259
|
-
<
|
|
260
|
-
<
|
|
261
|
-
|
|
242
|
+
</div>
|
|
243
|
+
<div class="dev-overlay-controls">
|
|
244
|
+
<button class="dev-overlay-button" onClick={redirectToGithub} type="button">
|
|
245
|
+
<GithubIcon title="Create an issue thread on Github" />
|
|
246
|
+
</button>
|
|
247
|
+
<button class="dev-overlay-button" onClick={redirectToDiscord} type="button">
|
|
248
|
+
<DiscordIcon title="Join our Discord Channel" />
|
|
249
|
+
</button>
|
|
250
|
+
<button class="dev-overlay-button" onClick={downloadScreenshot} type="button">
|
|
251
|
+
<CameraIcon title="Capture Error Overlay" />
|
|
252
|
+
</button>
|
|
253
|
+
<button class="dev-overlay-button" onClick={toggleIsCompiled} type="button">
|
|
254
|
+
<Show when={isCompiled()} fallback={(
|
|
255
|
+
<ViewOriginalIcon title="View Original Source" />
|
|
256
|
+
)}>
|
|
257
|
+
<ViewCompiledIcon title="View Compiled Source" />
|
|
258
|
+
</Show>
|
|
259
|
+
</button>
|
|
260
|
+
<button class="dev-overlay-button" onClick={props.resetError} type="button">
|
|
261
|
+
<RefreshIcon title="Reset Error" />
|
|
262
|
+
</button>
|
|
263
|
+
</div>
|
|
262
264
|
</div>
|
|
265
|
+
<Show when={props.errors[truncated() - 1]} keyed>
|
|
266
|
+
{(current) => (
|
|
267
|
+
<div class="dev-overlay-content">
|
|
268
|
+
<ErrorInfo error={current} />
|
|
269
|
+
<StackFrames error={current} isCompiled={isCompiled()} />
|
|
270
|
+
</div>
|
|
271
|
+
)}
|
|
272
|
+
</Show>
|
|
263
273
|
</div>
|
|
264
|
-
<Show when={props.errors[truncated() - 1]} keyed>
|
|
265
|
-
{(current) => (
|
|
266
|
-
<div class="dev-overlay-content">
|
|
267
|
-
<ErrorInfo error={current} />
|
|
268
|
-
<StackFrames error={current} isCompiled={isCompiled()} />
|
|
269
|
-
</div>
|
|
270
|
-
)}
|
|
271
|
-
</Show>
|
|
272
274
|
</DialogPanel>
|
|
273
275
|
</div>
|
|
274
276
|
</Dialog>
|