@solidjs/start 0.4.7 → 0.4.8

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/entry/index.ts ADDED
@@ -0,0 +1,106 @@
1
+ import { sharedConfig } from "solid-js";
2
+ import { renderToStream } from "solid-js/web";
3
+ /* @ts-ignore */
4
+ import { provideRequestEvent } from "solid-js/web/storage";
5
+ import {
6
+ EventHandlerObject,
7
+ EventHandlerRequest,
8
+ H3Event,
9
+ HTTPMethod,
10
+ eventHandler,
11
+ sendRedirect,
12
+ setHeader,
13
+ setResponseStatus
14
+ } from "vinxi/server";
15
+ import { getFetchEvent } from "../server/middleware";
16
+ import { createPageEvent } from "../server/page-event";
17
+ import { APIEvent, FetchEvent, PageEvent } from "../server/types";
18
+ import { matchAPIRoute } from "../shared/routes";
19
+
20
+ export function createBaseHandler(
21
+ fn: (context: PageEvent) => unknown,
22
+ options: {
23
+ nonce?: string;
24
+ renderId?: string;
25
+ timeoutMs?: number;
26
+ onCompleteAll?: (options: { write: (v: any) => void }) => void;
27
+ onCompleteShell?: (options: { write: (v: any) => void }) => void;
28
+ createPageEvent?: (event: FetchEvent) => Promise<PageEvent>;
29
+ onRequest?: EventHandlerObject["onRequest"];
30
+ onBeforeResponse?: EventHandlerObject["onBeforeResponse"];
31
+ } = {}
32
+ ) {
33
+ return eventHandler({
34
+ onRequest: options.onRequest,
35
+ onBeforeResponse: options.onBeforeResponse,
36
+ handler: (e: H3Event<EventHandlerRequest> & { startEvent: FetchEvent }) => {
37
+ const event = getFetchEvent(e);
38
+
39
+ return provideRequestEvent(event, async () => {
40
+ // api
41
+ const match = matchAPIRoute(new URL(event.request.url).pathname, event.request.method as HTTPMethod)
42
+ if (match) {
43
+ const mod = await match.handler.import();
44
+ const fn = mod[event.request.method];
45
+ (event as APIEvent).params = match.params;
46
+ sharedConfig.context = { event } as any;
47
+ return await fn(event);
48
+ }
49
+
50
+ // render stream
51
+ const doAsync = import.meta.env.START_SSR === "async";
52
+ const context = await createPageEvent(event);
53
+ let cloned = { ...options };
54
+ if (cloned.onCompleteAll) {
55
+ const og = cloned.onCompleteAll;
56
+ cloned.onCompleteAll = options => {
57
+ handleStreamCompleteRedirect(context)(options);
58
+ og(options);
59
+ };
60
+ } else cloned.onCompleteAll = handleStreamCompleteRedirect(context);
61
+ if (cloned.onCompleteShell) {
62
+ const og = cloned.onCompleteShell;
63
+ cloned.onCompleteShell = options => {
64
+ handleShellCompleteRedirect(context, e)();
65
+ og(options);
66
+ };
67
+ } else cloned.onCompleteShell = handleShellCompleteRedirect(context, e);
68
+ const stream = renderToStream(() => {
69
+ (sharedConfig.context as any).event = context;
70
+ return fn(context)
71
+ }, cloned);
72
+ if (context.response && context.response.headers.get("Location")) {
73
+ return sendRedirect(event, context.response.headers.get("Location"));
74
+ }
75
+ if (doAsync) return stream;
76
+ // fix cloudflare streaming
77
+ const { writable, readable } = new TransformStream();
78
+ stream.pipeTo(writable);
79
+ return readable;
80
+ });
81
+ }
82
+ });
83
+ }
84
+
85
+ function handleShellCompleteRedirect(context: PageEvent, e: H3Event<EventHandlerRequest>) {
86
+ return () => {
87
+ if (context.response && context.response.headers.get("Location")) {
88
+ setResponseStatus(e, 302);
89
+ setHeader(e, "Location", context.response.headers.get("Location"));
90
+ }
91
+ }
92
+ }
93
+
94
+ function handleStreamCompleteRedirect(context: PageEvent) {
95
+ return ({ write }: { write: (html: string) => void }) => {
96
+ const to = context.response && context.response.headers.get("Location");
97
+ to && write(`<script>window.location="${to}"</script>`);
98
+ };
99
+ }
100
+
101
+ export function createHandler(
102
+ fn: (context: PageEvent) => unknown,
103
+ options: Parameters<typeof createBaseHandler>[1] = {}
104
+ ) {
105
+ return createBaseHandler(fn, { ...options, createPageEvent });
106
+ }
@@ -0,0 +1,24 @@
1
+ import { createBaseHandler } from "..";
2
+ import { FetchEvent, PageEvent } from "../../server/types";
3
+
4
+ export function createHandler(
5
+ fn: (context: PageEvent) => unknown,
6
+ options?: { nonce?: string; renderId?: string; timeoutMs?: number }
7
+ ) {
8
+ return createBaseHandler(fn, { ...options, createPageEvent });
9
+ }
10
+
11
+ export async function createPageEvent(ctx: FetchEvent) {
12
+ const clientManifest = import.meta.env.MANIFEST["client"];
13
+ const pageEvent: PageEvent = Object.assign(ctx, {
14
+ manifest: await clientManifest.json(),
15
+ assets: [...(await clientManifest.inputs[clientManifest.handler].assets())],
16
+ routes: [],
17
+ // prevUrl: "",
18
+ // mutation: false,
19
+ // $type: FETCH_EVENT,
20
+ $islands: new Set<string>()
21
+ });
22
+
23
+ return pageEvent;
24
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidjs/start",
3
- "version": "0.4.7",
3
+ "version": "0.4.8",
4
4
  "type": "module",
5
5
  "author": "Ryan Carniato",
6
6
  "publishConfig": {
@@ -9,6 +9,7 @@
9
9
  "files": [
10
10
  "client",
11
11
  "config",
12
+ "entry",
12
13
  "server",
13
14
  "shared",
14
15
  "*.d.ts"
package/shared/routes.ts CHANGED
@@ -33,7 +33,7 @@ export const pageRoutes = defineRoutes((fileRoutes as unknown as Route[]).filter
33
33
  const apiRoutes = defineAPIRoutes((fileRoutes as unknown as Route[]).filter(o => o.type === "api"));
34
34
 
35
35
  export function matchAPIRoute(path: string, method: HTTPMethod) {
36
- const segments = path.split("/").filter(Boolean);
36
+ const segments = path.replace(import.meta.env.SERVER_BASE_URL, "").split("/").filter(Boolean);
37
37
 
38
38
  routeLoop: for (const route of apiRoutes) {
39
39
  const matchSegments = route.matchSegments;