@solidjs/start 1.1.7 → 2.0.0-alpha.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/README.md +88 -8
- package/dist/client/StartClient.d.ts +0 -1
- package/dist/client/StartClient.jsx +2 -4
- package/dist/client/index.d.ts +2 -3
- package/dist/client/index.jsx +2 -4
- package/dist/client/mount.js +10 -2
- package/dist/client/spa/index.d.ts +1 -2
- package/dist/client/spa/index.jsx +1 -2
- package/dist/config/constants.d.ts +16 -0
- package/dist/config/constants.js +16 -0
- package/dist/config/dev-server.d.ts +2 -0
- package/dist/config/dev-server.js +108 -0
- package/dist/config/fs-router.d.ts +37 -0
- package/dist/config/fs-router.js +153 -0
- package/dist/config/fs-routes/fs-watcher.d.ts +3 -0
- package/dist/config/fs-routes/fs-watcher.js +49 -0
- package/dist/config/fs-routes/index.d.ts +7 -0
- package/dist/config/fs-routes/index.js +109 -0
- package/dist/config/fs-routes/router.d.ts +37 -0
- package/dist/config/fs-routes/router.js +136 -0
- package/dist/config/fs-routes/tree-shake.d.ts +2 -0
- package/dist/config/fs-routes/tree-shake.js +357 -0
- package/dist/config/index.d.ts +10 -0
- package/dist/config/index.js +217 -0
- package/dist/config/lazy.d.ts +3 -0
- package/dist/config/lazy.js +82 -0
- package/dist/config/manifest.d.ts +3 -0
- package/dist/config/manifest.js +74 -0
- package/dist/config/utils.d.ts +4 -0
- package/dist/config/utils.js +6 -0
- package/dist/config/vite-utils.d.ts +16 -0
- package/dist/config/vite-utils.js +81 -0
- package/dist/http/index.d.ts +84 -0
- package/dist/http/index.js +131 -0
- package/dist/index.d.ts +6 -5
- package/dist/index.jsx +5 -5
- package/dist/middleware/index.d.ts +6 -6
- package/dist/middleware/index.js +39 -0
- package/dist/{router/FileRoutes.js → router.jsx} +5 -6
- package/dist/server/StartServer.d.ts +3 -3
- package/dist/server/StartServer.jsx +9 -63
- package/dist/server/assets/index.d.ts +2 -0
- package/dist/server/assets/index.js +52 -0
- package/dist/server/assets/render.d.ts +19 -0
- package/dist/server/{renderAsset.jsx → assets/render.jsx} +1 -1
- package/dist/server/collect-styles.d.ts +3 -0
- package/dist/server/collect-styles.js +69 -0
- package/dist/server/fetchEvent.d.ts +4 -3
- package/dist/server/fetchEvent.js +12 -74
- package/dist/server/fetchEvent.spec.d.ts +1 -0
- package/dist/server/fetchEvent.spec.js +65 -0
- package/dist/server/handler.d.ts +6 -12
- package/dist/server/handler.js +180 -95
- package/dist/server/index.d.ts +8 -6
- package/dist/server/index.jsx +14 -6
- package/dist/server/manifest/client-manifest.d.ts +9 -0
- package/dist/server/manifest/client-manifest.js +6 -0
- package/dist/server/manifest/dev-client-manifest.d.ts +4 -0
- package/dist/server/manifest/dev-client-manifest.js +24 -0
- package/dist/server/manifest/dev-ssr-manifest.d.ts +5 -0
- package/dist/server/manifest/dev-ssr-manifest.js +23 -0
- package/dist/server/manifest/prod-client-manifest.d.ts +5 -0
- package/dist/server/manifest/prod-client-manifest.js +26 -0
- package/dist/server/manifest/prod-ssr-manifest.d.ts +6 -0
- package/dist/server/manifest/prod-ssr-manifest.js +90 -0
- package/dist/server/manifest/ssr-manifest.d.ts +4 -0
- package/dist/server/manifest/ssr-manifest.js +6 -0
- package/dist/{router → server}/routes.d.ts +6 -10
- package/dist/{router → server}/routes.js +35 -27
- package/dist/{runtime → server}/server-fns-runtime.d.ts +1 -1
- package/dist/{runtime → server}/server-fns-runtime.js +7 -6
- package/dist/server/server-functions-handler.d.ts +2 -0
- package/dist/{runtime/server-handler.js → server/server-functions-handler.js} +76 -103
- package/dist/server/server-runtime.d.ts +3 -0
- package/dist/{runtime → server}/server-runtime.js +9 -16
- package/dist/server/spa/StartServer.d.ts +1 -1
- package/dist/server/spa/StartServer.jsx +7 -9
- package/dist/server/spa/handler.d.ts +3 -3
- package/dist/server/spa/handler.js +9 -11
- package/dist/server/spa/index.d.ts +4 -3
- package/dist/server/spa/index.jsx +4 -3
- package/dist/server/types.d.ts +7 -9
- package/dist/server/util.d.ts +2 -0
- package/dist/server/util.js +8 -0
- package/dist/shared/ErrorBoundary.jsx +2 -2
- package/dist/shared/HttpHeader.jsx +4 -2
- package/dist/shared/{HttpStatusCode.jsx → HttpStatusCode.js} +3 -1
- package/dist/shared/dev-overlay/DevOverlayDialog.d.ts +2 -2
- package/dist/shared/dev-overlay/DevOverlayDialog.jsx +75 -66
- package/dist/shared/dev-overlay/createStackFrame.js +3 -3
- package/dist/shared/dev-overlay/index.jsx +5 -8
- package/dist/shared/lazy.d.ts +3 -0
- package/dist/shared/lazy.js +40 -0
- package/dist/shared/serverFunction.d.ts +1 -1
- package/package.json +47 -65
- package/scripts/build.js +15 -0
- package/scripts/validate-imports.js +316 -0
- package/src/client/StartClient.tsx +34 -0
- package/src/client/index.tsx +2 -0
- package/src/client/mount.ts +114 -0
- package/src/client/spa/index.tsx +9 -0
- package/src/config/constants.ts +19 -0
- package/src/config/dev-server.ts +149 -0
- package/src/config/fs-router.ts +177 -0
- package/src/config/fs-routes/fs-watcher.ts +81 -0
- package/src/config/fs-routes/index.ts +138 -0
- package/src/config/fs-routes/router.ts +169 -0
- package/src/config/fs-routes/tree-shake.ts +392 -0
- package/src/config/index.ts +236 -0
- package/src/config/lazy.ts +100 -0
- package/src/config/manifest.ts +84 -0
- package/src/config/utils.ts +5 -0
- package/src/config/vite-utils.ts +113 -0
- package/src/env.d.ts +35 -0
- package/src/http/index.ts +253 -0
- package/src/index.tsx +19 -0
- package/src/internal.d.ts +14 -0
- package/src/middleware/index.ts +82 -0
- package/src/router.tsx +36 -0
- package/src/server/StartServer.tsx +62 -0
- package/src/server/assets/index.ts +70 -0
- package/src/server/assets/render.tsx +42 -0
- package/src/server/collect-styles.ts +94 -0
- package/src/server/fetchEvent.spec.ts +89 -0
- package/src/server/fetchEvent.ts +36 -0
- package/src/server/handler.ts +250 -0
- package/src/server/index.tsx +16 -0
- package/src/server/manifest/client-manifest.ts +8 -0
- package/src/server/manifest/dev-client-manifest.ts +19 -0
- package/src/server/manifest/dev-ssr-manifest.ts +21 -0
- package/src/server/manifest/prod-client-manifest.ts +18 -0
- package/src/server/manifest/prod-ssr-manifest.ts +125 -0
- package/src/server/manifest/ssr-manifest.ts +8 -0
- package/src/server/routes.ts +138 -0
- package/src/server/server-fns-runtime.ts +31 -0
- package/src/server/server-functions-handler.ts +364 -0
- package/src/server/server-runtime.ts +240 -0
- package/src/server/spa/StartServer.tsx +40 -0
- package/src/server/spa/handler.ts +29 -0
- package/src/server/spa/index.tsx +5 -0
- package/src/server/types.ts +82 -0
- package/src/server/util.ts +12 -0
- package/src/shared/ErrorBoundary.tsx +52 -0
- package/src/shared/GET.ts +8 -0
- package/src/shared/HttpHeader.tsx +42 -0
- package/src/shared/HttpStatusCode.ts +27 -0
- package/src/shared/clientOnly.ts +44 -0
- package/src/shared/dev-overlay/CodeView.tsx +95 -0
- package/src/shared/dev-overlay/DevOverlayDialog.tsx +316 -0
- package/src/shared/dev-overlay/createStackFrame.ts +77 -0
- package/src/shared/dev-overlay/download.ts +6 -0
- package/src/shared/dev-overlay/env.d.ts +4 -0
- package/src/shared/dev-overlay/get-source-map.ts +35 -0
- package/src/shared/dev-overlay/icons.tsx +288 -0
- package/src/shared/dev-overlay/index.tsx +63 -0
- package/src/shared/dev-overlay/styles.css +292 -0
- package/src/shared/lazy.ts +51 -0
- package/src/shared/serverFunction.ts +10 -0
- package/src/virtual.d.ts +27 -0
- package/tsconfig.json +23 -0
- package/vitest.config.ts +9 -0
- package/config/fs-router.js +0 -142
- package/config/index.d.ts +0 -39
- package/config/index.js +0 -303
- package/config/server-components.js +0 -106
- package/dist/client/islands.d.ts +0 -7
- package/dist/client/islands.jsx +0 -10
- package/dist/middleware/index.jsx +0 -35
- package/dist/router/index.d.ts +0 -1
- package/dist/router/index.jsx +0 -2
- package/dist/router/lazyRoute.d.ts +0 -6
- package/dist/router/lazyRoute.js +0 -53
- package/dist/runtime/server-handler.d.ts +0 -2
- package/dist/runtime/server-runtime.d.ts +0 -3
- package/dist/server/islands/index.d.ts +0 -19
- package/dist/server/islands/index.jsx +0 -62
- package/dist/server/islands/utils.d.ts +0 -1
- package/dist/server/islands/utils.jsx +0 -85
- package/dist/server/pageEvent.d.ts +0 -2
- package/dist/server/pageEvent.js +0 -56
- package/dist/server/renderAsset.d.ts +0 -2
- package/env.d.ts +0 -26
- /package/dist/{router/FileRoutes.d.ts → router.d.ts} +0 -0
- /package/dist/shared/{clientOnly.jsx → clientOnly.js} +0 -0
- /package/dist/shared/{serverFunction.jsx → serverFunction.js} +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { FetchEvent } from "./types.ts";
|
|
1
2
|
interface Route {
|
|
2
3
|
path: string;
|
|
3
4
|
id: string;
|
|
@@ -11,17 +12,12 @@ interface Route {
|
|
|
11
12
|
$PATCH?: any;
|
|
12
13
|
$DELETE?: any;
|
|
13
14
|
}
|
|
14
|
-
declare module "vinxi/routes" {
|
|
15
|
-
interface Register {
|
|
16
|
-
route: {
|
|
17
|
-
path: string;
|
|
18
|
-
children?: Route[];
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
15
|
export declare const pageRoutes: Route[];
|
|
23
16
|
export declare function matchAPIRoute(path: string, method: string): {
|
|
24
|
-
|
|
25
|
-
|
|
17
|
+
params?: Record<string, any>;
|
|
18
|
+
handler: {
|
|
19
|
+
import: () => Promise<Record<string, (e: FetchEvent) => Promise<any>>>;
|
|
20
|
+
};
|
|
21
|
+
isPage: boolean;
|
|
26
22
|
} | undefined;
|
|
27
23
|
export {};
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
+
// @ts-expect-error
|
|
2
|
+
import fileRoutes from "solid-start:routes";
|
|
1
3
|
import { createRouter } from "radix3";
|
|
2
|
-
|
|
3
|
-
export const pageRoutes = defineRoutes(fileRoutes.filter(o => o.page));
|
|
4
|
+
export const pageRoutes = defineRoutes(fileRoutes.filter((o) => o.page));
|
|
4
5
|
function defineRoutes(fileRoutes) {
|
|
5
6
|
function processRoute(routes, route, id, full) {
|
|
6
|
-
const parentRoute = Object.values(routes).find(o => {
|
|
7
|
+
const parentRoute = Object.values(routes).find((o) => {
|
|
7
8
|
return id.startsWith(o.id + "/");
|
|
8
9
|
});
|
|
9
10
|
if (!parentRoute) {
|
|
10
11
|
routes.push({
|
|
11
12
|
...route,
|
|
12
13
|
id,
|
|
13
|
-
path: id.replace(/\([^)/]+\)/g, "").replace(/\/+/g, "/")
|
|
14
|
+
path: id.replace(/\([^)/]+\)/g, "").replace(/\/+/g, "/"),
|
|
14
15
|
});
|
|
15
16
|
return routes;
|
|
16
17
|
}
|
|
@@ -23,36 +24,16 @@ function defineRoutes(fileRoutes) {
|
|
|
23
24
|
return processRoute(prevRoutes, route, route.path, route.path);
|
|
24
25
|
}, []);
|
|
25
26
|
}
|
|
26
|
-
export function matchAPIRoute(path, method) {
|
|
27
|
-
const match = router.lookup(path);
|
|
28
|
-
if (match && match.route) {
|
|
29
|
-
const handler = method === "HEAD" ? match.route["$HEAD"] || match.route["$GET"] : match.route[`$${method}`];
|
|
30
|
-
if (handler === undefined)
|
|
31
|
-
return;
|
|
32
|
-
return {
|
|
33
|
-
handler,
|
|
34
|
-
params: match.params
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
function containsHTTP(route) {
|
|
39
|
-
return (route["$HEAD"] ||
|
|
40
|
-
route["$GET"] ||
|
|
41
|
-
route["$POST"] ||
|
|
42
|
-
route["$PUT"] ||
|
|
43
|
-
route["$PATCH"] ||
|
|
44
|
-
route["$DELETE"]);
|
|
45
|
-
}
|
|
46
27
|
const router = createRouter({
|
|
47
28
|
routes: fileRoutes.reduce((memo, route) => {
|
|
48
29
|
if (!containsHTTP(route))
|
|
49
30
|
return memo;
|
|
50
|
-
|
|
31
|
+
const path = route.path
|
|
51
32
|
.replace(/\([^)/]+\)/g, "")
|
|
52
33
|
.replace(/\/+/g, "/")
|
|
53
34
|
.replace(/\*([^/]*)/g, (_, m) => `**:${m}`)
|
|
54
35
|
.split("/")
|
|
55
|
-
.map(s =>
|
|
36
|
+
.map((s) => s.startsWith(":") || s.startsWith("*") ? s : encodeURIComponent(s))
|
|
56
37
|
.join("/");
|
|
57
38
|
if (/:[^/]*\?/g.test(path)) {
|
|
58
39
|
throw new Error(`Optional parameters are not supported in API routes: ${path}`);
|
|
@@ -62,5 +43,32 @@ const router = createRouter({
|
|
|
62
43
|
}
|
|
63
44
|
memo[path] = { route };
|
|
64
45
|
return memo;
|
|
65
|
-
}, {})
|
|
46
|
+
}, {}),
|
|
66
47
|
});
|
|
48
|
+
function containsHTTP(route) {
|
|
49
|
+
return (route["$HEAD"] ||
|
|
50
|
+
route["$GET"] ||
|
|
51
|
+
route["$POST"] ||
|
|
52
|
+
route["$PUT"] ||
|
|
53
|
+
route["$PATCH"] ||
|
|
54
|
+
route["$DELETE"]);
|
|
55
|
+
}
|
|
56
|
+
export function matchAPIRoute(path, method) {
|
|
57
|
+
const match = router.lookup(path);
|
|
58
|
+
if (match && match.route) {
|
|
59
|
+
const route = match.route;
|
|
60
|
+
// Find the appropriate handler for the HTTP method
|
|
61
|
+
const handler = method === "HEAD" ? route.$HEAD || route.$GET : route[`$${method}`];
|
|
62
|
+
if (handler === undefined)
|
|
63
|
+
return;
|
|
64
|
+
// Check if this is a page route
|
|
65
|
+
const isPage = route.page === true && route.$component !== undefined;
|
|
66
|
+
// Return comprehensive route information
|
|
67
|
+
return {
|
|
68
|
+
handler,
|
|
69
|
+
params: match.params,
|
|
70
|
+
isPage,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function createServerReference(fn: Function, id: string
|
|
1
|
+
export declare function createServerReference(fn: Function, id: string): Function;
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { getRequestEvent } from "solid-js/web";
|
|
2
2
|
import { provideRequestEvent } from "solid-js/web/storage";
|
|
3
|
-
|
|
4
|
-
export function createServerReference(fn, id, name) {
|
|
3
|
+
export function createServerReference(fn, id) {
|
|
5
4
|
if (typeof fn !== "function")
|
|
6
5
|
throw new Error("Export from a 'use server' module must be a function");
|
|
7
|
-
|
|
6
|
+
let baseURL = import.meta.env.BASE_URL ?? "/";
|
|
7
|
+
if (!baseURL.endsWith("/"))
|
|
8
|
+
baseURL += "/";
|
|
8
9
|
return new Proxy(fn, {
|
|
9
10
|
get(target, prop, receiver) {
|
|
10
11
|
if (prop === "url") {
|
|
11
|
-
return `${baseURL}
|
|
12
|
+
return `${baseURL}_server?id=${encodeURIComponent(id)}`;
|
|
12
13
|
}
|
|
13
14
|
if (prop === "GET")
|
|
14
15
|
return receiver;
|
|
@@ -18,9 +19,9 @@ export function createServerReference(fn, id, name) {
|
|
|
18
19
|
const ogEvt = getRequestEvent();
|
|
19
20
|
if (!ogEvt)
|
|
20
21
|
throw new Error("Cannot call server function outside of a request");
|
|
21
|
-
const evt =
|
|
22
|
+
const evt = { ...ogEvt };
|
|
22
23
|
evt.locals.serverFunctionMeta = {
|
|
23
|
-
id
|
|
24
|
+
id
|
|
24
25
|
};
|
|
25
26
|
evt.serverOnly = true;
|
|
26
27
|
return provideRequestEvent(evt, () => {
|
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import {
|
|
1
|
+
import { getServerFnById } from "solidstart:server-fn-manifest";
|
|
2
|
+
import { parseSetCookie } from "cookie-es";
|
|
3
|
+
import { parseCookies } from "h3";
|
|
4
|
+
import { crossSerializeStream, fromJSON, getCrossReferenceHeader, } from "seroval";
|
|
5
|
+
import { CustomEventPlugin, DOMExceptionPlugin, EventPlugin, FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLPlugin, URLSearchParamsPlugin, } from "seroval-plugins/web";
|
|
5
6
|
import { sharedConfig } from "solid-js";
|
|
6
7
|
import { renderToString } from "solid-js/web";
|
|
7
8
|
import { provideRequestEvent } from "solid-js/web/storage";
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
11
|
-
import { getExpectedRedirectStatus } from "../server/handler";
|
|
12
|
-
import { createPageEvent } from "../server/pageEvent";
|
|
13
|
-
// @ts-ignore
|
|
14
|
-
import serverFnManifest from "solidstart:server-fn-manifest";
|
|
9
|
+
import { getFetchEvent, mergeResponseHeaders } from "./fetchEvent.js";
|
|
10
|
+
import { createPageEvent } from "./handler.js";
|
|
11
|
+
import { getExpectedRedirectStatus } from "./util.js";
|
|
15
12
|
function createChunk(data) {
|
|
16
13
|
const encodeData = new TextEncoder().encode(data);
|
|
17
14
|
const bytes = encodeData.length;
|
|
@@ -38,7 +35,7 @@ function serializeToStream(id, value) {
|
|
|
38
35
|
RequestPlugin,
|
|
39
36
|
ResponsePlugin,
|
|
40
37
|
URLSearchParamsPlugin,
|
|
41
|
-
URLPlugin
|
|
38
|
+
URLPlugin,
|
|
42
39
|
],
|
|
43
40
|
onSerialize(data, initial) {
|
|
44
41
|
controller.enqueue(createChunk(initial ? `(${getCrossReferenceHeader(id)},${data})` : data));
|
|
@@ -48,52 +45,32 @@ function serializeToStream(id, value) {
|
|
|
48
45
|
},
|
|
49
46
|
onError(error) {
|
|
50
47
|
controller.error(error);
|
|
51
|
-
}
|
|
48
|
+
},
|
|
52
49
|
});
|
|
53
|
-
}
|
|
50
|
+
},
|
|
54
51
|
});
|
|
55
52
|
}
|
|
56
|
-
async function handleServerFunction(h3Event) {
|
|
53
|
+
export async function handleServerFunction(h3Event) {
|
|
57
54
|
const event = getFetchEvent(h3Event);
|
|
58
55
|
const request = event.request;
|
|
59
56
|
const serverReference = request.headers.get("X-Server-Id");
|
|
60
57
|
const instance = request.headers.get("X-Server-Instance");
|
|
61
58
|
const singleFlight = request.headers.has("X-Single-Flight");
|
|
62
59
|
const url = new URL(request.url);
|
|
63
|
-
let functionId
|
|
60
|
+
let functionId;
|
|
64
61
|
if (serverReference) {
|
|
65
|
-
invariant(typeof serverReference === "string", "Invalid server function");
|
|
66
|
-
[functionId
|
|
62
|
+
// invariant(typeof serverReference === "string", "Invalid server function");
|
|
63
|
+
[functionId] = serverReference.split("#");
|
|
67
64
|
}
|
|
68
65
|
else {
|
|
69
66
|
functionId = url.searchParams.get("id");
|
|
70
|
-
|
|
71
|
-
if (!functionId || !name) {
|
|
67
|
+
if (!functionId) {
|
|
72
68
|
return process.env.NODE_ENV === "development"
|
|
73
69
|
? new Response("Server function not found", { status: 404 })
|
|
74
70
|
: new Response(null, { status: 404 });
|
|
75
71
|
}
|
|
76
72
|
}
|
|
77
|
-
const
|
|
78
|
-
let fnModule;
|
|
79
|
-
if (!serverFnInfo) {
|
|
80
|
-
return process.env.NODE_ENV === "development"
|
|
81
|
-
? new Response("Server function not found", { status: 404 })
|
|
82
|
-
: new Response(null, { status: 404 });
|
|
83
|
-
}
|
|
84
|
-
if (process.env.NODE_ENV === "development") {
|
|
85
|
-
// In dev, we use Vinxi to get the "server" server-side router
|
|
86
|
-
// Then we use that router's devServer.ssrLoadModule to get the serverFn
|
|
87
|
-
// This code comes from:
|
|
88
|
-
// https://github.com/TanStack/router/blob/266f5cc863cd1a99809d1af2669e58b6b6db9a67/packages/start-server-functions-handler/src/index.tsx#L83-L87
|
|
89
|
-
fnModule = await globalThis.app
|
|
90
|
-
.getRouter("server-fns")
|
|
91
|
-
.internals.devServer.ssrLoadModule(serverFnInfo.extractedFilename);
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
fnModule = await serverFnInfo.importer();
|
|
95
|
-
}
|
|
96
|
-
const serverFunction = fnModule[serverFnInfo.functionName];
|
|
73
|
+
const serverFunction = await getServerFnById(functionId);
|
|
97
74
|
let parsed = [];
|
|
98
75
|
// grab bound arguments from url when no JS
|
|
99
76
|
if (!instance || h3Event.method === "GET") {
|
|
@@ -112,41 +89,22 @@ async function handleServerFunction(h3Event) {
|
|
|
112
89
|
RequestPlugin,
|
|
113
90
|
ResponsePlugin,
|
|
114
91
|
URLSearchParamsPlugin,
|
|
115
|
-
URLPlugin
|
|
116
|
-
]
|
|
92
|
+
URLPlugin,
|
|
93
|
+
],
|
|
117
94
|
})
|
|
118
|
-
: json).forEach((arg) =>
|
|
95
|
+
: json).forEach((arg) => {
|
|
96
|
+
parsed.push(arg);
|
|
97
|
+
});
|
|
119
98
|
}
|
|
120
99
|
}
|
|
121
100
|
if (h3Event.method === "POST") {
|
|
122
101
|
const contentType = request.headers.get("content-type");
|
|
123
|
-
const h3Request = h3Event.node.req;
|
|
124
|
-
// This should never be the case in "proper" Nitro presets since node.req has to be IncomingMessage,
|
|
125
|
-
// But the new azure-functions preset for some reason uses a ReadableStream in node.req (#1521)
|
|
126
|
-
const isReadableStream = h3Request instanceof ReadableStream;
|
|
127
|
-
const hasReadableStream = h3Request.body instanceof ReadableStream;
|
|
128
|
-
const isH3EventBodyStreamLocked = (isReadableStream && h3Request.locked) ||
|
|
129
|
-
(hasReadableStream && h3Request.body.locked);
|
|
130
|
-
const requestBody = isReadableStream ? h3Request : h3Request.body;
|
|
131
102
|
if (contentType?.startsWith("multipart/form-data") ||
|
|
132
103
|
contentType?.startsWith("application/x-www-form-urlencoded")) {
|
|
133
|
-
|
|
134
|
-
// (issue only in edge runtimes and netlify preset)
|
|
135
|
-
parsed.push(await (isH3EventBodyStreamLocked
|
|
136
|
-
? request
|
|
137
|
-
: new Request(request, { ...request, body: requestBody })).formData());
|
|
138
|
-
// what should work when #1721 is fixed
|
|
139
|
-
// parsed.push(await request.formData);
|
|
104
|
+
parsed.push(await event.request.formData());
|
|
140
105
|
}
|
|
141
106
|
else if (contentType?.startsWith("application/json")) {
|
|
142
|
-
|
|
143
|
-
// (issue only in edge runtimes and netlify preset)
|
|
144
|
-
const tmpReq = isH3EventBodyStreamLocked
|
|
145
|
-
? request
|
|
146
|
-
: new Request(request, { ...request, body: requestBody });
|
|
147
|
-
// what should work when #1721 is fixed
|
|
148
|
-
// just use request.json() here
|
|
149
|
-
parsed = fromJSON(await tmpReq.json(), {
|
|
107
|
+
parsed = fromJSON(await event.request.json(), {
|
|
150
108
|
plugins: [
|
|
151
109
|
CustomEventPlugin,
|
|
152
110
|
DOMExceptionPlugin,
|
|
@@ -157,17 +115,17 @@ async function handleServerFunction(h3Event) {
|
|
|
157
115
|
RequestPlugin,
|
|
158
116
|
ResponsePlugin,
|
|
159
117
|
URLSearchParamsPlugin,
|
|
160
|
-
URLPlugin
|
|
161
|
-
]
|
|
118
|
+
URLPlugin,
|
|
119
|
+
],
|
|
162
120
|
});
|
|
163
121
|
}
|
|
164
122
|
}
|
|
165
123
|
try {
|
|
166
124
|
let result = await provideRequestEvent(event, async () => {
|
|
167
|
-
/* @ts-
|
|
125
|
+
/* @ts-expect-error */
|
|
168
126
|
sharedConfig.context = { event };
|
|
169
127
|
event.locals.serverFunctionMeta = {
|
|
170
|
-
id: functionId
|
|
128
|
+
id: functionId
|
|
171
129
|
};
|
|
172
130
|
return serverFunction(...parsed);
|
|
173
131
|
});
|
|
@@ -184,7 +142,7 @@ async function handleServerFunction(h3Event) {
|
|
|
184
142
|
mergeResponseHeaders(h3Event, result.headers);
|
|
185
143
|
// forward non-redirect statuses
|
|
186
144
|
if (result.status && (result.status < 300 || result.status >= 400))
|
|
187
|
-
|
|
145
|
+
h3Event.res.status = result.status;
|
|
188
146
|
if (result.customBody) {
|
|
189
147
|
result = await result.customBody();
|
|
190
148
|
}
|
|
@@ -195,7 +153,7 @@ async function handleServerFunction(h3Event) {
|
|
|
195
153
|
// handle no JS success case
|
|
196
154
|
if (!instance)
|
|
197
155
|
return handleNoJS(result, request, parsed);
|
|
198
|
-
|
|
156
|
+
h3Event.res.headers.set("content-type", "text/javascript");
|
|
199
157
|
return serializeToStream(instance, result);
|
|
200
158
|
}
|
|
201
159
|
catch (x) {
|
|
@@ -207,24 +165,25 @@ async function handleServerFunction(h3Event) {
|
|
|
207
165
|
if (x.headers)
|
|
208
166
|
mergeResponseHeaders(h3Event, x.headers);
|
|
209
167
|
// forward non-redirect statuses
|
|
210
|
-
if (x.status &&
|
|
211
|
-
|
|
168
|
+
if (x.status &&
|
|
169
|
+
(!instance || x.status < 300 || x.status >= 400))
|
|
170
|
+
h3Event.res.status = x.status;
|
|
212
171
|
if (x.customBody) {
|
|
213
172
|
x = x.customBody();
|
|
214
173
|
}
|
|
215
|
-
else if (x.body
|
|
174
|
+
else if (x.body === undefined)
|
|
216
175
|
x = null;
|
|
217
|
-
|
|
176
|
+
h3Event.res.headers.set("X-Error", "true");
|
|
218
177
|
}
|
|
219
178
|
else if (instance) {
|
|
220
179
|
const error = x instanceof Error ? x.message : typeof x === "string" ? x : "true";
|
|
221
|
-
|
|
180
|
+
h3Event.res.headers.set("X-Error", error.replace(/[\r\n]+/g, ""));
|
|
222
181
|
}
|
|
223
182
|
else {
|
|
224
183
|
x = handleNoJS(x, request, parsed, true);
|
|
225
184
|
}
|
|
226
185
|
if (instance) {
|
|
227
|
-
|
|
186
|
+
h3Event.res.headers.set("content-type", "text/javascript");
|
|
228
187
|
return serializeToStream(instance, x);
|
|
229
188
|
}
|
|
230
189
|
return x;
|
|
@@ -238,24 +197,29 @@ function handleNoJS(result, request, parsed, thrown) {
|
|
|
238
197
|
if (result instanceof Response) {
|
|
239
198
|
headers = new Headers(result.headers);
|
|
240
199
|
if (result.headers.has("Location")) {
|
|
241
|
-
headers.set(`Location`, new URL(result.headers.get("Location"), url.origin + import.meta.env.
|
|
200
|
+
headers.set(`Location`, new URL(result.headers.get("Location"), url.origin + import.meta.env.BASE_URL).toString());
|
|
242
201
|
statusCode = getExpectedRedirectStatus(result);
|
|
243
202
|
}
|
|
244
203
|
}
|
|
245
204
|
else
|
|
246
|
-
headers = new Headers({
|
|
205
|
+
headers = new Headers({
|
|
206
|
+
Location: new URL(request.headers.get("referer")).toString(),
|
|
207
|
+
});
|
|
247
208
|
if (result) {
|
|
248
209
|
headers.append("Set-Cookie", `flash=${encodeURIComponent(JSON.stringify({
|
|
249
210
|
url: url.pathname + url.search,
|
|
250
211
|
result: isError ? result.message : result,
|
|
251
212
|
thrown: thrown,
|
|
252
213
|
error: isError,
|
|
253
|
-
input: [
|
|
214
|
+
input: [
|
|
215
|
+
...parsed.slice(0, -1),
|
|
216
|
+
[...parsed[parsed.length - 1].entries()],
|
|
217
|
+
],
|
|
254
218
|
}))}; Secure; HttpOnly;`);
|
|
255
219
|
}
|
|
256
220
|
return new Response(null, {
|
|
257
221
|
status: statusCode,
|
|
258
|
-
headers
|
|
222
|
+
headers,
|
|
259
223
|
});
|
|
260
224
|
}
|
|
261
225
|
let App;
|
|
@@ -263,25 +227,33 @@ function createSingleFlightHeaders(sourceEvent) {
|
|
|
263
227
|
// cookie handling logic is pretty simplistic so this might be imperfect
|
|
264
228
|
// unclear if h3 internals are available on all platforms but we need a way to
|
|
265
229
|
// update request headers on the underlying H3 event.
|
|
266
|
-
const headers =
|
|
230
|
+
const headers = sourceEvent.request.headers;
|
|
267
231
|
const cookies = parseCookies(sourceEvent.nativeEvent);
|
|
268
232
|
const SetCookies = sourceEvent.response.headers.getSetCookie();
|
|
269
233
|
headers.delete("cookie");
|
|
270
|
-
let useH3Internals = false;
|
|
271
|
-
if (sourceEvent.nativeEvent.node?.req) {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
}
|
|
275
|
-
SetCookies.forEach(cookie => {
|
|
234
|
+
// let useH3Internals = false;
|
|
235
|
+
// if (sourceEvent.nativeEvent.node?.req) {
|
|
236
|
+
// useH3Internals = true;
|
|
237
|
+
// sourceEvent.nativeEvent.node.req.headers.cookie = "";
|
|
238
|
+
// }
|
|
239
|
+
SetCookies.forEach((cookie) => {
|
|
276
240
|
if (!cookie)
|
|
277
241
|
return;
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
242
|
+
const { maxAge, expires, name, value } = parseSetCookie(cookie);
|
|
243
|
+
if (maxAge != null && maxAge <= 0) {
|
|
244
|
+
delete cookies[name];
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (expires != null && expires.getTime() <= Date.now()) {
|
|
248
|
+
delete cookies[name];
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
cookies[name] = value;
|
|
281
252
|
});
|
|
282
253
|
Object.entries(cookies).forEach(([key, value]) => {
|
|
283
254
|
headers.append("cookie", `${key}=${value}`);
|
|
284
|
-
useH3Internals &&
|
|
255
|
+
// useH3Internals &&
|
|
256
|
+
// (sourceEvent.nativeEvent.node.req.headers.cookie += `${key}=${value};`);
|
|
285
257
|
});
|
|
286
258
|
return headers;
|
|
287
259
|
}
|
|
@@ -292,21 +264,23 @@ async function handleSingleFlight(sourceEvent, result) {
|
|
|
292
264
|
if (result.headers.has("X-Revalidate"))
|
|
293
265
|
revalidate = result.headers.get("X-Revalidate").split(",");
|
|
294
266
|
if (result.headers.has("Location"))
|
|
295
|
-
url = new URL(result.headers.get("Location"), new URL(sourceEvent.request.url).origin +
|
|
267
|
+
url = new URL(result.headers.get("Location"), new URL(sourceEvent.request.url).origin +
|
|
268
|
+
import.meta.env.BASE_URL).toString();
|
|
296
269
|
}
|
|
297
|
-
const event =
|
|
298
|
-
event.request = new Request(url, {
|
|
270
|
+
const event = { ...sourceEvent };
|
|
271
|
+
event.request = new Request(url, {
|
|
272
|
+
headers: createSingleFlightHeaders(sourceEvent),
|
|
273
|
+
});
|
|
299
274
|
return await provideRequestEvent(event, async () => {
|
|
300
275
|
await createPageEvent(event);
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
/* @ts-ignore */
|
|
276
|
+
App || (App = (await import("solid-start:app")).default);
|
|
277
|
+
/* @ts-expect-error */
|
|
304
278
|
event.router.dataOnly = revalidate || true;
|
|
305
|
-
/* @ts-
|
|
279
|
+
/* @ts-expect-error */
|
|
306
280
|
event.router.previousUrl = sourceEvent.request.headers.get("referer");
|
|
307
281
|
try {
|
|
308
282
|
renderToString(() => {
|
|
309
|
-
/* @ts-
|
|
283
|
+
/* @ts-expect-error */
|
|
310
284
|
sharedConfig.context.event = event;
|
|
311
285
|
App();
|
|
312
286
|
});
|
|
@@ -314,7 +288,7 @@ async function handleSingleFlight(sourceEvent, result) {
|
|
|
314
288
|
catch (e) {
|
|
315
289
|
console.log(e);
|
|
316
290
|
}
|
|
317
|
-
/* @ts-
|
|
291
|
+
/* @ts-expect-error */
|
|
318
292
|
const body = event.router.data;
|
|
319
293
|
if (!body)
|
|
320
294
|
return result;
|
|
@@ -339,4 +313,3 @@ async function handleSingleFlight(sourceEvent, result) {
|
|
|
339
313
|
return result;
|
|
340
314
|
});
|
|
341
315
|
}
|
|
342
|
-
export default eventHandler(handleServerFunction);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { deserialize, toJSONAsync } from "seroval";
|
|
2
2
|
import { CustomEventPlugin, DOMExceptionPlugin, EventPlugin, FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLPlugin, URLSearchParamsPlugin } from "seroval-plugins/web";
|
|
3
|
-
import { createIslandReference } from "../server/islands/index";
|
|
4
3
|
class SerovalChunkReader {
|
|
5
4
|
reader;
|
|
6
5
|
buffer;
|
|
@@ -44,9 +43,6 @@ class SerovalChunkReader {
|
|
|
44
43
|
// deserialize the data
|
|
45
44
|
const head = new TextDecoder().decode(this.buffer.subarray(1, 11));
|
|
46
45
|
const bytes = Number.parseInt(head, 16); // ;0x00000000;
|
|
47
|
-
if (Number.isNaN(bytes)) {
|
|
48
|
-
throw new Error(`Malformed server function stream header: ${head}`);
|
|
49
|
-
}
|
|
50
46
|
// Check if the buffer has enough bytes to be parsed
|
|
51
47
|
while (bytes > this.buffer.length - 12) {
|
|
52
48
|
// If it's not enough, and the reader is done
|
|
@@ -160,18 +156,21 @@ async function fetchServerFunction(base, id, options, args) {
|
|
|
160
156
|
}
|
|
161
157
|
return result;
|
|
162
158
|
}
|
|
163
|
-
export function createServerReference(
|
|
164
|
-
|
|
159
|
+
export function createServerReference(id) {
|
|
160
|
+
let baseURL = import.meta.env.BASE_URL ?? "/";
|
|
161
|
+
if (!baseURL.endsWith("/"))
|
|
162
|
+
baseURL += "/";
|
|
163
|
+
const fn = (...args) => fetchServerFunction(`${baseURL}_server`, id, {}, args);
|
|
165
164
|
return new Proxy(fn, {
|
|
166
165
|
get(target, prop, receiver) {
|
|
167
166
|
if (prop === "url") {
|
|
168
|
-
return `${baseURL}
|
|
167
|
+
return `${baseURL}_server?id=${encodeURIComponent(id)}`;
|
|
169
168
|
}
|
|
170
169
|
if (prop === "GET") {
|
|
171
170
|
return receiver.withOptions({ method: "GET" });
|
|
172
171
|
}
|
|
173
172
|
if (prop === "withOptions") {
|
|
174
|
-
const url = `${baseURL}
|
|
173
|
+
const url = `${baseURL}_server?id=${encodeURIComponent(id)}`;
|
|
175
174
|
return (options) => {
|
|
176
175
|
const fn = async (...args) => {
|
|
177
176
|
const encodeArgs = options.method && options.method.toUpperCase() === "GET";
|
|
@@ -180,7 +179,7 @@ export function createServerReference(fn, id, name) {
|
|
|
180
179
|
(args.length
|
|
181
180
|
? `&args=${encodeURIComponent(JSON.stringify(await Promise.resolve(toJSONAsync(args, { plugins }))))}`
|
|
182
181
|
: "")
|
|
183
|
-
: `${baseURL}
|
|
182
|
+
: `${baseURL}_server`, id, options, encodeArgs ? [] : args);
|
|
184
183
|
};
|
|
185
184
|
fn.url = url;
|
|
186
185
|
return fn;
|
|
@@ -188,14 +187,8 @@ export function createServerReference(fn, id, name) {
|
|
|
188
187
|
}
|
|
189
188
|
return target[prop];
|
|
190
189
|
},
|
|
191
|
-
apply(target, thisArg, args) {
|
|
192
|
-
return fetchServerFunction(`${baseURL}/_server`, `${id}#${name}`, {}, args);
|
|
193
|
-
}
|
|
194
190
|
});
|
|
195
191
|
}
|
|
196
|
-
export function createClientReference(Component, id
|
|
197
|
-
if (typeof Component === "function") {
|
|
198
|
-
return createIslandReference(Component, id, name);
|
|
199
|
-
}
|
|
192
|
+
export function createClientReference(Component, id) {
|
|
200
193
|
return Component;
|
|
201
194
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { NoHydration, getRequestEvent, ssr } from "solid-js/web";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { getSsrManifest } from "../manifest/ssr-manifest.js";
|
|
3
|
+
import { TopErrorBoundary } from "../../shared/ErrorBoundary.jsx";
|
|
4
|
+
import { useAssets } from "../assets/index.js";
|
|
4
5
|
const docType = ssr("<!DOCTYPE html>");
|
|
5
6
|
/**
|
|
6
7
|
*
|
|
@@ -10,16 +11,13 @@ export function StartServer(props) {
|
|
|
10
11
|
const context = getRequestEvent();
|
|
11
12
|
// @ts-ignore
|
|
12
13
|
const nonce = context.nonce;
|
|
14
|
+
useAssets(context.assets, nonce);
|
|
13
15
|
return (<NoHydration>
|
|
14
16
|
{docType}
|
|
15
17
|
<TopErrorBoundary>
|
|
16
|
-
<props.document
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
</>) : (<>
|
|
20
|
-
<script innerHTML={`window.manifest = ${JSON.stringify(context.manifest)}`}/>
|
|
21
|
-
<script type="module" src={import.meta.env.MANIFEST["client"].inputs[import.meta.env.MANIFEST["client"].handler].output.path}/>
|
|
22
|
-
</>)}/>
|
|
18
|
+
<props.document scripts={<>
|
|
19
|
+
<script type="module" src={getSsrManifest("client").path(import.meta.env.START_CLIENT_ENTRY)}/>
|
|
20
|
+
</>}/>
|
|
23
21
|
</TopErrorBoundary>
|
|
24
22
|
</NoHydration>);
|
|
25
23
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { JSX } from "solid-js";
|
|
2
|
+
import type { HandlerOptions, PageEvent } from "../types.ts";
|
|
2
3
|
/**
|
|
3
4
|
*
|
|
4
5
|
* Read more: https://docs.solidjs.com/solid-start/reference/server/create-handler
|
|
5
6
|
*/
|
|
6
|
-
export declare function createHandler(fn: (context: PageEvent) =>
|
|
7
|
-
export declare function createPageEvent(ctx: FetchEvent): Promise<PageEvent>;
|
|
7
|
+
export declare function createHandler(fn: (context: PageEvent) => JSX.Element, options?: HandlerOptions | ((context: PageEvent) => HandlerOptions)): import("h3").H3;
|