@solidjs/start 1.0.0-rc.0 → 1.0.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.
@@ -24,6 +24,7 @@ export class SolidStartClientFileRouter extends BaseFileSystemRouter {
24
24
 
25
25
  if (src.endsWith(".md") || src.endsWith(".mdx")) {
26
26
  return {
27
+ page: true,
27
28
  $component: {
28
29
  src: src,
29
30
  pick: ["$css"]
@@ -35,10 +36,11 @@ export class SolidStartClientFileRouter extends BaseFileSystemRouter {
35
36
  }
36
37
 
37
38
  const [_, exports] = analyzeModule(src);
38
- const hasDefault = exports.find(e => e.n === "default");
39
- const hasRouteConfig = exports.find(e => e.n === "route");
39
+ const hasDefault = !!exports.find(e => e.n === "default");
40
+ const hasRouteConfig = !!exports.find(e => e.n === "route");
40
41
  if (hasDefault) {
41
42
  return {
43
+ page: true,
42
44
  $component: {
43
45
  src: src,
44
46
  pick: ["default", "$css"]
@@ -93,6 +95,7 @@ export class SolidStartServerFileRouter extends BaseFileSystemRouter {
93
95
  let path = this.toPath(src);
94
96
  if (src.endsWith(".md") || src.endsWith(".mdx")) {
95
97
  return {
98
+ page: true,
96
99
  $component: {
97
100
  src: src,
98
101
  pick: ["$css"]
@@ -105,16 +108,18 @@ export class SolidStartServerFileRouter extends BaseFileSystemRouter {
105
108
 
106
109
  const [_, exports] = analyzeModule(src);
107
110
  const hasRouteConfig = exports.find(e => e.n === "route");
108
- const hasDefault = exports.find(e => e.n === "default");
109
- const hasAPIRoutes = exports.find(exp => HTTP_METHODS.includes(exp.n));
111
+ const hasDefault = !!exports.find(e => e.n === "default");
112
+ const hasAPIRoutes = !!exports.find(exp => HTTP_METHODS.includes(exp.n));
110
113
  if (hasDefault || hasAPIRoutes) {
111
114
  return {
112
- $component: hasDefault
113
- ? {
114
- src: src,
115
- pick: ["default", "$css"]
116
- }
117
- : undefined,
115
+ page: hasDefault,
116
+ $component:
117
+ !this.config.dataOnly && hasDefault
118
+ ? {
119
+ src: src,
120
+ pick: ["default", "$css"]
121
+ }
122
+ : undefined,
118
123
  $$route: hasRouteConfig
119
124
  ? {
120
125
  src: src,
package/config/index.js CHANGED
@@ -30,7 +30,8 @@ function solidStartServerFsRouter(config) {
30
30
  new SolidStartServerFileRouter(
31
31
  {
32
32
  dir: resolve.absolute(config.dir, router.root),
33
- extensions: config.extensions ?? DEFAULT_EXTENSIONS
33
+ extensions: config.extensions ?? DEFAULT_EXTENSIONS,
34
+ dataOnly: config.dataOnly
34
35
  },
35
36
  router,
36
37
  app
@@ -90,7 +91,7 @@ export function defineConfig(baseConfig = {}) {
90
91
  },
91
92
  handler: `${start.appRoot}/entry-server${entryExtension}`,
92
93
  middleware: start.middleware,
93
- routes: solidStartServerFsRouter({ dir: routeDir, extensions }),
94
+ routes: solidStartServerFsRouter({ dir: routeDir, extensions, dataOnly: !start.ssr }),
94
95
  extensions,
95
96
  target: "server",
96
97
  plugins: async () => {
@@ -133,6 +134,9 @@ export function defineConfig(baseConfig = {}) {
133
134
  },
134
135
  cacheDir: "node_modules/.vinxi/server",
135
136
  define: {
137
+ "import.meta.env.START_APP": JSON.stringify(
138
+ `${start.appRoot}/app${entryExtension}`
139
+ ),
136
140
  "import.meta.env.START_ISLANDS": JSON.stringify(start.experimental.islands),
137
141
  "import.meta.env.SSR": JSON.stringify(true),
138
142
  "import.meta.env.START_SSR": JSON.stringify(start.ssr),
@@ -200,6 +204,9 @@ export function defineConfig(baseConfig = {}) {
200
204
  },
201
205
  cacheDir: "node_modules/.vinxi/client",
202
206
  define: {
207
+ "import.meta.env.START_APP": JSON.stringify(
208
+ `${start.appRoot}/app${entryExtension}`
209
+ ),
203
210
  "import.meta.env.START_ISLANDS": JSON.stringify(start.experimental.islands),
204
211
  "import.meta.env.SSR": JSON.stringify(false),
205
212
  "import.meta.env.START_SSR": JSON.stringify(start.ssr),
@@ -211,7 +218,6 @@ export function defineConfig(baseConfig = {}) {
211
218
  ];
212
219
  }
213
220
  },
214
-
215
221
  {
216
222
  name: "server-fns",
217
223
  type: "http",
@@ -221,7 +227,7 @@ export function defineConfig(baseConfig = {}) {
221
227
  ),
222
228
  middleware: start.middleware,
223
229
  target: "server",
224
- routes: solidStartServerFsRouter({ dir: routeDir, extensions }),
230
+ routes: solidStartServerFsRouter({ dir: routeDir, extensions, dataOnly: !start.ssr }),
225
231
  plugins: async () => {
226
232
  const userConfig =
227
233
  typeof vite === "function" ? await vite({ router: "server-function" }) : { ...vite };
@@ -261,6 +267,9 @@ export function defineConfig(baseConfig = {}) {
261
267
  }
262
268
  },
263
269
  define: {
270
+ "import.meta.env.START_APP": JSON.stringify(
271
+ `${start.appRoot}/app${entryExtension}`
272
+ ),
264
273
  "import.meta.env.START_ISLANDS": JSON.stringify(start.experimental.islands),
265
274
  "import.meta.env.SSR": JSON.stringify(true),
266
275
  "import.meta.env.START_SSR": JSON.stringify(start.ssr),
@@ -10,7 +10,7 @@ export function createRoutes() {
10
10
  ...(route.$$route ? route.$$route.require().route.info : {}),
11
11
  filesystem: true
12
12
  },
13
- component: lazyRoute(route.$component, import.meta.env.START_ISLANDS
13
+ component: route.$component && lazyRoute(route.$component, import.meta.env.START_ISLANDS
14
14
  ? import.meta.env.MANIFEST["ssr"]
15
15
  : import.meta.env.MANIFEST["client"], import.meta.env.MANIFEST["ssr"]),
16
16
  children: route.children ? route.children.map(createRoute) : undefined
@@ -2,6 +2,7 @@ interface Route {
2
2
  path: string;
3
3
  id: string;
4
4
  children?: Route[];
5
+ page?: boolean;
5
6
  $component?: any;
6
7
  $GET?: any;
7
8
  $POST?: any;
@@ -1,6 +1,6 @@
1
1
  import { createRouter } from "radix3";
2
2
  import fileRoutes from "vinxi/routes";
3
- export const pageRoutes = defineRoutes(fileRoutes.filter(o => o.$component));
3
+ export const pageRoutes = defineRoutes(fileRoutes.filter(o => o.page));
4
4
  function defineRoutes(fileRoutes) {
5
5
  function processRoute(routes, route, id, full) {
6
6
  const parentRoute = Object.values(routes).find(o => {
@@ -21,7 +21,7 @@ function defineRoutes(fileRoutes) {
21
21
  }
22
22
  export function matchAPIRoute(path, method) {
23
23
  const match = router.lookup(path);
24
- if (match) {
24
+ if (match && match.route) {
25
25
  const handler = match.route[`$${method}`];
26
26
  if (handler === undefined)
27
27
  return;
@@ -38,7 +38,7 @@ const router = createRouter({
38
38
  routes: fileRoutes.reduce((memo, route) => {
39
39
  if (!containsHTTP(route))
40
40
  return memo;
41
- let path = route.path.replace(/\([^)/]+\)/g, "").replace(/\*([^/]*)/g, (_, m) => `**:${m}`);
41
+ let path = route.path.replace(/\/\([^)/]+\)/g, "").replace(/\([^)/]+\)/g, "").replace(/\*([^/]*)/g, (_, m) => `**:${m}`);
42
42
  if (/:[^/]*\?/g.test(path)) {
43
43
  throw new Error(`Optional parameters are not supported in API routes: ${path}`);
44
44
  }
@@ -9,11 +9,17 @@ import { eventHandler, setHeader, setResponseStatus } from "vinxi/http";
9
9
  import invariant from "vinxi/lib/invariant";
10
10
  import { cloneEvent, getFetchEvent, mergeResponseHeaders } from "../server/fetchEvent";
11
11
  import { createPageEvent } from "../server/pageEvent";
12
+ import { getExpectedRedirectStatus } from "../server/handler";
12
13
  function createChunk(data) {
13
- const bytes = data.length;
14
+ const encodeData = new TextEncoder().encode(data);
15
+ const bytes = encodeData.length;
14
16
  const baseHex = bytes.toString(16);
15
17
  const totalHex = "00000000".substring(0, 8 - baseHex.length) + baseHex; // 32-bit
16
- return new TextEncoder().encode(`;0x${totalHex};${data}`);
18
+ const head = new TextEncoder().encode(`;0x${totalHex};`);
19
+ const chunk = new Uint8Array(12 + bytes);
20
+ chunk.set(head);
21
+ chunk.set(encodeData, 12);
22
+ return chunk;
17
23
  }
18
24
  function serializeToStream(id, value) {
19
25
  return new ReadableStream({
@@ -150,11 +156,13 @@ async function handleServerFunction(h3Event) {
150
156
  if (!instance) {
151
157
  const isError = result instanceof Error;
152
158
  let redirectUrl = new URL(request.headers.get("referer")).toString();
159
+ let statusCode = 302;
153
160
  if (result instanceof Response && result.headers.has("Location")) {
154
161
  redirectUrl = new URL(result.headers.get("Location"), new URL(request.url).origin + import.meta.env.SERVER_BASE_URL).toString();
162
+ statusCode = getExpectedRedirectStatus(result);
155
163
  }
156
164
  return new Response(null, {
157
- status: 302,
165
+ status: statusCode,
158
166
  headers: {
159
167
  Location: redirectUrl,
160
168
  ...(result
@@ -7,7 +7,7 @@ class SerovalChunkReader {
7
7
  done;
8
8
  constructor(stream) {
9
9
  this.reader = stream.getReader();
10
- this.buffer = "";
10
+ this.buffer = new Uint8Array(0);
11
11
  this.done = false;
12
12
  }
13
13
  async readChunk() {
@@ -15,7 +15,10 @@ class SerovalChunkReader {
15
15
  const chunk = await this.reader.read();
16
16
  if (!chunk.done) {
17
17
  // repopulate the buffer
18
- this.buffer += new TextDecoder().decode(chunk.value);
18
+ let newBuffer = new Uint8Array(this.buffer.length + chunk.value.length);
19
+ newBuffer.set(this.buffer);
20
+ newBuffer.set(chunk.value, this.buffer.length);
21
+ this.buffer = newBuffer;
19
22
  }
20
23
  else {
21
24
  this.done = true;
@@ -23,7 +26,7 @@ class SerovalChunkReader {
23
26
  }
24
27
  async next() {
25
28
  // Check if the buffer is empty
26
- if (this.buffer === "") {
29
+ if (this.buffer.length === 0) {
27
30
  // if we are already done...
28
31
  if (this.done) {
29
32
  return {
@@ -39,7 +42,8 @@ class SerovalChunkReader {
39
42
  // The byte header tells us how big the expected data is
40
43
  // so we know how much data we should wait before we
41
44
  // deserialize the data
42
- const bytes = Number.parseInt(this.buffer.substring(1, 11), 16); // ;0x00000000;
45
+ const head = new TextDecoder().decode(this.buffer.subarray(1, 11));
46
+ const bytes = Number.parseInt(head, 16); // ;0x00000000;
43
47
  // Check if the buffer has enough bytes to be parsed
44
48
  while (bytes > this.buffer.length - 12) {
45
49
  // If it's not enough, and the reader is done
@@ -51,9 +55,9 @@ class SerovalChunkReader {
51
55
  await this.readChunk();
52
56
  }
53
57
  // Extract the exact chunk as defined by the byte header
54
- const partial = this.buffer.substring(12, 12 + bytes);
58
+ const partial = new TextDecoder().decode(this.buffer.subarray(12, 12 + bytes));
55
59
  // The rest goes to the buffer
56
- this.buffer = this.buffer.substring(12 + bytes);
60
+ this.buffer = this.buffer.subarray(12 + bytes);
57
61
  // Deserialize the chunk
58
62
  return {
59
63
  done: false,
@@ -163,7 +167,7 @@ export function createServerReference(fn, id, name) {
163
167
  const fn = async (...args) => {
164
168
  const encodeArgs = options.method && options.method.toUpperCase() === "GET";
165
169
  return fetchServerFunction(encodeArgs
166
- ? url + (args.length ? `&args=${JSON.stringify(await Promise.resolve(toJSONAsync(args, { plugins })))}` : "")
170
+ ? url + (args.length ? `&args=${encodeURIComponent(JSON.stringify(await Promise.resolve(toJSONAsync(args, { plugins }))))}` : "")
167
171
  : `${baseURL}/_server`, `${id}#${name}`, options, encodeArgs ? [] : args);
168
172
  };
169
173
  fn.url = url;
@@ -26,8 +26,9 @@ export function StartServer(props) {
26
26
  const context = getRequestEvent();
27
27
  // @ts-ignore
28
28
  const nonce = context.nonce;
29
- let assets = [];
29
+ let assets;
30
30
  Promise.resolve().then(async () => {
31
+ let assetPromises = [];
31
32
  // @ts-ignore
32
33
  if (context.router && context.router.matches) {
33
34
  // @ts-ignore
@@ -40,25 +41,25 @@ export function StartServer(props) {
40
41
  const segment = matched[i];
41
42
  const part = import.meta.env.MANIFEST[import.meta.env.START_ISLANDS ? "ssr" : "client"]
42
43
  .inputs[segment["$component"].src];
43
- const asset = (await part.assets());
44
- assets.push.apply(assets, asset);
44
+ assetPromises.push(part.assets());
45
45
  }
46
46
  }
47
- else
47
+ else if (import.meta.env.DEV)
48
48
  console.warn("No route matched for preloading js assets");
49
49
  }
50
+ assets = await Promise.all(assetPromises).then(a =>
50
51
  // dedupe assets
51
- assets = [...new Map(assets.map(item => [item.attrs.key, item])).values()].filter(asset => import.meta.env.START_ISLANDS
52
+ [...new Map(a.flat().map(item => [item.attrs.key, item])).values()].filter(asset => import.meta.env.START_ISLANDS
52
53
  ? false
53
54
  : asset.attrs.rel === "modulepreload" &&
54
- !context.assets.find((a) => a.attrs.key === asset.attrs.key));
55
+ !context.assets.find((a) => a.attrs.key === asset.attrs.key)));
55
56
  });
56
57
  useAssets(() => (assets.length ? assets.map(m => renderAsset(m)) : undefined));
57
58
  return (<NoHydration>
58
59
  {docType}
59
60
  <props.document assets={<>
60
61
  <HydrationScript />
61
- {context.assets.map((m) => renderAsset(m))}
62
+ {context.assets.map((m) => renderAsset(m, nonce))}
62
63
  </>} scripts={nonce ? (<>
63
64
  <script nonce={nonce} innerHTML={`window.manifest = ${JSON.stringify(context.manifest)}`}/>
64
65
  <script type="module" nonce={nonce} async src={import.meta.env.MANIFEST["client"].inputs[import.meta.env.MANIFEST["client"].handler].output.path}/>
@@ -1,4 +1,4 @@
1
- import { appendResponseHeader, getRequestIP, getResponseHeader, getResponseHeaders, getResponseStatus, getResponseStatusText, getWebRequest, removeResponseHeader, setHeader, setResponseHeader, setResponseStatus } from "vinxi/http";
1
+ import { appendResponseHeader, getRequestIP, getResponseHeader, getResponseHeaders, getResponseStatus, getResponseStatusText, getWebRequest, removeResponseHeader, setResponseHeader, setResponseStatus } from "vinxi/http";
2
2
  const fetchEventSymbol = Symbol("fetchEvent");
3
3
  export function createFetchEvent(event) {
4
4
  return {
@@ -23,7 +23,7 @@ export function getFetchEvent(h3Event) {
23
23
  }
24
24
  export function mergeResponseHeaders(h3Event, headers) {
25
25
  for (const [key, value] of headers.entries()) {
26
- setHeader(h3Event, key, value);
26
+ appendResponseHeader(h3Event, key, value);
27
27
  }
28
28
  }
29
29
  class HeaderProxy {
@@ -1,3 +1,8 @@
1
- import type { FetchEvent, HandlerOptions, PageEvent } from "./types";
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;
2
7
  export declare function createBaseHandler(fn: (context: PageEvent) => unknown, createPageEvent: (event: FetchEvent) => Promise<PageEvent>, options?: HandlerOptions | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>)): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
3
8
  export declare function createHandler(fn: (context: PageEvent) => unknown, options?: HandlerOptions | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>)): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
@@ -5,6 +5,18 @@ import { eventHandler, sendRedirect, setHeader, setResponseStatus } from "vinxi/
5
5
  import { matchAPIRoute } from "../router/routes";
6
6
  import { getFetchEvent } from "./fetchEvent";
7
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
+ }
8
20
  export function createBaseHandler(fn, createPageEvent, options = {}) {
9
21
  return eventHandler({
10
22
  handler: (e) => {
@@ -27,47 +39,48 @@ export function createBaseHandler(fn, createPageEvent, options = {}) {
27
39
  }
28
40
  // render
29
41
  const context = await createPageEvent(event);
30
- if (typeof options === "function")
31
- options = await options(context);
32
- const mode = options.mode || "stream";
42
+ const resolvedOptions = typeof options == "function" ? await options(context) : { ...options };
43
+ const mode = resolvedOptions.mode || "stream";
33
44
  // @ts-ignore
34
- if (options.nonce)
35
- context.nonce = options.nonce;
45
+ if (resolvedOptions.nonce)
46
+ context.nonce = resolvedOptions.nonce;
36
47
  if (mode === "sync" || !import.meta.env.START_SSR) {
37
48
  const html = renderToString(() => {
38
49
  sharedConfig.context.event = context;
39
50
  return fn(context);
40
- }, options);
51
+ }, resolvedOptions);
52
+ context.complete = true;
41
53
  if (context.response && context.response.headers.get("Location")) {
42
- return sendRedirect(e, context.response.headers.get("Location"));
54
+ const status = getExpectedRedirectStatus(context.response);
55
+ return sendRedirect(e, context.response.headers.get("Location"), status);
43
56
  }
44
57
  return html;
45
58
  }
46
- let cloned = { ...options };
47
- if (cloned.onCompleteAll) {
48
- const og = cloned.onCompleteAll;
49
- cloned.onCompleteAll = options => {
59
+ if (resolvedOptions.onCompleteAll) {
60
+ const og = resolvedOptions.onCompleteAll;
61
+ resolvedOptions.onCompleteAll = options => {
50
62
  handleStreamCompleteRedirect(context)(options);
51
63
  og(options);
52
64
  };
53
65
  }
54
66
  else
55
- cloned.onCompleteAll = handleStreamCompleteRedirect(context);
56
- if (cloned.onCompleteShell) {
57
- const og = cloned.onCompleteShell;
58
- cloned.onCompleteShell = options => {
67
+ resolvedOptions.onCompleteAll = handleStreamCompleteRedirect(context);
68
+ if (resolvedOptions.onCompleteShell) {
69
+ const og = resolvedOptions.onCompleteShell;
70
+ resolvedOptions.onCompleteShell = options => {
59
71
  handleShellCompleteRedirect(context, e)();
60
72
  og(options);
61
73
  };
62
74
  }
63
75
  else
64
- cloned.onCompleteShell = handleShellCompleteRedirect(context, e);
76
+ resolvedOptions.onCompleteShell = handleShellCompleteRedirect(context, e);
65
77
  const stream = renderToStream(() => {
66
78
  sharedConfig.context.event = context;
67
79
  return fn(context);
68
- }, cloned);
80
+ }, resolvedOptions);
69
81
  if (context.response && context.response.headers.get("Location")) {
70
- return sendRedirect(e, context.response.headers.get("Location"));
82
+ const status = getExpectedRedirectStatus(context.response);
83
+ return sendRedirect(e, context.response.headers.get("Location"), status);
71
84
  }
72
85
  if (mode === "async")
73
86
  return stream;
@@ -82,13 +95,15 @@ export function createBaseHandler(fn, createPageEvent, options = {}) {
82
95
  function handleShellCompleteRedirect(context, e) {
83
96
  return () => {
84
97
  if (context.response && context.response.headers.get("Location")) {
85
- setResponseStatus(e, 302);
98
+ const status = getExpectedRedirectStatus(context.response);
99
+ setResponseStatus(e, status);
86
100
  setHeader(e, "Location", context.response.headers.get("Location"));
87
101
  }
88
102
  };
89
103
  }
90
104
  function handleStreamCompleteRedirect(context) {
91
105
  return ({ write }) => {
106
+ context.complete = true;
92
107
  const to = context.response && context.response.headers.get("Location");
93
108
  to && write(`<script>window.location="${to}"</script>`);
94
109
  };
@@ -26,6 +26,7 @@ export async function createPageEvent(ctx) {
26
26
  manifest: await clientManifest.json(),
27
27
  assets: [
28
28
  ...(await clientManifest.inputs[clientManifest.handler].assets()),
29
+ ...(import.meta.env.DEV ? await clientManifest.inputs[import.meta.env.START_APP].assets() : []),
29
30
  ...(import.meta.env.START_ISLANDS
30
31
  ? (await serverManifest.inputs[serverManifest.handler].assets()).filter(s => s.attrs.rel !== "modulepreload")
31
32
  : [])
@@ -37,6 +38,7 @@ export async function createPageEvent(ctx) {
37
38
  // prevUrl: prevPath || "",
38
39
  // mutation: mutation,
39
40
  // $type: FETCH_EVENT,
41
+ complete: false,
40
42
  $islands: new Set()
41
43
  });
42
44
  return pageEvent;
@@ -1,2 +1,2 @@
1
1
  import type { Asset } from "./types";
2
- export declare function renderAsset(asset: Asset): any;
2
+ export declare function renderAsset(asset: Asset, nonce?: string): any;
@@ -7,7 +7,7 @@ const assetMap = {
7
7
  </script>) : null;
8
8
  }
9
9
  };
10
- export function renderAsset(asset) {
10
+ export function renderAsset(asset, nonce) {
11
11
  let { tag, attrs: { key, ...attrs } = { key: undefined }, children } = asset;
12
- return assetMap[tag]({ attrs, key, children });
12
+ return assetMap[tag]({ attrs: { ...attrs, nonce }, key, children });
13
13
  }
@@ -8,6 +8,7 @@ export async function createPageEvent(ctx) {
8
8
  manifest: await clientManifest.json(),
9
9
  assets: [...(await clientManifest.inputs[clientManifest.handler].assets())],
10
10
  routes: [],
11
+ complete: false,
11
12
  // prevUrl: "",
12
13
  // mutation: false,
13
14
  // $type: FETCH_EVENT,
@@ -60,6 +60,7 @@ export interface PageEvent extends RequestEvent {
60
60
  assets: any;
61
61
  routes: any[];
62
62
  $islands: Set<string>;
63
+ complete: boolean;
63
64
  }
64
65
  export interface APIEvent extends FetchEvent {
65
66
  params: {
@@ -9,7 +9,7 @@ export const HttpHeader = isServer
9
9
  else
10
10
  event.response.headers.set(props.name, props.value);
11
11
  onCleanup(() => {
12
- if (event.nativeEvent.handled)
12
+ if (event.nativeEvent.handled || event.complete)
13
13
  return;
14
14
  const value = event.response.headers.get(props.name);
15
15
  if (!value)
@@ -6,7 +6,7 @@ export const HttpStatusCode = isServer
6
6
  const event = getRequestEvent();
7
7
  event.response.status = props.code;
8
8
  event.response.statusText = props.text;
9
- onCleanup(() => !event.nativeEvent.handled && (event.response.status = 200));
9
+ onCleanup(() => !event.nativeEvent.handled && !event.complete && (event.response.status = 200));
10
10
  return null;
11
11
  }
12
12
  : (_props) => null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidjs/start",
3
- "version": "1.0.0-rc.0",
3
+ "version": "1.0.0",
4
4
  "type": "module",
5
5
  "author": "Ryan Carniato",
6
6
  "license": "MIT",
@@ -51,8 +51,8 @@
51
51
  }
52
52
  },
53
53
  "devDependencies": {
54
- "solid-js": "^1.8.16",
55
- "vinxi": "^0.3.10",
54
+ "solid-js": "^1.8.17",
55
+ "vinxi": "^0.3.11",
56
56
  "typescript": "^5.4.2"
57
57
  },
58
58
  "dependencies": {
@@ -70,7 +70,7 @@
70
70
  "source-map-js": "^1.0.2",
71
71
  "terracotta": "^1.0.4",
72
72
  "vite-plugin-inspect": "^0.7.33",
73
- "vite-plugin-solid": "~2.9.1"
73
+ "vite-plugin-solid": "^2.10.2"
74
74
  },
75
75
  "scripts": {
76
76
  "typecheck": "tsc --noEmit",