@rivetjs/router 0.0.0-stage → 0.1.0-alpha.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 (143) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -2
  3. package/adapters/assemble.d.ts +32 -0
  4. package/adapters/assemble.js +32 -0
  5. package/adapters/build.d.ts +24 -0
  6. package/adapters/build.js +43 -0
  7. package/adapters/bun.d.ts +18 -0
  8. package/adapters/bun.js +44 -0
  9. package/adapters/cloudflare.d.ts +5 -0
  10. package/adapters/cloudflare.js +8 -0
  11. package/adapters/cluster.d.ts +7 -0
  12. package/adapters/cluster.js +130 -0
  13. package/adapters/csr.d.ts +12 -0
  14. package/adapters/csr.js +11 -0
  15. package/adapters/deno.d.ts +13 -0
  16. package/adapters/deno.js +35 -0
  17. package/adapters/fetch.d.ts +55 -0
  18. package/adapters/fetch.js +72 -0
  19. package/adapters/files.d.ts +7 -0
  20. package/adapters/files.js +103 -0
  21. package/adapters/idle-memory.d.ts +23 -0
  22. package/adapters/idle-memory.js +91 -0
  23. package/adapters/netlify.d.ts +13 -0
  24. package/adapters/netlify.js +15 -0
  25. package/adapters/node.d.ts +163 -0
  26. package/adapters/node.js +940 -0
  27. package/adapters/pack.d.ts +39 -0
  28. package/adapters/pack.js +360 -0
  29. package/adapters/server-target.d.ts +17 -0
  30. package/adapters/server-target.js +8 -0
  31. package/adapters/static.d.ts +84 -0
  32. package/adapters/static.js +231 -0
  33. package/adapters/target-build.d.ts +92 -0
  34. package/adapters/target-build.js +118 -0
  35. package/adapters/vercel-edge.d.ts +7 -0
  36. package/adapters/vercel-edge.js +9 -0
  37. package/adapters/vercel.d.ts +33 -0
  38. package/adapters/vercel.js +45 -0
  39. package/build/codegen.d.ts +84 -0
  40. package/build/codegen.js +920 -0
  41. package/build/dev-errors.d.ts +19 -0
  42. package/build/dev-errors.js +236 -0
  43. package/build/migrate.d.ts +15 -0
  44. package/build/migrate.js +146 -0
  45. package/build/route-css.d.ts +54 -0
  46. package/build/route-css.js +216 -0
  47. package/build/routes.d.ts +50 -0
  48. package/build/routes.js +202 -0
  49. package/build/sync.d.ts +20 -0
  50. package/build/sync.js +16 -0
  51. package/build/vite.d.ts +195 -0
  52. package/build/vite.js +703 -0
  53. package/cli/rivet.d.ts +2 -0
  54. package/cli/rivet.js +100 -0
  55. package/client/active.d.ts +6 -0
  56. package/client/active.js +22 -0
  57. package/client/announce.d.ts +2 -0
  58. package/client/announce.js +21 -0
  59. package/client/dev.d.ts +41 -0
  60. package/client/dev.js +74 -0
  61. package/client/index.d.ts +152 -0
  62. package/client/index.js +680 -0
  63. package/client/layouts.d.ts +110 -0
  64. package/client/layouts.js +310 -0
  65. package/client/leave.d.ts +40 -0
  66. package/client/leave.js +75 -0
  67. package/client/link.d.ts +48 -0
  68. package/client/link.jsx +65 -0
  69. package/client/live.d.ts +57 -0
  70. package/client/live.js +170 -0
  71. package/client/navigate.d.ts +71 -0
  72. package/client/navigate.js +120 -0
  73. package/client/navigation.d.ts +28 -0
  74. package/client/navigation.js +14 -0
  75. package/client/params.d.ts +16 -0
  76. package/client/params.js +28 -0
  77. package/client/route-context.d.ts +32 -0
  78. package/client/route-context.js +21 -0
  79. package/client/scroll.d.ts +16 -0
  80. package/client/scroll.js +80 -0
  81. package/client/search.d.ts +8 -0
  82. package/client/search.js +17 -0
  83. package/client/tailwind.css +8 -0
  84. package/client/transition-helpers.d.ts +28 -0
  85. package/client/transition-helpers.js +63 -0
  86. package/client/transitions.css +90 -0
  87. package/client/transitions.d.ts +21 -0
  88. package/client/transitions.js +156 -0
  89. package/index.d.ts +138 -0
  90. package/index.js +7 -0
  91. package/package.json +156 -4
  92. package/server/app.d.ts +169 -0
  93. package/server/app.js +302 -0
  94. package/server/body.d.ts +20 -0
  95. package/server/body.js +8 -0
  96. package/server/early-hints.d.ts +34 -0
  97. package/server/early-hints.js +63 -0
  98. package/server/handler.d.ts +196 -0
  99. package/server/handler.js +623 -0
  100. package/server/index.d.ts +9 -0
  101. package/server/index.js +6 -0
  102. package/server/inline-styles.d.ts +21 -0
  103. package/server/inline-styles.js +28 -0
  104. package/server/module.d.ts +14 -0
  105. package/server/module.js +78 -0
  106. package/server/render.d.ts +94 -0
  107. package/server/render.js +489 -0
  108. package/server/route-cache.d.ts +175 -0
  109. package/server/route-cache.js +742 -0
  110. package/server/security.d.ts +18 -0
  111. package/server/security.js +47 -0
  112. package/server/strict-csp.d.ts +7 -0
  113. package/server/strict-csp.js +18 -0
  114. package/server-only.d.ts +1 -0
  115. package/server-only.js +3 -0
  116. package/shared/actions.d.ts +10 -0
  117. package/shared/actions.js +18 -0
  118. package/shared/base.d.ts +8 -0
  119. package/shared/base.js +20 -0
  120. package/shared/cookie.d.ts +7 -0
  121. package/shared/cookie.js +32 -0
  122. package/shared/csp-directives.d.ts +9 -0
  123. package/shared/csp-directives.js +85 -0
  124. package/shared/csp-hash.d.ts +39 -0
  125. package/shared/csp-hash.js +121 -0
  126. package/shared/csp.d.ts +26 -0
  127. package/shared/csp.js +13 -0
  128. package/shared/data.d.ts +175 -0
  129. package/shared/data.js +22 -0
  130. package/shared/errors.d.ts +31 -0
  131. package/shared/errors.js +51 -0
  132. package/shared/head.d.ts +57 -0
  133. package/shared/head.js +242 -0
  134. package/shared/nonce.d.ts +2 -0
  135. package/shared/nonce.js +23 -0
  136. package/shared/prefetch-fallback.min.d.ts +1 -0
  137. package/shared/prefetch-fallback.min.js +2 -0
  138. package/shared/prefetch.d.ts +54 -0
  139. package/shared/prefetch.js +74 -0
  140. package/shared/redirect.d.ts +6 -0
  141. package/shared/redirect.js +25 -0
  142. package/shared/slash.d.ts +8 -0
  143. package/shared/slash.js +24 -0
package/cli/rivet.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/cli/rivet.js ADDED
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env node
2
+ // Rivet router CLI.
3
+ // rivet sync [--root <dir>] [--config <vite config>] [--mode <mode>]
4
+ // Write the app's generated `.rivet/` files (route types, generated app, editor manifest) from its
5
+ // Vite config without starting Vite. Run before `tsc` / `rivet-check` on a fresh clone.
6
+ // rivet migrate server-exports [--routes src/routes] [--dry-run]
7
+ // Rename old `*.server.ts` export names (load, guard, actions, entries, headers, GET…) to
8
+ // serverLoad, serverGuard, serverActions, serverEntries, serverHeaders, onGet… (scope-aware).
9
+ // rivet mcp
10
+ // Start the Rivet MCP server (`@rivetjs/mcp`, stdio) installed in the app; same as `npx @rivetjs/mcp`.
11
+ import { relative } from "node:path";
12
+ const USAGE = `usage: rivet sync [--root <dir>] [--config <file>] [--mode <mode>]
13
+ rivet migrate server-exports [--routes <dir>] [--dry-run]
14
+ rivet mcp`;
15
+ async function syncCommand(args) {
16
+ const options = {};
17
+ for (let i = 0; i < args.length; i++) {
18
+ const [flag, value] = [args[i], args[i + 1]];
19
+ if (value === undefined || !["--root", "--config", "--mode"].includes(flag)) {
20
+ console.error(USAGE);
21
+ return 2;
22
+ }
23
+ options[flag === "--root" ? "root" : flag === "--config" ? "configFile" : "mode"] = value;
24
+ i++;
25
+ }
26
+ const { sync } = await import("../build/sync.js");
27
+ const result = await sync(options);
28
+ const where = relative(process.cwd(), result.root) || ".";
29
+ if (!result.configFile) {
30
+ console.error(`rivet sync: no Vite config in ${where}`);
31
+ return 2;
32
+ }
33
+ if (!result.manifest) {
34
+ console.error(`rivet sync: ${relative(process.cwd(), result.configFile)} uses no Rivet Vite plugin (nothing generated)`);
35
+ return 2;
36
+ }
37
+ const routes = result.manifest.routes?.length ?? 0;
38
+ const resume = result.manifest.resumeModules?.length ?? 0;
39
+ console.log(`rivet sync: ${where}/.rivet (${routes} route${routes === 1 ? "" : "s"}, ${resume} resume module${resume === 1 ? "" : "s"})`);
40
+ return 0;
41
+ }
42
+ async function migrateCommand(rest) {
43
+ let routes = "src/routes";
44
+ let dry = false;
45
+ for (let i = 0; i < rest.length; i++) {
46
+ if (rest[i] === "--dry-run")
47
+ dry = true;
48
+ else if (rest[i] === "--routes" && rest[i + 1])
49
+ routes = rest[++i];
50
+ else {
51
+ console.error(USAGE);
52
+ return 2;
53
+ }
54
+ }
55
+ const { migrateServerExports, writeMigration } = await import("../build/migrate.js");
56
+ const cwd = process.cwd();
57
+ const report = await migrateServerExports(cwd, routes);
58
+ for (const line of report.renamed)
59
+ console.log("renamed " + line);
60
+ for (const line of report.skipped)
61
+ console.log("skipped " + line);
62
+ if (!dry)
63
+ await writeMigration(report);
64
+ console.log(`${dry ? "would change" : "changed"} ${report.changes.size} file(s)${report.changes.size ? ": " + [...report.changes.keys()].map((f) => relative(cwd, f)).join(", ") : ""}`);
65
+ return 0;
66
+ }
67
+ /** `rivet mcp`: run the app's `@rivetjs/mcp` bin with this process's stdio (the MCP protocol). */
68
+ async function mcpCommand() {
69
+ const { createRequire } = await import("node:module");
70
+ const { dirname, join } = await import("node:path");
71
+ const { existsSync } = await import("node:fs");
72
+ const { spawn } = await import("node:child_process");
73
+ let dir;
74
+ try {
75
+ dir = dirname(createRequire(join(process.cwd(), "noop.js")).resolve("@rivetjs/mcp"));
76
+ }
77
+ catch {
78
+ console.error("rivet mcp: @rivetjs/mcp is not installed here; run `npx -y @rivetjs/mcp` or `npm install -D @rivetjs/mcp`");
79
+ return 2;
80
+ }
81
+ const cli = ["cli.js", "cli.ts"].map((name) => join(dir, name)).find((file) => existsSync(file));
82
+ const child = spawn(process.execPath, [cli, ...process.argv.slice(3)], { stdio: "inherit" });
83
+ return new Promise((done) => child.on("exit", (code) => done(code ?? 1)));
84
+ }
85
+ async function main(argv) {
86
+ const [command, ...rest] = argv;
87
+ if (command === "sync")
88
+ return syncCommand(rest);
89
+ if (command === "migrate" && rest[0] === "server-exports")
90
+ return migrateCommand(rest.slice(1));
91
+ if (command === "mcp")
92
+ return mcpCommand();
93
+ if (command === "-h" || command === "--help") {
94
+ console.log(USAGE);
95
+ return 0;
96
+ }
97
+ console.error(USAGE);
98
+ return 2;
99
+ }
100
+ process.exitCode = await main(process.argv.slice(2));
@@ -0,0 +1,6 @@
1
+ /** Link active mode: `"exact"` (same path) or `"prefix"` (same path or below it). */
2
+ export type ActiveMode = "exact" | "prefix";
3
+ /** `aria-current` for a link to `path` while the page is `here`: `page` on the page itself, `true` below it (prefix). */
4
+ export declare function currentOf(path: string, here: string, mode: ActiveMode): "page" | "true" | undefined;
5
+ /** @internal Generated App (apps using `<Link active>`): re-mark active links after a navigation commits. */
6
+ export declare function _markActive(): void;
@@ -0,0 +1,22 @@
1
+ // `<Link active>` state: the link's path against the current page's. Rendered by `<Link>` (server:
2
+ // the request URL; browser renders: `location`); after client navigation the generated App re-marks
3
+ // every `a[data-rivet-active]` (`_markActive`, only in apps that use `active`).
4
+ // One optional trailing slash is the same route (the matcher accepts it).
5
+ const trim = (path) => (path.length > 1 && path.endsWith("/") ? path.slice(0, -1) : path);
6
+ /** `aria-current` for a link to `path` while the page is `here`: `page` on the page itself, `true` below it (prefix). */
7
+ export function currentOf(path, here, mode) {
8
+ const to = trim(path), at = trim(here);
9
+ if (to === at)
10
+ return "page";
11
+ return mode === "prefix" && at.startsWith(to === "/" ? "/" : to + "/") ? "true" : undefined;
12
+ }
13
+ /** @internal Generated App (apps using `<Link active>`): re-mark active links after a navigation commits. */
14
+ export function _markActive() {
15
+ document.querySelectorAll("a[data-rivet-active]").forEach((anchor) => {
16
+ const current = currentOf(anchor.pathname, location.pathname, anchor.getAttribute("data-rivet-active"));
17
+ if (current)
18
+ (anchor.setAttribute("aria-current", current), anchor.setAttribute("data-current", ""));
19
+ else
20
+ (anchor.removeAttribute("aria-current"), anchor.removeAttribute("data-current"));
21
+ });
22
+ }
@@ -0,0 +1,2 @@
1
+ /** Announce the committed page to screen readers: its title, else its first h1, else its path. */
2
+ export declare function announce(): void;
@@ -0,0 +1,21 @@
1
+ // Route announcer: one visually hidden live region, created on the first client navigation (pages
2
+ // that never navigate client-side get no node and run nothing). Styled through CSSOM, which strict
3
+ // `style-src` policies allow, unlike an inline `style` attribute in markup.
4
+ let region;
5
+ const HIDDEN = "position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap";
6
+ /** Announce the committed page to screen readers: its title, else its first h1, else its path. */
7
+ export function announce() {
8
+ const text = document.title || document.querySelector("h1")?.textContent?.trim() || location.pathname;
9
+ if (!region) {
10
+ region = document.createElement("div");
11
+ region.setAttribute("aria-live", "assertive");
12
+ region.setAttribute("aria-atomic", "true");
13
+ region.style.cssText = HIDDEN;
14
+ }
15
+ if (!region.isConnected)
16
+ document.body.append(region);
17
+ // Cleared, then set a frame later: the same text twice in a row is announced again.
18
+ region.textContent = "";
19
+ const node = region;
20
+ requestAnimationFrame(() => (node.textContent = text));
21
+ }
@@ -0,0 +1,41 @@
1
+ import * as client from "./index.js";
2
+ import type { Layouts, RoutePayload } from "./index.js";
3
+ export * from "./index.js";
4
+ /** What the DevTools Router pane shows (plain data; values are previewed by the agent). */
5
+ export interface RouterSnapshot {
6
+ route: {
7
+ pattern: string;
8
+ url: string;
9
+ params: Readonly<Record<string, string>>;
10
+ } | null;
11
+ /** Loader data along the chain: layout ids, then `page`. */
12
+ data: {
13
+ id: string;
14
+ value: unknown;
15
+ }[];
16
+ layouts: string[];
17
+ pending: {
18
+ to: string;
19
+ type: string;
20
+ trigger: string;
21
+ ms: number;
22
+ state: string;
23
+ } | null;
24
+ last: RouterNavigation | null;
25
+ history: RouterNavigation[];
26
+ loadMs: number | null;
27
+ error: string | null;
28
+ }
29
+ export interface RouterNavigation {
30
+ from: string | null;
31
+ to: string;
32
+ type: string;
33
+ trigger: string;
34
+ /** Start to commit (ms). */
35
+ ms: number | null;
36
+ at: number;
37
+ }
38
+ /** `routeData`, recording the loaded route (pattern, params, loader data, time) for DevTools. */
39
+ export declare function routeData(...args: Parameters<typeof client.routeData>): Promise<RoutePayload>;
40
+ /** `_layouts`, keeping the generated layout table (layout ids for the chain). */
41
+ export declare function _layouts(...args: Parameters<typeof client._layouts>): Layouts;
package/client/dev.js ADDED
@@ -0,0 +1,74 @@
1
+ // Development façade of `@rivetjs/router/client` (`development` export condition: Vite dev, never a
2
+ // production build). Same exports; with a devtools hook installed it names the router's contexts and
3
+ // reports a `lib.router` describer: the shown route (pattern, params, loader data per layout), the
4
+ // layout chain, the navigation in flight and recent navigations. Generated apps import `routeData`,
5
+ // `_layouts` and `_landed` from this entry, so the wrappers below see every route load.
6
+ import { untrack } from "@rivetjs/reactivity";
7
+ import { devtoolsHook } from "@rivetjs/reactivity/debug";
8
+ import * as client from "./index.js";
9
+ export * from "./index.js";
10
+ const hook = devtoolsHook();
11
+ let table = null;
12
+ let shown = null;
13
+ let pending = null;
14
+ const history = [];
15
+ const changed = () => hook?.emit("lib.changed", { lib: "router" });
16
+ const now = () => performance.now();
17
+ function snapshot() {
18
+ const layouts = shown && table ? (table.routes.find(([pattern]) => pattern === shown.pattern)?.[1] ?? []).map((i) => table.ids[i]) : [];
19
+ const data = shown ? shown.data.map((value, i) => ({ id: i < layouts.length ? layouts[i] : i === shown.data.length - 1 ? "page" : "#" + i, value })) : [];
20
+ const state = untrack(client.navigation);
21
+ return {
22
+ route: shown ? { pattern: shown.pattern, url: shown.url, params: shown.params } : null,
23
+ data,
24
+ layouts,
25
+ pending: pending ? { to: pending.to, type: pending.type, trigger: pending.trigger, ms: now() - pending.start, state: state.state } : state.state !== "idle" && state.location ? { to: state.location.href, type: state.type ?? "push", trigger: "api", ms: 0, state: state.state } : null,
26
+ last: history.at(-1) ?? null,
27
+ history: history.slice(-10).reverse(),
28
+ loadMs: shown?.ms ?? null,
29
+ error: shown?.error ?? null,
30
+ };
31
+ }
32
+ if (hook !== undefined) {
33
+ for (const [token, name] of [
34
+ [client.Navigation, "Navigation"],
35
+ [client.SearchParams, "SearchParams"],
36
+ [client.RouteParamsContext, "RouteParams"],
37
+ [client.ServerData, "ServerData"],
38
+ ])
39
+ hook.emit("name", { value: token, name });
40
+ hook.emit("lib.register", { lib: "router", describe: snapshot });
41
+ client.onNavigate((nav) => {
42
+ pending = { from: nav.from?.href ?? null, to: nav.to.href, type: nav.type, trigger: nav.trigger, ms: null, at: Date.now(), start: now() };
43
+ changed();
44
+ return () => {
45
+ if (!pending)
46
+ return;
47
+ const { start, ...done } = pending;
48
+ history.push({ ...done, ms: now() - start });
49
+ if (history.length > 50)
50
+ history.shift();
51
+ pending = null;
52
+ changed();
53
+ };
54
+ });
55
+ }
56
+ /** `routeData`, recording the loaded route (pattern, params, loader data, time) for DevTools. */
57
+ export function routeData(...args) {
58
+ const loaded = client.routeData(...args);
59
+ if (hook === undefined)
60
+ return loaded;
61
+ const [, match] = args, start = now();
62
+ const route = match;
63
+ const record = (data, error) => {
64
+ shown = { pattern: route.route?.path ?? route.url.pathname, url: route.url.href, params: route.params ?? {}, data, ms: now() - start, error };
65
+ changed();
66
+ };
67
+ loaded.then((result) => record(result.data, null), (error) => record([], error instanceof Error ? error.message : String(error)));
68
+ return loaded;
69
+ }
70
+ /** `_layouts`, keeping the generated layout table (layout ids for the chain). */
71
+ export function _layouts(...args) {
72
+ table = args[2];
73
+ return client._layouts(...args);
74
+ }
@@ -0,0 +1,152 @@
1
+ import { type Context } from "@rivetjs/reactivity";
2
+ import { type RoutePayload } from "../shared/data.js";
3
+ import { type NavigationState, type NavigationType } from "./navigation.js";
4
+ import { type _go, type NavigateRequest } from "./navigate.js";
5
+ import { type LayoutTable, type Layouts } from "./layouts.js";
6
+ export { _layouts, _level, _enter, _take, _landed, _sync, _keepIds, type LayoutTable, type Layouts } from "./layouts.js";
7
+ export { beforeLeave, type LeaveEvent } from "./leave.js";
8
+ export type { ActionResult, Head, RoutePayload } from "../shared/data.js";
9
+ export { Navigation, navigation, IDLE, type NavigationState, type NavigationType } from "./navigation.js";
10
+ export { Link, type LinkProps } from "./link.jsx";
11
+ export { currentOf, _markActive, type ActiveMode } from "./active.js";
12
+ export { navigate, invalidate, revalidate, setSearchParams, _go, type NavigateOptions, type FreshData, type InvalidateTarget } from "./navigate.js";
13
+ export { useParams, useSearchParams, RouteParamsContext } from "./params.js";
14
+ export { SearchParams } from "./search.js";
15
+ export { _live, _livePage, _liveRouter, _armLive, _liveIntent, _liveLevels, _serveLive, type LivePage } from "./live.js";
16
+ export { ServerData, actionResult, type ServerRoutePayload } from "./route-context.js";
17
+ /** @internal The app router as the client drives it. */
18
+ export interface Navigator {
19
+ navigate?(to: string | URL, options?: {
20
+ replace?: boolean;
21
+ revalidate?: boolean;
22
+ }): void;
23
+ }
24
+ interface Work {
25
+ readonly signal: AbortSignal;
26
+ get<T>(token: Context<T>): T;
27
+ }
28
+ /**
29
+ * Where client navigation gets route data: the server's data endpoint, prerendered `_data.json`
30
+ * files (static adapter) or nowhere (CSR adapter: pages render without loader data).
31
+ */
32
+ export type DataSource = "server" | "static" | "none";
33
+ declare function dropPrefetch(except?: string, now?: number): void;
34
+ /** URL of a page's data for client navigation; `keep`: ids of layouts whose data the client has. */
35
+ export declare function dataURL(url: URL, source?: DataSource, keep?: string): string;
36
+ /** Decode a data-endpoint body (resume table encoding; built-in entries load their decoders first, `x`). */
37
+ export declare function decodeData(text: string): Promise<unknown>;
38
+ /**
39
+ * @internal Server render of a generated route level: the handler's loader results (`ServerData`) through the
40
+ * route's result chain synchronously (`ok` / `fail` as the `then` steps of the browser chain, then `land`) — no
41
+ * `Promise.all` / `then` hops per request, no page import (the lazy page view loads itself, rendering
42
+ * synchronously once its module is in). Browser (and no `ServerData`): undefined, the generated chain runs.
43
+ */
44
+ export declare function _ssrLevel<R, T>(work: Work, ok: (data: RoutePayload) => R, fail: (cause: unknown) => R, land: (result: R) => T): T | undefined;
45
+ /** Load a generated route's data: from `ServerData` on the server, from the data endpoint in the browser. */
46
+ export declare function routeData(work: Work, match: {
47
+ url: URL;
48
+ }, router: Navigator, source?: DataSource, keep?: string): Promise<RoutePayload>;
49
+ /**
50
+ * Same-origin, same-document-eligible anchor for a click/hover event, else null. With the app's page
51
+ * `modules`, a URL no page route matches (an endpoint, a file, another app on the origin) is not
52
+ * routable either: the browser loads its document (no data request, no chunk prefetch).
53
+ */
54
+ export declare function routableAnchor(event: Event, modules?: ModuleTable): HTMLAnchorElement | null;
55
+ /** One client navigation, from its start to its commit (`rivet:navigate` event detail, `onNavigate`). */
56
+ export interface NavigationInfo {
57
+ readonly from: URL | null;
58
+ readonly to: URL;
59
+ readonly type: NavigationType;
60
+ readonly trigger: "link" | "api" | "popstate" | "redirect";
61
+ /** The clicked anchor (link navigations). */
62
+ readonly anchor?: HTMLAnchorElement;
63
+ /** The link's `data-transition` (`<Link transition>`). */
64
+ readonly transition?: string | null;
65
+ /** Popstate the browser already animated (`hasUAVisualTransition`, e.g. a swipe). */
66
+ readonly visual?: boolean;
67
+ /** @internal The page module's `transition` export, once its chunk is in. */
68
+ route?: unknown;
69
+ }
70
+ /** @internal Hooks installed by `@rivetjs/router/transitions` once it loads. */
71
+ export declare const _transitions: {
72
+ start?(nav: NavigationInfo): void;
73
+ swap?(apply: () => void, next: ParentNode, nav: NavigationInfo): void;
74
+ };
75
+ /**
76
+ * Run `fn(nav)` when a client navigation starts (link, back/forward, redirect); a function it
77
+ * returns runs once the new page is in the document. Returns an unsubscribe function.
78
+ */
79
+ export declare function onNavigate(fn: (nav: NavigationInfo) => void | (() => void)): () => void;
80
+ /** @internal The navigation in flight (read by the transitions module when it installs). */
81
+ export declare const _current: () => NavigationInfo | null;
82
+ /** @internal Run the `onNavigate` callbacks' after-swap functions. */
83
+ export declare function _afterSwap(): void;
84
+ /** @internal Generated load: remember the loaded page module's `transition` export for the swap. */
85
+ export declare function _routeModule(module: unknown): void;
86
+ /** Navigation state accessor: idle unless `transitions` is on. Resumed regions reading it update in place. */
87
+ export declare function useNavigation(): () => NavigationState;
88
+ /** Delegated click handler: route same-origin links through the router (`modules`: only URLs a page route matches). */
89
+ export declare function interceptClick(event: MouseEvent, router: Navigator, modules?: ModuleTable): void;
90
+ /** Back/forward: the next settled route restores its saved position. */
91
+ export declare function notePopstate(event?: PopStateEvent): void;
92
+ /** Router `swap` of generated apps: the view transition when installed, then scroll and focus. */
93
+ export declare function swapRoute(apply: () => void, next: ParentNode): void;
94
+ /**
95
+ * @internal live.ts: a search-only navigation of a live page committed in place (no route render): the
96
+ * navigation in flight ends here, scroll and focus stay, `onNavigate` after-swap callbacks and waiters run.
97
+ */
98
+ export declare function _inPlace(): void;
99
+ /** `swapRoute` without the route announcer (generated apps of `rivetRouter({ announce: false })`). */
100
+ export declare function swapRouteQuiet(apply: () => void, next: ParentNode): void;
101
+ /**
102
+ * Router `hold` view of generated apps: on a resumed page's first client navigation the server
103
+ * rendered route content stays visible (inert) until the new route commits, instead of a blank region.
104
+ */
105
+ export declare function heldRoutes(level?: number): Node | null;
106
+ /** Warm a route's data on intent (pointer over / focus); `keep` as for `dataURL`. */
107
+ export declare function prefetchData(url: URL, source?: DataSource, keep?: string): void;
108
+ /**
109
+ * Page routes in match order: `[pattern, page importer]`. Rows whose importer is `_endpoint` are
110
+ * endpoints the server matches before a later dynamic page pattern that also fits them (generated).
111
+ */
112
+ export type ModuleTable = readonly (readonly [string, () => unknown])[];
113
+ /** @internal Generated `modules` row importer of an endpoint (its URLs load documents). */
114
+ export declare const _endpoint: () => void;
115
+ /** Import the page module of the route matching `url` (the import is shared with the render). */
116
+ export declare function loadModule(url: URL, modules: ModuleTable): Promise<unknown> | undefined;
117
+ /**
118
+ * Page loader of generated apps: import the page module and ready its lazy component (browser
119
+ * `lazyComponent(...).load`), so the route renders synchronously once loaded. Resolves the module.
120
+ */
121
+ export declare function preloadPage(component: unknown, importer: () => Promise<unknown>): Promise<unknown>;
122
+ /** Load the page chunk of the route matching `url` on intent; false when no page route matches (nothing to prefetch). */
123
+ export declare function prefetchModule(url: URL, modules: ModuleTable): boolean;
124
+ /** After a client-rendered route settles: restore or reset scroll, honour #hash, move focus, announce. */
125
+ export declare function settle(url: URL): void;
126
+ /**
127
+ * @internal Generated `App` of apps using `@rivetjs/forms` (codegen `forms`): every router handler (link click /
128
+ * intent, popstate, `rivet:go`) first installs the router under `Symbol.for("rivet.router")` — `clear` (drop warmed
129
+ * route data) and `go` (`navigate.ts` `_go`) — so forms reach it without importing this module (their chunks share
130
+ * no router code with the App). The first install dispatches `rivet:router` on the document (forms waiting for the
131
+ * router to boot). Assigned each call: a re-instantiated router module (dev HMR) replaces the old entry points.
132
+ */
133
+ export declare function _brand(go: typeof _go): void;
134
+ /** Drop warmed route data (form submits and `invalidate()` do; call it after other mutations). */
135
+ export declare function _clearPrefetch(): void;
136
+ /** Navigation flag: keep the scroll position. */
137
+ export declare const KEEP_SCROLL = 1,
138
+ /** Navigation flag: keep focus where it is. */
139
+ KEEP_FOCUS = 2;
140
+ /**
141
+ * @internal Generated `App`: start its route effects (nested level sync, `<Link active>` re-marking) once per
142
+ * router, from the first navigation entry point (link click, popstate, `rivet:go`) — not at load, so a resumed
143
+ * page loads no router code before a navigation (Z1). Each runs as an effect owned by the caller's owner.
144
+ */
145
+ export declare function _arm(router: object, ...effects: (() => void | (() => void))[]): void;
146
+ /**
147
+ * @internal Generated `App`: serve queued `navigate()` / `invalidate()` requests (`rivet:go` event).
148
+ * Server apps with layouts pass their layout state and table (`invalidate(key)` keeps loaders).
149
+ */
150
+ export declare function _serve(router: Navigator, state?: Layouts, table?: LayoutTable): void;
151
+ export { perform as _perform, dropPrefetch as _dropPrefetch };
152
+ declare function perform(router: Navigator, request: NavigateRequest, state?: Layouts, table?: LayoutTable): void;