@solidjs/start 0.5.5 → 0.5.6

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.
@@ -1,9 +1,10 @@
1
1
  // @ts-ignore
2
2
  import App from "#start/app";
3
+ import type { JSX } from "solid-js";
3
4
  import { ErrorBoundary } from "../shared/ErrorBoundary";
4
5
  import "./mount";
5
6
 
6
- function Dummy(props) {
7
+ function Dummy(props: { children: JSX.Element }) {
7
8
  return props.children;
8
9
  }
9
10
 
package/client/mount.ts CHANGED
@@ -1,7 +1,8 @@
1
+ import type { JSX } from "solid-js";
1
2
  import { createStore } from "solid-js/store";
2
- import { createComponent, getHydrationKey, getOwner, hydrate } from "solid-js/web";
3
+ import { createComponent, getHydrationKey, getOwner, hydrate, type MountableElement } from "solid-js/web";
3
4
 
4
- export function mount(fn, el) {
5
+ export function mount(fn: () => JSX.Element, el: MountableElement) {
5
6
  if (import.meta.env.START_ISLANDS) {
6
7
  const map = new WeakMap();
7
8
  async function mountIsland(el: HTMLElement) {
@@ -19,11 +20,11 @@ export function mount(fn, el) {
19
20
 
20
21
  let mod = await import(
21
22
  /* @vite-ignore */
22
- import.meta.env.MANIFEST["client"].chunks[el.dataset.id.split("#")[0]].output.path
23
+ import.meta.env.MANIFEST["client"]!.chunks[el.dataset.id!.split("#")[0] as string]!.output.path
23
24
  );
24
25
  if (!mod || !el.dataset.hk) return;
25
26
 
26
- let Component = mod[el.dataset.id.split("#")[1]];
27
+ let Component = mod[el.dataset.id!.split("#")[1] as string];
27
28
  let hk = el.dataset.hk;
28
29
  // _$DEBUG("hydrating island", el.dataset.island, hk.slice(0, hk.length - 1) + `1-`, el);
29
30
 
@@ -68,7 +69,7 @@ export function mount(fn, el) {
68
69
  Promise.all(
69
70
  [...assets].map(
70
71
  asset =>
71
- import(/* @vite-ignore */import.meta.env.MANIFEST["client"].chunks[asset.split("#")[0]].output.path)
72
+ import(/* @vite-ignore */import.meta.env.MANIFEST["client"]!.chunks[asset.split("#")[0] as string]!.output.path)
72
73
  )
73
74
  )
74
75
  .then(() => {
@@ -1,7 +1,8 @@
1
- import { render } from "solid-js/web";
1
+ import type { JSX } from "solid-js";
2
+ import { render, type MountableElement } from "solid-js/web";
2
3
  import "vinxi/client";
3
4
 
4
- export function mount(fn, el) {
5
+ export function mount(fn: () => JSX.Element, el: MountableElement) {
5
6
  render(fn, el);
6
7
  }
7
8
 
package/config/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { serverFunctions } from "@vinxi/server-functions/plugin";
2
- import { serverTransform } from "@vinxi/server-functions/server";
2
+ import { server as serverFunctionServer, serverTransform } from "@vinxi/server-functions/server";
3
3
  import defu from "defu";
4
4
  import { existsSync } from "node:fs";
5
5
  import { join } from "node:path";
@@ -8,10 +8,7 @@ import { createApp, resolve } from "vinxi";
8
8
  import { normalize } from "vinxi/lib/path";
9
9
  import { config } from "vinxi/plugins/config";
10
10
  import solid from "vite-plugin-solid";
11
- import {
12
- SolidStartClientFileRouter,
13
- SolidStartServerFileRouter
14
- } from "./fs-router.js";
11
+ import { SolidStartClientFileRouter, SolidStartServerFileRouter } from "./fs-router.js";
15
12
  import { serverComponents } from "./server-components.js";
16
13
 
17
14
  const DEFAULT_EXTENSIONS = ["js", "jsx", "ts", "tsx"];
@@ -120,6 +117,7 @@ export function defineConfig(baseConfig = {}) {
120
117
  ...userConfig.resolve?.alias
121
118
  }
122
119
  },
120
+ cacheDir: "node_modules/.vinxi/server",
123
121
  define: {
124
122
  "import.meta.env.START_ISLANDS": JSON.stringify(start.islands),
125
123
  "import.meta.env.SSR": JSON.stringify(true),
@@ -176,6 +174,7 @@ export function defineConfig(baseConfig = {}) {
176
174
  ...userConfig.resolve?.alias
177
175
  }
178
176
  },
177
+ cacheDir: "node_modules/.vinxi/client",
179
178
  define: {
180
179
  "import.meta.env.START_ISLANDS": JSON.stringify(start.islands),
181
180
  "import.meta.env.SSR": JSON.stringify(false),
@@ -187,9 +186,13 @@ export function defineConfig(baseConfig = {}) {
187
186
  ],
188
187
  base: "/_build"
189
188
  },
190
- serverFunctions.router({
189
+
190
+ {
191
+ name: "server-fns",
192
+ type: "http",
193
+ base: "/_server",
191
194
  handler: normalize(fileURLToPath(new URL("./server-handler.ts", import.meta.url))),
192
- runtime: normalize(fileURLToPath(new URL("./server-fns-runtime.ts", import.meta.url))),
195
+ target: "server",
193
196
  routes: solidStartServerFsRouter({ dir: `${start.appRoot}/routes`, extensions }),
194
197
  plugins: async () => [
195
198
  config("user", {
@@ -201,10 +204,13 @@ export function defineConfig(baseConfig = {}) {
201
204
  "@solidjs/start > source-map-js",
202
205
  "@solidjs/start > error-stack-parser"
203
206
  ]
204
- }
207
+ },
208
+ cacheDir: "node_modules/.vinxi/server-fns"
205
209
  }),
206
210
  ...(typeof plugins === "function" ? [...(await plugins())] : plugins),
207
-
211
+ serverFunctionServer({
212
+ runtime: normalize(fileURLToPath(new URL("./server-fns-runtime.ts", import.meta.url)))
213
+ }),
208
214
  solid({ ...start.solid, ssr: true, extensions: extensions.map(ext => `.${ext}`) }),
209
215
  config("app-server", {
210
216
  resolve: {
@@ -228,7 +234,7 @@ export function defineConfig(baseConfig = {}) {
228
234
  })
229
235
  ],
230
236
  middleware: start.middleware
231
- })
237
+ }
232
238
  ]
233
239
  });
234
240
  }
@@ -2,7 +2,7 @@ import { getRequestEvent } from "solid-js/web";
2
2
  import { provideRequestEvent } from "solid-js/web/storage";
3
3
  import { cloneEvent } from "../server/fetchEvent";
4
4
 
5
- export function createServerReference(fn, id, name) {
5
+ export function createServerReference(fn: Function, id: string, name: string) {
6
6
  if (typeof fn !== "function") throw new Error("Export from a 'use server' module must be a function");
7
7
  const baseURL = import.meta.env.SERVER_BASE_URL;
8
8
  return new Proxy(fn, {
@@ -14,9 +14,9 @@ import {
14
14
  URLSearchParamsPlugin
15
15
  } from "seroval-plugins/web";
16
16
  import { sharedConfig } from "solid-js";
17
- import { renderToStringAsync } from "solid-js/web";
17
+ import { renderToStream } from "solid-js/web";
18
18
  import { provideRequestEvent } from "solid-js/web/storage";
19
- import { eventHandler, setHeader, setResponseStatus } from "vinxi/http";
19
+ import { eventHandler, setHeader, setResponseStatus, type H3Event } from "vinxi/http";
20
20
  import invariant from "vinxi/lib/invariant";
21
21
  import { cloneEvent, getFetchEvent, mergeResponseHeaders } from "../server/fetchEvent";
22
22
  import { createPageEvent } from "../server/pageEvent";
@@ -24,14 +24,14 @@ import { createPageEvent } from "../server/pageEvent";
24
24
  import App from "#start/app";
25
25
  import { FetchEvent, PageEvent } from "../server";
26
26
 
27
- function createChunk(data) {
27
+ function createChunk(data: string) {
28
28
  const bytes = data.length;
29
29
  const baseHex = bytes.toString(16);
30
30
  const totalHex = "00000000".substring(0, 8 - baseHex.length) + baseHex; // 32-bit
31
31
  return new TextEncoder().encode(`;0x${totalHex};${data}`);
32
32
  }
33
33
 
34
- function serializeToStream(id, value) {
34
+ function serializeToStream(id: string, value: any) {
35
35
  return new ReadableStream({
36
36
  start(controller) {
37
37
  crossSerializeStream(value, {
@@ -64,7 +64,7 @@ function serializeToStream(id, value) {
64
64
  });
65
65
  }
66
66
 
67
- async function handleServerFunction(h3Event) {
67
+ async function handleServerFunction(h3Event: H3Event) {
68
68
  const event = getFetchEvent(h3Event);
69
69
  const request = event.request;
70
70
 
@@ -83,32 +83,32 @@ async function handleServerFunction(h3Event) {
83
83
  }
84
84
 
85
85
  const serverFunction = (
86
- await import.meta.env.MANIFEST[import.meta.env.ROUTER_NAME].chunks[filepath].import()
87
- )[name];
88
- let parsed = [];
86
+ await import.meta.env.MANIFEST[import.meta.env.ROUTER_NAME]!.chunks[filepath!]!.import()
87
+ )[name!];
88
+ let parsed: any[] = [];
89
89
 
90
90
  // grab bound arguments from url when no JS
91
91
  if (!instance || h3Event.method === "GET") {
92
92
  const args = url.searchParams.get("args");
93
- if (args) JSON.parse(args).forEach(arg => parsed.push(arg));
93
+ if (args) JSON.parse(args).forEach((arg: any) => parsed.push(arg));
94
94
  }
95
95
  if (h3Event.method === "POST") {
96
96
  const contentType = request.headers.get("content-type");
97
97
  if (
98
- contentType.startsWith("multipart/form-data") ||
99
- contentType.startsWith("application/x-www-form-urlencoded")
98
+ contentType?.startsWith("multipart/form-data") ||
99
+ contentType?.startsWith("application/x-www-form-urlencoded")
100
100
  ) {
101
101
  // workaround for https://github.com/unjs/nitro/issues/1721
102
102
  // (issue only in edge runtimes)
103
103
  parsed.push(
104
- await new Request(request, { ...request, body: h3Event.node.req.body }).formData()
104
+ await new Request(request, { ...request, body: (h3Event.node.req as any).body }).formData()
105
105
  );
106
106
  // what should work when #1721 is fixed
107
107
  // parsed.push(await request.formData);
108
108
  } else {
109
109
  // workaround for https://github.com/unjs/nitro/issues/1721
110
110
  // (issue only in edge runtimes)
111
- const tmpReq = new Request(request, { ...request, body: h3Event.node.req.body });
111
+ const tmpReq = new Request(request, { ...request, body: (h3Event.node.req as any).body });
112
112
  // what should work when #1721 is fixed
113
113
  // just use request.json() here
114
114
  parsed = fromJSON(await tmpReq.json(), {
@@ -150,7 +150,7 @@ async function handleServerFunction(h3Event) {
150
150
  // handle no JS success case
151
151
  if (!instance) {
152
152
  const isError = result instanceof Error;
153
- const refererUrl = new URL(request.headers.get("referer"));
153
+ const refererUrl = new URL(request.headers.get("referer")!);
154
154
  return new Response(null, {
155
155
  status: 302,
156
156
  headers: {
@@ -184,14 +184,14 @@ async function handleServerFunction(h3Event) {
184
184
  }
185
185
 
186
186
  async function handleSingleFlight(sourceEvent: FetchEvent, result: any) {
187
- let revalidate;
188
- let url = new URL(sourceEvent.request.headers.get("referer")).toString();
187
+ let revalidate: string[];
188
+ let url = new URL(sourceEvent.request.headers.get("referer")!).toString();
189
189
  if (result instanceof Response) {
190
190
  if (result.headers.has("X-Revalidate"))
191
- revalidate = result.headers.get("X-Revalidate").split(",");
191
+ revalidate = result.headers.get("X-Revalidate")!.split(",");
192
192
  if (result.headers.has("Location"))
193
193
  url = new URL(
194
- result.headers.get("Location"),
194
+ result.headers.get("Location")!,
195
195
  new URL(sourceEvent.request.url).origin + import.meta.env.SERVER_BASE_URL
196
196
  ).toString();
197
197
  }
@@ -205,9 +205,9 @@ async function handleSingleFlight(sourceEvent: FetchEvent, result: any) {
205
205
  event.router.previousUrl = sourceEvent.request.headers.get("referer");
206
206
  (async () => {
207
207
  try {
208
- await renderToStringAsync(() => {
208
+ await renderToStream(() => {
209
209
  /* @ts-ignore */
210
- sharedConfig.context = { event };
210
+ sharedConfig.context.event = event;
211
211
  App();
212
212
  });
213
213
  } catch (e) {
@@ -11,13 +11,14 @@ import {
11
11
  URLPlugin,
12
12
  URLSearchParamsPlugin
13
13
  } from "seroval-plugins/web";
14
+ import { type Component } from "solid-js";
14
15
  import { createIslandReference } from "../server/islands";
15
16
 
16
17
  class SerovalChunkReader {
17
18
  reader: ReadableStreamDefaultReader<Uint8Array>;
18
19
  buffer: string;
19
20
  done: boolean;
20
- constructor(stream) {
21
+ constructor(stream: ReadableStream<Uint8Array>) {
21
22
  this.reader = stream.getReader();
22
23
  this.buffer = "";
23
24
  this.done = false;
@@ -34,7 +35,7 @@ class SerovalChunkReader {
34
35
  }
35
36
  }
36
37
 
37
- async next() {
38
+ async next(): Promise<any> {
38
39
  // Check if the buffer is empty
39
40
  if (this.buffer === "") {
40
41
  // if we are already done...
@@ -84,7 +85,7 @@ class SerovalChunkReader {
84
85
  }
85
86
  }
86
87
 
87
- async function deserializeStream(id, response) {
88
+ async function deserializeStream(id: string, response: Response) {
88
89
  if (!response.body) {
89
90
  throw new Error("missing body");
90
91
  }
@@ -184,7 +185,7 @@ async function fetchServerFunction(
184
185
  throw result;
185
186
  }
186
187
 
187
- export function createServerReference(fn, id, name) {
188
+ export function createServerReference(fn: Function, id: string, name: string) {
188
189
  const baseURL = import.meta.env.SERVER_BASE_URL;
189
190
  return new Proxy(fn, {
190
191
  get(target, prop, receiver) {
@@ -196,7 +197,7 @@ export function createServerReference(fn, id, name) {
196
197
  }
197
198
  if (prop === "withOptions") {
198
199
  return (options: RequestInit) => {
199
- const fn = (...args) => {
200
+ const fn = (...args: any[]) => {
200
201
  const encodeArgs = options.method && options.method.toUpperCase() === "GET";
201
202
  return fetchServerFunction(
202
203
  encodeArgs
@@ -218,7 +219,7 @@ export function createServerReference(fn, id, name) {
218
219
  });
219
220
  }
220
221
 
221
- export function createClientReference(Component, id, name) {
222
+ export function createClientReference(Component: Component<any>, id: string, name: string) {
222
223
  if (typeof Component === "function") {
223
224
  return createIslandReference(Component, id, name);
224
225
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidjs/start",
3
- "version": "0.5.5",
3
+ "version": "0.5.6",
4
4
  "type": "module",
5
5
  "author": "Ryan Carniato",
6
6
  "publishConfig": {
@@ -1,6 +1,6 @@
1
1
  // @ts-ignore
2
2
  import App from "#start/app";
3
- import type { Component } from "solid-js";
3
+ import type { Component, JSX } from "solid-js";
4
4
  import {
5
5
  Hydration,
6
6
  HydrationScript,
@@ -11,15 +11,15 @@ import {
11
11
  } from "solid-js/web";
12
12
  import { ErrorBoundary } from "../shared/ErrorBoundary";
13
13
  import { renderAsset } from "./renderAsset";
14
- import type { DocumentComponentProps } from "./types";
14
+ import type { Asset, DocumentComponentProps, PageEvent } from "./types";
15
15
 
16
16
  const docType = ssr("<!DOCTYPE html>");
17
17
 
18
- function matchRoute(matches, routes, matched = []) {
18
+ function matchRoute(matches: any[], routes: any[], matched = []): any[] | undefined {
19
19
  for (let i = 0; i < routes.length; i++) {
20
20
  const segment = routes[i];
21
21
  if (segment.path !== matches[0].path) continue;
22
- let next = [...matched, segment];
22
+ let next: any = [...matched, segment];
23
23
  if (segment.children) {
24
24
  const nextMatches = matches.slice(1);
25
25
  if (nextMatches.length === 0) continue;
@@ -31,11 +31,13 @@ function matchRoute(matches, routes, matched = []) {
31
31
  }
32
32
 
33
33
  export function StartServer(props: { document: Component<DocumentComponentProps> }) {
34
- const context = getRequestEvent() as any;
34
+ const context = getRequestEvent() as PageEvent;
35
35
 
36
- let assets = [];
36
+ let assets: Asset[] = [];
37
37
  Promise.resolve().then(async () => {
38
+ // @ts-ignore
38
39
  if (context.router && context.router.matches) {
40
+ // @ts-ignore
39
41
  const matches = [...context.router.matches];
40
42
  while (matches.length && (!matches[0].info || !matches[0].info.filesystem))
41
43
  matches.shift();
@@ -43,9 +45,9 @@ export function StartServer(props: { document: Component<DocumentComponentProps>
43
45
  if (matched) {
44
46
  for (let i = 0; i < matched.length; i++) {
45
47
  const segment = matched[i];
46
- const part = import.meta.env.MANIFEST[import.meta.env.START_ISLANDS ? "ssr" : "client"]
47
- .inputs[segment["$component"].src];
48
- const asset = await part.assets();
48
+ const part = import.meta.env.MANIFEST[import.meta.env.START_ISLANDS ? "ssr" : "client"]!
49
+ .inputs[segment["$component"].src]!;
50
+ const asset = await part.assets() as any;
49
51
  assets.push.apply(assets, asset);
50
52
  }
51
53
  } else console.warn("No route matched for preloading js assets");
@@ -54,8 +56,8 @@ export function StartServer(props: { document: Component<DocumentComponentProps>
54
56
  assets = [...new Map(assets.map(item => [item.attrs.key, item])).values()].filter(asset =>
55
57
  import.meta.env.START_ISLANDS
56
58
  ? false
57
- : asset.attrs.rel === "modulepreload" &&
58
- !context.assets.find(a => a.attrs.key === asset.attrs.key)
59
+ : (asset.attrs as JSX.LinkHTMLAttributes<HTMLLinkElement>).rel === "modulepreload" &&
60
+ !context.assets.find((a: Asset) => a.attrs.key === asset.attrs.key)
59
61
  );
60
62
  });
61
63
 
@@ -68,7 +70,7 @@ export function StartServer(props: { document: Component<DocumentComponentProps>
68
70
  assets={
69
71
  <>
70
72
  <HydrationScript />
71
- {context.assets.map(m => renderAsset(m))}
73
+ {context.assets.map((m: any) => renderAsset(m))}
72
74
  </>
73
75
  }
74
76
  scripts={
@@ -78,9 +80,9 @@ export function StartServer(props: { document: Component<DocumentComponentProps>
78
80
  type="module"
79
81
  async
80
82
  src={
81
- import.meta.env.MANIFEST["client"].inputs[
82
- import.meta.env.MANIFEST["client"].handler
83
- ].output.path
83
+ import.meta.env.MANIFEST["client"]!.inputs[
84
+ import.meta.env.MANIFEST["client"]!.handler
85
+ ]!.output.path
84
86
  }
85
87
  />
86
88
  </>
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  H3Event,
3
+ HTTPEvent,
3
4
  HTTPEventSymbol,
4
5
  appendResponseHeader,
5
6
  getRequestIP,
@@ -37,15 +38,15 @@ export function cloneEvent<T extends FetchEvent>(fetchEvent: T): T {
37
38
  }
38
39
 
39
40
  export function getFetchEvent(h3Event: H3Event): FetchEvent {
40
- if (!h3Event[fetchEventSymbol]) {
41
+ if (!(h3Event as any)[fetchEventSymbol]) {
41
42
  const fetchEvent = createFetchEvent(h3Event);
42
- h3Event[fetchEventSymbol] = fetchEvent;
43
+ (h3Event as any)[fetchEventSymbol] = fetchEvent;
43
44
  }
44
45
 
45
- return h3Event[fetchEventSymbol];
46
+ return (h3Event as any)[fetchEventSymbol];
46
47
  }
47
48
 
48
- export function mergeResponseHeaders(h3Event, headers) {
49
+ export function mergeResponseHeaders(h3Event: HTTPEvent, headers: Headers) {
49
50
  for (const [key, value] of headers.entries()) {
50
51
  setHeader(h3Event, key, value);
51
52
  }
package/server/handler.ts CHANGED
@@ -31,7 +31,7 @@ export function createBaseHandler(
31
31
  return eventHandler({
32
32
  onRequest: options.onRequest,
33
33
  onBeforeResponse: options.onBeforeResponse,
34
- handler: (e: H3Event<EventHandlerRequest> & { startEvent: FetchEvent }) => {
34
+ handler: (e: H3Event<EventHandlerRequest>) => {
35
35
  const event = getFetchEvent(e);
36
36
  const mode = import.meta.env.START_SSR;
37
37
 
@@ -41,7 +41,7 @@ export function createBaseHandler(
41
41
  if (match) {
42
42
  const mod = await match.handler.import();
43
43
  const fn = mod[event.request.method];
44
- (event as APIEvent).params = match.params;
44
+ (event as APIEvent).params = match.params || {};
45
45
  // @ts-ignore
46
46
  sharedConfig.context = { event };
47
47
  const res = await fn(event);
@@ -61,7 +61,7 @@ export function createBaseHandler(
61
61
  return fn(context);
62
62
  }, options);
63
63
  if (context.response && context.response.headers.get("Location")) {
64
- return sendRedirect(event, context.response.headers.get("Location"));
64
+ return sendRedirect(event, context.response.headers.get("Location")!);
65
65
  }
66
66
  return html;
67
67
  }
@@ -85,7 +85,7 @@ export function createBaseHandler(
85
85
  return fn(context);
86
86
  }, cloned);
87
87
  if (context.response && context.response.headers.get("Location")) {
88
- return sendRedirect(event, context.response.headers.get("Location"));
88
+ return sendRedirect(event, context.response.headers.get("Location")!);
89
89
  }
90
90
  if (mode === "async") return stream;
91
91
  // fix cloudflare streaming
@@ -101,7 +101,7 @@ function handleShellCompleteRedirect(context: PageEvent, e: H3Event<EventHandler
101
101
  return () => {
102
102
  if (context.response && context.response.headers.get("Location")) {
103
103
  setResponseStatus(e, 302);
104
- setHeader(e, "Location", context.response.headers.get("Location"));
104
+ setHeader(e, "Location", context.response.headers.get("Location")!);
105
105
  }
106
106
  };
107
107
  }
@@ -20,17 +20,17 @@ function initFromFlash(ctx: FetchEvent) {
20
20
  }
21
21
 
22
22
  export async function createPageEvent(ctx: FetchEvent) {
23
- const clientManifest = import.meta.env.MANIFEST["client"];
24
- const serverManifest = import.meta.env.MANIFEST["ssr"];
23
+ const clientManifest = import.meta.env.MANIFEST["client"]!;
24
+ const serverManifest = import.meta.env.MANIFEST["ssr"]!;
25
25
  ctx.response.headers.set("Content-Type", "text/html");
26
26
  // const prevPath = ctx.request.headers.get("x-solid-referrer");
27
27
  // const mutation = ctx.request.headers.get("x-solid-mutation") === "true";
28
28
  const pageEvent: PageEvent = Object.assign(ctx, {
29
29
  manifest: await clientManifest.json(),
30
30
  assets: [
31
- ...(await clientManifest.inputs[clientManifest.handler].assets()),
31
+ ...(await clientManifest.inputs[clientManifest.handler]!.assets()),
32
32
  ...(import.meta.env.START_ISLANDS
33
- ? (await serverManifest.inputs[serverManifest.handler].assets()).filter(
33
+ ? (await serverManifest.inputs[serverManifest.handler]!.assets()).filter(
34
34
  s => (s as any).attrs.rel !== "modulepreload"
35
35
  )
36
36
  : [])
@@ -1,16 +1,21 @@
1
+ import type { JSX } from "solid-js";
2
+ import type { Asset } from "./types";
3
+
1
4
  const assetMap = {
2
- style: (props) => <style {...props.attrs}>{props.children}</style>,
3
- link: (props) => <link {...props.attrs} />,
4
- script: (props) => {
5
- return props.attrs.src ? (
6
- <script {...props.attrs} id={props.key}>
7
- {" "}
8
- </script>
9
- ) : null;
10
- },
5
+ style: (props: { attrs: JSX.StyleHTMLAttributes<HTMLStyleElement>; children?: JSX.Element }) => (
6
+ <style {...props.attrs}>{props.children}</style>
7
+ ),
8
+ link: (props: { attrs: JSX.LinkHTMLAttributes<HTMLLinkElement> }) => <link {...props.attrs} />,
9
+ script: (props: { attrs: JSX.ScriptHTMLAttributes<HTMLScriptElement>; key: string | undefined }) => {
10
+ return props.attrs.src ? (
11
+ <script {...props.attrs} id={props.key}>
12
+ {" "}
13
+ </script>
14
+ ) : null;
15
+ }
11
16
  };
12
17
 
13
- export function renderAsset(asset) {
14
- let { tag, attrs: { key, ...attrs } = { key: undefined }, children } = asset;
15
- return assetMap[tag]({ attrs, key, children });
16
- }
18
+ export function renderAsset(asset: Asset) {
19
+ let { tag, attrs: { key, ...attrs } = { key: undefined }, children } = asset as any;
20
+ return (assetMap as any)[tag]({ attrs, key, children });
21
+ }
@@ -1,18 +1,20 @@
1
1
  // @ts-ignore
2
+ import type { Component } from "solid-js";
2
3
  import { NoHydration, getRequestEvent, ssr } from "solid-js/web";
3
4
  import { renderAsset } from "../renderAsset";
5
+ import type { DocumentComponentProps, PageEvent } from "../types";
4
6
 
5
7
  const docType = ssr("<!DOCTYPE html>");
6
8
 
7
- export function StartServer(props) {
8
- const context = getRequestEvent() as any;
9
+ export function StartServer(props: { document: Component<DocumentComponentProps> }) {
10
+ const context = getRequestEvent() as PageEvent;
9
11
  return (
10
12
  <NoHydration>
11
13
  {docType as unknown as any}
12
14
  <props.document
13
15
  assets={
14
16
  <>
15
- {context.assets.map(m => renderAsset(m))}
17
+ {context.assets.map((m: any) => renderAsset(m))}
16
18
  </>
17
19
  }
18
20
  scripts={
@@ -21,9 +23,9 @@ export function StartServer(props) {
21
23
  <script
22
24
  type="module"
23
25
  src={
24
- import.meta.env.MANIFEST["client"].inputs[
25
- import.meta.env.MANIFEST["client"].handler
26
- ].output.path
26
+ import.meta.env.MANIFEST["client"]!.inputs[
27
+ import.meta.env.MANIFEST["client"]!.handler
28
+ ]!.output.path
27
29
  }
28
30
  />
29
31
  </>
@@ -9,10 +9,10 @@ export function createHandler(
9
9
  }
10
10
 
11
11
  export async function createPageEvent(ctx: FetchEvent) {
12
- const clientManifest = import.meta.env.MANIFEST["client"];
12
+ const clientManifest = import.meta.env.MANIFEST["client"]!;
13
13
  const pageEvent: PageEvent = Object.assign(ctx, {
14
14
  manifest: await clientManifest.json(),
15
- assets: [...(await clientManifest.inputs[clientManifest.handler].assets())],
15
+ assets: [...(await clientManifest.inputs[clientManifest.handler]!.assets())],
16
16
  routes: [],
17
17
  // prevUrl: "",
18
18
  // mutation: false,
package/server/types.ts CHANGED
@@ -1,13 +1,26 @@
1
1
  import type { JSX } from "solid-js";
2
- import { HTTPEventSymbol, type EventHandlerRequest, type H3Event } from "vinxi/http";
2
+ import { RequestEvent } from "solid-js/web";
3
+ import { H3Event, HTTPEventSymbol } from "vinxi/http";
3
4
 
4
5
  // export const FETCH_EVENT = "$FETCH";
5
6
 
6
7
  export type DocumentComponentProps = {
7
8
  assets: JSX.Element;
8
9
  scripts: JSX.Element;
9
- children: JSX.Element;
10
- }
10
+ children?: JSX.Element;
11
+ };
12
+
13
+ export type Asset = {
14
+ tag: "style";
15
+ attrs: JSX.StyleHTMLAttributes<HTMLStyleElement> & { key?: string };
16
+ children?: JSX.Element;
17
+ } | {
18
+ tag: "script";
19
+ attrs: JSX.ScriptHTMLAttributes<HTMLScriptElement> & { key?: string };
20
+ } | {
21
+ tag: "link";
22
+ attrs: JSX.LinkHTMLAttributes<HTMLLinkElement> & { key?: string };
23
+ };
11
24
 
12
25
  export type ContextMatches = {
13
26
  originalPath: string;
@@ -24,15 +37,15 @@ export interface ResponseStub {
24
37
  export interface FetchEvent {
25
38
  request: Request;
26
39
  response: ResponseStub;
27
- clientAddress: string;
40
+ clientAddress?: string;
28
41
  locals: RequestEventLocals;
29
- nativeEvent: H3Event<EventHandlerRequest>;
30
- [HTTPEventSymbol]: H3Event<EventHandlerRequest>;
42
+ nativeEvent: H3Event;
43
+ [HTTPEventSymbol]: H3Event;
31
44
  }
32
45
  export interface RequestEventLocals {
33
46
  [key: string | symbol]: any;
34
47
  }
35
- export interface PageEvent extends FetchEvent {
48
+ export interface PageEvent extends RequestEvent {
36
49
  manifest: any;
37
50
  assets: any;
38
51
  routes: any[];
@@ -2,11 +2,12 @@
2
2
  import { getRequestEvent, isServer } from "solid-js/web";
3
3
  import lazyRoute from "./lazyRoute";
4
4
 
5
+ import type { Route } from "vinxi/fs-router";
5
6
  import type { PageEvent } from "../server/types";
6
7
  import { pageRoutes as routeConfigs } from "./routes";
7
8
 
8
9
  export function createRoutes() {
9
- function createRoute(route) {
10
+ function createRoute(route: Route) {
10
11
  return {
11
12
  ...route,
12
13
  ...(route.$$route ? route.$$route.require().route : undefined),
@@ -28,7 +29,7 @@ export function createRoutes() {
28
29
  return routes;
29
30
  }
30
31
 
31
- let routes;
32
+ let routes: any[];
32
33
  export const FileRoutes = () => {
33
34
  return isServer ? (getRequestEvent() as PageEvent).routes : routes || (routes = createRoutes());
34
35
  };
@@ -1,9 +1,10 @@
1
1
  import { onCleanup } from "solid-js";
2
2
  import { getRequestEvent, isServer } from "solid-js/web";
3
+ import type { PageEvent } from "../server/types";
3
4
 
4
5
  export function HttpHeader(props: { name: string; value: string; append?: boolean }) {
5
6
  if (isServer) {
6
- const event = getRequestEvent();
7
+ const event = getRequestEvent() as PageEvent;
7
8
 
8
9
  if (props.append) event.response.headers.append(props.name, props.value);
9
10
  else event.response.headers.set(props.name, props.value);
@@ -1,9 +1,10 @@
1
1
  import { onCleanup } from "solid-js";
2
2
  import { getRequestEvent, isServer } from "solid-js/web";
3
+ import type { PageEvent } from "../server/types";
3
4
 
4
5
  export function HttpStatusCode(props: { code: number, text?: string }) {
5
6
  if (isServer) {
6
- const event = getRequestEvent();
7
+ const event = getRequestEvent() as PageEvent;
7
8
  event.response.status = props.code;
8
9
  event.response.statusText = props.text;
9
10
  onCleanup(() => !event.nativeEvent.handled && (event.response.status = 200));
@@ -58,7 +58,7 @@ export function CodeView(props: CodeViewProps): JSX.Element | null {
58
58
  ) ,async (value) => {
59
59
  const highlighter = await loadHighlighter();
60
60
  const lang = props.fileName
61
- .split(/[#?]/)[0]
61
+ .split(/[#?]/)[0]!
62
62
  .split('.')
63
63
  .pop()
64
64
  ?.trim() as BuiltinLanguage;
@@ -76,7 +76,7 @@ export function CodeView(props: CodeViewProps): JSX.Element | null {
76
76
  const lines = ref.querySelectorAll('span[class="line"]');
77
77
 
78
78
  for (let i = 0, len = lines.length; i < len; i++) {
79
- const el = lines[i];
79
+ const el = lines[i] as HTMLElement;
80
80
  if ((props.line - minLine() - 1) === i) {
81
81
  el.classList.add('dev-overlay-error-line');
82
82
  }
@@ -6,7 +6,7 @@ import { Portal } from 'solid-js/web';
6
6
  import { Dialog, DialogOverlay, DialogPanel, Select, SelectOption } from 'terracotta';
7
7
  import info from '../../package.json';
8
8
  import { CodeView } from './CodeView';
9
- import { type StackFrameSource, createStackFrame } from './createStackFrame';
9
+ import { createStackFrame, type StackFrameSource } from './createStackFrame';
10
10
  import download from './download';
11
11
  import { ArrowLeftIcon, ArrowRightIcon, CameraIcon, DiscordIcon, GithubIcon, RefreshIcon, SolidStartIcon, ViewCompiledIcon, ViewOriginalIcon } from './icons';
12
12
  import './styles.css';
@@ -21,7 +21,7 @@ interface ErrorInfoProps {
21
21
 
22
22
  function ErrorInfo(props: ErrorInfoProps): JSX.Element {
23
23
  return (
24
- <Show when={props.error instanceof Error && props.error} keyed fallback={<span>{props.error.toString()}</span>}>
24
+ <Show when={props.error instanceof Error && props.error} keyed fallback={<span>{(props.error as Error).toString()}</span>}>
25
25
  {(current) => (
26
26
  <span class="dev-overlay-error-info">
27
27
  <span class="dev-overlay-error-info-name">{current.name}</span>
@@ -41,7 +41,7 @@ function getFileName(source: string): string {
41
41
  try {
42
42
  const path = source.startsWith('/') ? new URL(source, 'file://') : new URL(source);
43
43
  const paths = path.pathname.split('/');
44
- return paths[paths.length - 1];
44
+ return paths[paths.length - 1]!;
45
45
  } catch (error) {
46
46
  return getFileName(`/${source}`);
47
47
  }
@@ -62,7 +62,7 @@ function CodeFallback(): JSX.Element {
62
62
  function StackFramesContent(props: StackFramesContentProps) {
63
63
  const stackframes = ErrorStackParser.parse(props.error);
64
64
 
65
- const [selectedFrame, setSelectedFrame] = createSignal(stackframes[0]);
65
+ const [selectedFrame, setSelectedFrame] = createSignal(stackframes[0]!);
66
66
 
67
67
  return (
68
68
  <div class="dev-overlay-stack-frames-content">
@@ -98,10 +98,10 @@ function StackFramesContent(props: StackFramesContentProps) {
98
98
  <div class="dev-overlay-stack-frame">
99
99
  <span class="dev-overlay-stack-frame-function">{current.functionName ?? '<anonymous>'}</span>
100
100
  <span class="dev-overlay-stack-frame-file">{getFilePath({
101
- source: current.getFileName(),
101
+ source: current.getFileName()!,
102
102
  content: '',
103
- line: current.getLineNumber(),
104
- column: current.getColumnNumber(),
103
+ line: current.getLineNumber()!,
104
+ column: current.getColumnNumber()!,
105
105
  name: current.getFunctionName(),
106
106
  })}</span>
107
107
  </div>
@@ -204,11 +204,11 @@ export default function DevOverlayDialog(props: DevOverlayDialogProps): JSX.Elem
204
204
  url.searchParams.append('labels', 'needs+triage');
205
205
  url.searchParams.append('template', 'bug.yml');
206
206
  url.searchParams.append('title', `[Bug?]:` + props.errors[truncated() - 1].toString());
207
- window.open(url, '_blank').focus();
207
+ window.open(url, '_blank')!.focus();
208
208
  }
209
209
 
210
210
  function redirectToDiscord() {
211
- window.open(DISCORD_INVITE, '_blank').focus();
211
+ window.open(DISCORD_INVITE, '_blank')!.focus();
212
212
  }
213
213
 
214
214
  return (
@@ -1,4 +1,4 @@
1
- import { type Accessor, createMemo, createResource } from "solid-js";
1
+ import { createMemo, createResource, type Accessor } from "solid-js";
2
2
  import getSourceMap from "./get-source-map";
3
3
 
4
4
  export interface StackFrameSource {
@@ -19,7 +19,7 @@ function getActualFileSource(path: string): string {
19
19
  export function createStackFrame(
20
20
  stackframe: StackFrame,
21
21
  isCompiled: () => boolean,
22
- ): Accessor<StackFrameSource> {
22
+ ) {
23
23
  const [data] = createResource(
24
24
  () => ({
25
25
  fileName: stackframe.fileName,
@@ -45,14 +45,13 @@ export function createStackFrame(
45
45
  },
46
46
  );
47
47
 
48
- const info = createMemo<StackFrameSource>(() => {
48
+ const info = createMemo(() => {
49
49
  const current = data();
50
50
  if (!current) {
51
51
  return undefined;
52
52
  }
53
53
  const { source, content, sourceMap } = current;
54
54
 
55
-
56
55
  if (!isCompiled() && source.line && source.column && sourceMap) {
57
56
  const result = sourceMap.originalPositionFor({
58
57
  line: source.line,
@@ -62,7 +61,7 @@ export function createStackFrame(
62
61
  return {
63
62
  ...result,
64
63
  content: sourceMap.sourceContentFor(result.source),
65
- };
64
+ } as StackFrameSource;
66
65
  }
67
66
 
68
67
  return {
@@ -71,8 +70,8 @@ export function createStackFrame(
71
70
  column: source.column,
72
71
  name: source.functionName,
73
72
  content,
74
- };
73
+ } as StackFrameSource;
75
74
  });
76
75
 
77
- return info;
76
+ return info as Accessor<StackFrameSource>;
78
77
  }
@@ -11,7 +11,7 @@ export default async function getSourceMap(
11
11
  const lines = content.split('\n');
12
12
  let sourceMapUrl: string | undefined;
13
13
  for (let i = lines.length - 1; i >= 0 && !sourceMapUrl; i--) {
14
- const result = lines[i].match(SOURCEMAP_REGEX);
14
+ const result = lines[i]!.match(SOURCEMAP_REGEX);
15
15
  if (result) {
16
16
  sourceMapUrl = result[1];
17
17
  }
@@ -1,10 +1,11 @@
1
1
  /// <reference types="vinxi/types/client" />
2
- import { createComponent, lazy, onCleanup } from "solid-js";
3
- import { appendStyles, cleanupStyles, updateStyles, preloadStyles } from "vinxi/css";
2
+ import { createComponent, lazy, onCleanup, type Component, type JSX } from "solid-js";
3
+ import { appendStyles, cleanupStyles, preloadStyles, updateStyles } from "vinxi/css";
4
4
 
5
5
  import { renderAsset } from "../server/renderAsset";
6
+ import { Asset } from "../server/types";
6
7
 
7
- export default function lazyRoute(component, clientManifest, serverManifest, exported = "default") {
8
+ export default function lazyRoute<T>(component: any, clientManifest: any, serverManifest: any, exported = "default") {
8
9
  return lazy(async () => {
9
10
  if (import.meta.env.DEV) {
10
11
  let manifest = import.meta.env.SSR ? serverManifest : clientManifest;
@@ -13,7 +14,7 @@ export default function lazyRoute(component, clientManifest, serverManifest, exp
13
14
  if (!mod[exported]) console.error(`Module ${component.src} does not export ${exported}`);
14
15
  const Component = mod[exported];
15
16
  let assets = await clientManifest.inputs?.[component.src].assets();
16
- const styles = assets.filter(asset => asset.tag === "style");
17
+ const styles = assets.filter((asset: Asset) => asset.tag === "style");
17
18
 
18
19
  if (typeof window !== "undefined" && import.meta.hot) {
19
20
  import.meta.hot.on("css-update", data => {
@@ -21,7 +22,7 @@ export default function lazyRoute(component, clientManifest, serverManifest, exp
21
22
  });
22
23
  }
23
24
 
24
- const Comp = props => {
25
+ const Comp: Component<T> = props => {
25
26
  if (typeof window !== "undefined") {
26
27
  appendStyles(styles);
27
28
  }
@@ -32,7 +33,7 @@ export default function lazyRoute(component, clientManifest, serverManifest, exp
32
33
  cleanupStyles(styles);
33
34
  }
34
35
  });
35
- return [...assets.map(asset => renderAsset(asset)), createComponent(Component, props)];
36
+ return [...assets.map((asset: Asset) => renderAsset(asset)), createComponent(Component, props)];
36
37
  };
37
38
  return { default: Comp };
38
39
  } else {
@@ -40,13 +41,13 @@ export default function lazyRoute(component, clientManifest, serverManifest, exp
40
41
  const Component = mod[exported];
41
42
  let assets = await clientManifest.inputs?.[component.src].assets();
42
43
  const styles = assets.filter(
43
- asset => asset.tag === "style" || asset.attrs.rel === "stylesheet"
44
+ (asset: Asset) => asset.tag === "style" || (asset.attrs as JSX.LinkHTMLAttributes<HTMLLinkElement>).rel === "stylesheet"
44
45
  );
45
46
  if (typeof window !== "undefined") {
46
47
  preloadStyles(styles);
47
48
  }
48
- const Comp = props => {
49
- return [...styles.map(asset => renderAsset(asset)), createComponent(Component, props)];
49
+ const Comp: Component<T> = props => {
50
+ return [...styles.map((asset: Asset) => renderAsset(asset)), createComponent(Component, props)];
50
51
  };
51
52
  return { default: Comp };
52
53
  }
package/shared/routes.ts CHANGED
@@ -6,6 +6,11 @@ interface Route {
6
6
  id: string;
7
7
  children?: Route[];
8
8
  $component?: any;
9
+ $GET?: any;
10
+ $POST?: any;
11
+ $PUT?: any;
12
+ $PATCH?: any;
13
+ $DELETE?: any;
9
14
  }
10
15
 
11
16
  declare module "vinxi/routes" {
@@ -43,7 +48,7 @@ function defineRoutes(fileRoutes: Route[]) {
43
48
 
44
49
  return fileRoutes
45
50
  .sort((a, b) => a.path.length - b.path.length)
46
- .reduce((prevRoutes, route) => {
51
+ .reduce((prevRoutes: Route[], route) => {
47
52
  return processRoute(prevRoutes, route, route.path, route.path);
48
53
  }, []);
49
54
  }
@@ -73,7 +78,7 @@ const router = createRouter({
73
78
  }
74
79
  if (memo[path]) {
75
80
  throw new Error(
76
- `Duplicate API routes for "${path}" found at "${memo[path].route.path}" and "${route.path}"`
81
+ `Duplicate API routes for "${path}" found at "${memo[path]!.route.path}" and "${route.path}"`
77
82
  );
78
83
  }
79
84
  memo[path] = { route };