Score global de préparation IA
Résultat combiné de tous les signaux de l’audit.
Score global de préparation IA
Résultat combiné de tous les signaux de l’audit.
Évaluation globale de préparation IA
state-in-url (state-in-url.dev) a obtenu 71/100 lors de l’audit technique automatisé de préparation à l’IA. llms.txt était accessible, llms-full.txt avait aucun fichier accessible et ai.txt était disponible. L’analyse de robots.txt a trouvé 0 robots IA explicitement autorisés, 0 bloqués et 1 sitemap déclaré. La complétude du balisage de la page d’accueil atteint 0% ; aucun type Schema.org détecté. Balises OpenGraph détectées : 0. Les résultats correspondent aux réponses publiques observées le 2026-07-21T05:47:11.824Z.
L’audit combine les fichiers lisibles par les machines, les règles des robots, les sitemaps et le balisage de la page d’accueil. llms.txt est accessible et contient 2 702 jetons.
robots.txt est disponible ; robots IA bloqués : 0. Sitemaps déclarés : 1. Aucun type Schema.org détecté.
Profil Lighthouse mobile : performance 83/100, accessibilité 100/100, SEO 100/100.
Une mesure Lighthouse mobile. La catégorie expérimentale Agentic Browsing est présentée séparément et ne remplace pas le score global de LLMSMap.
Performance
Accessibilité
Bonnes pratiques
SEO technique
Agentic Browsing
La performance mobile est de 83/100 ; le plus grand contenu visible est apparu en 4.1 s et le thread principal a été bloqué pendant 220 ms. Le décalage de mise en page est de 0. Les tâches longues retardent les actions des utilisateurs et des agents de navigateur.
Accessibilité : 100/100, bonnes pratiques : 100/100, SEO technique : 100/100. La catégorie expérimentale Agentic Browsing atteint 100/100 et reste distincte du score global de LLMSMap.
Découpez les longues tâches JavaScript, différez les scripts et styles non critiques et réduisez les chaînes de requêtes bloquantes.
Supprimez le CSS et le JavaScript inutilisés, chargez les widgets lourds à la demande et limitez les scripts tiers.
Premier contenu
Contenu principal
Stabilité visuelle
Temps de blocage
Vitesse visuelle
Fichiers lisibles par les machines, règles des robots, découverte et balisage de la page d’accueil.
La version complète est introuvable
1 sitemap trouvé
Aucun balisage Schema.org trouvé sur la page d’accueil
Aucune balise OpenGraph trouvée sur la page d’accueil
D’après l’analyse de robots.txt
Parcours de découverte déclarés pour les robots et les agents.
# state-in-url
> A React hook library for storing typed, JSON-serializable state in URL query parameters. ~2 KB, zero runtime deps. Supports the Next.js App Router (14/15/16), React Router 6/7, Remix 2, Astro (React/Preact islands), and plain React. MIT licensed.
Last updated: 2026-08-31. Canonical: <https://state-in-url.dev/llms.txt>.
## For AI coding agents — preferred path
This package ships task-focused SKILL.md files via [@tanstack/intent](https://tanstack.com/intent/latest/docs/overview). If your agent supports Intent, that is the right surface to load instead of this file:
```bash
# in the user's project, once
npx @tanstack/intent@latest install
# list skills available for installed libraries
npx @tanstack/intent@latest list
# load a specific skill into the current context
npx @tanstack/intent@latest load state-in-url#feature-state-hook
```
Available skills (under `node_modules/state-in-url/skills/`):
| Skill | Type | When to load |
|---|---|---|
| `feature-state-hook` | core | Defining state and wrapping `useUrlState` in a feature-scoped custom hook |
| `input-handling` | core | Text inputs / sliders / fast-changing controls |
| `nextjs-ssr` | framework | Next.js App Router: `searchParams` forwarding, Proxy for layouts |
| `react-router-remix-setup` | framework | React Router v6/v7 or Remix v2 setup |
| `astro-setup` | framework | Astro: React/Preact islands with the `searchParams` prop, or no client framework via `encodeState`/`decodeState` |
| `form-library-integration` | composition | Pairing with `react-hook-form` (or formik) |
| `shared-state-no-url` | core | `useSharedState` — cross-component state without URL sync |
The rest of this file is a condensed reference for agents that cannot load Intent skills.
## Comparison with alternatives
Full page: <https://state-in-url.dev/vs/nuqs> (Markdown: /vs/nuqs.md). Sizes: whole-library import, esbuild minify + gzip, measured August 2026 (nuqs 2.10.1).
| Library | Setup | Nested objects and dates | Size | Pick it when |
|---|---|---|---|---|
| state-in-url | None - import the hook | Preserved automatically, types included | ~2.9 KB gzip, zero deps | One typed object, zero setup, on Next.js / React Router / Remix / Astro |
| nuqs | Adapter component, parser per key | JSON parser plus your own validator | ~6.7 KB gzip, one dep | Each value as its own readable query param |
| TanStack Router | validateSearch on each route | JSON-first; dates need custom serialization | Built into the router | You are on TanStack Router |
| use-query-params | Provider plus router adapter, param config per key | Via a JSON param type, loosely typed | ~4.4 KB gzip + serialize-query-params | A codebase already built on it |
| useSearchParams | None - built into the router | Strings only, everything by hand | 0 KB | One or two flat string params |
## Package info
- npm: https://www.npmjs.com/package/state-in-url
- repo: https://github.com/asmyshlyaev177/state-in-url
- website: https://state-in-url.dev
- full README: https://raw.githubusercontent.com/asmyshlyaev177/state-in-url/refs/heads/master/README.md
## Supported frameworks
| Framework | Versions | Import path |
|---|---|---|
| Next.js (App Router only) | 14 / 15 / 16 | `state-in-url/next` |
| React Router | v7 | `state-in-url/react-router` |
| React Router | v6 | `state-in-url/react-router6` |
| Remix | v2 | `state-in-url/remix` |
| Astro | React or Preact (compat) islands, on-demand rendered pages | `state-in-url/astro` |
| Framework-agnostic | — | `state-in-url` (`useSharedState`), `state-in-url/encodeState` |
Pages Router is **not** supported.
## Install
```bash
npm install state-in-url
```
In `tsconfig.json`, ensure `"moduleResolution": "Bundler"` (or `"Node16"` / `"NodeNext"`).
## Core rules — read first
1. **Type, never interface.** The hook's generic constraint `JSONCompatible<T>` rejects `interface`. Always declare a `type` AND annotate the const: `const FOO_STATE: FooState = { ... }`.
2. **Default-state object must be a module-scoped `const`.** Never built from props, hook returns, or destructuring inside a component. Sharing is keyed by object identity.
3. **One feature → one shared default-state const → one custom hook.** Components import the hook, never `useUrlState` directly with their own defaults object.
4. **No secrets in URL.** Entity IDs (`jobId`, `memberId`) are fine; tokens, API keys, PII are not.
5. **JSON-serializable only.** Functions, BigInt, Symbol, Map, Set, class instances will not round-trip. Dates are supported.
6. **URL size**: keep total query-string under ~12 KB to stay safe across CDNs (Vercel header limit is 14 KB).
## API: `useUrlState`
```typescript
const { urlState, setState, setUrl, reset } = useUrlState(DEFAULT_STATE, options?);
```
- `urlState` — current state, typed identically to `DEFAULT_STATE`.
- `setState(value)` — updates internal state synchronously; **does not touch URL**.
- `setUrl(value, opts?)` — updates state + URL. URL write is throttled (next tick).
- `reset(opts?)` — sets state and URL back to `DEFAULT_STATE`.
Setter call signatures (both `setState` and `setUrl`):
```typescript
setUrl({ field: 'newValue' }); // partial patch
setUrl(curr => ({ ...curr, field: 'newValue' })); // functional with current
setUrl((curr, initial) => initial); // reset via callback
setUrl(); // flush current state to URL
```
`options` (per-call or as hook-level defaults):
- `replace?: boolean` — `router.replace` (default `true`) vs `router.push`.
- `scroll?: boolean` — Next.js scroll behavior (default `false`).
- React Router / Remix: any `NavigateOptions` (e.g. `preventScrollReset`).
Hook-level options (second arg to `useUrlState`):
- `searchParams` — pass `searchParams` from a Next.js server component. **Required for SSR correctness in Next.js App Router.** `useSearchParams()` is a fallback for components the prop cannot reach, and costs prerendering; see below.
- `useHistory?: boolean` — Next.js only. Default `true`. Uses `window.history.pushState` to avoid `_rsc` server round-trips on URL changes. Flip to `false` only when server data must refetch on URL change.
## Recommended pattern: feature-scoped hook
```typescript
// features/jobs/jobsState.ts
export type JobsState = {
status: '' | 'active' | 'closed';
tab: 'details' | 'qa' | 'applicants';
jobId: string;
};
export const JOBS_STATE: JobsState = {
status: '',
tab: 'details',
jobId: '',
};
```
```typescript
// features/jobs/useJobsState.ts
'use client';
import { useUrlState } from 'state-in-url/next';
import { JOBS_STATE } from './jobsState';
// `searchParams` comes from the server component at the top of the feature.
// Nested callers pass nothing and share the same store.
export function useJobsState(searchParams?: object) {
return useUrlState(JOBS_STATE, { searchParams });
}
```
Any component calling `useJobsState()` shares the same URL-synced store. No Context, no Provider.
Do not call `useSearchParams()` to feed the hook. It needs a `<Suspense>` boundary, opts the page out of prerendering, and buys nothing the server prop does not — on the client the hook already reads `window.location.search`. Thread `searchParams` from the server component. Reach for `useSearchParams()` only when a component genuinely cannot receive it, and accept the bailout.
## Next.js App Router — server page forwarding `searchParams`
In **Next.js 15+**, `searchParams` is a `Promise`:
```typescript
// app/jobs/page.tsx (Server Component)
import { JobsList } from './JobsList';
export default async function Page({
searchParams,
}: {
searchParams: Promise<Record<string, string | string[] | undefined>>;
}) {
const sp = await searchParams;
return <JobsList searchParams={sp} />;
}
// app/jobs/JobsList.tsx
'use client';
import { useUrlState } from 'state-in-url/next';
import { JOBS_STATE } from 'features/jobs/jobsState';
export function JobsList({ searchParams }: { searchParams: object }) {
const { urlState, setUrl } = useUrlState(JOBS_STATE, { searchParams });
// ...
}
```
Without `searchParams`, the first render uses defaults, then a client effect re-syncs from the URL on the next tick — visible flash plus hydration warning.
The hook does not call `useSearchParams` itself, so a component using it needs no `<Suspense>` boundary and does not opt its page out of prerendering — PPR and `cacheComponents: true` included. Initial state comes from `searchParams` on the server and `window.location.search` on the client; later changes are tracked through the History API, which also catches a bare `history.pushState` from unrelated code. A prerendered page still renders defaults, since there is no query string at build time — render dynamically when a shared stateful link must be correct on first paint.
## Next.js App Router — server layout (Proxy workaround)
Server layouts don't receive `searchParams`. Expose the query string via a Proxy header (Next.js 16+; `middleware.ts` still works as a deprecated alias):
```typescript
// proxy.ts
import type { NextRequest } from 'next/server';
import { NextResponse } from 'next/server';
export function proxy(request: NextRequest) {
const sp = (request.url.includes('_next') ? '' : request.url).split('?')[1] ?? '';
const headers = new Headers(request.headers);
headers.set('searchParams', sp);
return NextResponse.next({ request: { headers } });
}
```
```typescript
// app/jobs/layout.tsx
import { headers } from 'next/headers';
import { decodeState } from 'state-in-url/encodeState';
import { JOBS_STATE } from 'features/jobs/jobsState';
export default async function Layout({ children }: { children: React.ReactNode }) {
const sp = (await headers()).get('searchParams') ?? '';
const initial = decodeState(sp, JOBS_STATE);
return <>{/* use `initial` */}{children}</>;
}
```
## Input handling — instant feedback, deferred URL write
For text inputs and other fast-changing controls, split `setState` (instant render) and `setUrl` (URL flush):
```typescript
<input
value={urlState.q}
onChange={(e) => setState({ q: e.target.value })}
onBlur={() => setUrl()}
/>
```
`setUrl()` with no args flushes the current state to the URL with content-based diffing — safe to call repeatedly.
## React Router and Remix
API is identical to the Next.js variant; only the import path and `NavigateOptions` differ.
```typescript
import { useUrlState } from 'state-in-url/react-router'; // RR v7
import { useUrlState } from 'state-in-url/react-router6'; // RR v6 (since 6.0.0)
import { useUrlState } from 'state-in-url/remix'; // Remix v2
setUrl({ tab: 'b' }, { replace: false, preventScrollReset: true });
```
## Astro
Same API inside a React (or Preact `compat: true`) island. Pass `Object.fromEntries(Astro.url.searchParams)` as the island's `searchParams` prop so the server render matches the URL — a plain object, `URLSearchParams` serializes to `{}`. The page must render on demand (`output: 'server'` or `export const prerender = false`, with an adapter). Islands sharing one default-state object share state; there is no client router, so `replace` defaults to `true`.
```astro
---
import { Filters } from '../components/Filters';
const searchParams = Object.fromEntries(Astro.url.searchParams);
---
<Filters client:load searchParams={searchParams} />
```
```typescript
import { useUrlState } from 'state-in-url/astro';
export function Filters({ searchParams }: { searchParams?: Record<string, string> }) {
const { urlState, setUrl } = useUrlState(FILTERS_STATE, { searchParams });
...
}
```
No client framework at all: `decodeState(Astro.url.searchParams, FILTERS_STATE)` and `encodeState(next, FILTERS_STATE, Astro.url.searchParams)` from `state-in-url/encodeState` do the same job in the frontmatter, for links.
## react-hook-form integration
Share one defaults object, hydrate `useForm` from `urlState`, push form changes back via RHF `subscribe()` (not `watch()`):
```typescript
const { urlState, setUrl } = useUrlState(FILTERS_STATE, { searchParams });
const form = useForm<FiltersState>({ defaultValues: urlState });
React.useEffect(() => {
const sub = form.subscribe({
formState: { values: true },
callback: ({ values }) => setUrl(values),
});
return () => sub();
}, [form, setUrl]);
```
## `useSharedState` — cross-component state without URL
```typescript
import { useSharedState } from 'state-in-url';
const CART_STATE: CartState = { items: [], isOpen: false };
const { state, setState } = useSharedState(CART_STATE);
```
Same module-scoped default-state-identity rule. Use only when URL sync is explicitly NOT wanted.
## Common mistakes (CRITICAL — fix any agent generating these)
| Mistake | Fix |
|---|---|
| `defaultState` defined inside a React component | Move to a module-scoped `const`, annotated with a `type` |
| `interface FeatureState { ... }` for state shape | Use `type FeatureState = { ... }` |
| `setUrl` inside `useEffect` with `urlState` in deps | Causes infinite loop; gate on the actual change or derive on read |
| Two components each declaring `const DEFAULTS = {...}` | Export one const from a shared file; components import the hook |
| `setUrl`/`setState` called during render | Move into a handler or effect |
| `interface` instead of `type` | Same as above; `type` is required |
| Reading `searchParams` in a Next.js server layout | Use the Proxy + `headers()` + `decodeState` pattern |
| Using `state-in-url/next` in Pages Router | Not supported; use App Router or build a custom hook with `useUrlStateBase` |
| Importing `state-in-url/react-router` in a RR v6 project | Use `state-in-url/react-router6` (moved in 6.0.0) |
| `setUrl({...})` for fast typing inputs | Use `setState` on change, `setUrl()` on blur |
| Mutating `urlState` directly | Always go through `setState`/`setUrl` |
| Storing functions / `BigInt` / `Symbol` / `Map` / `Set` | Not serializable; use plain JSON-compatible values (Date is OK) |
| Storing tokens / API keys / passwords / PII in URL | Use auth storage; URL state is fully public |
## Documentation resources
- Next.js App Router guide (searchParams forwarding, layouts, history, FAQ): https://state-in-url.dev/nextjs — Markdown at https://state-in-url.dev/nextjs.md
- Comparison with nuqs, TanStack Router, use-query-params: https://state-in-url.dev/vs/nuqs — Markdown at https://state-in-url.dev/vs/nuqs.md
- Full README (humans): https://github.com/asmyshlyaev177/state-in-url/blob/master/README.md
- URL size limits: https://github.com/asmyshlyaev177/state-in-url/blob/master/Limits.md
- Working examples per framework: `packages/example-nextjs{14,15,16}`, `packages/example-react-router{6,7}`, `packages/example-remix2`, `packages/example-astro`
- JSDoc comments are available in IDE for all exported functions
## Contact
- Issues and bug reports: https://github.com/asmyshlyaev177/state-in-url/issues
- Discussions: https://github.com/asmyshlyaev177/state-in-url/discussions
- Maintainer: Aleksandr Smyshliaev (asmyshlyaev177) — https://asmyshlyaev177.dev
## AI Discovery Files
- ai.txt (what AI systems may and may not do with this content): https://state-in-url.dev/ai.txt
- ai.json (the same policy, machine-parseable): https://state-in-url.dev/ai.json
- identity.json (canonical project identity): https://state-in-url.dev/identity.json
- brand.txt (correct naming and terminology): https://state-in-url.dev/brand.txt
- faq-ai.txt (direct answers to common questions): https://state-in-url.dev/faq-ai.txt
- developer-ai.txt (exports, API surface, constraints): https://state-in-url.dev/developer-ai.txt
- robots-ai.txt (AI crawler directives): https://state-in-url.dev/robots-ai.txt
Des sites au score de préparation IA proche — comparez leur llms.txt et leur balisage.