@solidjs/start 2.0.0-rc.3 → 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 (49) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/config/env.js +2 -2
  3. package/dist/config/manifest.js +3 -2
  4. package/dist/directives/remove-unused-variables.js +2 -2
  5. package/dist/directives/xxhash32.js +5 -13
  6. package/dist/fns/handler.js +9 -8
  7. package/dist/fns/serialization.js +21 -1
  8. package/dist/server/assets/render.jsx +1 -1
  9. package/dist/shared/clientOnly.js +3 -1
  10. package/dist/shared/dev-toolbar/error-viewer/CodeView.jsx +1 -1
  11. package/dist/shared/dev-toolbar/functions/BlobViewer.css +1 -1
  12. package/dist/shared/dev-toolbar/functions/BlobViewer.d.ts +2 -2
  13. package/dist/shared/dev-toolbar/functions/BlobViewer.jsx +7 -11
  14. package/dist/shared/dev-toolbar/functions/FormDataViewer.d.ts +1 -1
  15. package/dist/shared/dev-toolbar/functions/FormDataViewer.jsx +7 -11
  16. package/dist/shared/dev-toolbar/functions/HeadersViewer.d.ts +1 -1
  17. package/dist/shared/dev-toolbar/functions/HeadersViewer.jsx +2 -2
  18. package/dist/shared/dev-toolbar/functions/HexViewer.d.ts +1 -1
  19. package/dist/shared/dev-toolbar/functions/HexViewer.jsx +7 -15
  20. package/dist/shared/dev-toolbar/functions/SerovalValue.css +0 -2
  21. package/dist/shared/dev-toolbar/functions/SerovalValue.d.ts +1 -1
  22. package/dist/shared/dev-toolbar/functions/SerovalValue.jsx +3 -3
  23. package/dist/shared/dev-toolbar/functions/SerovalViewer.css +0 -1
  24. package/dist/shared/dev-toolbar/functions/URLSearchParamsViewer.d.ts +1 -1
  25. package/dist/shared/dev-toolbar/functions/URLSearchParamsViewer.jsx +5 -7
  26. package/dist/shared/dev-toolbar/functions/styles.css +0 -1
  27. package/dist/shared/dev-toolbar/index.jsx +5 -0
  28. package/dist/shared/ui/Badge.css +0 -1
  29. package/dist/shared/ui/Badge.d.ts +3 -3
  30. package/dist/shared/ui/Badge.jsx +3 -3
  31. package/dist/shared/ui/Button.jsx +1 -1
  32. package/dist/shared/ui/Cascade.jsx +3 -3
  33. package/dist/shared/ui/Dialog.css +1 -2
  34. package/dist/shared/ui/Dialog.jsx +3 -3
  35. package/dist/shared/ui/IconButton.jsx +1 -1
  36. package/dist/shared/ui/Placeholder.css +1 -1
  37. package/dist/shared/ui/Placeholder.d.ts +2 -2
  38. package/dist/shared/ui/Placeholder.jsx +2 -4
  39. package/dist/shared/ui/Section.css +0 -1
  40. package/dist/shared/ui/Section.d.ts +2 -2
  41. package/dist/shared/ui/Section.jsx +3 -5
  42. package/dist/shared/ui/Select.jsx +3 -3
  43. package/dist/shared/ui/Table.d.ts +6 -6
  44. package/dist/shared/ui/Table.jsx +5 -5
  45. package/dist/shared/ui/Tabs.jsx +4 -4
  46. package/dist/shared/ui/Text.css +7 -3
  47. package/dist/shared/ui/Text.d.ts +8 -8
  48. package/dist/shared/ui/Text.jsx +9 -9
  49. package/package.json +26 -26
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
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
+
3
11
  ## 2.0.0-rc.3
4
12
 
5
13
  ### Patch 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) {
@@ -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
  }
@@ -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.3",
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
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",