{"_id":"@batthewz/response-ui-renderer","_rev":"8-024266c113cd08faa00416bd23b8b76e","name":"@batthewz/response-ui-renderer","dist-tags":{"latest":"0.7.0"},"versions":{"0.1.0":{"name":"@batthewz/response-ui-renderer","version":"0.1.0","keywords":["design-system","react","json","renderer","server-driven-ui","response-ui","llm"],"author":{"name":"BatthewZ"},"license":"MIT","_id":"@batthewz/response-ui-renderer@0.1.0","maintainers":[{"name":"batthewz","email":"benmatthews.it@gmail.com"}],"homepage":"https://github.com/BatthewZ/response-ui-renderer#readme","bugs":{"url":"https://github.com/BatthewZ/response-ui-renderer/issues"},"dist":{"shasum":"9b529e40774bc341f5d889b2790c880c71fa4469","tarball":"https://registry.npmjs.org/@batthewz/response-ui-renderer/-/response-ui-renderer-0.1.0.tgz","fileCount":228,"integrity":"sha512-9Rofl1iytrexGXUGHJ+8crZLdxsjjAJB/gdBz8v6Y8n6dsir7dA4RmutO77CT0JwTPMgRDdMIZsoPXy8MwnyEw==","signatures":[{"sig":"MEUCICND0jeGmxlTPlLA/3AOyrwt9bR6nCuaObsOy0sJsuQrAiEAxUJf4UX3N+GXI8JBjTs04Dc/f2psNFljVU0WdDuZgY0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2111456},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./zod":{"types":"./dist/zod.d.ts","import":"./dist/zod.js"},"./spec":{"types":"./dist/spec/index.d.ts","import":"./dist/spec/index.js"},"./icons":{"types":"./dist/icons.d.ts","import":"./dist/icons.js"},"./styles":"./dist/styles.css","./examples":{"types":"./dist/examples/index.d.ts","import":"./dist/examples/index.js"}},"gitHead":"1055c49ca6e8433fb87f9d087d66bad1c44a1eed","scripts":{"dev":"vite --config dev/vite.config.ts","lint":"eslint src dev","test":"vitest run","build":"vite build","prepack":"bun run build","dev:build":"vite build --config dev/vite.config.ts","typecheck":"tsc --noEmit && eslint src dev","test:watch":"vitest","docs:viewspec":"node scripts/gen-viewspec-doc.mjs","prepublishOnly":"bun run build && bun run typecheck && bun run docs:viewspec -- --check && bun run test"},"_npmUser":{"name":"batthewz","email":"benmatthews.it@gmail.com"},"repository":{"url":"git+https://github.com/BatthewZ/response-ui-renderer.git","type":"git"},"_npmVersion":"10.8.2","description":"Render declarative JSON (ViewSpec) as @batthewz/response-ui-react-components. The machine-authorable layer of the response-ui design system.","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","zod":"^4.4.3","glob":"^13.0.6","vite":"^8.0.0","jsdom":"^29.0.1","react":"^19.2.0","eslint":"^9.0.0","vitest":"^4.1.2","react-dom":"^19.2.0","@eslint/js":"^10.0.1","typescript":"^5.9.0","@types/node":"^26.1.1","tailwindcss":"^4.3.3","@types/react":"^19.2.0","lucide-react":"^0.564.0","vite-plugin-dts":"^4.5.4","@types/react-dom":"^19.2.0","@tailwindcss/vite":"^4.3.3","typescript-eslint":"^8.55.0","@floating-ui/react":"^0.27.19","@vitejs/plugin-react":"^6.0.0","@testing-library/react":"^16.3.2","@batthewz/response-ui-css":"^0.14.0","@testing-library/jest-dom":"^6.9.1","@testing-library/user-event":"^14.6.1","eslint-plugin-simple-import-sort":"^12.1.1","@batthewz/response-ui-react-components":"^0.17.1"},"peerDependencies":{"zod":"^4.0.0","react":"^19.0.0","react-dom":"^19.0.0","lucide-react":">=0.500.0 <2.0.0","@floating-ui/react":"^0.27.0","@batthewz/response-ui-react-components":"^0.17.1"},"peerDependenciesMeta":{"zod":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/response-ui-renderer_0.1.0_1786169535110_0.26665577200315393","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@batthewz/response-ui-renderer","version":"0.2.0","keywords":["design-system","react","json","renderer","server-driven-ui","response-ui","llm"],"author":{"name":"BatthewZ"},"license":"MIT","_id":"@batthewz/response-ui-renderer@0.2.0","maintainers":[{"name":"batthewz","email":"benmatthews.it@gmail.com"}],"homepage":"https://github.com/BatthewZ/response-ui-renderer#readme","bugs":{"url":"https://github.com/BatthewZ/response-ui-renderer/issues"},"dist":{"shasum":"ec59c27f07bdcc58d0c9067dfbb8041582aa4242","tarball":"https://registry.npmjs.org/@batthewz/response-ui-renderer/-/response-ui-renderer-0.2.0.tgz","fileCount":233,"integrity":"sha512-B3tqK7g08HKNXwAPObejgQDA+Z5VBS9YtCqjOvoVr1geTOCjr5pKDiJb0HkJPgVNKyM7mUGZWHMwOabyafoomg==","signatures":[{"sig":"MEYCIQDY/OC2ZZJa8VB0APf4SBHFAS32XNdXmPzDlS3K/5MyyAIhAKlwu5ujBboFz0z1Bc4ZN4y0hvIZ53sQZ8VWV3FHAwSG","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2169056},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./zod":{"types":"./dist/zod.d.ts","import":"./dist/zod.js"},"./spec":{"types":"./dist/spec/index.d.ts","import":"./dist/spec/index.js"},"./icons":{"types":"./dist/icons.d.ts","import":"./dist/icons.js"},"./styles":"./dist/styles.css","./examples":{"types":"./dist/examples/index.d.ts","import":"./dist/examples/index.js"}},"gitHead":"fcb2f10edc1a3022686843ae10256bfa964b1892","scripts":{"dev":"vite --config dev/vite.config.ts","lint":"eslint src dev","test":"vitest run","build":"vite build","prepack":"bun run build","dev:build":"vite build --config dev/vite.config.ts","typecheck":"tsc --noEmit && eslint src dev","test:watch":"vitest","docs:viewspec":"node scripts/gen-viewspec-doc.mjs","prepublishOnly":"bun run build && bun run typecheck && bun run docs:viewspec -- --check && bun run test"},"_npmUser":{"name":"batthewz","email":"benmatthews.it@gmail.com"},"repository":{"url":"git+https://github.com/BatthewZ/response-ui-renderer.git","type":"git"},"_npmVersion":"10.8.2","description":"Render declarative JSON (ViewSpec) as @batthewz/response-ui-react-components. The machine-authorable layer of the response-ui design system.","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","zod":"^4.4.3","glob":"^13.0.6","vite":"^8.0.0","jsdom":"^29.0.1","react":"^19.2.0","eslint":"^9.0.0","vitest":"^4.1.2","react-dom":"^19.2.0","@eslint/js":"^10.0.1","typescript":"^5.9.0","@types/node":"^26.1.1","tailwindcss":"^4.3.3","@types/react":"^19.2.0","lucide-react":"^0.564.0","vite-plugin-dts":"^4.5.4","@types/react-dom":"^19.2.0","@tailwindcss/vite":"^4.3.3","typescript-eslint":"^8.55.0","@floating-ui/react":"^0.27.19","@vitejs/plugin-react":"^6.0.0","@testing-library/react":"^16.3.2","@batthewz/response-ui-css":"^0.14.0","@testing-library/jest-dom":"^6.9.1","@testing-library/user-event":"^14.6.1","eslint-plugin-simple-import-sort":"^12.1.1","@batthewz/response-ui-react-components":"^0.18.0"},"peerDependencies":{"zod":"^4.0.0","react":"^19.0.0","react-dom":"^19.0.0","lucide-react":">=0.500.0 <2.0.0","@floating-ui/react":"^0.27.0","@batthewz/response-ui-react-components":"^0.18.0"},"peerDependenciesMeta":{"zod":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/response-ui-renderer_0.2.0_1786238741436_0.10279546762551339","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@batthewz/response-ui-renderer","version":"0.2.1","keywords":["design-system","react","json","renderer","server-driven-ui","response-ui","llm"],"author":{"name":"BatthewZ"},"license":"MIT","_id":"@batthewz/response-ui-renderer@0.2.1","maintainers":[{"name":"batthewz","email":"benmatthews.it@gmail.com"}],"homepage":"https://github.com/BatthewZ/response-ui-renderer#readme","bugs":{"url":"https://github.com/BatthewZ/response-ui-renderer/issues"},"dist":{"shasum":"abab9231b67cd64e8bb5f26958177b37820953d3","tarball":"https://registry.npmjs.org/@batthewz/response-ui-renderer/-/response-ui-renderer-0.2.1.tgz","fileCount":233,"integrity":"sha512-8taeGUWAnB5qNk+3krQHc02dPSrlXGBfN9HQVjMtfVSAOtbXsiOfZve80G6L/1zk0e63Kik9LuxO9PfWAlHGVw==","signatures":[{"sig":"MEUCID508A1uSVpmO6gqxoPZwqA/KSQGLgFpeemzUxqzCixJAiEAuqYIUfw0YWD5MI+Y0O9J+4qNf7nuav0dhL3YKQc32Mc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2171383},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./zod":{"types":"./dist/zod.d.ts","import":"./dist/zod.js"},"./spec":{"types":"./dist/spec/index.d.ts","import":"./dist/spec/index.js"},"./icons":{"types":"./dist/icons.d.ts","import":"./dist/icons.js"},"./styles":"./dist/styles.css","./examples":{"types":"./dist/examples/index.d.ts","import":"./dist/examples/index.js"}},"gitHead":"800aece4c337a40d66a0dfbf15a4567997b25db3","scripts":{"dev":"vite --config dev/vite.config.ts","lint":"eslint src dev","test":"vitest run","build":"vite build","prepack":"bun run build","dev:build":"vite build --config dev/vite.config.ts","typecheck":"tsc --noEmit && eslint src dev","test:watch":"vitest","docs:viewspec":"node scripts/gen-viewspec-doc.mjs","prepublishOnly":"bun run build && bun run typecheck && bun run docs:viewspec -- --check && bun run test"},"_npmUser":{"name":"batthewz","email":"benmatthews.it@gmail.com"},"repository":{"url":"git+https://github.com/BatthewZ/response-ui-renderer.git","type":"git"},"_npmVersion":"10.8.2","description":"Render declarative JSON (ViewSpec) as @batthewz/response-ui-react-components. The machine-authorable layer of the response-ui design system.","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","zod":"^4.4.3","glob":"^13.0.6","vite":"^8.0.0","jsdom":"^29.0.1","react":"^19.2.0","eslint":"^9.0.0","vitest":"^4.1.2","react-dom":"^19.2.0","@eslint/js":"^10.0.1","typescript":"^5.9.0","@types/node":"^26.1.1","tailwindcss":"^4.3.3","@types/react":"^19.2.0","lucide-react":"^0.564.0","vite-plugin-dts":"^4.5.4","@types/react-dom":"^19.2.0","@tailwindcss/vite":"^4.3.3","typescript-eslint":"^8.55.0","@floating-ui/react":"^0.27.19","@vitejs/plugin-react":"^6.0.0","@testing-library/react":"^16.3.2","@batthewz/response-ui-css":"^0.14.0","@testing-library/jest-dom":"^6.9.1","@testing-library/user-event":"^14.6.1","eslint-plugin-simple-import-sort":"^12.1.1","@batthewz/response-ui-react-components":"^0.18.0"},"peerDependencies":{"zod":"^4.0.0","react":"^19.0.0","react-dom":"^19.0.0","lucide-react":">=0.500.0 <2.0.0","@floating-ui/react":"^0.27.0","@batthewz/response-ui-react-components":"^0.18.0"},"peerDependenciesMeta":{"zod":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/response-ui-renderer_0.2.1_1786240167607_0.59542725752829","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@batthewz/response-ui-renderer","version":"0.3.0","keywords":["design-system","react","json","renderer","server-driven-ui","response-ui","llm"],"author":{"name":"BatthewZ"},"license":"MIT","_id":"@batthewz/response-ui-renderer@0.3.0","maintainers":[{"name":"batthewz","email":"benmatthews.it@gmail.com"}],"homepage":"https://github.com/BatthewZ/response-ui-renderer#readme","bugs":{"url":"https://github.com/BatthewZ/response-ui-renderer/issues"},"dist":{"shasum":"b2d0b6eda8016d7eb85b8c4afe890a0c7d3ab10e","tarball":"https://registry.npmjs.org/@batthewz/response-ui-renderer/-/response-ui-renderer-0.3.0.tgz","fileCount":260,"integrity":"sha512-f1x5dVB2OVq8xmuOdHkeSRKYi0w+Q8OigjyobN/kIIYfPPEmmB/PqrYBN4+PtD2HbTDx+keZJ3koX8fZuFKCoA==","signatures":[{"sig":"MEUCIAuP5bPJ1SChfKiW4eMPjPsjpyQ4wkndfgsGMdw1iIFYAiEAyhioz19Mv7qlZ0ERK7QwJ59nxHVSdLhJOgWLqTWYqA8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2642835},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./zod":{"types":"./dist/zod.d.ts","import":"./dist/zod.js"},"./spec":{"types":"./dist/spec/index.d.ts","import":"./dist/spec/index.js"},"./icons":{"types":"./dist/icons.d.ts","import":"./dist/icons.js"},"./styles":"./dist/styles.css","./examples":{"types":"./dist/examples/index.d.ts","import":"./dist/examples/index.js"},"./reference":{"types":"./dist/reference/index.d.ts","import":"./dist/reference/index.js"}},"gitHead":"fec26e2ea2d743b42d99eb62eb6d3eae019fed56","scripts":{"dev":"vite --config dev/vite.config.ts","lint":"eslint src dev test-setup.ts test-utils.ts","test":"vitest run","build":"vite build","prepack":"bun run build","dev:build":"vite build --config dev/vite.config.ts","typecheck":"tsc --noEmit && eslint src dev test-setup.ts test-utils.ts","test:watch":"vitest","docs:viewspec":"bun scripts/gen-viewspec-doc.mjs","prepublishOnly":"bun run build && bun run typecheck && bun run docs:viewspec -- --check && bun run test"},"_npmUser":{"name":"batthewz","email":"benmatthews.it@gmail.com"},"repository":{"url":"git+https://github.com/BatthewZ/response-ui-renderer.git","type":"git"},"_npmVersion":"10.8.2","description":"Render declarative JSON (ViewSpec) as @batthewz/response-ui-react-components. The machine-authorable layer of the response-ui design system.","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","zod":"^4.4.3","glob":"^13.0.6","vite":"^8.0.0","jsdom":"^29.0.1","react":"^19.2.0","eslint":"^9.0.0","vitest":"^4.1.2","react-dom":"^19.2.0","@eslint/js":"^10.0.1","typescript":"^5.9.0","@types/node":"^26.1.1","tailwindcss":"^4.3.3","@types/react":"^19.2.0","lucide-react":"^0.564.0","vite-plugin-dts":"^4.5.4","@types/react-dom":"^19.2.0","@tailwindcss/vite":"^4.3.3","typescript-eslint":"^8.55.0","@floating-ui/react":"^0.27.19","@vitejs/plugin-react":"^6.0.0","@testing-library/react":"^16.3.2","@batthewz/response-ui-css":"^0.14.0","@testing-library/jest-dom":"^6.9.1","@testing-library/user-event":"^14.6.1","eslint-plugin-simple-import-sort":"^12.1.1","@batthewz/response-ui-react-components":"^0.18.0"},"peerDependencies":{"zod":"^4.0.0","react":"^19.0.0","react-dom":"^19.0.0","lucide-react":">=0.500.0 <2.0.0","@floating-ui/react":"^0.27.0","@batthewz/response-ui-react-components":"^0.18.0"},"peerDependenciesMeta":{"zod":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/response-ui-renderer_0.3.0_1786261485301_0.25994563436815343","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@batthewz/response-ui-renderer","version":"0.4.0","keywords":["design-system","react","json","renderer","server-driven-ui","response-ui","llm"],"author":{"name":"BatthewZ"},"license":"MIT","_id":"@batthewz/response-ui-renderer@0.4.0","maintainers":[{"name":"batthewz","email":"benmatthews.it@gmail.com"}],"homepage":"https://github.com/BatthewZ/response-ui-renderer#readme","bugs":{"url":"https://github.com/BatthewZ/response-ui-renderer/issues"},"dist":{"shasum":"a7632d1eb5bf9bbcaa1d3f4c33f26e08c6d3316d","tarball":"https://registry.npmjs.org/@batthewz/response-ui-renderer/-/response-ui-renderer-0.4.0.tgz","fileCount":260,"integrity":"sha512-2iL6BwEcPInYP9w97yr+4bOHQV8pWeWdfvO4KX1grNe0MEf1exI6Ua83ZxO30w8+FX+4RaiEaZtjI0AAre6XNQ==","signatures":[{"sig":"MEQCICTg7awN/qHo1Gl3mS54i2Bt+6B2OI8+0OAH8HRhnH6lAiBkb8ijjrtdYrbp58vBbtAJNvN62r+WDRTLL39Hf9eeuQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2645481},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./zod":{"types":"./dist/zod.d.ts","import":"./dist/zod.js"},"./spec":{"types":"./dist/spec/index.d.ts","import":"./dist/spec/index.js"},"./icons":{"types":"./dist/icons.d.ts","import":"./dist/icons.js"},"./styles":"./dist/styles.css","./examples":{"types":"./dist/examples/index.d.ts","import":"./dist/examples/index.js"},"./reference":{"types":"./dist/reference/index.d.ts","import":"./dist/reference/index.js"}},"gitHead":"676cc7ede5fc4dfb60e23e2a24d46ef2adb94009","scripts":{"dev":"vite --config dev/vite.config.ts","lint":"eslint src dev test-setup.ts test-utils.ts","test":"vitest run","build":"vite build","prepack":"bun run build","dev:build":"vite build --config dev/vite.config.ts","typecheck":"tsc --noEmit && eslint src dev test-setup.ts test-utils.ts","test:watch":"vitest","docs:viewspec":"bun scripts/gen-viewspec-doc.mjs","prepublishOnly":"bun run build && bun run typecheck && bun run docs:viewspec -- --check && bun run test"},"_npmUser":{"name":"batthewz","email":"benmatthews.it@gmail.com"},"repository":{"url":"git+https://github.com/BatthewZ/response-ui-renderer.git","type":"git"},"_npmVersion":"10.8.2","description":"Render declarative JSON (ViewSpec) as @batthewz/response-ui-react-components. The machine-authorable layer of the response-ui design system.","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","zod":"^4.4.3","glob":"^13.0.6","vite":"^8.2.0","jsdom":"^29.1.1","react":"^19.2.8","eslint":"^9.39.5","vitest":"^4.1.10","react-dom":"^19.2.8","@eslint/js":"^10.0.1","typescript":"^5.9.3","@types/node":"^26.1.2","tailwindcss":"^4.3.3","@types/react":"^19.2.18","lucide-react":"^0.564.0","vite-plugin-dts":"^4.5.4","@types/react-dom":"^19.2.4","@tailwindcss/vite":"^4.3.3","typescript-eslint":"^8.65.0","@floating-ui/react":"^0.27.20","@vitejs/plugin-react":"^6.0.5","@testing-library/react":"^16.3.2","@batthewz/response-ui-css":"^0.14.0","@testing-library/jest-dom":"^6.10.0","@testing-library/user-event":"^14.6.1","eslint-plugin-simple-import-sort":"^12.1.1","@batthewz/response-ui-react-components":"^0.19.0"},"peerDependencies":{"zod":"^4.0.0","react":"^19.0.0","react-dom":"^19.0.0","lucide-react":">=0.500.0 <2.0.0","@floating-ui/react":"^0.27.0","@batthewz/response-ui-react-components":"^0.19.0"},"peerDependenciesMeta":{"zod":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/response-ui-renderer_0.4.0_1786316676494_0.8732654302953284","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@batthewz/response-ui-renderer","version":"0.5.0","keywords":["design-system","react","json","renderer","server-driven-ui","response-ui","llm"],"author":{"name":"BatthewZ"},"license":"MIT","_id":"@batthewz/response-ui-renderer@0.5.0","maintainers":[{"name":"batthewz","email":"benmatthews.it@gmail.com"}],"homepage":"https://github.com/BatthewZ/response-ui-renderer#readme","bugs":{"url":"https://github.com/BatthewZ/response-ui-renderer/issues"},"dist":{"shasum":"e65f67c709cd7542acaa1965751c6579dd8eead4","tarball":"https://registry.npmjs.org/@batthewz/response-ui-renderer/-/response-ui-renderer-0.5.0.tgz","fileCount":265,"integrity":"sha512-ZmXjjTRb/0aQPzoiMX3auxKCQrAJv9j9umpcBKaAjHg8xtIYxGT+BaQIXhv2oflMXSs/FbM2iifYGmp/hdsoPw==","signatures":[{"sig":"MEUCIQD7UCS5PVpz2tOMp+PcDZgZW92u5DBLodMyL2VBOHILsAIgXAVGVWgTwVxsJb7z+HK1sgPDR9IWBJz9OGmUiDFM0sM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2748656},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./zod":{"types":"./dist/zod.d.ts","import":"./dist/zod.js"},"./spec":{"types":"./dist/spec/index.d.ts","import":"./dist/spec/index.js"},"./icons":{"types":"./dist/icons.d.ts","import":"./dist/icons.js"},"./styles":"./dist/styles.css","./examples":{"types":"./dist/examples/index.d.ts","import":"./dist/examples/index.js"},"./reference":{"types":"./dist/reference/index.d.ts","import":"./dist/reference/index.js"}},"gitHead":"8cce2ef0c614185f190352ed5f384cfd47844e13","scripts":{"dev":"vite --config dev/vite.config.ts","lint":"eslint src dev test-setup.ts test-utils.ts","test":"vitest run","build":"vite build","prepack":"bun run build","dev:build":"vite build --config dev/vite.config.ts","typecheck":"tsc --noEmit && eslint src dev test-setup.ts test-utils.ts","test:watch":"vitest","docs:viewspec":"bun scripts/gen-viewspec-doc.mjs","prepublishOnly":"bun run build && bun run typecheck && bun run docs:viewspec -- --check && bun run test"},"_npmUser":{"name":"batthewz","email":"benmatthews.it@gmail.com"},"repository":{"url":"git+https://github.com/BatthewZ/response-ui-renderer.git","type":"git"},"_npmVersion":"10.8.2","description":"Render declarative JSON (ViewSpec) as @batthewz/response-ui-react-components. The machine-authorable layer of the response-ui design system.","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","zod":"^4.4.3","glob":"^13.0.6","vite":"^8.2.0","jsdom":"^29.1.1","react":"^19.2.8","eslint":"^9.39.5","vitest":"^4.1.10","react-dom":"^19.2.8","@eslint/js":"^10.0.1","typescript":"^5.9.3","@types/node":"^26.1.2","tailwindcss":"^4.3.3","@types/react":"^19.2.18","lucide-react":"^0.564.0","vite-plugin-dts":"^4.5.4","@types/react-dom":"^19.2.4","@tailwindcss/vite":"^4.3.3","typescript-eslint":"^8.66.0","@floating-ui/react":"^0.27.20","@vitejs/plugin-react":"^6.0.5","@testing-library/react":"^16.3.2","@batthewz/response-ui-css":"^0.15.0","@testing-library/jest-dom":"^6.10.0","@testing-library/user-event":"^14.6.3","eslint-plugin-simple-import-sort":"^12.1.1","@batthewz/response-ui-react-components":"^0.20.0"},"peerDependencies":{"zod":"^4.0.0","react":"^19.0.0","react-dom":"^19.0.0","lucide-react":">=0.500.0 <2.0.0","@floating-ui/react":"^0.27.0","@batthewz/response-ui-react-components":"^0.20.0"},"peerDependenciesMeta":{"zod":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/response-ui-renderer_0.5.0_1786421507839_0.246284837524974","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@batthewz/response-ui-renderer","version":"0.6.0","keywords":["design-system","react","json","renderer","server-driven-ui","response-ui","llm"],"author":{"name":"BatthewZ"},"license":"MIT","_id":"@batthewz/response-ui-renderer@0.6.0","maintainers":[{"name":"batthewz","email":"benmatthews.it@gmail.com"}],"homepage":"https://github.com/BatthewZ/response-ui-renderer#readme","bugs":{"url":"https://github.com/BatthewZ/response-ui-renderer/issues"},"dist":{"shasum":"764e7f378e361949abe87bb2610a74bebee1d7f8","tarball":"https://registry.npmjs.org/@batthewz/response-ui-renderer/-/response-ui-renderer-0.6.0.tgz","fileCount":265,"integrity":"sha512-JQiAuyZ7VEUcIs48QiKZxaxf3PeojCGYrSv6jJdnIIWLvHt4yHtAZuehp4DPxJ6Xn9eIWek7lXTVc/f6M4tFmg==","signatures":[{"sig":"MEUCIQC3pR6e4gzNl/W/Wj9cbzUL2RINyog/T7wl/zSiBxzqsAIgYPwqjebyWCLd/acRYFY+uOXquhgAPoQY+FC49/6L92M=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2748656},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./zod":{"types":"./dist/zod.d.ts","import":"./dist/zod.js"},"./spec":{"types":"./dist/spec/index.d.ts","import":"./dist/spec/index.js"},"./icons":{"types":"./dist/icons.d.ts","import":"./dist/icons.js"},"./styles":"./dist/styles.css","./examples":{"types":"./dist/examples/index.d.ts","import":"./dist/examples/index.js"},"./reference":{"types":"./dist/reference/index.d.ts","import":"./dist/reference/index.js"}},"gitHead":"4c9730bc335aa60ce97f561427cd10119c352e61","scripts":{"dev":"vite --config dev/vite.config.ts","lint":"eslint src dev test-setup.ts test-utils.ts","test":"vitest run","build":"vite build","prepack":"bun run build","dev:build":"vite build --config dev/vite.config.ts","typecheck":"tsc --noEmit && eslint src dev test-setup.ts test-utils.ts","test:watch":"vitest","docs:viewspec":"bun scripts/gen-viewspec-doc.mjs","prepublishOnly":"bun run build && bun run typecheck && bun run docs:viewspec -- --check && bun run test"},"_npmUser":{"name":"batthewz","email":"benmatthews.it@gmail.com"},"repository":{"url":"git+https://github.com/BatthewZ/response-ui-renderer.git","type":"git"},"_npmVersion":"10.8.2","description":"Render declarative JSON (ViewSpec) as @batthewz/response-ui-react-components. The machine-authorable layer of the response-ui design system.","directories":{},"sideEffects":false,"_nodeVersion":"22.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","zod":"^4.4.3","glob":"^13.0.6","vite":"^8.2.0","jsdom":"^29.1.1","react":"^19.2.8","eslint":"^9.39.5","vitest":"^4.1.10","react-dom":"^19.2.8","@eslint/js":"^10.0.1","typescript":"^5.9.3","@types/node":"^26.1.2","tailwindcss":"^4.3.3","@types/react":"^19.2.18","lucide-react":"^0.564.0","vite-plugin-dts":"^4.5.4","@types/react-dom":"^19.2.4","@tailwindcss/vite":"^4.3.3","typescript-eslint":"^8.66.0","@floating-ui/react":"^0.27.20","@vitejs/plugin-react":"^6.0.5","@testing-library/react":"^16.3.2","@batthewz/response-ui-css":"^0.15.0","@testing-library/jest-dom":"^6.10.0","@testing-library/user-event":"^14.6.3","eslint-plugin-simple-import-sort":"^12.1.1","@batthewz/response-ui-react-components":"^0.20.0"},"peerDependencies":{"zod":"^4.0.0","react":"^19.0.0","react-dom":"^19.0.0","lucide-react":">=0.500.0 <2.0.0","@floating-ui/react":"^0.27.0","@batthewz/response-ui-react-components":"^0.20.0"},"peerDependenciesMeta":{"zod":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/response-ui-renderer_0.6.0_1786421645393_0.41892040869413094","host":"s3://npm-registry-packages-npm-production"}},"0.7.0":{"name":"@batthewz/response-ui-renderer","version":"0.7.0","type":"module","description":"Render declarative JSON (ViewSpec) as @batthewz/response-ui-react-components. The machine-authorable layer of the response-ui design system.","sideEffects":false,"main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./spec":{"types":"./dist/spec/index.d.ts","import":"./dist/spec/index.js"},"./icons":{"types":"./dist/icons.d.ts","import":"./dist/icons.js"},"./zod":{"types":"./dist/zod.d.ts","import":"./dist/zod.js"},"./styles":"./dist/styles.css","./examples":{"types":"./dist/examples/index.d.ts","import":"./dist/examples/index.js"},"./reference":{"types":"./dist/reference/index.d.ts","import":"./dist/reference/index.js"}},"publishConfig":{"access":"public"},"scripts":{"build":"vite build","prepack":"bun run build","typecheck":"tsc --noEmit && eslint src dev test-setup.ts test-utils.ts","lint":"eslint src dev test-setup.ts test-utils.ts","test":"vitest run","test:watch":"vitest","prepublishOnly":"bun run build && bun run typecheck && bun run docs:viewspec -- --check && bun run test","dev":"vite --config dev/vite.config.ts","dev:build":"vite build --config dev/vite.config.ts","docs:viewspec":"bun scripts/gen-viewspec-doc.mjs"},"peerDependencies":{"@batthewz/response-ui-react-components":"^0.21.0","@floating-ui/react":"^0.27.0","lucide-react":">=0.500.0 <2.0.0","react":"^19.0.0","react-dom":"^19.0.0","zod":"^4.0.0"},"peerDependenciesMeta":{"zod":{"optional":true}},"devDependencies":{"@batthewz/response-ui-css":"^0.15.0","@batthewz/response-ui-react-components":"^0.21.0","@eslint/js":"^10.0.1","@floating-ui/react":"^0.27.20","@tailwindcss/vite":"^4.3.3","@testing-library/jest-dom":"^6.10.0","@testing-library/react":"^16.3.2","@testing-library/user-event":"^14.6.3","@types/node":"^26.1.2","@types/react":"^19.2.18","@types/react-dom":"^19.2.4","@vitejs/plugin-react":"^6.0.5","ajv":"^8.20.0","eslint":"^9.39.5","eslint-plugin-simple-import-sort":"^12.1.1","glob":"^13.0.6","jsdom":"^29.1.1","lucide-react":"^0.564.0","react":"^19.2.8","react-dom":"^19.2.8","tailwindcss":"^4.3.3","typescript":"^5.9.3","typescript-eslint":"^8.66.0","vite":"^8.2.0","vite-plugin-dts":"^4.5.4","vitest":"^4.1.10","zod":"^4.4.3"},"keywords":["design-system","react","json","renderer","server-driven-ui","response-ui","llm"],"license":"MIT","repository":{"type":"git","url":"git+https://github.com/BatthewZ/response-ui-renderer.git"},"homepage":"https://github.com/BatthewZ/response-ui-renderer#readme","bugs":{"url":"https://github.com/BatthewZ/response-ui-renderer/issues"},"author":{"name":"BatthewZ"},"_id":"@batthewz/response-ui-renderer@0.7.0","gitHead":"bf5cbb13e355f84f0c14c52ee828ae2a62a28bc8","_nodeVersion":"22.18.0","_npmVersion":"10.8.2","dist":{"integrity":"sha512-ySf6OFOUQTgfel6NlTAN+ksixGAL9wUPyOm3Db/2Xh7vahdV3lR8ymZ0FfqxyXaxtln8eX/sOl2220lxdhGGLg==","shasum":"cb076cd65e8b43c9ac15a1b9d36fb06f91c169f3","tarball":"https://registry.npmjs.org/@batthewz/response-ui-renderer/-/response-ui-renderer-0.7.0.tgz","fileCount":265,"unpackedSize":2750988,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCbCepGRT2HwFS0aKoLyOanuUIFyYo8MttrXVljn+VouQIgJ/LCZ7lwgxyg7T9ukItPIJ8PubGjQNSQDd1QSnzoKo0="}]},"_npmUser":{"name":"batthewz","email":"benmatthews.it@gmail.com"},"directories":{},"maintainers":[{"name":"batthewz","email":"benmatthews.it@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/response-ui-renderer_0.7.0_1786424470331_0.24378201768687124"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-08T06:12:14.936Z","modified":"2026-08-11T05:01:10.730Z","0.1.0":"2026-08-08T06:12:15.273Z","0.2.0":"2026-08-09T01:25:41.611Z","0.2.1":"2026-08-09T01:49:27.775Z","0.3.0":"2026-08-09T07:44:45.443Z","0.4.0":"2026-08-09T23:04:36.674Z","0.5.0":"2026-08-11T04:11:47.981Z","0.6.0":"2026-08-11T04:14:05.585Z","0.7.0":"2026-08-11T05:01:10.516Z"},"bugs":{"url":"https://github.com/BatthewZ/response-ui-renderer/issues"},"author":{"name":"BatthewZ"},"license":"MIT","homepage":"https://github.com/BatthewZ/response-ui-renderer#readme","keywords":["design-system","react","json","renderer","server-driven-ui","response-ui","llm"],"repository":{"type":"git","url":"git+https://github.com/BatthewZ/response-ui-renderer.git"},"description":"Render declarative JSON (ViewSpec) as @batthewz/response-ui-react-components. The machine-authorable layer of the response-ui design system.","maintainers":[{"name":"batthewz","email":"benmatthews.it@gmail.com"}],"readme":"# @batthewz/response-ui-renderer\n\n**Let a model build a page inside your app, without shipping code it wrote.**\n\nA producer — an LLM, a CMS, your own backend — emits a **ViewSpec**: plain JSON describing a view. You mount it. What renders is a themed, interactive page assembled from [`@batthewz/response-ui-react-components`](https://github.com/BatthewZ/response-ui-react-components), your own component library, with no per-component glue and no generated code in your users' browsers.\n\n```tsx\nimport { ViewRenderer } from \"@batthewz/response-ui-renderer\";\n\n<ViewRenderer spec={await res.json()} />;\n```\n\n**[Try it in the playground →](https://batthewz.github.io/response-ui-renderer/)** — edit a document, watch it render, retheme it from its own JSON. Nothing to install.\n\n- **Every component the library exports is addressable, and proven to render.** 101 components and 73 compound parts, derived from the library's own barrel at runtime — not a hand-copied list — and a coverage corpus renders every one of them. 7 need host code; they are named, with the reason, in [VIEWSPEC.md](VIEWSPEC.md).\n- **Zero runtime dependencies.** React and response-ui are peers; nothing else ships.\n- **Host-agnostic.** No router, no server routes, no auth model. Navigation, network and toasts are injected.\n- **Extensible to your own components.** Register them, declare a contract, and the renderer translates their props, the validator checks them and the reference documents them — through the same code that serves the library's own, not a parallel path.\n- **Hardened for machine-generated input.** Per-node error boundaries, prototype-safe lookups, forbidden-prop stripping, URL-scheme filtering, depth limits.\n\n---\n\n## Why a document, and not model-written HTML?\n\nA model can emit HTML directly, so it is fair to ask what the JSON detour buys. The difference is categorical: generated HTML+JS is a **program** you have to trust, sandbox and freeze, while a ViewSpec is **data** you can validate against a contract. Everything this package offers follows from that. (The underlying pattern is server-driven UI — the architecture Airbnb, Lyft and Shopify run natively — with a model as one possible author.)\n\n**Safety is structural, not best-effort.** A document cannot do anything the renderer does not allow: there is no script to inject, events come from a fixed action vocabulary, and you decide what `navigate`, `fetch` and `resolveSource` actually do. Model-authored HTML is arbitrary code running in your users' browsers, mitigable only with sandboxed iframes — and the sandbox that makes it safe also cuts it off from your app's navigation, state and toasts, which a document reaches through adapters.\n\n**The data never passes through the model.** An `api` or `source` binding means the model designs the *shape* of a view while the client fetches the numbers — with the user's own credentials, at render time. The model needs no access to the data it is presenting, a cached document stays live, and one document serves every tenant. Generated HTML either bakes stale data into the markup or ships model-written fetch code you then have to trust.\n\n**Consistency and accessibility come from the components.** Every view is assembled from your themed, focus-managed, ARIA-correct component library, so it lands looking native to your app and follows its theme — including one it has never seen. Model-authored markup reliably gets both wrong, and no prompt fully fixes that.\n\n**A document has a lifecycle a blob does not.** JSON can be validated before render (and regenerated on failure), diffed, patched — \"make that a bar chart\" is a small edit, not a regeneration — stored, and re-rendered better later: upgrade the component library and every stored document picks up the improvement. An HTML blob is frozen at generation time. A ViewSpec is also a fraction of the tokens of the equivalent HTML+CSS+JS, which compounds when generation happens per request rather than once.\n\n**What it costs.** Expressiveness is bounded by the registry: a document composes what is registered, and while [custom components](#custom-components) raise the ceiling, a genuinely novel visualization or bespoke interaction is outside the format on purpose. For a one-off, self-contained artifact that will never live inside your app — a shareable page, a throwaway prototype — letting the model write HTML is the better tool. This package is for UI that lives inside a product: matching its design language, bound to live authenticated data, interactive without shipping code, generated repeatedly, cached.\n\n---\n\n## Install\n\n```bash\nbun add @batthewz/response-ui-renderer @batthewz/response-ui-react-components \\\n  @batthewz/response-ui-css react react-dom @floating-ui/react lucide-react\n```\n\nThree CSS imports, in this order:\n\n```css\n@import \"@batthewz/response-ui-css\";                      /* tokens, scales, `default` theme */\n@import \"@batthewz/response-ui-react-components/styles\";  /* component CSS */\n@import \"@batthewz/response-ui-renderer/styles\";          /* renderer diagnostics */\n```\n\nOrder matters — each layer reads `var(--…)` from the one before it. Tailwind v4 must be in your build.\n\n### Your first document\n\nThe document. Nothing here is special-cased — `Card`, `Text` and `Button` are ordinary exports of the component library, addressed by name:\n\n```json\n{\n  \"version\": 1,\n  \"title\": \"Hello\",\n  \"root\": {\n    \"component\": \"Card\",\n    \"props\": { \"padding\": \"r4\" },\n    \"children\": [\n      { \"component\": \"Text\", \"props\": { \"variant\": \"h3\" }, \"children\": [\"It renders.\"] },\n      {\n        \"component\": \"Button\",\n        \"props\": { \"onClick\": { \"action\": \"showToast\", \"payload\": { \"message\": \"Hi\" } } },\n        \"children\": [\"Say hello\"]\n      }\n    ]\n  }\n}\n```\n\nThe host — the only code you write:\n\n```tsx\nimport { ViewRenderer } from \"@batthewz/response-ui-renderer\";\n\nimport spec from \"./hello.json\";\n\nexport default () => <ViewRenderer spec={spec} adapters={{ toast: console.log }} />;\n```\n\nYou should see a themed card with an `<h3>` and a working button; clicking it logs `Hi`, because `toast` is a host adapter and you decided what it does. Change `\"h3\"` to `\"h1\"` and the heading grows. Change `\"Card\"` to `\"Alert\"` and the shell changes. That is the whole loop: the document says *what*, your library decides *how*, and the host decides what an action means.\n\nMisspell `\"Card\"` and you get an inline warning in that node's place while the rest of the page still renders — documents are assumed to be machine-written, so a bad one degrades instead of throwing.\n\n---\n\n## The ViewSpec format\n\n**[VIEWSPEC.md](VIEWSPEC.md) is the terse reference to hand a model** — the whole format plus every component, its compound parts and its props, generated from the live library.\n\n```jsonc\n{\n  \"version\": 1,\n  \"title\": \"Team\",\n  \"theme\": \"aurora\",                            // optional — a theme your app defines\n  \"themeOverrides\": { \"--C-PRIMARY\": \"oklch(0.6 0.15 220)\" },  // optional\n  \"data\": { \"members\": { \"type\": \"static\", \"value\": [{ \"name\": \"Ada\" }] } },\n  \"forms\": { \"contact\": { \"fields\": { \"email\": { \"initialValue\": \"\" } } } },\n  \"state\": { \"page\": 1 },                       // optional — seeds `state.…` refs\n  \"root\": { \"component\": \"Stack\", \"children\": [\"Hello\"] }\n}\n```\n\n### Nodes\n\n| Node | Shape | Renders |\n| --- | --- | --- |\n| Text | `\"Hello\"` | a text node |\n| Component | `{ \"component\": \"Card\", \"props\": {…}, \"children\": [] }` | a registered component |\n| Reference | `{ \"$ref\": \"data.user.name\" }` | the resolved value as text |\n| Loop | `{ \"$each\": \"data.rows\", \"as\": \"row\", \"node\": {…} }` | `node` once per element |\n| Conditional | `{ \"$cond\": \"data.flag\", \"then\": {…}, \"else\": {…} }` | one branch, by truthiness |\n\n`component` accepts compound parts by dot path: `\"Table.Row\"`, `\"Accordion.Item\"`, `\"StatCard.Sparkline\"`. Unknown names render an inline warning; the rest of the view is unaffected.\n\n### Reference paths\n\nResolved highest-precedence first:\n\n1. `data.…` and `forms.…` — explicit namespaces\n2. `$each` aliases (`row`, `rowIndex`) and `state.…` — an alias shadows a data key of the same name, so a loop body always reads its own item\n3. bare data keys — `users.0.name` means `data.users[0].name`\n\nForm values are `forms.<name>.values.<field>`; `forms.<name>.<field>` is accepted as shorthand. Missing paths resolve to nothing rather than throwing, and prototype members (`constructor`, `__proto__`, `toString`) never resolve.\n\n### Props\n\nA prop value may be a literal, or one of:\n\n```jsonc\n{ \"$ref\": \"data.user.name\" }                              // resolved value\n{ \"action\": \"showToast\", \"payload\": { \"message\": \"Hi\" } } // event callback\n{ \"$node\": { \"component\": \"Badge\", \"children\": [\"New\"] } }  // a ViewNode in a prop\n```\n\n`$ref`, `$node` and complete handler objects resolve **inside array and object props** too, so `CommandPalette.items[].onSelect` and a `DataTable` column's `render` template work. Ordinary data is left alone — a row that happens to carry an `action` string stays a row.\n\nTwo-way form binding uses a bare `$field` key, which wires `value`/`checked` and `onChange` together:\n\n```jsonc\n{ \"component\": \"Input\", \"props\": { \"$field\": \"contact.email\" } }\n{ \"component\": \"Checkbox\", \"props\": { \"$field\": \"contact.subscribe\" } }   // binds `checked`\n```\n\nThe longhand `{ \"value\": { \"$field\": \"contact.email\" } }` is also accepted.\n\nA string on an icon-shaped prop (`icon`, `leftIcon`, `trailingIcon`, …) becomes an icon — see [Icons](#icons).\n\n### Data bindings\n\n| Type | Shape | Behaviour |\n| --- | --- | --- |\n| `static` | `{ \"type\": \"static\", \"value\": … }` | inlined, resolved synchronously |\n| `api` | `{ \"type\": \"api\", \"endpoint\": \"/x\", \"method\": \"GET\", \"headers\": {}, \"body\": … }` | fetched on mount via `adapters.fetch` |\n| `source` | `{ \"type\": \"source\", \"source\": \"crm\", \"params\": {} }` | delegated to `adapters.resolveSource` |\n\n`api` URLs are **not rewritten**. By default only relative or same-origin URLs are requested — override with `adapters.allowUrl`. `source` is the escape hatch for host-specific access (credentialed proxies, RPC, in-memory stores), so no host's server contract has to live in the wire format.\n\n### Events\n\n`submitForm`, `resetForm`, `navigate`, `showToast`, `apiCall`, `openDialog`, `closeDialog`, `setState`. Payloads are `$ref`-resolved before dispatch (except `apiCall.endpoint` and `setState.key`, read literally so state shape can't depend on data). Handler chains (`onSuccess`/`onError`/`onSubmit`) stop at depth 5.\n\nInside a payload, **`event` names the callback's arguments** — `event.value` for the first one (DOM events unwrapped), `event.args.N` for the rest. Without it a controlled component could never report anything back, so `Pagination` — controlled-only, with no `defaultPage` — could not move at all:\n\n```jsonc\n\"onPageChange\": { \"action\": \"setState\",\n                  \"payload\": { \"key\": \"page\", \"value\": { \"$ref\": \"event.value\" } } }\n```\n\n`event` resolves to nothing outside a handler. Prefer an uncontrolled seed (`defaultValue`, `defaultOpen`) where the component has one.\n\n```jsonc\n{\n  \"component\": \"Button\",\n  \"props\": { \"onClick\": { \"action\": \"submitForm\", \"payload\": { \"form\": \"contact\" } } },\n  \"children\": [\"Send\"]\n}\n```\n\n### Forms\n\n```jsonc\n\"forms\": {\n  \"contact\": {\n    \"fields\": {\n      \"email\": { \"initialValue\": \"\", \"validation\": { \"required\": true, \"minLength\": 3 } }\n    },\n    \"onSubmit\": { \"action\": \"showToast\", \"payload\": { \"message\": \"Sent\" } }\n  }\n}\n```\n\nRules: `required`, `min`, `max`, `minLength`, `maxLength`, `pattern`, `message`. `min`/`max` apply to numeric **strings** too, so they work on a plain text input. `submitForm` validates first and only then runs `onSubmit`. `Field` and `FieldError` accept `\"name\": \"contact.email\"` to surface the live error.\n\n---\n\n## Adapters\n\nNothing about your host is assumed. Supply only what your documents use.\n\n```tsx\nimport { useNavigate } from \"react-router-dom\";\nimport { useToast } from \"@batthewz/response-ui-react-components\";\n\nconst navigate = useNavigate();\nconst { toast } = useToast();\n\n<ViewRenderer\n  spec={spec}\n  adapters={{\n    navigate,\n    toast,\n    fetch: (url, init) => fetch(url, { ...init, credentials: \"include\" }),\n    resolveSource: async (binding, signal) =>\n      (await fetch(`/api/proxy/${binding.source}`, { signal })).json(),\n    allowUrl: (url) => url.startsWith(\"/\"),\n  }}\n/>;\n```\n\n| Adapter | Default | Used by |\n| --- | --- | --- |\n| `navigate` | warns | `navigate` |\n| `toast` | warns | `showToast`, request failures |\n| `fetch` | `globalThis.fetch` | `api` bindings, `apiCall` |\n| `resolveSource` | reports a diagnostic | `source` bindings |\n| `allowUrl` | relative or same-origin | every request |\n\n`toast` is injected rather than read from `useToast()` internally, because the library's hook throws without a `ToastProvider` — the renderer must stay mountable anywhere.\n\n---\n\n## Theming\n\n`themeOverrides` sets CSS custom properties inline on the view's wrapper. They cascade to descendants, so **this always works and is always scoped to the view**:\n\n```jsonc\n\"themeOverrides\": { \"--C-PRIMARY\": \"oklch(0.6 0.15 220)\", \"--RADIUS-MD\": \"1rem\" }\n```\n\nKeys must start with `--`; anything else is ignored. See the [theme contract](https://github.com/BatthewZ/response-ui-css/blob/main/docs/theme-contract.md) for the full token list.\n\n\"Cascade to descendants\" is the whole rule, and portalled content is the case where it bites: a `Portal`, and any floating panel opened outside an overlay, is appended to `<body>` and keeps the host's tokens. Open that same panel inside a `Dialog`, `Drawer` or `CommandPalette` and it portals into the overlay — still a descendant of the wrapper, so it inherits the overrides.\n\n### `theme` and the `:root` caveat\n\nA `theme` name refers to a theme **your application defines** — writing your own is the normal case. `response-ui-css` defines only `default` (which is `:root` itself); the `events` / `grimdark` / `tech` themes it ships are opt-in worked examples, not a built-in set, and nothing imports them for you.\n\n⚠️ **A theme authored `:root[data-theme=\"…\"]` matches `<html>` and nothing else.** A theme name therefore cannot be scoped to a subtree if it is written that way — the attribute has to be on the document element or the rule matches nothing. The worked examples, and the theme template most themes start from, are written that way.\n\n`themeMode` makes the trade-off explicit:\n\n| `themeMode` | Writes `data-theme` to | Works with a `:root[data-theme]` theme | Scope |\n| --- | --- | --- | --- |\n| `\"root\"` *(default)* | `<html>` | ✅ yes | whole document |\n| `\"scoped\"` | the view's wrapper | ❌ no — needs a bare `[data-theme]` theme | the view only |\n\nA view that declares no theme makes no claim at all, so it never strips the host's theme. `\"root\"` claims are a stack — the most recently mounted wins, releasing one falls back to the next, and the last one out restores the host's own value — and it warns whenever more than one view is claiming `<html>`. For genuinely independent per-view themes, either author your themes with a bare `[data-theme=\"…\"]` selector and use `\"scoped\"`, or express the theme as `themeOverrides`.\n\n---\n\n## Several documents on one page\n\nA page that mounts one `ViewRenderer` per document — a transcript rendering a view per turn, say — puts every document into one DOM id namespace. Author-supplied ids pass through verbatim, which is what lets a document wire its own `Label` to its own control, so two documents naming a control the same thing collide silently:\n\n- **Radio groups merge.** `name` is how the browser groups radios, and that grouping is per page. Two documents each rendering a `name: \"confidence\"` group become *one* group, and choosing in the second clears the first.\n- **Labels retarget.** `htmlFor` resolves to the **first** matching id on the page, so clicking the second document's label activates the first document's control.\n\n`idScope` namespaces them:\n\n```tsx\n{turns.map((turn) => (\n  <ViewRenderer key={turn.id} spec={turn.view} idScope />\n))}\n```\n\n| `idScope` | Prefix | For |\n| --- | --- | --- |\n| omitted *(default)* | none — ids pass through | a single document on the page |\n| `true` | derived, unique per instance | a host composing a list |\n| `\"turn-7\"` | exactly that | an id you must construct from outside — a deep link, a test, an `aria-labelledby` pointing in |\n\nIt rewrites `id`, `htmlFor`, `list`, `form`, the ARIA id references and `DateRangePicker`'s `startInputId` / `endInputId`, on the **resolved** value — so an id that arrives through a `$ref`, or out of an `api` binding that had not loaded yet, is scoped like any other. Strings and numbers both, because a row id pulled out of data is usually a number.\n\n`name` is rewritten only where it is a **DOM form-control name** — `Input`, `Radio`, `Checkbox`, `Select`, `Textarea` and the rest of the form controls. Components that spend `name` on something else keep it verbatim: an `Icon`'s identity, an `Avatar`'s display name, a `Field` / `FieldError` form path, a `Repeater`'s field-array path, a `ViewTransition`'s CSS `view-transition-name`. A component the renderer does not know about — including one you register yourself through `extendRegistry` — is left alone, so a custom component's `name` is never rewritten behind your back. Say `nameProp: \"dom\"` in its [contract](#custom-components) when it *is* a form control and you want it scoped.\n\nIt never touches `$field` paths, the names in `spec.forms`, `$ref` / `state` keys, or the `dialogId` an `openDialog` action names: those are already scoped to the renderer instance, so a document's actions go on naming the ids the document wrote. Components build their own internal ARIA wiring with React's per-instance id hook, which is unique already.\n\n**What it cannot do for you:**\n\n- **References that point out of the document.** Scoping rewrites every id a document writes, so `aria-labelledby` naming a heading in your page chrome, or `form` naming a host `<form>`, will point at nothing. Use the string form and prefix those ids yourself, or keep the reference inside the document.\n- **Fragment links.** `href=\"#section\"` is not scoped — `href` goes through the URL filter — so an in-page anchor to a scoped `id` will not resolve. Give the link an explicit scoped target.\n- **`$each` over a literal `id`.** Repeating a node that carries a literal `id` duplicates ids *within* one document; there is one scope per renderer, so this cannot separate them. Derive the id from the row instead.\n- **Separate render passes.** `true` is unique per component instance within a render pass. If you server-render each document in its own pass, every one derives the same prefix — pass a string you control instead.\n\n---\n\n## Icons\n\nresponse-ui exports no `Icon` component, but many of its components take `icon` props typed `ReactNode` — which JSON cannot express. This package adds an `Icon` node and coerces string-valued icon props, given an icon set:\n\n```tsx\nimport { lucideIcons } from \"@batthewz/response-ui-renderer/icons\";\n\n<ViewRenderer spec={spec} icons={lucideIcons} />;\n```\n\n```jsonc\n{ \"component\": \"Icon\", \"props\": { \"name\": \"Check\", \"size\": 16 } }\n{ \"component\": \"Timeline.Item\", \"props\": { \"icon\": \"Check\" } }\n```\n\nThe full lucide set is a **separate entry point** because it is ~1600 modules and the core must not make you pay for it. For a smaller bundle, pass a curated map:\n\n```tsx\nimport { Check, TrendingUp, X } from \"lucide-react\";\n<ViewRenderer spec={spec} icons={{ Check, TrendingUp, X }} />;\n```\n\nNames are matched leniently — `\"trending-up\"`, `\"trending_up\"` and `\"TrendingUp\"` all resolve. An unresolved name renders a placeholder that holds its slot rather than throwing.\n\n---\n\n## Validation\n\nThe core validator is dependency-free:\n\n```ts\nimport { defaultRegistry } from \"@batthewz/response-ui-renderer\";\nimport { validateViewSpec } from \"@batthewz/response-ui-renderer/spec\";\n\nconst result = validateViewSpec(json, { registry: defaultRegistry });\nif (!result.ok) return renderErrors(result.issues);\nfor (const issue of result.issues) console.warn(issue.path, issue.message);\n```\n\n**Pass the registry and it checks the names.** Without it the validator has no way to tell a typo from a component it was never told about, so it judges no name at all and `\"Cadr\"` passes clean — surfacing only as an inline warning once the page has already drawn. With it:\n\n```\nroot.children[2].component\nunknown component \"Cadr\"; the node renders an inline warning in its place — did you mean \"Card\"?\n```\n\n`registry` also takes a plain list of names, which is what `listComponentNames(registry)` returns — the form that survives being sent to a validation service with no React in it. Per-component checks (bounded prop values, dialogs that need an `id`, roots that parse their children as text) come from `contracts`, and cover [your own components](#custom-components) as readily as the library's.\n\nEvery issue carries a `severity`:\n\n- `\"error\"` — the document does not conform; `ok` is `false`. Use `errorsOf(issues)`.\n- `\"warning\"` — it conforms, but names something that will not do what it looks like: a forbidden prop, a URL whose scheme is not allowed, an element `as` will not render, an unknown action inside a prop, a theme override that is not a custom property, nesting past the depth cap, or a value outside the set a prop accepts. Use `warningsOf(issues)`.\n\nThat last one is the difference between a document that fails and one that quietly underdelivers. Props like `gap`, `variant` and `size` are looked up in a table of classes; a miss returns nothing, so the component renders with that dimension absent and nothing in the DOM to notice. The accepted values are read out of the library's own declarations, so the reference a model authors from and the check it is validated against are one artifact.\n\n`ViewRenderer` never consults this — it degrades per node regardless — so validation is a gate you choose to put in front of it.\n\n### Zod (optional)\n\n`zod` is an **optional peer**; importing this subpath is opt-in and the core never pulls it in.\n\n```ts\nimport { viewSpecSchema, viewSpecJsonSchema } from \"@batthewz/response-ui-renderer/zod\";\n\nviewSpecSchema.safeParse(json);           // server-side gate\nconst schema = viewSpecJsonSchema();      // JSON Schema for LLM structured output\n```\n\n`viewSpecJsonSchema()` is the more interesting one: hand it to a model as a tool / structured-output schema and shape generation into valid documents, rather than repairing them afterwards. The node types are mutually recursive, so the output uses `$ref` cycles — check your provider accepts them.\n\nThe two agree on **conformance** (`ok`), and a test suite fails if they ever diverge. They deliberately differ below that: Zod types `props` as an open record, so the warning tier above has no Zod counterpart. Validate with `validateViewSpec` if you want those.\n\n---\n\n## Hardening\n\nDocuments are assumed untrusted, because a generator wrote them.\n\n| Risk | Handling |\n| --- | --- |\n| A component throws | per-node error boundary; siblings keep rendering |\n| Unknown component | inline warning in place |\n| `dangerouslySetInnerHTML`, `srcDoc`, `ref`, `key`, `constructor`, `prototype`, `__proto__` | dropped before `createElement`. Inside a spread props bag, `dangerouslySetInnerHTML`, `srcDoc` and `__proto__` only — `ref` and `key` are ordinary field names on a data row |\n| URLs | scheme **allowlist** — `http:`, `https:`, `mailto:`, `tel:`, relative, and `data:` for real image types. Everything else is dropped, including `java\\tscript:`, `blob:`, `ftp:`, `sms:` and `data:image/svg+xml`. Attribute names are matched case-insensitively, as the DOM matches them |\n| A URL under a prop that is not spelled like one | checked too — `Swimlane.viewAllHref`, `AppShell.SidebarLink.to` and `RequireAuth.redirect` all become an `href`, and the registry records that. Register your own with `urlProps` |\n| A URL inside a spread props bag (`imgProps`, `tableProps`, …) | checked, including when the bag arrives whole from a `$ref`. Not past 20 levels of nesting, and not inside an event-handler payload or a `columnDefs` array |\n| Choosing the element: `as`, `titleAs`, `headingLevel` | constrained to an allowlist of content elements. `script`, `iframe`, `object`, `embed`, `style`, `link`, `base`, `meta`, `template`, `slot`, `svg` and `math` are refused, and so is anything not on the list — see `ALLOWED_AS_ELEMENTS` for the full set |\n| `\"component\": \"__proto__\"` | own-property lookups only; resolves to nothing |\n| `$ref` into `constructor` / `__proto__` | own-property walks only |\n| Runaway nesting | capped at 50 levels |\n| Handler recursion | capped at 5 |\n| Cross-origin requests | blocked unless `allowUrl` says otherwise. The endpoint is **resolved** and its origin compared, not pattern-matched, so `/\\evil.test/x` and its tab- and newline-separated spellings are refused |\n\nThis is defence in depth, not a sanitiser: a component given hostile *content* still renders that content as text.\n\n---\n\n## Styling from a document\n\n`className` reaches the element a component renders itself; `classNames` reaches the ones it renders inside itself, keyed by slot. Both are passed through untouched and both still collapse correctly — every response-ui component merges them through `cn()` internally, so `\"p-r3 p-r5\"` resolves to `p-r5` without the renderer doing anything. The slot keys for every component are listed in [VIEWSPEC.md](VIEWSPEC.md).\n\n⚠️ **Tailwind generates utilities by scanning source at build time, and a document arrives at runtime.** A class a document invents is therefore not in your CSS unless something else already used it. If your documents are stored rather than streamed, point Tailwind at them:\n\n```css\n@source \"./content/views/**/*.json\";\n```\n\nOtherwise keep documents to the scale (`gap-r4`, `p-r3`, `w-full`) and prefer real props — which is what the reference tells a model to do, and what `validateViewSpec` checks.\n\n---\n\n## Custom components\n\nRegistering a component makes it *renderable*. A **contract** tells the renderer, the validator and the reference generator everything else they know about a component — the same record, read by the same code, for your components and the library's alike.\n\n```tsx\nimport { defaultRegistry, extendRegistry } from \"@batthewz/response-ui-renderer\";\n\nconst registry = extendRegistry(defaultRegistry, { BarChart, Widget: { component: W, subComponents: { Item } } });\n<ViewRenderer spec={spec} registry={registry} />;\n```\n\n`listComponentNames(registry)` returns every addressable name including compound parts — useful for generating the catalogue you give a model.\n\n### Contracts\n\nEverything this package knows about a component beyond how to construct it lives in one record per addressable name, and `extendContracts` merges yours in:\n\n```tsx\nimport { defaultContracts, extendContracts } from \"@batthewz/response-ui-renderer\";\n\nconst contracts = extendContracts(defaultContracts, {\n  BarChart: {\n    category: \"Charts\",\n    note: \"Bind `series` to a `data` key; `orientation` defaults to vertical.\",\n    propEnums: { orientation: [\"horizontal\", \"vertical\"] },\n    coercions: { since: \"isoDate\", rowKey: \"keyAccessor\" },\n  },\n  \"Widget.Item\": { propEnums: { tone: [\"muted\", \"loud\"] } },\n});\n\n<ViewRenderer spec={spec} registry={registry} contracts={contracts} />;\n```\n\nMerging is **per field**, so naming a component that already has a record adds to it — you can attach a note to `Card` without knowing what else `Card`'s record holds. A field you supply replaces that field whole. Nothing is registered globally and nothing mutates: contracts are a value you pass, so two renderers on one page can hold different ones and a test cannot leak into the next.\n\n| Field | What it does |\n| --- | --- |\n| `category` · `note` | Where the component appears in a generated reference, and the one thing an author would otherwise get wrong |\n| `propEnums` | Props bounded to a fixed set of strings. `validateViewSpec` warns on anything else — the component would look the value up in a table of classes and draw nothing |\n| `coercions` | `isoDate` · `isoDateRange` · `keyAccessor` · `columnDefs` — props typed with something JSON cannot express |\n| `functionChildren` | `children` is a function the component calls. `args` are the names a document may `$ref` inside them — the keys of the single options object your component passes, or, if it passes positional arguments, the names they bind to in order |\n| `textChildren` | `children` is source text the component parses, not nodes it places |\n| `dialog` | The renderer owns its open state, so `openDialog` / `closeDialog` can target it |\n| `childInspection` | It clones or reads its own children, so no error boundary may sit between them. `\"asChild\"` to apply only when the node sets `asChild` |\n| `iconComponentProps` | Icon slots typed as a component rather than a node — handing one an element throws instead of degrading. Only consulted for props the renderer already treats as icons: named `icon`, or ending in `Icon` |\n| `nameProp` | `\"dom\"` when `name` reaches a real form element, so `idScope` namespaces it |\n| `urlProps` | Props your component turns into a URL attribute under a different name — a `to` or a `linkHref`. The universal DOM names (`href`, `src`, …) are checked for every component; without this a renamed one is not |\n| `elementProps` | Props your component reads as the host element to render, spelled as something other than `as`. Constrained to the same allowlist |\n| `headingLevelProps` | Props interpolated *into* a tag name (`` `h${level}` ``) rather than being one. Constrained to 1–6 |\n| `contentProps` | Props whose name matches a URL attribute's but whose value is content — a `ReactNode` slot named `action`. Exempts them from the URL check |\n| `props` · `slots` | Reference only: the props table and `classNames` slot keys |\n\nOmit the whole thing and a registered component still renders — it simply gets none of the above, which is what it got before contracts existed.\n\n**What a contract cannot express.** Two validator rules stay specific to the peer library: `Radio`'s bare-form `$field` spelling, and the handful of parents whose child *identity* checks (`child.type === Avatar`) cannot survive a renderer. Both turn on per-component structure — which child, which prop — rather than on data, so a contract field would have to be a predicate, and a warning that fires when an author can do nothing about it is a warning they learn to ignore. `enumeratedValues(component, prop, contracts)` reads your contracts too, so it never disagrees with the warning the validator would raise.\n\n### A reference for your registry\n\n`VIEWSPEC.md` is generated by calling the same function this package exports, so a reference covering your components is one call rather than a fork of a build script:\n\n```ts\nimport {\n  DEFAULT_CATEGORIES,\n  defaultReferenceContracts,\n  extendContracts,\n  renderReferenceRegions,\n} from \"@batthewz/response-ui-renderer/reference\";\n\nconst { components, slots } = renderReferenceRegions(\n  extendContracts(defaultReferenceContracts, contracts),\n  { categories: [...DEFAULT_CATEGORIES, { name: \"Charts\", blurb: \"Rendered from live data.\" }] },\n);\n```\n\n`defaultReferenceContracts` is `defaultContracts` plus everything only a reference reads: the prop tables, the slot keys, **and the library's curated category and note**. That is 60-odd kilobytes of documentation nothing reads at render or validate time, which is why it sits behind its own entry point rather than in the core — and why `defaultContracts` alone carries no category, so generating a reference from it would describe nothing. It throws rather than hand you an empty table. Compound parts are read off the names themselves: register `\"Widget.Item\"` and it appears in `Widget`'s Parts column.\n\nThe **derivation** does not ship, only the rendering. The library's prop tables and slot keys were machine-extracted from its `.d.ts` by a script that stays in this repo; for your own components you write `props` and `slots` yourself, or their columns read `—`.\n\nCategories are yours to name, and a component categorised under a heading you did not list **throws** rather than being quietly dropped — the failure mode that once cost `VIEWSPEC.md` its entire Action section while every check still passed.\n\nProse is not generated: this returns the table regions, and the words around them stay yours.\n\n### A reference scoped to what you actually author\n\nMost producers use a fraction of the library. A tutoring app that emits a lesson as a document might author 17 component names, over and over — and pay ~12k tokens per request to find them among the 96 the reference documents. Narrow the contracts and the reference narrows with them:\n\n```ts\nimport { renderViewSpecReference } from \"@batthewz/response-ui-renderer/reference\";\n\nconst reference = renderViewSpecReference({\n  include: NAMES_MY_APP_AUTHORS,\n  propLimit: false,\n});\n```\n\n`renderViewSpecReference` returns `VIEWSPEC.md` as a string — prose and all. With no options it *is* the shipped file, byte for byte; given a scope it is the same document describing only those components. For the 17-name vocabulary above: **47,848 → 26,148 bytes, a 45.4% saving** on every request that carries it. Generate it once at startup and cache the string.\n\nPass `contracts: extendContracts(defaultReferenceContracts, yours)` to have components you registered documented alongside the library's, or compose `scopeContracts` yourself when you want the same narrowed set for something else — feeding `validateViewSpec` a registry of exactly the names your prompt describes, for instance.\n\n**`propLimit: false` is about accuracy, not size.** The full reference caps each row at seven props because 96 components have to fit one readable file — a cap that hides props on 20 of those rows. A hidden prop is one an author invents instead, and nothing catches that: value checking cannot fire on a prop name that was never declared. A narrow scope has no size problem, so it can carry the complete list. For the 17 names above it happens to change nothing — none of them is truncated — and it is worth passing anyway, because which of your components sits near the cap is not a thing you should have to track.\n\nThree things the scope deliberately leaves alone, and one honest limit.\n\n- A compound part **travels with its root in both directions**, so `Stepper` brings `Stepper.Step`, and `AppShell.Navbar` brings `AppShell` *and its seven other parts* — a part cannot render anywhere else, and a root advertising some of its parts is a subtler lie than one advertising none.\n- The **prose and the worked examples stay whole**, and the scope *names what that costs*. After scoping to those 17 names, 8 of the document's 11 example component names sit outside it — the `MultiSelect` block and the `Pagination` one. Those components still render, so a model copying an example gets no error, just no prop table to author against. Rather than tag prose by component set (a mis-tag silently deletes advice, which is worse), the components region opens with a generated line naming every one of them, and a table a scope leaves empty says so instead of showing a bare header.\n- The **not-addressable table stays whole** (1,813 bytes of the 26,148), because it is advice about absence — filtering it would remove the line that stops an author reaching for `FileUpload` in the one document where nothing else mentions it. Scoping it too would land at ~24,300 bytes, a 49% saving; that is the trade.\n- The tables describe the component library **as of this package's release**, not as of the copy in your `node_modules` — they are derived at build time from its declarations. Regenerating cannot drift past this package; within one `^` range, it can lag its peer.\n\nA name no contract holds **throws**, with the nearest match. That is the point of generating rather than keeping a hand-copied subset: when the library moves, the scope tells you.\n\n---\n\n## API\n\n`ViewRenderer` · `NodeRenderer` · `NodeErrorBoundary` · `ViewThemeScope` · `ViewDataProvider` · `ViewContextExtender` · `useViewData` · `defaultRegistry` · `extendRegistry` · `createRegistryFromModule` · `lookupComponent` · `listComponentNames` · `defaultContracts` · `extendContracts` · `contractFor` · `componentNamesOf` · `Icon` · `IconSetProvider` · `useIconSet` · `useFormsState` · `createEventCallback` · `validateField` · `validateForm` · `resolveRef` · `resolveDeep` · `validateViewSpec` · `isViewSpec` · `PROP_ENUMS` / `enumeratedValues` · `FUNCTION_CHILDREN` · `TEXT_CHILDREN` · `COMPONENT_TYPED_ICON_SLOTS` · `COMPONENT_NOTES` · `PROP_COERCIONS` — plus every type.\n\nThat last group is there for prompt and schema building: the accepted values of every bounded prop, the components whose `children` is a function of their own data, and the ones whose `children` is source text they parse. `COMPONENT_TYPED_ICON_SLOTS` is the odd one — *most* icon slots take a name (see [VIEWSPEC.md](VIEWSPEC.md)); this is the exception that wants a component type rather than an element, invisible from a document and useful to a schema builder.\n\nSubpaths: `/spec` (types + validator + contracts, no React) · `/reference` (reference generation and scoping) · `/icons` (lucide set) · `/zod` (schemas) · `/styles` (CSS).\n\n## License\n\nMIT\n","readmeFilename":"README.md"}