@solidjs/start 2.0.0-beta.9 → 2.0.0-rc.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +149 -1
- package/dist/config/app-root-alias.d.ts +7 -0
- package/dist/config/app-root-alias.js +58 -0
- package/dist/config/constants.d.ts +2 -0
- package/dist/config/constants.js +2 -0
- package/dist/config/env.js +13 -10
- package/dist/config/fs-routes/index.js +3 -3
- package/dist/config/fs-routes/tree-shake.d.ts +27 -0
- package/dist/config/fs-routes/tree-shake.js +226 -33
- package/dist/config/index.d.ts +154 -5
- package/dist/config/index.js +23 -10
- package/dist/config/lazy.js +7 -2
- package/dist/config/manifest.d.ts +3 -0
- package/dist/config/manifest.js +26 -4
- package/dist/directives/remove-unused-variables.js +15 -3
- package/dist/directives/xxhash32.js +5 -13
- package/dist/fns/client.js +14 -5
- package/dist/fns/error-handler.d.ts +34 -0
- package/dist/fns/error-handler.js +10 -0
- package/dist/fns/handler.d.ts +1 -1
- package/dist/fns/handler.js +58 -12
- package/dist/fns/plugins.d.ts +34 -0
- package/dist/fns/plugins.js +33 -0
- package/dist/fns/serialization.d.ts +15 -0
- package/dist/fns/serialization.js +36 -6
- package/dist/middleware/index.js +4 -1
- package/dist/server/StartServer.jsx +1 -1
- package/dist/server/assets/render.jsx +1 -1
- package/dist/server/collect-styles.d.ts +3 -1
- package/dist/server/collect-styles.js +8 -5
- package/dist/server/fetchEvent.d.ts +10 -0
- package/dist/server/fetchEvent.js +10 -0
- package/dist/server/handler.d.ts +3 -4
- package/dist/server/handler.js +22 -56
- package/dist/server/index.d.ts +3 -1
- package/dist/server/index.jsx +1 -0
- package/dist/server/manifest/dev-client-manifest.js +1 -1
- package/dist/server/manifest/dev-ssr-manifest.js +1 -1
- package/dist/server/spa/StartServer.jsx +1 -1
- package/dist/server/spa/handler.d.ts +2 -3
- package/dist/server/spa/handler.js +2 -2
- package/dist/server/strip-path-base.d.ts +1 -0
- package/dist/server/strip-path-base.js +10 -0
- package/dist/server/types.d.ts +12 -1
- package/dist/server/web-stream.d.ts +9 -0
- package/dist/server/web-stream.js +29 -0
- package/dist/shared/ErrorBoundary.jsx +3 -3
- package/dist/shared/clientOnly.js +3 -1
- package/dist/shared/{dev-overlay → dev-toolbar/error-viewer}/CodeView.jsx +3 -3
- package/dist/shared/dev-toolbar/error-viewer/create-stack-frame.js +90 -0
- package/dist/shared/{dev-overlay/DevOverlayDialog.d.ts → dev-toolbar/error-viewer/index.d.ts} +3 -2
- package/dist/shared/{dev-overlay/DevOverlayDialog.jsx → dev-toolbar/error-viewer/index.jsx} +66 -77
- package/dist/shared/dev-toolbar/error-viewer/styles.css +224 -0
- package/dist/shared/dev-toolbar/functions/BlobViewer.css +4 -0
- package/dist/shared/dev-toolbar/functions/BlobViewer.d.ts +6 -0
- package/dist/shared/dev-toolbar/functions/BlobViewer.jsx +37 -0
- package/dist/shared/dev-toolbar/functions/FormDataViewer.d.ts +5 -0
- package/dist/shared/dev-toolbar/functions/FormDataViewer.jsx +23 -0
- package/dist/shared/dev-toolbar/functions/HeadersViewer.css +8 -0
- package/dist/shared/dev-toolbar/functions/HeadersViewer.d.ts +6 -0
- package/dist/shared/dev-toolbar/functions/HeadersViewer.jsx +15 -0
- package/dist/shared/dev-toolbar/functions/HexViewer.css +34 -0
- package/dist/shared/dev-toolbar/functions/HexViewer.d.ts +11 -0
- package/dist/shared/dev-toolbar/functions/HexViewer.jsx +70 -0
- package/dist/shared/dev-toolbar/functions/SerovalValue.css +5 -0
- package/dist/shared/dev-toolbar/functions/SerovalValue.d.ts +7 -0
- package/dist/shared/dev-toolbar/functions/SerovalValue.jsx +10 -0
- package/dist/shared/dev-toolbar/functions/SerovalViewer.css +70 -0
- package/dist/shared/dev-toolbar/functions/SerovalViewer.d.ts +6 -0
- package/dist/shared/dev-toolbar/functions/SerovalViewer.jsx +796 -0
- package/dist/shared/dev-toolbar/functions/URLSearchParamsViewer.d.ts +5 -0
- package/dist/shared/dev-toolbar/functions/URLSearchParamsViewer.jsx +22 -0
- package/dist/shared/dev-toolbar/functions/index.d.ts +13 -0
- package/dist/shared/dev-toolbar/functions/index.jsx +216 -0
- package/dist/shared/dev-toolbar/functions/styles.css +109 -0
- package/dist/shared/dev-toolbar/functions/tracker.d.ts +19 -0
- package/dist/shared/dev-toolbar/functions/tracker.js +29 -0
- package/dist/shared/{dev-overlay → dev-toolbar}/icons.d.ts +9 -0
- package/dist/shared/{dev-overlay → dev-toolbar}/icons.jsx +19 -1
- package/dist/shared/dev-toolbar/index.css +88 -0
- package/dist/shared/dev-toolbar/index.d.ts +6 -0
- package/dist/shared/dev-toolbar/index.jsx +179 -0
- package/dist/shared/ui/Badge.css +33 -0
- package/dist/shared/ui/Badge.d.ts +7 -0
- package/dist/shared/ui/Badge.jsx +7 -0
- package/dist/shared/ui/Button.css +32 -0
- package/dist/shared/ui/Button.d.ts +4 -0
- package/dist/shared/ui/Button.jsx +4 -0
- package/dist/shared/ui/Cascade.css +29 -0
- package/dist/shared/ui/Cascade.d.ts +4 -0
- package/dist/shared/ui/Cascade.jsx +4 -0
- package/dist/shared/ui/Dialog.css +25 -0
- package/dist/shared/ui/Dialog.d.ts +5 -0
- package/dist/shared/ui/Dialog.jsx +5 -0
- package/dist/shared/ui/IconButton.css +39 -0
- package/dist/shared/ui/IconButton.d.ts +4 -0
- package/dist/shared/ui/IconButton.jsx +4 -0
- package/dist/shared/ui/Placeholder.css +12 -0
- package/dist/shared/ui/Placeholder.d.ts +6 -0
- package/dist/shared/ui/Placeholder.jsx +4 -0
- package/dist/shared/ui/Section.css +18 -0
- package/dist/shared/ui/Section.d.ts +9 -0
- package/dist/shared/ui/Section.jsx +10 -0
- package/dist/shared/ui/Select.css +37 -0
- package/dist/shared/ui/Select.d.ts +4 -0
- package/dist/shared/ui/Select.jsx +4 -0
- package/dist/shared/ui/Table.css +22 -0
- package/dist/shared/ui/Table.d.ts +11 -0
- package/dist/shared/ui/Table.jsx +13 -0
- package/dist/shared/ui/Tabs.css +51 -0
- package/dist/shared/ui/Tabs.d.ts +6 -0
- package/dist/shared/ui/Tabs.jsx +6 -0
- package/dist/shared/ui/Text.css +73 -0
- package/dist/shared/ui/Text.d.ts +12 -0
- package/dist/shared/ui/Text.jsx +17 -0
- package/package.json +36 -29
- package/dist/shared/dev-overlay/createStackFrame.js +0 -56
- package/dist/shared/dev-overlay/index.d.ts +0 -5
- package/dist/shared/dev-overlay/index.jsx +0 -39
- package/dist/shared/dev-overlay/styles.css +0 -292
- /package/dist/shared/{dev-overlay → dev-toolbar/error-viewer}/CodeView.d.ts +0 -0
- /package/dist/shared/{dev-overlay/createStackFrame.d.ts → dev-toolbar/error-viewer/create-stack-frame.d.ts} +0 -0
- /package/dist/shared/{dev-overlay → dev-toolbar/error-viewer}/download.d.ts +0 -0
- /package/dist/shared/{dev-overlay → dev-toolbar/error-viewer}/download.js +0 -0
- /package/dist/shared/{dev-overlay → dev-toolbar/error-viewer}/get-source-map.d.ts +0 -0
- /package/dist/shared/{dev-overlay → dev-toolbar/error-viewer}/get-source-map.js +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { crossSerializeStream, deserialize, Feature, fromCrossJSON, getCrossReferenceHeader, toCrossJSONStream, } from "seroval";
|
|
2
2
|
import { AbortSignalPlugin, CustomEventPlugin, DOMExceptionPlugin, EventPlugin, FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLPlugin, URLSearchParamsPlugin, } from "seroval-plugins/web";
|
|
3
|
-
|
|
3
|
+
import userPlugins from "solid-start:seroval-plugins";
|
|
4
4
|
const DEFAULT_PLUGINS = [
|
|
5
5
|
AbortSignalPlugin,
|
|
6
6
|
CustomEventPlugin,
|
|
@@ -14,8 +14,37 @@ const DEFAULT_PLUGINS = [
|
|
|
14
14
|
URLSearchParamsPlugin,
|
|
15
15
|
URLPlugin,
|
|
16
16
|
];
|
|
17
|
+
/**
|
|
18
|
+
* Plugins from `serialization.plugins` are appended rather than prepended:
|
|
19
|
+
* seroval picks the first plugin whose `test()` passes, so the built-ins win
|
|
20
|
+
* and a loose user `test()` can't take over `Request`/`FormData`/`URL`.
|
|
21
|
+
*
|
|
22
|
+
* The same list has to be used on both ends of a server function, which is why
|
|
23
|
+
* this comes from a virtual module bundled into the client and the server
|
|
24
|
+
* rather than a runtime option.
|
|
25
|
+
*/
|
|
26
|
+
const PLUGINS = [...DEFAULT_PLUGINS, ...userPlugins];
|
|
17
27
|
const MAX_SERIALIZATION_DEPTH_LIMIT = 64;
|
|
18
28
|
const DISABLED_FEATURES = Feature.RegExp;
|
|
29
|
+
/**
|
|
30
|
+
* An error thrown by a server function is serialized and rethrown on the
|
|
31
|
+
* client, and seroval includes `Error.prototype.stack` by default. In
|
|
32
|
+
* production that leaks server file paths, internal function names and the
|
|
33
|
+
* shape of the deployment to anyone who can trigger a throw, so strip it.
|
|
34
|
+
* Development keeps the stack: that's where it's actually useful, and the
|
|
35
|
+
* paths it exposes are the developer's own.
|
|
36
|
+
*
|
|
37
|
+
* Only applied when writing; parsing leaves `DISABLED_FEATURES` alone so an
|
|
38
|
+
* incoming payload that does carry a stack still deserializes.
|
|
39
|
+
*/
|
|
40
|
+
const SERIALIZE_DISABLED_FEATURES = import.meta.env.PROD
|
|
41
|
+
? DISABLED_FEATURES | Feature.ErrorPrototypeStack
|
|
42
|
+
: DISABLED_FEATURES;
|
|
43
|
+
/**
|
|
44
|
+
* `crossSerializeStream` historically ran with every feature enabled, so only
|
|
45
|
+
* add the stack removal here rather than the full serialize set.
|
|
46
|
+
*/
|
|
47
|
+
const JS_SERIALIZE_DISABLED_FEATURES = import.meta.env.PROD ? Feature.ErrorPrototypeStack : 0;
|
|
19
48
|
/**
|
|
20
49
|
* Alexis:
|
|
21
50
|
*
|
|
@@ -47,7 +76,8 @@ export function serializeToJSStream(id, value) {
|
|
|
47
76
|
start(controller) {
|
|
48
77
|
crossSerializeStream(value, {
|
|
49
78
|
scopeId: id,
|
|
50
|
-
|
|
79
|
+
disabledFeatures: JS_SERIALIZE_DISABLED_FEATURES,
|
|
80
|
+
plugins: PLUGINS,
|
|
51
81
|
onSerialize(data, initial) {
|
|
52
82
|
controller.enqueue(createChunk(initial ? `(${getCrossReferenceHeader(id)},${data})` : data));
|
|
53
83
|
},
|
|
@@ -65,9 +95,9 @@ export function serializeToJSONStream(value) {
|
|
|
65
95
|
return new ReadableStream({
|
|
66
96
|
start(controller) {
|
|
67
97
|
toCrossJSONStream(value, {
|
|
68
|
-
disabledFeatures:
|
|
98
|
+
disabledFeatures: SERIALIZE_DISABLED_FEATURES,
|
|
69
99
|
depthLimit: MAX_SERIALIZATION_DEPTH_LIMIT,
|
|
70
|
-
plugins:
|
|
100
|
+
plugins: PLUGINS,
|
|
71
101
|
onParse(node) {
|
|
72
102
|
controller.enqueue(createChunk(JSON.stringify(node)));
|
|
73
103
|
},
|
|
@@ -81,7 +111,7 @@ export function serializeToJSONStream(value) {
|
|
|
81
111
|
},
|
|
82
112
|
});
|
|
83
113
|
}
|
|
84
|
-
class SerovalChunkReader {
|
|
114
|
+
export class SerovalChunkReader {
|
|
85
115
|
reader;
|
|
86
116
|
buffer;
|
|
87
117
|
done;
|
|
@@ -180,7 +210,7 @@ export async function deserializeJSONStream(response) {
|
|
|
180
210
|
refs,
|
|
181
211
|
disabledFeatures: DISABLED_FEATURES,
|
|
182
212
|
depthLimit: MAX_SERIALIZATION_DEPTH_LIMIT,
|
|
183
|
-
plugins:
|
|
213
|
+
plugins: PLUGINS,
|
|
184
214
|
});
|
|
185
215
|
return value;
|
|
186
216
|
}
|
package/dist/middleware/index.js
CHANGED
|
@@ -54,7 +54,10 @@ export function createMiddleware(args) {
|
|
|
54
54
|
mw.push(wrapResponseMiddleware(args.onBeforeResponse));
|
|
55
55
|
}
|
|
56
56
|
else if (Array.isArray(args.onBeforeResponse)) {
|
|
57
|
-
|
|
57
|
+
// h3 middleware compose onion-style: logic after `await next()` unwinds
|
|
58
|
+
// innermost-first (reverse registration order). Register the wrappers
|
|
59
|
+
// reversed so onBeforeResponse functions run in their declared order.
|
|
60
|
+
mw.push(...args.onBeforeResponse.map(wrapResponseMiddleware).reverse());
|
|
58
61
|
}
|
|
59
62
|
return mw;
|
|
60
63
|
}
|
|
@@ -19,7 +19,7 @@ export function StartServer(props) {
|
|
|
19
19
|
<TopErrorBoundary>
|
|
20
20
|
<props.document assets={<HydrationScript />} scripts={<>
|
|
21
21
|
<PatchVirtualDevStyles nonce={nonce}/>
|
|
22
|
-
<script type="module" nonce={nonce} async src={getSsrManifest("client").path(import.meta.env.
|
|
22
|
+
<script type="module" nonce={nonce} async src={getSsrManifest("client").path(import.meta.env.START_CLIENT_ENTRY_URL)}/>
|
|
23
23
|
</>}>
|
|
24
24
|
{!import.meta.env.START_ISLANDS ? (<Hydration>
|
|
25
25
|
<ErrorBoundary>
|
|
@@ -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
|
|
12
|
+
let { tag, attrs: { key, ...attrs } = { key: undefined }, children } = asset;
|
|
13
13
|
return assetMap[tag]({ attrs: { ...attrs, nonce }, key, children });
|
|
14
14
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import type { DevEnvironment } from "vite";
|
|
2
|
+
type StyleFilter = (id: string) => boolean;
|
|
2
3
|
export declare const isCssModulesFile: (file: string) => boolean;
|
|
3
|
-
export declare function findStylesInModuleGraph(vite: DevEnvironment, id: string): Promise<Record<string, any>>;
|
|
4
|
+
export declare function findStylesInModuleGraph(vite: DevEnvironment, id: string, filter: StyleFilter): Promise<Record<string, any>>;
|
|
5
|
+
export {};
|
|
@@ -8,13 +8,16 @@ async function getViteModuleNode(vite, file, importer) {
|
|
|
8
8
|
}
|
|
9
9
|
catch (err) { }
|
|
10
10
|
}
|
|
11
|
-
async function findModuleDependencies(vite, file, deps, crawledFiles = new Set(), importer) {
|
|
11
|
+
async function findModuleDependencies(vite, file, deps, filter, crawledFiles = new Set(), importer) {
|
|
12
12
|
crawledFiles.add(file);
|
|
13
13
|
const module = await getViteModuleNode(vite, file, importer);
|
|
14
14
|
if (!module?.id || deps.has(module))
|
|
15
15
|
return;
|
|
16
16
|
deps.add(module);
|
|
17
|
-
if (module.url.endsWith(".css")
|
|
17
|
+
if (module.url.endsWith(".css"))
|
|
18
|
+
return;
|
|
19
|
+
// Apply user-config file filters only to real files (virtual modules should always be included)
|
|
20
|
+
if (module.file && !module.id.startsWith("\0") && !filter(module.file))
|
|
18
21
|
return;
|
|
19
22
|
if (!module.transformResult) {
|
|
20
23
|
await vite.transformRequest(module.id).catch(() => { });
|
|
@@ -28,7 +31,7 @@ async function findModuleDependencies(vite, file, deps, crawledFiles = new Set()
|
|
|
28
31
|
if (crawledFiles.has(dep)) {
|
|
29
32
|
continue;
|
|
30
33
|
}
|
|
31
|
-
await findModuleDependencies(vite, dep, deps, crawledFiles, module.id);
|
|
34
|
+
await findModuleDependencies(vite, dep, deps, filter, crawledFiles, module.id);
|
|
32
35
|
}
|
|
33
36
|
}
|
|
34
37
|
// Vite doesn't expose these so we just copy the list for now
|
|
@@ -38,11 +41,11 @@ const cssFileRegExp = /\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)$/;
|
|
|
38
41
|
const cssModulesRegExp = new RegExp(`\\.module${cssFileRegExp.source}`);
|
|
39
42
|
const isCssFile = (file) => cssFileRegExp.test(file);
|
|
40
43
|
export const isCssModulesFile = (file) => cssModulesRegExp.test(file);
|
|
41
|
-
export async function findStylesInModuleGraph(vite, id) {
|
|
44
|
+
export async function findStylesInModuleGraph(vite, id, filter) {
|
|
42
45
|
const absolute = path.resolve(process.cwd(), id);
|
|
43
46
|
const dependencies = new Set();
|
|
44
47
|
try {
|
|
45
|
-
await findModuleDependencies(vite, absolute, dependencies);
|
|
48
|
+
await findModuleDependencies(vite, absolute, dependencies, filter);
|
|
46
49
|
}
|
|
47
50
|
catch (e) {
|
|
48
51
|
console.error(e);
|
|
@@ -3,5 +3,15 @@ import type { FetchEvent } from "./types.ts";
|
|
|
3
3
|
export declare function createFetchEvent(event: H3Event): FetchEvent;
|
|
4
4
|
export declare function getFetchEvent(h3Event: H3Event): FetchEvent;
|
|
5
5
|
export declare function mergeResponseHeaders(h3Event: H3Event, headers: Headers): void;
|
|
6
|
+
/**
|
|
7
|
+
* Wrap an h3 event handler so Solid's request context is available while it runs.
|
|
8
|
+
*
|
|
9
|
+
* @experimental
|
|
10
|
+
*/
|
|
6
11
|
export declare const decorateHandler: <T extends EventHandler>(fn: T) => T;
|
|
12
|
+
/**
|
|
13
|
+
* Wrap h3 middleware so Solid's request context is available while it runs.
|
|
14
|
+
*
|
|
15
|
+
* @experimental
|
|
16
|
+
*/
|
|
7
17
|
export declare const decorateMiddleware: <T extends Middleware>(fn: T) => T;
|
|
@@ -22,5 +22,15 @@ export function mergeResponseHeaders(h3Event, headers) {
|
|
|
22
22
|
h3Event.res.headers.append(key, value);
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Wrap an h3 event handler so Solid's request context is available while it runs.
|
|
27
|
+
*
|
|
28
|
+
* @experimental
|
|
29
|
+
*/
|
|
25
30
|
export const decorateHandler = (fn) => (event => provideRequestEvent(getFetchEvent(event), () => fn(event)));
|
|
31
|
+
/**
|
|
32
|
+
* Wrap h3 middleware so Solid's request context is available while it runs.
|
|
33
|
+
*
|
|
34
|
+
* @experimental
|
|
35
|
+
*/
|
|
26
36
|
export const decorateMiddleware = (fn) => ((event, next) => provideRequestEvent(getFetchEvent(event), () => fn(event, next)));
|
package/dist/server/handler.d.ts
CHANGED
|
@@ -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>)):
|
|
5
|
-
export declare function createHandler(fn: (context: PageEvent) => JSX.Element, options?: HandlerOptions | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>)):
|
|
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>;
|
package/dist/server/handler.js
CHANGED
|
@@ -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";
|
|
@@ -8,8 +8,10 @@ import { getSsrManifest } from "./manifest/ssr-manifest.js";
|
|
|
8
8
|
import { matchAPIRoute } from "./routes.js";
|
|
9
9
|
import { handleServerFunction } from "../fns/handler.js";
|
|
10
10
|
import { getExpectedRedirectStatus } from "./util.js";
|
|
11
|
+
import { toWebReadableStream } from "./web-stream.js";
|
|
12
|
+
import { stripPathBase } from "./strip-path-base.js";
|
|
11
13
|
const SERVER_FN_BASE = "/_server";
|
|
12
|
-
export function createBaseHandler(createPageEvent, fn, options = {}) {
|
|
14
|
+
export function createBaseHandler(createPageEvent, fn, options = {}, routerLoad) {
|
|
13
15
|
const handler = defineHandler({
|
|
14
16
|
middleware: middleware.length ? middleware.map(decorateMiddleware) : undefined,
|
|
15
17
|
handler: decorateHandler(async (e) => {
|
|
@@ -17,12 +19,7 @@ export function createBaseHandler(createPageEvent, fn, options = {}) {
|
|
|
17
19
|
const url = new URL(event.request.url);
|
|
18
20
|
const pathname = stripBaseUrl(url.pathname);
|
|
19
21
|
if (pathname.startsWith(SERVER_FN_BASE)) {
|
|
20
|
-
|
|
21
|
-
if (serverFnResponse instanceof Response)
|
|
22
|
-
return produceResponseWithEventHeaders(serverFnResponse);
|
|
23
|
-
return new Response(serverFnResponse, {
|
|
24
|
-
headers: e.res.headers,
|
|
25
|
-
});
|
|
22
|
+
return await handleServerFunction(e);
|
|
26
23
|
}
|
|
27
24
|
const match = matchAPIRoute(pathname, event.request.method);
|
|
28
25
|
if (match) {
|
|
@@ -34,8 +31,6 @@ export function createBaseHandler(createPageEvent, fn, options = {}) {
|
|
|
34
31
|
sharedConfig.context = { event };
|
|
35
32
|
const res = await fn(event);
|
|
36
33
|
if (res !== undefined) {
|
|
37
|
-
if (res instanceof Response)
|
|
38
|
-
return produceResponseWithEventHeaders(res);
|
|
39
34
|
return res;
|
|
40
35
|
}
|
|
41
36
|
if (event.request.method !== "GET") {
|
|
@@ -45,6 +40,8 @@ export function createBaseHandler(createPageEvent, fn, options = {}) {
|
|
|
45
40
|
return;
|
|
46
41
|
}
|
|
47
42
|
}
|
|
43
|
+
if (routerLoad)
|
|
44
|
+
await routerLoad(event);
|
|
48
45
|
const context = await createPageEvent(event);
|
|
49
46
|
const resolvedOptions = typeof options === "function" ? await options(context) : { ...options };
|
|
50
47
|
const mode = resolvedOptions.mode || "stream";
|
|
@@ -92,23 +89,17 @@ export function createBaseHandler(createPageEvent, fn, options = {}) {
|
|
|
92
89
|
}
|
|
93
90
|
if (mode === "async")
|
|
94
91
|
return await stream;
|
|
95
|
-
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
if (globalThis.USING_SOLID_START_DEV_SERVER)
|
|
99
|
-
return stream;
|
|
100
|
-
// returning stream directly breaks cloudflare workers
|
|
101
|
-
const { writable, readable } = new TransformStream();
|
|
102
|
-
stream.pipeTo(writable);
|
|
103
|
-
return readable;
|
|
92
|
+
// h3 expects a standard web ReadableStream across runtimes. The adapter
|
|
93
|
+
// also tolerates cancellation while Solid finishes outstanding work.
|
|
94
|
+
return iterable(toWebReadableStream(stream));
|
|
104
95
|
}),
|
|
105
96
|
});
|
|
106
97
|
const app = new H3();
|
|
107
98
|
app.use(handler);
|
|
108
99
|
return app;
|
|
109
100
|
}
|
|
110
|
-
export function createHandler(fn, options = {}) {
|
|
111
|
-
return createBaseHandler(createPageEvent, fn, options);
|
|
101
|
+
export function createHandler(fn, options = {}, routerLoad) {
|
|
102
|
+
return createBaseHandler(createPageEvent, fn, options, routerLoad);
|
|
112
103
|
}
|
|
113
104
|
export async function createPageEvent(ctx) {
|
|
114
105
|
ctx.response.headers.set("Content-Type", "text/html");
|
|
@@ -180,43 +171,18 @@ function handleStreamCompleteRedirect(context) {
|
|
|
180
171
|
return ({ write }) => {
|
|
181
172
|
context.complete = true;
|
|
182
173
|
const to = context.response && context.response.headers.get("Location");
|
|
183
|
-
|
|
174
|
+
if (!to)
|
|
175
|
+
return;
|
|
176
|
+
// The shell has already flushed, so the redirect has to happen client side.
|
|
177
|
+
// Carry the nonce so a strict `script-src` CSP doesn't block it.
|
|
178
|
+
const nonce = context.nonce ? ` nonce="${escapeAttribute(context.nonce)}"` : "";
|
|
179
|
+
write(`<script${nonce}>window.location=${JSON.stringify(to).replace(/</g, "\\u003c")}</script>`);
|
|
184
180
|
};
|
|
185
181
|
}
|
|
186
|
-
function
|
|
187
|
-
|
|
188
|
-
let ret = res;
|
|
189
|
-
// Response.redirect returns an immutable value, so we clone on any redirect just in case
|
|
190
|
-
if (300 <= res.status && res.status < 400) {
|
|
191
|
-
const cookies = res.headers.getSetCookie?.() ?? [];
|
|
192
|
-
const headers = new Headers();
|
|
193
|
-
res.headers.forEach((value, key) => {
|
|
194
|
-
if (key.toLowerCase() !== "set-cookie") {
|
|
195
|
-
headers.set(key, value);
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
for (const cookie of cookies) {
|
|
199
|
-
headers.append("Set-Cookie", cookie);
|
|
200
|
-
}
|
|
201
|
-
ret = new Response(res.body, {
|
|
202
|
-
status: res.status,
|
|
203
|
-
statusText: res.statusText,
|
|
204
|
-
headers,
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
const eventCookies = event.response.headers.getSetCookie?.() ?? [];
|
|
208
|
-
for (const cookie of eventCookies) {
|
|
209
|
-
ret.headers.append("Set-Cookie", cookie);
|
|
210
|
-
}
|
|
211
|
-
for (const [name, value] of event.response.headers) {
|
|
212
|
-
if (name.toLowerCase() !== "set-cookie") {
|
|
213
|
-
ret.headers.set(name, value);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
return ret;
|
|
182
|
+
function escapeAttribute(value) {
|
|
183
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
217
184
|
}
|
|
218
185
|
function stripBaseUrl(path) {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
return path.slice(import.meta.env.BASE_URL.length);
|
|
186
|
+
const base = import.meta.env.SERVER_BASE_URL || import.meta.env.BASE_URL || "/";
|
|
187
|
+
return stripPathBase(path, base);
|
|
222
188
|
}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export { default as lazy } from "../shared/lazy.ts";
|
|
2
2
|
export { getServerFunctionMeta } from "../shared/serverFunction.ts";
|
|
3
3
|
export { StartServer } from "./StartServer.tsx";
|
|
4
|
+
export { decorateHandler, decorateMiddleware } from "./fetchEvent.ts";
|
|
4
5
|
export { createHandler } from "./handler.ts";
|
|
5
|
-
export type {
|
|
6
|
+
export type { ServerFunctionErrorHandler } from "../fns/error-handler.ts";
|
|
7
|
+
export type { APIEvent, APIHandler, Asset, ContextMatches, DocumentComponentProps, FetchEvent, HandlerOptions, PageEvent, ResponseStub, ServerFunctionMeta, StartHandler, } from "./types.ts";
|
|
6
8
|
/**
|
|
7
9
|
* Checks if user has set a redirect status in the response.
|
|
8
10
|
* If not, falls back to the 302 (temporary redirect)
|
package/dist/server/index.jsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { default as lazy } from "../shared/lazy.js";
|
|
2
2
|
export { getServerFunctionMeta } from "../shared/serverFunction.js";
|
|
3
3
|
export { StartServer } from "./StartServer.jsx";
|
|
4
|
+
export { decorateHandler, decorateMiddleware } from "./fetchEvent.js";
|
|
4
5
|
export { createHandler } from "./handler.js";
|
|
5
6
|
/**
|
|
6
7
|
* Checks if user has set a redirect status in the response.
|
|
@@ -13,7 +13,7 @@ export function getClientDevManifest() {
|
|
|
13
13
|
return import(__rewriteRelativeImportExtension(/* @vite-ignore */ join("/", id), true));
|
|
14
14
|
},
|
|
15
15
|
async getAssets(id) {
|
|
16
|
-
const assetsPath = `/@manifest/client/${Date.now()}/assets?id=${id}`;
|
|
16
|
+
const assetsPath = `/@manifest/client/${Date.now()}/assets?id=${encodeURIComponent(id)}`;
|
|
17
17
|
const assets = (await import(__rewriteRelativeImportExtension(/* @vite-ignore */ assetsPath, true))).default;
|
|
18
18
|
return await Promise.all(assets.map(async (v) => ({
|
|
19
19
|
...v,
|
|
@@ -11,7 +11,7 @@ export function getSsrDevManifest(environment) {
|
|
|
11
11
|
return {
|
|
12
12
|
path: (id) => normalize(join(import.meta.env.BASE_URL, id)),
|
|
13
13
|
async getAssets(id) {
|
|
14
|
-
const assetsPath = `/@manifest/${environment}/${Date.now()}/assets?id=${id}`;
|
|
14
|
+
const assetsPath = `/@manifest/${environment}/${Date.now()}/assets?id=${encodeURIComponent(id)}`;
|
|
15
15
|
const assets = (await import(__rewriteRelativeImportExtension(/* @vite-ignore */ assetsPath, true))).default;
|
|
16
16
|
return await Promise.all(assets.map(async (v) => ({
|
|
17
17
|
...v,
|
|
@@ -18,7 +18,7 @@ export function StartServer(props) {
|
|
|
18
18
|
<TopErrorBoundary>
|
|
19
19
|
<props.document scripts={<>
|
|
20
20
|
<PatchVirtualDevStyles nonce={nonce}/>
|
|
21
|
-
<script type="module" src={getSsrManifest("client").path(import.meta.env.
|
|
21
|
+
<script type="module" nonce={nonce} src={getSsrManifest("client").path(import.meta.env.START_CLIENT_ENTRY_URL)}/>
|
|
22
22
|
</>}/>
|
|
23
23
|
</TopErrorBoundary>
|
|
24
24
|
</NoHydration>);
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import type { H3 } from "h3/generic";
|
|
2
1
|
import type { JSX } from "solid-js";
|
|
3
|
-
import type { 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)):
|
|
7
|
+
export declare function createHandler(fn: (context: PageEvent) => JSX.Element, options?: HandlerOptions | ((context: PageEvent) => HandlerOptions), routerLoad?: (event: FetchEvent) => Promise<void>): StartHandler;
|
|
@@ -4,8 +4,8 @@ import { getSsrManifest } from "../manifest/ssr-manifest.js";
|
|
|
4
4
|
*
|
|
5
5
|
* Read more: https://docs.solidjs.com/solid-start/reference/server/create-handler
|
|
6
6
|
*/
|
|
7
|
-
export function createHandler(fn, options) {
|
|
8
|
-
return createBaseHandler(createPageEvent, fn, options);
|
|
7
|
+
export function createHandler(fn, options, routerLoad) {
|
|
8
|
+
return createBaseHandler(createPageEvent, fn, options, routerLoad);
|
|
9
9
|
}
|
|
10
10
|
async function createPageEvent(ctx) {
|
|
11
11
|
const manifest = getSsrManifest("ssr");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function stripPathBase(path: string, base: string): string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function stripPathBase(path, base) {
|
|
2
|
+
if (!base || base === "/")
|
|
3
|
+
return path;
|
|
4
|
+
const normalizedBase = base.endsWith("/") ? base.slice(0, -1) : base;
|
|
5
|
+
if (path === normalizedBase)
|
|
6
|
+
return "/";
|
|
7
|
+
if (path.startsWith(`${normalizedBase}/`))
|
|
8
|
+
return path.slice(normalizedBase.length);
|
|
9
|
+
return path;
|
|
10
|
+
}
|
package/dist/server/types.d.ts
CHANGED
|
@@ -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;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type PipeableStream = {
|
|
2
|
+
pipe(writable: {
|
|
3
|
+
write(payload: string): void;
|
|
4
|
+
end(): void;
|
|
5
|
+
}): void;
|
|
6
|
+
};
|
|
7
|
+
/** Convert Solid's streaming SSR result into a cancellation-safe web stream. */
|
|
8
|
+
export declare function toWebReadableStream(stream: PipeableStream): ReadableStream<Uint8Array<ArrayBufferLike>>;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Convert Solid's streaming SSR result into a cancellation-safe web stream. */
|
|
2
|
+
export function toWebReadableStream(stream) {
|
|
3
|
+
const encoder = new TextEncoder();
|
|
4
|
+
let active = true;
|
|
5
|
+
return new ReadableStream({
|
|
6
|
+
start(controller) {
|
|
7
|
+
stream.pipe({
|
|
8
|
+
write(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));
|
|
14
|
+
},
|
|
15
|
+
end() {
|
|
16
|
+
if (!active)
|
|
17
|
+
return;
|
|
18
|
+
active = false;
|
|
19
|
+
controller.close();
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
},
|
|
23
|
+
cancel() {
|
|
24
|
+
// Solid may still resolve Suspense resources after the response is
|
|
25
|
+
// cancelled. Ignore those writes and let Solid finish its cleanup.
|
|
26
|
+
active = false;
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// @refresh skip
|
|
2
|
-
import { ErrorBoundary as DefaultErrorBoundary
|
|
2
|
+
import { catchError, ErrorBoundary as DefaultErrorBoundary } from "solid-js";
|
|
3
3
|
import { isServer } from "solid-js/web";
|
|
4
|
+
import { DevToolbar } from "./dev-toolbar/index.jsx";
|
|
4
5
|
import { HttpStatusCode } from "./HttpStatusCode.js";
|
|
5
|
-
import { DevOverlay } from "./dev-overlay/index.jsx";
|
|
6
6
|
export const ErrorBoundary = import.meta.env.DEV && import.meta.env.START_DEV_OVERLAY
|
|
7
|
-
? (props) => <
|
|
7
|
+
? (props) => <DevToolbar>{props.children}</DevToolbar>
|
|
8
8
|
: (props) => {
|
|
9
9
|
const message = isServer
|
|
10
10
|
? "500 | Internal Server Error"
|
|
@@ -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()),
|
|
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,12 +51,12 @@ 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.
|
|
54
|
+
el.dataset.startErrorViewerErrorLine = "";
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
});
|
|
59
|
-
return (<div ref={ref} data-start-
|
|
60
|
-
"--
|
|
59
|
+
return (<div ref={ref} data-start-error-viewer-code-view style={{
|
|
60
|
+
"--error-viewer-code-view-start": minLine() + 1,
|
|
61
61
|
}}/>);
|
|
62
62
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { createMemo, createResource } from "solid-js";
|
|
2
|
+
import getSourceMap from "./get-source-map.js";
|
|
3
|
+
const HTTP_URL_REGEX = /^https?:\/\//;
|
|
4
|
+
const LEADING_SLASH_REGEX = /^\/+/;
|
|
5
|
+
// Frames from an SSR error carry filesystem paths (or file:// URLs) rather
|
|
6
|
+
// than the http URL the module is served from. Their positions are already
|
|
7
|
+
// mapped back to the original source by the Vite module runner, unlike
|
|
8
|
+
// client frames whose positions refer to the compiled module.
|
|
9
|
+
function isServerSource(path) {
|
|
10
|
+
return !HTTP_URL_REGEX.test(path);
|
|
11
|
+
}
|
|
12
|
+
function getActualFileSource(path) {
|
|
13
|
+
if (path.startsWith("file://")) {
|
|
14
|
+
return "/@fs/" + path.substring("file://".length).replace(LEADING_SLASH_REGEX, "");
|
|
15
|
+
}
|
|
16
|
+
if (isServerSource(path)) {
|
|
17
|
+
return "/@fs/" + path.replace(LEADING_SLASH_REGEX, "");
|
|
18
|
+
}
|
|
19
|
+
return path;
|
|
20
|
+
}
|
|
21
|
+
export function createStackFrame(stackframe, isCompiled) {
|
|
22
|
+
const [data] = createResource(() => ({
|
|
23
|
+
fileName: stackframe.fileName,
|
|
24
|
+
line: stackframe.lineNumber,
|
|
25
|
+
column: stackframe.columnNumber,
|
|
26
|
+
functionName: stackframe.functionName,
|
|
27
|
+
}), async (source) => {
|
|
28
|
+
if (!source.fileName) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const url = getActualFileSource(source.fileName);
|
|
32
|
+
const response = await fetch(url);
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
const content = await response.text();
|
|
37
|
+
const sourceMap = await getSourceMap(url, content);
|
|
38
|
+
return {
|
|
39
|
+
source,
|
|
40
|
+
content,
|
|
41
|
+
sourceMap,
|
|
42
|
+
isServer: isServerSource(source.fileName),
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
const info = createMemo(() => {
|
|
46
|
+
const current = data();
|
|
47
|
+
if (!current) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
const { source, content, sourceMap, isServer } = current;
|
|
51
|
+
if (!isCompiled() && source.line && source.column && sourceMap) {
|
|
52
|
+
if (isServer) {
|
|
53
|
+
// The position is already original; only the original content needs
|
|
54
|
+
// to be pulled out of the source map.
|
|
55
|
+
const originalContent = sourceMap.sources.length
|
|
56
|
+
? sourceMap.sourceContentFor(sourceMap.sources[0], true)
|
|
57
|
+
: null;
|
|
58
|
+
if (originalContent) {
|
|
59
|
+
return {
|
|
60
|
+
source: source.fileName,
|
|
61
|
+
line: source.line,
|
|
62
|
+
column: source.column,
|
|
63
|
+
name: source.functionName,
|
|
64
|
+
content: originalContent,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
const result = sourceMap.originalPositionFor({
|
|
70
|
+
line: source.line,
|
|
71
|
+
column: source.column,
|
|
72
|
+
});
|
|
73
|
+
if (result.source) {
|
|
74
|
+
return {
|
|
75
|
+
...result,
|
|
76
|
+
content: sourceMap.sourceContentFor(result.source, true),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
source: source.fileName,
|
|
83
|
+
line: source.line,
|
|
84
|
+
column: source.column,
|
|
85
|
+
name: source.functionName,
|
|
86
|
+
content,
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
return info;
|
|
90
|
+
}
|
package/dist/shared/{dev-overlay/DevOverlayDialog.d.ts → dev-toolbar/error-viewer/index.d.ts}
RENAMED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { JSX } from "solid-js";
|
|
2
2
|
import "./styles.css";
|
|
3
3
|
export declare function classNames(...classes: (string | boolean | undefined)[]): string;
|
|
4
|
-
interface
|
|
4
|
+
interface ErrorViewerProps {
|
|
5
|
+
show?: boolean;
|
|
5
6
|
errors: any[];
|
|
6
7
|
resetError: () => void;
|
|
7
8
|
}
|
|
8
|
-
export default function
|
|
9
|
+
export default function ErrorViewer(props: ErrorViewerProps): JSX.Element;
|
|
9
10
|
export {};
|