@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.
Files changed (37) hide show
  1. package/README.md +5 -1
  2. package/dist/app-BN3pjxtw.d.mts +24 -0
  3. package/dist/{app-w-P1wf5T.mjs → app-CGRKjZ6Z.mjs} +96 -7
  4. package/dist/app-graph-BlaCcGUZ.mjs +52 -0
  5. package/dist/app-graph-DBoDsHJ5.d.mts +38 -0
  6. package/dist/browser.d.mts +7 -6
  7. package/dist/browser.mjs +8 -7
  8. package/dist/client.d.mts +3 -3
  9. package/dist/client.mjs +3 -3
  10. package/dist/dev-404.d.mts +26 -0
  11. package/dist/dev-404.mjs +166 -0
  12. package/dist/devtools.d.mts +8 -0
  13. package/dist/devtools.mjs +156 -0
  14. package/dist/error-overlay.d.mts +38 -1
  15. package/dist/error-overlay.mjs +134 -5
  16. package/dist/index.d.mts +9 -7
  17. package/dist/index.mjs +9 -7
  18. package/dist/manifest.d.mts +2 -1
  19. package/dist/manifest.mjs +1 -1
  20. package/dist/{runtime-context-B5pREhcM.mjs → navigation-state-BjwXTeVz.mjs} +74 -2
  21. package/dist/{prefetch-D9amIQtw.mjs → prefetch-COYeuvQK.mjs} +44 -27
  22. package/dist/prefetch-api-Bf-P7XFo.d.mts +39 -0
  23. package/dist/prefetch-api-ChSCTbEB.mjs +69 -0
  24. package/dist/{prefetch-cache-DzP2Bj9H.mjs → prefetch-cache-BNLEp9H5.mjs} +12 -1
  25. package/dist/{prerender-B8_CqYwd.d.mts → prerender-BV42B9jK.d.mts} +31 -2
  26. package/dist/{prerender-CoMyuJKm.mjs → prerender-C8BpANz3.mjs} +53 -9
  27. package/dist/{router-BcUmg1kB.d.mts → router-B_Aj5TtY.d.mts} +2 -2
  28. package/dist/{router-BkkyNjqB.mjs → router-E5Wh-dOR.mjs} +251 -58
  29. package/dist/{runtime-context-ytVd7GmZ.d.mts → runtime-context-BYBwVA0M.d.mts} +1 -1
  30. package/dist/{runtime-middleware-aeBdgjYr.d.mts → runtime-middleware-pYubngnL.d.mts} +57 -4
  31. package/dist/server.d.mts +7 -5
  32. package/dist/server.mjs +6 -5
  33. package/dist/{app-BWriseLj.d.mts → types-B-sfVjaH.d.mts} +42 -22
  34. package/dist/{types-DQv2poC5.mjs → types-DEPXdbyp.mjs} +43 -15
  35. package/package.json +9 -1
  36. package/dist/hydration-M1QzbQ1O.d.mts +0 -23
  37. /package/dist/{forwardRef-grZ6t4GS.mjs → forwardRef-B0cSkHwH.mjs} +0 -0
@@ -1,4 +1,4 @@
1
- import { A as HrefRouteDefinition, st as RouteParams } from "./app-BWriseLj.mjs";
1
+ import { b as HrefRouteDefinition, et as RouteParams } from "./types-B-sfVjaH.mjs";
2
2
  import * as _$preact from "preact";
3
3
  import { ComponentChildren } from "preact";
4
4
 
@@ -1,26 +1,79 @@
1
- import { A as HrefRouteDefinition, F as LoaderLike, N as LoaderData, O as HrefFn, dt as RouteTarget, nt as RouteId, st as RouteParams } from "./app-BWriseLj.mjs";
2
- import { c as SerializedRouteError } from "./runtime-context-ytVd7GmZ.mjs";
1
+ import { E as LoaderLike, J as RouteId, K as RouteDataFor, S as LinkPrefetchStrategy, at as RouteTarget, b as HrefRouteDefinition, et as RouteParams, v as HrefFn, w as LoaderData } from "./types-B-sfVjaH.mjs";
2
+ import { c as SerializedRouteError } from "./runtime-context-BYBwVA0M.mjs";
3
3
  import * as _$preact from "preact";
4
4
  import { JSX, h } from "preact";
5
5
 
6
6
  //#region src/href.d.ts
7
7
  declare function createHref(routes: readonly HrefRouteDefinition[]): HrefFn;
8
8
  //#endregion
9
+ //#region src/navigation-state.d.ts
10
+ /**
11
+ * Shared reactive store for the current client navigation / form submission.
12
+ *
13
+ * The client router (`router.ts`) and `<Form>` (`runtime-hooks.ts`) write to
14
+ * this store; `useNavigation()` subscribes to it. The store lives in its own
15
+ * module so both writers can import it without creating a cycle, and so it
16
+ * stays safe to import during SSR (no `window` access at module scope).
17
+ */
18
+ interface NavigationLocation {
19
+ pathname: string;
20
+ search: string;
21
+ hash: string;
22
+ href: string;
23
+ }
24
+ type Navigation = {
25
+ state: "idle";
26
+ location?: undefined;
27
+ formData?: undefined;
28
+ } | {
29
+ state: "loading";
30
+ location: NavigationLocation;
31
+ formData?: undefined;
32
+ } | {
33
+ state: "submitting";
34
+ location: NavigationLocation;
35
+ formData: FormData;
36
+ };
37
+ //#endregion
9
38
  //#region src/runtime-hooks.d.ts
10
39
  interface FormProps extends Omit<JSX.HTMLAttributes<HTMLFormElement>, "action" | "method"> {
11
40
  action?: string;
12
41
  method?: string;
13
42
  }
14
- type LinkProps<TRoute extends RouteId = RouteId> = Omit<JSX.HTMLAttributes<HTMLAnchorElement>, "href"> & RouteTarget<TRoute>;
43
+ type LinkProps<TRoute extends RouteId = RouteId> = Omit<JSX.HTMLAttributes<HTMLAnchorElement>, "href"> & RouteTarget<TRoute> & {
44
+ /**
45
+ * Prefetch strategy for this link, overriding the route-level strategy:
46
+ * `"intent"` (hover/focus), `"viewport"` (IntersectionObserver),
47
+ * `"render"` (as soon as the link mounts), or `"none"`. When omitted the
48
+ * route's `prefetch` meta applies (default: `"intent"`).
49
+ */
50
+ prefetch?: LinkPrefetchStrategy; /** Keep the current scroll position when this link navigates. */
51
+ preserveScroll?: boolean;
52
+ /**
53
+ * Wrap the navigation triggered by this link in
54
+ * `document.startViewTransition()` when supported.
55
+ */
56
+ viewTransition?: boolean;
57
+ };
15
58
  interface Location {
16
59
  pathname: string;
17
60
  search: string;
18
61
  }
62
+ declare function useRouteData<TRoute extends RouteId>(routeId: TRoute): RouteDataFor<TRoute>;
19
63
  declare function useRouteData<TLoader extends LoaderLike>(): LoaderData<TLoader>;
20
64
  declare function useRouteData<TData = unknown>(): TData;
21
65
  declare function useLocation(): Location;
22
66
  declare function useParams(): RouteParams;
23
67
  declare function useRevalidate(): () => Promise<unknown>;
68
+ /**
69
+ * Reactive pending state for the current client navigation or `<Form>`
70
+ * submission. Returns `{ state: "idle" }` when nothing is in flight,
71
+ * `{ state: "loading", location }` while the router fetches and commits a
72
+ * navigation, and `{ state: "submitting", location, formData }` while a
73
+ * `<Form>` submission is awaiting its response. During SSR it always
74
+ * returns the idle state.
75
+ */
76
+ declare function useNavigation(): Navigation;
24
77
  declare function Link<TRoute extends RouteId>(props: LinkProps<TRoute>): _$preact.VNode<_$preact.ClassAttributes<HTMLAnchorElement> & h.JSX.HTMLAttributes<HTMLAnchorElement>>;
25
78
  declare function Form(props: FormProps): _$preact.VNode<_$preact.ClassAttributes<HTMLFormElement> & h.JSX.HTMLAttributes<HTMLFormElement>>;
26
79
  //#endregion
@@ -74,4 +127,4 @@ type RedirectOptions = number | {
74
127
  */
75
128
  declare function redirect(target: string, options?: RedirectOptions): Response;
76
129
  //#endregion
77
- export { parseSafeNavigationUrl as a, Link as c, useLocation as d, useParams as f, createHref as h, fetchPrachtRouteState as i, LinkProps as l, useRouteData as m, redirect as n, Form as o, useRevalidate as p, RouteStateResult as r, FormProps as s, RedirectOptions as t, Location as u };
130
+ export { NavigationLocation as _, parseSafeNavigationUrl as a, Link as c, useLocation as d, useNavigation as f, Navigation as g, useRouteData as h, fetchPrachtRouteState as i, LinkProps as l, useRevalidate as m, redirect as n, Form as o, useParams as p, RouteStateResult as r, FormProps as s, RedirectOptions as t, Location as u, createHref as v };
package/dist/server.d.mts CHANGED
@@ -1,5 +1,7 @@
1
- import { $ as RouteComponentProps, A as HrefRouteDefinition, B as ModuleImporter, C as HeadAttributes, D as HrefArgs, E as HeadersArgs, G as PrachtAppConfig, H as ModuleRegistry, I as MiddlewareArgs, J as Register, K as PrachtHttpError, L as MiddlewareFn, M as LoaderArgs, N as LoaderData, O as HrefFn, P as LoaderFn, Q as ResolvedRoute, R as MiddlewareModule, S as HeadArgs, T as HeadScriptDescriptor, U as NavigateOptions, V as ModuleRef, W as PrachtApp, X as ResolvedApiRoute, Y as RenderMode, Z as ResolvedPrachtApp, _ as BuildHrefOptions, _t as ShellProps, a as matchApiRoute, at as RouteModule, b as GroupDefinition, c as resolveApp, ct as RouteParamsFor, d as ApiConfig, dt as RouteTarget, et as RouteConfig, f as ApiRouteArgs, ft as RouteTreeNode, g as BaseRouteArgs, gt as ShellModule, h as ApiRouteModule, ht as SearchParamsInput, i as group, it as RouteMeta, j as HttpMethod, k as HrefOptions, l as route, lt as RouteRevalidate, m as ApiRouteMatch, mt as SearchParamValue, n as buildPathFromSegments, nt as RouteId, o as matchAppRoute, ot as RouteParamInput, p as ApiRouteHandler, pt as SearchParamPrimitive, q as PrefetchStrategy, r as defineApp, rt as RouteMatch, s as resolveApiRoutes, st as RouteParams, t as buildHref, tt as RouteDefinition, u as timeRevalidate, ut as RouteSearchFor, v as DataModule, vt as TimeRevalidatePolicy, w as HeadMetadata, x as GroupMeta, y as ErrorBoundaryProps, z as MiddlewareNext } from "./app-BWriseLj.mjs";
2
- import { h as createHref, n as redirect, t as RedirectOptions } from "./runtime-middleware-aeBdgjYr.mjs";
3
- import { c as SerializedRouteError, n as PrachtRuntimeProvider, o as PrachtRuntimeDiagnosticPhase, s as PrachtRuntimeDiagnostics } from "./runtime-context-ytVd7GmZ.mjs";
4
- import { a as prerenderApp, c as applyDefaultSecurityHeaders, i as PrerenderResult, n as PrerenderAppOptions, o as HandlePrachtRequestOptions, r as PrerenderAppResult, s as handlePrachtRequest, t as ISGManifestEntry } from "./prerender-B8_CqYwd.mjs";
5
- export { type ApiConfig, type ApiRouteArgs, type ApiRouteHandler, type ApiRouteMatch, type ApiRouteModule, type BaseRouteArgs, type BuildHrefOptions, type DataModule, type ErrorBoundaryProps, type GroupDefinition, type GroupMeta, type HandlePrachtRequestOptions, type HeadArgs, type HeadAttributes, type HeadMetadata, type HeadScriptDescriptor, type HeadersArgs, type HrefArgs, type HrefFn, type HrefOptions, type HrefRouteDefinition, type HttpMethod, type ISGManifestEntry, type LoaderArgs, type LoaderData, type LoaderFn, type MiddlewareArgs, type MiddlewareFn, type MiddlewareModule, type MiddlewareNext, type ModuleImporter, type ModuleRef, type ModuleRegistry, type NavigateOptions, type PrachtApp, type PrachtAppConfig, PrachtHttpError, type PrachtRuntimeDiagnosticPhase, type PrachtRuntimeDiagnostics, PrachtRuntimeProvider, type PrefetchStrategy, type PrerenderAppOptions, type PrerenderAppResult, type PrerenderResult, 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 RouteTarget, type RouteTreeNode, type SearchParamPrimitive, type SearchParamValue, type SearchParamsInput, type SerializedRouteError, type ShellModule, type ShellProps, type TimeRevalidatePolicy, applyDefaultSecurityHeaders, buildHref, buildPathFromSegments, createHref, defineApp, group, handlePrachtRequest, matchApiRoute, matchAppRoute, prerenderApp, redirect, resolveApiRoutes, resolveApp, route, timeRevalidate };
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, 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 { a as matchApiRoute, c as resolveApp, i as group, l as route, n as buildPathFromSegments, o as matchAppRoute, r as defineApp, s as resolveApiRoutes, t as buildHref, u as timeRevalidate } from "./app-BN3pjxtw.mjs";
3
+ import { n as redirect, t as RedirectOptions, v as createHref } from "./runtime-middleware-pYubngnL.mjs";
4
+ import { c as SerializedRouteError, n as PrachtRuntimeProvider, o as PrachtRuntimeDiagnosticPhase, s as PrachtRuntimeDiagnostics } from "./runtime-context-BYBwVA0M.mjs";
5
+ 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";
6
+ import { a as prerenderApp, c as applyDefaultSecurityHeaders, i as PrerenderResult, l as PrachtPhaseTimings, n as PrerenderAppOptions, o as HandlePrachtRequestOptions, r as PrerenderAppResult, s as handlePrachtRequest, t as ISGManifestEntry, u as formatServerTimingHeader } from "./prerender-BV42B9jK.mjs";
7
+ export { type ApiConfig, type ApiRouteArgs, type ApiRouteHandler, type ApiRouteMatch, type ApiRouteModule, type AppGraph, type AppGraphApiRoute, type AppGraphModuleAccess, type AppGraphRoute, type BaseRouteArgs, type BuildHrefOptions, type DataModule, type ErrorBoundaryProps, type GroupDefinition, type GroupMeta, type HandlePrachtRequestOptions, type HeadArgs, type HeadAttributes, type HeadMetadata, type HeadScriptDescriptor, type HeadersArgs, type HrefArgs, type HrefFn, type HrefOptions, type HrefRouteDefinition, type HttpMethod, type ISGManifestEntry, type LoaderArgs, type LoaderData, type LoaderFn, type MiddlewareArgs, type MiddlewareFn, type MiddlewareModule, type MiddlewareNext, type ModuleImporter, type ModuleRef, type ModuleRegistry, type NavigateOptions, type PrachtApp, type PrachtAppConfig, PrachtHttpError, type PrachtPhaseTimings, type PrachtRuntimeDiagnosticPhase, type PrachtRuntimeDiagnostics, PrachtRuntimeProvider, type PrefetchStrategy, type PrerenderAppOptions, type PrerenderAppResult, type PrerenderResult, 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 RouteTarget, type RouteTreeNode, type SearchParamPrimitive, type SearchParamValue, type SearchParamsInput, type SerializedRouteError, type ShellModule, type ShellProps, type TimeRevalidatePolicy, applyDefaultSecurityHeaders, buildAppGraph, buildHref, buildPathFromSegments, createHref, defineApp, detectApiMethods, formatServerTimingHeader, group, handlePrachtRequest, matchApiRoute, matchAppRoute, prerenderApp, redirect, resolveApiRoutes, resolveApp, route, serializeApiRoutes, serializeAppRoutes, timeRevalidate };
package/dist/server.mjs CHANGED
@@ -1,5 +1,6 @@
1
- import { a as matchApiRoute, c as resolveApp, i as group, l as route, n as buildPathFromSegments, o as matchAppRoute, r as defineApp, s as resolveApiRoutes, t as buildHref, u as timeRevalidate } from "./app-w-P1wf5T.mjs";
2
- import { S as createHref, _ as applyDefaultSecurityHeaders, t as PrachtHttpError, u as redirect } from "./types-DQv2poC5.mjs";
3
- import { t as PrachtRuntimeProvider } from "./runtime-context-B5pREhcM.mjs";
4
- import { n as handlePrachtRequest, t as prerenderApp } from "./prerender-CoMyuJKm.mjs";
5
- export { PrachtHttpError, PrachtRuntimeProvider, applyDefaultSecurityHeaders, buildHref, buildPathFromSegments, createHref, defineApp, group, handlePrachtRequest, matchApiRoute, matchAppRoute, prerenderApp, redirect, resolveApiRoutes, resolveApp, route, timeRevalidate };
1
+ import { a as matchApiRoute, c as resolveApp, i as group, l as route, n as buildPathFromSegments, o as matchAppRoute, r as defineApp, s as resolveApiRoutes, t as buildHref, u as timeRevalidate } from "./app-CGRKjZ6Z.mjs";
2
+ import { C as createHref, d as redirect, t as PrachtHttpError, v as applyDefaultSecurityHeaders } from "./types-DEPXdbyp.mjs";
3
+ import { i as serializeAppRoutes, n as detectApiMethods, r as serializeApiRoutes, t as buildAppGraph } from "./app-graph-BlaCcGUZ.mjs";
4
+ import { s as PrachtRuntimeProvider } from "./navigation-state-BjwXTeVz.mjs";
5
+ import { n as handlePrachtRequest, r as formatServerTimingHeader, t as prerenderApp } from "./prerender-C8BpANz3.mjs";
6
+ export { PrachtHttpError, PrachtRuntimeProvider, applyDefaultSecurityHeaders, buildAppGraph, buildHref, buildPathFromSegments, createHref, defineApp, detectApiMethods, formatServerTimingHeader, group, handlePrachtRequest, matchApiRoute, matchAppRoute, prerenderApp, redirect, resolveApiRoutes, resolveApp, route, serializeApiRoutes, serializeAppRoutes, timeRevalidate };
@@ -32,6 +32,17 @@ interface BuildHrefOptions {
32
32
  }
33
33
  interface NavigateOptions {
34
34
  replace?: boolean;
35
+ /**
36
+ * Keep the current scroll position after the navigation commits instead of
37
+ * scrolling to the top (or to the target `#hash` element).
38
+ */
39
+ preserveScroll?: boolean;
40
+ /**
41
+ * Wrap this navigation's DOM commit in `document.startViewTransition()`
42
+ * when the browser supports it. Overrides the app-level
43
+ * `viewTransitions` default for this navigation.
44
+ */
45
+ viewTransition?: boolean;
35
46
  }
36
47
  interface HrefRouteDefinition {
37
48
  id?: string;
@@ -51,6 +62,9 @@ type RouteParamsFor<TRoute extends RouteId> = HasRegisteredRoutes extends true ?
51
62
  type RouteSearchFor<TRoute extends RouteId> = HasRegisteredRoutes extends true ? TRoute extends keyof RegisteredRouteMap ? RegisteredRouteMap[TRoute] extends {
52
63
  search: infer TSearch;
53
64
  } ? TSearch : SearchParamsInput : never : SearchParamsInput;
65
+ type RouteDataFor<TRoute extends RouteId> = HasRegisteredRoutes extends true ? TRoute extends keyof RegisteredRouteMap ? RegisteredRouteMap[TRoute] extends {
66
+ data: infer TData;
67
+ } ? TData : unknown : never : unknown;
54
68
  type TypedHrefOptions<TRoute extends RouteId> = IsEmptyRouteParams<RouteParamsFor<TRoute>> extends true ? {
55
69
  params?: never;
56
70
  search?: RouteSearchFor<TRoute>;
@@ -105,6 +119,12 @@ interface ApiRouteMatch {
105
119
  pathname: string;
106
120
  }
107
121
  type PrefetchStrategy = "none" | "hover" | "viewport" | "intent";
122
+ /**
123
+ * Per-link prefetch strategy accepted by `<Link prefetch>`. Extends the
124
+ * route-level strategies with `"render"`, which prefetches as soon as the
125
+ * link is rendered.
126
+ */
127
+ type LinkPrefetchStrategy = PrefetchStrategy | "render";
108
128
  interface RouteMeta {
109
129
  id?: string;
110
130
  shell?: string;
@@ -153,12 +173,20 @@ interface PrachtAppConfig {
153
173
  middleware?: Record<string, ModuleRef>;
154
174
  api?: ApiConfig;
155
175
  routes: RouteTreeNode[];
176
+ /**
177
+ * Enable the View Transitions API for every client navigation by default.
178
+ * Individual navigations can still opt out via
179
+ * `navigate(to, { viewTransition: false })`. Ignored in browsers without
180
+ * `document.startViewTransition` support.
181
+ */
182
+ viewTransitions?: boolean;
156
183
  }
157
184
  interface PrachtApp {
158
185
  shells: Record<string, string>;
159
186
  middleware: Record<string, string>;
160
187
  api: ApiConfig;
161
188
  routes: RouteTreeNode[];
189
+ viewTransitions?: boolean;
162
190
  }
163
191
  interface StaticRouteSegment {
164
192
  type: "static";
@@ -216,6 +244,19 @@ interface HeadMetadata {
216
244
  type MaybePromise<T> = T | Promise<T>;
217
245
  type LoaderLike = ((args: LoaderArgs<any>) => unknown) | undefined;
218
246
  type LoaderData<TLoader extends LoaderLike> = TLoader extends ((...args: any[]) => infer TResult) ? Awaited<TResult> : never;
247
+ /**
248
+ * Extract loader data from a route module type. `pracht typegen` uses this to
249
+ * register per-route loader data on `Register["routes"]`. When a separate
250
+ * loader module is wired via the manifest (`loader: () => import(...)`), pass
251
+ * it first and the route module second — the loader module wins, matching the
252
+ * runtime's resolution order. Modules without a `loader` export resolve to
253
+ * `undefined`, mirroring the data a loaderless route receives.
254
+ */
255
+ type RouteLoaderData<TModule, TFallbackModule = TModule> = TModule extends {
256
+ loader: (...args: any[]) => infer TResult;
257
+ } ? Awaited<TResult> : TFallbackModule extends {
258
+ loader: (...args: any[]) => infer TFallbackResult;
259
+ } ? Awaited<TFallbackResult> : undefined;
219
260
  interface HeadArgs<TLoader extends LoaderLike = undefined, TContext = any> extends BaseRouteArgs<TContext> {
220
261
  data: LoaderData<TLoader>;
221
262
  }
@@ -274,25 +315,4 @@ declare class PrachtHttpError extends Error {
274
315
  constructor(status: number, message: string);
275
316
  }
276
317
  //#endregion
277
- //#region src/app.d.ts
278
- declare function timeRevalidate(seconds: number): TimeRevalidatePolicy;
279
- declare function route(path: string, file: ModuleRef, meta?: RouteMeta): RouteDefinition;
280
- declare function route(path: string, config: RouteConfig): RouteDefinition;
281
- declare function group(meta: GroupMeta, routes: RouteTreeNode[]): GroupDefinition;
282
- declare function defineApp(config: PrachtAppConfig): PrachtApp;
283
- declare function resolveApp(app: PrachtApp): ResolvedPrachtApp;
284
- declare function matchAppRoute(app: PrachtApp | ResolvedPrachtApp, pathname: string): RouteMatch | undefined;
285
- declare function buildPathFromSegments(segments: readonly RouteSegment[], params: RouteParams): string;
286
- declare function buildHref<TRoute extends RouteId>(routes: readonly HrefRouteDefinition[], routeId: TRoute, ...args: HrefArgs<TRoute>): string;
287
- /**
288
- * Convert a list of file paths from `import.meta.glob` into resolved API routes.
289
- *
290
- * Example: `"/src/api/health.ts"` → path `/api/health`
291
- * `"/src/api/users/[id].ts"` → path `/api/users/:id`
292
- * `"/src/api/files/[...path].ts"` → path `/api/files/*`
293
- * `"/src/api/index.ts"` → path `/api`
294
- */
295
- declare function resolveApiRoutes(files: string[], apiDir?: string): ResolvedApiRoute[];
296
- declare function matchApiRoute(apiRoutes: ResolvedApiRoute[], pathname: string): ApiRouteMatch | undefined;
297
- //#endregion
298
- export { RouteComponentProps as $, HrefRouteDefinition as A, ModuleImporter as B, HeadAttributes as C, HrefArgs as D, HeadersArgs as E, LoaderLike as F, PrachtAppConfig as G, ModuleRegistry as H, MiddlewareArgs as I, Register as J, PrachtHttpError as K, MiddlewareFn as L, LoaderArgs as M, LoaderData as N, HrefFn as O, LoaderFn as P, ResolvedRoute as Q, MiddlewareModule as R, HeadArgs as S, HeadScriptDescriptor as T, NavigateOptions as U, ModuleRef as V, PrachtApp as W, ResolvedApiRoute as X, RenderMode as Y, ResolvedPrachtApp as Z, BuildHrefOptions as _, ShellProps as _t, matchApiRoute as a, RouteModule as at, GroupDefinition as b, resolveApp as c, RouteParamsFor as ct, ApiConfig as d, RouteTarget as dt, RouteConfig as et, ApiRouteArgs as f, RouteTreeNode as ft, BaseRouteArgs as g, ShellModule as gt, ApiRouteModule as h, SearchParamsInput as ht, group as i, RouteMeta as it, HttpMethod as j, HrefOptions as k, route as l, RouteRevalidate as lt, ApiRouteMatch as m, SearchParamValue as mt, buildPathFromSegments as n, RouteId as nt, matchAppRoute as o, RouteParamInput as ot, ApiRouteHandler as p, SearchParamPrimitive as pt, PrefetchStrategy as q, defineApp as r, RouteMatch as rt, resolveApiRoutes as s, RouteParams as st, buildHref as t, RouteDefinition as tt, timeRevalidate as u, RouteSearchFor as ut, DataModule as v, TimeRevalidatePolicy as vt, HeadMetadata as w, GroupMeta as x, ErrorBoundaryProps as y, MiddlewareNext as z };
318
+ export { RouteParamInput as $, MiddlewareNext as A, RenderMode as B, LoaderArgs as C, MiddlewareArgs as D, LoaderLike as E, PrachtApp as F, RouteConfig as G, ResolvedPrachtApp as H, PrachtAppConfig as I, RouteId as J, RouteDataFor as K, PrachtHttpError as L, ModuleRef as M, ModuleRegistry as N, MiddlewareFn as O, NavigateOptions as P, RouteModule as Q, PrefetchStrategy as R, LinkPrefetchStrategy as S, LoaderFn as T, ResolvedRoute as U, ResolvedApiRoute as V, RouteComponentProps as W, RouteMatch as X, RouteLoaderData as Y, RouteMeta as Z, HrefArgs as _, ApiRouteModule as a, RouteTarget as at, HrefRouteDefinition as b, DataModule as c, SearchParamValue as ct, GroupMeta as d, ShellProps as dt, RouteParams as et, HeadArgs as f, TimeRevalidatePolicy as ft, HeadersArgs as g, HeadScriptDescriptor as h, ApiRouteMatch as i, RouteSegment as it, ModuleImporter as j, MiddlewareModule as k, ErrorBoundaryProps as l, SearchParamsInput as lt, HeadMetadata as m, ApiRouteArgs as n, RouteRevalidate as nt, BaseRouteArgs as o, RouteTreeNode as ot, HeadAttributes as p, RouteDefinition as q, ApiRouteHandler as r, RouteSearchFor as rt, BuildHrefOptions as s, SearchParamPrimitive as st, ApiConfig as t, RouteParamsFor as tt, GroupDefinition as u, ShellModule as ut, HrefFn as v, LoaderData as w, HttpMethod as x, HrefOptions as y, Register as z };
@@ -1,8 +1,8 @@
1
- import { t as buildHref } from "./app-w-P1wf5T.mjs";
2
- import { c as navigateToClientLocation, h as SAFE_METHODS, l as parseSafeNavigationUrl, m as ROUTE_STATE_REQUEST_HEADER, p as ROUTE_STATE_CACHE_CONTROL, r as clearPrefetchCache, s as fetchPrachtRouteState } from "./prefetch-cache-DzP2Bj9H.mjs";
3
- import { n as RouteDataContext, s as deserializeRouteError } from "./runtime-context-B5pREhcM.mjs";
1
+ import { t as buildHref } from "./app-CGRKjZ6Z.mjs";
2
+ import { _ as ROUTE_STATE_REQUEST_HEADER, c as fetchPrachtRouteState, g as ROUTE_STATE_CACHE_CONTROL, h as PRESERVE_SCROLL_ATTRIBUTE, l as navigateToClientLocation, m as PREFETCH_ATTRIBUTE, r as clearPrefetchCache, u as parseSafeNavigationUrl, v as SAFE_METHODS, y as VIEW_TRANSITION_ATTRIBUTE } from "./prefetch-cache-BNLEp9H5.mjs";
3
+ import { a as settleNavigation, c as RouteDataContext, i as getNavigation, n as beginSubmittingNavigation, o as subscribeToNavigation, p as deserializeRouteError, r as createNavigationLocation } from "./navigation-state-BjwXTeVz.mjs";
4
4
  import { h } from "preact";
5
- import { useContext } from "preact/hooks";
5
+ import { useContext, useEffect, useState } from "preact/hooks";
6
6
  //#region src/href.ts
7
7
  function createHref(routes) {
8
8
  return ((routeId, options) => buildHref(routes, routeId, options));
@@ -268,8 +268,10 @@ async function mergeDocumentHeaders(shellModule, routeModule, routeArgs, data) {
268
268
  }
269
269
  //#endregion
270
270
  //#region src/runtime-hooks.ts
271
- function useRouteData() {
272
- return useContext(RouteDataContext)?.data;
271
+ function useRouteData(routeId) {
272
+ const runtime = useContext(RouteDataContext);
273
+ if (import.meta.env?.DEV && routeId !== void 0 && runtime && runtime.routeId !== routeId) console.warn(`useRouteData("${routeId}") rendered inside route "${runtime.routeId}"; returning the active route's data.`);
274
+ return runtime?.data;
273
275
  }
274
276
  function useLocation() {
275
277
  return parseLocation(useContext(RouteDataContext)?.url ?? (typeof window !== "undefined" ? window.location.pathname + window.location.search : "/"));
@@ -291,17 +293,36 @@ function useRevalidate() {
291
293
  return result.data;
292
294
  };
293
295
  }
296
+ /**
297
+ * Reactive pending state for the current client navigation or `<Form>`
298
+ * submission. Returns `{ state: "idle" }` when nothing is in flight,
299
+ * `{ state: "loading", location }` while the router fetches and commits a
300
+ * navigation, and `{ state: "submitting", location, formData }` while a
301
+ * `<Form>` submission is awaiting its response. During SSR it always
302
+ * returns the idle state.
303
+ */
304
+ function useNavigation() {
305
+ const [navigation, setNavigation] = useState(getNavigation);
306
+ useEffect(() => {
307
+ setNavigation(getNavigation());
308
+ return subscribeToNavigation(setNavigation);
309
+ }, []);
310
+ return navigation;
311
+ }
294
312
  function Link(props) {
295
313
  const routes = useContext(RouteDataContext)?.routes ?? globalThis.__PRACHT_ROUTE_DEFINITIONS__;
296
314
  if (!routes) throw new Error("<Link route=...> must render inside a pracht route tree.");
297
- const { route, params, search, hash, ...anchorProps } = props;
315
+ const { route, params, search, hash, prefetch, preserveScroll, viewTransition, ...anchorProps } = props;
298
316
  return h("a", {
299
317
  ...anchorProps,
300
318
  href: buildHref(routes, route, {
301
319
  params,
302
320
  search,
303
321
  hash
304
- })
322
+ }),
323
+ [PREFETCH_ATTRIBUTE]: prefetch,
324
+ [PRESERVE_SCROLL_ATTRIBUTE]: preserveScroll ? "" : void 0,
325
+ [VIEW_TRANSITION_ATTRIBUTE]: viewTransition ? "" : void 0
305
326
  });
306
327
  }
307
328
  function Form(props) {
@@ -318,12 +339,19 @@ function Form(props) {
318
339
  if (SAFE_METHODS.has(formMethod)) return;
319
340
  event.preventDefault();
320
341
  clearPrefetchCache();
321
- const response = await fetch(props.action ?? form.action, {
322
- method: formMethod,
323
- body: new FormData(form),
324
- redirect: "manual"
325
- });
326
- if (response.type === "opaqueredirect" || response.status >= 300 && response.status < 400) await navigateToClientLocation(response.headers.get("location") ?? props.action ?? form.action);
342
+ const actionUrl = props.action ?? form.action;
343
+ const formData = new FormData(form);
344
+ const navigationToken = beginSubmittingNavigation(createNavigationLocation(actionUrl), formData);
345
+ try {
346
+ const response = await fetch(actionUrl, {
347
+ method: formMethod,
348
+ body: formData,
349
+ redirect: "manual"
350
+ });
351
+ if (response.type === "opaqueredirect" || response.status >= 300 && response.status < 400) await navigateToClientLocation(response.headers.get("location") ?? actionUrl);
352
+ } finally {
353
+ settleNavigation(navigationToken);
354
+ }
327
355
  }
328
356
  });
329
357
  }
@@ -345,4 +373,4 @@ var PrachtHttpError = class extends Error {
345
373
  }
346
374
  };
347
375
  //#endregion
348
- export { createHref as S, applyDefaultSecurityHeaders as _, useParams as a, withDefaultSecurityHeaders as b, mergeDocumentHeaders as c, runMiddlewareChain as d, resolveDataFunctions as f, appendVaryHeader as g, resolveRegistryModule as h, useLocation as i, mergeHeadMetadata as l, resolvePageJsUrls as m, Form as n, useRevalidate as o, resolvePageCssUrls as p, Link as r, useRouteData as s, PrachtHttpError as t, redirect as u, applyHeaders as v, withRouteResponseHeaders as x, applySecurityAndRouteHeaders as y };
376
+ export { createHref as C, withRouteResponseHeaders as S, appendVaryHeader as _, useNavigation as a, applySecurityAndRouteHeaders as b, useRouteData as c, redirect as d, runMiddlewareChain as f, resolveRegistryModule as g, resolvePageJsUrls as h, useLocation as i, mergeDocumentHeaders as l, resolvePageCssUrls as m, Form as n, useParams as o, resolveDataFunctions as p, Link as r, useRevalidate as s, PrachtHttpError as t, mergeHeadMetadata as u, applyDefaultSecurityHeaders as v, withDefaultSecurityHeaders as x, applyHeaders as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pracht/core",
3
- "version": "0.8.1",
3
+ "version": "0.9.0",
4
4
  "description": "Core runtime for Pracht, a full-stack Preact framework with per-route SSR, SSG, ISG, SPA, loaders, and API routes.",
5
5
  "keywords": [
6
6
  "pracht",
@@ -53,6 +53,14 @@
53
53
  "./error-overlay": {
54
54
  "types": "./dist/error-overlay.d.mts",
55
55
  "default": "./dist/error-overlay.mjs"
56
+ },
57
+ "./dev-404": {
58
+ "types": "./dist/dev-404.d.mts",
59
+ "default": "./dist/dev-404.mjs"
60
+ },
61
+ "./devtools": {
62
+ "types": "./dist/devtools.d.mts",
63
+ "default": "./dist/devtools.mjs"
56
64
  }
57
65
  },
58
66
  "publishConfig": {
@@ -1,23 +0,0 @@
1
- import { FunctionComponent } from "preact";
2
-
3
- //#region src/forwardRef.d.ts
4
- /**
5
- * Pass ref down to a child. This is mainly used in libraries with HOCs that
6
- * wrap components. Using `forwardRef` there is an easy way to get a reference
7
- * of the wrapped component instead of one of the wrapper itself.
8
- */
9
- declare function forwardRef<P = {}>(fn: ((props: P, ref: any) => any) & {
10
- displayName?: string;
11
- }): FunctionComponent<P & {
12
- ref?: any;
13
- }>;
14
- //#endregion
15
- //#region src/hydration.d.ts
16
- /**
17
- * Returns `true` once the initial hydration (including all Suspense
18
- * boundaries) has fully resolved. During SSR and hydration this returns
19
- * `false`.
20
- */
21
- declare function useIsHydrated(): boolean;
22
- //#endregion
23
- export { forwardRef as n, useIsHydrated as t };