@pracht/core 0.8.1 → 0.9.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 +5 -1
- package/dist/app-BN3pjxtw.d.mts +24 -0
- package/dist/{app-w-P1wf5T.mjs → app-CGRKjZ6Z.mjs} +96 -7
- package/dist/app-graph-BlaCcGUZ.mjs +52 -0
- package/dist/app-graph-DBoDsHJ5.d.mts +38 -0
- package/dist/browser.d.mts +7 -6
- package/dist/browser.mjs +8 -7
- package/dist/client.d.mts +3 -3
- package/dist/client.mjs +3 -3
- package/dist/dev-404.d.mts +26 -0
- package/dist/dev-404.mjs +166 -0
- package/dist/devtools.d.mts +8 -0
- package/dist/devtools.mjs +156 -0
- package/dist/error-overlay.d.mts +38 -1
- package/dist/error-overlay.mjs +134 -5
- package/dist/index.d.mts +9 -7
- package/dist/index.mjs +9 -7
- package/dist/manifest.d.mts +2 -1
- package/dist/manifest.mjs +1 -1
- package/dist/{runtime-context-B5pREhcM.mjs → navigation-state-BjwXTeVz.mjs} +74 -2
- package/dist/{prefetch-D9amIQtw.mjs → prefetch-COYeuvQK.mjs} +44 -27
- package/dist/prefetch-api-Bf-P7XFo.d.mts +39 -0
- package/dist/prefetch-api-ChSCTbEB.mjs +69 -0
- package/dist/{prefetch-cache-DzP2Bj9H.mjs → prefetch-cache-BNLEp9H5.mjs} +12 -1
- package/dist/{prerender-B8_CqYwd.d.mts → prerender-BV42B9jK.d.mts} +31 -2
- package/dist/{prerender-CoMyuJKm.mjs → prerender-C8BpANz3.mjs} +53 -9
- package/dist/{router-BcUmg1kB.d.mts → router-B_Aj5TtY.d.mts} +2 -2
- package/dist/{router-BkkyNjqB.mjs → router-E5Wh-dOR.mjs} +251 -58
- package/dist/{runtime-context-ytVd7GmZ.d.mts → runtime-context-BYBwVA0M.d.mts} +1 -1
- package/dist/{runtime-middleware-aeBdgjYr.d.mts → runtime-middleware-pYubngnL.d.mts} +57 -4
- package/dist/server.d.mts +7 -5
- package/dist/server.mjs +6 -5
- package/dist/{app-BWriseLj.d.mts → types-B-sfVjaH.d.mts} +42 -22
- package/dist/{types-DQv2poC5.mjs → types-DEPXdbyp.mjs} +43 -15
- package/package.json +9 -1
- package/dist/hydration-M1QzbQ1O.d.mts +0 -23
- /package/dist/{forwardRef-grZ6t4GS.mjs → forwardRef-B0cSkHwH.mjs} +0 -0
package/README.md
CHANGED
|
@@ -36,13 +36,17 @@ metadata for the failure phase and matched framework files when available.
|
|
|
36
36
|
|
|
37
37
|
- `startApp()` — client-side hydration and runtime
|
|
38
38
|
- `useLocation()` — access the current pathname and search string separately
|
|
39
|
-
- `useRouteData()` — access loader data inside a route component
|
|
39
|
+
- `useRouteData()` — access loader data inside a route component; pass a route
|
|
40
|
+
id for fully typed data after `pracht typegen`, or a `typeof loader` generic
|
|
41
|
+
otherwise
|
|
40
42
|
- `useRevalidate()` — trigger a revalidation of the current route's data
|
|
41
43
|
- `<Form>` — progressive enhancement form component
|
|
42
44
|
|
|
43
45
|
### Types
|
|
44
46
|
|
|
45
47
|
- `LoaderData<T>` — infer the return type of a loader
|
|
48
|
+
- `RouteLoaderData<TModule, TFallbackModule?>` — infer loader data from a route
|
|
49
|
+
module type; used by `pracht typegen` to key loader data by route id
|
|
46
50
|
- `RouteComponentProps<T>` — props type for route components
|
|
47
51
|
- `LoaderArgs` — argument type passed to loaders
|
|
48
52
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { F as PrachtApp, G as RouteConfig, H as ResolvedPrachtApp, I as PrachtAppConfig, J as RouteId, M as ModuleRef, V as ResolvedApiRoute, X as RouteMatch, Z as RouteMeta, _ as HrefArgs, b as HrefRouteDefinition, d as GroupMeta, et as RouteParams, ft as TimeRevalidatePolicy, i as ApiRouteMatch, it as RouteSegment, ot as RouteTreeNode, q as RouteDefinition, u as GroupDefinition } from "./types-B-sfVjaH.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/app.d.ts
|
|
4
|
+
declare function timeRevalidate(seconds: number): TimeRevalidatePolicy;
|
|
5
|
+
declare function route(path: string, file: ModuleRef, meta?: RouteMeta): RouteDefinition;
|
|
6
|
+
declare function route(path: string, config: RouteConfig): RouteDefinition;
|
|
7
|
+
declare function group(meta: GroupMeta, routes: RouteTreeNode[]): GroupDefinition;
|
|
8
|
+
declare function defineApp(config: PrachtAppConfig): PrachtApp;
|
|
9
|
+
declare function resolveApp(app: PrachtApp): ResolvedPrachtApp;
|
|
10
|
+
declare function matchAppRoute(app: PrachtApp | ResolvedPrachtApp, pathname: string): RouteMatch | undefined;
|
|
11
|
+
declare function buildPathFromSegments(segments: readonly RouteSegment[], params: RouteParams): string;
|
|
12
|
+
declare function buildHref<TRoute extends RouteId>(routes: readonly HrefRouteDefinition[], routeId: TRoute, ...args: HrefArgs<TRoute>): string;
|
|
13
|
+
/**
|
|
14
|
+
* Convert a list of file paths from `import.meta.glob` into resolved API routes.
|
|
15
|
+
*
|
|
16
|
+
* Example: `"/src/api/health.ts"` → path `/api/health`
|
|
17
|
+
* `"/src/api/users/[id].ts"` → path `/api/users/:id`
|
|
18
|
+
* `"/src/api/files/[...path].ts"` → path `/api/files/*`
|
|
19
|
+
* `"/src/api/index.ts"` → path `/api`
|
|
20
|
+
*/
|
|
21
|
+
declare function resolveApiRoutes(files: string[], apiDir?: string): ResolvedApiRoute[];
|
|
22
|
+
declare function matchApiRoute(apiRoutes: ResolvedApiRoute[], pathname: string): ApiRouteMatch | undefined;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { matchApiRoute as a, resolveApp as c, group as i, route as l, buildPathFromSegments as n, matchAppRoute as o, defineApp as r, resolveApiRoutes as s, buildHref as t, timeRevalidate as u };
|
|
@@ -1,3 +1,61 @@
|
|
|
1
|
+
//#region src/name-suggestions.ts
|
|
2
|
+
/**
|
|
3
|
+
* "Did you mean" helpers for manifest wiring errors.
|
|
4
|
+
*
|
|
5
|
+
* When a route references an unknown shell, middleware, or route id, the
|
|
6
|
+
* error message includes the closest registered name plus the full list of
|
|
7
|
+
* registered names. A tiny internal edit-distance implementation keeps this
|
|
8
|
+
* dependency-free.
|
|
9
|
+
*/
|
|
10
|
+
/** Classic Levenshtein edit distance using two rolling rows. */
|
|
11
|
+
function levenshteinDistance(a, b) {
|
|
12
|
+
if (a === b) return 0;
|
|
13
|
+
if (a.length === 0) return b.length;
|
|
14
|
+
if (b.length === 0) return a.length;
|
|
15
|
+
let previous = Array.from({ length: b.length + 1 }, (_, index) => index);
|
|
16
|
+
let current = Array.from({ length: b.length + 1 });
|
|
17
|
+
for (let i = 1; i <= a.length; i += 1) {
|
|
18
|
+
current[0] = i;
|
|
19
|
+
for (let j = 1; j <= b.length; j += 1) {
|
|
20
|
+
const substitution = previous[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1);
|
|
21
|
+
current[j] = Math.min(previous[j] + 1, current[j - 1] + 1, substitution);
|
|
22
|
+
}
|
|
23
|
+
[previous, current] = [current, previous];
|
|
24
|
+
}
|
|
25
|
+
return previous[b.length];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Return the candidate closest to `input`, or `undefined` when nothing is
|
|
29
|
+
* close enough to be a plausible typo. The threshold scales with the input
|
|
30
|
+
* length (roughly a third of it, minimum 2 edits).
|
|
31
|
+
*/
|
|
32
|
+
function closestName(input, candidates) {
|
|
33
|
+
let best;
|
|
34
|
+
let bestDistance = Infinity;
|
|
35
|
+
for (const candidate of candidates) {
|
|
36
|
+
const distance = levenshteinDistance(input.toLowerCase(), candidate.toLowerCase());
|
|
37
|
+
if (distance < bestDistance) {
|
|
38
|
+
bestDistance = distance;
|
|
39
|
+
best = candidate;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const threshold = Math.max(2, Math.floor(input.length / 3));
|
|
43
|
+
return bestDistance <= threshold ? best : void 0;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Format an enriched wiring error, e.g.
|
|
47
|
+
* `Unknown shell "pubic" for route "/". Did you mean "public"? Registered shells: public, app.`
|
|
48
|
+
*/
|
|
49
|
+
function formatUnknownNameError(options) {
|
|
50
|
+
const { kind, name, registered, context } = options;
|
|
51
|
+
const kindPlural = options.kindPlural ?? `${kind}s`;
|
|
52
|
+
let message = `Unknown ${kind} "${name}"${context ? ` for ${context}` : ""}.`;
|
|
53
|
+
const suggestion = closestName(name, registered);
|
|
54
|
+
if (suggestion) message += ` Did you mean "${suggestion}"?`;
|
|
55
|
+
message += registered.length > 0 ? ` Registered ${kindPlural}: ${registered.join(", ")}.` : ` No ${kindPlural} are registered in defineApp().`;
|
|
56
|
+
return message;
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
1
59
|
//#region src/app.ts
|
|
2
60
|
function timeRevalidate(seconds) {
|
|
3
61
|
if (!Number.isInteger(seconds) || seconds <= 0) throw new Error("timeRevalidate expects a positive integer number of seconds.");
|
|
@@ -40,7 +98,8 @@ function defineApp(config) {
|
|
|
40
98
|
shells: resolveModuleRefRecord(config.shells ?? {}),
|
|
41
99
|
middleware: resolveModuleRefRecord(config.middleware ?? {}),
|
|
42
100
|
api: config.api ?? {},
|
|
43
|
-
routes: config.routes
|
|
101
|
+
routes: config.routes,
|
|
102
|
+
viewTransitions: config.viewTransitions
|
|
44
103
|
};
|
|
45
104
|
}
|
|
46
105
|
function resolveModuleRefRecord(record) {
|
|
@@ -54,13 +113,21 @@ function resolveApp(app) {
|
|
|
54
113
|
pathPrefix: "/",
|
|
55
114
|
middleware: []
|
|
56
115
|
};
|
|
116
|
+
for (const name of app.api?.middleware ?? []) if (!hasOwnEntry(app.middleware, name)) throw new Error(formatUnknownNameError({
|
|
117
|
+
kind: "middleware",
|
|
118
|
+
kindPlural: "middleware",
|
|
119
|
+
name,
|
|
120
|
+
registered: Object.keys(app.middleware),
|
|
121
|
+
context: "api routes"
|
|
122
|
+
}));
|
|
57
123
|
for (const node of app.routes) flattenRouteNode(app, node, inherited, routes);
|
|
58
124
|
return {
|
|
59
125
|
shells: app.shells,
|
|
60
126
|
middleware: app.middleware,
|
|
61
127
|
api: app.api,
|
|
62
128
|
routes,
|
|
63
|
-
apiRoutes: []
|
|
129
|
+
apiRoutes: [],
|
|
130
|
+
viewTransitions: app.viewTransitions
|
|
64
131
|
};
|
|
65
132
|
}
|
|
66
133
|
function matchAppRoute(app, pathname) {
|
|
@@ -90,6 +157,12 @@ function flattenRouteNode(app, node, inherited, routes) {
|
|
|
90
157
|
const fullPath = mergeRoutePaths(inherited.pathPrefix, node.path);
|
|
91
158
|
const shell = node.shell ?? inherited.shell;
|
|
92
159
|
const middleware = [...inherited.middleware, ...node.middleware ?? []];
|
|
160
|
+
if (shell !== void 0 && !hasOwnEntry(app.shells, shell)) throw new Error(formatUnknownNameError({
|
|
161
|
+
kind: "shell",
|
|
162
|
+
name: shell,
|
|
163
|
+
registered: Object.keys(app.shells),
|
|
164
|
+
context: `route "${fullPath}"`
|
|
165
|
+
}));
|
|
93
166
|
routes.push({
|
|
94
167
|
id: node.id ?? createRouteId(fullPath),
|
|
95
168
|
path: fullPath,
|
|
@@ -97,17 +170,28 @@ function flattenRouteNode(app, node, inherited, routes) {
|
|
|
97
170
|
loaderFile: node.loaderFile,
|
|
98
171
|
hasLoader: node.loaderFile ? true : node.hasLoader,
|
|
99
172
|
shell,
|
|
100
|
-
shellFile: shell ? app.shells[shell] : void 0,
|
|
173
|
+
shellFile: shell !== void 0 ? app.shells[shell] : void 0,
|
|
101
174
|
render: node.render ?? inherited.render,
|
|
102
175
|
middleware,
|
|
103
|
-
middlewareFiles: middleware.
|
|
104
|
-
|
|
105
|
-
|
|
176
|
+
middlewareFiles: middleware.map((name) => {
|
|
177
|
+
if (!hasOwnEntry(app.middleware, name)) throw new Error(formatUnknownNameError({
|
|
178
|
+
kind: "middleware",
|
|
179
|
+
kindPlural: "middleware",
|
|
180
|
+
name,
|
|
181
|
+
registered: Object.keys(app.middleware),
|
|
182
|
+
context: `route "${fullPath}"`
|
|
183
|
+
}));
|
|
184
|
+
return app.middleware[name];
|
|
106
185
|
}),
|
|
186
|
+
prefetch: node.prefetch,
|
|
107
187
|
revalidate: node.revalidate,
|
|
108
188
|
segments: parseRouteSegments(fullPath)
|
|
109
189
|
});
|
|
110
190
|
}
|
|
191
|
+
/** `in` would also match `Object.prototype` keys such as `constructor`. */
|
|
192
|
+
function hasOwnEntry(record, name) {
|
|
193
|
+
return Object.prototype.hasOwnProperty.call(record, name);
|
|
194
|
+
}
|
|
111
195
|
function isResolvedApp(app) {
|
|
112
196
|
return app.routes.length === 0 || "segments" in app.routes[0];
|
|
113
197
|
}
|
|
@@ -192,7 +276,12 @@ function buildHref(routes, routeId, ...args) {
|
|
|
192
276
|
}
|
|
193
277
|
function buildHrefUntyped(routes, routeId, options = {}) {
|
|
194
278
|
const route = routes.find((candidate) => candidate.id === routeId);
|
|
195
|
-
if (!route) throw new Error(
|
|
279
|
+
if (!route) throw new Error(formatUnknownNameError({
|
|
280
|
+
kind: "pracht route id",
|
|
281
|
+
kindPlural: "route ids",
|
|
282
|
+
name: routeId,
|
|
283
|
+
registered: routes.flatMap((candidate) => candidate.id ? [candidate.id] : [])
|
|
284
|
+
}));
|
|
196
285
|
const segments = route.segments ?? parseRouteSegments(route.path);
|
|
197
286
|
return `${buildPathFromSegments(segments, normalizeHrefParams(segments, options.params ?? {}))}${serializeSearch(options.search)}${serializeHash(options.hash)}`;
|
|
198
287
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
//#region src/app-graph.ts
|
|
2
|
+
const API_METHOD_ORDER = [
|
|
3
|
+
"GET",
|
|
4
|
+
"POST",
|
|
5
|
+
"PUT",
|
|
6
|
+
"PATCH",
|
|
7
|
+
"DELETE",
|
|
8
|
+
"HEAD",
|
|
9
|
+
"OPTIONS"
|
|
10
|
+
];
|
|
11
|
+
function serializeAppRoutes(routes) {
|
|
12
|
+
return routes.map((route) => ({
|
|
13
|
+
file: route.file,
|
|
14
|
+
id: route.id ?? "",
|
|
15
|
+
loaderFile: route.loaderFile ?? null,
|
|
16
|
+
middleware: route.middleware,
|
|
17
|
+
path: route.path,
|
|
18
|
+
render: route.render ?? null,
|
|
19
|
+
revalidate: route.revalidate ?? null,
|
|
20
|
+
shell: route.shell ?? null,
|
|
21
|
+
shellFile: route.shellFile ?? null
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
function serializeApiRoutes(apiRoutes, access) {
|
|
25
|
+
return Promise.all(apiRoutes.map(async (route) => ({
|
|
26
|
+
file: route.file,
|
|
27
|
+
methods: await detectApiMethods(route.file, access),
|
|
28
|
+
path: route.path
|
|
29
|
+
})));
|
|
30
|
+
}
|
|
31
|
+
async function buildAppGraph(options) {
|
|
32
|
+
return {
|
|
33
|
+
api: await serializeApiRoutes(options.apiRoutes ?? [], options),
|
|
34
|
+
routes: serializeAppRoutes(options.app.routes)
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async function detectApiMethods(file, access) {
|
|
38
|
+
try {
|
|
39
|
+
const module = await access.loadModule(file);
|
|
40
|
+
return API_METHOD_ORDER.filter((method) => typeof module[method] === "function");
|
|
41
|
+
} catch {
|
|
42
|
+
let source;
|
|
43
|
+
try {
|
|
44
|
+
source = access.readSource(file);
|
|
45
|
+
} catch {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
return API_METHOD_ORDER.filter((method) => new RegExp(`export\\s+(?:async\\s+)?(?:function|const|let|var)\\s+${method}\\b`).test(source));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { serializeAppRoutes as i, detectApiMethods as n, serializeApiRoutes as r, buildAppGraph as t };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { H as ResolvedPrachtApp, U as ResolvedRoute, V as ResolvedApiRoute, x as HttpMethod } from "./types-B-sfVjaH.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/app-graph.d.ts
|
|
4
|
+
interface AppGraphRoute {
|
|
5
|
+
file: string;
|
|
6
|
+
id: string;
|
|
7
|
+
loaderFile: string | null;
|
|
8
|
+
middleware: string[];
|
|
9
|
+
path: string;
|
|
10
|
+
render: string | null;
|
|
11
|
+
revalidate: unknown;
|
|
12
|
+
shell: string | null;
|
|
13
|
+
shellFile: string | null;
|
|
14
|
+
}
|
|
15
|
+
interface AppGraphApiRoute {
|
|
16
|
+
file: string;
|
|
17
|
+
methods: string[];
|
|
18
|
+
path: string;
|
|
19
|
+
}
|
|
20
|
+
interface AppGraph {
|
|
21
|
+
api: AppGraphApiRoute[];
|
|
22
|
+
routes: AppGraphRoute[];
|
|
23
|
+
}
|
|
24
|
+
interface AppGraphModuleAccess {
|
|
25
|
+
/** Import an app module by its app-relative file path (e.g. Vite's `ssrLoadModule`). */
|
|
26
|
+
loadModule: (file: string) => Promise<Record<string, unknown>>;
|
|
27
|
+
/** Read an app module's source text — fallback method detection when importing fails. */
|
|
28
|
+
readSource: (file: string) => string;
|
|
29
|
+
}
|
|
30
|
+
declare function serializeAppRoutes(routes: readonly ResolvedRoute[]): AppGraphRoute[];
|
|
31
|
+
declare function serializeApiRoutes(apiRoutes: readonly ResolvedApiRoute[], access: AppGraphModuleAccess): Promise<AppGraphApiRoute[]>;
|
|
32
|
+
declare function buildAppGraph(options: {
|
|
33
|
+
apiRoutes?: readonly ResolvedApiRoute[];
|
|
34
|
+
app: ResolvedPrachtApp;
|
|
35
|
+
} & AppGraphModuleAccess): Promise<AppGraph>;
|
|
36
|
+
declare function detectApiMethods(file: string, access: AppGraphModuleAccess): Promise<HttpMethod[]>;
|
|
37
|
+
//#endregion
|
|
38
|
+
export { buildAppGraph as a, serializeAppRoutes as c, AppGraphRoute as i, AppGraphApiRoute as n, detectApiMethods as o, AppGraphModuleAccess as r, serializeApiRoutes as s, AppGraph as t };
|
package/dist/browser.d.mts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
import {
|
|
3
|
-
import { n as
|
|
4
|
-
import {
|
|
5
|
-
import { i as
|
|
1
|
+
import { $ as RouteParamInput, A as MiddlewareNext, B as RenderMode, C as LoaderArgs, D as MiddlewareArgs, F as PrachtApp, G as RouteConfig, H as ResolvedPrachtApp, I as PrachtAppConfig, J as RouteId, K as RouteDataFor, L as PrachtHttpError, M as ModuleRef, N as ModuleRegistry, O as MiddlewareFn, P as NavigateOptions, Q as RouteModule, R as PrefetchStrategy, S as LinkPrefetchStrategy, T as LoaderFn, U as ResolvedRoute, V as ResolvedApiRoute, W as RouteComponentProps, X as RouteMatch, Y as RouteLoaderData, Z as RouteMeta, _ as HrefArgs, a as ApiRouteModule, at as RouteTarget, b as HrefRouteDefinition, c as DataModule, ct as SearchParamValue, d as GroupMeta, dt as ShellProps, et as RouteParams, f as HeadArgs, ft as TimeRevalidatePolicy, g as HeadersArgs, h as HeadScriptDescriptor, i as ApiRouteMatch, j as ModuleImporter, k as MiddlewareModule, l as ErrorBoundaryProps, lt as SearchParamsInput, m as HeadMetadata, n as ApiRouteArgs, nt as RouteRevalidate, o as BaseRouteArgs, ot as RouteTreeNode, p as HeadAttributes, q as RouteDefinition, r as ApiRouteHandler, rt as RouteSearchFor, s as BuildHrefOptions, st as SearchParamPrimitive, t as ApiConfig, tt as RouteParamsFor, u as GroupDefinition, ut as ShellModule, v as HrefFn, w as LoaderData, x as HttpMethod, y as HrefOptions, z as Register } from "./types-B-sfVjaH.mjs";
|
|
2
|
+
import { c as resolveApp, i as group, l as route, n as buildPathFromSegments, o as matchAppRoute, r as defineApp, t as buildHref, u as timeRevalidate } from "./app-BN3pjxtw.mjs";
|
|
3
|
+
import { _ as NavigationLocation, a as parseSafeNavigationUrl, c as Link, d as useLocation, f as useNavigation, g as Navigation, h as useRouteData, i as fetchPrachtRouteState, l as LinkProps, m as useRevalidate, n as redirect, o as Form, p as useParams, r as RouteStateResult, s as FormProps, t as RedirectOptions, u as Location, v as createHref } from "./runtime-middleware-pYubngnL.mjs";
|
|
4
|
+
import { i as forwardRef, n as prefetch, r as useIsHydrated, t as PrefetchFn } from "./prefetch-api-Bf-P7XFo.mjs";
|
|
5
|
+
import { a as startApp, c as SerializedRouteError, i as readHydrationState, n as PrachtRuntimeProvider, r as StartAppOptions, t as PrachtHydrationState } from "./runtime-context-BYBwVA0M.mjs";
|
|
6
|
+
import { i as useNavigate, n as NavigateFn, r as initClientRouter, t as InitClientRouterOptions } from "./router-B_Aj5TtY.mjs";
|
|
6
7
|
import { Suspense, lazy } from "preact-suspense";
|
|
7
|
-
export { type ApiConfig, type ApiRouteArgs, type ApiRouteHandler, type ApiRouteMatch, type ApiRouteModule, type BaseRouteArgs, type BuildHrefOptions, type DataModule, type ErrorBoundaryProps, Form, type FormProps, type GroupDefinition, type GroupMeta, type HeadArgs, type HeadAttributes, type HeadMetadata, type HeadScriptDescriptor, type HeadersArgs, type HrefArgs, type HrefFn, type HrefOptions, type HrefRouteDefinition, type HttpMethod, type InitClientRouterOptions, Link, type LinkProps, type LoaderArgs, type LoaderData, type LoaderFn, type Location, type MiddlewareArgs, type MiddlewareFn, type MiddlewareModule, type MiddlewareNext, type ModuleImporter, type ModuleRef, type ModuleRegistry, type NavigateFn, type NavigateOptions, type PrachtApp, type PrachtAppConfig, PrachtHttpError, type PrachtHydrationState, PrachtRuntimeProvider, type PrefetchStrategy, type RedirectOptions, type Register, type RenderMode, type ResolvedApiRoute, type ResolvedPrachtApp, type ResolvedRoute, type RouteComponentProps, type RouteConfig, type RouteDefinition, type RouteId, type RouteMatch, type RouteMeta, type RouteModule, type RouteParamInput, type RouteParams, type RouteParamsFor, type RouteRevalidate, type RouteSearchFor, type RouteStateResult, type RouteTarget, type RouteTreeNode, type SearchParamPrimitive, type SearchParamValue, type SearchParamsInput, type SerializedRouteError, type ShellModule, type ShellProps, type StartAppOptions, Suspense, type TimeRevalidatePolicy, buildHref, buildPathFromSegments, createHref, defineApp, fetchPrachtRouteState, forwardRef, group, initClientRouter, lazy, matchAppRoute, parseSafeNavigationUrl, readHydrationState, redirect, resolveApp, route, startApp, timeRevalidate, useIsHydrated, useLocation, useNavigate, useParams, useRevalidate, useRouteData };
|
|
8
|
+
export { type ApiConfig, type ApiRouteArgs, type ApiRouteHandler, type ApiRouteMatch, type ApiRouteModule, type BaseRouteArgs, type BuildHrefOptions, type DataModule, type ErrorBoundaryProps, Form, type FormProps, type GroupDefinition, type GroupMeta, type HeadArgs, type HeadAttributes, type HeadMetadata, type HeadScriptDescriptor, type HeadersArgs, type HrefArgs, type HrefFn, type HrefOptions, type HrefRouteDefinition, type HttpMethod, type InitClientRouterOptions, Link, type LinkPrefetchStrategy, type LinkProps, type LoaderArgs, type LoaderData, type LoaderFn, type Location, type MiddlewareArgs, type MiddlewareFn, type MiddlewareModule, type MiddlewareNext, type ModuleImporter, type ModuleRef, type ModuleRegistry, type NavigateFn, type NavigateOptions, type Navigation, type NavigationLocation, type PrachtApp, type PrachtAppConfig, PrachtHttpError, type PrachtHydrationState, PrachtRuntimeProvider, type PrefetchFn, type PrefetchStrategy, type RedirectOptions, type Register, type RenderMode, type ResolvedApiRoute, type ResolvedPrachtApp, type ResolvedRoute, type RouteComponentProps, type RouteConfig, type RouteDataFor, type RouteDefinition, type RouteId, type RouteLoaderData, type RouteMatch, type RouteMeta, type RouteModule, type RouteParamInput, type RouteParams, type RouteParamsFor, type RouteRevalidate, type RouteSearchFor, type RouteStateResult, type RouteTarget, type RouteTreeNode, type SearchParamPrimitive, type SearchParamValue, type SearchParamsInput, type SerializedRouteError, type ShellModule, type ShellProps, type StartAppOptions, Suspense, type TimeRevalidatePolicy, buildHref, buildPathFromSegments, createHref, defineApp, fetchPrachtRouteState, forwardRef, group, initClientRouter, lazy, matchAppRoute, parseSafeNavigationUrl, prefetch, readHydrationState, redirect, resolveApp, route, startApp, timeRevalidate, useIsHydrated, useLocation, useNavigate, useNavigation, useParams, useRevalidate, useRouteData };
|
package/dist/browser.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { c as resolveApp, i as group, l as route, n as buildPathFromSegments, o as matchAppRoute, r as defineApp, t as buildHref, u as timeRevalidate } from "./app-
|
|
2
|
-
import {
|
|
3
|
-
import { t as forwardRef } from "./forwardRef-
|
|
4
|
-
import { n as useNavigate, r as useIsHydrated, t as initClientRouter } from "./router-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { c as resolveApp, i as group, l as route, n as buildPathFromSegments, o as matchAppRoute, r as defineApp, t as buildHref, u as timeRevalidate } from "./app-CGRKjZ6Z.mjs";
|
|
2
|
+
import { C as createHref, a as useNavigation, c as useRouteData, d as redirect, i as useLocation, n as Form, o as useParams, r as Link, s as useRevalidate, t as PrachtHttpError } from "./types-DEPXdbyp.mjs";
|
|
3
|
+
import { t as forwardRef } from "./forwardRef-B0cSkHwH.mjs";
|
|
4
|
+
import { n as useNavigate, r as useIsHydrated, t as initClientRouter } from "./router-E5Wh-dOR.mjs";
|
|
5
|
+
import { c as fetchPrachtRouteState, u as parseSafeNavigationUrl } from "./prefetch-cache-BNLEp9H5.mjs";
|
|
6
|
+
import { l as readHydrationState, s as PrachtRuntimeProvider, u as startApp } from "./navigation-state-BjwXTeVz.mjs";
|
|
7
|
+
import { t as prefetch } from "./prefetch-api-ChSCTbEB.mjs";
|
|
7
8
|
import { Suspense, lazy } from "preact-suspense";
|
|
8
|
-
export { Form, Link, PrachtHttpError, PrachtRuntimeProvider, Suspense, buildHref, buildPathFromSegments, createHref, defineApp, fetchPrachtRouteState, forwardRef, group, initClientRouter, lazy, matchAppRoute, parseSafeNavigationUrl, readHydrationState, redirect, resolveApp, route, startApp, timeRevalidate, useIsHydrated, useLocation, useNavigate, useParams, useRevalidate, useRouteData };
|
|
9
|
+
export { Form, Link, PrachtHttpError, PrachtRuntimeProvider, Suspense, buildHref, buildPathFromSegments, createHref, defineApp, fetchPrachtRouteState, forwardRef, group, initClientRouter, lazy, matchAppRoute, parseSafeNavigationUrl, prefetch, readHydrationState, redirect, resolveApp, route, startApp, timeRevalidate, useIsHydrated, useLocation, useNavigate, useNavigation, useParams, useRevalidate, useRouteData };
|
package/dist/client.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as resolveApp } from "./app-
|
|
2
|
-
import { i as readHydrationState, t as PrachtHydrationState } from "./runtime-context-
|
|
3
|
-
import { n as NavigateFn, r as initClientRouter, t as InitClientRouterOptions } from "./router-
|
|
1
|
+
import { c as resolveApp } from "./app-BN3pjxtw.mjs";
|
|
2
|
+
import { i as readHydrationState, t as PrachtHydrationState } from "./runtime-context-BYBwVA0M.mjs";
|
|
3
|
+
import { n as NavigateFn, r as initClientRouter, t as InitClientRouterOptions } from "./router-B_Aj5TtY.mjs";
|
|
4
4
|
export { type InitClientRouterOptions, type NavigateFn, type PrachtHydrationState, initClientRouter, readHydrationState, resolveApp };
|
package/dist/client.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as resolveApp } from "./app-
|
|
2
|
-
import { t as initClientRouter } from "./router-
|
|
3
|
-
import {
|
|
1
|
+
import { c as resolveApp } from "./app-CGRKjZ6Z.mjs";
|
|
2
|
+
import { t as initClientRouter } from "./router-E5Wh-dOR.mjs";
|
|
3
|
+
import { l as readHydrationState } from "./navigation-state-BjwXTeVz.mjs";
|
|
4
4
|
export { initClientRouter, readHydrationState, resolveApp };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/dev-404.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Self-contained 404 page for pracht dev mode.
|
|
4
|
+
*
|
|
5
|
+
* Returns a standalone HTML document with inline styles and scripts.
|
|
6
|
+
* Not a Preact component — rendered by the dev middleware when a request
|
|
7
|
+
* matches no page route and no API route. Loaded exclusively through the
|
|
8
|
+
* dev server (`@pracht/core/dev-404`) and never reachable from production
|
|
9
|
+
* code paths.
|
|
10
|
+
*/
|
|
11
|
+
interface DevNotFoundRoute {
|
|
12
|
+
path: string;
|
|
13
|
+
render?: string | null;
|
|
14
|
+
}
|
|
15
|
+
interface DevNotFoundApiRoute {
|
|
16
|
+
path: string;
|
|
17
|
+
methods?: string[];
|
|
18
|
+
}
|
|
19
|
+
interface DevNotFoundOptions {
|
|
20
|
+
requestedPath: string;
|
|
21
|
+
routes: DevNotFoundRoute[];
|
|
22
|
+
apiRoutes?: DevNotFoundApiRoute[];
|
|
23
|
+
}
|
|
24
|
+
declare function buildDevNotFoundHtml(options: DevNotFoundOptions): string;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { DevNotFoundApiRoute, DevNotFoundOptions, DevNotFoundRoute, buildDevNotFoundHtml };
|
package/dist/dev-404.mjs
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
//#region src/dev-404.ts
|
|
2
|
+
const DYNAMIC_SEGMENT = /[:*]/;
|
|
3
|
+
function buildDevNotFoundHtml(options) {
|
|
4
|
+
const { requestedPath, routes, apiRoutes = [] } = options;
|
|
5
|
+
const routeRows = routes.map((route) => {
|
|
6
|
+
const mode = route.render ?? "ssr";
|
|
7
|
+
return `<tr><td>${!DYNAMIC_SEGMENT.test(route.path) ? `<a class="path" href="${escapeHtml(route.path)}">${escapeHtml(route.path)}</a>` : `<span class="path dynamic">${escapeHtml(route.path)}</span>`}</td><td><span class="mode mode-${escapeHtml(mode)}">${escapeHtml(mode)}</span></td></tr>`;
|
|
8
|
+
}).join("\n ");
|
|
9
|
+
const routesHtml = routes.length > 0 ? `<table class="routes">\n ${routeRows}\n </table>` : `<p class="empty">No page routes are registered.</p>`;
|
|
10
|
+
const apiRows = apiRoutes.map((route) => {
|
|
11
|
+
const methods = route.methods?.length ? route.methods.join(", ") : "";
|
|
12
|
+
return `<tr><td><span class="path">${escapeHtml(route.path)}</span></td><td><span class="methods">${escapeHtml(methods)}</span></td></tr>`;
|
|
13
|
+
}).join("\n ");
|
|
14
|
+
const apiHtml = apiRoutes.length > 0 ? `<h2>API routes</h2>\n <table class="routes">\n ${apiRows}\n </table>` : "";
|
|
15
|
+
return `<!DOCTYPE html>
|
|
16
|
+
<html>
|
|
17
|
+
<head>
|
|
18
|
+
<meta charset="utf-8">
|
|
19
|
+
<title>404 — pracht dev</title>
|
|
20
|
+
<style>
|
|
21
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
22
|
+
body {
|
|
23
|
+
font-family: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, monospace;
|
|
24
|
+
background: #1a1a2e;
|
|
25
|
+
color: #e0e0e0;
|
|
26
|
+
padding: 32px;
|
|
27
|
+
line-height: 1.5;
|
|
28
|
+
}
|
|
29
|
+
.overlay {
|
|
30
|
+
max-width: 900px;
|
|
31
|
+
margin: 0 auto;
|
|
32
|
+
}
|
|
33
|
+
.header {
|
|
34
|
+
display: flex;
|
|
35
|
+
align-items: center;
|
|
36
|
+
gap: 12px;
|
|
37
|
+
margin-bottom: 24px;
|
|
38
|
+
padding-bottom: 16px;
|
|
39
|
+
border-bottom: 1px solid #333;
|
|
40
|
+
}
|
|
41
|
+
.badge {
|
|
42
|
+
background: #f39c12;
|
|
43
|
+
color: #1a1a2e;
|
|
44
|
+
font-size: 11px;
|
|
45
|
+
font-weight: 700;
|
|
46
|
+
text-transform: uppercase;
|
|
47
|
+
letter-spacing: 0.05em;
|
|
48
|
+
padding: 4px 10px;
|
|
49
|
+
border-radius: 4px;
|
|
50
|
+
}
|
|
51
|
+
.title {
|
|
52
|
+
font-size: 14px;
|
|
53
|
+
color: #888;
|
|
54
|
+
}
|
|
55
|
+
.message {
|
|
56
|
+
font-size: 18px;
|
|
57
|
+
font-weight: 600;
|
|
58
|
+
color: #ffd166;
|
|
59
|
+
margin-bottom: 8px;
|
|
60
|
+
word-break: break-word;
|
|
61
|
+
}
|
|
62
|
+
.requested {
|
|
63
|
+
color: #a0c4ff;
|
|
64
|
+
}
|
|
65
|
+
.sub {
|
|
66
|
+
font-size: 13px;
|
|
67
|
+
color: #888;
|
|
68
|
+
margin-bottom: 28px;
|
|
69
|
+
}
|
|
70
|
+
h2 {
|
|
71
|
+
font-size: 13px;
|
|
72
|
+
font-weight: 600;
|
|
73
|
+
text-transform: uppercase;
|
|
74
|
+
letter-spacing: 0.08em;
|
|
75
|
+
color: #888;
|
|
76
|
+
margin: 28px 0 10px;
|
|
77
|
+
}
|
|
78
|
+
.routes {
|
|
79
|
+
width: 100%;
|
|
80
|
+
border-collapse: collapse;
|
|
81
|
+
background: #16162a;
|
|
82
|
+
border: 1px solid #333;
|
|
83
|
+
border-radius: 8px;
|
|
84
|
+
overflow: hidden;
|
|
85
|
+
font-size: 13px;
|
|
86
|
+
}
|
|
87
|
+
.routes td {
|
|
88
|
+
padding: 8px 16px;
|
|
89
|
+
border-bottom: 1px solid #262640;
|
|
90
|
+
}
|
|
91
|
+
.routes tr:last-child td {
|
|
92
|
+
border-bottom: none;
|
|
93
|
+
}
|
|
94
|
+
.routes td:last-child {
|
|
95
|
+
text-align: right;
|
|
96
|
+
width: 1%;
|
|
97
|
+
white-space: nowrap;
|
|
98
|
+
}
|
|
99
|
+
a.path {
|
|
100
|
+
color: #a0c4ff;
|
|
101
|
+
text-decoration: none;
|
|
102
|
+
}
|
|
103
|
+
a.path:hover {
|
|
104
|
+
text-decoration: underline;
|
|
105
|
+
}
|
|
106
|
+
.path.dynamic {
|
|
107
|
+
color: #ccc;
|
|
108
|
+
}
|
|
109
|
+
.mode {
|
|
110
|
+
font-size: 11px;
|
|
111
|
+
font-weight: 700;
|
|
112
|
+
text-transform: uppercase;
|
|
113
|
+
letter-spacing: 0.05em;
|
|
114
|
+
padding: 2px 8px;
|
|
115
|
+
border-radius: 4px;
|
|
116
|
+
background: #262640;
|
|
117
|
+
color: #a0c4ff;
|
|
118
|
+
}
|
|
119
|
+
.mode-ssg { color: #7bd88f; }
|
|
120
|
+
.mode-isg { color: #5fd7d7; }
|
|
121
|
+
.mode-ssr { color: #ffd166; }
|
|
122
|
+
.mode-spa { color: #d7a0ff; }
|
|
123
|
+
.methods {
|
|
124
|
+
font-size: 12px;
|
|
125
|
+
color: #7bd88f;
|
|
126
|
+
}
|
|
127
|
+
.empty {
|
|
128
|
+
font-size: 13px;
|
|
129
|
+
color: #888;
|
|
130
|
+
}
|
|
131
|
+
.hint {
|
|
132
|
+
margin-top: 24px;
|
|
133
|
+
font-size: 12px;
|
|
134
|
+
color: #666;
|
|
135
|
+
}
|
|
136
|
+
</style>
|
|
137
|
+
</head>
|
|
138
|
+
<body>
|
|
139
|
+
<div class="overlay">
|
|
140
|
+
<div class="header">
|
|
141
|
+
<span class="badge">404</span>
|
|
142
|
+
<span class="title">pracht dev</span>
|
|
143
|
+
</div>
|
|
144
|
+
<div class="message">No route matches <span class="requested">${escapeHtml(requestedPath)}</span></div>
|
|
145
|
+
<div class="sub">This page is only shown in development — production serves your app's own 404 response.</div>
|
|
146
|
+
<h2>Page routes</h2>
|
|
147
|
+
${routesHtml}
|
|
148
|
+
${apiHtml}
|
|
149
|
+
<div class="hint">Add the route to your app manifest and save — the page will reload automatically.</div>
|
|
150
|
+
</div>
|
|
151
|
+
<script>
|
|
152
|
+
// Auto-reload when Vite triggers a full reload (e.g. a route was added)
|
|
153
|
+
if (import.meta.hot) {
|
|
154
|
+
import.meta.hot.on("vite:beforeFullReload", function () {
|
|
155
|
+
window.location.reload();
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
<\/script>
|
|
159
|
+
</body>
|
|
160
|
+
</html>`;
|
|
161
|
+
}
|
|
162
|
+
function escapeHtml(str) {
|
|
163
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
164
|
+
}
|
|
165
|
+
//#endregion
|
|
166
|
+
export { buildDevNotFoundHtml };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { a as buildAppGraph, c as serializeAppRoutes, i as AppGraphRoute, n as AppGraphApiRoute, o as detectApiMethods, r as AppGraphModuleAccess, s as serializeApiRoutes, t as AppGraph } from "./app-graph-DBoDsHJ5.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/devtools.d.ts
|
|
4
|
+
declare const DEVTOOLS_PATH = "/_pracht";
|
|
5
|
+
declare const DEVTOOLS_JSON_PATH = "/_pracht.json";
|
|
6
|
+
declare function buildDevtoolsHtml(graph: AppGraph): string;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { type AppGraph, type AppGraphApiRoute, type AppGraphModuleAccess, type AppGraphRoute, DEVTOOLS_JSON_PATH, DEVTOOLS_PATH, buildAppGraph, buildDevtoolsHtml, detectApiMethods, serializeApiRoutes, serializeAppRoutes };
|