@solidjs/start 1.2.0 → 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.js +18 -197
- package/dist/server/handler.d.ts +6 -12
- package/dist/server/handler.js +180 -97
- 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 +5 -10
- package/dist/{router → server}/routes.js +35 -36
- 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} +65 -100
- 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 +45 -67
- 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 -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/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,62 +1,35 @@
|
|
|
1
|
+
import * as h3 from "h3";
|
|
1
2
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
vi.mock("
|
|
4
|
-
getWebRequest: vi.fn(),
|
|
5
|
-
getRequestIP: vi.fn(),
|
|
6
|
-
getResponseStatus: vi.fn(),
|
|
7
|
-
setResponseStatus: vi.fn(),
|
|
8
|
-
getResponseStatusText: vi.fn(),
|
|
9
|
-
getResponseHeader: vi.fn(),
|
|
10
|
-
getResponseHeaders: vi.fn(),
|
|
11
|
-
setResponseHeader: vi.fn(),
|
|
12
|
-
appendResponseHeader: vi.fn(),
|
|
13
|
-
removeResponseHeader: vi.fn()
|
|
14
|
-
}));
|
|
15
|
-
import * as vinxiHttp from "vinxi/http";
|
|
16
|
-
const mockedVinxiHttp = vi.mocked(vinxiHttp);
|
|
17
|
-
const createMockH3Event = () => {
|
|
18
|
-
const mockRequest = new Request("http://localhost/test");
|
|
19
|
-
const mockStatus = 200;
|
|
20
|
-
const mockStatusText = "OK";
|
|
3
|
+
import { createFetchEvent, getFetchEvent, mergeResponseHeaders, } from "./fetchEvent.js";
|
|
4
|
+
vi.mock(import("h3"), async (mod) => {
|
|
21
5
|
return {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
res: {
|
|
25
|
-
statusCode: mockStatus,
|
|
26
|
-
statusMessage: mockStatusText
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
context: {},
|
|
30
|
-
web: {
|
|
31
|
-
request: mockRequest
|
|
32
|
-
}
|
|
6
|
+
...(await mod()),
|
|
7
|
+
getRequestIP: vi.fn(),
|
|
33
8
|
};
|
|
9
|
+
});
|
|
10
|
+
const mockedH3 = vi.mocked(h3);
|
|
11
|
+
const createMockH3Event = () => {
|
|
12
|
+
const event = new h3.H3Event(new Request("http://localhost/test"));
|
|
13
|
+
event.res.status = 200;
|
|
14
|
+
event.res.statusText = "OK";
|
|
15
|
+
return event;
|
|
34
16
|
};
|
|
35
17
|
describe("fetchEvent", () => {
|
|
36
18
|
let mockH3Event;
|
|
37
19
|
beforeEach(() => {
|
|
38
20
|
mockH3Event = createMockH3Event();
|
|
39
21
|
vi.clearAllMocks();
|
|
40
|
-
|
|
41
|
-
mockedVinxiHttp.getRequestIP.mockReturnValue("127.0.0.1");
|
|
42
|
-
mockedVinxiHttp.getResponseStatus.mockReturnValue(200);
|
|
43
|
-
mockedVinxiHttp.setResponseStatus.mockImplementation(() => { });
|
|
44
|
-
mockedVinxiHttp.getResponseStatusText.mockReturnValue("OK");
|
|
45
|
-
mockedVinxiHttp.getResponseHeader.mockReturnValue(undefined);
|
|
46
|
-
mockedVinxiHttp.getResponseHeaders.mockReturnValue({});
|
|
47
|
-
mockedVinxiHttp.setResponseHeader.mockImplementation(() => { });
|
|
48
|
-
mockedVinxiHttp.appendResponseHeader.mockImplementation(() => { });
|
|
49
|
-
mockedVinxiHttp.removeResponseHeader.mockImplementation(() => { });
|
|
22
|
+
mockedH3.getRequestIP.mockReturnValue("127.0.0.1");
|
|
50
23
|
});
|
|
51
24
|
describe("createFetchEvent", () => {
|
|
52
25
|
it("should create a FetchEvent from H3Event", () => {
|
|
53
26
|
const fetchEvent = createFetchEvent(mockH3Event);
|
|
54
27
|
expect(fetchEvent).toEqual({
|
|
55
|
-
request: mockH3Event.
|
|
28
|
+
request: mockH3Event.req,
|
|
56
29
|
response: expect.any(Object),
|
|
57
30
|
clientAddress: "127.0.0.1",
|
|
58
31
|
locals: {},
|
|
59
|
-
nativeEvent: mockH3Event
|
|
32
|
+
nativeEvent: mockH3Event,
|
|
60
33
|
});
|
|
61
34
|
});
|
|
62
35
|
it("should create response stub with correct properties", () => {
|
|
@@ -66,16 +39,6 @@ describe("fetchEvent", () => {
|
|
|
66
39
|
expect(fetchEvent.response).toHaveProperty("headers");
|
|
67
40
|
});
|
|
68
41
|
});
|
|
69
|
-
describe("cloneEvent", () => {
|
|
70
|
-
it("should create a shallow copy of FetchEvent", () => {
|
|
71
|
-
const original = createFetchEvent(mockH3Event);
|
|
72
|
-
const cloned = cloneEvent(original);
|
|
73
|
-
expect(cloned).toEqual(original);
|
|
74
|
-
expect(cloned).not.toBe(original);
|
|
75
|
-
expect(cloned.request).toBe(original.request);
|
|
76
|
-
expect(cloned.response).toBe(original.response);
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
42
|
describe("getFetchEvent", () => {
|
|
80
43
|
it("should create and cache FetchEvent on first call", () => {
|
|
81
44
|
const fetchEvent = getFetchEvent(mockH3Event);
|
|
@@ -92,153 +55,11 @@ describe("fetchEvent", () => {
|
|
|
92
55
|
it("should merge headers from Headers object to H3Event", () => {
|
|
93
56
|
const headers = new Headers({
|
|
94
57
|
"content-type": "application/json",
|
|
95
|
-
"x-custom": "value"
|
|
58
|
+
"x-custom": "value",
|
|
96
59
|
});
|
|
97
60
|
mergeResponseHeaders(mockH3Event, headers);
|
|
98
|
-
expect(
|
|
99
|
-
expect(
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
describe("ResponseStub", () => {
|
|
103
|
-
let fetchEvent;
|
|
104
|
-
beforeEach(() => {
|
|
105
|
-
fetchEvent = createFetchEvent(mockH3Event);
|
|
106
|
-
});
|
|
107
|
-
describe("status", () => {
|
|
108
|
-
it("should get status from H3Event", () => {
|
|
109
|
-
expect(fetchEvent.response.status).toBe(200);
|
|
110
|
-
});
|
|
111
|
-
it("should set status on H3Event", () => {
|
|
112
|
-
fetchEvent.response.status = 404;
|
|
113
|
-
expect(mockedVinxiHttp.setResponseStatus).toHaveBeenCalledWith(mockH3Event, 404);
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
describe("statusText", () => {
|
|
117
|
-
it("should get statusText from H3Event", () => {
|
|
118
|
-
expect(fetchEvent.response.statusText).toBe("OK");
|
|
119
|
-
});
|
|
120
|
-
it("should set statusText on H3Event", () => {
|
|
121
|
-
fetchEvent.response.statusText = "Not Found";
|
|
122
|
-
expect(mockedVinxiHttp.setResponseStatus).toHaveBeenCalledWith(mockH3Event, 200, "Not Found");
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
describe("HeaderProxy", () => {
|
|
127
|
-
let fetchEvent;
|
|
128
|
-
beforeEach(() => {
|
|
129
|
-
fetchEvent = createFetchEvent(mockH3Event);
|
|
130
|
-
});
|
|
131
|
-
describe("get", () => {
|
|
132
|
-
it("should return null for non-existent header", () => {
|
|
133
|
-
expect(fetchEvent.response.headers.get("non-existent")).toBe(null);
|
|
134
|
-
});
|
|
135
|
-
it("should return string value for single header", () => {
|
|
136
|
-
mockedVinxiHttp.getResponseHeader.mockReturnValue("application/json");
|
|
137
|
-
expect(fetchEvent.response.headers.get("content-type")).toBe("application/json");
|
|
138
|
-
});
|
|
139
|
-
it("should join array values with comma", () => {
|
|
140
|
-
mockedVinxiHttp.getResponseHeader.mockReturnValue(["text/html", "application/json"]);
|
|
141
|
-
expect(fetchEvent.response.headers.get("accept")).toBe("text/html, application/json");
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
describe("has", () => {
|
|
145
|
-
it("should return false for non-existent header", () => {
|
|
146
|
-
mockedVinxiHttp.getResponseHeader.mockReturnValue(undefined);
|
|
147
|
-
expect(fetchEvent.response.headers.has("non-existent")).toBe(false);
|
|
148
|
-
});
|
|
149
|
-
it("should return true for existing header", () => {
|
|
150
|
-
mockedVinxiHttp.getResponseHeader.mockReturnValue("application/json");
|
|
151
|
-
expect(fetchEvent.response.headers.has("content-type")).toBe(true);
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
describe("set", () => {
|
|
155
|
-
it("should set header value", () => {
|
|
156
|
-
fetchEvent.response.headers.set("content-type", "application/json");
|
|
157
|
-
expect(mockedVinxiHttp.setResponseHeader).toHaveBeenCalledWith(mockH3Event, "content-type", "application/json");
|
|
158
|
-
});
|
|
159
|
-
});
|
|
160
|
-
describe("delete", () => {
|
|
161
|
-
it("should remove header", () => {
|
|
162
|
-
fetchEvent.response.headers.delete("content-type");
|
|
163
|
-
expect(mockedVinxiHttp.removeResponseHeader).toHaveBeenCalledWith(mockH3Event, "content-type");
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
describe("append", () => {
|
|
167
|
-
it("should append header value", () => {
|
|
168
|
-
fetchEvent.response.headers.append("x-custom", "value");
|
|
169
|
-
expect(mockedVinxiHttp.appendResponseHeader).toHaveBeenCalledWith(mockH3Event, "x-custom", "value");
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
describe("getSetCookie", () => {
|
|
173
|
-
it("should return array for single cookie", () => {
|
|
174
|
-
mockedVinxiHttp.getResponseHeader.mockReturnValue("session=abc123");
|
|
175
|
-
expect(fetchEvent.response.headers.getSetCookie()).toEqual(["session=abc123"]);
|
|
176
|
-
});
|
|
177
|
-
it("should return array for multiple cookies", () => {
|
|
178
|
-
mockedVinxiHttp.getResponseHeader.mockReturnValue(["session=abc123", "theme=dark"]);
|
|
179
|
-
expect(fetchEvent.response.headers.getSetCookie()).toEqual([
|
|
180
|
-
"session=abc123",
|
|
181
|
-
"theme=dark"
|
|
182
|
-
]);
|
|
183
|
-
});
|
|
184
|
-
});
|
|
185
|
-
describe("forEach", () => {
|
|
186
|
-
it("should iterate over headers", () => {
|
|
187
|
-
mockedVinxiHttp.getResponseHeaders.mockReturnValue({
|
|
188
|
-
"content-type": "application/json",
|
|
189
|
-
"x-custom": ["value1", "value2"]
|
|
190
|
-
});
|
|
191
|
-
const callback = vi.fn();
|
|
192
|
-
fetchEvent.response.headers.forEach(callback);
|
|
193
|
-
expect(callback).toHaveBeenCalledWith("application/json", "content-type", expect.any(Object));
|
|
194
|
-
expect(callback).toHaveBeenCalledWith("value1, value2", "x-custom", expect.any(Object));
|
|
195
|
-
});
|
|
196
|
-
});
|
|
197
|
-
describe("entries", () => {
|
|
198
|
-
it("should return iterator of header entries", () => {
|
|
199
|
-
mockedVinxiHttp.getResponseHeaders.mockReturnValue({
|
|
200
|
-
"content-type": "application/json",
|
|
201
|
-
"x-custom": ["value1", "value2"]
|
|
202
|
-
});
|
|
203
|
-
const entries = Array.from(fetchEvent.response.headers.entries());
|
|
204
|
-
expect(entries).toEqual([
|
|
205
|
-
["content-type", "application/json"],
|
|
206
|
-
["x-custom", "value1, value2"]
|
|
207
|
-
]);
|
|
208
|
-
});
|
|
209
|
-
});
|
|
210
|
-
describe("keys", () => {
|
|
211
|
-
it("should return iterator of header keys", () => {
|
|
212
|
-
mockedVinxiHttp.getResponseHeaders.mockReturnValue({
|
|
213
|
-
"content-type": "application/json",
|
|
214
|
-
"x-custom": "value"
|
|
215
|
-
});
|
|
216
|
-
const keys = Array.from(fetchEvent.response.headers.keys());
|
|
217
|
-
expect(keys).toEqual(["content-type", "x-custom"]);
|
|
218
|
-
});
|
|
219
|
-
});
|
|
220
|
-
describe("values", () => {
|
|
221
|
-
it("should return iterator of header values", () => {
|
|
222
|
-
mockedVinxiHttp.getResponseHeaders.mockReturnValue({
|
|
223
|
-
"content-type": "application/json",
|
|
224
|
-
"x-custom": ["value1", "value2"]
|
|
225
|
-
});
|
|
226
|
-
const values = Array.from(fetchEvent.response.headers.values());
|
|
227
|
-
expect(values).toEqual(["application/json", "value1, value2"]);
|
|
228
|
-
});
|
|
229
|
-
});
|
|
230
|
-
describe("Symbol.iterator", () => {
|
|
231
|
-
it("should be iterable", () => {
|
|
232
|
-
mockedVinxiHttp.getResponseHeaders.mockReturnValue({
|
|
233
|
-
"content-type": "application/json",
|
|
234
|
-
"x-custom": "value"
|
|
235
|
-
});
|
|
236
|
-
const entries = Array.from(fetchEvent.response.headers);
|
|
237
|
-
expect(entries).toEqual([
|
|
238
|
-
["content-type", "application/json"],
|
|
239
|
-
["x-custom", "value"]
|
|
240
|
-
]);
|
|
241
|
-
});
|
|
61
|
+
expect(headers.get("content-type")).toBe("application/json");
|
|
62
|
+
expect(headers.get("x-custom")).toBe("value");
|
|
242
63
|
});
|
|
243
64
|
});
|
|
244
65
|
});
|
package/dist/server/handler.d.ts
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export declare function
|
|
7
|
-
export declare function createBaseHandler(fn: (context: PageEvent) => unknown, createPageEvent: (event: FetchEvent) => Promise<PageEvent>, options?: HandlerOptions | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>), routerLoad?: (event: FetchEvent) => Promise<void>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
8
|
-
/**
|
|
9
|
-
*
|
|
10
|
-
* Read more: https://docs.solidjs.com/solid-start/reference/server/create-handler
|
|
11
|
-
*/
|
|
12
|
-
export declare function createHandler(fn: (context: PageEvent) => unknown, options?: HandlerOptions | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>), routerLoad?: (event: FetchEvent) => Promise<void>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
1
|
+
import { H3 } from "h3";
|
|
2
|
+
import type { JSX } from "solid-js";
|
|
3
|
+
import type { FetchEvent, HandlerOptions, PageEvent } from "./types.ts";
|
|
4
|
+
export declare function createBaseHandler(createPageEvent: (e: FetchEvent) => Promise<PageEvent>, fn: (context: PageEvent) => JSX.Element, options?: HandlerOptions | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>)): H3;
|
|
5
|
+
export declare function createHandler(fn: (context: PageEvent) => JSX.Element, options?: HandlerOptions | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>)): H3;
|
|
6
|
+
export declare function createPageEvent(ctx: FetchEvent): Promise<PageEvent>;
|
package/dist/server/handler.js
CHANGED
|
@@ -1,108 +1,182 @@
|
|
|
1
|
+
import middleware from "solid-start:middleware";
|
|
2
|
+
import { defineHandler, getCookie, H3, redirect, setCookie } from "h3";
|
|
3
|
+
import { join } from "pathe";
|
|
1
4
|
import { sharedConfig } from "solid-js";
|
|
2
|
-
import { renderToStream, renderToString } from "solid-js/web";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (res
|
|
38
|
-
return res;
|
|
39
|
-
|
|
40
|
-
throw new Error(`API handler for ${event.request.method} "${event.request.url}" did not return a response.`);
|
|
41
|
-
}
|
|
42
|
-
if (!match.isPage)
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
// render
|
|
46
|
-
const context = await createPageEvent(event);
|
|
47
|
-
const resolvedOptions = typeof options == "function" ? await options(context) : { ...options };
|
|
48
|
-
const mode = resolvedOptions.mode || "stream";
|
|
49
|
-
// @ts-ignore
|
|
50
|
-
if (resolvedOptions.nonce)
|
|
51
|
-
context.nonce = resolvedOptions.nonce;
|
|
52
|
-
if (mode === "sync" || !import.meta.env.START_SSR) {
|
|
53
|
-
const html = renderToString(() => {
|
|
54
|
-
sharedConfig.context.event = context;
|
|
55
|
-
return fn(context);
|
|
56
|
-
}, resolvedOptions);
|
|
57
|
-
context.complete = true;
|
|
58
|
-
if (context.response && context.response.headers.get("Location")) {
|
|
59
|
-
const status = getExpectedRedirectStatus(context.response);
|
|
60
|
-
return sendRedirect(e, context.response.headers.get("Location"), status);
|
|
61
|
-
}
|
|
62
|
-
return html;
|
|
5
|
+
import { getRequestEvent, renderToStream, renderToString } from "solid-js/web";
|
|
6
|
+
import { createRoutes } from "../router.jsx";
|
|
7
|
+
import { decorateHandler, decorateMiddleware } from "./fetchEvent.js";
|
|
8
|
+
import { getSsrManifest } from "./manifest/ssr-manifest.js";
|
|
9
|
+
import { matchAPIRoute } from "./routes.js";
|
|
10
|
+
import { handleServerFunction } from "./server-functions-handler.js";
|
|
11
|
+
import { getExpectedRedirectStatus } from "./util.js";
|
|
12
|
+
const SERVER_FN_BASE = "/_server";
|
|
13
|
+
export function createBaseHandler(createPageEvent, fn, options = {}) {
|
|
14
|
+
const handler = defineHandler({
|
|
15
|
+
middleware: middleware.length ? middleware.map(decorateMiddleware) : undefined,
|
|
16
|
+
handler: decorateHandler(async (e) => {
|
|
17
|
+
const event = getRequestEvent();
|
|
18
|
+
const url = new URL(event.request.url);
|
|
19
|
+
const pathname = url.pathname;
|
|
20
|
+
const serverFunctionTest = join(import.meta.env.BASE_URL, SERVER_FN_BASE);
|
|
21
|
+
if (pathname.startsWith(serverFunctionTest)) {
|
|
22
|
+
const serverFnResponse = await handleServerFunction(e);
|
|
23
|
+
if (serverFnResponse instanceof Response)
|
|
24
|
+
return produceResponseWithEventHeaders(serverFnResponse);
|
|
25
|
+
return new Response(serverFnResponse, {
|
|
26
|
+
headers: e.res.headers,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
const match = matchAPIRoute(pathname, event.request.method);
|
|
30
|
+
if (match) {
|
|
31
|
+
const mod = await match.handler.import();
|
|
32
|
+
const fn = event.request.method === "HEAD"
|
|
33
|
+
? mod["HEAD"] || mod["GET"]
|
|
34
|
+
: mod[event.request.method];
|
|
35
|
+
event.params = match.params || {};
|
|
36
|
+
// @ts-expect-error
|
|
37
|
+
sharedConfig.context = { event };
|
|
38
|
+
const res = await fn(event);
|
|
39
|
+
if (res !== undefined) {
|
|
40
|
+
if (res instanceof Response)
|
|
41
|
+
return produceResponseWithEventHeaders(res);
|
|
42
|
+
return res;
|
|
63
43
|
}
|
|
64
|
-
if (
|
|
65
|
-
|
|
66
|
-
resolvedOptions.onCompleteAll = options => {
|
|
67
|
-
handleStreamCompleteRedirect(context)(options);
|
|
68
|
-
og(options);
|
|
69
|
-
};
|
|
44
|
+
if (event.request.method !== "GET") {
|
|
45
|
+
throw new Error(`API handler for ${event.request.method} "${event.request.url}" did not return a response.`);
|
|
70
46
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
resolvedOptions.onCompleteShell = handleShellCompleteRedirect(context, e);
|
|
82
|
-
const stream = renderToStream(() => {
|
|
47
|
+
if (!match.isPage)
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const context = await createPageEvent(event);
|
|
51
|
+
const resolvedOptions = typeof options === "function" ? await options(context) : { ...options };
|
|
52
|
+
const mode = resolvedOptions.mode || "stream";
|
|
53
|
+
if (resolvedOptions.nonce)
|
|
54
|
+
context.nonce = resolvedOptions.nonce;
|
|
55
|
+
if (mode === "sync" || !import.meta.env.START_SSR) {
|
|
56
|
+
const html = renderToString(() => {
|
|
83
57
|
sharedConfig.context.event = context;
|
|
84
58
|
return fn(context);
|
|
85
|
-
}
|
|
59
|
+
});
|
|
60
|
+
context.complete = true;
|
|
86
61
|
if (context.response && context.response.headers.get("Location")) {
|
|
87
62
|
const status = getExpectedRedirectStatus(context.response);
|
|
88
|
-
return
|
|
63
|
+
return redirect(context.response.headers.get("Location"), status);
|
|
89
64
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
65
|
+
return html;
|
|
66
|
+
}
|
|
67
|
+
if (resolvedOptions.onCompleteAll) {
|
|
68
|
+
const og = resolvedOptions.onCompleteAll;
|
|
69
|
+
resolvedOptions.onCompleteAll = options => {
|
|
70
|
+
handleStreamCompleteRedirect(context)(options);
|
|
71
|
+
og(options);
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
else
|
|
75
|
+
resolvedOptions.onCompleteAll = handleStreamCompleteRedirect(context);
|
|
76
|
+
if (resolvedOptions.onCompleteShell) {
|
|
77
|
+
const og = resolvedOptions.onCompleteShell;
|
|
78
|
+
resolvedOptions.onCompleteShell = options => {
|
|
79
|
+
handleShellCompleteRedirect(context, e)();
|
|
80
|
+
og(options);
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
else
|
|
84
|
+
resolvedOptions.onCompleteShell = handleShellCompleteRedirect(context, e);
|
|
85
|
+
const _stream = renderToStream(() => {
|
|
86
|
+
sharedConfig.context.event = context;
|
|
87
|
+
return fn(context);
|
|
88
|
+
}, resolvedOptions);
|
|
89
|
+
const stream = _stream; // stream has a hidden 'then' method
|
|
90
|
+
if (context.response && context.response.headers.get("Location")) {
|
|
91
|
+
const status = getExpectedRedirectStatus(context.response);
|
|
92
|
+
return redirect(context.response.headers.get("Location"), status);
|
|
93
|
+
}
|
|
94
|
+
if (mode === "async")
|
|
95
|
+
return await stream;
|
|
96
|
+
delete stream.then;
|
|
97
|
+
// using TransformStream in dev can cause solid-start-dev-server to crash
|
|
98
|
+
// when stream is cancelled
|
|
99
|
+
if (globalThis.USING_SOLID_START_DEV_SERVER)
|
|
100
|
+
return stream;
|
|
101
|
+
// returning stream directly breaks cloudflare workers
|
|
102
|
+
const { writable, readable } = new TransformStream();
|
|
103
|
+
stream.pipeTo(writable);
|
|
104
|
+
return readable;
|
|
105
|
+
}),
|
|
98
106
|
});
|
|
107
|
+
const app = new H3();
|
|
108
|
+
app.use(handler);
|
|
109
|
+
return app;
|
|
110
|
+
}
|
|
111
|
+
export function createHandler(fn, options = {}) {
|
|
112
|
+
return createBaseHandler(createPageEvent, fn, options);
|
|
113
|
+
}
|
|
114
|
+
export async function createPageEvent(ctx) {
|
|
115
|
+
ctx.response.headers.set("Content-Type", "text/html");
|
|
116
|
+
// const prevPath = ctx.request.headers.get("x-solid-referrer");
|
|
117
|
+
// const mutation = ctx.request.headers.get("x-solid-mutation") === "true";
|
|
118
|
+
const manifest = getSsrManifest(import.meta.env.SSR && import.meta.env.DEV ? "ssr" : "client");
|
|
119
|
+
// Handle Vite build.cssCodeSplit
|
|
120
|
+
// When build.cssCodeSplit is false, a single CSS file is generated with the key style.css
|
|
121
|
+
const mergedCSS = import.meta.env.PROD ? await manifest.getAssets('style.css') : [];
|
|
122
|
+
const assets = [
|
|
123
|
+
...mergedCSS,
|
|
124
|
+
...(await manifest.getAssets(import.meta.env.START_CLIENT_ENTRY)),
|
|
125
|
+
...(await manifest.getAssets(import.meta.env.START_APP_ENTRY)),
|
|
126
|
+
// ...(import.meta.env.START_ISLANDS
|
|
127
|
+
// ? (await serverManifest.inputs[serverManifest.handler]!.assets()).filter(
|
|
128
|
+
// s => (s as any).attrs.rel !== "modulepreload"
|
|
129
|
+
// )
|
|
130
|
+
// : [])
|
|
131
|
+
];
|
|
132
|
+
const pageEvent = Object.assign(ctx, {
|
|
133
|
+
assets,
|
|
134
|
+
router: {
|
|
135
|
+
submission: initFromFlash(ctx),
|
|
136
|
+
},
|
|
137
|
+
routes: createRoutes(),
|
|
138
|
+
// prevUrl: prevPath || "",
|
|
139
|
+
// mutation: mutation,
|
|
140
|
+
// $type: FETCH_EVENT,
|
|
141
|
+
complete: false,
|
|
142
|
+
$islands: new Set(),
|
|
143
|
+
});
|
|
144
|
+
return pageEvent;
|
|
145
|
+
}
|
|
146
|
+
function initFromFlash(ctx) {
|
|
147
|
+
const flash = getCookie(ctx.nativeEvent, "flash");
|
|
148
|
+
if (!flash)
|
|
149
|
+
return;
|
|
150
|
+
try {
|
|
151
|
+
const param = JSON.parse(flash);
|
|
152
|
+
if (!param || !param.result)
|
|
153
|
+
return;
|
|
154
|
+
const input = [
|
|
155
|
+
...param.input.slice(0, -1),
|
|
156
|
+
new Map(param.input[param.input.length - 1]),
|
|
157
|
+
];
|
|
158
|
+
const result = param.error ? new Error(param.result) : param.result;
|
|
159
|
+
return {
|
|
160
|
+
input,
|
|
161
|
+
url: param.url,
|
|
162
|
+
pending: false,
|
|
163
|
+
result: param.thrown ? undefined : result,
|
|
164
|
+
error: param.thrown ? result : undefined,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
catch (e) {
|
|
168
|
+
console.error(e);
|
|
169
|
+
}
|
|
170
|
+
finally {
|
|
171
|
+
setCookie(ctx.nativeEvent, "flash", "", { maxAge: 0 });
|
|
172
|
+
}
|
|
99
173
|
}
|
|
100
174
|
function handleShellCompleteRedirect(context, e) {
|
|
101
175
|
return () => {
|
|
102
176
|
if (context.response && context.response.headers.get("Location")) {
|
|
103
177
|
const status = getExpectedRedirectStatus(context.response);
|
|
104
|
-
|
|
105
|
-
|
|
178
|
+
e.res.status = status;
|
|
179
|
+
e.res.headers.set("Location", context.response.headers.get("Location"));
|
|
106
180
|
}
|
|
107
181
|
};
|
|
108
182
|
}
|
|
@@ -113,10 +187,19 @@ function handleStreamCompleteRedirect(context) {
|
|
|
113
187
|
to && write(`<script>window.location="${to}"</script>`);
|
|
114
188
|
};
|
|
115
189
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
190
|
+
function produceResponseWithEventHeaders(res) {
|
|
191
|
+
const event = getRequestEvent();
|
|
192
|
+
let ret = res;
|
|
193
|
+
// Response.redirect returns an immutable value, so we clone on any redirect just in case
|
|
194
|
+
if (300 <= res.status && res.status < 400) {
|
|
195
|
+
ret = new Response(res.body, {
|
|
196
|
+
status: res.status,
|
|
197
|
+
statusText: res.statusText,
|
|
198
|
+
headers: Object.fromEntries(res.headers.entries())
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
for (const [name, value] of event.response.headers) {
|
|
202
|
+
ret.headers.set(name, value);
|
|
203
|
+
}
|
|
204
|
+
return ret;
|
|
122
205
|
}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
|
|
1
|
+
export { default as lazy } from "../shared/lazy.ts";
|
|
2
|
+
export { getServerFunctionMeta } from "../shared/serverFunction.ts";
|
|
3
|
+
export { StartServer } from "./StartServer.tsx";
|
|
4
|
+
export { createHandler } from "./handler.ts";
|
|
5
|
+
/**
|
|
6
|
+
* Checks if user has set a redirect status in the response.
|
|
7
|
+
* If not, falls back to the 302 (temporary redirect)
|
|
8
|
+
*/
|
package/dist/server/index.jsx
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
export {
|
|
3
|
-
export { StartServer } from "./StartServer";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
|
|
1
|
+
export { default as lazy } from "../shared/lazy.js";
|
|
2
|
+
export { getServerFunctionMeta } from "../shared/serverFunction.js";
|
|
3
|
+
export { StartServer } from "./StartServer.jsx";
|
|
4
|
+
export { createHandler } from "./handler.js";
|
|
5
|
+
/**
|
|
6
|
+
* Checks if user has set a redirect status in the response.
|
|
7
|
+
* If not, falls back to the 302 (temporary redirect)
|
|
8
|
+
*/
|
|
9
|
+
// export function getExpectedRedirectStatus(response: ResponseStub): number {
|
|
10
|
+
// if (response.status && validRedirectStatuses.has(response.status)) {
|
|
11
|
+
// return response.status;
|
|
12
|
+
// }
|
|
13
|
+
// return 302;
|
|
14
|
+
// }
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function getClientManifest(): {
|
|
2
|
+
import(id: string): Promise<any>;
|
|
3
|
+
getAssets(id: string): Promise<any[]>;
|
|
4
|
+
} | {
|
|
5
|
+
import(id: string): Promise<any>;
|
|
6
|
+
getAssets(id: string): Promise<any>;
|
|
7
|
+
json(): Promise<any>;
|
|
8
|
+
};
|
|
9
|
+
export { getClientManifest as getManifest };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { getClientDevManifest } from "./dev-client-manifest.js";
|
|
2
|
+
import { getClientProdManifest } from "./prod-client-manifest.js";
|
|
3
|
+
export function getClientManifest() {
|
|
4
|
+
return import.meta.env.DEV ? getClientDevManifest() : getClientProdManifest();
|
|
5
|
+
}
|
|
6
|
+
export { getClientManifest as getManifest };
|