@solidjs/start 2.0.0-rc.2 → 2.0.0-rc.4

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 (58) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/config/env.js +2 -2
  3. package/dist/config/fs-routes/tree-shake.js +5 -0
  4. package/dist/config/index.d.ts +78 -3
  5. package/dist/config/manifest.js +3 -2
  6. package/dist/directives/remove-unused-variables.js +2 -2
  7. package/dist/directives/xxhash32.js +5 -13
  8. package/dist/fns/handler.js +9 -8
  9. package/dist/fns/serialization.js +21 -1
  10. package/dist/server/assets/render.jsx +1 -1
  11. package/dist/server/handler.d.ts +3 -4
  12. package/dist/server/handler.js +3 -43
  13. package/dist/server/index.d.ts +1 -1
  14. package/dist/server/spa/handler.d.ts +2 -3
  15. package/dist/server/types.d.ts +12 -1
  16. package/dist/server/web-stream.d.ts +1 -1
  17. package/dist/server/web-stream.js +5 -2
  18. package/dist/shared/clientOnly.js +3 -1
  19. package/dist/shared/dev-toolbar/error-viewer/CodeView.jsx +1 -1
  20. package/dist/shared/dev-toolbar/functions/BlobViewer.css +1 -1
  21. package/dist/shared/dev-toolbar/functions/BlobViewer.d.ts +2 -2
  22. package/dist/shared/dev-toolbar/functions/BlobViewer.jsx +7 -11
  23. package/dist/shared/dev-toolbar/functions/FormDataViewer.d.ts +1 -1
  24. package/dist/shared/dev-toolbar/functions/FormDataViewer.jsx +7 -11
  25. package/dist/shared/dev-toolbar/functions/HeadersViewer.d.ts +1 -1
  26. package/dist/shared/dev-toolbar/functions/HeadersViewer.jsx +2 -2
  27. package/dist/shared/dev-toolbar/functions/HexViewer.d.ts +1 -1
  28. package/dist/shared/dev-toolbar/functions/HexViewer.jsx +7 -15
  29. package/dist/shared/dev-toolbar/functions/SerovalValue.css +0 -2
  30. package/dist/shared/dev-toolbar/functions/SerovalValue.d.ts +1 -1
  31. package/dist/shared/dev-toolbar/functions/SerovalValue.jsx +3 -3
  32. package/dist/shared/dev-toolbar/functions/SerovalViewer.css +0 -1
  33. package/dist/shared/dev-toolbar/functions/URLSearchParamsViewer.d.ts +1 -1
  34. package/dist/shared/dev-toolbar/functions/URLSearchParamsViewer.jsx +5 -7
  35. package/dist/shared/dev-toolbar/functions/styles.css +0 -1
  36. package/dist/shared/dev-toolbar/index.jsx +5 -0
  37. package/dist/shared/ui/Badge.css +0 -1
  38. package/dist/shared/ui/Badge.d.ts +3 -3
  39. package/dist/shared/ui/Badge.jsx +3 -3
  40. package/dist/shared/ui/Button.jsx +1 -1
  41. package/dist/shared/ui/Cascade.jsx +3 -3
  42. package/dist/shared/ui/Dialog.css +1 -2
  43. package/dist/shared/ui/Dialog.jsx +3 -3
  44. package/dist/shared/ui/IconButton.jsx +1 -1
  45. package/dist/shared/ui/Placeholder.css +1 -1
  46. package/dist/shared/ui/Placeholder.d.ts +2 -2
  47. package/dist/shared/ui/Placeholder.jsx +2 -4
  48. package/dist/shared/ui/Section.css +0 -1
  49. package/dist/shared/ui/Section.d.ts +2 -2
  50. package/dist/shared/ui/Section.jsx +3 -5
  51. package/dist/shared/ui/Select.jsx +3 -3
  52. package/dist/shared/ui/Table.d.ts +6 -6
  53. package/dist/shared/ui/Table.jsx +5 -5
  54. package/dist/shared/ui/Tabs.jsx +4 -4
  55. package/dist/shared/ui/Text.css +7 -3
  56. package/dist/shared/ui/Text.d.ts +8 -8
  57. package/dist/shared/ui/Text.jsx +9 -9
  58. package/package.json +27 -27
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @solidjs/start
2
2
 
3
+ ## 2.0.0-rc.4
4
+
5
+ ### Patch Changes
6
+
7
+ - b6dfaac: Updated dependencies, including `cookie-es` to 3, `shiki` to 4, `srvx` to 0.12.4, `oxc-parser` to 0.141 and `seroval` to 1.5.6. `parseSetCookie` now returns `undefined` for cookies with a forbidden name or an empty name and value, and those cookies are no longer forwarded to nested server function requests.
8
+ - 02cd41e: Stop the dev toolbar from reporting benign `ResizeObserver loop` notifications as application errors. Browsers dispatch these as window `error` events carrying no error object, so the toolbar was capturing the raw `ErrorEvent` and force-opening the error panel over the app on every resize.
9
+ - d3c2af2: Don't send server error stack traces to the client in production builds. When a server function throws, the error is serialized and rethrown on the client, and seroval included `Error.prototype.stack` by default, leaking server file paths and internal function names. Stacks are still serialized in development.
10
+
11
+ ## 2.0.0-rc.3
12
+
13
+ ### Patch Changes
14
+
15
+ - d9018d6: fix(types): add missing properties to `SolidStartOptions` and expose them via Vite plugin configuration
16
+ - e26cef0: Fix TS2883/TS2742 when emitting declarations for `entry-server.tsx`. `createHandler` now returns `StartHandler`, a type owned by `@solidjs/start`, instead of h3's `H3`, so the inferred type of `export default createHandler(...)` no longer has to be named through a nested `node_modules/@solidjs/start/node_modules/h3` path.
17
+ - 7c8dbe6: keep TypeScript namespace members in route files during production builds
18
+ - b3c7aaf: Update `h3` to `2.0.1-rc.26`.
19
+ - b3c7aaf: Fixed event response status and headers set during server-side rendering with deferred async resources, not being applied on the outgoing response.
20
+
3
21
  ## 2.0.0-rc.2
4
22
 
5
23
  ### Minor Changes
@@ -58,13 +58,13 @@ export function envPlugin(options) {
58
58
  }
59
59
  const vars = currentOptions.server?.load
60
60
  ? currentOptions.server.load(env)
61
- : loadEnv(env, '.', serverPrefix);
61
+ : loadEnv(env, ".", serverPrefix);
62
62
  return convertObjectToModule(vars);
63
63
  }
64
64
  if (filename === CLIENT_ENV) {
65
65
  const vars = currentOptions.client?.load
66
66
  ? currentOptions.client.load(env)
67
- : loadEnv(env, '.', clientPrefix);
67
+ : loadEnv(env, ".", clientPrefix);
68
68
  return convertObjectToModule(vars);
69
69
  }
70
70
  if (filename === SERVER_RUNTIME_LOADER) {
@@ -133,6 +133,11 @@ function treeShakeTransform({ types: t }) {
133
133
  if (!state.opts.pick) {
134
134
  return;
135
135
  }
136
+ // Only module-level exports are route exports; `export` inside a
137
+ // TS namespace/module block is unrelated to the pick list.
138
+ if (!exportNamedPath.parentPath.isProgram()) {
139
+ return;
140
+ }
136
141
  const specifiers = exportNamedPath.get("specifiers");
137
142
  if (specifiers.length) {
138
143
  specifiers.forEach(s => {
@@ -2,24 +2,99 @@ import type { PluginOption } from "vite";
2
2
  import { type Options as SolidOptions } from "vite-plugin-solid";
3
3
  import { type ServerFunctionsOptions } from "../directives/index.ts";
4
4
  import { type EnvPluginOptions } from "./env.ts";
5
+ /**
6
+ * Configuration options for SolidStart. (previously in `app.config.ts`)
7
+ *
8
+ * @see https://docs.solidjs.com/solid-start/v2/migrating-from-v1#move-framework-configuration-into-viteconfigts
9
+ */
5
10
  export interface SolidStartOptions {
11
+ /**
12
+ * Path to the root of the application (where `app.tsx` / `app.jsx` lives).
13
+ *
14
+ * @default "./src"
15
+ */
16
+ appRoot?: string;
17
+ /**
18
+ * Options forwarded to `vite-plugin-solid`.
19
+ *
20
+ * @see https://github.com/solidjs/vite-plugin-solid#api
21
+ */
6
22
  solid?: Partial<SolidOptions>;
23
+ /**
24
+ * Enable or disable server-side rendering.
25
+ *
26
+ * - `true` — SSR (default)
27
+ * - `false` — client-side rendering only (SPA mode)
28
+ *
29
+ * @default true
30
+ */
7
31
  ssr?: boolean;
32
+ /**
33
+ * Show the SolidStart development overlay (error overlay, etc.) in development.
34
+ *
35
+ * @default true
36
+ */
37
+ devOverlay?: boolean;
38
+ /**
39
+ * Experimental features.
40
+ */
41
+ experimental?: {
42
+ /**
43
+ * Enable islands architecture mode.
44
+ *
45
+ * Currently fixed to `false` (not yet fully supported).
46
+ *
47
+ * @default false
48
+ */
49
+ islands?: false;
50
+ };
51
+ /**
52
+ * Directory containing file-system routes, relative to {@link appRoot}.
53
+ *
54
+ * @default "./routes"
55
+ */
8
56
  routeDir?: string;
57
+ /**
58
+ * File extensions that should be treated as routes.
59
+ *
60
+ * @default ["js", "jsx", "ts", "tsx"]
61
+ */
9
62
  extensions?: string[];
63
+ /**
64
+ * Path to an optional middleware module.
65
+ *
66
+ * The module should export a middleware created with `createMiddleware`
67
+ * from `@solidjs/start/middleware`.
68
+ *
69
+ * @example "src/middleware/index.ts"
70
+ */
10
71
  middleware?: string;
72
+ /**
73
+ * Serialization settings for server-function / action payloads
74
+ * that cross the server-client boundary.
75
+ */
11
76
  serialization?: {
12
77
  /**
13
78
  * The serialization mode to use for server functions/actions.
14
- * The "js" mode uses a custom binary format that is more efficient than JSON, but requires a custom deserializer (with `eval()`) on the client.
15
- * A strong CSP should block `eval()` executions, which would prevent the "js" mode from working.
16
- * The "json" mode uses JSON for serialization, which is less efficient but can be deserialized with `JSON.parse` on the client.
79
+ *
80
+ * - `"js"` — Uses a custom binary format (Seroval) that is more efficient
81
+ * than JSON, but requires a custom deserializer (with `eval()`) on the client.
82
+ * A strong CSP that blocks `eval()` will prevent this mode from working.
83
+ * - `"json"` — Uses JSON for serialization. Less efficient / larger payloads,
84
+ * but can be deserialized with `JSON.parse` on the client and is CSP-friendly.
17
85
  *
18
86
  * @default "json"
19
87
  */
20
88
  mode?: "js" | "json";
21
89
  };
90
+ /**
91
+ * Configures plugin behavior per build environment
92
+ */
22
93
  env?: EnvPluginOptions;
94
+ /**
95
+ * Options controlling which files are processed as server functions
96
+ * (inclusion / exclusion filters for the `"use server"` transform).
97
+ */
23
98
  serverFunctions?: Pick<ServerFunctionsOptions, "filter">;
24
99
  }
25
100
  export declare function solidStart(options?: SolidStartOptions): Array<PluginOption>;
@@ -40,7 +40,7 @@ export function manifest(start) {
40
40
  if (!entry)
41
41
  throw new Error("No client entry found");
42
42
  let rawManifest;
43
- const viteMajor = parseInt(viteVersion.split('.')[0], 10);
43
+ const viteMajor = parseInt(viteVersion.split(".")[0], 10);
44
44
  const manifestKey = Object.keys(globalThis.START_CLIENT_BUNDLE).find(k => k.endsWith("manifest.json"));
45
45
  if (manifestKey && viteMajor < 8) {
46
46
  const manifestAsset = globalThis.START_CLIENT_BUNDLE[manifestKey];
@@ -53,7 +53,8 @@ export function manifest(start) {
53
53
  if (devServer?.environments?.client?.config?.build?.outDir) {
54
54
  outDir = devServer.environments.client.config.build.outDir;
55
55
  }
56
- else if (this.environment?.config?.build?.outDir && this.environment?.config?.consumer === "client") {
56
+ else if (this.environment?.config?.build?.outDir &&
57
+ this.environment?.config?.consumer === "client") {
57
58
  outDir = this.environment.config.build.outDir;
58
59
  }
59
60
  else if (globalThis.START_CLIENT_OUT_DIR) {
@@ -8,7 +8,7 @@ function isInvalidForRemoval(path) {
8
8
  // This one is for destructured variables
9
9
  let target = path;
10
10
  if (isPathValid(path, t.isVariableDeclarator)) {
11
- target = path.get('id');
11
+ target = path.get("id");
12
12
  }
13
13
  return isPathValid(target, t.isObjectPattern) || isPathValid(target, t.isArrayPattern);
14
14
  }
@@ -42,7 +42,7 @@ export function removeUnusedVariables(program) {
42
42
  }
43
43
  dirty = true;
44
44
  }
45
- else if (!(isInvalidForRemoval(binding.path))) {
45
+ else if (!isInvalidForRemoval(binding.path)) {
46
46
  binding.path.remove();
47
47
  dirty = true;
48
48
  }
@@ -34,7 +34,7 @@ function toUtf8(text) {
34
34
  * @param seed - optional seed (32-bit unsigned);
35
35
  */
36
36
  export default function xxHash32(buffer, seed = 0) {
37
- buffer = typeof buffer === 'string' ? toUtf8(buffer) : buffer;
37
+ buffer = typeof buffer === "string" ? toUtf8(buffer) : buffer;
38
38
  const b = buffer;
39
39
  /*
40
40
  Step 1. Initialize internal accumulators
@@ -144,9 +144,7 @@ export default function xxHash32(buffer, seed = 0) {
144
144
  const laneP = laneN0 * PRIME32_3 + ((laneN1 * PRIME32_3) << 16);
145
145
  acc = (acc + laneP) & 0xffffffff;
146
146
  acc = (acc << 17) | (acc >>> 15);
147
- acc =
148
- ((acc & 0xffff) * PRIME32_4 + (((acc >>> 16) * PRIME32_4) << 16)) &
149
- 0xffffffff;
147
+ acc = ((acc & 0xffff) * PRIME32_4 + (((acc >>> 16) * PRIME32_4) << 16)) & 0xffffffff;
150
148
  }
151
149
  /*
152
150
  ```
@@ -162,9 +160,7 @@ export default function xxHash32(buffer, seed = 0) {
162
160
  const lane = b[offset];
163
161
  acc += lane * PRIME32_5;
164
162
  acc = (acc << 11) | (acc >>> 21);
165
- acc =
166
- ((acc & 0xffff) * PRIME32_1 + (((acc >>> 16) * PRIME32_1) << 16)) &
167
- 0xffffffff;
163
+ acc = ((acc & 0xffff) * PRIME32_1 + (((acc >>> 16) * PRIME32_1) << 16)) & 0xffffffff;
168
164
  }
169
165
  /*
170
166
  Step 6. Final mix (avalanche)
@@ -180,13 +176,9 @@ export default function xxHash32(buffer, seed = 0) {
180
176
  ```
181
177
  */
182
178
  acc ^= acc >>> 15;
183
- acc =
184
- (((acc & 0xffff) * PRIME32_2) & 0xffffffff) +
185
- (((acc >>> 16) * PRIME32_2) << 16);
179
+ acc = (((acc & 0xffff) * PRIME32_2) & 0xffffffff) + (((acc >>> 16) * PRIME32_2) << 16);
186
180
  acc ^= acc >>> 13;
187
- acc =
188
- (((acc & 0xffff) * PRIME32_3) & 0xffffffff) +
189
- (((acc >>> 16) * PRIME32_3) << 16);
181
+ acc = (((acc & 0xffff) * PRIME32_3) & 0xffffffff) + (((acc >>> 16) * PRIME32_3) << 16);
190
182
  acc ^= acc >>> 16;
191
183
  // turn any negatives back into a positive number;
192
184
  return acc < 0 ? acc + 4294967296 : acc;
@@ -132,8 +132,7 @@ export async function handleServerFunction(h3Event) {
132
132
  if (x.headers)
133
133
  mergeResponseHeaders(h3Event, x.headers);
134
134
  // forward non-redirect statuses
135
- if (x.status &&
136
- (!instance || x.status < 300 || x.status >= 400))
135
+ if (x.status && (!instance || x.status < 300 || x.status >= 400))
137
136
  h3Event.res.status = x.status;
138
137
  if (x.customBody) {
139
138
  x = await x.customBody();
@@ -204,10 +203,7 @@ function handleNoJS(result, request, parsed, thrown) {
204
203
  result: isError ? result.message : result,
205
204
  thrown: thrown,
206
205
  error: isError,
207
- input: [
208
- ...parsed.slice(0, -1),
209
- [...parsed[parsed.length - 1].entries()],
210
- ],
206
+ input: [...parsed.slice(0, -1), [...parsed[parsed.length - 1].entries()]],
211
207
  }))}; Secure; HttpOnly;`);
212
208
  }
213
209
  return new Response(null, {
@@ -229,10 +225,15 @@ export function createSingleFlightHeaders(sourceEvent) {
229
225
  // useH3Internals = true;
230
226
  // sourceEvent.nativeEvent.node.req.headers.cookie = "";
231
227
  // }
232
- SetCookies.forEach((cookie) => {
228
+ SetCookies.forEach(cookie => {
233
229
  if (!cookie)
234
230
  return;
235
- const { maxAge, expires, name, value } = parseSetCookie(cookie);
231
+ // `parseSetCookie` returns undefined for forbidden cookie names and for
232
+ // cookies with an empty name and value.
233
+ const parsed = parseSetCookie(cookie);
234
+ if (!parsed)
235
+ return;
236
+ const { maxAge, expires, name, value } = parsed;
236
237
  if (maxAge != null && maxAge <= 0) {
237
238
  delete cookies[name];
238
239
  return;
@@ -16,6 +16,25 @@ const DEFAULT_PLUGINS = [
16
16
  ];
17
17
  const MAX_SERIALIZATION_DEPTH_LIMIT = 64;
18
18
  const DISABLED_FEATURES = Feature.RegExp;
19
+ /**
20
+ * An error thrown by a server function is serialized and rethrown on the
21
+ * client, and seroval includes `Error.prototype.stack` by default. In
22
+ * production that leaks server file paths, internal function names and the
23
+ * shape of the deployment to anyone who can trigger a throw, so strip it.
24
+ * Development keeps the stack: that's where it's actually useful, and the
25
+ * paths it exposes are the developer's own.
26
+ *
27
+ * Only applied when writing; parsing leaves `DISABLED_FEATURES` alone so an
28
+ * incoming payload that does carry a stack still deserializes.
29
+ */
30
+ const SERIALIZE_DISABLED_FEATURES = import.meta.env.PROD
31
+ ? DISABLED_FEATURES | Feature.ErrorPrototypeStack
32
+ : DISABLED_FEATURES;
33
+ /**
34
+ * `crossSerializeStream` historically ran with every feature enabled, so only
35
+ * add the stack removal here rather than the full serialize set.
36
+ */
37
+ const JS_SERIALIZE_DISABLED_FEATURES = import.meta.env.PROD ? Feature.ErrorPrototypeStack : 0;
19
38
  /**
20
39
  * Alexis:
21
40
  *
@@ -47,6 +66,7 @@ export function serializeToJSStream(id, value) {
47
66
  start(controller) {
48
67
  crossSerializeStream(value, {
49
68
  scopeId: id,
69
+ disabledFeatures: JS_SERIALIZE_DISABLED_FEATURES,
50
70
  plugins: DEFAULT_PLUGINS,
51
71
  onSerialize(data, initial) {
52
72
  controller.enqueue(createChunk(initial ? `(${getCrossReferenceHeader(id)},${data})` : data));
@@ -65,7 +85,7 @@ export function serializeToJSONStream(value) {
65
85
  return new ReadableStream({
66
86
  start(controller) {
67
87
  toCrossJSONStream(value, {
68
- disabledFeatures: DISABLED_FEATURES,
88
+ disabledFeatures: SERIALIZE_DISABLED_FEATURES,
69
89
  depthLimit: MAX_SERIALIZATION_DEPTH_LIMIT,
70
90
  plugins: DEFAULT_PLUGINS,
71
91
  onParse(node) {
@@ -9,6 +9,6 @@ const assetMap = {
9
9
  noscript: (props) => (<noscript {...props.attrs}>{props.children}</noscript>),
10
10
  };
11
11
  export function renderAsset(asset, nonce) {
12
- let { tag, attrs: { key, ...attrs } = { key: undefined }, children, } = asset;
12
+ let { tag, attrs: { key, ...attrs } = { key: undefined }, children } = asset;
13
13
  return assetMap[tag]({ attrs: { ...attrs, nonce }, key, children });
14
14
  }
@@ -1,6 +1,5 @@
1
- import { H3 } from "h3/generic";
2
1
  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>), routerLoad?: (event: FetchEvent) => Promise<void>): H3;
5
- export declare function createHandler(fn: (context: PageEvent) => JSX.Element, options?: HandlerOptions | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>), routerLoad?: (event: FetchEvent) => Promise<void>): H3;
2
+ import type { FetchEvent, HandlerOptions, PageEvent, StartHandler } from "./types.ts";
3
+ export declare function createBaseHandler(createPageEvent: (e: FetchEvent) => Promise<PageEvent>, fn: (context: PageEvent) => JSX.Element, options?: HandlerOptions | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>), routerLoad?: (event: FetchEvent) => Promise<void>): StartHandler;
4
+ export declare function createHandler(fn: (context: PageEvent) => JSX.Element, options?: HandlerOptions | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>), routerLoad?: (event: FetchEvent) => Promise<void>): StartHandler;
6
5
  export declare function createPageEvent(ctx: FetchEvent): Promise<PageEvent>;
@@ -1,5 +1,5 @@
1
1
  import middleware from "solid-start:middleware";
2
- import { defineHandler, getCookie, H3, redirect, setCookie } from "h3/generic";
2
+ import { defineHandler, getCookie, H3, iterable, redirect, setCookie, } from "h3/generic";
3
3
  import { sharedConfig } from "solid-js";
4
4
  import { getRequestEvent, renderToStream, renderToString } from "solid-js/web";
5
5
  import { createRoutes } from "../router.jsx";
@@ -19,12 +19,7 @@ export function createBaseHandler(createPageEvent, fn, options = {}, routerLoad)
19
19
  const url = new URL(event.request.url);
20
20
  const pathname = stripBaseUrl(url.pathname);
21
21
  if (pathname.startsWith(SERVER_FN_BASE)) {
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
- });
22
+ return await handleServerFunction(e);
28
23
  }
29
24
  const match = matchAPIRoute(pathname, event.request.method);
30
25
  if (match) {
@@ -36,8 +31,6 @@ export function createBaseHandler(createPageEvent, fn, options = {}, routerLoad)
36
31
  sharedConfig.context = { event };
37
32
  const res = await fn(event);
38
33
  if (res !== undefined) {
39
- if (res instanceof Response)
40
- return produceResponseWithEventHeaders(res);
41
34
  return res;
42
35
  }
43
36
  if (event.request.method !== "GET") {
@@ -96,10 +89,9 @@ export function createBaseHandler(createPageEvent, fn, options = {}, routerLoad)
96
89
  }
97
90
  if (mode === "async")
98
91
  return await stream;
99
- delete stream.then;
100
92
  // h3 expects a standard web ReadableStream across runtimes. The adapter
101
93
  // also tolerates cancellation while Solid finishes outstanding work.
102
- return toWebReadableStream(stream);
94
+ return iterable(toWebReadableStream(stream));
103
95
  }),
104
96
  });
105
97
  const app = new H3();
@@ -182,38 +174,6 @@ function handleStreamCompleteRedirect(context) {
182
174
  to && write(`<script>window.location=${JSON.stringify(to).replace(/</g, "\\u003c")}</script>`);
183
175
  };
184
176
  }
185
- function produceResponseWithEventHeaders(res) {
186
- const event = getRequestEvent();
187
- let ret = res;
188
- // Response.redirect returns an immutable value, so we clone on any redirect just in case
189
- if (300 <= res.status && res.status < 400) {
190
- const cookies = res.headers.getSetCookie?.() ?? [];
191
- const headers = new Headers();
192
- res.headers.forEach((value, key) => {
193
- if (key.toLowerCase() !== "set-cookie") {
194
- headers.set(key, value);
195
- }
196
- });
197
- for (const cookie of cookies) {
198
- headers.append("Set-Cookie", cookie);
199
- }
200
- ret = new Response(res.body, {
201
- status: res.status,
202
- statusText: res.statusText,
203
- headers,
204
- });
205
- }
206
- const eventCookies = event.response.headers.getSetCookie?.() ?? [];
207
- for (const cookie of eventCookies) {
208
- ret.headers.append("Set-Cookie", cookie);
209
- }
210
- for (const [name, value] of event.response.headers) {
211
- if (name.toLowerCase() !== "set-cookie") {
212
- ret.headers.set(name, value);
213
- }
214
- }
215
- return ret;
216
- }
217
177
  function stripBaseUrl(path) {
218
178
  const base = import.meta.env.SERVER_BASE_URL || import.meta.env.BASE_URL || "/";
219
179
  return stripPathBase(path, base);
@@ -3,7 +3,7 @@ export { getServerFunctionMeta } from "../shared/serverFunction.ts";
3
3
  export { StartServer } from "./StartServer.tsx";
4
4
  export { decorateHandler, decorateMiddleware } from "./fetchEvent.ts";
5
5
  export { createHandler } from "./handler.ts";
6
- export type { APIEvent, APIHandler, Asset, ContextMatches, DocumentComponentProps, FetchEvent, HandlerOptions, PageEvent, ResponseStub, ServerFunctionMeta, } from "./types.ts";
6
+ export type { APIEvent, APIHandler, Asset, ContextMatches, DocumentComponentProps, FetchEvent, HandlerOptions, PageEvent, ResponseStub, ServerFunctionMeta, StartHandler, } from "./types.ts";
7
7
  /**
8
8
  * Checks if user has set a redirect status in the response.
9
9
  * If not, falls back to the 302 (temporary redirect)
@@ -1,8 +1,7 @@
1
- import type { H3 } from "h3/generic";
2
1
  import type { JSX } from "solid-js";
3
- import type { FetchEvent, HandlerOptions, PageEvent } from "../types.ts";
2
+ import type { FetchEvent, HandlerOptions, PageEvent, StartHandler } from "../types.ts";
4
3
  /**
5
4
  *
6
5
  * Read more: https://docs.solidjs.com/solid-start/reference/server/create-handler
7
6
  */
8
- export declare function createHandler(fn: (context: PageEvent) => JSX.Element, options?: HandlerOptions | ((context: PageEvent) => HandlerOptions), routerLoad?: (event: FetchEvent) => Promise<void>): H3;
7
+ export declare function createHandler(fn: (context: PageEvent) => JSX.Element, options?: HandlerOptions | ((context: PageEvent) => HandlerOptions), routerLoad?: (event: FetchEvent) => Promise<void>): StartHandler;
@@ -1,6 +1,17 @@
1
- import type { H3Event } from "h3";
1
+ import type { H3, H3Event } from "h3";
2
2
  import type { JSX } from "solid-js";
3
3
  import type { RequestEvent } from "solid-js/web";
4
+ /**
5
+ * The h3 app instance returned by `createHandler`.
6
+ *
7
+ * Structurally identical to h3's `H3`, but declared here so that `export default
8
+ * createHandler(...)` in `entry-server.tsx` can be named through `@solidjs/start`.
9
+ * Referring to `H3` directly makes TypeScript emit a reference to h3's internal
10
+ * `H3$1` class, which is not portable when h3 is nested inside
11
+ * `node_modules/@solidjs/start/node_modules` (TS2742 / TS2883).
12
+ */
13
+ export interface StartHandler extends H3 {
14
+ }
4
15
  export type DocumentComponentProps = {
5
16
  assets?: JSX.Element;
6
17
  scripts: JSX.Element;
@@ -5,5 +5,5 @@ type PipeableStream = {
5
5
  }): void;
6
6
  };
7
7
  /** Convert Solid's streaming SSR result into a cancellation-safe web stream. */
8
- export declare function toWebReadableStream(stream: PipeableStream): ReadableStream<Uint8Array>;
8
+ export declare function toWebReadableStream(stream: PipeableStream): ReadableStream<Uint8Array<ArrayBufferLike>>;
9
9
  export {};
@@ -6,8 +6,11 @@ export function toWebReadableStream(stream) {
6
6
  start(controller) {
7
7
  stream.pipe({
8
8
  write(payload) {
9
- if (active)
10
- controller.enqueue(encoder.encode(payload));
9
+ if (!active)
10
+ return;
11
+ // Encoding string to Uint8Array makes sure that
12
+ // the stream can be consumed as Response body
13
+ controller.enqueue(encoder.encode(payload));
11
14
  },
12
15
  end() {
13
16
  if (!active)
@@ -19,7 +19,9 @@ export default function clientOnly(fn, options = {}) {
19
19
  return Comp(rest);
20
20
  const [mounted, setMounted] = createSignal(!sharedConfig.context);
21
21
  onMount(() => setMounted(true));
22
- return createMemo(() => ((Comp = comp()), (m = mounted()), untrack(() => (Comp && m ? Comp(rest) : props.fallback))));
22
+ return createMemo(() => ((Comp = comp()),
23
+ (m = mounted()),
24
+ untrack(() => (Comp && m ? Comp(rest) : props.fallback))));
23
25
  };
24
26
  }
25
27
  function load(fn, setComp) {
@@ -51,7 +51,7 @@ export function CodeView(props) {
51
51
  for (let i = 0, len = lines.length; i < len; i++) {
52
52
  const el = lines[i];
53
53
  if (props.line - minLine() - 1 === i) {
54
- el.dataset.startErrorViewerErrorLine = '';
54
+ el.dataset.startErrorViewerErrorLine = "";
55
55
  }
56
56
  }
57
57
  }
@@ -1,4 +1,4 @@
1
1
  [data-start-blob-viewer] svg {
2
2
  width: 1rem;
3
3
  height: 1rem;
4
- }
4
+ }
@@ -1,5 +1,5 @@
1
- import { type JSX } from 'solid-js';
2
- import './BlobViewer.css';
1
+ import { type JSX } from "solid-js";
2
+ import "./BlobViewer.css";
3
3
  export interface BlobViewerProps {
4
4
  source: Blob | File | Promise<Blob | File>;
5
5
  }
@@ -1,7 +1,7 @@
1
- import { createMemo, createResource, onCleanup, Show, Suspense } from 'solid-js';
1
+ import { createMemo, createResource, onCleanup, Show, Suspense } from "solid-js";
2
2
  import { Badge } from "../../ui/Badge.jsx";
3
3
  import Button from "../../ui/Button.jsx";
4
- import './BlobViewer.css';
4
+ import "./BlobViewer.css";
5
5
  function DocumentIcon(props) {
6
6
  return (<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" {...props}>
7
7
  <title>{props.title}</title>
@@ -23,19 +23,15 @@ function BlobViewerInner(props) {
23
23
  document.body.removeChild(link);
24
24
  }
25
25
  return (<Button data-start-blob-viewer onClick={() => openFileInNewTab()}>
26
- {props.source instanceof File
27
- ? (<Badge type="info">
28
- <DocumentIcon title={props.source.name}/>
29
- {props.source.name}
30
- </Badge>)
31
- : <Badge type="info">{props.source.type}</Badge>}
26
+ {props.source instanceof File ? (<Badge type="info">
27
+ <DocumentIcon title={props.source.name}/>
28
+ {props.source.name}
29
+ </Badge>) : (<Badge type="info">{props.source.type}</Badge>)}
32
30
  </Button>);
33
31
  }
34
32
  export function BlobViewer(props) {
35
33
  const [data] = createResource(() => props.source);
36
34
  return (<Suspense>
37
- <Show when={data()}>
38
- {(current) => <BlobViewerInner source={current()}/>}
39
- </Show>
35
+ <Show when={data()}>{current => <BlobViewerInner source={current()}/>}</Show>
40
36
  </Suspense>);
41
37
  }
@@ -1,4 +1,4 @@
1
- import { type JSX } from 'solid-js';
1
+ import { type JSX } from "solid-js";
2
2
  export interface FormDataViewerProps {
3
3
  source: FormData | Promise<FormData>;
4
4
  }
@@ -1,17 +1,15 @@
1
- import { createResource, For, Show, Suspense } from 'solid-js';
2
- import { Section } from '../../ui/Section.jsx';
3
- import { BlobViewer } from './BlobViewer.jsx';
4
- import { PropertySeparator, SerovalValue } from './SerovalValue.jsx';
1
+ import { createResource, For, Show, Suspense } from "solid-js";
2
+ import { Section } from "../../ui/Section.jsx";
3
+ import { BlobViewer } from "./BlobViewer.jsx";
4
+ import { PropertySeparator, SerovalValue } from "./SerovalValue.jsx";
5
5
  function FormDataViewerInner(props) {
6
- return (<Section title="FormData" options={{ size: 'sm' }}>
6
+ return (<Section title="FormData" options={{ size: "sm" }}>
7
7
  <div data-start-form-data-viewer data-start-properties>
8
8
  <For each={Array.from(props.source.entries())}>
9
9
  {([key, value]) => (<div data-start-property>
10
10
  <SerovalValue value={`"${key}"`}/>
11
11
  <PropertySeparator />
12
- {typeof value === 'string'
13
- ? <SerovalValue value={`"${JSON.stringify(value)}"`}/>
14
- : <BlobViewer source={value}/>}
12
+ {typeof value === "string" ? (<SerovalValue value={`"${JSON.stringify(value)}"`}/>) : (<BlobViewer source={value}/>)}
15
13
  </div>)}
16
14
  </For>
17
15
  </div>
@@ -20,8 +18,6 @@ function FormDataViewerInner(props) {
20
18
  export function FormDataViewer(props) {
21
19
  const [data] = createResource(() => props.source);
22
20
  return (<Suspense>
23
- <Show when={data()}>
24
- {(current) => <FormDataViewerInner source={current()}/>}
25
- </Show>
21
+ <Show when={data()}>{current => <FormDataViewerInner source={current()}/>}</Show>
26
22
  </Suspense>);
27
23
  }
@@ -1,4 +1,4 @@
1
- import './HeadersViewer.css';
1
+ import "./HeadersViewer.css";
2
2
  interface HeadersViewerProps {
3
3
  headers: Headers;
4
4
  }
@@ -1,12 +1,12 @@
1
1
  import { For } from "solid-js";
2
2
  import { PropertySeparator, SerovalValue } from "./SerovalValue.jsx";
3
- import './HeadersViewer.css';
3
+ import "./HeadersViewer.css";
4
4
  import { Text } from "../../ui/Text.jsx";
5
5
  export function HeadersViewer(props) {
6
6
  return (<div data-start-headers-viewer data-start-properties>
7
7
  <For each={Array.from(props.headers.entries())}>
8
8
  {([key, value]) => (<div data-start-property>
9
- <Text options={{ size: 'xs', weight: 'semibold', wrap: 'nowrap' }}>{key}</Text>
9
+ <Text options={{ size: "xs", weight: "semibold", wrap: "nowrap" }}>{key}</Text>
10
10
  <PropertySeparator />
11
11
  <SerovalValue value={value}/>
12
12
  </div>)}
@@ -1,5 +1,5 @@
1
1
  import { type JSX } from "solid-js";
2
- import './HexViewer.css';
2
+ import "./HexViewer.css";
3
3
  interface HexViewerInnerProps {
4
4
  bytes: Uint8Array;
5
5
  }
@@ -1,8 +1,8 @@
1
1
  import { createMemo, createResource, For, Show, Suspense } from "solid-js";
2
2
  import { Text } from "../../ui/Text.jsx";
3
- import './HexViewer.css';
3
+ import "./HexViewer.css";
4
4
  function toHex(num, digits = 2) {
5
- return num.toString(16).padStart(digits, '0').toUpperCase();
5
+ return num.toString(16).padStart(digits, "0").toUpperCase();
6
6
  }
7
7
  function HexChunk(props) {
8
8
  const content = createMemo(() => {
@@ -12,7 +12,7 @@ function HexChunk(props) {
12
12
  const byte4 = props.bytes[3] || 0;
13
13
  return `${toHex(byte1)} ${toHex(byte2)} ${toHex(byte3)} ${toHex(byte4)}`;
14
14
  });
15
- return (<Text data-start-hex-chunk options={{ size: 'xs', weight: 'bold', wrap: 'nowrap' }}>
15
+ return (<Text data-start-hex-chunk options={{ size: "xs", weight: "bold", wrap: "nowrap" }}>
16
16
  {content()}
17
17
  </Text>);
18
18
  }
@@ -42,9 +42,7 @@ function HexText(props) {
42
42
  return result;
43
43
  });
44
44
  return (<div data-start-hex-text>
45
- <Text options={{ size: 'xs', weight: 'bold', wrap: 'nowrap' }}>
46
- {text()}
47
- </Text>
45
+ <Text options={{ size: "xs", weight: "bold", wrap: "nowrap" }}>{text()}</Text>
48
46
  </div>);
49
47
  }
50
48
  export function HexViewerInner(props) {
@@ -57,22 +55,16 @@ export function HexViewerInner(props) {
57
55
  });
58
56
  return (<div data-start-hex-viewer>
59
57
  <div data-start-hex-viewer-bytes>
60
- <For each={rows()}>
61
- {(current) => <HexRow bytes={current}/>}
62
- </For>
58
+ <For each={rows()}>{current => <HexRow bytes={current}/>}</For>
63
59
  </div>
64
60
  <div data-start-hex-viewer-text>
65
- <For each={rows()}>
66
- {(current) => <HexText bytes={current}/>}
67
- </For>
61
+ <For each={rows()}>{current => <HexText bytes={current}/>}</For>
68
62
  </div>
69
63
  </div>);
70
64
  }
71
65
  export function HexViewer(props) {
72
66
  const [data] = createResource(() => props.bytes);
73
67
  return (<Suspense>
74
- <Show when={data()}>
75
- {(current) => <HexViewerInner bytes={current()}/>}
76
- </Show>
68
+ <Show when={data()}>{current => <HexViewerInner bytes={current()}/>}</Show>
77
69
  </Suspense>);
78
70
  }
@@ -1,5 +1,3 @@
1
-
2
-
3
1
  [data-start-seroval-value] {
4
2
  display: flex;
5
3
  gap: 0.25rem;
@@ -1,4 +1,4 @@
1
- import './SerovalValue.css';
1
+ import "./SerovalValue.css";
2
2
  interface SerovalValueProps {
3
3
  value: string | number | boolean | undefined | null;
4
4
  }
@@ -1,10 +1,10 @@
1
1
  import { Text } from "../../ui/Text.jsx";
2
- import './SerovalValue.css';
2
+ import "./SerovalValue.css";
3
3
  export function SerovalValue(props) {
4
- return (<Text data-start-seroval-value options={{ size: 'xs', weight: 'semibold', wrap: 'nowrap' }}>
4
+ return (<Text data-start-seroval-value options={{ size: "xs", weight: "semibold", wrap: "nowrap" }}>
5
5
  {`${props.value}`}
6
6
  </Text>);
7
7
  }
8
8
  export function PropertySeparator() {
9
- return <Text options={{ size: 'xs', weight: 'semibold', wrap: 'nowrap' }}>:</Text>;
9
+ return <Text options={{ size: "xs", weight: "semibold", wrap: "nowrap" }}>:</Text>;
10
10
  }
@@ -68,4 +68,3 @@
68
68
  width: 1rem;
69
69
  height: 1rem;
70
70
  }
71
-
@@ -1,4 +1,4 @@
1
- import { type JSX } from 'solid-js';
1
+ import { type JSX } from "solid-js";
2
2
  export interface URLSearchParamsViewerProps {
3
3
  source: URLSearchParams | Promise<URLSearchParams>;
4
4
  }
@@ -1,8 +1,8 @@
1
- import { createResource, For, Show, Suspense } from 'solid-js';
2
- import { Section } from '../../ui/Section.jsx';
3
- import { PropertySeparator, SerovalValue } from './SerovalValue.jsx';
1
+ import { createResource, For, Show, Suspense } from "solid-js";
2
+ import { Section } from "../../ui/Section.jsx";
3
+ import { PropertySeparator, SerovalValue } from "./SerovalValue.jsx";
4
4
  function URLSearchParamsViewerInner(props) {
5
- return (<Section title="URLSearchParams" options={{ size: 'sm' }}>
5
+ return (<Section title="URLSearchParams" options={{ size: "sm" }}>
6
6
  <div data-start-properties>
7
7
  <For each={Array.from(props.source.entries())}>
8
8
  {([key, value]) => (<div data-start-property>
@@ -17,8 +17,6 @@ function URLSearchParamsViewerInner(props) {
17
17
  export function URLSearchParamsViewer(props) {
18
18
  const [data] = createResource(() => props.source);
19
19
  return (<Suspense>
20
- <Show when={data()}>
21
- {(current) => <URLSearchParamsViewerInner source={current()}/>}
22
- </Show>
20
+ <Show when={data()}>{current => <URLSearchParamsViewerInner source={current()}/>}</Show>
23
21
  </Suspense>);
24
22
  }
@@ -101,7 +101,6 @@
101
101
  }
102
102
 
103
103
  [data-start-function-instance-viewer-content] {
104
-
105
104
  height: 100%;
106
105
  }
107
106
 
@@ -104,6 +104,11 @@ export function DevToolbar(props) {
104
104
  }
105
105
  createEffect(() => {
106
106
  const onErrorEvent = (error) => {
107
+ // Browsers dispatch benign ResizeObserver loop notifications as window
108
+ // "error" events carrying no error object. They aren't app errors.
109
+ if (!error.error && error.message?.startsWith("ResizeObserver loop")) {
110
+ return;
111
+ }
107
112
  pushError(error.error ?? error);
108
113
  };
109
114
  window.addEventListener("error", onErrorEvent);
@@ -27,7 +27,6 @@
27
27
  --foreground: oklch(47.6% 0.114 61.907);
28
28
  }
29
29
 
30
-
31
30
  [data-start-badge="info"] {
32
31
  --background: oklch(97% 0.014 254.604);
33
32
  --foreground: oklch(48.8% 0.243 264.376);
@@ -1,7 +1,7 @@
1
- import type { JSX } from 'solid-js';
2
- import './Badge.css';
1
+ import type { JSX } from "solid-js";
2
+ import "./Badge.css";
3
3
  export interface BadgeProps {
4
- type: 'info' | 'success' | 'failure' | 'warning';
4
+ type: "info" | "success" | "failure" | "warning";
5
5
  children: JSX.Element;
6
6
  }
7
7
  export declare function Badge(props: BadgeProps): JSX.Element;
@@ -1,7 +1,7 @@
1
- import './Badge.css';
2
- import { Text } from './Text.jsx';
1
+ import "./Badge.css";
2
+ import { Text } from "./Text.jsx";
3
3
  export function Badge(props) {
4
- return (<Text options={{ size: 'xs', wrap: 'nowrap', weight: 'semibold' }} data-start-badge={props.type}>
4
+ return (<Text options={{ size: "xs", wrap: "nowrap", weight: "semibold" }} data-start-badge={props.type}>
5
5
  {props.children}
6
6
  </Text>);
7
7
  }
@@ -1,4 +1,4 @@
1
1
  import { Button as BaseButton } from "terracotta";
2
2
  import "./Button.css";
3
- const Button = (props) => (<BaseButton type="button" data-start-button {...props}/>);
3
+ const Button = props => (<BaseButton type="button" data-start-button {...props}/>);
4
4
  export default Button;
@@ -1,4 +1,4 @@
1
- import { Select as BaseSelect, SelectOption as BaseSelectOption, } from "terracotta";
1
+ import { Select as BaseSelect, SelectOption as BaseSelectOption } from "terracotta";
2
2
  import "./Cascade.css";
3
- export const Cascade = (props) => (<BaseSelect data-start-cascade {...props}/>);
4
- export const CascadeOption = (props) => (<BaseSelectOption data-start-cascade-option {...props}/>);
3
+ export const Cascade = props => <BaseSelect data-start-cascade {...props}/>;
4
+ export const CascadeOption = props => (<BaseSelectOption data-start-cascade-option {...props}/>);
@@ -5,8 +5,7 @@
5
5
  overflow-y: auto;
6
6
  }
7
7
 
8
-
9
- [data-start-dialog]>div {
8
+ [data-start-dialog] > div {
10
9
  position: relative;
11
10
  display: flex;
12
11
  align-items: center;
@@ -1,5 +1,5 @@
1
1
  import { Dialog as BaseDialog, DialogOverlay as BaseDialogOverlay, DialogPanel as BaseDialogPanel, } from "terracotta";
2
2
  import "./Dialog.css";
3
- export const Dialog = (props) => (<BaseDialog data-start-dialog {...props}/>);
4
- export const DialogOverlay = (props) => (<BaseDialogOverlay data-start-dialog-overlay {...props}/>);
5
- export const DialogPanel = (props) => (<BaseDialogPanel data-start-dialog-panel {...props}/>);
3
+ export const Dialog = props => <BaseDialog data-start-dialog {...props}/>;
4
+ export const DialogOverlay = props => (<BaseDialogOverlay data-start-dialog-overlay {...props}/>);
5
+ export const DialogPanel = props => (<BaseDialogPanel data-start-dialog-panel {...props}/>);
@@ -1,4 +1,4 @@
1
1
  import { Button as BaseButton } from "terracotta";
2
2
  import "./IconButton.css";
3
- const IconButton = (props) => (<BaseButton type="button" data-start-icon-button {...props}/>);
3
+ const IconButton = props => (<BaseButton type="button" data-start-icon-button {...props}/>);
4
4
  export default IconButton;
@@ -9,4 +9,4 @@
9
9
 
10
10
  [data-start-placeholder] > span {
11
11
  text-align: center;
12
- }
12
+ }
@@ -1,5 +1,5 @@
1
- import type { JSX } from 'solid-js';
2
- import './Placeholder.css';
1
+ import type { JSX } from "solid-js";
2
+ import "./Placeholder.css";
3
3
  export interface PlaceholderProps {
4
4
  children?: JSX.Element;
5
5
  }
@@ -1,6 +1,4 @@
1
- import './Placeholder.css';
1
+ import "./Placeholder.css";
2
2
  export default function Placeholder(props) {
3
- return (<div data-start-placeholder>
4
- {props.children}
5
- </div>);
3
+ return <div data-start-placeholder>{props.children}</div>;
6
4
  }
@@ -7,7 +7,6 @@
7
7
  text-transform: uppercase;
8
8
  }
9
9
 
10
-
11
10
  [data-start-section-content] {
12
11
  margin-left: 0.5rem;
13
12
  padding-left: 0.5rem;
@@ -1,9 +1,9 @@
1
1
  import type { JSX } from "solid-js";
2
2
  import { type TextProps } from "./Text.tsx";
3
- import './Section.css';
3
+ import "./Section.css";
4
4
  export interface SectionProps {
5
5
  title: string;
6
- options?: TextProps<'span'>['options'];
6
+ options?: TextProps<"span">["options"];
7
7
  children: JSX.Element;
8
8
  }
9
9
  export declare function Section(props: SectionProps): JSX.Element;
@@ -1,12 +1,10 @@
1
1
  import { Text } from "./Text.jsx";
2
- import './Section.css';
2
+ import "./Section.css";
3
3
  export function Section(props) {
4
4
  return (<div data-start-section>
5
- <Text data-start-section-title options={{ weight: 'bold', font: 'sans', ...props.options }}>
5
+ <Text data-start-section-title options={{ weight: "bold", font: "sans", ...props.options }}>
6
6
  {props.title}
7
7
  </Text>
8
- <div data-start-section-content>
9
- {props.children}
10
- </div>
8
+ <div data-start-section-content>{props.children}</div>
11
9
  </div>);
12
10
  }
@@ -1,4 +1,4 @@
1
- import { Select as BaseSelect, SelectOption as BaseSelectOption, } from "terracotta";
1
+ import { Select as BaseSelect, SelectOption as BaseSelectOption } from "terracotta";
2
2
  import "./Select.css";
3
- export const Select = (props) => (<BaseSelect data-start-select {...props}/>);
4
- export const SelectOption = (props) => (<BaseSelectOption data-start-select-option {...props}/>);
3
+ export const Select = props => <BaseSelect data-start-select {...props}/>;
4
+ export const SelectOption = props => (<BaseSelectOption data-start-select-option {...props}/>);
@@ -1,11 +1,11 @@
1
- import type { ComponentProps, JSX } from 'solid-js';
2
- import './Table.css';
3
- type TableProps = ComponentProps<'div'>;
1
+ import type { ComponentProps, JSX } from "solid-js";
2
+ import "./Table.css";
3
+ type TableProps = ComponentProps<"div">;
4
4
  export declare function Table(props: TableProps): JSX.Element;
5
- type TableHeaderProps = ComponentProps<'div'>;
5
+ type TableHeaderProps = ComponentProps<"div">;
6
6
  export declare function TableHeader(props: TableHeaderProps): JSX.Element;
7
- type TableRowProps = ComponentProps<'div'>;
7
+ type TableRowProps = ComponentProps<"div">;
8
8
  export declare function TableRow(props: TableRowProps): JSX.Element;
9
- type TableCellProps = ComponentProps<'div'>;
9
+ type TableCellProps = ComponentProps<"div">;
10
10
  export declare function TableCell(props: TableCellProps): JSX.Element;
11
11
  export {};
@@ -1,13 +1,13 @@
1
- import './Table.css';
1
+ import "./Table.css";
2
2
  export function Table(props) {
3
- return (<div data-start-table {...props}/>);
3
+ return <div data-start-table {...props}/>;
4
4
  }
5
5
  export function TableHeader(props) {
6
- return (<div data-start-table-header {...props}/>);
6
+ return <div data-start-table-header {...props}/>;
7
7
  }
8
8
  export function TableRow(props) {
9
- return (<div data-start-table-row {...props}/>);
9
+ return <div data-start-table-row {...props}/>;
10
10
  }
11
11
  export function TableCell(props) {
12
- return (<div data-start-table-cell {...props}/>);
12
+ return <div data-start-table-cell {...props}/>;
13
13
  }
@@ -1,6 +1,6 @@
1
1
  import { Tab as BaseTab, TabGroup as BaseTabGroup, TabList as BaseTabList, TabPanel as BaseTabPanel, } from "terracotta";
2
2
  import "./Tabs.css";
3
- export const Tab = (props) => (<BaseTab data-start-tab {...props}/>);
4
- export const TabGroup = (props) => (<BaseTabGroup data-start-tab-group {...props}/>);
5
- export const TabPanel = (props) => (<BaseTabPanel data-start-tab-panel {...props}/>);
6
- export const TabList = (props) => (<BaseTabList data-start-tab-list {...props}/>);
3
+ export const Tab = props => <BaseTab data-start-tab {...props}/>;
4
+ export const TabGroup = props => (<BaseTabGroup data-start-tab-group {...props}/>);
5
+ export const TabPanel = props => (<BaseTabPanel data-start-tab-panel {...props}/>);
6
+ export const TabList = props => <BaseTabList data-start-tab-list {...props}/>;
@@ -24,13 +24,17 @@
24
24
  }
25
25
 
26
26
  [data-start-text-font="sans"] {
27
- font-family: system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
27
+ font-family:
28
+ system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
29
+ "Noto Color Emoji";
28
30
  }
29
31
  [data-start-text-font="serif"] {
30
- font-family: ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif;
32
+ font-family: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
31
33
  }
32
34
  [data-start-text-font="mono"] {
33
- font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
35
+ font-family:
36
+ ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New",
37
+ monospace;
34
38
  }
35
39
 
36
40
  [data-start-text-weight="thin"] {
@@ -1,12 +1,12 @@
1
- import { type ComponentProps, type JSX } from 'solid-js';
2
- import './Text.css';
3
- export type TextProps<T extends keyof JSX.IntrinsicElements = 'span'> = ComponentProps<T> & {
1
+ import { type ComponentProps, type JSX } from "solid-js";
2
+ import "./Text.css";
3
+ export type TextProps<T extends keyof JSX.IntrinsicElements = "span"> = ComponentProps<T> & {
4
4
  options?: {
5
5
  as?: T;
6
- size?: 'xs' | 'sm' | 'base' | 'lg' | 'xl' | '2xl';
7
- font?: 'sans' | 'serif' | 'mono';
8
- weight?: 'thin' | 'extralight' | 'light' | 'normal' | 'medium' | 'semibold' | 'bold' | 'extrabold';
9
- wrap?: 'wrap' | 'nowrap';
6
+ size?: "xs" | "sm" | "base" | "lg" | "xl" | "2xl";
7
+ font?: "sans" | "serif" | "mono";
8
+ weight?: "thin" | "extralight" | "light" | "normal" | "medium" | "semibold" | "bold" | "extrabold";
9
+ wrap?: "wrap" | "nowrap";
10
10
  };
11
11
  };
12
- export declare function Text<T extends keyof JSX.IntrinsicElements = 'span'>(props: TextProps<T>): JSX.Element;
12
+ export declare function Text<T extends keyof JSX.IntrinsicElements = "span">(props: TextProps<T>): JSX.Element;
@@ -1,17 +1,17 @@
1
- import { createMemo, splitProps } from 'solid-js';
2
- import { Dynamic } from 'solid-js/web';
3
- import './Text.css';
1
+ import { createMemo, splitProps } from "solid-js";
2
+ import { Dynamic } from "solid-js/web";
3
+ import "./Text.css";
4
4
  export function Text(props) {
5
- const [current, rest] = splitProps(props, ['options']);
5
+ const [current, rest] = splitProps(props, ["options"]);
6
6
  const customization = createMemo(() => {
7
7
  const options = Object.assign({}, {
8
- size: 'base',
9
- font: 'mono',
10
- weight: 'normal',
11
- wrap: 'wrap',
8
+ size: "base",
9
+ font: "mono",
10
+ weight: "normal",
11
+ wrap: "wrap",
12
12
  }, current.options);
13
13
  const entries = Object.entries(options);
14
14
  return Object.fromEntries(entries.map(([key, value]) => [`data-start-text-${key}`, value]));
15
15
  });
16
- return (<Dynamic component={(current.options?.as || 'span')} {...rest} {...customization()}/>);
16
+ return (<Dynamic component={(current.options?.as || "span")} {...rest} {...customization()}/>);
17
17
  }
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@solidjs/start",
3
- "version": "2.0.0-rc.2",
4
- "type": "module",
5
- "files": [
6
- "dist",
7
- "env.d.ts",
8
- "CHANGELOG.md"
9
- ],
3
+ "version": "2.0.0-rc.4",
10
4
  "repository": {
11
5
  "type": "git",
12
6
  "url": "git+https://github.com/solidjs/solid-start.git",
13
7
  "directory": "packages/start"
14
8
  },
9
+ "files": [
10
+ "dist",
11
+ "env.d.ts",
12
+ "CHANGELOG.md"
13
+ ],
14
+ "type": "module",
15
15
  "exports": {
16
16
  ".": "./dist/index.jsx",
17
17
  "./config": "./dist/config/index.js",
@@ -30,44 +30,44 @@
30
30
  "access": "public"
31
31
  },
32
32
  "dependencies": {
33
- "@babel/core": "^7.29.0",
34
- "@babel/traverse": "^7.29.0",
35
- "@babel/types": "^7.29.0",
33
+ "@babel/core": "^7.29.7",
34
+ "@babel/traverse": "^7.29.7",
35
+ "@babel/types": "^7.29.7",
36
36
  "@solidjs/meta": "^0.29.4",
37
37
  "@types/babel__traverse": "^7.28.0",
38
38
  "@types/micromatch": "^4.0.10",
39
- "cookie-es": "^2.0.0",
40
- "defu": "^6.1.4",
39
+ "cookie-es": "^3.1.1",
40
+ "defu": "^6.1.7",
41
41
  "error-stack-parser": "^2.1.4",
42
42
  "fast-glob": "^3.3.3",
43
- "h3": "^2.0.1-rc.25",
43
+ "h3": "^2.0.1-rc.26",
44
44
  "html-to-image": "^1.11.13",
45
45
  "micromatch": "^4.0.8",
46
- "oxc-parser": "^0.139.0",
47
- "path-to-regexp": "^8.3.0",
46
+ "oxc-parser": "^0.141.0",
47
+ "path-to-regexp": "^8.4.2",
48
48
  "pathe": "^2.0.3",
49
49
  "radix3": "^1.1.2",
50
- "seroval": "^1.5.4",
51
- "seroval-plugins": "^1.5.1",
52
- "shiki": "^1.29.2",
53
- "solid-js": "^1.9.11",
50
+ "seroval": "^1.5.6",
51
+ "seroval-plugins": "^1.5.6",
52
+ "shiki": "^4.3.1",
53
+ "solid-js": "^1.9.14",
54
54
  "source-map-js": "^1.2.1",
55
- "srvx": "^0.12.0",
55
+ "srvx": "^0.12.4",
56
56
  "terracotta": "^1.1.1",
57
- "vite-plugin-solid": "^2.11.11"
58
- },
59
- "engines": {
60
- "node": ">=24"
57
+ "vite-plugin-solid": "^2.11.13"
61
58
  },
62
59
  "devDependencies": {
63
60
  "@types/babel__core": "^7.20.5",
64
- "@types/node": "^25.5.0",
65
- "vite": "^8.0.0",
66
- "vitest": "^4.1.0"
61
+ "@types/node": "^26.1.1",
62
+ "vite": "^8.1.5",
63
+ "vitest": "^4.1.10"
67
64
  },
68
65
  "peerDependencies": {
69
66
  "vite": "^8 || ^9"
70
67
  },
68
+ "engines": {
69
+ "node": ">=24"
70
+ },
71
71
  "scripts": {
72
72
  "build": "pnpm validate-imports && tsc && node scripts/build.js",
73
73
  "dev": "tsc --watch",