@voltro/web 0.1.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.
@@ -0,0 +1,1077 @@
1
+ import { ComponentType } from 'react';
2
+ import { Context } from 'react';
3
+ import { ImgHTMLAttributes } from 'react';
4
+ import { MouseEvent as MouseEvent_2 } from 'react';
5
+ import { ReactElement } from 'react';
6
+ import { ReactNode } from 'react';
7
+ import { Rpc } from '@effect/rpc';
8
+ import { RpcGroup } from '@effect/rpc';
9
+
10
+ /** Decision outcome for a document-level anchor click. */
11
+ export declare type AnchorNavigationDecision = {
12
+ readonly kind: 'spa';
13
+ readonly to: string;
14
+ } | {
15
+ readonly kind: 'native';
16
+ };
17
+
18
+ /**
19
+ * Map of api name → resolved typed rpc client. Installed by the
20
+ * framework's mount() bootstrap. Consumers read it via useAppClient().
21
+ */
22
+ export declare type AppClients = ReadonlyMap<string, unknown>;
23
+
24
+ export declare const AppClientsContext: Context<AppClients | null>;
25
+
26
+ /** A navigation the blocker is holding back. `retry()` proceeds with the
27
+ * original navigation; `reset()` cancels it and clears the block. */
28
+ export declare interface BlockedNavigation {
29
+ /** The `to` argument of the held-back `navigate` call. */
30
+ readonly to: string;
31
+ /** The options of the held-back call (e.g. `{ replace: true }`). */
32
+ readonly opts?: NavigateOptions;
33
+ /** Proceed with the blocked navigation (bypasses the guard once). */
34
+ readonly retry: () => void;
35
+ /** Cancel the blocked navigation and return to the idle state. */
36
+ readonly reset: () => void;
37
+ }
38
+
39
+ /** A registered navigation guard. Returns `true` to BLOCK the pending
40
+ * navigation. `to`/`opts` describe where the user is trying to go. */
41
+ export declare type BlockerFn = (next: {
42
+ readonly to: string;
43
+ readonly opts?: NavigateOptions;
44
+ }) => boolean;
45
+
46
+ /** The state a `useBlocker` returns. `blocked` is `false` until a navigation
47
+ * is held back; when true, `retry()`/`reset()` proceed or cancel it. */
48
+ export declare type BlockerState = {
49
+ readonly blocked: false;
50
+ } | {
51
+ readonly blocked: true;
52
+ /** Where the user is trying to go. */
53
+ readonly to: string;
54
+ /** Proceed with the held-back navigation. */
55
+ readonly retry: () => void;
56
+ /** Cancel the held-back navigation. */
57
+ readonly reset: () => void;
58
+ };
59
+
60
+ /** A breadcrumb entry — the last one is rendered as the current page. */
61
+ export declare interface BlogBreadcrumb {
62
+ readonly label: string;
63
+ readonly href?: string;
64
+ }
65
+
66
+ /**
67
+ * The blog/changelog content shell. Centered max-width container with a
68
+ * sticky header (brand + top nav), optional breadcrumbs, and an optional
69
+ * footer.
70
+ */
71
+ export declare const BlogLayout: (props: BlogLayoutProps) => ReactNode;
72
+
73
+ export declare interface BlogLayoutProps {
74
+ readonly brand: ReactNode;
75
+ readonly topNav: ReadonlyArray<BlogNavItem>;
76
+ readonly children: ReactNode;
77
+ /** Active path for top-nav + breadcrumb highlighting. */
78
+ readonly pathname?: string;
79
+ /** Optional node pinned to the right of the header, after the nav — e.g. a
80
+ * language switcher or action buttons. */
81
+ readonly headerRight?: ReactNode;
82
+ /** Router link component (e.g. `PlainLink` from @voltro/web). */
83
+ readonly Link?: ComponentType<BlogLinkProps>;
84
+ readonly footer?: ReactNode;
85
+ readonly breadcrumbs?: ReadonlyArray<BlogBreadcrumb>;
86
+ }
87
+
88
+ /** Minimal shape a link component must satisfy (matches PlainLinkProps). */
89
+ export declare interface BlogLinkProps {
90
+ readonly to: string;
91
+ readonly children: ReactNode;
92
+ readonly className?: string;
93
+ }
94
+
95
+ /** A top-nav entry. */
96
+ export declare interface BlogNavItem {
97
+ readonly label: string;
98
+ readonly href: string;
99
+ }
100
+
101
+ export declare interface BrowserConsoleBridge {
102
+ /** Restore `console.*`, flush pending entries one last time. */
103
+ readonly dispose: () => void;
104
+ }
105
+
106
+ export declare interface BrowserConsoleBridgeOptions {
107
+ /** URL the CLI mounts `/_voltro/inspect/clientLog` on. Pass the
108
+ * same origin the page is loaded from in the common case
109
+ * (`window.location.origin`); the CLI's webDev middleware accepts
110
+ * it without CORS preflight. */
111
+ readonly baseUrl: string;
112
+ /** Voltro app name (the `name:` from `app.config.ts`). Carried in
113
+ * every batch so multi-app dev setups can attribute log lines. */
114
+ readonly appName: string;
115
+ /** Override flush interval (default 400ms). Mainly for tests. */
116
+ readonly flushAfterMs?: number;
117
+ }
118
+
119
+ /**
120
+ * Structured result of running a route's loaders: the page (leaf) loader's
121
+ * data plus each chain segment's loader data, keyed by segment index.
122
+ */
123
+ export declare interface ChainLoaderData {
124
+ readonly page: unknown;
125
+ readonly segments: Readonly<Record<number, unknown>>;
126
+ }
127
+
128
+ declare interface CompiledRoute extends PageDescriptor {
129
+ readonly regex: RegExp;
130
+ /** Names of capture groups, in match order. Catch-all params capture
131
+ * a `/`-joined string of the remaining path segments. */
132
+ readonly paramNames: ReadonlyArray<string>;
133
+ /** Sort priority — lower wins. Static segments rank above dynamic,
134
+ * dynamic above catch-all. Ensures `/users/me` beats `/users/[id]` and
135
+ * both beat `/users/[...rest]`. */
136
+ readonly priority: number;
137
+ }
138
+
139
+ export declare const compileRoute: (route: PageDescriptor) => CompiledRoute;
140
+
141
+ /** The English defaults. A consumer overrides any subtree via
142
+ * {@link FallbackStringsProvider} or a per-component `strings` prop;
143
+ * unspecified keys fall through to these. */
144
+ export declare const defaultFallbackStrings: FallbackStrings;
145
+
146
+ export declare interface DevStatus {
147
+ /** Stable id; re-pushing the same id replaces the entry (lets a
148
+ * caller update its label without dropping + re-creating). */
149
+ readonly id: string;
150
+ readonly kind: DevStatusKind;
151
+ /** Short label rendered inside the pill, e.g. "Compiling…". Kept
152
+ * under ~24 chars so the pill stays visually compact. */
153
+ readonly label: string;
154
+ }
155
+
156
+ export declare type DevStatusKind = 'compiling' | 'loading' | 'reconnecting' | 'error';
157
+
158
+ export declare interface ErrorBoundaryProps {
159
+ readonly error: unknown;
160
+ readonly reset: () => void;
161
+ }
162
+
163
+ declare const EXTERNAL_URL_BRAND: unique symbol;
164
+
165
+ /**
166
+ * Escape-hatch for any URL the codegen can't model: cross-origin
167
+ * (`https://example.com`), `mailto:`, `tel:`, hash-only (`#section`),
168
+ * or a sibling-app route the workspace scanner missed.
169
+ *
170
+ * The wrapper is a no-op at runtime — the brand exists purely for
171
+ * compile-time `<Link to=…>` checks. The point is to force a deliberate
172
+ * choice at the call-site instead of letting any string slip past.
173
+ */
174
+ export declare const externalUrl: (url: string) => VoltroExternalUrl;
175
+
176
+ /** Every user-facing string the shipped fallback chrome renders. Scalars are
177
+ * literals; anything that interpolates a value is a function so a locale can
178
+ * reorder. English defaults live in {@link defaultFallbackStrings}. */
179
+ export declare interface FallbackStrings {
180
+ /** <DefaultErrorFallback> — the runtime-error diagnostic card. */
181
+ readonly error: {
182
+ /** The muted brand tag at the top-right of the card. */
183
+ readonly brandTag: string;
184
+ /** The collapsible stack-trace disclosure summary. */
185
+ readonly stackTrace: string;
186
+ /** Primary action — in-place ErrorBoundary reset. */
187
+ readonly retry: string;
188
+ /** Secondary action — hard `window.location.reload()`. */
189
+ readonly reload: string;
190
+ /** Copy-to-clipboard button, idle label. */
191
+ readonly copy: string;
192
+ /** Copy button label after a successful clipboard write. */
193
+ readonly copied: string;
194
+ /** Copy button label after BOTH clipboard paths failed (points at the
195
+ * revealed manual-select block). */
196
+ readonly copyFailed: string;
197
+ /** The footer hint's bold heading. */
198
+ readonly serverContextHeading: string;
199
+ /** The footer hint prose. `command` is the pre-formatted `<code>` element
200
+ * for `voltro logs --since 30s` — a locale reorders the sentence around
201
+ * it but never translates the command itself. */
202
+ readonly serverContextHint: (command: ReactNode) => ReactNode;
203
+ };
204
+ /** <DefaultNotFound> — the route-miss (404) card. */
205
+ readonly notFound: {
206
+ /** The pill tag at the top of the card. */
207
+ readonly badge: string;
208
+ /** The headline. */
209
+ readonly heading: string;
210
+ /** The body prose. `path` is the current pathname `<code>`, `pagesDir` the
211
+ * `src/pages/` `<code>` — a locale reorders the sentence around both. */
212
+ readonly body: (path: ReactNode, pagesDir: ReactNode) => ReactNode;
213
+ };
214
+ }
215
+
216
+ /** Provide localized (or otherwise overridden) fallback strings to the shipped
217
+ * default ErrorBoundary / NotFound chrome below. Overrides are deep-merged onto
218
+ * the English defaults — supply only the sections/keys you change. Nesting
219
+ * providers merges onto the parent. */
220
+ export declare function FallbackStringsProvider(props: {
221
+ readonly strings: PartialFallbackStrings;
222
+ readonly children: ReactNode;
223
+ }): ReactNode;
224
+
225
+ /**
226
+ * Pick the not-found descriptor whose prefix is the longest match for
227
+ * `pathname`. `''` (root) always matches as a last resort. Returns null
228
+ * only if there are no descriptors at all.
229
+ */
230
+ export declare const findNotFound: (notFounds: ReadonlyArray<NotFoundDescriptor>, pathname: string) => NotFoundDescriptor | null;
231
+
232
+ /** Browser-style printf substitution over a console call's args. Exported
233
+ * for direct unit coverage; the bridge below is its only runtime caller. */
234
+ export declare const formatPrintf: (args: ReadonlyArray<unknown>) => FormattedCall;
235
+
236
+ declare interface FormattedCall {
237
+ readonly message: string;
238
+ readonly rest: ReadonlyArray<unknown>;
239
+ }
240
+
241
+ /**
242
+ * Look up a registered island Component by name. Returns undefined if
243
+ * the name isn't registered (typically means the user forgot to import
244
+ * the island file in this bundle).
245
+ */
246
+ export declare const getIslandComponent: (name: string) => ComponentType<unknown> | undefined;
247
+
248
+ /** Read the latest snapshot. Returns a frozen-ish reference safe to
249
+ * use as a `useSyncExternalStore` getSnapshot result. */
250
+ export declare const getRouteSnapshot: () => RouteSnapshot;
251
+
252
+ /** Read the current set of statuses. Returns a STABLE reference —
253
+ * same array until the next mutation, so the result is safe to use
254
+ * as a `useSyncExternalStore` snapshot. */
255
+ export declare const getStatuses: () => ReadonlyArray<DevStatus>;
256
+
257
+ /**
258
+ * Client-side runtime: scan the document for `[data-voltro-island]`
259
+ * markers and schedule each for hydration per its strategy. Called once
260
+ * at mount time by `@voltro/web/mount` when the page declares
261
+ * `interactive: 'islands'`. Idempotent — running twice is a no-op (we
262
+ * mark elements as visited).
263
+ */
264
+ export declare const hydrateIslandsOnPage: () => void;
265
+
266
+ export declare type HydrateStrategy =
267
+ /** Hydrate as soon as the client runtime mounts (after main script load). */
268
+ 'load'
269
+ /** Hydrate when the browser is idle (via `requestIdleCallback`, with a
270
+ * setTimeout fallback for browsers that lack it). */
271
+ | 'idle'
272
+ /** Hydrate when the element scrolls into the viewport (IntersectionObserver). */
273
+ | 'visible'
274
+ /** Hydrate on the first pointer / keyboard interaction with the element. */
275
+ | 'interaction'
276
+ /** Never hydrate. Useful for fully-static islands (e.g. SSR-only data
277
+ * display that never changes). */
278
+ | 'never';
279
+
280
+ declare const Image_2: ({ src, alt, width, height, fill, sizes, priority, loader, placeholder, blurDataURL, style, ...rest }: ImageProps) => ReactElement;
281
+ export { Image_2 as Image }
282
+
283
+ /** App-level default loader for every `<Image>` below it. A per-image
284
+ * `loader` prop overrides this. */
285
+ export declare const ImageConfigProvider: ({ loader, children, }: {
286
+ readonly loader: ImageLoader;
287
+ readonly children: ReactNode;
288
+ }) => ReactElement;
289
+
290
+ /** Maps a logical src + a target pixel width to a concrete URL. The hook
291
+ * for on-the-fly resizing — e.g. `({src,width}) => \`${src}?w=${width}\``
292
+ * against an image CDN or the storage serve endpoint. */
293
+ export declare type ImageLoader = (params: {
294
+ readonly src: string;
295
+ readonly width: number;
296
+ }) => string;
297
+
298
+ export declare interface ImageProps extends Omit<ImgHTMLAttributes<HTMLImageElement>, 'src' | 'width' | 'height' | 'loading' | 'srcSet'> {
299
+ readonly src: string;
300
+ /** Required — accessibility. Use `alt=""` for purely decorative images. */
301
+ readonly alt: string;
302
+ /** Intrinsic width in px. Required unless `fill`. */
303
+ readonly width?: number;
304
+ /** Intrinsic height in px. Required unless `fill`. */
305
+ readonly height?: number;
306
+ /** Absolutely fill the nearest positioned ancestor (object-fit: cover).
307
+ * Use instead of width/height when the container sizes the image. */
308
+ readonly fill?: boolean;
309
+ /** `sizes` media hint, e.g. `(max-width:768px) 100vw, 50vw`. Defaults to
310
+ * `100vw` under `fill`. */
311
+ readonly sizes?: string;
312
+ /** Above-the-fold / LCP image: eager-load + high fetch priority. */
313
+ readonly priority?: boolean;
314
+ /** Per-image URL loader (overrides the ImageConfigProvider default). */
315
+ readonly loader?: ImageLoader;
316
+ /** `'blur'` paints `blurDataURL` behind the image until it loads. */
317
+ readonly placeholder?: 'blur' | 'empty';
318
+ readonly blurDataURL?: string;
319
+ }
320
+
321
+ export declare const installBrowserConsoleBridge: (options: BrowserConsoleBridgeOptions) => BrowserConsoleBridge;
322
+
323
+ export declare const installServerLogRelay: (options: ServerLogRelayOptions) => ServerLogRelay;
324
+
325
+ /**
326
+ * How the client-side JS hydrates a server-rendered page.
327
+ *
328
+ * - 'full' — Hydrate the entire page tree as one React root.
329
+ * Default for `'spa'` pages and the safe default for
330
+ * `'static'` pages that haven't been thought through.
331
+ * Subscriptions + interactivity work everywhere.
332
+ * - 'islands' — Skip the full-tree hydration. The client runtime
333
+ * only hydrates `<div data-voltro-island>` markers
334
+ * emitted by `island()`. Other parts of the page stay
335
+ * pure static HTML with no React lifecycle running.
336
+ * Best perf for content-heavy pages with isolated
337
+ * interactive zones.
338
+ *
339
+ * Defaults to `'full'` when not specified.
340
+ */
341
+ export declare type InteractiveMode = 'full' | 'islands' | 'none';
342
+
343
+ /**
344
+ * Wrap a Component as an island. The returned Component renders the
345
+ * inner content wrapped in a marker `<div data-voltro-island>` that
346
+ * carries the island's name + props + hydrate strategy. The same
347
+ * call also registers the Component under its name so the client
348
+ * runtime can find it when hydrating.
349
+ */
350
+ export declare const island: <P extends Record<string, unknown>>(Component: ComponentType<P>, options: IslandOptions) => ComponentType<P>;
351
+
352
+ export declare interface IslandOptions {
353
+ /** Stable id of this island. Must be unique within an app. The framework
354
+ * uses it to match the server-rendered marker with the client-side
355
+ * Component. */
356
+ readonly name: string;
357
+ /** When the client runtime should hydrate this island. Defaults to
358
+ * `visible` — matches Astro's default and is the best perf/UX balance. */
359
+ readonly hydrate?: HydrateStrategy;
360
+ }
361
+
362
+ /** Brand guard — true for any `NotFoundError`, even one minted by a
363
+ * duplicate class identity in another bundle. */
364
+ export declare const isNotFound: (e: unknown) => e is NotFoundError;
365
+
366
+ /** Brand guard — true for any `RedirectError`, even cross-bundle. */
367
+ export declare const isRedirect: (e: unknown) => e is RedirectError;
368
+
369
+ /** Lazy variant of `pageRoute`: takes a thunk that dynamically imports the page
370
+ * instead of an already-imported module. The chunk loads only when the route
371
+ * first matches — the initial bundle no longer pulls in every page. */
372
+ export declare const lazyPageRoute: (pattern: string, load: () => Promise<Record<string, unknown>>, extras?: {
373
+ readonly chain?: ReadonlyArray<RouteSegment>;
374
+ }) => PageDescriptor;
375
+
376
+ export declare const Link: ({ to, children, onClick, prefetch: prefetchProp, replace, onMouseEnter, onFocus, ...anchorProps }: LinkProps) => ReactNode;
377
+
378
+ export declare interface LinkProps extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'href' | 'onClick'> {
379
+ readonly to: VoltroUrl;
380
+ readonly children: ReactNode;
381
+ readonly onClick?: (event: MouseEvent_2<HTMLAnchorElement>) => void;
382
+ /** When set, pre-warm the destination's loader on hover/focus. */
383
+ readonly prefetch?: boolean;
384
+ /** Swap the current history entry instead of pushing a new one —
385
+ * mirror of `NavigateOptions.replace`. */
386
+ readonly replace?: boolean;
387
+ }
388
+
389
+ export declare class LoaderCache {
390
+ private readonly entries;
391
+ get(key: string): LoaderEntry | undefined;
392
+ /**
393
+ * Start a loader run for `key` if one isn't already in flight (or settled).
394
+ * Returns the entry — callers can wait on `.promise` for pending entries.
395
+ *
396
+ * `run` is invoked SYNCHRONOUSLY so callers (and tests) can observe its
397
+ * single-call semantics without first flushing a microtask. Sync throws
398
+ * are caught and surface as a rejected entry just like async rejections.
399
+ */
400
+ start<T>(key: string, run: (signal: AbortSignal) => Promise<T> | T): LoaderEntry<T>;
401
+ /** Abort a pending loader; preserves settled (success/error) entries. */
402
+ abort(key: string): void;
403
+ /** Drop entries matching `pattern` (any params). */
404
+ invalidate(pattern: string): void;
405
+ /** Drop every entry. Test-only escape hatch. */
406
+ clear(): void;
407
+ }
408
+
409
+ export declare const loaderCacheKey: (pattern: string, params: Readonly<Record<string, string>>) => string;
410
+
411
+ export declare interface LoaderContext {
412
+ readonly params: Readonly<Record<string, string>>;
413
+ readonly pathname: string;
414
+ /** Aborted when the user navigates away before the loader resolves. */
415
+ readonly signal: AbortSignal;
416
+ /** Request headers when the loader runs server-side via `voltro
417
+ * start`. Lowercased keys. Empty `{}` for client-side loader
418
+ * invocations (browser-fetch goes through the rpc layer, not the
419
+ * loader). Use this for tenant resolution, auth headers, etc.
420
+ * until the auth slice ships a typed Subject. */
421
+ readonly headers?: Readonly<Record<string, string>>;
422
+ /** Server-side one-shot rpc fetch. Invokes any backend rpc (queries
423
+ * included — the FIRST snapshot of a streaming query is resolved and
424
+ * returned) over the api's HTTP rpc surface (`POST /rpc`), forwarding
425
+ * the request's `cookie` header so the api resolves the same Subject +
426
+ * tenant the WS path would. Bound to the app's single / first api.
427
+ *
428
+ * Present ONLY when the loader runs server-side (`voltro start` /
429
+ * `voltro dev` SSR). `undefined` for client-side loader invocations —
430
+ * in the browser, use `useSubscription` in the component for live data
431
+ * instead; the loader's `query` is for SSR first-paint + `meta`. */
432
+ readonly query?: <T = unknown>(tag: string, input?: Record<string, unknown>) => Promise<T>;
433
+ }
434
+
435
+ /* Excluded from this release type: LoaderDataContext */
436
+
437
+ declare type LoaderEntry<T = unknown> = {
438
+ readonly status: 'pending';
439
+ readonly promise: Promise<void>;
440
+ readonly controller: AbortController;
441
+ } | {
442
+ readonly status: 'success';
443
+ readonly data: T;
444
+ } | {
445
+ readonly status: 'error';
446
+ readonly error: unknown;
447
+ };
448
+
449
+ export declare type LoaderFn<T = unknown> = (ctx: LoaderContext) => Promise<T> | T;
450
+
451
+ export declare const matchRoute: (compiled: ReadonlyArray<CompiledRoute>, pathname: string) => RouteMatch | null;
452
+
453
+ /**
454
+ * Boot the framework's React stack against the given app. Resolves the
455
+ * typed rpc client for each api in parallel, renders the user's component
456
+ * tree inside the framework runtime + clients providers, and in dev mode
457
+ * auto-recovers each client in-place when its dev server restarts.
458
+ */
459
+ export declare const mount: (App: ComponentType, options: MountOptions) => void;
460
+
461
+ export declare interface MountApiSpec<Rpcs extends Rpc.Any = Rpc.Any> {
462
+ /** The RpcGroup this api speaks. */
463
+ readonly group: RpcGroup.RpcGroup<Rpcs>;
464
+ /** Per-rpc-tag descriptor metadata: `{ kind, source?, targets? }`. The
465
+ * framework's auto-optimistic flow reads this to know which mutation
466
+ * affects which cached query. The CLI's codegen emits it as
467
+ * `appDescriptors` next to `appGroup`. */
468
+ readonly descriptors?: Readonly<Record<string, {
469
+ readonly kind: 'query' | 'mutation' | 'action' | 'stream' | 'workflow';
470
+ readonly source?: string;
471
+ readonly targets?: ReadonlyArray<{
472
+ readonly table: string;
473
+ readonly op: 'insert' | 'update' | 'delete';
474
+ readonly order?: 'prepend' | 'append';
475
+ }>;
476
+ }>>;
477
+ /** Explicit WebSocket URL for this api. Required for external apis
478
+ * (where there's no Vite proxy). Defaults to same-origin `/ws/<name>`
479
+ * for workspace apis served via the framework's dev proxy. */
480
+ readonly wsUrl?: string;
481
+ /** Auth headers sent with EVERY rpc request over the socket — this is how
482
+ * a cross-origin api authenticates WS subscriptions. They ride in the
483
+ * @effect/rpc message frame, NOT the WS handshake (a browser can't set
484
+ * upgrade headers). Pass a thunk to fetch a rotating token fresh on every
485
+ * (re)connect, e.g. `headers: async () => ({ authorization: 'Bearer ' +
486
+ * (await supabase.auth.getSession()).data.session?.access_token })`; a
487
+ * static object is also accepted. Do NOT hardcode a secret literal — it
488
+ * ships to the client and is visible in source; resolve it at runtime. */
489
+ readonly headers?: ResolvableHeaders;
490
+ }
491
+
492
+ export declare interface MountOptions {
493
+ /** Map of api name → spec. The name is the lookup key for hooks
494
+ * (`useAppClient<T>(name)`, `useSubscription(name, ...)`, etc.). */
495
+ readonly apis: Record<string, MountApiSpec>;
496
+ /** Override the root element id. Defaults to 'root'. */
497
+ readonly rootId?: string;
498
+ /** Optional in-page devtools overlay component. Wired up by the
499
+ * CLI's generated `main.tsx` when `import.meta.env.DEV` is truthy
500
+ * and the app hasn't set `disableDevtools` in app.config.ts.
501
+ * Renders INSIDE the FrameworkBoot tree so its hooks
502
+ * (useFrameworkRuntimes, useLoaderData, …) resolve normally.
503
+ * PascalCase because it is a React component reference rendered
504
+ * as <Devtools/>. */
505
+ readonly Devtools?: ComponentType;
506
+ }
507
+
508
+ /** Options for an imperative navigation. `replace` swaps the current
509
+ * history entry instead of pushing a new one — what a loader redirect
510
+ * wants so Back doesn't bounce the user onto the page that redirected. */
511
+ export declare interface NavigateOptions {
512
+ readonly replace?: boolean;
513
+ /** Set to `false` to preserve the current scroll position. Defaults to true. */
514
+ readonly scroll?: boolean;
515
+ }
516
+
517
+ export declare const NavigationIndicator: () => ReactNode;
518
+
519
+ /** Construct-and-throw sugar for `NotFoundError`. Typed `: never` so
520
+ * control-flow narrows at the call site (`const x = row ?? notFound()`). */
521
+ export declare const notFound: (detail?: string) => never;
522
+
523
+ /**
524
+ * Stand-alone descriptor for URL prefixes that have no concrete page but
525
+ * SHOULD respond to unmatched subpaths with a scoped `not-found.tsx`. The
526
+ * router picks the longest-prefix match.
527
+ */
528
+ export declare interface NotFoundDescriptor {
529
+ /** Path prefix this not-found is responsible for. `''` = root. */
530
+ readonly prefix: string;
531
+ readonly Component: ComponentType;
532
+ readonly chain?: ReadonlyArray<RouteSegment> | undefined;
533
+ }
534
+
535
+ /** Thrown from a loader to render the scoped `not-found.tsx` subtree
536
+ * (client nav) / emit a 404 (SSR / SSG). */
537
+ export declare class NotFoundError extends Error {
538
+ readonly _voltroControl: "not-found";
539
+ constructor(detail?: string);
540
+ }
541
+
542
+ export declare interface PageDescriptor<TLoaderData = unknown> {
543
+ /** URL pattern, e.g. `/`, `/about`, `/users/[id]`, `/docs/[...slug]`. */
544
+ readonly pattern: string;
545
+ /** The page component. Present on eager routes; on a LAZY route (see
546
+ * `load`) it's filled by the Router once the page chunk has loaded. */
547
+ readonly Component?: ComponentType | undefined;
548
+ /** LAZY route: a thunk that dynamically imports the page module. When set,
549
+ * the page chunk is fetched only when this route first matches, so the
550
+ * initial bundle never imports every page. The Router resolves
551
+ * `Component` / `loader` / `meta` / … from the loaded module; the layout
552
+ * `chain` stays eager. */
553
+ readonly load?: (() => Promise<Record<string, unknown>>) | undefined;
554
+ /** Static meta, or a function of `{ params, loaderData, locale }` —
555
+ * so a document title can read what the page loader fetched (the
556
+ * dynamic metadata case) AND can localise per-locale at SSG time
557
+ * for URL-prefix i18n routing. `loaderData` is the page loader's
558
+ * result; `locale` is the active i18n locale during pre-render
559
+ * (driven by `params.locale` for `[locale]/...` routes, falling
560
+ * back to the app's defaultLocale). On the client, `locale` is
561
+ * the URL-derived locale when the route is locale-prefixed,
562
+ * otherwise the framework's resolved locale (cookie / Accept-
563
+ * Language / default). */
564
+ readonly meta?: PageMeta | ((ctx: {
565
+ readonly params: Readonly<Record<string, string>>;
566
+ readonly loaderData: unknown;
567
+ readonly locale: string;
568
+ }) => PageMeta) | undefined;
569
+ /** Async data preload; result available via useLoaderData<T>(). */
570
+ readonly loader?: LoaderFn<TLoaderData> | undefined;
571
+ /** Catches render + loader errors for THIS leaf. Tighter scope than `chain[*].Error`. */
572
+ readonly ErrorBoundary?: ComponentType<ErrorBoundaryProps> | undefined;
573
+ /** Shown while the loader is in flight (first navigation to the route). */
574
+ readonly Pending?: ComponentType | undefined;
575
+ /**
576
+ * Outer-to-inner layer chain. Each segment maps to one directory level
577
+ * (or route group) on the way from the pages root down to this leaf.
578
+ * Codegen produces this from the discovery walk; user code rarely
579
+ * writes it by hand.
580
+ */
581
+ readonly chain?: ReadonlyArray<RouteSegment> | undefined;
582
+ /** How the page's HTML is produced. Defaults to 'static' so pages
583
+ * pre-render by default — SEO + first-paint speed are wins users
584
+ * pay nothing for. Opt out with `'spa'` for pages that need a
585
+ * per-request render. */
586
+ readonly renderMode?: RenderMode | undefined;
587
+ /** How the page's client-side JS hydrates. Defaults to `'full'`
588
+ * (whole tree). Pages designed around the islands pattern should
589
+ * set this to `'islands'` so only marked interactive zones
590
+ * hydrate; the rest stays pure static HTML. */
591
+ readonly interactive?: InteractiveMode | undefined;
592
+ }
593
+
594
+ export declare interface PageMeta {
595
+ readonly title?: string;
596
+ readonly description?: string;
597
+ /** Canonical URL for this page. Emitted as `<link rel="canonical">`.
598
+ * Relative paths are accepted — search engines resolve them
599
+ * against the document's base URL. Use this on duplicated routes
600
+ * (locale variants, alternate URL forms) to declare the preferred
601
+ * one indexable URL. */
602
+ readonly canonical?: string;
603
+ /** Arbitrary additional meta tags. `name` OR `property` is required. */
604
+ readonly tags?: ReadonlyArray<{
605
+ readonly name?: string;
606
+ readonly property?: string;
607
+ readonly content: string;
608
+ }>;
609
+ /** Arbitrary additional `<link>` tags. Use for `alternate` hreflang,
610
+ * prev/next pagination, RSS feeds, manifest, etc. (For the common
611
+ * canonical case, prefer the dedicated `canonical` field above.) */
612
+ readonly links?: ReadonlyArray<{
613
+ readonly rel: string;
614
+ readonly href: string;
615
+ readonly hreflang?: string;
616
+ readonly type?: string;
617
+ readonly title?: string;
618
+ }>;
619
+ /** JSON-LD structured-data payloads. Each entry is emitted as a
620
+ * separate `<script type="application/ld+json">` so search engines
621
+ * and LLM crawlers can pick up rich metadata (Article, Product,
622
+ * SoftwareApplication, BreadcrumbList, FAQPage, etc.). Anything
623
+ * JSON-serialisable is accepted; `@context` + `@type` are
624
+ * authored, not synthesised. */
625
+ readonly jsonLd?: ReadonlyArray<Record<string, unknown>>;
626
+ }
627
+
628
+ export declare const pageRoute: (pattern: string, mod: Record<string, unknown>, extras?: {
629
+ readonly chain?: ReadonlyArray<RouteSegment>;
630
+ }) => PageDescriptor;
631
+
632
+ export declare const parseCookieHeader: (raw: string | undefined) => Record<string, string>;
633
+
634
+ /** A caller may override any subtree, not the whole object — deep-partial per
635
+ * section (each section is a flat bag of literals/functions, so a shallow
636
+ * per-section merge is exact). */
637
+ export declare type PartialFallbackStrings = {
638
+ readonly [K in keyof FallbackStrings]?: Partial<FallbackStrings[K]>;
639
+ };
640
+
641
+ /** Default: no resizing — every candidate width resolves to the same URL.
642
+ * Still emits a (degenerate) srcSet so swapping in a real loader is a
643
+ * one-line change with no call-site churn. */
644
+ export declare const passthroughImageLoader: ImageLoader;
645
+
646
+ export declare const PlainLink: (props: PlainLinkProps) => ReactNode;
647
+
648
+ export declare interface PlainLinkProps {
649
+ readonly to: string;
650
+ readonly children: ReactNode;
651
+ readonly className?: string;
652
+ readonly style?: React.CSSProperties;
653
+ readonly onClick?: (event: MouseEvent_2<HTMLAnchorElement>) => void;
654
+ readonly prefetch?: boolean;
655
+ }
656
+
657
+ /**
658
+ * Preload the page module for the route matching `pathname`, when that route is
659
+ * lazy. `load()` fetches the chunk AND — via the codegen's lazy thunk — records
660
+ * the module in the app's `refs.pages` registry, so the NEXT `buildRoutes()`
661
+ * yields an EAGER route for it.
662
+ *
663
+ * The generated `main.tsx` awaits this for the current URL BEFORE `hydrateRoot`
664
+ * whenever it's hydrating pre-rendered HTML. Without it, the client's first
665
+ * render resolves a lazy leaf to `null` (its chunk hasn't loaded yet) while the
666
+ * SSG/SSR HTML rendered the full page — a `<main>`-content hydration mismatch
667
+ * (React #418) that regenerates the tree and shifts every `useId` beneath it.
668
+ * With the module preloaded, the first client render matches the server exactly.
669
+ *
670
+ * No-op for eager routes (already resolvable) or an unmatched path. A failed
671
+ * chunk load is swallowed here — it surfaces via the leaf error boundary when
672
+ * the route renders.
673
+ */
674
+ export declare const preloadRouteModule: (routes: ReadonlyArray<PageDescriptor>, pathname: string) => Promise<void>;
675
+
676
+ /** Publish a status. Returns the dispose handle — call it when the
677
+ * underlying work finishes. Safe to call dispose twice. */
678
+ export declare const pushStatus: (status: DevStatus) => (() => void);
679
+
680
+ export declare const ReconnectContext: Context<(() => void) | null>;
681
+
682
+ /** Construct-and-throw sugar for `RedirectError`. Typed `: never`. */
683
+ export declare const redirect: (location: string, opts?: {
684
+ readonly status?: 303 | 307 | 308;
685
+ }) => never;
686
+
687
+ /** Thrown from a loader to redirect: 3xx + `Location` on SSR, a
688
+ * client-side `navigate(..., { replace: true })` on the SPA path. */
689
+ export declare class RedirectError extends Error {
690
+ readonly _voltroControl: "redirect";
691
+ readonly location: string;
692
+ readonly status: 303 | 307 | 308;
693
+ constructor(location: string, opts?: {
694
+ readonly status?: 303 | 307 | 308;
695
+ });
696
+ }
697
+
698
+ export declare const registerClientTrace: (traceId: string) => void;
699
+
700
+ /**
701
+ * How a page's HTML is produced.
702
+ *
703
+ * - 'static' — Pre-rendered to flat HTML at build time. Default.
704
+ * Shipped as `dist/<route>/index.html`. JS bundle
705
+ * still loads to hydrate islands + handle SPA-style
706
+ * navigation, but the first paint is instant + SEO
707
+ * friendly. Loaders MUST be side-effect-free + must
708
+ * not require per-request context (subject, headers).
709
+ * - 'spa' — Client-only rendering. No HTML pre-render; the
710
+ * shipped HTML is a shell that mounts on the
711
+ * client. Useful for pages that genuinely need a
712
+ * fresh client render every load (most reactive
713
+ * dashboards).
714
+ *
715
+ * - 'ssr' — Rendered on every request, server-side, via `voltro
716
+ * start`. Loaders run per request with access to
717
+ * `headers` + `query` (the api HTTP rpc); the resolved
718
+ * HTML is sent fresh each time. Use for personalised /
719
+ * tenant-scoped first paint.
720
+ * - 'isr' — Like 'ssr' on the first request, then cached and
721
+ * revalidated in the background on a TTL.
722
+ */
723
+ export declare type RenderMode = 'static' | 'spa' | 'ssr' | 'isr';
724
+
725
+ /**
726
+ * Auth headers for an api's WS rpc client. @effect/rpc sends these in the
727
+ * per-request MESSAGE frame (NOT the WS upgrade — a browser can't set upgrade
728
+ * headers), so the server's AuthMiddleware sees them on every call; this is
729
+ * what lets a cross-origin api authenticate WS subscriptions. A thunk is
730
+ * resolved fresh on every (re)connect, so a rotating token (e.g. a Supabase
731
+ * access token) is pulled anew per connect instead of freezing at first mount.
732
+ */
733
+ declare type ResolvableHeaders = Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
734
+
735
+ /**
736
+ * Decide whether a click on (or inside) an anchor should be handled by the
737
+ * SPA router or left to the browser. Pure — no side effects, no
738
+ * `preventDefault`. The caller performs the navigation + preventDefault
739
+ * when the result is `'spa'`.
740
+ *
741
+ * Returns `'native'` (browser handles it) when ANY of:
742
+ * - the event was already handled (`defaultPrevented` — a `<Link>` ran)
743
+ * - it's not a plain left-click (middle/right click, any modifier key)
744
+ * - no enclosing `<a>`, or the anchor has no `href`
745
+ * - the anchor targets another browsing context (`target` ≠ `_self`)
746
+ * - the anchor is a download, `rel="external"`, or opts out (`data-no-spa`)
747
+ * - the resolved URL is cross-origin
748
+ * - the resolved URL is a pure in-page hash on the current page
749
+ *
750
+ * Otherwise returns `'spa'` with the path+search+hash to navigate to.
751
+ *
752
+ * `currentHref` is the document's current URL (`location.href`) — passed in
753
+ * so the function is deterministic and unit-testable.
754
+ */
755
+ export declare const resolveAnchorNavigation: (event: {
756
+ readonly defaultPrevented: boolean;
757
+ readonly button: number;
758
+ readonly metaKey: boolean;
759
+ readonly ctrlKey: boolean;
760
+ readonly shiftKey: boolean;
761
+ readonly altKey: boolean;
762
+ readonly target: EventTarget | null;
763
+ }, currentHref: string) => AnchorNavigationDecision;
764
+
765
+ export declare const resolveMeta: (meta: PageDescriptor["meta"], params: Readonly<Record<string, string>>, loaderData?: unknown, locale?: string) => PageMeta | null;
766
+
767
+ declare const ROUTE_URL_BRAND: unique symbol;
768
+
769
+ export declare interface RouteMatch {
770
+ readonly route: CompiledRoute;
771
+ readonly params: Readonly<Record<string, string>>;
772
+ }
773
+
774
+ export declare const Router: ({ routes, notFounds, notFound: NotFound, errorFallback: ErrorFallback, }: RouterProps) => ReactNode;
775
+
776
+ /* Excluded from this release type: RouterContext */
777
+
778
+ declare interface RouterContextValue {
779
+ readonly pathname: string;
780
+ /** `search + hash` of the current URL (e.g. `?tab=skills#x`). Tracked in
781
+ * state so query-param-only navigations (same pathname) still re-render
782
+ * consumers — `useSearchParams`/`useLocation` would otherwise go stale
783
+ * until an unrelated re-render. */
784
+ readonly search: string;
785
+ readonly navigate: (to: string, opts?: NavigateOptions) => void;
786
+ readonly params: Readonly<Record<string, string>>;
787
+ readonly prefetch: (to: string) => void;
788
+ /** Internal: loader data for the active match. */
789
+ readonly loaderData: unknown;
790
+ /** Internal: register a navigation guard; returns an unregister fn.
791
+ * Consumed by `useBlocker`. */
792
+ readonly registerBlocker: (id: symbol, fn: BlockerFn) => () => void;
793
+ /** Internal: the navigation currently held back by a blocker, if any.
794
+ * Consumed by `useBlocker` to surface `retry`/`reset` to the caller. */
795
+ readonly blocked: BlockedNavigation | null;
796
+ }
797
+
798
+ export declare interface RouterProps {
799
+ readonly routes: ReadonlyArray<PageDescriptor>;
800
+ /**
801
+ * Per-prefix not-found descriptors. Router picks the longest-prefix
802
+ * match when no concrete route hits. `notFound` (component) is the
803
+ * fallback for paths without any matching prefix.
804
+ */
805
+ readonly notFounds?: ReadonlyArray<NotFoundDescriptor>;
806
+ readonly notFound?: ComponentType;
807
+ /** Fallback ErrorBoundary used when neither the leaf nor its chain supplies one. */
808
+ readonly errorFallback?: ComponentType<ErrorBoundaryProps>;
809
+ }
810
+
811
+ /**
812
+ * One layer in a page's nesting chain. Each represents a directory level
813
+ * in the file-convention layout (or a route group).
814
+ *
815
+ * Layouts wrap their children — outer layers wrap inner ones. Errors are
816
+ * caught by the deepest layer with an `Error` component; if none, the
817
+ * error bubbles up the chain. NotFound applies when an URL is under this
818
+ * layer's scope but no concrete page matches.
819
+ *
820
+ * The chain persists across navigation within its scope — React preserves
821
+ * the layout component instances because their position in the tree is
822
+ * stable for any leaf within that subtree.
823
+ */
824
+ export declare interface RouteSegment {
825
+ /** Outer-vs-inner ordering label (debug only). */
826
+ readonly id?: string | undefined;
827
+ readonly Layout?: ComponentType<{
828
+ children: ReactNode;
829
+ }> | undefined;
830
+ readonly Error?: ComponentType<ErrorBoundaryProps> | undefined;
831
+ readonly Pending?: ComponentType | undefined;
832
+ readonly NotFound?: ComponentType | undefined;
833
+ /** Async data preload for THIS layout level. Runs in parallel with the
834
+ * page loader (and the other layouts') before mount; the result is
835
+ * reachable via `useLoaderData<T>()` from INSIDE this layout (each
836
+ * level sees its own loader's data). A `layout.tsx` exports it like a
837
+ * page does — codegen wires it onto the segment. Server-side it
838
+ * receives request `headers` (session/tenant resolution). */
839
+ readonly loader?: LoaderFn | undefined;
840
+ }
841
+
842
+ declare interface RouteSnapshot {
843
+ readonly pathname: string;
844
+ readonly params: Readonly<Record<string, string>>;
845
+ /** Loader-resolved data for the active route. `undefined` when the
846
+ * route has no loader OR the loader rejected. */
847
+ readonly loaderData: unknown;
848
+ }
849
+
850
+ /** The next search-params value: either the params object directly, or an
851
+ * updater that receives the CURRENT `URLSearchParams` and returns the next. */
852
+ export declare type SearchParamsInit = URLSearchParams | Readonly<Record<string, string>> | ((current: URLSearchParams) => URLSearchParams | Record<string, string>);
853
+
854
+ /**
855
+ * Cache key for a layout (chain segment) loader. Distinct from the page's
856
+ * key for the same (pattern, params) so a layout's data and the page's
857
+ * never collide. `index` is the segment's position in the outer→inner
858
+ * chain. Defined above `loaderCacheKey`'s body via the shared formatter.
859
+ */
860
+ export declare const segmentLoaderKey: (pattern: string, index: number, params: Readonly<Record<string, string>>) => string;
861
+
862
+ export declare interface ServerLogRelay {
863
+ readonly dispose: () => void;
864
+ }
865
+
866
+ export declare interface ServerLogRelayOptions {
867
+ /** HTTP(S) origin the CLI exposes the inspect stream on. */
868
+ readonly baseUrl: string;
869
+ /** Short label included in every emitted prefix — typically the api
870
+ * name ("cloud") or "web". Helps disambiguate multi-source streams. */
871
+ readonly originLabel: string;
872
+ }
873
+
874
+ export declare const ServerRequestContext: Context<ServerRequestContextValue | null>;
875
+
876
+ export declare interface ServerRequestContextValue {
877
+ readonly cookies: Readonly<Record<string, string>>;
878
+ readonly headers: Readonly<Record<string, string>>;
879
+ /** Raw request URL as it came off the wire (path + query). Useful
880
+ * for SSR pages that need to read `?q=…` style search params
881
+ * without touching anything client-only. Empty string for build-
882
+ * time SSG renders where there is no incoming request. */
883
+ readonly url: string;
884
+ }
885
+
886
+ export declare const ServerRequestProvider: ({ value, children, }: {
887
+ readonly value: ServerRequestContextValue;
888
+ readonly children: ReactNode;
889
+ }) => ReactNode;
890
+
891
+ /** Push a new route snapshot. Router calls this from its render
892
+ * effect; observers re-render on the next microtask. */
893
+ export declare const setRouteSnapshot: (next: RouteSnapshot) => void;
894
+
895
+ /** How a `useSetSearchParams` write should update history. Defaults to
896
+ * `replace` — a filter/tab tweak shouldn't stack a Back entry per keystroke. */
897
+ export declare interface SetSearchParamsOptions {
898
+ /** Push a new history entry instead of replacing the current one. */
899
+ readonly push?: boolean;
900
+ /** Set to `false` to preserve the current scroll position. Defaults to true. */
901
+ readonly scroll?: boolean;
902
+ }
903
+
904
+ /**
905
+ * Stable-sort compiled routes by ascending priority, so that more-specific
906
+ * routes (lower priority) match before less-specific ones. Static beats
907
+ * dynamic; dynamic beats catch-all. Within the same priority bucket,
908
+ * declaration order is preserved.
909
+ */
910
+ export declare const sortRoutesByPriority: (compiled: ReadonlyArray<CompiledRoute>) => ReadonlyArray<CompiledRoute>;
911
+
912
+ /** Subscribe to snapshot changes. Returns the unsubscribe function. */
913
+ export declare const subscribeRouteSnapshot: (cb: () => void) => (() => void);
914
+
915
+ /** Subscribe to changes. Returns the unsubscribe function. */
916
+ export declare const subscribeStatuses: (cb: () => void) => (() => void);
917
+
918
+ /** Subscribe to surfaced trace errors. Returns an unsubscribe fn. */
919
+ export declare const subscribeTraceErrors: (listener: TraceErrorListener) => () => void;
920
+
921
+ export declare interface TraceErrorEvent {
922
+ /** Trace id (32 hex) — the same id `voltro logs --trace <id>` accepts. */
923
+ readonly traceId: string;
924
+ /** Span that failed (e.g. `rpc.mutation`, `webhook/stripe`). */
925
+ readonly spanName: string;
926
+ /** Which api the failed span ran in (the relay's originLabel). */
927
+ readonly api: string;
928
+ /** Error message from the span status. */
929
+ readonly message: string;
930
+ /** When the overlay received it. */
931
+ readonly ts: number;
932
+ }
933
+
934
+ declare type TraceErrorListener = (event: TraceErrorEvent) => void;
935
+
936
+ /**
937
+ * Returns the typed rpc client mounted under `apiName`. Generic narrows
938
+ * the result to the caller's group; pass `typeof appGroup` from the api's
939
+ * generated rpcGroup module:
940
+ *
941
+ * import type { appGroup } from '@app/api/rpcGroup'
942
+ * import type { RpcClient, RpcGroup } from '@effect/rpc'
943
+ * type ApiClient = RpcClient.RpcClient<RpcGroup.Rpcs<typeof appGroup>>
944
+ *
945
+ * const client = useAppClient<ApiClient>('api')
946
+ * const { data } = useSubscription('api', () => client.todos.list({}), [])
947
+ *
948
+ * Throws if no api is mounted under `apiName` (typo, missing entry in
949
+ * app.config.ts, or app not mounted yet).
950
+ */
951
+ export declare const useAppClient: <Client>(apiName: string) => Client;
952
+
953
+ /**
954
+ * Block SPA navigations while `shouldBlock` is true — the unsaved-changes
955
+ * guard. When the user tries to leave (a `<Link>` click, an intercepted
956
+ * anchor, or an imperative `navigate`) and `shouldBlock` returns true, the
957
+ * navigation is HELD and this hook returns `{ blocked: true, retry, reset }`
958
+ * so you can render a confirm prompt: `retry()` proceeds, `reset()` stays.
959
+ * A full-page unload (tab close / reload) additionally triggers the browser's
960
+ * native `beforeunload` prompt while any blocker is active.
961
+ *
962
+ * ```tsx
963
+ * const blocker = useBlocker(form.isDirty)
964
+ * // …
965
+ * {blocker.blocked && (
966
+ * <ConfirmDialog
967
+ * message="Discard unsaved changes?"
968
+ * onConfirm={blocker.retry}
969
+ * onCancel={blocker.reset}
970
+ * />
971
+ * )}
972
+ * ```
973
+ *
974
+ * Pass a boolean or a predicate. A predicate sees the pending `{ to, opts }`
975
+ * so you can allow some destinations (e.g. don't block leaving to `/logout`).
976
+ */
977
+ export declare const useBlocker: (shouldBlock: boolean | BlockerFn) => BlockerState;
978
+
979
+ /** Read the active fallback strings. Returns the English defaults when no
980
+ * provider is mounted, so the chrome works with zero setup. A per-component
981
+ * `strings` prop is deep-merged on top of whatever this returns. */
982
+ export declare const useFallbackStrings: (override?: PartialFallbackStrings) => FallbackStrings;
983
+
984
+ /**
985
+ * Returns the loader data for the nearest level in the render tree: inside
986
+ * a `layout.tsx` it's that layout's loader result; inside the page it's
987
+ * the page loader's. Narrowed to the caller's type.
988
+ */
989
+ export declare const useLoaderData: <T>() => T;
990
+
991
+ export declare const useLocation: () => string;
992
+
993
+ export declare const useNavigate: () => RouterContextValue["navigate"];
994
+
995
+ export declare const useParams: <T extends Record<string, string> = Record<string, string>>() => T;
996
+
997
+ /** Imperatively pre-warm a route's loader. No-op if the route has no loader. */
998
+ export declare const usePrefetch: () => ((to: string) => void);
999
+
1000
+ export declare const useReconnect: () => (() => void);
1001
+
1002
+ /**
1003
+ * Read the request's URL search params as a standard `URLSearchParams`.
1004
+ *
1005
+ * Server-side (SSR / ISR) it parses the query off the request URL the
1006
+ * SSR pipeline captured — so a `renderMode: 'ssr'` page or layout can
1007
+ * read `?q=…` during `renderToString` with no client round-trip and
1008
+ * with the value already correct in the first paint. Client-side it
1009
+ * reads `window.location.search`. Both sides return the native
1010
+ * `URLSearchParams`, so call sites are identical:
1011
+ *
1012
+ * ```tsx
1013
+ * const params = useSearchParams()
1014
+ * const q = params.get('q') ?? ''
1015
+ * ```
1016
+ *
1017
+ * Resolves the params for the CURRENT render. SPA pages that must react
1018
+ * to router-pushed query changes without a reload should re-render via
1019
+ * the router (e.g. `useNavigate`/`useLocation`) — this hook then
1020
+ * re-resolves on that render.
1021
+ */
1022
+ export declare const useSearchParams: () => URLSearchParams;
1023
+
1024
+ export declare const useServerRequest: () => ServerRequestContextValue | null;
1025
+
1026
+ /**
1027
+ * The WRITE half of `useSearchParams` — returns a setter that updates the
1028
+ * query string on the current pathname via the router's `navigate`
1029
+ * (`navigate` + rebuilt `?…`), so the URL changes AND every router-context
1030
+ * consumer re-renders immediately (same path that `withQuery` links take).
1031
+ *
1032
+ * ```tsx
1033
+ * const params = useSearchParams() // read (SSR-aware)
1034
+ * const setParams = useSetSearchParams() // write
1035
+ * setParams({ tab: 'skills' }) // → ?tab=skills (replace)
1036
+ * setParams((p) => { p.set('page', '2'); return p }, { push: true })
1037
+ * ```
1038
+ *
1039
+ * Defaults to a history REPLACE (a filter tweak shouldn't stack Back entries);
1040
+ * pass `{ push: true }` for a distinct history entry. Client-only — during SSR
1041
+ * there is no history to write, so read `useSearchParams()` off the request URL
1042
+ * instead and mutate on the client after hydration.
1043
+ */
1044
+ export declare const useSetSearchParams: () => ((next: SearchParamsInit, opts?: SetSearchParamsOptions) => void);
1045
+
1046
+ /** A URL minted by `externalUrl()` — anchored, hash, or cross-origin. */
1047
+ export declare type VoltroExternalUrl = string & {
1048
+ readonly [EXTERNAL_URL_BRAND]: 'external';
1049
+ };
1050
+
1051
+ /** A URL minted by the app's generated `routes` builder. */
1052
+ export declare type VoltroRouteUrl = string & {
1053
+ readonly [ROUTE_URL_BRAND]: 'route';
1054
+ };
1055
+
1056
+ export declare type VoltroUrl = VoltroRouteUrl | VoltroExternalUrl;
1057
+
1058
+ export declare const WEB_NAME: "framework-web";
1059
+
1060
+ /** Append a `#hash` to a route URL. Preserves the brand. */
1061
+ export declare const withHash: (url: VoltroRouteUrl, hash: string) => VoltroRouteUrl;
1062
+
1063
+ /**
1064
+ * Append a query string to a route URL. Preserves the brand so the
1065
+ * result still flows through `<Link to=…>`. Pass `undefined` values
1066
+ * to omit a param entirely.
1067
+ *
1068
+ * withQuery(routes['/_/p/[orgSlug]/[projectSlug]']({…}), { env: 'prod' })
1069
+ * //→ '/_/p/acme/web?env=prod' (typed as VoltroRouteUrl)
1070
+ */
1071
+ export declare const withQuery: (url: VoltroRouteUrl, params: Readonly<Record<string, string | number | undefined>>) => VoltroRouteUrl;
1072
+
1073
+
1074
+ export * from "@voltro/client";
1075
+ export * from "@voltro/ui";
1076
+
1077
+ export { }