Repository navigation
Conversation
useSearchParams(schema) returns [output, update] and validates the url with any Standard Schema. Route type generation finds the schemas components pass to the hook and types Link searchParams per destination. The router now writes array params as repeated keys. Validation: focused probe across zod, valibot, arktype and a hand-written schema (types and runtime), web flow with 28 interaction checks against the tests app, oxlint, unit tests in packages/one (remaining failures are unbuilt vite-native-hmr dist, native closure and a calendar test that also fails on main). No native build.
The schema input keeps only keys in the route's own href query, so a layout no longer sees its child's path params (id, catch-all slug) as query, and a page no longer picks up a sibling tab's stale path param or the '#' key. An unfocused screen no longer carries the focused route's hash on update. The item fixture gets generateStaticParams so build:web passes. Adds layout, catch-all and tabs fixtures. Docs note the repeated-key URL change, Link params comma-joining, and the async schema TypeError. Validation: real-router chromium probe against one dev (before: 6 failures, after: 20/20 pass); bun run build:web in tests/test passes; tsc --noEmit in packages/one and oxlint on touched files clean. Not run: test:prod, native. Team-Machine-Session: r125501
useSearchParams(schema, { global: true }) in a mounted unfocused page
filtered the active params by the page's own href and updated the page's own
path. Global now takes params, href and pathname from the store route info.
Adds a global reader to the tab one fixture.
Validation: real-router chromium probe, new case failed before (read page 1
with key a, update wrote /tabs/one?a=1&page=2), 24/24 pass after; build:web,
tsc --noEmit in packages/one and oxlint clean. Not run: test:prod, native.
Team-Machine-Session: r125501
|
The approved feature is included in the held One minor batch #1027 on
The full feature patch identity is unchanged. Only the two root export files combined pre-existing release-branch context automatically. The existing reviewer has been asked to check that overlap through the original review chain. Validation on the containing branch: normal One package build and typecheck pass; existing routing/native-engine checks report 10 passed and one pre-existing skipped test. Generated declarations remain clean. No new browser or native runtime validation is claimed here. This PR remains the source and review record. Delivery is through the held minor batch, rather than a separate main patch. Broader feature and stable-release approval remain unchanged. |
|
Awesome! I recommend renaming |
…aders A server transform gives route modules the search schemas found in the route and its layouts. The server validates the query before the loader (400 on failure) and passes searchParams. Query parsing no longer assigns __proto__ keys. Validation: tsc; typed-routes vitest; dev server and one build + one serve against tests/test (transformed values, 400 with no loader call, composition, hot edit and deletion, hooks/URL behavior); tests/test/tests/search-params-loader.test.ts passes. Worker and Vercel paths not run. Team-Machine-Session: r126840
Validated searchParams now reach ssr loaders on client navigation and refetch. The query travels as __one_search; loader state and preload keys include it. Validation: tsc --noEmit in packages/one; vitest for useLoader, cleanUrl, createHandleRequest, workerHandler and router (196 passed); tests/test search-params-loader (3 tests, headless Chromium, dev and prod servers) passed. Worker handler and Vercel paths, native and ssg not run. Team-Machine-Session: r126840
The generated Vercel handler reads __one_search and validates through the shared runtime. A rejected query answers a loader request with a 400 marker; client navigation loads the url as a document and refetch rejects. Validation: tsc --noEmit in packages/one; vitest for useLoader, cleanUrl, createHandleRequest, workerHandler, router, vercel (196 passed); tests/test search-params-loader (3 tests, headless Chromium, dev and prod servers) passed; generated Vercel handler run locally against the built tests/test server dist with VERCEL=1 (loader valid/invalid/no query, document valid/invalid). No Vercel deploy, dynamic route rewrite, worker, native or ssg run. Team-Machine-Session: r126840
Fix the stale source and declaration comments identified by independent review; include the native production initial-load limitation. Validation: diff check passed; comment-only changes in source and emitted declaration, runtime unchanged from approved3317a56e7f. Team-Machine-Session: r116738
…test Wait for a hydrated marker before the first click and for the url query after the data changes, replacing the fixed sleep. Validation: search-params-loader test passed in tests/test under TEST_ENV=dev and prod, and once on a cold dev server in an isolated consumer of canary 2.0.0-0.canary.1792904062387. Team-Machine-Session: r126840
Implements #1039 on the Standard Schema protocol. No Zod dependency, adapter or inspection. Owner direction and design are in the Contrast plan
plans/contrast/one-search-params-schema.md. This approves building; merging and any minor release stay with review.API
useSearchParams()anduseSearchParams({ global })still return a read-onlyURLSearchParams.useSearchParams(schema, { global? })returns[output, update]. The schema gets every query key as a string, or a string array when the key repeats. Path params are left out.update(partial, { replace? })merges into the current URL viarouter.push(default) orrouter.replace. Path params, other keys and the hash stay.null/undefinedremoves a key. Writable values are string, number, boolean and arrays of those (repeated keys). Fields whose output is not writable (aDate) take the schema's input type; anything else throwsTypeError.SearchValidationErrorin render, so the nearest error boundary isolates it. Async schemas throw aTypeError.LinkgainssearchParams, typed from the destination route. It is a second overload, so existingLinktyping (including template-literal hrefs) is unchanged.validateSearchandvalidateParamsnow share one synchronous Standard Schema runner; their exports are unchanged.Discovery and generated types
generateRouteTypesparses each route file, its ancestor layouts and their static relative or tsconfig-path imports with oxc, findsuseSearchParams(schema)calls and writesSearchParamTypesintoroutes.d.tsastypeof import('./file')['name'], so TypeScript derives the shape. No app module is evaluated and no schema internals are read. Editing a scanned file regenerates the types (checked live: adding and removing a component updates the route's keys).Choices to review
?page=2, arrays as repeated keys), not the issue's file-name prefix or dot-notation. Prefixes would break existing URLs and renames. Two components on one route using the same key get the intersection of their types. The owner has not picked key naming; this is the default.getPathFromStatefix. The router read repeated keys as arrays but wrote arrays as comma-joined text. It now writes repeated keys (unit test added). This changes URLs written for array params froma=1,2toa=1&a=2.Link'sparamsobject still comma-joins arrays throughresolveHref;searchParamsuses repeated keys. Left as is.string | string[]where a key may repeat.update.Proof
tscand runtime both clean.tests/test(Playwright, 28 checks): defaults, push and replace history, no remount, unrelated keys, arrays as repeated keys, back/forward, hash, malformed value breaking only its boundary, typed link hrefs, dynamic route with path param. Type errors confirmed for misspelled keys, wrong values and object-href forms.oxlintclean;packages/oneunit tests pass exceptpackage-exports(vite-native-hmrdistnot built in the worktree),packedClosureand the calendar ios test (the last also fails on main).useParamsincludes extra keys there, andupdatefrom an unfocused screen.