{"_id":"@archon-research/router-kit","_rev":"11-1a5684a7b517d530cb5dbf6266b81f1c","name":"@archon-research/router-kit","dist-tags":{"latest":"0.11.0","dev":"0.11.0-rohit-synced-tooltip-readout.1"},"versions":{"0.10.0-rohit-pre-release-consumer-fixes.1":{"name":"@archon-research/router-kit","version":"0.10.0-rohit-pre-release-consumer-fixes.1","_id":"@archon-research/router-kit@0.10.0-rohit-pre-release-consumer-fixes.1","maintainers":[{"name":"r0hitsh","email":"rs@rohit.sh"}],"dist":{"shasum":"14548238ff8bd3c94cb14358ec92309bd2ce2dc3","tarball":"https://registry.npmjs.org/@archon-research/router-kit/-/router-kit-0.10.0-rohit-pre-release-consumer-fixes.1.tgz","fileCount":26,"integrity":"sha512-Z9shLeHgTilIbe4CJK6wRvmgNRqMC60gIPGkHOBBqFdyNtH0eELJrxtoXEsEpoIzWiR3XYwcPAzycDzmYcF9ww==","signatures":[{"sig":"MEQCIEnzreLiTuRKC+JBT5zlRjjn/yoTk5bCYQ90fnfJ83ErAiBeCYBLMdnEX5+O4BWB9c2YUtSX3m2vAd2btms2laeO1Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":116589},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./testing":{"types":"./dist/testing.d.ts","default":"./dist/testing.js"}},"scripts":{"lint":"oxlint -c oxlint.config.ts src","test":"vitest run","build":"tsc -p tsconfig.build.json","clean":"rm -rf dist","format":"oxfmt -c oxfmt.config.ts --write src","prepare":"npm run build","lint:fix":"oxlint -c oxlint.config.ts --fix src","type:check":"tsc -p tsconfig.json --noEmit","format:check":"oxfmt -c oxfmt.config.ts --check src"},"_npmUser":{"name":"r0hitsh","email":"rs@rohit.sh"},"_npmVersion":"11.16.0","description":"The generic pieces every [TanStack Router](https://tanstack.com/router) app rebuilds: search-param schemas that never reject, a root-route cleanup that keeps the address bar honest, an adapter for the design system's URL-synced table, and a test harness t","directories":{},"sideEffects":false,"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"zod":"4.4.3","oxfmt":"0.62.0","oxlint":"1.77.0","vitest":"^4.1.9","@tanstack/react-router":"1.170.27","@archon-research/tsconfig":"*","@archon-research/oxfmt-config":"*","@archon-research/oxlint-config":"*"},"peerDependencies":{"zod":"^4.0.0","@tanstack/react-router":"^1.170.0"},"_npmOperationalInternal":{"tmp":"tmp/router-kit_0.10.0-rohit-pre-release-consumer-fixes.1_1787235074688_0.6051108471275775","host":"s3://npm-registry-packages-npm-production"}},"0.10.0-rohit-pre-release-consumer-fixes.3":{"name":"@archon-research/router-kit","version":"0.10.0-rohit-pre-release-consumer-fixes.3","_id":"@archon-research/router-kit@0.10.0-rohit-pre-release-consumer-fixes.3","maintainers":[{"name":"r0hitsh","email":"rs@rohit.sh"}],"homepage":"https://github.com/archon-research/uikit#readme","bugs":{"url":"https://github.com/archon-research/uikit/issues"},"dist":{"shasum":"16856b380b2de76eede7cece65445f9ff1cd598d","tarball":"https://registry.npmjs.org/@archon-research/router-kit/-/router-kit-0.10.0-rohit-pre-release-consumer-fixes.3.tgz","fileCount":27,"integrity":"sha512-kFZA1VHL+2W3+h0GK0EtCn6TcL2HzgO01b84phvOyudyh/7shHQsDxtqCXXYsscuAD++OvxtGunkq+27/bBjsw==","signatures":[{"sig":"MEQCID3cvLkA2jocpeJzGn1h3NH7MAdUpDvkZLjsZcMilns2AiA+EsWFelilcw95V5J0bj+wZ8iixA6wdOkGnk2jSTRvFg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@archon-research%2frouter-kit@0.10.0-rohit-pre-release-consumer-fixes.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":189062},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./testing":{"types":"./dist/testing.d.ts","default":"./dist/testing.js"}},"gitHead":"cad22a209afe1250b6564f60134acf160a465c29","scripts":{"lint":"oxlint -c oxlint.config.ts src","test":"vitest run","build":"tsc -p tsconfig.build.json","clean":"rm -rf dist","format":"oxfmt -c oxfmt.config.ts --write src","prepare":"npm run build","lint:fix":"oxlint -c oxlint.config.ts --fix src","type:check":"tsc -p tsconfig.json --noEmit","format:check":"oxfmt -c oxfmt.config.ts --check src"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:cd9dab58-edf8-40b4-b72d-fdc15a17b7f7"}},"repository":{"url":"git+https://github.com/archon-research/uikit.git"},"_npmVersion":"11.16.0","description":"The generic pieces every [TanStack Router](https://tanstack.com/router) app rebuilds: search-param schemas that never reject, a root-route cleanup that keeps the address bar honest, an adapter for the design system's URL-synced table, and a test harness t","directories":{},"sideEffects":false,"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"zod":"4.4.3","oxfmt":"0.62.0","oxlint":"1.77.0","vitest":"^4.1.9","@tanstack/react-router":"1.170.27","@archon-research/tsconfig":"*","@archon-research/oxfmt-config":"*","@archon-research/oxlint-config":"*"},"peerDependencies":{"zod":"^4.0.0","@tanstack/react-router":"^1.170.0"},"_npmOperationalInternal":{"tmp":"tmp/router-kit_0.10.0-rohit-pre-release-consumer-fixes.3_1787320155337_0.39090664880431425","host":"s3://npm-registry-packages-npm-production"}},"0.10.0":{"name":"@archon-research/router-kit","version":"0.10.0","_id":"@archon-research/router-kit@0.10.0","maintainers":[{"name":"r0hitsh","email":"rs@rohit.sh"}],"homepage":"https://github.com/archon-research/uikit#readme","bugs":{"url":"https://github.com/archon-research/uikit/issues"},"dist":{"shasum":"26fe0ef668d07e7cd509f2f90bb5c25f9c1e14ad","tarball":"https://registry.npmjs.org/@archon-research/router-kit/-/router-kit-0.10.0.tgz","fileCount":27,"integrity":"sha512-Uk/74LncNh1Iwv1G2iLUJ6/WTgwoCcDTA/NLZhdCL1lYbJNAP7SLGZqR1WsmerqsVJhuTRrdALW320sQyGiEzA==","signatures":[{"sig":"MEUCIH8ndkNOg9+l5RhGlL5ggk9CbTXrQIXEwrO4dRk1DDT/AiEAoWnzzZ7gFSgMViXLhzWanjrNwMLf32eDBg1eDwuAH9c=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@archon-research%2frouter-kit@0.10.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":189027},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./testing":{"types":"./dist/testing.d.ts","default":"./dist/testing.js"}},"gitHead":"3a7a4f261aaea5fe1cf1e292d61e603a2b48da4a","scripts":{"lint":"oxlint -c oxlint.config.ts src","test":"vitest run","build":"tsc -p tsconfig.build.json","clean":"rm -rf dist","format":"oxfmt -c oxfmt.config.ts --write src","prepare":"npm run build","lint:fix":"oxlint -c oxlint.config.ts --fix src","type:check":"tsc -p tsconfig.json --noEmit","format:check":"oxfmt -c oxfmt.config.ts --check src"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:cd9dab58-edf8-40b4-b72d-fdc15a17b7f7"}},"repository":{"url":"git+https://github.com/archon-research/uikit.git"},"_npmVersion":"11.16.0","description":"The generic pieces every [TanStack Router](https://tanstack.com/router) app rebuilds: search-param schemas that never reject, a root-route cleanup that keeps the address bar honest, an adapter for the design system's URL-synced table, and a test harness t","directories":{},"sideEffects":false,"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"zod":"4.4.3","oxfmt":"0.62.0","oxlint":"1.77.0","vitest":"^4.1.9","@tanstack/react-router":"1.170.27","@archon-research/tsconfig":"*","@archon-research/oxfmt-config":"*","@archon-research/oxlint-config":"*"},"peerDependencies":{"zod":"^4.0.0","@tanstack/react-router":"^1.170.0"},"_npmOperationalInternal":{"tmp":"tmp/router-kit_0.10.0_1787569821639_0.6498081723902598","host":"s3://npm-registry-packages-npm-production"}},"0.11.0-rohit-publish-only-affected-packages.1":{"name":"@archon-research/router-kit","version":"0.11.0-rohit-publish-only-affected-packages.1","_id":"@archon-research/router-kit@0.11.0-rohit-publish-only-affected-packages.1","maintainers":[{"name":"r0hitsh","email":"rs@rohit.sh"}],"homepage":"https://github.com/archon-research/uikit#readme","bugs":{"url":"https://github.com/archon-research/uikit/issues"},"dist":{"shasum":"2a3979da0b1bd179577c87fda516efc97025de8c","tarball":"https://registry.npmjs.org/@archon-research/router-kit/-/router-kit-0.11.0-rohit-publish-only-affected-packages.1.tgz","fileCount":27,"integrity":"sha512-Q4/pzHJ1y1tObqHH0a/JlNjrDpIxzcN0rA1v6qtxJTQ6v7U8pcVepYob0I36HRElEtphdNmIKuxr/GK5uWABaw==","signatures":[{"sig":"MEYCIQDWKdtaDbyc1fBEv8kBq+lpqoQd6IMug9wdmlRG1d+lpwIhAN5Q8/YtQDOeIxDsgqQk9yIWdMFzWWjaKCnKE1JTZzpS","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@archon-research%2frouter-kit@0.11.0-rohit-publish-only-affected-packages.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":189066},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./testing":{"types":"./dist/testing.d.ts","default":"./dist/testing.js"}},"gitHead":"9f7ef8dae868fa1668d7d98f801716eadb85e5c2","scripts":{"lint":"oxlint -c oxlint.config.ts src","test":"vitest run","build":"tsc -p tsconfig.build.json","clean":"rm -rf dist","format":"oxfmt -c oxfmt.config.ts --write src","prepare":"npm run build","lint:fix":"oxlint -c oxlint.config.ts --fix src","type:check":"tsc -p tsconfig.json --noEmit","format:check":"oxfmt -c oxfmt.config.ts --check src"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:cd9dab58-edf8-40b4-b72d-fdc15a17b7f7"}},"repository":{"url":"git+https://github.com/archon-research/uikit.git"},"_npmVersion":"12.0.2","description":"The generic pieces every [TanStack Router](https://tanstack.com/router) app rebuilds: search-param schemas that never reject, a root-route cleanup that keeps the address bar honest, an adapter for the design system's URL-synced table, and a test harness t","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"zod":"4.4.3","oxfmt":"0.62.0","oxlint":"1.77.0","vitest":"^4.1.9","@tanstack/react-router":"1.170.27","@archon-research/tsconfig":"*","@archon-research/oxfmt-config":"*","@archon-research/oxlint-config":"*"},"peerDependencies":{"zod":"^4.0.0","@tanstack/react-router":"^1.170.0"},"_npmOperationalInternal":{"tmp":"tmp/router-kit_0.11.0-rohit-publish-only-affected-packages.1_1787856385449_0.5187675987586207","host":"s3://npm-registry-packages-npm-production"}},"0.10.1-rohit-publish-only-affected-packages.1":{"name":"@archon-research/router-kit","version":"0.10.1-rohit-publish-only-affected-packages.1","_id":"@archon-research/router-kit@0.10.1-rohit-publish-only-affected-packages.1","maintainers":[{"name":"r0hitsh","email":"rs@rohit.sh"}],"homepage":"https://github.com/archon-research/uikit#readme","bugs":{"url":"https://github.com/archon-research/uikit/issues"},"dist":{"shasum":"b2256a696c8a977eee930896d351042198e2a35f","tarball":"https://registry.npmjs.org/@archon-research/router-kit/-/router-kit-0.10.1-rohit-publish-only-affected-packages.1.tgz","fileCount":27,"integrity":"sha512-tQpegVggyLixmpfLG1719m5eUCWNB5megJsliYfwcZuR73ebdIMqL1G+mDDOvYjJzAQslrCuCD2o3novr+VFLw==","signatures":[{"sig":"MEQCIFmLxQqIWBtdD/Q2fWcI48/XojzKxf8R5AVd1yD9Ryv5AiBmfEcD0a5AIzZOghpXiwU41LcKmE9+VTWsoj/EigRJGQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@archon-research%2frouter-kit@0.10.1-rohit-publish-only-affected-packages.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":189066},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./testing":{"types":"./dist/testing.d.ts","default":"./dist/testing.js"}},"gitHead":"a391960fe1d643570c0e953df209509436ea0fc4","scripts":{"lint":"oxlint -c oxlint.config.ts src","test":"vitest run","build":"tsc -p tsconfig.build.json","clean":"rm -rf dist","format":"oxfmt -c oxfmt.config.ts --write src","prepare":"npm run build","lint:fix":"oxlint -c oxlint.config.ts --fix src","type:check":"tsc -p tsconfig.json --noEmit","format:check":"oxfmt -c oxfmt.config.ts --check src"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:cd9dab58-edf8-40b4-b72d-fdc15a17b7f7"}},"repository":{"url":"git+https://github.com/archon-research/uikit.git"},"_npmVersion":"12.0.2","description":"The generic pieces every [TanStack Router](https://tanstack.com/router) app rebuilds: search-param schemas that never reject, a root-route cleanup that keeps the address bar honest, an adapter for the design system's URL-synced table, and a test harness t","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"zod":"4.4.3","oxfmt":"0.62.0","oxlint":"1.77.0","vitest":"^4.1.9","@tanstack/react-router":"1.170.27","@archon-research/tsconfig":"*","@archon-research/oxfmt-config":"*","@archon-research/oxlint-config":"*"},"peerDependencies":{"zod":"^4.0.0","@tanstack/react-router":"^1.170.0"},"_npmOperationalInternal":{"tmp":"tmp/router-kit_0.10.1-rohit-publish-only-affected-packages.1_1787860750418_0.026978367519402635","host":"s3://npm-registry-packages-npm-production"}},"0.10.1-rohit-publish-only-affected-packages.2":{"name":"@archon-research/router-kit","version":"0.10.1-rohit-publish-only-affected-packages.2","_id":"@archon-research/router-kit@0.10.1-rohit-publish-only-affected-packages.2","maintainers":[{"name":"r0hitsh","email":"rs@rohit.sh"}],"homepage":"https://github.com/archon-research/uikit#readme","bugs":{"url":"https://github.com/archon-research/uikit/issues"},"dist":{"shasum":"96d038f87564218792ce3bac2b2b2aa3c229808c","tarball":"https://registry.npmjs.org/@archon-research/router-kit/-/router-kit-0.10.1-rohit-publish-only-affected-packages.2.tgz","fileCount":27,"integrity":"sha512-+mt7ReBKAbntVMvRnsZx+2UCA+ONPf4RQnfckWsBDKdhkXCFEQWcQCGu4R3zxkWozcxW6wGlL4Ylze0DbBKKBQ==","signatures":[{"sig":"MEQCIDixkrnhwHuuiNF0DSKyk3kY2M84o9EWOOZyJHCHcg5gAiAdF8GOqMRsUKq4L84CFedrqKiAt/QFRCCe1BFaacO8ig==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@archon-research%2frouter-kit@0.10.1-rohit-publish-only-affected-packages.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":189066},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./testing":{"types":"./dist/testing.d.ts","default":"./dist/testing.js"}},"gitHead":"fa84dc595f35f199ed5022d2adfbfd35a4488eca","scripts":{"lint":"oxlint -c oxlint.config.ts src","test":"vitest run","build":"tsc -p tsconfig.build.json","clean":"rm -rf dist","format":"oxfmt -c oxfmt.config.ts --write src","prepare":"npm run build","lint:fix":"oxlint -c oxlint.config.ts --fix src","type:check":"tsc -p tsconfig.json --noEmit","format:check":"oxfmt -c oxfmt.config.ts --check src"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:cd9dab58-edf8-40b4-b72d-fdc15a17b7f7"}},"repository":{"url":"git+https://github.com/archon-research/uikit.git"},"_npmVersion":"12.0.2","description":"The generic pieces every [TanStack Router](https://tanstack.com/router) app rebuilds: search-param schemas that never reject, a root-route cleanup that keeps the address bar honest, an adapter for the design system's URL-synced table, and a test harness t","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"zod":"4.4.3","oxfmt":"0.62.0","oxlint":"1.77.0","vitest":"^4.1.9","@tanstack/react-router":"1.170.27","@archon-research/tsconfig":"*","@archon-research/oxfmt-config":"*","@archon-research/oxlint-config":"*"},"peerDependencies":{"zod":"^4.0.0","@tanstack/react-router":"^1.170.0"},"_npmOperationalInternal":{"tmp":"tmp/router-kit_0.10.1-rohit-publish-only-affected-packages.2_1787863255644_0.7182396493440899","host":"s3://npm-registry-packages-npm-production"}},"0.10.1-rohit-publish-only-affected-packages.3":{"name":"@archon-research/router-kit","version":"0.10.1-rohit-publish-only-affected-packages.3","_id":"@archon-research/router-kit@0.10.1-rohit-publish-only-affected-packages.3","maintainers":[{"name":"r0hitsh","email":"rs@rohit.sh"}],"homepage":"https://github.com/archon-research/uikit#readme","bugs":{"url":"https://github.com/archon-research/uikit/issues"},"dist":{"shasum":"51d93b2d8a682cc0ef69516386d21cfcebdd3fa4","tarball":"https://registry.npmjs.org/@archon-research/router-kit/-/router-kit-0.10.1-rohit-publish-only-affected-packages.3.tgz","fileCount":27,"integrity":"sha512-+81NZ/V9V6hFVXc0SoOArXD8LIV9u0cIiG3f9h9voR6ODBBuA2r2zel1wkprjsQAXE0AEA7l7O7eQdaTjvNQsg==","signatures":[{"sig":"MEUCIQCUvIljKwXE/vHPm0fUzRgC0OsCGrSz2QfQTQ0jQeIa9wIgZjFYy1T7TyhxKwkJOJByhcD9BmiP/4r4PcH2UB7VRQQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@archon-research%2frouter-kit@0.10.1-rohit-publish-only-affected-packages.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":189225},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./testing":{"types":"./dist/testing.d.ts","default":"./dist/testing.js"}},"gitHead":"d13754c46a34feb8f215e4bb06a44c5fa85a582d","scripts":{"lint":"oxlint -c oxlint.config.ts src","test":"vitest run","build":"tsc -p tsconfig.build.json","clean":"rm -rf dist","format":"oxfmt -c oxfmt.config.ts --write src","prepare":"npm run build","lint:fix":"oxlint -c oxlint.config.ts --fix src","type:check":"tsc -p tsconfig.json --noEmit","format:check":"oxfmt -c oxfmt.config.ts --check src"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:cd9dab58-edf8-40b4-b72d-fdc15a17b7f7"}},"repository":{"url":"git+https://github.com/archon-research/uikit.git"},"_npmVersion":"12.0.2","description":"The generic pieces every [TanStack Router](https://tanstack.com/router) app rebuilds: search-param schemas that never reject, a root-route cleanup that keeps the address bar honest, an adapter for the design system's URL-synced table, and a test harness t","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"zod":"4.4.3","oxfmt":"0.62.0","oxlint":"1.77.0","vitest":"^4.1.9","@tanstack/react-router":"1.170.27","@archon-research/tsconfig":"*","@archon-research/oxfmt-config":"*","@archon-research/oxlint-config":"*"},"peerDependencies":{"zod":"^4.0.0","@tanstack/react-router":"^1.170.0"},"_npmOperationalInternal":{"tmp":"tmp/router-kit_0.10.1-rohit-publish-only-affected-packages.3_1787864268462_0.34222579810864007","host":"s3://npm-registry-packages-npm-production"}},"0.10.1-rohit-static-analysis-preset-coverage.1":{"name":"@archon-research/router-kit","version":"0.10.1-rohit-static-analysis-preset-coverage.1","_id":"@archon-research/router-kit@0.10.1-rohit-static-analysis-preset-coverage.1","maintainers":[{"name":"r0hitsh","email":"rs@rohit.sh"}],"homepage":"https://github.com/archon-research/uikit#readme","bugs":{"url":"https://github.com/archon-research/uikit/issues"},"dist":{"shasum":"0b031a357c5d5872d54a07f6b772abd95307f648","tarball":"https://registry.npmjs.org/@archon-research/router-kit/-/router-kit-0.10.1-rohit-static-analysis-preset-coverage.1.tgz","fileCount":27,"integrity":"sha512-dseB5bvHJurkL+EVrySdQYvT0F37JW3FgolnNQ0NJW7Xtw14m5LgETd5x2z9ePjahTSurtxekfANTrdxsn6dog==","signatures":[{"sig":"MEYCIQC1CUWWOgGw/y0+CtgceYmbLFXNbXenLpQdVGzF2K63zgIhAMaNSS5DpFSLgOxsMMiC7tDv/TyQtZ1XEp/wthSRzLJc","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@archon-research%2frouter-kit@0.10.1-rohit-static-analysis-preset-coverage.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":189604},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./testing":{"types":"./dist/testing.d.ts","default":"./dist/testing.js"}},"gitHead":"390b3a9c9790cd8d16c3ab9bdc1fbfa79ed205c2","scripts":{"lint":"oxlint -c oxlint.config.ts src","test":"vitest run","build":"tsc -p tsconfig.build.json","clean":"rm -rf dist","format":"oxfmt -c oxfmt.config.ts --write src","prepare":"npm run build","lint:fix":"oxlint -c oxlint.config.ts --fix src","type:check":"tsc -p tsconfig.json --noEmit","format:check":"oxfmt -c oxfmt.config.ts --check src"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:cd9dab58-edf8-40b4-b72d-fdc15a17b7f7"}},"repository":{"url":"git+https://github.com/archon-research/uikit.git"},"_npmVersion":"12.0.2","description":"The generic pieces every [TanStack Router](https://tanstack.com/router) app rebuilds: search-param schemas that never reject, a root-route cleanup that keeps the address bar honest, an adapter for the design system's URL-synced table, and a test harness t","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"zod":"4.4.3","oxfmt":"0.62.0","oxlint":"1.77.0","vitest":"^4.1.9","@tanstack/react-router":"1.170.27","@archon-research/tsconfig":"*","@archon-research/oxfmt-config":"*","@archon-research/oxlint-config":"*"},"peerDependencies":{"zod":"^4.0.0","@tanstack/react-router":"^1.170.0"},"_npmOperationalInternal":{"tmp":"tmp/router-kit_0.10.1-rohit-static-analysis-preset-coverage.1_1787909456656_0.805777780153585","host":"s3://npm-registry-packages-npm-production"}},"0.10.1":{"name":"@archon-research/router-kit","version":"0.10.1","_id":"@archon-research/router-kit@0.10.1","maintainers":[{"name":"r0hitsh","email":"rs@rohit.sh"}],"homepage":"https://github.com/archon-research/uikit#readme","bugs":{"url":"https://github.com/archon-research/uikit/issues"},"dist":{"shasum":"3803cf1b04c1667cc39e6ff0972b38638369988e","tarball":"https://registry.npmjs.org/@archon-research/router-kit/-/router-kit-0.10.1.tgz","fileCount":27,"integrity":"sha512-yDNLLv0tYZ5IsXvLXwT+5oFACD9+GnjQ2zhBdreag8NAIaAm76rH9WglzlXWrls+XMsSGuBq4Z/FRlBGYHlgpg==","signatures":[{"sig":"MEYCIQDFudLLjANnfEUkOyRcVvO8puzZQO2fes2w9Ita8uCG4gIhAIPsYxPg7TvdS/jafpWvjJ9Q012yXUOjt9sM6vsRbLoo","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@archon-research%2frouter-kit@0.10.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":189581},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./testing":{"types":"./dist/testing.d.ts","default":"./dist/testing.js"}},"gitHead":"1a3806d230e3ccd4ca2938c408f3216444954eeb","scripts":{"lint":"oxlint -c oxlint.config.ts --max-warnings=0 src","test":"vitest run","build":"tsc -p tsconfig.build.json","clean":"rm -rf dist","format":"oxfmt -c oxfmt.config.ts --write src","prepare":"npm run build","lint:fix":"oxlint -c oxlint.config.ts --fix src","type:check":"tsc -p tsconfig.json --noEmit","format:check":"oxfmt -c oxfmt.config.ts --check src"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:cd9dab58-edf8-40b4-b72d-fdc15a17b7f7"}},"repository":{"url":"git+https://github.com/archon-research/uikit.git"},"_npmVersion":"12.0.2","description":"The generic pieces every [TanStack Router](https://tanstack.com/router) app rebuilds: search-param schemas that never reject, a root-route cleanup that keeps the address bar honest, an adapter for the design system's URL-synced table, and a test harness t","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"zod":"4.4.3","oxfmt":"0.62.0","oxlint":"1.77.0","vitest":"^4.1.9","@tanstack/react-router":"1.170.32","@archon-research/tsconfig":"*","@archon-research/oxfmt-config":"*","@archon-research/oxlint-config":"*"},"peerDependencies":{"zod":"^4.0.0","@tanstack/react-router":"^1.170.0"},"_npmOperationalInternal":{"tmp":"tmp/router-kit_0.10.1_1788163361914_0.1621343926998422","host":"s3://npm-registry-packages-npm-production"}},"0.11.0-rohit-synced-tooltip-readout.1":{"name":"@archon-research/router-kit","version":"0.11.0-rohit-synced-tooltip-readout.1","_id":"@archon-research/router-kit@0.11.0-rohit-synced-tooltip-readout.1","maintainers":[{"name":"r0hitsh","email":"rs@rohit.sh"}],"homepage":"https://github.com/archon-research/uikit#readme","bugs":{"url":"https://github.com/archon-research/uikit/issues"},"dist":{"shasum":"2d5db0ec7cee0d78db71276458ce80013f1217e3","tarball":"https://registry.npmjs.org/@archon-research/router-kit/-/router-kit-0.11.0-rohit-synced-tooltip-readout.1.tgz","fileCount":27,"integrity":"sha512-WOFuWSKbFBhPVygLhs0tsp9gXaQurhD85o9S+s05zyttTXg43apQNeMnCuvksW4kkZ089sHCt4I8/n30IDwbQg==","signatures":[{"sig":"MEUCIQDG85VcICSmZm7EUivJq4mYtIEH2uapemBi6EUZmJgJdwIgc6VrWALvnajhrNIQ2G2IacF5upRaK1fBvaAVnqisK+s=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@archon-research%2frouter-kit@0.11.0-rohit-synced-tooltip-readout.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":193528},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./testing":{"types":"./dist/testing.d.ts","default":"./dist/testing.js"}},"gitHead":"b2a7afc91e801d10385309dc479149188c80c34b","scripts":{"lint":"oxlint -c oxlint.config.ts --max-warnings=0 src","test":"vitest run","build":"tsc -p tsconfig.build.json","clean":"rm -rf dist","format":"oxfmt -c oxfmt.config.ts --write src","prepare":"npm run build","lint:fix":"oxlint -c oxlint.config.ts --fix src","type:check":"tsc -p tsconfig.json --noEmit","format:check":"oxfmt -c oxfmt.config.ts --check src"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:cd9dab58-edf8-40b4-b72d-fdc15a17b7f7"}},"repository":{"url":"git+https://github.com/archon-research/uikit.git"},"_npmVersion":"12.0.2","description":"The generic pieces every [TanStack Router](https://tanstack.com/router) app rebuilds: search-param schemas that never reject, a root-route cleanup that keeps the address bar honest, an adapter for the design system's URL-synced table, and a test harness t","directories":{},"sideEffects":false,"_nodeVersion":"24.20.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"zod":"4.5.4","oxfmt":"0.65.0","oxlint":"1.80.0","vitest":"^4.1.9","@tanstack/react-router":"1.170.32","@archon-research/tsconfig":"*","@archon-research/oxfmt-config":"*","@archon-research/oxlint-config":"*"},"peerDependencies":{"zod":"^4.0.0","@tanstack/react-router":"^1.170.0"},"_npmOperationalInternal":{"tmp":"tmp/router-kit_0.11.0-rohit-synced-tooltip-readout.1_1789472401580_0.999713269688979","host":"s3://npm-registry-packages-npm-production"}},"0.11.0":{"name":"@archon-research/router-kit","publishConfig":{"access":"public"},"type":"module","sideEffects":false,"main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./testing":{"types":"./dist/testing.d.ts","default":"./dist/testing.js"}},"scripts":{"build":"tsc -p tsconfig.build.json","clean":"rm -rf dist","prepare":"npm run build","type:check":"tsc -p tsconfig.json --noEmit","lint":"oxlint -c oxlint.config.ts --max-warnings=0 src","lint:fix":"oxlint -c oxlint.config.ts --fix src","format":"oxfmt -c oxfmt.config.ts --write src","format:check":"oxfmt -c oxfmt.config.ts --check src","test":"vitest run"},"peerDependencies":{"@tanstack/react-router":"^1.170.0","zod":"^4.0.0"},"devDependencies":{"@archon-research/oxfmt-config":"*","@archon-research/oxlint-config":"*","@archon-research/tsconfig":"*","@tanstack/react-router":"1.170.33","oxfmt":"0.65.0","oxlint":"1.80.0","vitest":"^4.1.9","zod":"4.5.4"},"version":"0.11.0","repository":{"url":"git+https://github.com/archon-research/uikit.git"},"gitHead":"ac3b8ae8fa3f561a78f8e1b4c6eca8d1140d06c3","_id":"@archon-research/router-kit@0.11.0","description":"The generic pieces every [TanStack Router](https://tanstack.com/router) app rebuilds: search-param schemas that never reject, a root-route cleanup that keeps the address bar honest, an adapter for the design system's URL-synced table, and a test harness t","bugs":{"url":"https://github.com/archon-research/uikit/issues"},"homepage":"https://github.com/archon-research/uikit#readme","_nodeVersion":"24.20.0","_npmVersion":"12.0.2","dist":{"integrity":"sha512-vW65hZH2iQHoWa91Hut7PYjj9kdil9luKAhGxL2xIZUrY56u2q9MmK0olZ9v2BZvbcvJilnVBaWzfYJhvJejEg==","shasum":"e7c294fe506cee27490e63cb4907b8ba86cb265d","tarball":"https://registry.npmjs.org/@archon-research/router-kit/-/router-kit-0.11.0.tgz","fileCount":27,"unpackedSize":193497,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@archon-research%2frouter-kit@0.11.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCKfRfBGQSHTEUs+Xd3QUzY5kkRxKrt2XNum1132sggqQIgHP41rA0qT1Jjabfp+5Xt09sLCaiQV7bhl31EMnwdMPo="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:cd9dab58-edf8-40b4-b72d-fdc15a17b7f7"}},"directories":{},"maintainers":[{"name":"r0hitsh","email":"rs@rohit.sh"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/router-kit_0.11.0_1789503661954_0.23940051535963502"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-20T14:11:14.471Z","modified":"2026-09-15T20:21:02.425Z","0.10.0-rohit-pre-release-consumer-fixes.1":"2026-08-20T14:11:14.845Z","0.10.0-rohit-pre-release-consumer-fixes.3":"2026-08-21T13:49:15.468Z","0.10.0":"2026-08-24T11:10:21.772Z","0.11.0-rohit-publish-only-affected-packages.1":"2026-08-27T18:46:25.723Z","0.10.1-rohit-publish-only-affected-packages.1":"2026-08-27T19:59:10.556Z","0.10.1-rohit-publish-only-affected-packages.2":"2026-08-27T20:40:55.790Z","0.10.1-rohit-publish-only-affected-packages.3":"2026-08-27T20:57:48.603Z","0.10.1-rohit-static-analysis-preset-coverage.1":"2026-08-28T09:30:56.783Z","0.10.1":"2026-08-31T08:02:42.279Z","0.11.0-rohit-synced-tooltip-readout.1":"2026-09-15T11:40:01.712Z","0.11.0":"2026-09-15T20:21:02.102Z"},"bugs":{"url":"https://github.com/archon-research/uikit/issues"},"homepage":"https://github.com/archon-research/uikit#readme","repository":{"url":"git+https://github.com/archon-research/uikit.git"},"description":"The generic pieces every [TanStack Router](https://tanstack.com/router) app rebuilds: search-param schemas that never reject, a root-route cleanup that keeps the address bar honest, an adapter for the design system's URL-synced table, and a test harness t","maintainers":[{"name":"r0hitsh","email":"rs@rohit.sh"}],"readme":"# @archon-research/router-kit\n\nThe generic pieces every [TanStack Router](https://tanstack.com/router) app\nrebuilds: search-param schemas that never reject, a root-route cleanup that keeps\nthe address bar honest, an adapter for the design system's URL-synced table, and\na test harness that follows entry URLs to a fixed point.\n\nConsumers adopt `@tanstack/react-router` directly — it stays a peer dependency\nand this package never wraps it, never owns your route tree, and never asks you\nto describe a route twice. See [DESIGN.md](./DESIGN.md) for the dependency-shape\ndecisions and what is deliberately not here.\n\n## Installation\n\n```bash\nnpm install @archon-research/router-kit @tanstack/react-router zod\n```\n\n`@tanstack/react-router` and `zod` are both peer dependencies. See\n[peer-version policy](#peer-version-policy) for what that means for upgrades.\n\n## The thing to know first: the query decoder coerces\n\nYour `validateSearch` never sees the raw query text — `parseSearch` has already\ndecoded it, and decoding rewrites values. So a parser written against `string`\nmeets four other shapes in production:\n\n| URL             | value your parser actually receives |\n| --------------- | ----------------------------------- |\n| `?rows=25`      | the number `25`                     |\n| `?dense=true`   | the boolean `true`                  |\n| `?q=` or `?q`   | the empty string `''`               |\n| `?q=a&q=b`      | the array `['a', 'b']`              |\n\nThis is the single most common source of \"the param works in dev and vanishes in\nproduction\" — `?page=2` typed by hand becomes a number, a `z.string()` schema\nrejects it, and the route throws.\n\nHow much coercion depends on which grammar your router was built with, and both\ncommon choices coerce:\n\n- **`parseSearchWith(JSON.parse)`** — the router's default, so this is what you\n  get by not configuring one. It applies the decode above and then `JSON.parse`s\n  every value still a string, so `?v=1e5` arrives as `100000`, `?v=null` as\n  `null`, and `?v=-0` as `0`.\n- **`parseSearchWith((value) => value)`** — the identity parser, for apps whose\n  params are all plain text. It stops after the decode, so those three stay\n  strings.\n\nA hand-written `parseSearch` *is* the decoder rather than a stage after it, so it\ncan opt out — but then it owns the whole grammar.\n\n`toSearchText` is idempotent under either: feed its own output back through a\nrender-and-redecode round trip and you get that output unchanged. What it does\n**not** promise is byte-preserved URL text — under the default grammar `?v=1e5`\ncanonicalizes to `100000`, because the value really was decoded to a number.\n\nThat rewrite is the *grammar's*, and it costs no redirect: the router\nrestringifies the decoded search whenever it builds a location, so its own\nmount-time commit puts `?v=100000` in the address bar. Step 2's rewrites are the\nones that redirect. Either way it is one rewrite, not a loop; the second pass is\nstable, and step 4 pins the settled form of both under both grammars.\n\n`textParam()` and `oneOfParam()` absorb all of it. Reach for `toSearchText` or\n`toSearchOption` directly when a control needs to apply the same rule while\nwriting a value back.\n\n## Usage\n\n### 1. Describe the search params\n\n```ts\nimport { oneOfParam, textParam } from '@archon-research/router-kit';\nimport { z } from 'zod';\n\nexport const TABS = ['overview', 'detail'] as const;\n\nexport const sharedSearchSchema = z.object({\n  q: textParam(),\n  tab: oneOfParam(TABS),\n});\n```\n\n`textParam()` trims and treats empty as absent. `oneOfParam(allowed)` keeps a\nvalue only if it is in the set — pass the set `as const` so the inferred type is\nthe literal union rather than `string`.\n\nEvery builder here is **total** and **idempotent**:\n\n- **Total** — no input fails, so `validateSearch` never rejects a URL. A\n  hand-edited, stale, or bot-mangled param degrades to absent and the route still\n  renders.\n- **Idempotent** — normalizing an already-normalized value, through a full\n  render-and-redecode round trip, returns it unchanged.\n\nIdempotence is not a nicety; step 2 does not terminate without it.\n\n### 2. Make the URL tell the truth\n\nThe schemas above drop values they cannot honour, but the address bar keeps them.\nSo `?range=90D` reads as ninety days of data next to a chart showing the default\n— and that is the URL that gets shared. `createValidatedSearchRedirect` closes\nthe gap on the root route: the URL is either the state on screen, or it is\nreplaced with the one that is.\n\n```ts\nimport { createValidatedSearchRedirect } from '@archon-research/router-kit';\nimport {\n  createRootRoute,\n  createRouter,\n  parseSearchWith,\n  stringifySearchWith,\n} from '@tanstack/react-router';\n\n// Params here are plain text; the default JSON round trip would write\n// `?rows=1` as `?rows=%221%22`.\nconst parseSearch = parseSearchWith((value: string) => value);\nconst stringifySearch = stringifySearchWith(JSON.stringify);\n\nconst rootRoute = createRootRoute({\n  validateSearch: sharedSearchSchema,\n  component: App,\n  beforeLoad: createValidatedSearchRedirect({ stringifySearch }),\n});\n\nexport const router = createRouter({\n  routeTree,\n  parseSearch,\n  stringifySearch,\n});\n```\n\nPass the **same** `stringifySearch` to both. It is the one function the helper\ncannot derive, and a mismatch means the cleanup rewrites to a URL the router\nreads differently — which shows up as an infinite redirect. Step 4 is what\ncatches that.\n\nTwo properties, both load-bearing:\n\n- **It redirects to an explicit `href`, not `to: '.'`.** A relative target\n  resolves against the *pending* location, which during a `beforeLoad` is the\n  location being navigated to, not necessarily the one whose params were just\n  validated.\n- **It requires total, idempotent schemas.** The rewritten URL is validated\n  again on arrival, so a param whose output fails to re-validate to itself\n  redirects forever.\n\n#### Declare it or lose it\n\nRead the mechanism literally: **any key no schema on the route declares is\ndeleted from the URL.** That is the feature — a stale `?range=90D` has to go —\nand it does not know what it is deleting. A param some *other* system owns is\nundeclared from this route's point of view, and it goes just as fast.\n\nThe way this is found in production is an OAuth callback. The provider returns\nthe user to `/callback?code=…&state=…`, the root cleanup runs first, and the\ncallback route reads an empty query string. The login fails, and nothing in the\nlogs mentions the URL. Same shape for a `?utm_source=…` a tag manager reads on\nload, or a `?session_id=…` a payment provider appends.\n\nTwo ways out, and the first is usually right:\n\n1. **Declare the key in a route schema.** Then it is typed, it is part of the\n   route's contract, and `useSearch` can read it.\n2. **Allowlist it**, for keys something outside the route tree owns:\n\n```ts\nbeforeLoad: createValidatedSearchRedirect({\n  stringifySearch,\n  preserveKeys: ['code', 'state'],\n});\n```\n\nAn allowlisted key is exempt from the deletion *and* from the comparison, so its\npresence never triggers a rewrite on its own, and it cannot be the param that\nfails to converge. List only keys no schema declares: a listed key never\noverrides a value validation produced, but for a value validation *rejected*\nthere is no applied value to lose to, so the rejected one survives in the address\nbar — which is the lie this whole step exists to remove.\n\nFor the sibling case — a value that moved out of the query string on one branch\nwhile shared links still carry the old key — `createSearchParamStripper` drops\none key and carries the rest across:\n\n```ts\nconst itemDetailRoute = createRoute({\n  getParentRoute: () => rootRoute,\n  path: '/items/$itemId',\n  // The id rides in the path here, so a leftover `?item=` names a second one\n  // that nothing reads.\n  beforeLoad: createSearchParamStripper('item', { stringifySearch }),\n});\n```\n\n### 3. Sync a table to the URL\n\n`createUrlSyncedTableAdapter` builds the adapter the design system's\n`useUrlSyncedTableStateAdapter` takes, reading two search keys and writing them\nback with replace semantics.\n\n```ts\nimport { useUrlSyncedTableStateAdapter } from '@archon-research/design-system';\nimport type { UseUrlSyncedTableReturn } from '@archon-research/design-system';\nimport { createUrlSyncedTableAdapter } from '@archon-research/router-kit';\nimport { useNavigate, useSearch } from '@tanstack/react-router';\nimport { useMemo } from 'react';\n\nexport function useItemsTableUrlState(): UseUrlSyncedTableReturn {\n  // Not strict: a table in a drawer can stay mounted on a route where this\n  // search does not exist, and both params then read as absent.\n  const search = useSearch({ from: '/items', shouldThrow: false });\n  const navigate = useNavigate();\n\n  const adapter = useMemo(\n    () =>\n      createUrlSyncedTableAdapter({\n        search,\n        sortKey: 'sort',\n        searchKey: 'q',\n        navigate,\n      }),\n    [search, navigate],\n  );\n\n  return useUrlSyncedTableStateAdapter(adapter);\n}\n```\n\nFour things worth knowing:\n\n- **`useMemo` is required, not tidy.** `useUrlSyncedTableStateAdapter` memoizes\n  the setters it returns *on the adapter object*, so a fresh object per render\n  makes `setGlobalFilter` a new reference every time. A debounced search commit\n  holding that reference as a dependency is then torn down and re-armed on every\n  unrelated re-render, and never fires under a burst of keystrokes.\n- **`useNavigate()`'s return value goes straight in.** No wrapper: the adapter\n  fixes all three navigation fields itself, and types each as the single value it\n  takes. It navigates with `to: '.'`, which keeps the current route's path params\n  without this package knowing your route tree. A relative target resolves\n  against the pending location if there is one, which is why it is wrong in a\n  `beforeLoad` (that runs *while* one is pending) and right from an event handler\n  (normally none is). The residual case is a write landing inside another\n  navigation's microtask window — a debounced search commit racing a link click.\n- **`sortKey` and `searchKey` have no defaults.** Two tables that silently share\n  `sort`/`q` leak whichever state was set last across every switch between them,\n  and it reads as a bug in the table rather than in the URL.\n- **The read is verbatim; the schema owns trimming.** A string param reaches the\n  table exactly as the URL holds it, whitespace included, so a write-read-write\n  round trip is lossless. It has to be: the hook renders `searchParam` back into\n  the search box, so an adapter that trimmed would make `'usd '` read back as\n  `'usd'`, land the next keystroke on `'usdc'`, and leave a two-word term\n  untypeable. Trim at the route boundary instead, where it is visible and\n  opt-out-able — `textParam()` does exactly that. Values the URL cannot mean (a\n  repeated key's array, an object) read as absent, and a number or boolean the\n  decoder produced reads as its text.\n\n### 4. Prove the entry URLs settle\n\n`settleEntryUrl` builds a memory-history router from **your exported\n`router.options`**, follows every `beforeLoad` redirect to a fixed point, and\nthrows if the chain never gets there.\n\n```ts\nimport { settleEntryUrl } from '@archon-research/router-kit/testing';\nimport { describe, expect, it } from 'vitest';\n\nimport { router } from '../src/router';\n\ndescribe('entry URLs', () => {\n  it.each([\n    '/',\n    '/items?tab=bogus',\n    '/items/42?item=7',\n    '/unknown/deep/path',\n  ])('settles %s', async (url) => {\n    await expect(settleEntryUrl(router.options, url)).resolves.toBeDefined();\n  });\n\n  it('rewrites a rejected param out of the address bar', async () => {\n    const settled = await settleEntryUrl(router.options, '/items?tab=bogus');\n\n    expect(settled.url).toBe('/items');\n  });\n});\n```\n\nBoth entry points are async, so `await` them. That is not incidental: a\n`beforeLoad` is often `async` — an auth guard or a context fetch — and its\nredirect then arrives as a rejected promise rather than a synchronous throw. A\nharness that did not await would report the *rejected* route as the settled one,\nso your spec would pass while production redirected somewhere else.\n\nIt takes `router.options` rather than a route tree on purpose. `parseSearch`,\n`stringifySearch`, `trailingSlash`, `caseSensitive`, and `basepath` all decide\nwhat a URL *means*; a harness that rebuilt them would assert against a grammar\nyour app does not use — passing while production breaks, or failing on a\ndifference that exists only in the test. There is one description of the\ngrammar, and it is the one the app runs with.\n\nEach throw covers a failure that is invisible from inside the app:\n\n- **Non-termination** is a hung tab with a spinning address bar. Here it is a\n  thrown error naming the cycle it walked. This is also what catches a\n  `stringifySearch` that disagrees with the router's.\n- **A schema that rejected the URL** is a thrown error naming the route and the\n  validation message. The router does not throw one: it records the rejection on\n  the match and carries on with a search no schema produced. So a harness that\n  did not look would report the one URL your schemas *could not* validate as\n  settled and clean. Step 1's builders are total, so this fires for a schema\n  that is not — a bare `z.number()` on a param, most often.\n\nIt does **not** assert that a hop replaces rather than pushes, because a\n`beforeLoad` redirect cannot push: every path that follows one overrides\n`replace: true` over the redirect's own options. Such an assertion would fail a\nperfectly good `throw redirect({ to: '/login' })` — `replace` undefined, replaced\nanyway. `resolveEntryUrl` still reports `replace` if you want to pin what your\nown helper *declares*.\n\nTwo options of yours are overridden rather than honoured, both because a\nheadless run cannot mean them: `isServer` is forced false (client mode is what\nmakes `beforeLoad` run the way a cold load runs it) and `scrollRestoration` is\nforced off. The second is not cosmetic — the router arms scroll restoration from\nits own constructor via bare `history` and `document` references, so leaving it\non would throw `ReferenceError: history is not defined` before a route was\nmatched, and every app that sets it would find the harness unusable. Neither\noption has any bearing on what a URL means.\n\nUnder a `basepath` (or a `rewrite`), `settled.url` and `settled.hops` come back\nin the **router's** spelling — `/items`, not `/app/items`. Both spellings of an\nentry URL resolve to the same route, so pass whichever you have; but a redirect\ntarget built inside a `beforeLoad` is written in the router's space, so reporting\nyour string verbatim would put two spellings of one URL in a single `hops` array.\nAssert against your route paths, the way you wrote them.\n\nKnown limit: the harness supplies a `beforeLoad` with `location`, `matches`,\n`params`, and `search`. A `beforeLoad` that reads route `context` or calls\n`navigate` fails loudly here rather than being silently skipped — entry-time\nredirects do not normally need either, and a loud failure is the point.\n\n## Peer-version policy\n\n| Peer                     | Range         |\n| ------------------------ | ------------- |\n| `@tanstack/react-router` | `^1.170.0`    |\n| `zod`                    | `^4.0.0`      |\n\nBoth are peers because a second copy of either would break something real:\n\n- **The router** carries its types through module augmentation. Your\n  `declare module '@tanstack/react-router' { interface Register { ... } }` binds\n  to one copy, so a second one leaves your route paths and search types\n  unavailable to it. React context is per-copy too, so hooks from one copy return\n  nothing inside the other's provider.\n- **zod** schemas built here are composed into `z.object({ ... })` in your app.\n  Schemas from two copies are not reliably interchangeable, and when they are\n  not, the failure reads as an opaque variance error at the route definition\n  rather than as a duplicate dependency.\n\nThe floor is the line this package is developed and tested against, and the caret\nmeans router and zod patch/minor upgrades do not need a release here. The one\nthing to know when upgrading the router: the cleanup and the harness both read\n`_strictSearch`, a router-internal field. It is stable in practice, and this\npackage's own suite fails loudly if it moves — but that is why the floor is\nrecorded rather than left open.\n\n`@archon-research/design-system` is **not** a dependency of this package, not\neven an optional peer. The table adapter's type is restated structurally; see\n[DESIGN.md](./DESIGN.md), which ships in the tarball alongside this file.\n\n## Exported surface\n\nFrom the root entry:\n\n| Export                            | Kind     | Module               |\n| --------------------------------- | -------- | -------------------- |\n| `toSearchText`                    | function | `search-params`      |\n| `toSearchOption`                  | function | `search-params`      |\n| `textParam`                       | function | `search-params`      |\n| `oneOfParam`                      | function | `search-params`      |\n| `SearchTextParam`                 | type     | `search-params`      |\n| `SearchOptionParam`               | type     | `search-params`      |\n| `createValidatedSearchRedirect`   | function | `validated-search`   |\n| `createSearchParamStripper`       | function | `validated-search`   |\n| `rendersSameSearch`               | function | `validated-search`   |\n| `SearchRecord`                    | type     | `validated-search`   |\n| `StringifySearch`                 | type     | `validated-search`   |\n| `CanonicalSearchOptions`          | type     | `validated-search`   |\n| `ValidatedSearchRedirectOptions`  | type     | `validated-search`   |\n| `ValidatedSearchContext`          | type     | `validated-search`   |\n| `SearchParamStripperContext`      | type     | `validated-search`   |\n| `createUrlSyncedTableAdapter`     | function | `table-adapter`      |\n| `UrlSyncedTableStateAdapter`      | type     | `table-adapter`      |\n| `UrlSyncedTableAdapterOptions`    | type     | `table-adapter`      |\n| `UrlSyncedTableNavigate`          | type     | `table-adapter`      |\n| `UrlSyncedTableNavigateOptions`   | type     | `table-adapter`      |\n\nFrom `@archon-research/router-kit/testing`:\n\n| Export                  | Kind     |\n| ----------------------- | -------- |\n| `settleEntryUrl`        | function |\n| `resolveEntryUrl`       | function |\n| `EntryRouterOptions`    | type     |\n| `EntryUrlResolution`    | type     |\n| `EntryRedirect`         | type     |\n| `EntryLeaf`             | type     |\n| `SettleEntryUrlOptions` | type     |\n| `SettledEntryUrl`       | type     |\n\nBoth functions return promises — see [step 4](#4-prove-the-entry-urls-settle).\n\n## See also\n\nSibling packages are linked by full URL, not by `../`: this file ships in the\npublished tarball, where a relative path to another package resolves to nothing.\n\n- [design-system](https://github.com/archon-research/uikit/tree/main/packages/design-system)\n  for `useUrlSyncedTableStateAdapter` and the `DataTable` this package's adapter\n  feeds\n- [http-client-react](https://github.com/archon-research/uikit/tree/main/packages/http-client-react)\n  for the TanStack Query layer that a future loader/query glue would have to\n  straddle (see [DESIGN.md](./DESIGN.md#loader-and-query-glue))\n","readmeFilename":"README.md"}