@kasperrt/smolter 0.2.0 → 0.3.1
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/.generated/client/deployment.ts +161 -0
- package/{src/internal → .generated}/client/index.ts +3 -0
- package/.generated/core/environment.ts +43 -0
- package/{src/internal → .generated}/core/errors.ts +1 -1
- package/{src/internal → .generated}/core/index.ts +1 -0
- package/.generated/core/navigation-router.ts +107 -0
- package/.generated/core/navigation.ts +147 -0
- package/.generated/core/presentation.ts +108 -0
- package/.generated/core/resource-types.ts +44 -0
- package/.generated/core/resources.ts +444 -0
- package/.generated/core/responses.ts +86 -0
- package/{src/internal → .generated}/core/router.ts +136 -63
- package/{src/internal → .generated}/core/serialize.ts +7 -2
- package/.generated/core/store.ts +25 -0
- package/.generated/core/submission.ts +116 -0
- package/{src/internal → .generated}/core/types.ts +18 -1
- package/.generated/core/url.ts +29 -0
- package/.generated/core/utils.ts +5 -0
- package/.generated/preact/await.tsx +41 -0
- package/.generated/preact/client.tsx +93 -0
- package/.generated/preact/context.ts +59 -0
- package/.generated/preact/document.tsx +198 -0
- package/{src/internal → .generated}/preact/fetcher.ts +43 -23
- package/.generated/preact/form.ts +58 -0
- package/{src/internal → .generated}/preact/hooks.ts +25 -28
- package/.generated/preact/index.ts +34 -0
- package/.generated/preact/lazy-route.ts +100 -0
- package/.generated/preact/navigation-state.ts +9 -0
- package/.generated/preact/navigation.tsx +147 -0
- package/.generated/preact/root-context.ts +21 -0
- package/.generated/preact/root-data.ts +45 -0
- package/.generated/preact/route-hooks.tsx +170 -0
- package/.generated/preact/route-types.ts +76 -0
- package/.generated/preact/router.tsx +107 -0
- package/{src/internal → .generated}/preact/routes.ts +17 -9
- package/.generated/react/context.ts +59 -0
- package/.generated/react/data.ts +25 -0
- package/{src/internal → .generated}/react/fetcher.ts +13 -11
- package/.generated/react/form.ts +58 -0
- package/{src/internal → .generated}/react/hooks.ts +9 -14
- package/{src/internal/preact → .generated/react}/index.ts +5 -1
- package/{src/internal → .generated}/react/link.ts +13 -21
- package/.generated/react/resources/components.tsx +404 -0
- package/{src/internal → .generated}/react/routes.ts +17 -9
- package/.generated/server/application.tsx +185 -0
- package/.generated/server/assets.ts +19 -0
- package/.generated/server/handler.ts +69 -0
- package/.generated/server/http.ts +55 -0
- package/{src/internal → .generated}/server/index.ts +3 -3
- package/.generated/server/node.ts +4 -0
- package/.generated/server/preact.ts +7 -0
- package/.generated/vite/application/browser-boundary.ts +42 -0
- package/.generated/vite/application/lazy-files.ts +138 -0
- package/.generated/vite/application/vite.ts +144 -0
- package/.generated/vite/deployment.ts +46 -0
- package/{src/internal → .generated}/vite/index.ts +11 -4
- package/{src/preact-vite.ts → .generated/vite/preact.ts} +14 -3
- package/{src/react-vite.ts → .generated/vite/react.ts} +8 -3
- package/CHANGELOG.md +63 -0
- package/README.md +277 -35
- package/dist/client/deployment.d.ts +12 -0
- package/dist/client/deployment.js +102 -0
- package/dist/client/deserialize.js +10 -0
- package/dist/{internal/client → client}/index.d.ts +2 -0
- package/dist/client/index.js +47 -0
- package/dist/core/environment.d.ts +12 -0
- package/dist/core/environment.js +23 -0
- package/dist/core/errors.js +7 -0
- package/dist/{internal/core → core}/index.d.ts +1 -0
- package/dist/core/match.js +33 -0
- package/dist/core/navigation-router.d.ts +15 -0
- package/dist/core/navigation-router.js +64 -0
- package/dist/core/navigation.d.ts +15 -0
- package/dist/core/navigation.js +92 -0
- package/dist/core/presentation.d.ts +5 -0
- package/dist/core/presentation.js +69 -0
- package/dist/core/resource-types.d.ts +37 -0
- package/dist/core/resources.d.ts +19 -0
- package/dist/core/resources.js +345 -0
- package/dist/core/responses.d.ts +15 -0
- package/dist/core/responses.js +48 -0
- package/dist/{internal/core → core}/router.d.ts +1 -1
- package/dist/core/router.js +204 -0
- package/dist/{internal/core → core}/serialize.d.ts +2 -0
- package/dist/core/serialize.js +17 -0
- package/dist/core/store.d.ts +6 -0
- package/dist/core/store.js +21 -0
- package/dist/core/submission.d.ts +30 -0
- package/dist/core/submission.js +41 -0
- package/dist/{internal/core → core}/types.d.ts +16 -1
- package/dist/core/url.d.ts +7 -0
- package/dist/core/url.js +12 -0
- package/dist/core/utils.d.ts +5 -0
- package/dist/core/utils.js +5 -0
- package/dist/files/index.js +64 -0
- package/dist/preact/await.d.ts +7 -0
- package/dist/preact/await.js +19 -0
- package/dist/preact/client.d.ts +7 -0
- package/dist/preact/client.js +68 -0
- package/dist/preact/context.d.ts +18 -0
- package/dist/preact/context.js +23 -0
- package/dist/preact/document.d.ts +15 -0
- package/dist/preact/document.js +155 -0
- package/dist/{internal/preact → preact}/fetcher.d.ts +9 -5
- package/dist/preact/fetcher.js +45 -0
- package/dist/{internal/preact → preact}/form.d.ts +5 -6
- package/dist/preact/form.js +21 -0
- package/dist/{internal/preact → preact}/hooks.d.ts +7 -6
- package/dist/preact/hooks.js +25 -0
- package/dist/preact/index.d.ts +18 -0
- package/dist/preact/index.js +15 -0
- package/dist/preact/lazy-route.d.ts +19 -0
- package/dist/preact/lazy-route.js +51 -0
- package/dist/preact/navigation-state.d.ts +2 -0
- package/dist/preact/navigation-state.js +9 -0
- package/dist/preact/navigation.d.ts +28 -0
- package/dist/preact/navigation.js +60 -0
- package/dist/preact/root-context.d.ts +13 -0
- package/dist/preact/root-context.js +9 -0
- package/dist/preact/root-data.d.ts +8 -0
- package/dist/preact/root-data.js +28 -0
- package/dist/preact/route-hooks.d.ts +32 -0
- package/dist/preact/route-hooks.js +94 -0
- package/dist/preact/route-types.d.ts +54 -0
- package/dist/preact/router.d.ts +16 -0
- package/dist/preact/router.js +63 -0
- package/dist/{internal/preact → preact}/routes.d.ts +1 -1
- package/dist/preact/routes.js +12 -0
- package/dist/{internal/preact → preact}/runtime.js +1 -1
- package/dist/react/context.d.ts +18 -0
- package/dist/react/context.js +23 -0
- package/dist/react/data.d.ts +5 -0
- package/dist/react/data.js +3 -0
- package/dist/{internal/react → react}/fetcher.d.ts +2 -2
- package/dist/react/fetcher.js +34 -0
- package/dist/{internal/react → react}/form.d.ts +5 -6
- package/dist/react/form.js +21 -0
- package/dist/react/hooks.js +25 -0
- package/dist/{internal/react → react}/index.d.ts +1 -1
- package/dist/react/index.js +10 -0
- package/dist/{internal/react → react}/link.d.ts +2 -2
- package/dist/react/link.js +27 -0
- package/dist/react/resources/components.d.ts +64 -0
- package/dist/react/resources/components.js +239 -0
- package/dist/{internal/react → react}/routes.d.ts +1 -1
- package/dist/react/routes.js +12 -0
- package/dist/react/runtime.js +1 -0
- package/dist/server/application.d.ts +4 -0
- package/dist/server/application.js +119 -0
- package/dist/server/assets.d.ts +5 -0
- package/dist/server/assets.js +7 -0
- package/dist/server/handler.d.ts +19 -0
- package/dist/server/handler.js +22 -0
- package/dist/server/http.d.ts +4 -0
- package/dist/server/http.js +27 -0
- package/dist/server/index.js +76 -0
- package/dist/server/node.d.ts +3 -0
- package/dist/server/node.js +3 -0
- package/dist/server/preact.d.ts +3 -0
- package/dist/server/preact.js +4 -0
- package/dist/vite/application/browser-boundary.d.ts +3 -0
- package/dist/vite/application/browser-boundary.js +35 -0
- package/dist/vite/application/lazy-files.d.ts +2 -0
- package/dist/vite/application/lazy-files.js +88 -0
- package/dist/vite/application/vite.d.ts +9 -0
- package/dist/vite/application/vite.js +101 -0
- package/dist/vite/deployment.d.ts +8 -0
- package/dist/vite/deployment.js +36 -0
- package/dist/vite/index.js +109 -0
- package/dist/{preact-vite.d.ts → vite/preact.d.ts} +6 -3
- package/dist/vite/preact.js +16 -0
- package/dist/{react-vite.d.ts → vite/react.d.ts} +4 -3
- package/dist/vite/react.js +15 -0
- package/dist/vite/transport.js +35 -0
- package/jsr.json +28 -16
- package/package.json +115 -35
- package/dist/client.d.ts +0 -2
- package/dist/client.js +0 -2
- package/dist/core.d.ts +0 -2
- package/dist/core.js +0 -2
- package/dist/files.d.ts +0 -2
- package/dist/files.js +0 -2
- package/dist/internal/client/deserialize.js +0 -11
- package/dist/internal/client/index.js +0 -44
- package/dist/internal/core/errors.js +0 -6
- package/dist/internal/core/index.js +0 -7
- package/dist/internal/core/match.js +0 -27
- package/dist/internal/core/router.js +0 -189
- package/dist/internal/core/serialize.js +0 -13
- package/dist/internal/core/types.js +0 -5
- package/dist/internal/core/url.d.ts +0 -2
- package/dist/internal/core/url.js +0 -6
- package/dist/internal/files/index.js +0 -77
- package/dist/internal/preact/context.d.ts +0 -18
- package/dist/internal/preact/context.js +0 -20
- package/dist/internal/preact/fetcher.js +0 -28
- package/dist/internal/preact/form.js +0 -41
- package/dist/internal/preact/hooks.js +0 -35
- package/dist/internal/preact/index.d.ts +0 -9
- package/dist/internal/preact/index.js +0 -7
- package/dist/internal/preact/link.d.ts +0 -12
- package/dist/internal/preact/link.js +0 -28
- package/dist/internal/preact/routes.js +0 -22
- package/dist/internal/react/context.d.ts +0 -18
- package/dist/internal/react/context.js +0 -20
- package/dist/internal/react/fetcher.js +0 -28
- package/dist/internal/react/form.js +0 -41
- package/dist/internal/react/hooks.js +0 -35
- package/dist/internal/react/index.js +0 -7
- package/dist/internal/react/link.js +0 -28
- package/dist/internal/react/routes.js +0 -22
- package/dist/internal/react/runtime.js +0 -2
- package/dist/internal/server/index.js +0 -69
- package/dist/internal/vite/index.js +0 -132
- package/dist/internal/vite/transport.js +0 -42
- package/dist/preact-client.d.ts +0 -2
- package/dist/preact-client.js +0 -2
- package/dist/preact-server.d.ts +0 -2
- package/dist/preact-server.js +0 -2
- package/dist/preact-vite.js +0 -9
- package/dist/preact.d.ts +0 -2
- package/dist/preact.js +0 -2
- package/dist/react-client.d.ts +0 -2
- package/dist/react-client.js +0 -2
- package/dist/react-server.d.ts +0 -2
- package/dist/react-server.js +0 -2
- package/dist/react-vite.js +0 -9
- package/dist/react.d.ts +0 -2
- package/dist/react.js +0 -2
- package/dist/server.d.ts +0 -2
- package/dist/server.js +0 -2
- package/dist/utils.d.ts +0 -5
- package/dist/utils.js +0 -5
- package/dist/vite.d.ts +0 -2
- package/dist/vite.js +0 -2
- package/src/client.ts +0 -2
- package/src/core.ts +0 -2
- package/src/files.ts +0 -2
- package/src/internal/core/url.ts +0 -6
- package/src/internal/preact/context.ts +0 -46
- package/src/internal/preact/form.ts +0 -79
- package/src/internal/preact/link.ts +0 -46
- package/src/internal/react/context.ts +0 -46
- package/src/internal/react/form.ts +0 -79
- package/src/internal/react/index.ts +0 -13
- package/src/preact-client.ts +0 -2
- package/src/preact-server.ts +0 -2
- package/src/preact.ts +0 -2
- package/src/react-client.ts +0 -2
- package/src/react-server.ts +0 -2
- package/src/react.ts +0 -2
- package/src/server.ts +0 -2
- package/src/utils.ts +0 -5
- package/src/vite.ts +0 -2
- /package/{src/internal → .generated}/client/deserialize.ts +0 -0
- /package/{src/internal → .generated}/core/match.ts +0 -0
- /package/{src/internal → .generated}/files/index.ts +0 -0
- /package/{src/internal → .generated}/preact/runtime.ts +0 -0
- /package/{src/internal → .generated}/react/runtime.ts +0 -0
- /package/{src/internal → .generated}/vite/transport.ts +0 -0
- /package/dist/{internal/client → client}/deserialize.d.ts +0 -0
- /package/dist/{internal/core → core}/errors.d.ts +0 -0
- /package/dist/{internal/core → core}/match.d.ts +0 -0
- /package/dist/{internal/files → files}/index.d.ts +0 -0
- /package/dist/{internal/preact → preact}/runtime.d.ts +0 -0
- /package/dist/{internal/react → react}/hooks.d.ts +0 -0
- /package/dist/{internal/react → react}/runtime.d.ts +0 -0
- /package/dist/{internal/server → server}/index.d.ts +0 -0
- /package/dist/{internal/vite → vite}/index.d.ts +0 -0
- /package/dist/{internal/vite → vite}/transport.d.ts +0 -0
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* React components and typed data hooks. Import from @kasperrt/smolter/react.
|
|
3
|
-
* @module
|
|
4
|
-
*/
|
|
5
|
-
import { useRouter, useSnapshot } from "./context.js";
|
|
6
|
-
function useData(key, route) {
|
|
7
|
-
const path = route?.path;
|
|
8
|
-
return useSnapshot((snapshot) => {
|
|
9
|
-
if (path !== undefined && path !== snapshot.path)
|
|
10
|
-
return undefined;
|
|
11
|
-
return snapshot[key];
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
/** Pass a route for inference, or use useLoaderData<typeof loader>() in its module. */
|
|
15
|
-
export function useLoaderData(route) {
|
|
16
|
-
return useData("data", route);
|
|
17
|
-
}
|
|
18
|
-
/** Read the last page action result, optionally inferring its type from a route. */
|
|
19
|
-
export function useActionData(route) {
|
|
20
|
-
return useData("actionData", route);
|
|
21
|
-
}
|
|
22
|
-
/** Read path parameters for the active route. */
|
|
23
|
-
export function useParams() {
|
|
24
|
-
return useSnapshot((snapshot) => snapshot.params);
|
|
25
|
-
}
|
|
26
|
-
/** Read the current path, search, and hash together with the navigate function. */
|
|
27
|
-
export function useLocation() {
|
|
28
|
-
const router = useRouter();
|
|
29
|
-
const url = useSnapshot((snapshot) => snapshot.url);
|
|
30
|
-
return [url.replace(/^\w+:\/\/[^/]+/, ""), router.navigate];
|
|
31
|
-
}
|
|
32
|
-
/** Get the function that revalidates the current loader subject to shouldRevalidate. */
|
|
33
|
-
export function useRevalidator() {
|
|
34
|
-
return useRouter().revalidate;
|
|
35
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export { createRouter, defineRoute } from "../core/index.js";
|
|
2
|
-
export { RouterProvider, useRouter, } from "./context.js";
|
|
3
|
-
export * from "./fetcher.js";
|
|
4
|
-
export * from "./form.js";
|
|
5
|
-
export * from "./hooks.js";
|
|
6
|
-
export * from "./link.js";
|
|
7
|
-
export * from "./routes.js";
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* React components and typed data hooks. Import from @kasperrt/smolter/react.
|
|
3
|
-
* @module
|
|
4
|
-
*/
|
|
5
|
-
import { internalURL } from "../core/index.js";
|
|
6
|
-
import { useRouter } from "./context.js";
|
|
7
|
-
import { createElement } from "./runtime.js";
|
|
8
|
-
/** Render an anchor that handles internal navigation and preserves native modified clicks. */
|
|
9
|
-
export function Link({ href, replace, onClick, ...props }) {
|
|
10
|
-
const router = useRouter();
|
|
11
|
-
const click = (event) => {
|
|
12
|
-
onClick?.(event);
|
|
13
|
-
if (event.defaultPrevented ||
|
|
14
|
-
event.button ||
|
|
15
|
-
event.metaKey ||
|
|
16
|
-
event.ctrlKey ||
|
|
17
|
-
event.altKey ||
|
|
18
|
-
event.shiftKey ||
|
|
19
|
-
props.download !== undefined ||
|
|
20
|
-
(props.target && props.target !== "_self"))
|
|
21
|
-
return;
|
|
22
|
-
if (!internalURL(router.getSnapshot().url, href))
|
|
23
|
-
return;
|
|
24
|
-
event.preventDefault();
|
|
25
|
-
void router.navigate(href, { replace });
|
|
26
|
-
};
|
|
27
|
-
return createElement("a", { ...props, href, onClick: click });
|
|
28
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* React components and typed data hooks. Import from @kasperrt/smolter/react.
|
|
3
|
-
* @module
|
|
4
|
-
*/
|
|
5
|
-
import { useRouter, useSnapshot } from "./context.js";
|
|
6
|
-
import { createElement, useMemo } from "./runtime.js";
|
|
7
|
-
/** Renders the first matching registered module. */
|
|
8
|
-
export function Routes({ fallback = null }) {
|
|
9
|
-
const router = useRouter();
|
|
10
|
-
const state = useSnapshot((snapshot) => snapshot);
|
|
11
|
-
const module = router.routes.find((route) => route.path === state.path);
|
|
12
|
-
const component = state.error
|
|
13
|
-
? module?.ErrorBoundary
|
|
14
|
-
: state.state === "loading" && !state.loaded
|
|
15
|
-
? module?.HydrateFallback
|
|
16
|
-
: module?.default;
|
|
17
|
-
const element = useMemo(() => component &&
|
|
18
|
-
createElement(component, {
|
|
19
|
-
error: state.error,
|
|
20
|
-
}), [component, state.error]);
|
|
21
|
-
return element ?? state.error?.message ?? fallback;
|
|
22
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Request-scoped server rendering and HTTP data dispatch.
|
|
3
|
-
* @module
|
|
4
|
-
*/
|
|
5
|
-
import { createRouter, matchRoutes, safeWrapAsync, } from "../core/index.js";
|
|
6
|
-
/** Create one router per server request, await this, then render the provider. */
|
|
7
|
-
export async function loadRouter(routes, input) {
|
|
8
|
-
const url = typeof input === "string" ? input : input.url;
|
|
9
|
-
const wrap = (handler) => {
|
|
10
|
-
if (!handler || typeof input === "string")
|
|
11
|
-
return handler;
|
|
12
|
-
return (args) => {
|
|
13
|
-
const signal = AbortSignal.any([input.signal, args.signal]);
|
|
14
|
-
const request = new Request(args.request, { signal });
|
|
15
|
-
input.headers.forEach((value, name) => {
|
|
16
|
-
if (!request.headers.has(name))
|
|
17
|
-
request.headers.set(name, value);
|
|
18
|
-
});
|
|
19
|
-
return handler({ ...args, request, signal });
|
|
20
|
-
};
|
|
21
|
-
};
|
|
22
|
-
const serverRoutes = routes.map((route) => ({
|
|
23
|
-
...route,
|
|
24
|
-
clientLoader: undefined,
|
|
25
|
-
clientAction: undefined,
|
|
26
|
-
loader: wrap(route.loader),
|
|
27
|
-
action: wrap(route.action),
|
|
28
|
-
}));
|
|
29
|
-
const router = createRouter(serverRoutes, { url });
|
|
30
|
-
await router.navigate(url);
|
|
31
|
-
const snapshot = router.getSnapshot();
|
|
32
|
-
if (!snapshot.error &&
|
|
33
|
-
snapshot.data === undefined &&
|
|
34
|
-
routes.some((route) => route.path === snapshot.path && route.clientLoader && !route.loader)) {
|
|
35
|
-
return createRouter(serverRoutes, {
|
|
36
|
-
url,
|
|
37
|
-
hydrationData: { ...snapshot, loaded: false, state: "loading" },
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
return router;
|
|
41
|
-
}
|
|
42
|
-
export { serialize } from "../core/index.js";
|
|
43
|
-
/** Dispatch an HTTP data request to a registered server loader or action. */
|
|
44
|
-
export async function handleRequest(routes, request) {
|
|
45
|
-
const match = matchRoutes(routes, new URL(request.url).pathname);
|
|
46
|
-
const reading = request.method === "GET";
|
|
47
|
-
if (!match)
|
|
48
|
-
return Response.json({ error: "No route" }, { status: 404 });
|
|
49
|
-
if (!reading && !["POST", "PUT", "PATCH", "DELETE"].includes(request.method))
|
|
50
|
-
return Response.json({ error: "Method not allowed" }, { status: 405 });
|
|
51
|
-
const handler = reading ? match.route.loader : match.route.action;
|
|
52
|
-
if (!handler)
|
|
53
|
-
return Response.json({ error: `No ${reading ? "loader" : "action"}` }, { status: 405 });
|
|
54
|
-
const result = await safeWrapAsync(() => handler({ request, params: match.params, signal: request.signal }));
|
|
55
|
-
const error = result.error ?? (result.data instanceof Error && result.data);
|
|
56
|
-
if (error)
|
|
57
|
-
return Response.json({ error: error.message }, { status: 500 });
|
|
58
|
-
if (result.data instanceof Response) {
|
|
59
|
-
const location = result.data.headers.get("Location");
|
|
60
|
-
if (location)
|
|
61
|
-
return new Response(null, {
|
|
62
|
-
headers: { "X-Smolter-Redirect": location },
|
|
63
|
-
});
|
|
64
|
-
return result.data;
|
|
65
|
-
}
|
|
66
|
-
return Response.json(result.data ?? null, {
|
|
67
|
-
headers: { "Cache-Control": "no-store" },
|
|
68
|
-
});
|
|
69
|
-
}
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
-
import { resolve } from "node:path";
|
|
3
|
-
import { flatRoutes } from "../files/index.js";
|
|
4
|
-
import { transformWithOxc } from "vite";
|
|
5
|
-
import { configureTransport } from "./transport.js";
|
|
6
|
-
/** Build-time flat route discovery and the optional server data transport. */
|
|
7
|
-
export function routerPlugin({ directory = "src/routes", clientRoutes, serverRoutes, framework = "react", } = {}) {
|
|
8
|
-
let root;
|
|
9
|
-
let projectRoot;
|
|
10
|
-
const publicId = "virtual:smolter/routes";
|
|
11
|
-
const virtualId = `\0${publicId}`;
|
|
12
|
-
const suffix = "?smolter-client";
|
|
13
|
-
return {
|
|
14
|
-
name: "smolter-flat-routes",
|
|
15
|
-
enforce: "pre",
|
|
16
|
-
configResolved(config) {
|
|
17
|
-
projectRoot = config.root;
|
|
18
|
-
root = resolve(config.root, directory);
|
|
19
|
-
},
|
|
20
|
-
resolveId(id) {
|
|
21
|
-
if (id === publicId)
|
|
22
|
-
return virtualId;
|
|
23
|
-
},
|
|
24
|
-
async load(id, options) {
|
|
25
|
-
if (id.endsWith(suffix)) {
|
|
26
|
-
const file = id.slice(0, -suffix.length);
|
|
27
|
-
const transformed = await transformWithOxc(await readFile(file, "utf8"), file);
|
|
28
|
-
const ast = this.parse(transformed.code);
|
|
29
|
-
const edits = [];
|
|
30
|
-
for (const statement of ast.body) {
|
|
31
|
-
if (statement.type === "ExportAllDeclaration") {
|
|
32
|
-
return this.error(`Use explicit named exports in ${file}; export * cannot be safely split between server and browser.`);
|
|
33
|
-
}
|
|
34
|
-
if (statement.type !== "ExportNamedDeclaration")
|
|
35
|
-
continue;
|
|
36
|
-
const server = statement.specifiers.filter((specifier) => {
|
|
37
|
-
const name = specifier.exported.type === "Identifier"
|
|
38
|
-
? specifier.exported.name
|
|
39
|
-
: specifier.exported.value;
|
|
40
|
-
return name === "loader" || name === "action";
|
|
41
|
-
});
|
|
42
|
-
if (!server.length) {
|
|
43
|
-
const declaration = statement.declaration;
|
|
44
|
-
const name = declaration?.type === "FunctionDeclaration"
|
|
45
|
-
? declaration.id?.name
|
|
46
|
-
: undefined;
|
|
47
|
-
const variables = declaration?.type === "VariableDeclaration"
|
|
48
|
-
? declaration.declarations
|
|
49
|
-
: [];
|
|
50
|
-
if (name === "loader" ||
|
|
51
|
-
name === "action" ||
|
|
52
|
-
variables.some((item) => item.id.type === "Identifier" &&
|
|
53
|
-
["loader", "action"].includes(item.id.name))) {
|
|
54
|
-
return this.error(`Re-export loader/action from separate files in ${file}; inline server handlers cannot enter a browser module.`);
|
|
55
|
-
}
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
if (!statement.source ||
|
|
59
|
-
server.length !== statement.specifiers.length) {
|
|
60
|
-
return this.error(`Use separate export { loader } / export { action } statements in ${file}.`);
|
|
61
|
-
}
|
|
62
|
-
edits.push([statement.start, statement.end]);
|
|
63
|
-
}
|
|
64
|
-
let code = transformed.code;
|
|
65
|
-
for (const [start, end] of edits.reverse())
|
|
66
|
-
code = code.slice(0, start) + code.slice(end);
|
|
67
|
-
return { code, map: null };
|
|
68
|
-
}
|
|
69
|
-
if (id !== virtualId)
|
|
70
|
-
return;
|
|
71
|
-
if (clientRoutes || serverRoutes) {
|
|
72
|
-
if (!clientRoutes || !serverRoutes)
|
|
73
|
-
return this.error("Specify both clientRoutes and serverRoutes for manual routing.");
|
|
74
|
-
const entry = resolve(projectRoot, options?.ssr ? serverRoutes : clientRoutes).replaceAll("\\", "/");
|
|
75
|
-
return `export { routes as default } from ${JSON.stringify(entry)};`;
|
|
76
|
-
}
|
|
77
|
-
const routes = await flatRoutes(root);
|
|
78
|
-
if (routes instanceof Error)
|
|
79
|
-
return this.error(routes.message);
|
|
80
|
-
const imports = [];
|
|
81
|
-
const definitions = [];
|
|
82
|
-
for (const [index, route] of routes.entries()) {
|
|
83
|
-
this.addWatchFile(route.file);
|
|
84
|
-
const file = route.file.replaceAll("\\", "/");
|
|
85
|
-
const transformed = await transformWithOxc(await readFile(file, "utf8"), file);
|
|
86
|
-
const ast = this.parse(transformed.code);
|
|
87
|
-
const handlers = {};
|
|
88
|
-
for (const statement of ast.body) {
|
|
89
|
-
if (statement.type !== "ExportNamedDeclaration")
|
|
90
|
-
continue;
|
|
91
|
-
for (const specifier of statement.specifiers) {
|
|
92
|
-
const name = specifier.exported.type === "Identifier"
|
|
93
|
-
? specifier.exported.name
|
|
94
|
-
: specifier.exported.value;
|
|
95
|
-
if (name === "loader" || name === "action")
|
|
96
|
-
handlers[name] = true;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
imports.push(`import * as route${index} from ${JSON.stringify(file + (options?.ssr ? "" : suffix))};`);
|
|
100
|
-
definitions.push(options?.ssr || !Object.keys(handlers).length
|
|
101
|
-
? `{ ...route${index}, path: ${JSON.stringify(route.path)} }`
|
|
102
|
-
: `serverRoute(${JSON.stringify(route.path)}, route${index}, ${JSON.stringify(handlers)})`);
|
|
103
|
-
}
|
|
104
|
-
if (!options?.ssr &&
|
|
105
|
-
definitions.some((definition) => definition.startsWith("serverRoute(")))
|
|
106
|
-
imports.unshift(`import { serverRoute } from "@kasperrt/smolter/${framework}/client";`);
|
|
107
|
-
return `${imports.join("\n")}\nexport default [${definitions.join(",\n")}];\n`;
|
|
108
|
-
},
|
|
109
|
-
configureServer(server) {
|
|
110
|
-
server.watcher.add(root);
|
|
111
|
-
const refresh = (file) => {
|
|
112
|
-
if (!file.startsWith(`${root}/`))
|
|
113
|
-
return;
|
|
114
|
-
const module = server.moduleGraph.getModuleById(virtualId);
|
|
115
|
-
if (module)
|
|
116
|
-
server.moduleGraph.invalidateModule(module);
|
|
117
|
-
server.ws.send({ type: "full-reload" });
|
|
118
|
-
};
|
|
119
|
-
server.watcher.on("add", refresh);
|
|
120
|
-
server.watcher.on("change", refresh);
|
|
121
|
-
server.watcher.on("unlink", refresh);
|
|
122
|
-
server.httpServer?.once("close", () => {
|
|
123
|
-
server.watcher.off("add", refresh);
|
|
124
|
-
server.watcher.off("change", refresh);
|
|
125
|
-
server.watcher.off("unlink", refresh);
|
|
126
|
-
});
|
|
127
|
-
configureTransport(server, publicId, framework);
|
|
128
|
-
},
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
/** File routing is the default; this alias keeps configuration explicit. */
|
|
132
|
-
export const fileRouter = routerPlugin;
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
export function configureTransport(server, publicId, framework = "react") {
|
|
2
|
-
server.middlewares.use((incoming, outgoing, next) => {
|
|
3
|
-
if (!incoming.url?.startsWith("/_smolter?"))
|
|
4
|
-
return next();
|
|
5
|
-
const dispatch = async () => {
|
|
6
|
-
const origin = `http://${incoming.headers.host}`;
|
|
7
|
-
const target = new URL(incoming.url, origin).searchParams.get("url");
|
|
8
|
-
if (!target?.startsWith("/") || target.startsWith("//")) {
|
|
9
|
-
outgoing.statusCode = 400;
|
|
10
|
-
outgoing.end("Invalid route URL");
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
const headers = new Headers();
|
|
14
|
-
for (const [name, value] of Object.entries(incoming.headers)) {
|
|
15
|
-
if (value)
|
|
16
|
-
headers.set(name, Array.isArray(value) ? value.join(", ") : value);
|
|
17
|
-
}
|
|
18
|
-
const chunks = [];
|
|
19
|
-
for await (const chunk of incoming)
|
|
20
|
-
chunks.push(chunk);
|
|
21
|
-
const controller = new AbortController();
|
|
22
|
-
outgoing.once("close", () => controller.abort());
|
|
23
|
-
const request = new Request(new URL(target, origin), {
|
|
24
|
-
signal: controller.signal,
|
|
25
|
-
method: incoming.method,
|
|
26
|
-
headers,
|
|
27
|
-
...(incoming.method !== "GET" && {
|
|
28
|
-
body: new Uint8Array(Buffer.concat(chunks)),
|
|
29
|
-
}),
|
|
30
|
-
});
|
|
31
|
-
const [{ default: routes }, { handleRequest }] = await Promise.all([
|
|
32
|
-
server.ssrLoadModule(publicId),
|
|
33
|
-
server.ssrLoadModule(`@kasperrt/smolter/${framework}/server`),
|
|
34
|
-
]);
|
|
35
|
-
const response = await handleRequest(routes, request);
|
|
36
|
-
outgoing.statusCode = response.status;
|
|
37
|
-
response.headers.forEach((value, name) => outgoing.setHeader(name, value));
|
|
38
|
-
outgoing.end(new Uint8Array(await response.arrayBuffer()));
|
|
39
|
-
};
|
|
40
|
-
void dispatch().catch(next);
|
|
41
|
-
});
|
|
42
|
-
}
|
package/dist/preact-client.d.ts
DELETED
package/dist/preact-client.js
DELETED
package/dist/preact-server.d.ts
DELETED
package/dist/preact-server.js
DELETED
package/dist/preact-vite.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/** Optional flat-file routing for Preact builds. @module */
|
|
2
|
-
import { routerPlugin as createPlugin, } from "./internal/vite/index.js";
|
|
3
|
-
export * from "./internal/files/index.js";
|
|
4
|
-
/** Configure flat routes and server transport for Preact. */
|
|
5
|
-
export function routerPlugin(options = {}) {
|
|
6
|
-
return createPlugin({ ...options, framework: "preact" });
|
|
7
|
-
}
|
|
8
|
-
/** File routing is the default; this alias keeps configuration explicit. */
|
|
9
|
-
export const fileRouter = routerPlugin;
|
package/dist/preact.d.ts
DELETED
package/dist/preact.js
DELETED
package/dist/react-client.d.ts
DELETED
package/dist/react-client.js
DELETED
package/dist/react-server.d.ts
DELETED
package/dist/react-server.js
DELETED
package/dist/react-vite.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/** Optional flat-file routing for React builds. @module */
|
|
2
|
-
import { routerPlugin as createPlugin, } from "./internal/vite/index.js";
|
|
3
|
-
export * from "./internal/files/index.js";
|
|
4
|
-
/** Configure flat routes and server transport for React. */
|
|
5
|
-
export function routerPlugin(options = {}) {
|
|
6
|
-
return createPlugin({ ...options, framework: "react" });
|
|
7
|
-
}
|
|
8
|
-
/** File routing is the default; this alias keeps configuration explicit. */
|
|
9
|
-
export const fileRouter = routerPlugin;
|
package/dist/react.d.ts
DELETED
package/dist/react.js
DELETED
package/dist/server.d.ts
DELETED
package/dist/server.js
DELETED
package/dist/utils.d.ts
DELETED
package/dist/utils.js
DELETED
package/dist/vite.d.ts
DELETED
package/dist/vite.js
DELETED
package/src/client.ts
DELETED
package/src/core.ts
DELETED
package/src/files.ts
DELETED
package/src/internal/core/url.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Preact components and typed data hooks. Import from @kasperrt/smolter/preact.
|
|
3
|
-
* @module
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { Router, Snapshot } from "../core/index.ts";
|
|
7
|
-
import type { ReactNode } from "./runtime.ts";
|
|
8
|
-
import {
|
|
9
|
-
createContext,
|
|
10
|
-
createElement,
|
|
11
|
-
useContext,
|
|
12
|
-
useEffect,
|
|
13
|
-
useSyncExternalStore,
|
|
14
|
-
} from "./runtime.ts";
|
|
15
|
-
|
|
16
|
-
const RouterContext = createContext<Router | undefined>(undefined);
|
|
17
|
-
|
|
18
|
-
/** Router instance and children rendered within its context. */
|
|
19
|
-
export interface RouterProviderProps {
|
|
20
|
-
router: Router;
|
|
21
|
-
children?: ReactNode;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** Provide a router to descendant hooks and connect its browser lifecycle. */
|
|
25
|
-
export function RouterProvider({
|
|
26
|
-
router,
|
|
27
|
-
children,
|
|
28
|
-
}: RouterProviderProps): ReactNode {
|
|
29
|
-
useEffect(router.start, [router]);
|
|
30
|
-
|
|
31
|
-
return createElement(RouterContext.Provider, { value: router }, children);
|
|
32
|
-
}
|
|
33
|
-
/** Hooks require a RouterProvider. */
|
|
34
|
-
export function useRouter(): Router {
|
|
35
|
-
return useContext(RouterContext) as Router;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
type SnapshotSelector<T> = (snapshot: Snapshot) => T;
|
|
39
|
-
|
|
40
|
-
export function useSnapshot<T>(select: SnapshotSelector<T>): T {
|
|
41
|
-
const router = useRouter();
|
|
42
|
-
|
|
43
|
-
const getSnapshot = () => select(router.getSnapshot());
|
|
44
|
-
|
|
45
|
-
return useSyncExternalStore(router.subscribe, getSnapshot, getSnapshot);
|
|
46
|
-
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Preact components and typed data hooks. Import from @kasperrt/smolter/preact.
|
|
3
|
-
* @module
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { Fetcher, SubmitOptions } from "../core/index.ts";
|
|
7
|
-
import { internalURL } from "../core/index.ts";
|
|
8
|
-
import { useRouter } from "./context.ts";
|
|
9
|
-
import type { FormHTMLAttributes, ReactNode } from "./runtime.ts";
|
|
10
|
-
import { createElement } from "./runtime.ts";
|
|
11
|
-
|
|
12
|
-
/** Form attributes with GET loader requests or POST, PUT, PATCH, and DELETE actions. */
|
|
13
|
-
export interface FormProps
|
|
14
|
-
extends Omit<FormHTMLAttributes<HTMLFormElement>, "action" | "method"> {
|
|
15
|
-
action?: string;
|
|
16
|
-
method?: "get" | "post" | "put" | "patch" | "delete";
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
type FormSubmitEvent = Parameters<NonNullable<FormProps["onSubmit"]>>[0];
|
|
20
|
-
|
|
21
|
-
interface InternalFormProps extends FormProps {
|
|
22
|
-
fetcher?: Fetcher;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/** Submit form data to a registered route without a document reload. */
|
|
26
|
-
export function Form({
|
|
27
|
-
action,
|
|
28
|
-
method = "post",
|
|
29
|
-
fetcher,
|
|
30
|
-
onSubmit,
|
|
31
|
-
...props
|
|
32
|
-
}: InternalFormProps): ReactNode {
|
|
33
|
-
const router = useRouter();
|
|
34
|
-
const submit = (event: FormSubmitEvent) => {
|
|
35
|
-
onSubmit?.(event);
|
|
36
|
-
|
|
37
|
-
if (event.defaultPrevented) return;
|
|
38
|
-
|
|
39
|
-
const submitter = (event as SubmitEvent).submitter;
|
|
40
|
-
const target = internalURL(
|
|
41
|
-
router.getSnapshot().url,
|
|
42
|
-
submitter?.getAttribute("formaction") ?? action,
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
if (!target) return;
|
|
46
|
-
event.preventDefault();
|
|
47
|
-
|
|
48
|
-
const data = new FormData(event.currentTarget, submitter);
|
|
49
|
-
const verb = (
|
|
50
|
-
submitter?.getAttribute("formmethod") ?? method
|
|
51
|
-
).toUpperCase();
|
|
52
|
-
|
|
53
|
-
if (verb === "GET") {
|
|
54
|
-
const search = new URLSearchParams();
|
|
55
|
-
|
|
56
|
-
for (const [key, value] of data)
|
|
57
|
-
search.append(key, typeof value === "string" ? value : value.name);
|
|
58
|
-
|
|
59
|
-
target.search = String(search);
|
|
60
|
-
|
|
61
|
-
void (fetcher ? fetcher.load : router.navigate)(target.href);
|
|
62
|
-
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const options: SubmitOptions = {
|
|
67
|
-
method: verb as SubmitOptions["method"],
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
void (fetcher ?? router).submit(target.href, data, options);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
return createElement("form", {
|
|
74
|
-
...props,
|
|
75
|
-
action,
|
|
76
|
-
method: method === "get" ? "get" : "post",
|
|
77
|
-
onSubmit: submit,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Preact components and typed data hooks. Import from @kasperrt/smolter/preact.
|
|
3
|
-
* @module
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { internalURL } from "../core/index.ts";
|
|
7
|
-
import { useRouter } from "./context.ts";
|
|
8
|
-
import type { AnchorHTMLAttributes, MouseEvent, ReactNode } from "./runtime.ts";
|
|
9
|
-
import { createElement } from "./runtime.ts";
|
|
10
|
-
|
|
11
|
-
/** Anchor attributes with internal navigation and optional history replacement. */
|
|
12
|
-
export interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
13
|
-
href: string;
|
|
14
|
-
replace?: boolean;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/** Render an anchor that handles internal navigation and preserves native modified clicks. */
|
|
18
|
-
export function Link({
|
|
19
|
-
href,
|
|
20
|
-
replace,
|
|
21
|
-
onClick,
|
|
22
|
-
...props
|
|
23
|
-
}: LinkProps): ReactNode {
|
|
24
|
-
const router = useRouter();
|
|
25
|
-
const click = (event: MouseEvent<HTMLAnchorElement>) => {
|
|
26
|
-
onClick?.(event);
|
|
27
|
-
|
|
28
|
-
if (
|
|
29
|
-
event.defaultPrevented ||
|
|
30
|
-
event.button ||
|
|
31
|
-
event.metaKey ||
|
|
32
|
-
event.ctrlKey ||
|
|
33
|
-
event.altKey ||
|
|
34
|
-
event.shiftKey ||
|
|
35
|
-
props.download !== undefined ||
|
|
36
|
-
(props.target && props.target !== "_self")
|
|
37
|
-
)
|
|
38
|
-
return;
|
|
39
|
-
|
|
40
|
-
if (!internalURL(router.getSnapshot().url, href)) return;
|
|
41
|
-
event.preventDefault();
|
|
42
|
-
void router.navigate(href, { replace });
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
return createElement("a", { ...props, href, onClick: click });
|
|
46
|
-
}
|