@solidjs/start 1.1.7 → 2.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. package/README.md +88 -8
  2. package/dist/client/StartClient.d.ts +0 -1
  3. package/dist/client/StartClient.jsx +2 -4
  4. package/dist/client/index.d.ts +2 -3
  5. package/dist/client/index.jsx +2 -4
  6. package/dist/client/mount.js +10 -2
  7. package/dist/client/spa/index.d.ts +1 -2
  8. package/dist/client/spa/index.jsx +1 -2
  9. package/dist/config/constants.d.ts +16 -0
  10. package/dist/config/constants.js +16 -0
  11. package/dist/config/dev-server.d.ts +2 -0
  12. package/dist/config/dev-server.js +108 -0
  13. package/dist/config/fs-router.d.ts +37 -0
  14. package/dist/config/fs-router.js +153 -0
  15. package/dist/config/fs-routes/fs-watcher.d.ts +3 -0
  16. package/dist/config/fs-routes/fs-watcher.js +49 -0
  17. package/dist/config/fs-routes/index.d.ts +7 -0
  18. package/dist/config/fs-routes/index.js +109 -0
  19. package/dist/config/fs-routes/router.d.ts +37 -0
  20. package/dist/config/fs-routes/router.js +136 -0
  21. package/dist/config/fs-routes/tree-shake.d.ts +2 -0
  22. package/dist/config/fs-routes/tree-shake.js +357 -0
  23. package/dist/config/index.d.ts +10 -0
  24. package/dist/config/index.js +217 -0
  25. package/dist/config/lazy.d.ts +3 -0
  26. package/dist/config/lazy.js +82 -0
  27. package/dist/config/manifest.d.ts +3 -0
  28. package/dist/config/manifest.js +74 -0
  29. package/dist/config/utils.d.ts +4 -0
  30. package/dist/config/utils.js +6 -0
  31. package/dist/config/vite-utils.d.ts +16 -0
  32. package/dist/config/vite-utils.js +81 -0
  33. package/dist/http/index.d.ts +84 -0
  34. package/dist/http/index.js +131 -0
  35. package/dist/index.d.ts +6 -5
  36. package/dist/index.jsx +5 -5
  37. package/dist/middleware/index.d.ts +6 -6
  38. package/dist/middleware/index.js +39 -0
  39. package/dist/{router/FileRoutes.js → router.jsx} +5 -6
  40. package/dist/server/StartServer.d.ts +3 -3
  41. package/dist/server/StartServer.jsx +9 -63
  42. package/dist/server/assets/index.d.ts +2 -0
  43. package/dist/server/assets/index.js +52 -0
  44. package/dist/server/assets/render.d.ts +19 -0
  45. package/dist/server/{renderAsset.jsx → assets/render.jsx} +1 -1
  46. package/dist/server/collect-styles.d.ts +3 -0
  47. package/dist/server/collect-styles.js +69 -0
  48. package/dist/server/fetchEvent.d.ts +4 -3
  49. package/dist/server/fetchEvent.js +12 -74
  50. package/dist/server/fetchEvent.spec.d.ts +1 -0
  51. package/dist/server/fetchEvent.spec.js +65 -0
  52. package/dist/server/handler.d.ts +6 -12
  53. package/dist/server/handler.js +180 -95
  54. package/dist/server/index.d.ts +8 -6
  55. package/dist/server/index.jsx +14 -6
  56. package/dist/server/manifest/client-manifest.d.ts +9 -0
  57. package/dist/server/manifest/client-manifest.js +6 -0
  58. package/dist/server/manifest/dev-client-manifest.d.ts +4 -0
  59. package/dist/server/manifest/dev-client-manifest.js +24 -0
  60. package/dist/server/manifest/dev-ssr-manifest.d.ts +5 -0
  61. package/dist/server/manifest/dev-ssr-manifest.js +23 -0
  62. package/dist/server/manifest/prod-client-manifest.d.ts +5 -0
  63. package/dist/server/manifest/prod-client-manifest.js +26 -0
  64. package/dist/server/manifest/prod-ssr-manifest.d.ts +6 -0
  65. package/dist/server/manifest/prod-ssr-manifest.js +90 -0
  66. package/dist/server/manifest/ssr-manifest.d.ts +4 -0
  67. package/dist/server/manifest/ssr-manifest.js +6 -0
  68. package/dist/{router → server}/routes.d.ts +6 -10
  69. package/dist/{router → server}/routes.js +35 -27
  70. package/dist/{runtime → server}/server-fns-runtime.d.ts +1 -1
  71. package/dist/{runtime → server}/server-fns-runtime.js +7 -6
  72. package/dist/server/server-functions-handler.d.ts +2 -0
  73. package/dist/{runtime/server-handler.js → server/server-functions-handler.js} +76 -103
  74. package/dist/server/server-runtime.d.ts +3 -0
  75. package/dist/{runtime → server}/server-runtime.js +9 -16
  76. package/dist/server/spa/StartServer.d.ts +1 -1
  77. package/dist/server/spa/StartServer.jsx +7 -9
  78. package/dist/server/spa/handler.d.ts +3 -3
  79. package/dist/server/spa/handler.js +9 -11
  80. package/dist/server/spa/index.d.ts +4 -3
  81. package/dist/server/spa/index.jsx +4 -3
  82. package/dist/server/types.d.ts +7 -9
  83. package/dist/server/util.d.ts +2 -0
  84. package/dist/server/util.js +8 -0
  85. package/dist/shared/ErrorBoundary.jsx +2 -2
  86. package/dist/shared/HttpHeader.jsx +4 -2
  87. package/dist/shared/{HttpStatusCode.jsx → HttpStatusCode.js} +3 -1
  88. package/dist/shared/dev-overlay/DevOverlayDialog.d.ts +2 -2
  89. package/dist/shared/dev-overlay/DevOverlayDialog.jsx +75 -66
  90. package/dist/shared/dev-overlay/createStackFrame.js +3 -3
  91. package/dist/shared/dev-overlay/index.jsx +5 -8
  92. package/dist/shared/lazy.d.ts +3 -0
  93. package/dist/shared/lazy.js +40 -0
  94. package/dist/shared/serverFunction.d.ts +1 -1
  95. package/package.json +47 -65
  96. package/scripts/build.js +15 -0
  97. package/scripts/validate-imports.js +316 -0
  98. package/src/client/StartClient.tsx +34 -0
  99. package/src/client/index.tsx +2 -0
  100. package/src/client/mount.ts +114 -0
  101. package/src/client/spa/index.tsx +9 -0
  102. package/src/config/constants.ts +19 -0
  103. package/src/config/dev-server.ts +149 -0
  104. package/src/config/fs-router.ts +177 -0
  105. package/src/config/fs-routes/fs-watcher.ts +81 -0
  106. package/src/config/fs-routes/index.ts +138 -0
  107. package/src/config/fs-routes/router.ts +169 -0
  108. package/src/config/fs-routes/tree-shake.ts +392 -0
  109. package/src/config/index.ts +236 -0
  110. package/src/config/lazy.ts +100 -0
  111. package/src/config/manifest.ts +84 -0
  112. package/src/config/utils.ts +5 -0
  113. package/src/config/vite-utils.ts +113 -0
  114. package/src/env.d.ts +35 -0
  115. package/src/http/index.ts +253 -0
  116. package/src/index.tsx +19 -0
  117. package/src/internal.d.ts +14 -0
  118. package/src/middleware/index.ts +82 -0
  119. package/src/router.tsx +36 -0
  120. package/src/server/StartServer.tsx +62 -0
  121. package/src/server/assets/index.ts +70 -0
  122. package/src/server/assets/render.tsx +42 -0
  123. package/src/server/collect-styles.ts +94 -0
  124. package/src/server/fetchEvent.spec.ts +89 -0
  125. package/src/server/fetchEvent.ts +36 -0
  126. package/src/server/handler.ts +250 -0
  127. package/src/server/index.tsx +16 -0
  128. package/src/server/manifest/client-manifest.ts +8 -0
  129. package/src/server/manifest/dev-client-manifest.ts +19 -0
  130. package/src/server/manifest/dev-ssr-manifest.ts +21 -0
  131. package/src/server/manifest/prod-client-manifest.ts +18 -0
  132. package/src/server/manifest/prod-ssr-manifest.ts +125 -0
  133. package/src/server/manifest/ssr-manifest.ts +8 -0
  134. package/src/server/routes.ts +138 -0
  135. package/src/server/server-fns-runtime.ts +31 -0
  136. package/src/server/server-functions-handler.ts +364 -0
  137. package/src/server/server-runtime.ts +240 -0
  138. package/src/server/spa/StartServer.tsx +40 -0
  139. package/src/server/spa/handler.ts +29 -0
  140. package/src/server/spa/index.tsx +5 -0
  141. package/src/server/types.ts +82 -0
  142. package/src/server/util.ts +12 -0
  143. package/src/shared/ErrorBoundary.tsx +52 -0
  144. package/src/shared/GET.ts +8 -0
  145. package/src/shared/HttpHeader.tsx +42 -0
  146. package/src/shared/HttpStatusCode.ts +27 -0
  147. package/src/shared/clientOnly.ts +44 -0
  148. package/src/shared/dev-overlay/CodeView.tsx +95 -0
  149. package/src/shared/dev-overlay/DevOverlayDialog.tsx +316 -0
  150. package/src/shared/dev-overlay/createStackFrame.ts +77 -0
  151. package/src/shared/dev-overlay/download.ts +6 -0
  152. package/src/shared/dev-overlay/env.d.ts +4 -0
  153. package/src/shared/dev-overlay/get-source-map.ts +35 -0
  154. package/src/shared/dev-overlay/icons.tsx +288 -0
  155. package/src/shared/dev-overlay/index.tsx +63 -0
  156. package/src/shared/dev-overlay/styles.css +292 -0
  157. package/src/shared/lazy.ts +51 -0
  158. package/src/shared/serverFunction.ts +10 -0
  159. package/src/virtual.d.ts +27 -0
  160. package/tsconfig.json +23 -0
  161. package/vitest.config.ts +9 -0
  162. package/config/fs-router.js +0 -142
  163. package/config/index.d.ts +0 -39
  164. package/config/index.js +0 -303
  165. package/config/server-components.js +0 -106
  166. package/dist/client/islands.d.ts +0 -7
  167. package/dist/client/islands.jsx +0 -10
  168. package/dist/middleware/index.jsx +0 -35
  169. package/dist/router/index.d.ts +0 -1
  170. package/dist/router/index.jsx +0 -2
  171. package/dist/router/lazyRoute.d.ts +0 -6
  172. package/dist/router/lazyRoute.js +0 -53
  173. package/dist/runtime/server-handler.d.ts +0 -2
  174. package/dist/runtime/server-runtime.d.ts +0 -3
  175. package/dist/server/islands/index.d.ts +0 -19
  176. package/dist/server/islands/index.jsx +0 -62
  177. package/dist/server/islands/utils.d.ts +0 -1
  178. package/dist/server/islands/utils.jsx +0 -85
  179. package/dist/server/pageEvent.d.ts +0 -2
  180. package/dist/server/pageEvent.js +0 -56
  181. package/dist/server/renderAsset.d.ts +0 -2
  182. package/env.d.ts +0 -26
  183. /package/dist/{router/FileRoutes.d.ts → router.d.ts} +0 -0
  184. /package/dist/shared/{clientOnly.jsx → clientOnly.js} +0 -0
  185. /package/dist/shared/{serverFunction.jsx → serverFunction.js} +0 -0
@@ -0,0 +1,65 @@
1
+ import * as h3 from "h3";
2
+ import { beforeEach, describe, expect, it, vi } from "vitest";
3
+ import { createFetchEvent, getFetchEvent, mergeResponseHeaders, } from "./fetchEvent.js";
4
+ vi.mock(import("h3"), async (mod) => {
5
+ return {
6
+ ...(await mod()),
7
+ getRequestIP: vi.fn(),
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;
16
+ };
17
+ describe("fetchEvent", () => {
18
+ let mockH3Event;
19
+ beforeEach(() => {
20
+ mockH3Event = createMockH3Event();
21
+ vi.clearAllMocks();
22
+ mockedH3.getRequestIP.mockReturnValue("127.0.0.1");
23
+ });
24
+ describe("createFetchEvent", () => {
25
+ it("should create a FetchEvent from H3Event", () => {
26
+ const fetchEvent = createFetchEvent(mockH3Event);
27
+ expect(fetchEvent).toEqual({
28
+ request: mockH3Event.req,
29
+ response: expect.any(Object),
30
+ clientAddress: "127.0.0.1",
31
+ locals: {},
32
+ nativeEvent: mockH3Event,
33
+ });
34
+ });
35
+ it("should create response stub with correct properties", () => {
36
+ const fetchEvent = createFetchEvent(mockH3Event);
37
+ expect(fetchEvent.response).toHaveProperty("status");
38
+ expect(fetchEvent.response).toHaveProperty("statusText");
39
+ expect(fetchEvent.response).toHaveProperty("headers");
40
+ });
41
+ });
42
+ describe("getFetchEvent", () => {
43
+ it("should create and cache FetchEvent on first call", () => {
44
+ const fetchEvent = getFetchEvent(mockH3Event);
45
+ expect(mockH3Event.context.solidFetchEvent).toBe(fetchEvent);
46
+ expect(fetchEvent.nativeEvent).toBe(mockH3Event);
47
+ });
48
+ it("should return cached FetchEvent on subsequent calls", () => {
49
+ const firstCall = getFetchEvent(mockH3Event);
50
+ const secondCall = getFetchEvent(mockH3Event);
51
+ expect(firstCall).toBe(secondCall);
52
+ });
53
+ });
54
+ describe("mergeResponseHeaders", () => {
55
+ it("should merge headers from Headers object to H3Event", () => {
56
+ const headers = new Headers({
57
+ "content-type": "application/json",
58
+ "x-custom": "value",
59
+ });
60
+ mergeResponseHeaders(mockH3Event, headers);
61
+ expect(headers.get("content-type")).toBe("application/json");
62
+ expect(headers.get("x-custom")).toBe("value");
63
+ });
64
+ });
65
+ });
@@ -1,12 +1,6 @@
1
- import type { FetchEvent, HandlerOptions, PageEvent, ResponseStub } from "./types";
2
- /**
3
- * Checks if user has set a redirect status in the response.
4
- * If not, falls back to the 302 (temporary redirect)
5
- */
6
- export declare function getExpectedRedirectStatus(response: ResponseStub): number;
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>;
@@ -1,106 +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 { provideRequestEvent } from "solid-js/web/storage";
4
- import { eventHandler, sendRedirect, setHeader, setResponseStatus } from "vinxi/http";
5
- import { matchAPIRoute } from "../router/routes";
6
- import { getFetchEvent } from "./fetchEvent";
7
- import { createPageEvent } from "./pageEvent";
8
- // according to https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#redirection_messages
9
- const validRedirectStatuses = new Set([301, 302, 303, 307, 308]);
10
- /**
11
- * Checks if user has set a redirect status in the response.
12
- * If not, falls back to the 302 (temporary redirect)
13
- */
14
- export function getExpectedRedirectStatus(response) {
15
- if (response.status && validRedirectStatuses.has(response.status)) {
16
- return response.status;
17
- }
18
- return 302;
19
- }
20
- export function createBaseHandler(fn, createPageEvent, options = {}, routerLoad) {
21
- return eventHandler({
22
- handler: (e) => {
23
- const event = getFetchEvent(e);
24
- return provideRequestEvent(event, async () => {
25
- if (routerLoad) {
26
- await routerLoad(event);
27
- }
28
- // api
29
- const match = matchAPIRoute(new URL(event.request.url).pathname, event.request.method);
30
- if (match) {
31
- const mod = await match.handler.import();
32
- const fn = event.request.method === "HEAD" ? mod["HEAD"] || mod["GET"] : mod[event.request.method];
33
- event.params = match.params || {};
34
- // @ts-ignore
35
- sharedConfig.context = { event };
36
- const res = await fn(event);
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
- }
43
- // render
44
- const context = await createPageEvent(event);
45
- const resolvedOptions = typeof options == "function" ? await options(context) : { ...options };
46
- const mode = resolvedOptions.mode || "stream";
47
- // @ts-ignore
48
- if (resolvedOptions.nonce)
49
- context.nonce = resolvedOptions.nonce;
50
- if (mode === "sync" || !import.meta.env.START_SSR) {
51
- const html = renderToString(() => {
52
- sharedConfig.context.event = context;
53
- return fn(context);
54
- }, resolvedOptions);
55
- context.complete = true;
56
- if (context.response && context.response.headers.get("Location")) {
57
- const status = getExpectedRedirectStatus(context.response);
58
- return sendRedirect(e, context.response.headers.get("Location"), status);
59
- }
60
- 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;
61
43
  }
62
- if (resolvedOptions.onCompleteAll) {
63
- const og = resolvedOptions.onCompleteAll;
64
- resolvedOptions.onCompleteAll = options => {
65
- handleStreamCompleteRedirect(context)(options);
66
- og(options);
67
- };
44
+ if (event.request.method !== "GET") {
45
+ throw new Error(`API handler for ${event.request.method} "${event.request.url}" did not return a response.`);
68
46
  }
69
- else
70
- resolvedOptions.onCompleteAll = handleStreamCompleteRedirect(context);
71
- if (resolvedOptions.onCompleteShell) {
72
- const og = resolvedOptions.onCompleteShell;
73
- resolvedOptions.onCompleteShell = options => {
74
- handleShellCompleteRedirect(context, e)();
75
- og(options);
76
- };
77
- }
78
- else
79
- resolvedOptions.onCompleteShell = handleShellCompleteRedirect(context, e);
80
- 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(() => {
81
57
  sharedConfig.context.event = context;
82
58
  return fn(context);
83
- }, resolvedOptions);
59
+ });
60
+ context.complete = true;
84
61
  if (context.response && context.response.headers.get("Location")) {
85
62
  const status = getExpectedRedirectStatus(context.response);
86
- return sendRedirect(e, context.response.headers.get("Location"), status);
63
+ return redirect(context.response.headers.get("Location"), status);
87
64
  }
88
- if (mode === "async")
89
- return stream;
90
- // fix cloudflare streaming
91
- const { writable, readable } = new TransformStream();
92
- stream.pipeTo(writable);
93
- return readable;
94
- });
95
- }
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
+ }),
96
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
+ }
97
173
  }
98
174
  function handleShellCompleteRedirect(context, e) {
99
175
  return () => {
100
176
  if (context.response && context.response.headers.get("Location")) {
101
177
  const status = getExpectedRedirectStatus(context.response);
102
- setResponseStatus(e, status);
103
- setHeader(e, "Location", context.response.headers.get("Location"));
178
+ e.res.status = status;
179
+ e.res.headers.set("Location", context.response.headers.get("Location"));
104
180
  }
105
181
  };
106
182
  }
@@ -111,10 +187,19 @@ function handleStreamCompleteRedirect(context) {
111
187
  to && write(`<script>window.location="${to}"</script>`);
112
188
  };
113
189
  }
114
- /**
115
- *
116
- * Read more: https://docs.solidjs.com/solid-start/reference/server/create-handler
117
- */
118
- export function createHandler(fn, options, routerLoad) {
119
- return createBaseHandler(fn, createPageEvent, options, routerLoad);
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;
120
205
  }
@@ -1,6 +1,8 @@
1
- export { createHandler } from "./handler";
2
- export { StartServer } from "./StartServer";
3
- export type { APIEvent, APIHandler, Asset, ContextMatches, DocumentComponentProps, FetchEvent, HandlerOptions, PageEvent, ResponseStub, ServerFunctionMeta } from "./types";
4
- import { getServerFunctionMeta as getServerFunctionMeta_ } from "../shared/serverFunction";
5
- /** @deprecated */
6
- export declare const getServerFunctionMeta: typeof getServerFunctionMeta_;
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
+ */
@@ -1,6 +1,14 @@
1
- // @refresh skip
2
- export { createHandler } from "./handler";
3
- export { StartServer } from "./StartServer";
4
- import { getServerFunctionMeta as getServerFunctionMeta_ } from "../shared/serverFunction";
5
- /** @deprecated */
6
- export const getServerFunctionMeta = getServerFunctionMeta_;
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 };
@@ -0,0 +1,4 @@
1
+ export declare function getClientDevManifest(): {
2
+ import(id: string): Promise<any>;
3
+ getAssets(id: string): Promise<any[]>;
4
+ };
@@ -0,0 +1,24 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ import { join } from "pathe";
10
+ export function getClientDevManifest() {
11
+ return {
12
+ import(id) {
13
+ return import(__rewriteRelativeImportExtension(/* @vite-ignore */ join("/", id), true));
14
+ },
15
+ async getAssets(id) {
16
+ const assetsPath = `/@manifest/client/${Date.now()}/assets?id=${id}`;
17
+ const assets = (await import(__rewriteRelativeImportExtension(/* @vite-ignore */ assetsPath, true))).default;
18
+ return await Promise.all(assets.map(async (v) => ({
19
+ ...v,
20
+ children: await v.children()
21
+ })));
22
+ },
23
+ };
24
+ }
@@ -0,0 +1,5 @@
1
+ export declare function getSsrDevManifest(environment: "client" | "ssr"): {
2
+ path: (id: string) => string;
3
+ getAssets(id: string): Promise<any[]>;
4
+ };
5
+ export { getSsrDevManifest as getSsrManifest };
@@ -0,0 +1,23 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ import { join, normalize } from "pathe";
10
+ export function getSsrDevManifest(environment) {
11
+ return {
12
+ path: (id) => normalize(join(import.meta.env.BASE_URL, id)),
13
+ async getAssets(id) {
14
+ const assetsPath = `/@manifest/${environment}/${Date.now()}/assets?id=${id}`;
15
+ const assets = (await import(__rewriteRelativeImportExtension(/* @vite-ignore */ assetsPath, true))).default;
16
+ return await Promise.all(assets.map(async (v) => ({
17
+ ...v,
18
+ children: await v.children()
19
+ })));
20
+ },
21
+ };
22
+ }
23
+ export { getSsrDevManifest as getSsrManifest };
@@ -0,0 +1,5 @@
1
+ export declare function getClientProdManifest(): {
2
+ import(id: string): Promise<any>;
3
+ getAssets(id: string): Promise<any>;
4
+ json(): Promise<any>;
5
+ };
@@ -0,0 +1,26 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ export function getClientProdManifest() {
10
+ return {
11
+ import(id) {
12
+ // @ts-ignore
13
+ return import(__rewriteRelativeImportExtension(/* @vite-ignore */ window.manifest[id].output, true));
14
+ },
15
+ async getAssets(id) {
16
+ if (id.startsWith("./"))
17
+ id = id.slice(2);
18
+ // @ts-ignore
19
+ return window.manifest[id]?.assets ?? [];
20
+ },
21
+ async json() {
22
+ // @ts-ignore
23
+ return window.manifest;
24
+ },
25
+ };
26
+ }
@@ -0,0 +1,6 @@
1
+ import type { Asset } from "../assets/render.tsx";
2
+ export declare function getSsrProdManifest(): {
3
+ path(id: string): string;
4
+ getAssets(id: string): Promise<Asset[]>;
5
+ json(): Promise<Record<string, any>>;
6
+ };
@@ -0,0 +1,90 @@
1
+ import { clientViteManifest } from "solid-start:client-vite-manifest";
2
+ import { join } from "pathe";
3
+ // Only reads from client manifest atm, might need server support for islands
4
+ export function getSsrProdManifest() {
5
+ const viteManifest = clientViteManifest;
6
+ return {
7
+ path(id) {
8
+ if (id.startsWith("./"))
9
+ id = id.slice(2);
10
+ const viteManifestEntry = clientViteManifest[id /*import.meta.env.START_CLIENT_ENTRY*/];
11
+ if (!viteManifestEntry)
12
+ throw new Error(`No entry found in vite manifest for '${id}'`);
13
+ return join("/", viteManifestEntry.file);
14
+ },
15
+ async getAssets(id) {
16
+ if (id.startsWith("./"))
17
+ id = id.slice(2);
18
+ return createHtmlTagsForAssets(findAssetsInViteManifest(clientViteManifest, id));
19
+ },
20
+ async json() {
21
+ const json = {};
22
+ const entryKeys = Object.keys(viteManifest)
23
+ .filter((id) => viteManifest[id]?.isEntry || viteManifest[id]?.isDynamicEntry)
24
+ .map((id) => id);
25
+ for (const entryKey of entryKeys) {
26
+ json[entryKey] = {
27
+ output: join("/", viteManifest[entryKey].file),
28
+ assets: await this.getAssets(entryKey),
29
+ };
30
+ }
31
+ return json;
32
+ },
33
+ };
34
+ }
35
+ function createHtmlTagsForAssets(assets) {
36
+ return assets
37
+ .filter((asset) => asset.endsWith(".css") ||
38
+ asset.endsWith(".js") ||
39
+ asset.endsWith(".ts") ||
40
+ asset.endsWith(".mjs"))
41
+ .map((asset) => ({
42
+ tag: "link",
43
+ attrs: {
44
+ href: '/' + asset,
45
+ key: asset,
46
+ ...(asset.endsWith(".css")
47
+ ? { rel: "stylesheet" }
48
+ : { rel: "modulepreload" }),
49
+ },
50
+ }));
51
+ }
52
+ const entryId = import.meta.env.START_CLIENT_ENTRY.slice(2);
53
+ let entryImports = undefined;
54
+ function findAssetsInViteManifest(manifest, id, assetMap = new Map(), stack = []) {
55
+ if (stack.includes(id)) {
56
+ return [];
57
+ }
58
+ const cached = assetMap.get(id);
59
+ if (cached) {
60
+ return cached;
61
+ }
62
+ const chunk = manifest[id];
63
+ if (!chunk) {
64
+ return [];
65
+ }
66
+ if (!entryImports) {
67
+ entryImports = [
68
+ entryId,
69
+ ...(manifest[entryId]?.imports ?? [])
70
+ ];
71
+ }
72
+ // Only include entry imports, if we are specifically crawling the entry
73
+ // Chunks (e.g. routes) that import something from entry, should not render entry css redundantly
74
+ const excludeEntryImports = id !== entryId;
75
+ const assets = chunk.css?.filter(Boolean) || [];
76
+ if (chunk.imports) {
77
+ stack.push(id);
78
+ for (let i = 0, l = chunk.imports.length; i < l; i++) {
79
+ const importId = chunk.imports[i];
80
+ if (!importId || (excludeEntryImports && entryImports.includes(importId)))
81
+ continue;
82
+ assets.push(...findAssetsInViteManifest(manifest, importId, assetMap, stack));
83
+ }
84
+ stack.pop();
85
+ }
86
+ assets.push(chunk.file);
87
+ const all = Array.from(new Set(assets));
88
+ assetMap.set(id, all);
89
+ return all;
90
+ }
@@ -0,0 +1,4 @@
1
+ import { getSsrDevManifest } from "./dev-ssr-manifest.ts";
2
+ import { getSsrProdManifest } from "./prod-ssr-manifest.ts";
3
+ export declare function getSsrManifest(target: "client" | "ssr"): ReturnType<typeof getSsrDevManifest> | ReturnType<typeof getSsrProdManifest>;
4
+ export { getSsrManifest as getManifest };
@@ -0,0 +1,6 @@
1
+ import { getSsrDevManifest } from "./dev-ssr-manifest.js";
2
+ import { getSsrProdManifest } from "./prod-ssr-manifest.js";
3
+ export function getSsrManifest(target) {
4
+ return import.meta.env.DEV ? getSsrDevManifest(target) : getSsrProdManifest();
5
+ }
6
+ export { getSsrManifest as getManifest };