@solidjs/start 1.0.0-rc.0 → 1.0.0-rc.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/config/index.js +3 -0
- package/dist/router/routes.js +1 -1
- package/dist/runtime/server-handler.js +7 -2
- package/dist/runtime/server-runtime.js +11 -7
- package/dist/server/StartServer.jsx +1 -1
- package/dist/server/fetchEvent.js +2 -2
- package/dist/server/handler.js +16 -16
- package/dist/server/pageEvent.js +2 -0
- package/dist/server/renderAsset.d.ts +1 -1
- package/dist/server/renderAsset.jsx +2 -2
- package/dist/server/spa/handler.js +1 -0
- package/dist/server/types.d.ts +1 -0
- package/dist/shared/HttpHeader.jsx +1 -1
- package/dist/shared/HttpStatusCode.jsx +1 -1
- package/dist/shared/dev-overlay/get-source-map.d.ts +1 -0
- package/package.json +4 -4
package/config/index.js
CHANGED
|
@@ -133,6 +133,7 @@ export function defineConfig(baseConfig = {}) {
|
|
|
133
133
|
},
|
|
134
134
|
cacheDir: "node_modules/.vinxi/server",
|
|
135
135
|
define: {
|
|
136
|
+
"import.meta.env.START_APP": JSON.stringify(`${start.appRoot}/app${entryExtension}`),
|
|
136
137
|
"import.meta.env.START_ISLANDS": JSON.stringify(start.experimental.islands),
|
|
137
138
|
"import.meta.env.SSR": JSON.stringify(true),
|
|
138
139
|
"import.meta.env.START_SSR": JSON.stringify(start.ssr),
|
|
@@ -200,6 +201,7 @@ export function defineConfig(baseConfig = {}) {
|
|
|
200
201
|
},
|
|
201
202
|
cacheDir: "node_modules/.vinxi/client",
|
|
202
203
|
define: {
|
|
204
|
+
"import.meta.env.START_APP": JSON.stringify(`${start.appRoot}/app${entryExtension}`),
|
|
203
205
|
"import.meta.env.START_ISLANDS": JSON.stringify(start.experimental.islands),
|
|
204
206
|
"import.meta.env.SSR": JSON.stringify(false),
|
|
205
207
|
"import.meta.env.START_SSR": JSON.stringify(start.ssr),
|
|
@@ -261,6 +263,7 @@ export function defineConfig(baseConfig = {}) {
|
|
|
261
263
|
}
|
|
262
264
|
},
|
|
263
265
|
define: {
|
|
266
|
+
"import.meta.env.START_APP": JSON.stringify(`${start.appRoot}/app${entryExtension}`),
|
|
264
267
|
"import.meta.env.START_ISLANDS": JSON.stringify(start.experimental.islands),
|
|
265
268
|
"import.meta.env.SSR": JSON.stringify(true),
|
|
266
269
|
"import.meta.env.START_SSR": JSON.stringify(start.ssr),
|
package/dist/router/routes.js
CHANGED
|
@@ -38,7 +38,7 @@ const router = createRouter({
|
|
|
38
38
|
routes: fileRoutes.reduce((memo, route) => {
|
|
39
39
|
if (!containsHTTP(route))
|
|
40
40
|
return memo;
|
|
41
|
-
let path = route.path.replace(/\([^)/]+\)/g, "").replace(/\*([^/]*)/g, (_, m) => `**:${m}`);
|
|
41
|
+
let path = route.path.replace(/\/\([^)/]+\)/g, "").replace(/\([^)/]+\)/g, "").replace(/\*([^/]*)/g, (_, m) => `**:${m}`);
|
|
42
42
|
if (/:[^/]*\?/g.test(path)) {
|
|
43
43
|
throw new Error(`Optional parameters are not supported in API routes: ${path}`);
|
|
44
44
|
}
|
|
@@ -10,10 +10,15 @@ import invariant from "vinxi/lib/invariant";
|
|
|
10
10
|
import { cloneEvent, getFetchEvent, mergeResponseHeaders } from "../server/fetchEvent";
|
|
11
11
|
import { createPageEvent } from "../server/pageEvent";
|
|
12
12
|
function createChunk(data) {
|
|
13
|
-
const
|
|
13
|
+
const encodeData = new TextEncoder().encode(data);
|
|
14
|
+
const bytes = encodeData.length;
|
|
14
15
|
const baseHex = bytes.toString(16);
|
|
15
16
|
const totalHex = "00000000".substring(0, 8 - baseHex.length) + baseHex; // 32-bit
|
|
16
|
-
|
|
17
|
+
const head = new TextEncoder().encode(`;0x${totalHex};`);
|
|
18
|
+
const chunk = new Uint8Array(12 + bytes);
|
|
19
|
+
chunk.set(head);
|
|
20
|
+
chunk.set(encodeData, 12);
|
|
21
|
+
return chunk;
|
|
17
22
|
}
|
|
18
23
|
function serializeToStream(id, value) {
|
|
19
24
|
return new ReadableStream({
|
|
@@ -7,7 +7,7 @@ class SerovalChunkReader {
|
|
|
7
7
|
done;
|
|
8
8
|
constructor(stream) {
|
|
9
9
|
this.reader = stream.getReader();
|
|
10
|
-
this.buffer =
|
|
10
|
+
this.buffer = new Uint8Array(0);
|
|
11
11
|
this.done = false;
|
|
12
12
|
}
|
|
13
13
|
async readChunk() {
|
|
@@ -15,7 +15,10 @@ class SerovalChunkReader {
|
|
|
15
15
|
const chunk = await this.reader.read();
|
|
16
16
|
if (!chunk.done) {
|
|
17
17
|
// repopulate the buffer
|
|
18
|
-
|
|
18
|
+
let newBuffer = new Uint8Array(this.buffer.length + chunk.value.length);
|
|
19
|
+
newBuffer.set(this.buffer);
|
|
20
|
+
newBuffer.set(chunk.value, this.buffer.length);
|
|
21
|
+
this.buffer = newBuffer;
|
|
19
22
|
}
|
|
20
23
|
else {
|
|
21
24
|
this.done = true;
|
|
@@ -23,7 +26,7 @@ class SerovalChunkReader {
|
|
|
23
26
|
}
|
|
24
27
|
async next() {
|
|
25
28
|
// Check if the buffer is empty
|
|
26
|
-
if (this.buffer ===
|
|
29
|
+
if (this.buffer.length === 0) {
|
|
27
30
|
// if we are already done...
|
|
28
31
|
if (this.done) {
|
|
29
32
|
return {
|
|
@@ -39,7 +42,8 @@ class SerovalChunkReader {
|
|
|
39
42
|
// The byte header tells us how big the expected data is
|
|
40
43
|
// so we know how much data we should wait before we
|
|
41
44
|
// deserialize the data
|
|
42
|
-
const
|
|
45
|
+
const head = new TextDecoder().decode(this.buffer.subarray(1, 11));
|
|
46
|
+
const bytes = Number.parseInt(head, 16); // ;0x00000000;
|
|
43
47
|
// Check if the buffer has enough bytes to be parsed
|
|
44
48
|
while (bytes > this.buffer.length - 12) {
|
|
45
49
|
// If it's not enough, and the reader is done
|
|
@@ -51,9 +55,9 @@ class SerovalChunkReader {
|
|
|
51
55
|
await this.readChunk();
|
|
52
56
|
}
|
|
53
57
|
// Extract the exact chunk as defined by the byte header
|
|
54
|
-
const partial = this.buffer.
|
|
58
|
+
const partial = new TextDecoder().decode(this.buffer.subarray(12, 12 + bytes));
|
|
55
59
|
// The rest goes to the buffer
|
|
56
|
-
this.buffer = this.buffer.
|
|
60
|
+
this.buffer = this.buffer.subarray(12 + bytes);
|
|
57
61
|
// Deserialize the chunk
|
|
58
62
|
return {
|
|
59
63
|
done: false,
|
|
@@ -163,7 +167,7 @@ export function createServerReference(fn, id, name) {
|
|
|
163
167
|
const fn = async (...args) => {
|
|
164
168
|
const encodeArgs = options.method && options.method.toUpperCase() === "GET";
|
|
165
169
|
return fetchServerFunction(encodeArgs
|
|
166
|
-
? url + (args.length ? `&args=${JSON.stringify(await Promise.resolve(toJSONAsync(args, { plugins })))}` : "")
|
|
170
|
+
? url + (args.length ? `&args=${encodeURIComponent(JSON.stringify(await Promise.resolve(toJSONAsync(args, { plugins }))))}` : "")
|
|
167
171
|
: `${baseURL}/_server`, `${id}#${name}`, options, encodeArgs ? [] : args);
|
|
168
172
|
};
|
|
169
173
|
fn.url = url;
|
|
@@ -58,7 +58,7 @@ export function StartServer(props) {
|
|
|
58
58
|
{docType}
|
|
59
59
|
<props.document assets={<>
|
|
60
60
|
<HydrationScript />
|
|
61
|
-
{context.assets.map((m) => renderAsset(m))}
|
|
61
|
+
{context.assets.map((m) => renderAsset(m, nonce))}
|
|
62
62
|
</>} scripts={nonce ? (<>
|
|
63
63
|
<script nonce={nonce} innerHTML={`window.manifest = ${JSON.stringify(context.manifest)}`}/>
|
|
64
64
|
<script type="module" nonce={nonce} async src={import.meta.env.MANIFEST["client"].inputs[import.meta.env.MANIFEST["client"].handler].output.path}/>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { appendResponseHeader, getRequestIP, getResponseHeader, getResponseHeaders, getResponseStatus, getResponseStatusText, getWebRequest, removeResponseHeader,
|
|
1
|
+
import { appendResponseHeader, getRequestIP, getResponseHeader, getResponseHeaders, getResponseStatus, getResponseStatusText, getWebRequest, removeResponseHeader, setResponseHeader, setResponseStatus } from "vinxi/http";
|
|
2
2
|
const fetchEventSymbol = Symbol("fetchEvent");
|
|
3
3
|
export function createFetchEvent(event) {
|
|
4
4
|
return {
|
|
@@ -23,7 +23,7 @@ export function getFetchEvent(h3Event) {
|
|
|
23
23
|
}
|
|
24
24
|
export function mergeResponseHeaders(h3Event, headers) {
|
|
25
25
|
for (const [key, value] of headers.entries()) {
|
|
26
|
-
|
|
26
|
+
appendResponseHeader(h3Event, key, value);
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
class HeaderProxy {
|
package/dist/server/handler.js
CHANGED
|
@@ -27,45 +27,44 @@ export function createBaseHandler(fn, createPageEvent, options = {}) {
|
|
|
27
27
|
}
|
|
28
28
|
// render
|
|
29
29
|
const context = await createPageEvent(event);
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const mode = options.mode || "stream";
|
|
30
|
+
const resolvedOptions = typeof options == "function" ? await options(context) : { ...options };
|
|
31
|
+
const mode = resolvedOptions.mode || "stream";
|
|
33
32
|
// @ts-ignore
|
|
34
|
-
if (
|
|
35
|
-
context.nonce =
|
|
33
|
+
if (resolvedOptions.nonce)
|
|
34
|
+
context.nonce = resolvedOptions.nonce;
|
|
36
35
|
if (mode === "sync" || !import.meta.env.START_SSR) {
|
|
37
36
|
const html = renderToString(() => {
|
|
38
37
|
sharedConfig.context.event = context;
|
|
39
38
|
return fn(context);
|
|
40
|
-
},
|
|
39
|
+
}, resolvedOptions);
|
|
40
|
+
context.complete = true;
|
|
41
41
|
if (context.response && context.response.headers.get("Location")) {
|
|
42
42
|
return sendRedirect(e, context.response.headers.get("Location"));
|
|
43
43
|
}
|
|
44
44
|
return html;
|
|
45
45
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
cloned.onCompleteAll = options => {
|
|
46
|
+
if (resolvedOptions.onCompleteAll) {
|
|
47
|
+
const og = resolvedOptions.onCompleteAll;
|
|
48
|
+
resolvedOptions.onCompleteAll = options => {
|
|
50
49
|
handleStreamCompleteRedirect(context)(options);
|
|
51
50
|
og(options);
|
|
52
51
|
};
|
|
53
52
|
}
|
|
54
53
|
else
|
|
55
|
-
|
|
56
|
-
if (
|
|
57
|
-
const og =
|
|
58
|
-
|
|
54
|
+
resolvedOptions.onCompleteAll = handleStreamCompleteRedirect(context);
|
|
55
|
+
if (resolvedOptions.onCompleteShell) {
|
|
56
|
+
const og = resolvedOptions.onCompleteShell;
|
|
57
|
+
resolvedOptions.onCompleteShell = options => {
|
|
59
58
|
handleShellCompleteRedirect(context, e)();
|
|
60
59
|
og(options);
|
|
61
60
|
};
|
|
62
61
|
}
|
|
63
62
|
else
|
|
64
|
-
|
|
63
|
+
resolvedOptions.onCompleteShell = handleShellCompleteRedirect(context, e);
|
|
65
64
|
const stream = renderToStream(() => {
|
|
66
65
|
sharedConfig.context.event = context;
|
|
67
66
|
return fn(context);
|
|
68
|
-
},
|
|
67
|
+
}, resolvedOptions);
|
|
69
68
|
if (context.response && context.response.headers.get("Location")) {
|
|
70
69
|
return sendRedirect(e, context.response.headers.get("Location"));
|
|
71
70
|
}
|
|
@@ -89,6 +88,7 @@ function handleShellCompleteRedirect(context, e) {
|
|
|
89
88
|
}
|
|
90
89
|
function handleStreamCompleteRedirect(context) {
|
|
91
90
|
return ({ write }) => {
|
|
91
|
+
context.complete = true;
|
|
92
92
|
const to = context.response && context.response.headers.get("Location");
|
|
93
93
|
to && write(`<script>window.location="${to}"</script>`);
|
|
94
94
|
};
|
package/dist/server/pageEvent.js
CHANGED
|
@@ -26,6 +26,7 @@ export async function createPageEvent(ctx) {
|
|
|
26
26
|
manifest: await clientManifest.json(),
|
|
27
27
|
assets: [
|
|
28
28
|
...(await clientManifest.inputs[clientManifest.handler].assets()),
|
|
29
|
+
...(import.meta.env.DEV ? await clientManifest.inputs[import.meta.env.START_APP].assets() : []),
|
|
29
30
|
...(import.meta.env.START_ISLANDS
|
|
30
31
|
? (await serverManifest.inputs[serverManifest.handler].assets()).filter(s => s.attrs.rel !== "modulepreload")
|
|
31
32
|
: [])
|
|
@@ -37,6 +38,7 @@ export async function createPageEvent(ctx) {
|
|
|
37
38
|
// prevUrl: prevPath || "",
|
|
38
39
|
// mutation: mutation,
|
|
39
40
|
// $type: FETCH_EVENT,
|
|
41
|
+
complete: false,
|
|
40
42
|
$islands: new Set()
|
|
41
43
|
});
|
|
42
44
|
return pageEvent;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { Asset } from "./types";
|
|
2
|
-
export declare function renderAsset(asset: Asset): any;
|
|
2
|
+
export declare function renderAsset(asset: Asset, nonce?: string): any;
|
|
@@ -7,7 +7,7 @@ const assetMap = {
|
|
|
7
7
|
</script>) : null;
|
|
8
8
|
}
|
|
9
9
|
};
|
|
10
|
-
export function renderAsset(asset) {
|
|
10
|
+
export function renderAsset(asset, nonce) {
|
|
11
11
|
let { tag, attrs: { key, ...attrs } = { key: undefined }, children } = asset;
|
|
12
|
-
return assetMap[tag]({ attrs, key, children });
|
|
12
|
+
return assetMap[tag]({ attrs: { ...attrs, nonce }, key, children });
|
|
13
13
|
}
|
|
@@ -8,6 +8,7 @@ export async function createPageEvent(ctx) {
|
|
|
8
8
|
manifest: await clientManifest.json(),
|
|
9
9
|
assets: [...(await clientManifest.inputs[clientManifest.handler].assets())],
|
|
10
10
|
routes: [],
|
|
11
|
+
complete: false,
|
|
11
12
|
// prevUrl: "",
|
|
12
13
|
// mutation: false,
|
|
13
14
|
// $type: FETCH_EVENT,
|
package/dist/server/types.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export const HttpHeader = isServer
|
|
|
9
9
|
else
|
|
10
10
|
event.response.headers.set(props.name, props.value);
|
|
11
11
|
onCleanup(() => {
|
|
12
|
-
if (event.nativeEvent.handled)
|
|
12
|
+
if (event.nativeEvent.handled || event.complete)
|
|
13
13
|
return;
|
|
14
14
|
const value = event.response.headers.get(props.name);
|
|
15
15
|
if (!value)
|
|
@@ -6,7 +6,7 @@ export const HttpStatusCode = isServer
|
|
|
6
6
|
const event = getRequestEvent();
|
|
7
7
|
event.response.status = props.code;
|
|
8
8
|
event.response.statusText = props.text;
|
|
9
|
-
onCleanup(() => !event.nativeEvent.handled && (event.response.status = 200));
|
|
9
|
+
onCleanup(() => !event.nativeEvent.handled && !event.complete && (event.response.status = 200));
|
|
10
10
|
return null;
|
|
11
11
|
}
|
|
12
12
|
: (_props) => null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidjs/start",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": "Ryan Carniato",
|
|
6
6
|
"license": "MIT",
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
}
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"solid-js": "^1.8.
|
|
55
|
-
"vinxi": "^0.3.
|
|
54
|
+
"solid-js": "^1.8.17",
|
|
55
|
+
"vinxi": "^0.3.11",
|
|
56
56
|
"typescript": "^5.4.2"
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"source-map-js": "^1.0.2",
|
|
71
71
|
"terracotta": "^1.0.4",
|
|
72
72
|
"vite-plugin-inspect": "^0.7.33",
|
|
73
|
-
"vite-plugin-solid": "
|
|
73
|
+
"vite-plugin-solid": "^2.10.2"
|
|
74
74
|
},
|
|
75
75
|
"scripts": {
|
|
76
76
|
"typecheck": "tsc --noEmit",
|