@solidjs/start 1.2.1 → 2.0.0-alpha.1
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 +14 -0
- package/README.md +2 -2
- 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.d.ts +1 -7
- package/dist/client/mount.js +1 -91
- 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 +141 -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 +107 -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 +348 -0
- package/dist/config/index.d.ts +10 -0
- package/dist/config/index.js +214 -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 +81 -0
- package/dist/http/index.js +129 -0
- package/dist/index.d.ts +5 -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} +7 -8
- 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.js +18 -197
- package/dist/server/handler.d.ts +6 -12
- package/dist/server/handler.js +193 -96
- package/dist/server/index.d.ts +9 -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 +85 -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 +5 -10
- package/dist/{router → server}/routes.js +32 -33
- package/dist/{runtime → server}/server-fns-runtime.d.ts +1 -1
- package/dist/{runtime → server}/server-fns-runtime.js +8 -7
- package/dist/server/server-functions-handler.d.ts +2 -0
- package/dist/{runtime/server-handler.js → server/server-functions-handler.js} +57 -97
- package/dist/server/server-runtime.d.ts +3 -0
- package/dist/{runtime → server}/server-runtime.js +17 -24
- 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/CodeView.d.ts +1 -1
- package/dist/shared/dev-overlay/CodeView.jsx +23 -34
- package/dist/shared/dev-overlay/DevOverlayDialog.d.ts +2 -2
- package/dist/shared/dev-overlay/DevOverlayDialog.jsx +73 -64
- package/dist/shared/dev-overlay/createStackFrame.js +3 -3
- package/dist/shared/dev-overlay/get-source-map.d.ts +1 -1
- package/dist/shared/dev-overlay/get-source-map.js +5 -5
- package/dist/shared/dev-overlay/icons.d.ts +10 -10
- package/dist/shared/dev-overlay/icons.jsx +91 -91
- package/dist/shared/dev-overlay/index.jsx +6 -9
- package/dist/shared/lazy.d.ts +3 -0
- package/dist/shared/lazy.js +42 -0
- package/dist/shared/serverFunction.d.ts +1 -1
- package/env.d.ts +2 -19
- package/package.json +44 -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 +1 -0
- package/src/client/spa/index.tsx +9 -0
- package/src/config/constants.ts +19 -0
- package/src/config/dev-server.ts +145 -0
- package/{config/fs-router.js → src/config/fs-router.ts} +49 -29
- package/src/config/fs-routes/fs-watcher.ts +77 -0
- package/src/config/fs-routes/index.ts +136 -0
- package/src/config/fs-routes/router.ts +169 -0
- package/src/config/fs-routes/tree-shake.ts +371 -0
- package/src/config/index.ts +233 -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 +109 -0
- package/src/env.d.ts +17 -0
- package/src/http/index.ts +216 -0
- package/src/index.tsx +7 -0
- package/src/internal.d.ts +14 -0
- package/src/middleware/index.ts +72 -0
- package/src/router.tsx +37 -0
- package/src/server/StartServer.tsx +56 -0
- package/src/server/assets/index.ts +70 -0
- package/src/server/assets/render.tsx +46 -0
- package/src/server/collect-styles.ts +87 -0
- package/src/server/fetchEvent.spec.ts +85 -0
- package/src/server/fetchEvent.ts +36 -0
- package/src/server/handler.ts +257 -0
- package/src/server/index.tsx +29 -0
- package/src/server/manifest/client-manifest.ts +8 -0
- package/src/server/manifest/dev-client-manifest.ts +21 -0
- package/src/server/manifest/dev-ssr-manifest.ts +23 -0
- package/src/server/manifest/prod-client-manifest.ts +21 -0
- package/src/server/manifest/prod-ssr-manifest.ts +109 -0
- package/src/server/manifest/ssr-manifest.ts +10 -0
- package/src/server/routes.ts +126 -0
- package/src/server/server-fns-runtime.ts +31 -0
- package/src/server/server-functions-handler.ts +339 -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 +92 -0
- package/src/shared/dev-overlay/DevOverlayDialog.tsx +316 -0
- package/src/shared/dev-overlay/createStackFrame.ts +74 -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 +33 -0
- package/src/shared/dev-overlay/icons.tsx +456 -0
- package/src/shared/dev-overlay/index.tsx +63 -0
- package/src/shared/dev-overlay/styles.css +292 -0
- package/src/shared/lazy.ts +52 -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/index.d.ts +0 -40
- package/config/index.js +0 -304
- 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/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,18 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
import { getServerFnById } from "solidstart:server-fn-manifest";
|
|
2
2
|
import { parseSetCookie } from "cookie-es";
|
|
3
|
+
import { parseCookies } from "h3";
|
|
3
4
|
import { crossSerializeStream, fromJSON, getCrossReferenceHeader } from "seroval";
|
|
4
|
-
|
|
5
|
-
import { CustomEventPlugin, DOMExceptionPlugin, EventPlugin, FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLPlugin, URLSearchParamsPlugin } from "seroval-plugins/web";
|
|
5
|
+
import { CustomEventPlugin, DOMExceptionPlugin, EventPlugin, FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLPlugin, URLSearchParamsPlugin, } from "seroval-plugins/web";
|
|
6
6
|
import { sharedConfig } from "solid-js";
|
|
7
7
|
import { renderToString } from "solid-js/web";
|
|
8
8
|
import { provideRequestEvent } from "solid-js/web/storage";
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
import { getExpectedRedirectStatus } from "../server/handler";
|
|
13
|
-
import { createPageEvent } from "../server/pageEvent";
|
|
14
|
-
// @ts-ignore
|
|
15
|
-
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";
|
|
16
12
|
function createChunk(data) {
|
|
17
13
|
const encodeData = new TextEncoder().encode(data);
|
|
18
14
|
const bytes = encodeData.length;
|
|
@@ -39,7 +35,7 @@ function serializeToStream(id, value) {
|
|
|
39
35
|
RequestPlugin,
|
|
40
36
|
ResponsePlugin,
|
|
41
37
|
URLSearchParamsPlugin,
|
|
42
|
-
URLPlugin
|
|
38
|
+
URLPlugin,
|
|
43
39
|
],
|
|
44
40
|
onSerialize(data, initial) {
|
|
45
41
|
controller.enqueue(createChunk(initial ? `(${getCrossReferenceHeader(id)},${data})` : data));
|
|
@@ -49,52 +45,32 @@ function serializeToStream(id, value) {
|
|
|
49
45
|
},
|
|
50
46
|
onError(error) {
|
|
51
47
|
controller.error(error);
|
|
52
|
-
}
|
|
48
|
+
},
|
|
53
49
|
});
|
|
54
|
-
}
|
|
50
|
+
},
|
|
55
51
|
});
|
|
56
52
|
}
|
|
57
|
-
async function handleServerFunction(h3Event) {
|
|
53
|
+
export async function handleServerFunction(h3Event) {
|
|
58
54
|
const event = getFetchEvent(h3Event);
|
|
59
55
|
const request = event.request;
|
|
60
56
|
const serverReference = request.headers.get("X-Server-Id");
|
|
61
57
|
const instance = request.headers.get("X-Server-Instance");
|
|
62
58
|
const singleFlight = request.headers.has("X-Single-Flight");
|
|
63
59
|
const url = new URL(request.url);
|
|
64
|
-
let functionId
|
|
60
|
+
let functionId;
|
|
65
61
|
if (serverReference) {
|
|
66
|
-
invariant(typeof serverReference === "string", "Invalid server function");
|
|
67
|
-
[functionId
|
|
62
|
+
// invariant(typeof serverReference === "string", "Invalid server function");
|
|
63
|
+
[functionId] = serverReference.split("#");
|
|
68
64
|
}
|
|
69
65
|
else {
|
|
70
66
|
functionId = url.searchParams.get("id");
|
|
71
|
-
|
|
72
|
-
if (!functionId || !name) {
|
|
67
|
+
if (!functionId) {
|
|
73
68
|
return process.env.NODE_ENV === "development"
|
|
74
69
|
? new Response("Server function not found", { status: 404 })
|
|
75
70
|
: new Response(null, { status: 404 });
|
|
76
71
|
}
|
|
77
72
|
}
|
|
78
|
-
const
|
|
79
|
-
let fnModule;
|
|
80
|
-
if (!serverFnInfo) {
|
|
81
|
-
return process.env.NODE_ENV === "development"
|
|
82
|
-
? new Response("Server function not found", { status: 404 })
|
|
83
|
-
: new Response(null, { status: 404 });
|
|
84
|
-
}
|
|
85
|
-
if (process.env.NODE_ENV === "development") {
|
|
86
|
-
// In dev, we use Vinxi to get the "server" server-side router
|
|
87
|
-
// Then we use that router's devServer.ssrLoadModule to get the serverFn
|
|
88
|
-
// This code comes from:
|
|
89
|
-
// https://github.com/TanStack/router/blob/266f5cc863cd1a99809d1af2669e58b6b6db9a67/packages/start-server-functions-handler/src/index.tsx#L83-L87
|
|
90
|
-
fnModule = await globalThis.app
|
|
91
|
-
.getRouter("server-fns")
|
|
92
|
-
.internals.devServer.ssrLoadModule(serverFnInfo.extractedFilename);
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
fnModule = await serverFnInfo.importer();
|
|
96
|
-
}
|
|
97
|
-
const serverFunction = fnModule[serverFnInfo.functionName];
|
|
73
|
+
const serverFunction = await getServerFnById(functionId);
|
|
98
74
|
let parsed = [];
|
|
99
75
|
// grab bound arguments from url when no JS
|
|
100
76
|
if (!instance || h3Event.method === "GET") {
|
|
@@ -113,41 +89,22 @@ async function handleServerFunction(h3Event) {
|
|
|
113
89
|
RequestPlugin,
|
|
114
90
|
ResponsePlugin,
|
|
115
91
|
URLSearchParamsPlugin,
|
|
116
|
-
URLPlugin
|
|
117
|
-
]
|
|
92
|
+
URLPlugin,
|
|
93
|
+
],
|
|
118
94
|
})
|
|
119
|
-
: json).forEach((arg) =>
|
|
95
|
+
: json).forEach((arg) => {
|
|
96
|
+
parsed.push(arg);
|
|
97
|
+
});
|
|
120
98
|
}
|
|
121
99
|
}
|
|
122
100
|
if (h3Event.method === "POST") {
|
|
123
101
|
const contentType = request.headers.get("content-type");
|
|
124
|
-
const h3Request = h3Event.node.req;
|
|
125
|
-
// This should never be the case in "proper" Nitro presets since node.req has to be IncomingMessage,
|
|
126
|
-
// But the new azure-functions preset for some reason uses a ReadableStream in node.req (#1521)
|
|
127
|
-
const isReadableStream = h3Request instanceof ReadableStream;
|
|
128
|
-
const hasReadableStream = h3Request.body instanceof ReadableStream;
|
|
129
|
-
const isH3EventBodyStreamLocked = (isReadableStream && h3Request.locked) ||
|
|
130
|
-
(hasReadableStream && h3Request.body.locked);
|
|
131
|
-
const requestBody = isReadableStream ? h3Request : h3Request.body;
|
|
132
102
|
if (contentType?.startsWith("multipart/form-data") ||
|
|
133
103
|
contentType?.startsWith("application/x-www-form-urlencoded")) {
|
|
134
|
-
|
|
135
|
-
// (issue only in edge runtimes and netlify preset)
|
|
136
|
-
parsed.push(await (isH3EventBodyStreamLocked
|
|
137
|
-
? request
|
|
138
|
-
: new Request(request, { ...request, body: requestBody })).formData());
|
|
139
|
-
// what should work when #1721 is fixed
|
|
140
|
-
// parsed.push(await request.formData);
|
|
104
|
+
parsed.push(await event.request.formData());
|
|
141
105
|
}
|
|
142
106
|
else if (contentType?.startsWith("application/json")) {
|
|
143
|
-
|
|
144
|
-
// (issue only in edge runtimes and netlify preset)
|
|
145
|
-
const tmpReq = isH3EventBodyStreamLocked
|
|
146
|
-
? request
|
|
147
|
-
: new Request(request, { ...request, body: requestBody });
|
|
148
|
-
// what should work when #1721 is fixed
|
|
149
|
-
// just use request.json() here
|
|
150
|
-
parsed = fromJSON(await tmpReq.json(), {
|
|
107
|
+
parsed = fromJSON(await event.request.json(), {
|
|
151
108
|
plugins: [
|
|
152
109
|
CustomEventPlugin,
|
|
153
110
|
DOMExceptionPlugin,
|
|
@@ -158,17 +115,17 @@ async function handleServerFunction(h3Event) {
|
|
|
158
115
|
RequestPlugin,
|
|
159
116
|
ResponsePlugin,
|
|
160
117
|
URLSearchParamsPlugin,
|
|
161
|
-
URLPlugin
|
|
162
|
-
]
|
|
118
|
+
URLPlugin,
|
|
119
|
+
],
|
|
163
120
|
});
|
|
164
121
|
}
|
|
165
122
|
}
|
|
166
123
|
try {
|
|
167
124
|
let result = await provideRequestEvent(event, async () => {
|
|
168
|
-
/* @ts-
|
|
125
|
+
/* @ts-expect-error */
|
|
169
126
|
sharedConfig.context = { event };
|
|
170
127
|
event.locals.serverFunctionMeta = {
|
|
171
|
-
id: functionId
|
|
128
|
+
id: functionId,
|
|
172
129
|
};
|
|
173
130
|
return serverFunction(...parsed);
|
|
174
131
|
});
|
|
@@ -185,7 +142,7 @@ async function handleServerFunction(h3Event) {
|
|
|
185
142
|
mergeResponseHeaders(h3Event, result.headers);
|
|
186
143
|
// forward non-redirect statuses
|
|
187
144
|
if (result.status && (result.status < 300 || result.status >= 400))
|
|
188
|
-
|
|
145
|
+
h3Event.res.status = result.status;
|
|
189
146
|
if (result.customBody) {
|
|
190
147
|
result = await result.customBody();
|
|
191
148
|
}
|
|
@@ -196,7 +153,7 @@ async function handleServerFunction(h3Event) {
|
|
|
196
153
|
// handle no JS success case
|
|
197
154
|
if (!instance)
|
|
198
155
|
return handleNoJS(result, request, parsed);
|
|
199
|
-
|
|
156
|
+
h3Event.res.headers.set("content-type", "text/javascript");
|
|
200
157
|
return serializeToStream(instance, result);
|
|
201
158
|
}
|
|
202
159
|
catch (x) {
|
|
@@ -209,23 +166,23 @@ async function handleServerFunction(h3Event) {
|
|
|
209
166
|
mergeResponseHeaders(h3Event, x.headers);
|
|
210
167
|
// forward non-redirect statuses
|
|
211
168
|
if (x.status && (!instance || x.status < 300 || x.status >= 400))
|
|
212
|
-
|
|
169
|
+
h3Event.res.status = x.status;
|
|
213
170
|
if (x.customBody) {
|
|
214
171
|
x = x.customBody();
|
|
215
172
|
}
|
|
216
|
-
else if (x.body
|
|
173
|
+
else if (x.body === undefined)
|
|
217
174
|
x = null;
|
|
218
|
-
|
|
175
|
+
h3Event.res.headers.set("X-Error", "true");
|
|
219
176
|
}
|
|
220
177
|
else if (instance) {
|
|
221
178
|
const error = x instanceof Error ? x.message : typeof x === "string" ? x : "true";
|
|
222
|
-
|
|
179
|
+
h3Event.res.headers.set("X-Error", error.replace(/[\r\n]+/g, ""));
|
|
223
180
|
}
|
|
224
181
|
else {
|
|
225
182
|
x = handleNoJS(x, request, parsed, true);
|
|
226
183
|
}
|
|
227
184
|
if (instance) {
|
|
228
|
-
|
|
185
|
+
h3Event.res.headers.set("content-type", "text/javascript");
|
|
229
186
|
return serializeToStream(instance, x);
|
|
230
187
|
}
|
|
231
188
|
return x;
|
|
@@ -239,24 +196,26 @@ function handleNoJS(result, request, parsed, thrown) {
|
|
|
239
196
|
if (result instanceof Response) {
|
|
240
197
|
headers = new Headers(result.headers);
|
|
241
198
|
if (result.headers.has("Location")) {
|
|
242
|
-
headers.set(`Location`, new URL(result.headers.get("Location"), url.origin + import.meta.env.
|
|
199
|
+
headers.set(`Location`, new URL(result.headers.get("Location"), url.origin + import.meta.env.BASE_URL).toString());
|
|
243
200
|
statusCode = getExpectedRedirectStatus(result);
|
|
244
201
|
}
|
|
245
202
|
}
|
|
246
203
|
else
|
|
247
|
-
headers = new Headers({
|
|
204
|
+
headers = new Headers({
|
|
205
|
+
Location: new URL(request.headers.get("referer")).toString(),
|
|
206
|
+
});
|
|
248
207
|
if (result) {
|
|
249
208
|
headers.append("Set-Cookie", `flash=${encodeURIComponent(JSON.stringify({
|
|
250
209
|
url: url.pathname + url.search,
|
|
251
210
|
result: isError ? result.message : result,
|
|
252
211
|
thrown: thrown,
|
|
253
212
|
error: isError,
|
|
254
|
-
input: [...parsed.slice(0, -1), [...parsed[parsed.length - 1].entries()]]
|
|
213
|
+
input: [...parsed.slice(0, -1), [...parsed[parsed.length - 1].entries()]],
|
|
255
214
|
}))}; Secure; HttpOnly;`);
|
|
256
215
|
}
|
|
257
216
|
return new Response(null, {
|
|
258
217
|
status: statusCode,
|
|
259
|
-
headers
|
|
218
|
+
headers,
|
|
260
219
|
});
|
|
261
220
|
}
|
|
262
221
|
let App;
|
|
@@ -264,15 +223,15 @@ function createSingleFlightHeaders(sourceEvent) {
|
|
|
264
223
|
// cookie handling logic is pretty simplistic so this might be imperfect
|
|
265
224
|
// unclear if h3 internals are available on all platforms but we need a way to
|
|
266
225
|
// update request headers on the underlying H3 event.
|
|
267
|
-
const headers =
|
|
226
|
+
const headers = sourceEvent.request.headers;
|
|
268
227
|
const cookies = parseCookies(sourceEvent.nativeEvent);
|
|
269
228
|
const SetCookies = sourceEvent.response.headers.getSetCookie();
|
|
270
229
|
headers.delete("cookie");
|
|
271
|
-
let useH3Internals = false;
|
|
272
|
-
if (sourceEvent.nativeEvent.node?.req) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
}
|
|
230
|
+
// let useH3Internals = false;
|
|
231
|
+
// if (sourceEvent.nativeEvent.node?.req) {
|
|
232
|
+
// useH3Internals = true;
|
|
233
|
+
// sourceEvent.nativeEvent.node.req.headers.cookie = "";
|
|
234
|
+
// }
|
|
276
235
|
SetCookies.forEach(cookie => {
|
|
277
236
|
if (!cookie)
|
|
278
237
|
return;
|
|
@@ -289,7 +248,8 @@ function createSingleFlightHeaders(sourceEvent) {
|
|
|
289
248
|
});
|
|
290
249
|
Object.entries(cookies).forEach(([key, value]) => {
|
|
291
250
|
headers.append("cookie", `${key}=${value}`);
|
|
292
|
-
useH3Internals &&
|
|
251
|
+
// useH3Internals &&
|
|
252
|
+
// (sourceEvent.nativeEvent.node.req.headers.cookie += `${key}=${value};`);
|
|
293
253
|
});
|
|
294
254
|
return headers;
|
|
295
255
|
}
|
|
@@ -300,21 +260,22 @@ async function handleSingleFlight(sourceEvent, result) {
|
|
|
300
260
|
if (result.headers.has("X-Revalidate"))
|
|
301
261
|
revalidate = result.headers.get("X-Revalidate").split(",");
|
|
302
262
|
if (result.headers.has("Location"))
|
|
303
|
-
url = new URL(result.headers.get("Location"), new URL(sourceEvent.request.url).origin + import.meta.env.
|
|
263
|
+
url = new URL(result.headers.get("Location"), new URL(sourceEvent.request.url).origin + import.meta.env.BASE_URL).toString();
|
|
304
264
|
}
|
|
305
|
-
const event =
|
|
306
|
-
event.request = new Request(url, {
|
|
265
|
+
const event = { ...sourceEvent };
|
|
266
|
+
event.request = new Request(url, {
|
|
267
|
+
headers: createSingleFlightHeaders(sourceEvent),
|
|
268
|
+
});
|
|
307
269
|
return await provideRequestEvent(event, async () => {
|
|
308
270
|
await createPageEvent(event);
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
/* @ts-ignore */
|
|
271
|
+
App || (App = (await import("solid-start:app")).default);
|
|
272
|
+
/* @ts-expect-error */
|
|
312
273
|
event.router.dataOnly = revalidate || true;
|
|
313
|
-
/* @ts-
|
|
274
|
+
/* @ts-expect-error */
|
|
314
275
|
event.router.previousUrl = sourceEvent.request.headers.get("referer");
|
|
315
276
|
try {
|
|
316
277
|
renderToString(() => {
|
|
317
|
-
/* @ts-
|
|
278
|
+
/* @ts-expect-error */
|
|
318
279
|
sharedConfig.context.event = event;
|
|
319
280
|
App();
|
|
320
281
|
});
|
|
@@ -322,7 +283,7 @@ async function handleSingleFlight(sourceEvent, result) {
|
|
|
322
283
|
catch (e) {
|
|
323
284
|
console.log(e);
|
|
324
285
|
}
|
|
325
|
-
/* @ts-
|
|
286
|
+
/* @ts-expect-error */
|
|
326
287
|
const body = event.router.data;
|
|
327
288
|
if (!body)
|
|
328
289
|
return result;
|
|
@@ -347,4 +308,3 @@ async function handleSingleFlight(sourceEvent, result) {
|
|
|
347
308
|
return result;
|
|
348
309
|
});
|
|
349
310
|
}
|
|
350
|
-
export default eventHandler(handleServerFunction);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { deserialize, toJSONAsync } from "seroval";
|
|
2
|
-
import { CustomEventPlugin, DOMExceptionPlugin, EventPlugin, FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLPlugin, URLSearchParamsPlugin } from "seroval-plugins/web";
|
|
3
|
-
import { createIslandReference } from "../server/islands/index";
|
|
2
|
+
import { CustomEventPlugin, DOMExceptionPlugin, EventPlugin, FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLPlugin, URLSearchParamsPlugin, } from "seroval-plugins/web";
|
|
4
3
|
class SerovalChunkReader {
|
|
5
4
|
reader;
|
|
6
5
|
buffer;
|
|
@@ -31,7 +30,7 @@ class SerovalChunkReader {
|
|
|
31
30
|
if (this.done) {
|
|
32
31
|
return {
|
|
33
32
|
done: true,
|
|
34
|
-
value: undefined
|
|
33
|
+
value: undefined,
|
|
35
34
|
};
|
|
36
35
|
}
|
|
37
36
|
// Otherwise, read a new chunk
|
|
@@ -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
|
|
@@ -64,7 +60,7 @@ class SerovalChunkReader {
|
|
|
64
60
|
// Deserialize the chunk
|
|
65
61
|
return {
|
|
66
62
|
done: false,
|
|
67
|
-
value: deserialize(partial)
|
|
63
|
+
value: deserialize(partial),
|
|
68
64
|
};
|
|
69
65
|
}
|
|
70
66
|
async drain() {
|
|
@@ -100,8 +96,8 @@ function createRequest(base, id, instance, options) {
|
|
|
100
96
|
headers: {
|
|
101
97
|
...options.headers,
|
|
102
98
|
"X-Server-Id": id,
|
|
103
|
-
"X-Server-Instance": instance
|
|
104
|
-
}
|
|
99
|
+
"X-Server-Instance": instance,
|
|
100
|
+
},
|
|
105
101
|
});
|
|
106
102
|
}
|
|
107
103
|
const plugins = [
|
|
@@ -114,7 +110,7 @@ const plugins = [
|
|
|
114
110
|
RequestPlugin,
|
|
115
111
|
ResponsePlugin,
|
|
116
112
|
URLSearchParamsPlugin,
|
|
117
|
-
URLPlugin
|
|
113
|
+
URLPlugin,
|
|
118
114
|
];
|
|
119
115
|
async function fetchServerFunction(base, id, options, args) {
|
|
120
116
|
const instance = `server-fn:${INSTANCE++}`;
|
|
@@ -126,12 +122,12 @@ async function fetchServerFunction(base, id, options, args) {
|
|
|
126
122
|
? createRequest(base, id, instance, {
|
|
127
123
|
...options,
|
|
128
124
|
body: args[0],
|
|
129
|
-
headers: { ...options.headers, "Content-Type": "application/x-www-form-urlencoded" }
|
|
125
|
+
headers: { ...options.headers, "Content-Type": "application/x-www-form-urlencoded" },
|
|
130
126
|
})
|
|
131
127
|
: createRequest(base, id, instance, {
|
|
132
128
|
...options,
|
|
133
129
|
body: JSON.stringify(await Promise.resolve(toJSONAsync(args, { plugins }))),
|
|
134
|
-
headers: { ...options.headers, "Content-Type": "application/json" }
|
|
130
|
+
headers: { ...options.headers, "Content-Type": "application/json" },
|
|
135
131
|
}));
|
|
136
132
|
if (response.headers.has("Location") ||
|
|
137
133
|
response.headers.has("X-Revalidate") ||
|
|
@@ -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;
|
|
@@ -1,22 +1,20 @@
|
|
|
1
|
-
import { createBaseHandler } from "../handler";
|
|
1
|
+
import { createBaseHandler } from "../handler.js";
|
|
2
|
+
import { getSsrManifest } from "../manifest/ssr-manifest.js";
|
|
2
3
|
/**
|
|
3
4
|
*
|
|
4
5
|
* Read more: https://docs.solidjs.com/solid-start/reference/server/create-handler
|
|
5
6
|
*/
|
|
6
|
-
export function createHandler(fn, options
|
|
7
|
-
return createBaseHandler(
|
|
7
|
+
export function createHandler(fn, options) {
|
|
8
|
+
return createBaseHandler(createPageEvent, fn, options);
|
|
8
9
|
}
|
|
9
|
-
|
|
10
|
-
const
|
|
10
|
+
async function createPageEvent(ctx) {
|
|
11
|
+
const manifest = getSsrManifest("ssr");
|
|
11
12
|
const pageEvent = Object.assign(ctx, {
|
|
12
|
-
manifest: await
|
|
13
|
-
assets:
|
|
13
|
+
manifest: "json" in manifest ? await manifest.json() : {},
|
|
14
|
+
assets: await manifest.getAssets(import.meta.env.START_CLIENT_ENTRY),
|
|
14
15
|
routes: [],
|
|
15
16
|
complete: false,
|
|
16
|
-
|
|
17
|
-
// mutation: false,
|
|
18
|
-
// $type: FETCH_EVENT,
|
|
19
|
-
$islands: new Set()
|
|
17
|
+
$islands: new Set(),
|
|
20
18
|
});
|
|
21
19
|
return pageEvent;
|
|
22
20
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
export {
|
|
1
|
+
export { default as lazy } from "../../shared/lazy.ts";
|
|
2
|
+
export * from "../types.ts";
|
|
3
|
+
export { StartServer } from "./StartServer.tsx";
|
|
4
|
+
export { createHandler } from "./handler.ts";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// @refresh skip
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
export {
|
|
2
|
+
export { default as lazy } from "../../shared/lazy.js";
|
|
3
|
+
export * from "../types.js";
|
|
4
|
+
export { StartServer } from "./StartServer.jsx";
|
|
5
|
+
export { createHandler } from "./handler.js";
|
package/dist/server/types.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import type { H3Event } from "h3";
|
|
1
2
|
import type { JSX } from "solid-js";
|
|
2
|
-
import { RequestEvent } from "solid-js/web";
|
|
3
|
-
import { HTTPEvent } from "vinxi/http";
|
|
3
|
+
import type { RequestEvent } from "solid-js/web";
|
|
4
4
|
export type DocumentComponentProps = {
|
|
5
|
-
assets
|
|
5
|
+
assets?: JSX.Element;
|
|
6
6
|
scripts: JSX.Element;
|
|
7
7
|
children?: JSX.Element;
|
|
8
8
|
};
|
|
@@ -50,23 +50,21 @@ export interface FetchEvent {
|
|
|
50
50
|
response: ResponseStub;
|
|
51
51
|
clientAddress?: string;
|
|
52
52
|
locals: App.RequestEventLocals;
|
|
53
|
-
nativeEvent:
|
|
53
|
+
nativeEvent: H3Event;
|
|
54
54
|
}
|
|
55
55
|
export interface PageEvent extends RequestEvent {
|
|
56
|
-
|
|
57
|
-
assets: any;
|
|
56
|
+
assets: any[];
|
|
58
57
|
routes: any[];
|
|
59
58
|
$islands: Set<string>;
|
|
60
59
|
complete: boolean;
|
|
60
|
+
nonce?: string;
|
|
61
61
|
}
|
|
62
62
|
export interface APIEvent extends FetchEvent {
|
|
63
63
|
params: {
|
|
64
64
|
[key: string]: string;
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
|
-
export
|
|
68
|
-
(event: APIEvent): Promise<any>;
|
|
69
|
-
}
|
|
67
|
+
export type APIHandler = (event: APIEvent) => Promise<any>;
|
|
70
68
|
export interface ServerFunctionMeta {
|
|
71
69
|
id: string;
|
|
72
70
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// according to https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#redirection_messages
|
|
2
|
+
const validRedirectStatuses = new Set([301, 302, 303, 307, 308]);
|
|
3
|
+
export function getExpectedRedirectStatus(response) {
|
|
4
|
+
if (response.status && validRedirectStatuses.has(response.status)) {
|
|
5
|
+
return response.status;
|
|
6
|
+
}
|
|
7
|
+
return 302;
|
|
8
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// @refresh skip
|
|
2
2
|
import { ErrorBoundary as DefaultErrorBoundary, catchError } from "solid-js";
|
|
3
3
|
import { isServer } from "solid-js/web";
|
|
4
|
-
import { HttpStatusCode } from "./HttpStatusCode";
|
|
5
|
-
import { DevOverlay } from "./dev-overlay";
|
|
4
|
+
import { HttpStatusCode } from "./HttpStatusCode.js";
|
|
5
|
+
import { DevOverlay } from "./dev-overlay/index.jsx";
|
|
6
6
|
export const ErrorBoundary = import.meta.env.DEV && import.meta.env.START_DEV_OVERLAY
|
|
7
7
|
? (props) => <DevOverlay>{props.children}</DevOverlay>
|
|
8
8
|
: (props) => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// @refresh skip
|
|
2
2
|
import { onCleanup } from "solid-js";
|
|
3
3
|
import { getRequestEvent, isServer } from "solid-js/web";
|
|
4
|
+
import { appendHeader, setHeader } from "../http/index.js";
|
|
4
5
|
/**
|
|
5
6
|
*
|
|
6
7
|
* Read more: https://docs.solidjs.com/solid-start/reference/server/http-header
|
|
@@ -9,10 +10,11 @@ export const HttpHeader = isServer
|
|
|
9
10
|
? (props) => {
|
|
10
11
|
const event = getRequestEvent();
|
|
11
12
|
if (props.append)
|
|
12
|
-
|
|
13
|
+
appendHeader(props.name, props.value);
|
|
13
14
|
else
|
|
14
|
-
|
|
15
|
+
setHeader(props.name, props.value);
|
|
15
16
|
onCleanup(() => {
|
|
17
|
+
// @ts-expect-error
|
|
16
18
|
if (event.nativeEvent.handled || event.complete)
|
|
17
19
|
return;
|
|
18
20
|
const value = event.response.headers.get(props.name);
|
|
@@ -10,7 +10,9 @@ export const HttpStatusCode = isServer
|
|
|
10
10
|
const event = getRequestEvent();
|
|
11
11
|
event.response.status = props.code;
|
|
12
12
|
event.response.statusText = props.text;
|
|
13
|
-
onCleanup(() =>
|
|
13
|
+
onCleanup(() =>
|
|
14
|
+
// !event.nativeEvent.handled &&
|
|
15
|
+
!event.complete && (event.response.status = 200));
|
|
14
16
|
return null;
|
|
15
17
|
}
|
|
16
18
|
: (_props) => null;
|