weifuwu 0.31.1 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +238 -120
- package/dist/ai/agent.d.ts +127 -0
- package/dist/ai/index.d.ts +26 -0
- package/dist/ai/types.d.ts +59 -0
- package/dist/core/router.d.ts +11 -0
- package/dist/index.d.ts +16 -7
- package/dist/index.js +1186 -315
- package/dist/middleware/auth.d.ts +68 -0
- package/dist/middleware/esbuild-dev.d.ts +69 -0
- package/dist/middleware/esbuild-dev.js +335 -0
- package/dist/middleware/sandbox.d.ts +52 -0
- package/dist/middleware/tailwind-dev.d.ts +43 -0
- package/dist/middleware/tailwind-dev.js +199 -0
- package/dist/react/client.d.ts +64 -27
- package/dist/react/client.js +130 -248
- package/dist/react/compile.d.ts +17 -0
- package/dist/react/error-boundary.d.ts +18 -19
- package/dist/react/index.d.ts +80 -16
- package/dist/react/index.js +835 -267
- package/dist/react/types.d.ts +134 -34
- package/dist/types.d.ts +7 -0
- package/package.json +17 -6
- package/dist/react/navigation.d.ts +0 -63
- package/dist/react/navigation.js +0 -154
- package/dist/react/render.d.ts +0 -8
- package/dist/react/route-utils.d.ts +0 -31
package/dist/react/types.d.ts
CHANGED
|
@@ -1,46 +1,146 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { Context, Middleware } from '../types.ts';
|
|
1
|
+
import type { Context } from '../types.ts';
|
|
3
2
|
declare module '../types.ts' {
|
|
4
3
|
interface Context {
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Compile and render a .tsx file to HTML.
|
|
6
|
+
* The component should render a full page.
|
|
7
|
+
*/
|
|
8
|
+
render(path: string, opts?: RenderOptions): Promise<Response>;
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
11
|
+
/** Options for the react() middleware. */
|
|
12
|
+
export interface ReactOptions {
|
|
13
|
+
/**
|
|
14
|
+
* Path to a shared layout component (relative to cwd or absolute).
|
|
15
|
+
* The layout wraps every rendered page as its `children`.
|
|
16
|
+
* Layout + page are wrapped in HtmlShell for <html>/<head>/<body> structure.
|
|
17
|
+
*
|
|
18
|
+
* The layout component receives `{ children: ReactNode }`.
|
|
19
|
+
* Both layout and page can use `useServerData()`.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```tsx
|
|
23
|
+
* // layouts/Root.tsx
|
|
24
|
+
* export default function Root({ children }: { children: ReactNode }) {
|
|
25
|
+
* const { user } = useServerData()
|
|
26
|
+
* return <><Nav user={user} /><main>{children}</main><Footer /></>
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
layout?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Directory for compiled .tsx module cache.
|
|
33
|
+
* Default: node_modules/.weifuwu/react
|
|
34
|
+
* Persisted across restarts — source changes trigger recompilation.
|
|
35
|
+
*/
|
|
36
|
+
cacheDir?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface BootstrapScriptDescriptor {
|
|
39
|
+
src: string;
|
|
40
|
+
crossOrigin?: string;
|
|
41
|
+
integrity?: string;
|
|
27
42
|
}
|
|
28
43
|
export interface RenderOptions {
|
|
29
|
-
/**
|
|
44
|
+
/** Props passed directly to the page component. */
|
|
45
|
+
props?: Record<string, unknown>;
|
|
46
|
+
/** Data passed to useServerData() in the component tree. */
|
|
30
47
|
data?: Record<string, unknown>;
|
|
31
|
-
/**
|
|
32
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Async loader that runs before render.
|
|
50
|
+
* Receives ctx (with params, query) and returns data merged into useServerData().
|
|
51
|
+
* Throw HttpError for non-200 status codes.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* app.get('/users/:id', (_req, ctx) => ctx.render('./UserPage.tsx', {
|
|
56
|
+
* loader: async (ctx) => {
|
|
57
|
+
* const user = await db.findUser(ctx.params.id)
|
|
58
|
+
* if (!user) throw new HttpError('Not found', 404)
|
|
59
|
+
* return { user }
|
|
60
|
+
* },
|
|
61
|
+
* }))
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
loader?: (ctx: Context) => Promise<Record<string, unknown>>;
|
|
65
|
+
/** HTTP status code (default 200). */
|
|
33
66
|
status?: number;
|
|
67
|
+
/** Extra response headers. */
|
|
34
68
|
headers?: Record<string, string>;
|
|
69
|
+
/** Classic scripts injected by React. */
|
|
70
|
+
bootstrapScripts?: Array<string | BootstrapScriptDescriptor>;
|
|
71
|
+
/** ES module scripts injected by React. */
|
|
72
|
+
bootstrapModules?: Array<string | BootstrapScriptDescriptor>;
|
|
73
|
+
/**
|
|
74
|
+
* Import map for ES module resolution.
|
|
75
|
+
* Rendered as <script type="importmap"> in <head>.
|
|
76
|
+
*/
|
|
77
|
+
importMap?: {
|
|
78
|
+
imports?: Record<string, string>;
|
|
79
|
+
};
|
|
80
|
+
/** Stylesheet URLs injected as <link rel="stylesheet"> in <head>. */
|
|
81
|
+
stylesheets?: string[];
|
|
82
|
+
/**
|
|
83
|
+
* Enable streaming SSR (default: true).
|
|
84
|
+
* When true, the response starts sending immediately and Suspense
|
|
85
|
+
* boundaries are streamed as they resolve.
|
|
86
|
+
* When false, waits for all Suspense boundaries before sending.
|
|
87
|
+
*/
|
|
88
|
+
stream?: boolean;
|
|
35
89
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
90
|
+
/** Options for the reactRouter() helper. */
|
|
91
|
+
export interface ReactRouterOptions extends Omit<RenderOptions, 'component' | 'loader'> {
|
|
92
|
+
/**
|
|
93
|
+
* Shared layout component path (relative to cwd).
|
|
94
|
+
* Same as react()'s layout option.
|
|
95
|
+
*/
|
|
96
|
+
layout?: string;
|
|
97
|
+
/**
|
|
98
|
+
* Per-route loaders. Keys must match paths in the routes config.
|
|
99
|
+
* Each loader receives ctx and returns data merged into useServerData().
|
|
100
|
+
* Throw HttpError for non-200 status codes.
|
|
101
|
+
*/
|
|
102
|
+
loaders?: Record<string, (ctx: Context) => Promise<Record<string, unknown>>>;
|
|
41
103
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
104
|
+
/** Options for createReactApp — one call to set up SSR routing + client bundle. */
|
|
105
|
+
export interface ReactAppOptions {
|
|
106
|
+
/** Page route → component path mapping for both server and client. */
|
|
107
|
+
pages: Record<string, string>;
|
|
108
|
+
/** Per-route data loaders. Keys match page route paths. */
|
|
109
|
+
loaders?: Record<string, (ctx: Context) => Promise<Record<string, unknown>>>;
|
|
110
|
+
/** Shared layout component path (relative to cwd). */
|
|
111
|
+
layout: string;
|
|
112
|
+
/** 404 fallback component path (relative to cwd). */
|
|
113
|
+
notFound?: string;
|
|
114
|
+
/** Stylesheet URLs injected in <head>. */
|
|
115
|
+
stylesheets?: string[];
|
|
116
|
+
/** ES module bootstrap scripts. */
|
|
117
|
+
bootstrapModules?: Array<string | BootstrapScriptDescriptor>;
|
|
118
|
+
/**
|
|
119
|
+
* Client bundle config.
|
|
120
|
+
* - `false` to disable client-side JS (static SSR only)
|
|
121
|
+
* - `true` or omitted for defaults
|
|
122
|
+
* - `{ ... }` to customize
|
|
123
|
+
*/
|
|
124
|
+
client?: boolean | {
|
|
125
|
+
/** URL path for the client bundle (default: '/assets/client.js'). */
|
|
126
|
+
path?: string;
|
|
127
|
+
/** Minify output (default: false). */
|
|
128
|
+
minify?: boolean;
|
|
129
|
+
/** Code splitting (default: true). */
|
|
130
|
+
splitting?: boolean;
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* Tailwind CSS config. When provided, tailwindDev middleware is set up
|
|
134
|
+
* and the output path is automatically added to stylesheets.
|
|
135
|
+
*/
|
|
136
|
+
tailwind?: {
|
|
137
|
+
/** URL path for the compiled CSS (default: '/assets/tailwind.css'). */
|
|
138
|
+
path?: string;
|
|
139
|
+
/** Source CSS entry point (default: './styles/input.css'). */
|
|
140
|
+
entry?: string;
|
|
141
|
+
};
|
|
142
|
+
/** Compilation cache directory. */
|
|
143
|
+
cacheDir?: string;
|
|
144
|
+
/** Enable streaming SSR (default: true). */
|
|
145
|
+
stream?: boolean;
|
|
45
146
|
}
|
|
46
|
-
export type ReactMiddleware = Middleware<Context, Context & ReactInjected>;
|
package/dist/types.d.ts
CHANGED
|
@@ -19,6 +19,13 @@ export interface WebSocket {
|
|
|
19
19
|
removeEventListener(event: string, handler: (...args: unknown[]) => void): void;
|
|
20
20
|
}
|
|
21
21
|
export type { Redis, RedisOptions } from 'ioredis';
|
|
22
|
+
/** User injected by auth() middleware. */
|
|
23
|
+
export interface User {
|
|
24
|
+
id: string;
|
|
25
|
+
role?: string;
|
|
26
|
+
tenant?: string;
|
|
27
|
+
[key: string]: unknown;
|
|
28
|
+
}
|
|
22
29
|
export interface WsContext {
|
|
23
30
|
/** Per-connection state object */
|
|
24
31
|
state: Record<string, unknown>;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "weifuwu",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.32.0",
|
|
5
5
|
"description": "Web-standard HTTP microframework for Node.js — (req, ctx) => Response",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
@@ -15,10 +15,6 @@
|
|
|
15
15
|
"./react/client": {
|
|
16
16
|
"types": "./dist/react/client.d.ts",
|
|
17
17
|
"default": "./dist/react/client.js"
|
|
18
|
-
},
|
|
19
|
-
"./react/navigation": {
|
|
20
|
-
"types": "./dist/react/navigation.d.ts",
|
|
21
|
-
"default": "./dist/react/navigation.js"
|
|
22
18
|
}
|
|
23
19
|
},
|
|
24
20
|
"files": [
|
|
@@ -36,25 +32,39 @@
|
|
|
36
32
|
},
|
|
37
33
|
"dependencies": {
|
|
38
34
|
"@graphql-tools/schema": "^10",
|
|
35
|
+
"ai": "^7.0.14",
|
|
39
36
|
"graphql": "^16",
|
|
40
37
|
"ioredis": "^5.11.0",
|
|
41
38
|
"postgres": "^3.4.9",
|
|
42
39
|
"ws": "^8"
|
|
43
40
|
},
|
|
44
41
|
"peerDependencies": {
|
|
42
|
+
"@tailwindcss/node": "^4",
|
|
43
|
+
"esbuild": "^0.28",
|
|
45
44
|
"react": "19",
|
|
46
|
-
"react-dom": "19"
|
|
45
|
+
"react-dom": "19",
|
|
46
|
+
"tailwindcss": "^4"
|
|
47
47
|
},
|
|
48
48
|
"peerDependenciesMeta": {
|
|
49
|
+
"@tailwindcss/node": {
|
|
50
|
+
"optional": true
|
|
51
|
+
},
|
|
52
|
+
"esbuild": {
|
|
53
|
+
"optional": true
|
|
54
|
+
},
|
|
49
55
|
"react": {
|
|
50
56
|
"optional": true
|
|
51
57
|
},
|
|
52
58
|
"react-dom": {
|
|
53
59
|
"optional": true
|
|
60
|
+
},
|
|
61
|
+
"tailwindcss": {
|
|
62
|
+
"optional": true
|
|
54
63
|
}
|
|
55
64
|
},
|
|
56
65
|
"devDependencies": {
|
|
57
66
|
"@eslint/js": "^10.0.1",
|
|
67
|
+
"@tailwindcss/node": "^4.3.2",
|
|
58
68
|
"@types/node": "^25",
|
|
59
69
|
"@types/react": "^19.2.17",
|
|
60
70
|
"@types/react-dom": "^19.2.3",
|
|
@@ -63,6 +73,7 @@
|
|
|
63
73
|
"globals": "^17.7.0",
|
|
64
74
|
"react": "^19.2.7",
|
|
65
75
|
"react-dom": "^19.2.7",
|
|
76
|
+
"tailwindcss": "^4.3.2",
|
|
66
77
|
"typescript-eslint": "^8.62.1"
|
|
67
78
|
},
|
|
68
79
|
"sideEffects": false
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared navigation primitives — usable on both server and client.
|
|
3
|
-
*
|
|
4
|
-
* - Link: renders <a> on server (no RouterContext), SPA <a> on client
|
|
5
|
-
* - useParams / useNavigate: client hooks (throw friendly error on server)
|
|
6
|
-
*/
|
|
7
|
-
import { type ReactNode, type ReactElement } from 'react';
|
|
8
|
-
export type NavigationState = 'idle' | 'loading';
|
|
9
|
-
export interface RouterContextValue {
|
|
10
|
-
params: Record<string, string>;
|
|
11
|
-
navigate: (url: string) => Promise<void>;
|
|
12
|
-
revalidate: () => Promise<void>;
|
|
13
|
-
state: NavigationState;
|
|
14
|
-
}
|
|
15
|
-
export declare const RouterContext: import("react").Context<RouterContextValue | null>;
|
|
16
|
-
/** Get current route params. Returns {} when no router context (SSR / outside router). */
|
|
17
|
-
export declare function useParams(): Record<string, string>;
|
|
18
|
-
/** Programmatic navigation. Throws if used outside a client router. */
|
|
19
|
-
export declare function useNavigate(): (url: string) => Promise<void>;
|
|
20
|
-
/** Navigation state — 'idle' or 'loading'. Use for progress bars / disabled states. */
|
|
21
|
-
export declare function useNavigation(): {
|
|
22
|
-
state: NavigationState;
|
|
23
|
-
};
|
|
24
|
-
export interface LinkProps {
|
|
25
|
-
href: string;
|
|
26
|
-
children: ReactNode;
|
|
27
|
-
[key: string]: unknown;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Navigation link.
|
|
31
|
-
*
|
|
32
|
-
* When inside a client router context: intercepts clicks for SPA navigation.
|
|
33
|
-
* When outside (SSR / plain React): renders a plain <a> tag.
|
|
34
|
-
*
|
|
35
|
-
* Both cases produce identical DOM output — safe for hydration.
|
|
36
|
-
*/
|
|
37
|
-
export declare function Link({ href, children, ...props }: LinkProps): ReactElement;
|
|
38
|
-
export interface FormProps {
|
|
39
|
-
method?: 'get' | 'post' | 'put' | 'delete' | 'patch';
|
|
40
|
-
action?: string;
|
|
41
|
-
children: ReactNode;
|
|
42
|
-
[key: string]: unknown;
|
|
43
|
-
}
|
|
44
|
-
/** Revalidate the current route's data. */
|
|
45
|
-
export declare function useRevalidate(): () => Promise<void>;
|
|
46
|
-
/**
|
|
47
|
-
* SPA form — submits via fetch instead of full page reload.
|
|
48
|
-
*
|
|
49
|
-
* On submit:
|
|
50
|
-
* 1. Serializes form data via FormData
|
|
51
|
-
* 2. fetch(action, { method, body })
|
|
52
|
-
* 3. On redirect (3xx): SPA-navigates to the Location header
|
|
53
|
-
* 4. On success: revalidates the current route's loader
|
|
54
|
-
*
|
|
55
|
-
* On the server (no RouterContext): renders a plain <form>.
|
|
56
|
-
*/
|
|
57
|
-
export declare function Form({ method, action, children, ...props }: FormProps): ReactElement;
|
|
58
|
-
export declare function matchPath(pathname: string, pattern: string): Record<string, string> | null;
|
|
59
|
-
export { useServerData } from './hooks.ts';
|
|
60
|
-
export { ServerDataContext } from './context.ts';
|
|
61
|
-
export { ErrorBoundary } from './error-boundary.ts';
|
|
62
|
-
export type { ErrorBoundaryProps } from './error-boundary.ts';
|
|
63
|
-
export { defineRoute } from './route-utils.ts';
|
package/dist/react/navigation.js
DELETED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
// src/react/navigation.ts
|
|
2
|
-
import {
|
|
3
|
-
createElement,
|
|
4
|
-
createContext as createContext2,
|
|
5
|
-
useContext as useContext2
|
|
6
|
-
} from "react";
|
|
7
|
-
|
|
8
|
-
// src/react/hooks.ts
|
|
9
|
-
import { useContext } from "react";
|
|
10
|
-
|
|
11
|
-
// src/react/context.ts
|
|
12
|
-
import { createContext } from "react";
|
|
13
|
-
var CTX_KEY = /* @__PURE__ */ Symbol.for("weifuwu.react.ServerDataContext");
|
|
14
|
-
function getServerDataContext() {
|
|
15
|
-
const globalStore = globalThis;
|
|
16
|
-
if (globalStore[CTX_KEY]) return globalStore[CTX_KEY];
|
|
17
|
-
const ctx = createContext({});
|
|
18
|
-
ctx.displayName = "ServerData";
|
|
19
|
-
globalStore[CTX_KEY] = ctx;
|
|
20
|
-
return ctx;
|
|
21
|
-
}
|
|
22
|
-
var ServerDataContext = getServerDataContext();
|
|
23
|
-
|
|
24
|
-
// src/react/hooks.ts
|
|
25
|
-
function useServerData() {
|
|
26
|
-
return useContext(ServerDataContext);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// src/react/error-boundary.ts
|
|
30
|
-
import { Component } from "react";
|
|
31
|
-
var ErrorBoundary = class extends Component {
|
|
32
|
-
state = { error: null };
|
|
33
|
-
static getDerivedStateFromError(error) {
|
|
34
|
-
return { error };
|
|
35
|
-
}
|
|
36
|
-
componentDidCatch(error, info) {
|
|
37
|
-
this.props.onError?.(error, info);
|
|
38
|
-
}
|
|
39
|
-
render() {
|
|
40
|
-
if (this.state.error) {
|
|
41
|
-
return this.props.fallback;
|
|
42
|
-
}
|
|
43
|
-
return this.props.children;
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
// src/react/route-utils.ts
|
|
48
|
-
function defineRoute(config) {
|
|
49
|
-
return config;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// src/react/navigation.ts
|
|
53
|
-
var RouterContext = createContext2(null);
|
|
54
|
-
RouterContext.displayName = "ClientRouter";
|
|
55
|
-
function useParams() {
|
|
56
|
-
return useContext2(RouterContext)?.params ?? {};
|
|
57
|
-
}
|
|
58
|
-
function useNavigate() {
|
|
59
|
-
const ctx = useContext2(RouterContext);
|
|
60
|
-
if (!ctx) throw new Error("useNavigate() must be used within a client router");
|
|
61
|
-
return ctx.navigate;
|
|
62
|
-
}
|
|
63
|
-
function useNavigation() {
|
|
64
|
-
const ctx = useContext2(RouterContext);
|
|
65
|
-
return { state: ctx?.state ?? "idle" };
|
|
66
|
-
}
|
|
67
|
-
function Link({ href, children, ...props }) {
|
|
68
|
-
const router = useContext2(RouterContext);
|
|
69
|
-
const isExternal = href.startsWith("http://") || href.startsWith("https://") || href.startsWith("//") || href.startsWith("mailto:") || href.startsWith("tel:");
|
|
70
|
-
if (!router || isExternal || props.target !== void 0) {
|
|
71
|
-
return createElement("a", { href, ...props }, children);
|
|
72
|
-
}
|
|
73
|
-
const handleClick = (e) => {
|
|
74
|
-
if (e.ctrlKey || e.metaKey || e.altKey || e.shiftKey) return;
|
|
75
|
-
if (e.button !== 0) return;
|
|
76
|
-
e.preventDefault();
|
|
77
|
-
router.navigate(href);
|
|
78
|
-
};
|
|
79
|
-
return createElement("a", { href, onClick: handleClick, ...props }, children);
|
|
80
|
-
}
|
|
81
|
-
function useRevalidate() {
|
|
82
|
-
const ctx = useContext2(RouterContext);
|
|
83
|
-
if (!ctx) throw new Error("useRevalidate() must be used within a client router");
|
|
84
|
-
return ctx.revalidate;
|
|
85
|
-
}
|
|
86
|
-
function Form({ method = "post", action, children, ...props }) {
|
|
87
|
-
const router = useContext2(RouterContext);
|
|
88
|
-
if (!router) {
|
|
89
|
-
return createElement("form", { method, action, ...props }, children);
|
|
90
|
-
}
|
|
91
|
-
const handleSubmit = async (e) => {
|
|
92
|
-
e.preventDefault();
|
|
93
|
-
const form = e.target;
|
|
94
|
-
const formData = new FormData(form);
|
|
95
|
-
const url = action || window.location.pathname;
|
|
96
|
-
const fetchMethod = method === "get" ? "GET" : method.toUpperCase();
|
|
97
|
-
try {
|
|
98
|
-
const res = await fetch(url, {
|
|
99
|
-
method: fetchMethod,
|
|
100
|
-
body: fetchMethod === "GET" ? void 0 : formData,
|
|
101
|
-
redirect: "manual"
|
|
102
|
-
});
|
|
103
|
-
if (res.status >= 300 && res.status < 400) {
|
|
104
|
-
const loc = res.headers.get("Location");
|
|
105
|
-
if (loc) {
|
|
106
|
-
router.navigate(loc);
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
await router.revalidate();
|
|
111
|
-
} catch (err) {
|
|
112
|
-
console.error("[weifuwu/react] Form submit failed:", err);
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
return createElement(
|
|
116
|
-
"form",
|
|
117
|
-
{ method, action, ...props, onSubmit: handleSubmit },
|
|
118
|
-
children
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
function matchPath(pathname, pattern) {
|
|
122
|
-
const patParts = pattern.split("/").filter(Boolean);
|
|
123
|
-
const pathParts = pathname.split("/").filter(Boolean);
|
|
124
|
-
const hasWildcard = patParts[patParts.length - 1] === "*";
|
|
125
|
-
if (!hasWildcard && patParts.length !== pathParts.length) return null;
|
|
126
|
-
if (hasWildcard && pathParts.length < patParts.length - 1) return null;
|
|
127
|
-
const params = {};
|
|
128
|
-
for (let i = 0; i < patParts.length; i++) {
|
|
129
|
-
if (patParts[i] === "*") {
|
|
130
|
-
params["*"] = pathParts.slice(i).join("/");
|
|
131
|
-
break;
|
|
132
|
-
}
|
|
133
|
-
if (patParts[i].startsWith(":")) {
|
|
134
|
-
params[patParts[i].slice(1)] = decodeURIComponent(pathParts[i]);
|
|
135
|
-
} else if (patParts[i] !== pathParts[i]) {
|
|
136
|
-
return null;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
return params;
|
|
140
|
-
}
|
|
141
|
-
export {
|
|
142
|
-
ErrorBoundary,
|
|
143
|
-
Form,
|
|
144
|
-
Link,
|
|
145
|
-
RouterContext,
|
|
146
|
-
ServerDataContext,
|
|
147
|
-
defineRoute,
|
|
148
|
-
matchPath,
|
|
149
|
-
useNavigate,
|
|
150
|
-
useNavigation,
|
|
151
|
-
useParams,
|
|
152
|
-
useRevalidate,
|
|
153
|
-
useServerData
|
|
154
|
-
};
|
package/dist/react/render.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { type ReactElement, type ComponentType, type ReactNode } from 'react';
|
|
2
|
-
import type { RenderOptions } from './types.ts';
|
|
3
|
-
export declare function render(element: ReactElement, layouts: ComponentType<{
|
|
4
|
-
children: ReactNode;
|
|
5
|
-
}>[], options?: RenderOptions): Response;
|
|
6
|
-
export declare function renderStream(element: ReactElement, layouts: ComponentType<{
|
|
7
|
-
children: ReactNode;
|
|
8
|
-
}>[], options?: RenderOptions): Promise<Response>;
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { ComponentType } from 'react';
|
|
2
|
-
/**
|
|
3
|
-
* Type-safe route definition.
|
|
4
|
-
*
|
|
5
|
-
* Captures the loader return type as a phantom `$data` field.
|
|
6
|
-
* Use with `useServerData<typeof route.$data>()` for auto-complete.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```ts
|
|
10
|
-
* const userRoute = defineRoute({
|
|
11
|
-
* path: '/users/:id',
|
|
12
|
-
* component: UserPage,
|
|
13
|
-
* loader: (params) => fetch(`/users/${params.id}?_data`).then(r => r.json()),
|
|
14
|
-
* })
|
|
15
|
-
* // userRoute.$data = { user: { id: number; name: string; ... } }
|
|
16
|
-
*
|
|
17
|
-
* // In the component:
|
|
18
|
-
* const { user } = useServerData<typeof userRoute.$data>()
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
|
-
export declare function defineRoute<T extends Record<string, unknown> = Record<string, unknown>>(config: {
|
|
22
|
-
path: string;
|
|
23
|
-
component: ComponentType;
|
|
24
|
-
loader: (params: Record<string, string>) => Promise<T>;
|
|
25
|
-
}): {
|
|
26
|
-
path: string;
|
|
27
|
-
component: ComponentType;
|
|
28
|
-
loader: (params: Record<string, string>) => Promise<T>;
|
|
29
|
-
/** Phantom type — use with `typeof route.$data` for `useServerData`. */
|
|
30
|
-
$data: T;
|
|
31
|
-
};
|