@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,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("vinxi/http").EventHandler<import("vinxi/http").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("vinxi/http").EventHandler<import("vinxi/http").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,175 @@
|
|
|
1
|
+
import middleware from "solid-start:middleware";
|
|
2
|
+
import { defineHandler, getCookie, H3, redirect, setCookie } from "h3";
|
|
1
3
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (res !== undefined)
|
|
38
|
-
return res;
|
|
39
|
-
if (event.request.method !== "GET") {
|
|
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;
|
|
63
|
-
}
|
|
64
|
-
if (resolvedOptions.onCompleteAll) {
|
|
65
|
-
const og = resolvedOptions.onCompleteAll;
|
|
66
|
-
resolvedOptions.onCompleteAll = options => {
|
|
67
|
-
handleStreamCompleteRedirect(context)(options);
|
|
68
|
-
og(options);
|
|
69
|
-
};
|
|
4
|
+
import { getRequestEvent, renderToStream, renderToString } from "solid-js/web";
|
|
5
|
+
import { createRoutes } from "../router.jsx";
|
|
6
|
+
import { decorateHandler, decorateMiddleware } from "./fetchEvent.js";
|
|
7
|
+
import { getSsrManifest } from "./manifest/ssr-manifest.js";
|
|
8
|
+
import { matchAPIRoute } from "./routes.js";
|
|
9
|
+
import { handleServerFunction } from "./server-functions-handler.js";
|
|
10
|
+
import { getExpectedRedirectStatus } from "./util.js";
|
|
11
|
+
const SERVER_FN_BASE = "/_server";
|
|
12
|
+
export function createBaseHandler(createPageEvent, fn, options = {}) {
|
|
13
|
+
const handler = defineHandler({
|
|
14
|
+
middleware: middleware.length ? middleware.map(decorateMiddleware) : undefined,
|
|
15
|
+
handler: decorateHandler(async (e) => {
|
|
16
|
+
const event = getRequestEvent();
|
|
17
|
+
const url = new URL(event.request.url);
|
|
18
|
+
const pathname = stripBaseUrl(url.pathname);
|
|
19
|
+
if (pathname.startsWith(SERVER_FN_BASE)) {
|
|
20
|
+
const serverFnResponse = await handleServerFunction(e);
|
|
21
|
+
if (serverFnResponse instanceof Response)
|
|
22
|
+
return produceResponseWithEventHeaders(serverFnResponse);
|
|
23
|
+
return new Response(serverFnResponse, {
|
|
24
|
+
headers: e.res.headers,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
const match = matchAPIRoute(pathname, event.request.method);
|
|
28
|
+
if (match) {
|
|
29
|
+
const mod = await match.handler.import();
|
|
30
|
+
const fn = event.request.method === "HEAD" ? mod["HEAD"] || mod["GET"] : mod[event.request.method];
|
|
31
|
+
event.params = match.params || {};
|
|
32
|
+
// @ts-expect-error
|
|
33
|
+
sharedConfig.context = { event };
|
|
34
|
+
const res = await fn(event);
|
|
35
|
+
if (res !== undefined) {
|
|
36
|
+
if (res instanceof Response)
|
|
37
|
+
return produceResponseWithEventHeaders(res);
|
|
38
|
+
return res;
|
|
70
39
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if (resolvedOptions.onCompleteShell) {
|
|
74
|
-
const og = resolvedOptions.onCompleteShell;
|
|
75
|
-
resolvedOptions.onCompleteShell = options => {
|
|
76
|
-
handleShellCompleteRedirect(context, e)();
|
|
77
|
-
og(options);
|
|
78
|
-
};
|
|
40
|
+
if (event.request.method !== "GET") {
|
|
41
|
+
throw new Error(`API handler for ${event.request.method} "${event.request.url}" did not return a response.`);
|
|
79
42
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
43
|
+
if (!match.isPage)
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const context = await createPageEvent(event);
|
|
47
|
+
const resolvedOptions = typeof options === "function" ? await options(context) : { ...options };
|
|
48
|
+
const mode = resolvedOptions.mode || "stream";
|
|
49
|
+
if (resolvedOptions.nonce)
|
|
50
|
+
context.nonce = resolvedOptions.nonce;
|
|
51
|
+
if (mode === "sync" || !import.meta.env.START_SSR) {
|
|
52
|
+
const html = renderToString(() => {
|
|
83
53
|
sharedConfig.context.event = context;
|
|
84
54
|
return fn(context);
|
|
85
55
|
}, resolvedOptions);
|
|
56
|
+
context.complete = true;
|
|
86
57
|
if (context.response && context.response.headers.get("Location")) {
|
|
87
58
|
const status = getExpectedRedirectStatus(context.response);
|
|
88
|
-
return
|
|
59
|
+
return redirect(context.response.headers.get("Location"), status);
|
|
89
60
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
61
|
+
return html;
|
|
62
|
+
}
|
|
63
|
+
if (resolvedOptions.onCompleteAll) {
|
|
64
|
+
const og = resolvedOptions.onCompleteAll;
|
|
65
|
+
resolvedOptions.onCompleteAll = options => {
|
|
66
|
+
handleStreamCompleteRedirect(context)(options);
|
|
67
|
+
og(options);
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
else
|
|
71
|
+
resolvedOptions.onCompleteAll = handleStreamCompleteRedirect(context);
|
|
72
|
+
if (resolvedOptions.onCompleteShell) {
|
|
73
|
+
const og = resolvedOptions.onCompleteShell;
|
|
74
|
+
resolvedOptions.onCompleteShell = options => {
|
|
75
|
+
handleShellCompleteRedirect(context, e)();
|
|
76
|
+
og(options);
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
else
|
|
80
|
+
resolvedOptions.onCompleteShell = handleShellCompleteRedirect(context, e);
|
|
81
|
+
const _stream = renderToStream(() => {
|
|
82
|
+
sharedConfig.context.event = context;
|
|
83
|
+
return fn(context);
|
|
84
|
+
}, resolvedOptions);
|
|
85
|
+
const stream = _stream; // stream has a hidden 'then' method
|
|
86
|
+
if (context.response && context.response.headers.get("Location")) {
|
|
87
|
+
const status = getExpectedRedirectStatus(context.response);
|
|
88
|
+
return redirect(context.response.headers.get("Location"), status);
|
|
89
|
+
}
|
|
90
|
+
if (mode === "async")
|
|
91
|
+
return await stream;
|
|
92
|
+
delete stream.then;
|
|
93
|
+
// using TransformStream in dev can cause solid-start-dev-server to crash
|
|
94
|
+
// when stream is cancelled
|
|
95
|
+
if (globalThis.USING_SOLID_START_DEV_SERVER)
|
|
96
|
+
return stream;
|
|
97
|
+
// returning stream directly breaks cloudflare workers
|
|
98
|
+
const { writable, readable } = new TransformStream();
|
|
99
|
+
stream.pipeTo(writable);
|
|
100
|
+
return readable;
|
|
101
|
+
}),
|
|
98
102
|
});
|
|
103
|
+
const app = new H3();
|
|
104
|
+
app.use(handler);
|
|
105
|
+
return app;
|
|
106
|
+
}
|
|
107
|
+
export function createHandler(fn, options = {}) {
|
|
108
|
+
return createBaseHandler(createPageEvent, fn, options);
|
|
109
|
+
}
|
|
110
|
+
export async function createPageEvent(ctx) {
|
|
111
|
+
ctx.response.headers.set("Content-Type", "text/html");
|
|
112
|
+
// const prevPath = ctx.request.headers.get("x-solid-referrer");
|
|
113
|
+
// const mutation = ctx.request.headers.get("x-solid-mutation") === "true";
|
|
114
|
+
const manifest = getSsrManifest(import.meta.env.SSR && import.meta.env.DEV ? "ssr" : "client");
|
|
115
|
+
// Handle Vite build.cssCodeSplit
|
|
116
|
+
// When build.cssCodeSplit is false, a single CSS file is generated with the key style.css
|
|
117
|
+
const mergedCSS = import.meta.env.PROD ? await manifest.getAssets("style.css") : [];
|
|
118
|
+
const assets = [
|
|
119
|
+
...mergedCSS,
|
|
120
|
+
...(await manifest.getAssets(import.meta.env.START_CLIENT_ENTRY)),
|
|
121
|
+
...(await manifest.getAssets(import.meta.env.START_APP_ENTRY)),
|
|
122
|
+
// ...(import.meta.env.START_ISLANDS
|
|
123
|
+
// ? (await serverManifest.inputs[serverManifest.handler]!.assets()).filter(
|
|
124
|
+
// s => (s as any).attrs.rel !== "modulepreload"
|
|
125
|
+
// )
|
|
126
|
+
// : [])
|
|
127
|
+
];
|
|
128
|
+
const pageEvent = Object.assign(ctx, {
|
|
129
|
+
assets,
|
|
130
|
+
router: {
|
|
131
|
+
submission: initFromFlash(ctx),
|
|
132
|
+
},
|
|
133
|
+
routes: createRoutes(),
|
|
134
|
+
// prevUrl: prevPath || "",
|
|
135
|
+
// mutation: mutation,
|
|
136
|
+
// $type: FETCH_EVENT,
|
|
137
|
+
complete: false,
|
|
138
|
+
$islands: new Set(),
|
|
139
|
+
});
|
|
140
|
+
return pageEvent;
|
|
141
|
+
}
|
|
142
|
+
function initFromFlash(ctx) {
|
|
143
|
+
const flash = getCookie(ctx.nativeEvent, "flash");
|
|
144
|
+
if (!flash)
|
|
145
|
+
return;
|
|
146
|
+
try {
|
|
147
|
+
const param = JSON.parse(flash);
|
|
148
|
+
if (!param || !param.result)
|
|
149
|
+
return;
|
|
150
|
+
const input = [...param.input.slice(0, -1), new Map(param.input[param.input.length - 1])];
|
|
151
|
+
const result = param.error ? new Error(param.result) : param.result;
|
|
152
|
+
return {
|
|
153
|
+
input,
|
|
154
|
+
url: param.url,
|
|
155
|
+
pending: false,
|
|
156
|
+
result: param.thrown ? undefined : result,
|
|
157
|
+
error: param.thrown ? result : undefined,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
catch (e) {
|
|
161
|
+
console.error(e);
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
setCookie(ctx.nativeEvent, "flash", "", { maxAge: 0 });
|
|
165
|
+
}
|
|
99
166
|
}
|
|
100
167
|
function handleShellCompleteRedirect(context, e) {
|
|
101
168
|
return () => {
|
|
102
169
|
if (context.response && context.response.headers.get("Location")) {
|
|
103
170
|
const status = getExpectedRedirectStatus(context.response);
|
|
104
|
-
|
|
105
|
-
|
|
171
|
+
e.res.status = status;
|
|
172
|
+
e.res.headers.set("Location", context.response.headers.get("Location"));
|
|
106
173
|
}
|
|
107
174
|
};
|
|
108
175
|
}
|
|
@@ -113,10 +180,40 @@ function handleStreamCompleteRedirect(context) {
|
|
|
113
180
|
to && write(`<script>window.location="${to}"</script>`);
|
|
114
181
|
};
|
|
115
182
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
183
|
+
function produceResponseWithEventHeaders(res) {
|
|
184
|
+
const event = getRequestEvent();
|
|
185
|
+
let ret = res;
|
|
186
|
+
// Response.redirect returns an immutable value, so we clone on any redirect just in case
|
|
187
|
+
if (300 <= res.status && res.status < 400) {
|
|
188
|
+
const cookies = res.headers.getSetCookie?.() ?? [];
|
|
189
|
+
const headers = new Headers();
|
|
190
|
+
res.headers.forEach((value, key) => {
|
|
191
|
+
if (key.toLowerCase() !== "set-cookie") {
|
|
192
|
+
headers.set(key, value);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
for (const cookie of cookies) {
|
|
196
|
+
headers.append("Set-Cookie", cookie);
|
|
197
|
+
}
|
|
198
|
+
ret = new Response(res.body, {
|
|
199
|
+
status: res.status,
|
|
200
|
+
statusText: res.statusText,
|
|
201
|
+
headers,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
const eventCookies = event.response.headers.getSetCookie?.() ?? [];
|
|
205
|
+
for (const cookie of eventCookies) {
|
|
206
|
+
ret.headers.append("Set-Cookie", cookie);
|
|
207
|
+
}
|
|
208
|
+
for (const [name, value] of event.response.headers) {
|
|
209
|
+
if (name.toLowerCase() !== "set-cookie") {
|
|
210
|
+
ret.headers.set(name, value);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return ret;
|
|
214
|
+
}
|
|
215
|
+
function stripBaseUrl(path) {
|
|
216
|
+
if (import.meta.env.BASE_URL === "/" || import.meta.env.BASE_URL === "")
|
|
217
|
+
return path;
|
|
218
|
+
return path.slice(import.meta.env.BASE_URL.length);
|
|
122
219
|
}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
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
|
+
export type { APIEvent, APIHandler, Asset, ContextMatches, DocumentComponentProps, FetchEvent, HandlerOptions, PageEvent, ResponseStub, ServerFunctionMeta, } from "./types.ts";
|
|
6
|
+
/**
|
|
7
|
+
* Checks if user has set a redirect status in the response.
|
|
8
|
+
* If not, falls back to the 302 (temporary redirect)
|
|
9
|
+
*/
|
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 };
|