{"_id":"@agilearn/router","_rev":"6-0dff0211a4c3319814a8addb367e5290","name":"@agilearn/router","dist-tags":{"latest":"1.3.2"},"versions":{"1.0.0":{"name":"@agilearn/router","version":"1.0.0","keywords":["cloudflare","workers","router","typescript","edge","serverless"],"author":{"name":"Matthew Gibbons"},"license":"ISC","_id":"@agilearn/router@1.0.0","maintainers":[{"name":"accuser","email":"mhgibbons@me.com"}],"dist":{"shasum":"4ab27d793bc99915cb3999eeb86b4ac431c6c464","tarball":"https://registry.npmjs.org/@agilearn/router/-/router-1.0.0.tgz","fileCount":69,"integrity":"sha512-lEiWmDSpbOtA09r8MLMuP701K7pcrQmElIHDH27RhleP8HdNBSJf0rtu2Q5Yv91F+a76rDBCDs4vISU68wFMcg==","signatures":[{"sig":"MEQCIA52XxGLyOkWYmVWYfS85Aj5rw5m7g3d5+xoFplDEDQxAiA3ue176oghUnDO8GW8mOP44RKYkkc2Klddb9ymei1c9Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":25836},"type":"module","_from":"file:agilearn-router-1.0.0.tgz","types":"dist/index.d.ts","module":"dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs"}},"scripts":{"dev":"pnpm run build --watch","test":"vitest run","build":"pnpm run build:esm && pnpm run build:types","clean":"rm -rf dist","types":"wrangler types","build:esm":"esbuild src/index.ts --bundle --format=esm --minify --outfile=dist/index.mjs --platform=neutral","test:watch":"vitest","build:types":"tsc --emitDeclarationOnly --outDir dist","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"accuser","email":"mhgibbons@me.com"},"_resolved":"/tmp/05abfe6fe280c1e5941494aa22ff3800/agilearn-router-1.0.0.tgz","_integrity":"sha512-lEiWmDSpbOtA09r8MLMuP701K7pcrQmElIHDH27RhleP8HdNBSJf0rtu2Q5Yv91F+a76rDBCDs4vISU68wFMcg==","_npmVersion":"11.5.1","description":"A lightweight router for Cloudflare Workers with TypeScript support","directories":{},"_nodeVersion":"24.5.0","_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.2.4","esbuild":"^0.25.8","wrangler":"^4.26.1","typescript":"^5.8.3","@types/node":"^24.1.0","@vitest/coverage-v8":"^3.2.4"},"_npmOperationalInternal":{"tmp":"tmp/router_1.0.0_1754112199934_0.05403250795369785","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@agilearn/router","version":"1.1.0","keywords":["cloudflare","workers","router","typescript","edge","serverless"],"author":{"name":"Matthew Gibbons"},"license":"ISC","_id":"@agilearn/router@1.1.0","maintainers":[{"name":"accuser","email":"mhgibbons@me.com"}],"homepage":"https://github.com/accuser/router#readme","bugs":{"url":"https://github.com/accuser/router/issues"},"dist":{"shasum":"e80e5f0330e10d9dc8dab609f4764f26a5963feb","tarball":"https://registry.npmjs.org/@agilearn/router/-/router-1.1.0.tgz","fileCount":46,"integrity":"sha512-VKCsDL0Vl24bx+WHm3IYX2plry6uxmXjdy1ZTgEE4nJ2scs+Qw5G4ntfeEQdfn00vO/BTa9dT86noOrcWW4BSw==","signatures":[{"sig":"MEUCIB7RuFjky+rm0JLdaUmyEK+TM63RLQegiJd8MH3q6qR1AiEAtxYH9OLMfb7/7w3U1EB7En+QfWXycCJzgK8+BkpTesI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":23718},"type":"module","_from":"file:agilearn-router-1.1.0.tgz","types":"dist/index.d.ts","module":"dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs"}},"private":false,"scripts":{"dev":"pnpm run build --watch","test":"vitest","build":"pnpm run types && pnpm run build:esm && pnpm run build:types","clean":"rm -rf dist","types":"wrangler types","test:run":"vitest run","build:esm":"esbuild src/index.ts --bundle --format=esm --minify --outfile=dist/index.mjs --platform=neutral","build:types":"tsc --emitDeclarationOnly --outDir dist","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"accuser","email":"mhgibbons@me.com"},"_resolved":"/tmp/7bd2cdb3a36a18d29f887aedbfe9bf4d/agilearn-router-1.1.0.tgz","_integrity":"sha512-VKCsDL0Vl24bx+WHm3IYX2plry6uxmXjdy1ZTgEE4nJ2scs+Qw5G4ntfeEQdfn00vO/BTa9dT86noOrcWW4BSw==","repository":{"url":"git+https://github.com/accuser/router.git","type":"git"},"_npmVersion":"11.5.1","description":"A lightweight router for Cloudflare Workers with TypeScript support","directories":{},"_nodeVersion":"24.5.0","_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.2.4","esbuild":"^0.25.8","valibot":"^1.1.0","wrangler":"^4.26.1","typescript":"^5.8.3","@types/node":"^24.1.0","@vitest/coverage-v8":"^3.2.4"},"_npmOperationalInternal":{"tmp":"tmp/router_1.1.0_1754381805944_0.3015964958496862","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@agilearn/router","version":"1.2.0","keywords":["cloudflare","workers","router","typescript","edge","serverless"],"author":{"name":"Matthew Gibbons"},"license":"ISC","_id":"@agilearn/router@1.2.0","maintainers":[{"name":"accuser","email":"mhgibbons@me.com"}],"homepage":"https://github.com/accuser/router#readme","bugs":{"url":"https://github.com/accuser/router/issues"},"dist":{"shasum":"cf9c873c6abb35355961f3bfff0b0df2cc4d3e50","tarball":"https://registry.npmjs.org/@agilearn/router/-/router-1.2.0.tgz","fileCount":46,"integrity":"sha512-EiDp3K6Sm0zO0NX11oVL36oIMM3ucHHbKdYAEA1Hr0KiWUSH4lT7tVmCeYysR2320xcTHBQINOTpNLJhzlhkRw==","signatures":[{"sig":"MEUCIQDfLOfm8L+ZTgYkuauDCUj7YwZSmxZInOAxDe6Ap1+MdwIgerW1923Ok9nYQQozoTK2Ned8S9F9gVw35qXuzD/npkY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":24833},"main":"dist/index.mjs","type":"module","_from":"file:agilearn-router-1.2.0.tgz","types":"dist/index.d.ts","module":"dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs"}},"private":false,"scripts":{"dev":"pnpm run build --watch","test":"vitest","build":"pnpm run clean && pnpm run types && pnpm run build:esm && pnpm run build:types","clean":"rm -rf dist","types":"wrangler types","test:run":"vitest run","build:esm":"esbuild src/index.ts --bundle --format=esm --minify --outfile=dist/index.mjs --platform=neutral","build:types":"tsc --emitDeclarationOnly","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"accuser","email":"mhgibbons@me.com"},"_resolved":"/tmp/744f2e0be14dbeb1319bacfce4147dee/agilearn-router-1.2.0.tgz","_integrity":"sha512-EiDp3K6Sm0zO0NX11oVL36oIMM3ucHHbKdYAEA1Hr0KiWUSH4lT7tVmCeYysR2320xcTHBQINOTpNLJhzlhkRw==","repository":{"url":"git+https://github.com/accuser/router.git","type":"git"},"_npmVersion":"11.5.1","description":"A lightweight router for Cloudflare Workers with TypeScript support","directories":{},"_nodeVersion":"24.5.0","_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.2.4","esbuild":"^0.25.8","wrangler":"^4.28.0","typescript":"^5.9.2","@vitest/coverage-v8":"^3.2.4"},"_npmOperationalInternal":{"tmp":"tmp/router_1.2.0_1754547400132_0.9404708368034884","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"@agilearn/router","version":"1.3.0","keywords":["cloudflare","workers","router","typescript","edge","serverless"],"author":{"name":"Matthew Gibbons"},"license":"ISC","_id":"@agilearn/router@1.3.0","maintainers":[{"name":"accuser","email":"mhgibbons@me.com"}],"homepage":"https://github.com/accuser/router#readme","bugs":{"url":"https://github.com/accuser/router/issues"},"dist":{"shasum":"695194ad02650ca706ad367c1b228445192a9496","tarball":"https://registry.npmjs.org/@agilearn/router/-/router-1.3.0.tgz","fileCount":50,"integrity":"sha512-vn86WTPNyBhcPFy5XcHCo9G5YtAetTW46b0sX2lFlAYMuVNUgr9EEuCz53/CQjW73mdqZtUNuemskijDIJABqA==","signatures":[{"sig":"MEQCICWT51miWVSE9U9oPrLCqdfUmk1c0YbagWvP5aoC6dApAiA1+3PTAD2rt9v6nnIRE9Zt1THpr5Evj88LjS7XKH9tkA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":25851},"main":"dist/index.mjs","type":"module","_from":"file:agilearn-router-1.3.0.tgz","types":"dist/index.d.ts","module":"dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs"}},"private":false,"scripts":{"dev":"pnpm run build --watch","test":"vitest","build":"pnpm run clean && pnpm run types && pnpm run build:esm && pnpm run build:types","clean":"rm -rf dist","types":"wrangler types","test:run":"vitest run","build:esm":"esbuild src/index.ts --bundle --format=esm --minify --outfile=dist/index.mjs --platform=neutral","build:types":"tsc --emitDeclarationOnly","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"accuser","email":"mhgibbons@me.com"},"_resolved":"/tmp/9e5ab07a5aea99c5a60aa387bc4141de/agilearn-router-1.3.0.tgz","_integrity":"sha512-vn86WTPNyBhcPFy5XcHCo9G5YtAetTW46b0sX2lFlAYMuVNUgr9EEuCz53/CQjW73mdqZtUNuemskijDIJABqA==","repository":{"url":"git+https://github.com/accuser/router.git","type":"git"},"_npmVersion":"11.5.1","description":"A lightweight router for Cloudflare Workers with TypeScript support","directories":{},"_nodeVersion":"24.5.0","_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.2.4","esbuild":"^0.25.8","wrangler":"^4.28.0","typescript":"^5.9.2","@vitest/coverage-v8":"^3.2.4"},"_npmOperationalInternal":{"tmp":"tmp/router_1.3.0_1754549428709_0.5764997397324283","host":"s3://npm-registry-packages-npm-production"}},"1.3.1":{"name":"@agilearn/router","version":"1.3.1","keywords":["cloudflare","workers","router","typescript","edge","serverless"],"author":{"name":"Matthew Gibbons"},"license":"ISC","_id":"@agilearn/router@1.3.1","maintainers":[{"name":"accuser","email":"mhgibbons@me.com"}],"homepage":"https://github.com/accuser/router#readme","bugs":{"url":"https://github.com/accuser/router/issues"},"dist":{"shasum":"efad07b8c40876a588e3a7e722ed17d804797ead","tarball":"https://registry.npmjs.org/@agilearn/router/-/router-1.3.1.tgz","fileCount":50,"integrity":"sha512-qtt30w0++DcfGwAVaRlrzAb6e5ubbkKf7b1ZXTMtKcl52uhqU+pfEC5OkFqDLquD2wNsYzUhH0I6Js2G8MH3Jg==","signatures":[{"sig":"MEYCIQCtpxcXJB1NN3zR0U1yb/q7SHrO71X6zGBrlAA4OAJeagIhAMt06OsCxConaFd5y26m8dS2FvlWfZ2KAWPDP9aUf8w9","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":25851},"main":"dist/index.mjs","type":"module","_from":"file:agilearn-router-1.3.1.tgz","types":"dist/index.d.ts","module":"dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs"}},"private":false,"scripts":{"dev":"pnpm run build --watch","test":"vitest","build":"pnpm run clean && pnpm run types && pnpm run build:esm && pnpm run build:types","clean":"rm -rf dist","types":"wrangler types","test:run":"vitest run","build:esm":"esbuild src/index.ts --bundle --format=esm --minify --outfile=dist/index.mjs --platform=neutral","build:types":"tsc --emitDeclarationOnly","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"accuser","email":"mhgibbons@me.com"},"_resolved":"/tmp/3861905bd552933067b31c63e4893c90/agilearn-router-1.3.1.tgz","_integrity":"sha512-qtt30w0++DcfGwAVaRlrzAb6e5ubbkKf7b1ZXTMtKcl52uhqU+pfEC5OkFqDLquD2wNsYzUhH0I6Js2G8MH3Jg==","repository":{"url":"git+https://github.com/accuser/router.git","type":"git"},"_npmVersion":"11.5.1","description":"A lightweight router for Cloudflare Workers with TypeScript support","directories":{},"_nodeVersion":"24.5.0","_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.2.4","esbuild":"^0.25.8","wrangler":"^4.28.0","typescript":"^5.9.2","@vitest/coverage-v8":"^3.2.4"},"_npmOperationalInternal":{"tmp":"tmp/router_1.3.1_1754549631759_0.3428071725631736","host":"s3://npm-registry-packages-npm-production"}},"1.3.2":{"name":"@agilearn/router","version":"1.3.2","description":"A lightweight router for Cloudflare Workers with TypeScript support","type":"module","private":false,"main":"dist/index.mjs","module":"dist/index.mjs","types":"dist/index.d.ts","exports":{".":{"import":"./dist/index.mjs","types":"./dist/index.d.ts"}},"keywords":["cloudflare","workers","router","typescript","edge","serverless"],"author":{"name":"Matthew Gibbons"},"license":"ISC","devDependencies":{"@vitest/coverage-v8":"^3.2.4","esbuild":"^0.25.8","typescript":"^5.9.2","vitest":"^3.2.4","wrangler":"^4.28.0"},"repository":{"type":"git","url":"git+https://github.com/accuser/router.git"},"homepage":"https://github.com/accuser/router#readme","bugs":{"url":"https://github.com/accuser/router/issues"},"scripts":{"build":"pnpm run clean && pnpm run types && pnpm run build:esm && pnpm run build:types","build:esm":"esbuild src/index.ts --bundle --format=esm --minify --outfile=dist/index.mjs --platform=neutral","build:types":"tsc --emitDeclarationOnly","clean":"rm -rf dist","dev":"pnpm run build --watch","test":"vitest","test:run":"vitest run","test:coverage":"vitest run --coverage","types":"wrangler types"},"_id":"@agilearn/router@1.3.2","_integrity":"sha512-JqEXD4f1VoLgkFBzM5IMCBAo0kg4fFz5Mf8BtKE2nsi4pYlPJ20aUCxzPuMjlksUFEXrv7Bywj1a3Yt1rLP37g==","_resolved":"/tmp/4eaf22178329c7aa161cda6f429270db/agilearn-router-1.3.2.tgz","_from":"file:agilearn-router-1.3.2.tgz","_nodeVersion":"24.5.0","_npmVersion":"11.5.1","dist":{"integrity":"sha512-JqEXD4f1VoLgkFBzM5IMCBAo0kg4fFz5Mf8BtKE2nsi4pYlPJ20aUCxzPuMjlksUFEXrv7Bywj1a3Yt1rLP37g==","shasum":"8c990a197de927986baa13ff3c352e0cdb3f2bf0","tarball":"https://registry.npmjs.org/@agilearn/router/-/router-1.3.2.tgz","fileCount":50,"unpackedSize":25809,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIFOsEJivdEq5XJw1GPu7k+xRh7Sblwyjc+h+HgzN3Yw1AiEAyHiBKWwA6GnvEk8PPDGjM0XYCKSrKYcMXXEi4G0rMX4="}]},"_npmUser":{"name":"accuser","email":"mhgibbons@me.com"},"directories":{},"maintainers":[{"name":"accuser","email":"mhgibbons@me.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/router_1.3.2_1754550031743_0.046031023509530256"},"_hasShrinkwrap":false}},"time":{"created":"2025-08-02T05:23:19.875Z","modified":"2025-08-07T07:00:32.181Z","1.0.0":"2025-08-02T05:23:20.173Z","1.1.0":"2025-08-05T08:16:46.147Z","1.2.0":"2025-08-07T06:16:40.407Z","1.3.0":"2025-08-07T06:50:28.930Z","1.3.1":"2025-08-07T06:53:51.993Z","1.3.2":"2025-08-07T07:00:31.982Z"},"bugs":{"url":"https://github.com/accuser/router/issues"},"author":{"name":"Matthew Gibbons"},"license":"ISC","homepage":"https://github.com/accuser/router#readme","keywords":["cloudflare","workers","router","typescript","edge","serverless"],"repository":{"type":"git","url":"git+https://github.com/accuser/router.git"},"description":"A lightweight router for Cloudflare Workers with TypeScript support","maintainers":[{"name":"accuser","email":"mhgibbons@me.com"}],"readme":"# Router\n\nA type-safe, lightweight router designed specifically for Cloudflare Workers with built-in JSON:API support. Inspired by [itty-router](https://github.com/kwhitley/itty-router) and [SvelteKit](https://github.com/sveltejs/kit).\n\n## Features\n\n- 🔥 **Zero dependencies** - Lightweight and fast\n- 🛡️ **Type-safe** - Full TypeScript support with route parameter inference\n- 🌐 **Cloudflare Workers optimized** - Built for the edge\n- 📡 **JSON:API compliant** - Follows JSON:API specification\n- 🚀 **Simple API** - Intuitive method chaining\n- 🔄 **Dynamic routes** - Support for parameters, wildcards, and catch-all routes\n- ⚡ **High performance** - Minimal overhead with efficient route matching\n- 🛠️ **Optional response helpers** - Built-in helpers for common responses and errors\n\n## Installation\n\n```bash\nnpm install @agilearn/router\n```\n\n## Quick Start\n\n```typescript\nimport { router, json, error, notFound, internalServerError } from '@agilearn/router';\n\nconst app = router();\n\n// Simple route\napp.get('/hello', () => json({ message: 'Hello, World!' }));\n\n// Route with parameters\napp.get('/users/:id', ({ params }) => {\n\treturn json({\n\t\tdata: {\n\t\t\ttype: 'users',\n\t\t\tid: params.id,\n\t\t\tattributes: { name: 'John Doe' },\n\t\t},\n\t});\n});\n\n// Handle not found\napp.get('/missing', () => notFound());\n\n// Handle errors\napp.post('/users', () => {\n\ttry {\n\t\t// Some operation that might fail\n\t\tthrow new Error('Database error');\n\t} catch (err) {\n\t\treturn internalServerError(err);\n\t}\n});\n\nexport default app;\n```\n\n## Response Helpers\n\nThe router includes several built-in response helpers for common HTTP responses:\n\n### JSON Responses\n\n```typescript\nimport { json, created } from '@agilearn/router/response';\n\n// JSON response with data (200 OK)\njson({ message: 'Success' });\n\n// JSON with custom status and headers\ncreated(\n\t{ data: user },\n\t{\n\t\theaders: { Location: '/users/123' },\n\t}\n);\n```\n\n### Error Responses\n\n```typescript\nimport { error } from '@agilearn/router';\n\n// Basic error (follows JSON:API error format)\nerror(404, 'Not Found');\n\n// Error with description\nerror(400, 'Bad Request', 'Invalid email format');\n\n// Error with Error object\nerror(500, 'Internal Server Error', new Error('Database failed'));\n```\n\n### Common HTTP Responses\n\n```typescript\nimport { notFound, internalServerError } from '@agilearn/router/response';\n\n// 404 Not Found\napp.get('/missing', () => notFound());\n\n// 500 Internal Server Error\napp.get('/error', () => internalServerError());\n\n// 500 with custom error\napp.get('/custom-error', () => internalServerError(new Error('Custom error')));\n```\n\n## API Reference\n\n### Router Creation\n\n```typescript\nconst app = router<Options>({\n  base?: string;\n  onError?: (error: unknown, request: Request) => Response | Promise<Response>;\n});\n```\n\n**Options:**\n\n- `base` - Base path for all routes (optional). Must start with '/'.\n- `onError` - Custom error handler (optional, defaults to `internalServerError`)\n\n### HTTP Methods\n\nThe router supports all standard HTTP methods:\n\n```typescript\napp.get(path, ...handlers);\napp.post(path, ...handlers);\napp.put(path, ...handlers);\napp.patch(path, ...handlers);\napp.delete(path, ...handlers);\napp.head(path, ...handlers);\napp.options(path, ...handlers);\napp.trace(path, ...handlers);\n```\n\n### Route Patterns\n\n#### Static Routes\n\n```typescript\napp.get('/users', handler);\napp.post('/api/v1/posts', handler);\n```\n\n#### Parameters\n\n```typescript\n// Single parameter\napp.get('/users/:id', ({ params }) => {\n\tconsole.log(params.id); // Type-safe!\n});\n\n// Multiple parameters\napp.get('/users/:userId/posts/:postId', ({ params }) => {\n\tconsole.log(params.userId, params.postId);\n});\n```\n\n#### Catch-all Parameters\n\n```typescript\n// Matches everything after /files/\napp.get('/files/:path+', ({ params }) => {\n\tconsole.log(params.path); // Could be \"docs/readme.txt\"\n});\n```\n\n#### Wildcards\n\n```typescript\n// Matches any path\napp.get('/api/*', handler);\n```\n\n### Request Handler\n\n```typescript\ntype RequestHandler<Options, Pathname> = (\n\tevent: RequestEvent<Options, Pathname>\n) => Response | Promise<Response> | void;\n\ninterface RequestEvent<Options, Pathname> {\n\tparams: RouteParams<Pathname>; // Route parameters (type-safe)\n\tplatform: Platform<Options>; // Cloudflare Workers context\n\trequest: Request; // Original request\n\turl: URL; // Parsed URL\n}\n```\n\n## Advanced Usage\n\n### Custom Types\n\n```typescript\ninterface MyEnv {\n\tDATABASE_URL: string;\n\tAPI_KEY: string;\n}\n\ninterface MyProps {\n\tuserId: string;\n}\n\nconst app = router<{\n\tenv: MyEnv;\n\tprops: MyProps;\n}>();\n\napp.get('/protected', ({ platform }) => {\n\t// platform.env is typed as MyEnv\n\t// platform.ctx.props is typed as MyProps\n\tconst dbUrl = platform.env.DATABASE_URL;\n\treturn json({ success: true });\n});\n```\n\n### Error Handling\n\n```typescript\nimport { internalServerError } from '@agilearn/router/response';\n\nconst app = router({\n\tonError: (error, request) => {\n\t\tconsole.error('Router error:', error);\n\t\treturn internalServerError(error);\n\t},\n});\n```\n\n### Middleware Pattern\n\n```typescript\nimport { error } from '@agilearn/router/response';\n\nconst authenticate = ({ request, platform }) => {\n\tconst token = request.headers.get('Authorization');\n\tif (!token) {\n\t\tthrow error(401, 'Unauthorized');\n\t}\n\t// Continue to next handler by returning void/undefined\n};\n\nconst getUser = ({ params }) => {\n\treturn json({\n\t\tdata: {\n\t\t\ttype: 'users',\n\t\t\tid: params.id,\n\t\t},\n\t});\n};\n\n// Chain handlers\napp.get('/users/:id', authenticate, getUser);\n```\n\n### Error Handling Best Practices\n\n```typescript\nimport { badRequest, internalServerError, notFound } from '@agilearn/router';\n\napp.get('/users/:id', async ({ params, platform }) => {\n\ttry {\n\t\tconst user = await getUser(params.id, platform.env.DATABASE_URL);\n\n\t\tif (!user) {\n\t\t\treturn notFound();\n\t\t}\n\n\t\treturn json({\n\t\t\tdata: {\n\t\t\t\ttype: 'users',\n\t\t\t\tid: user.id,\n\t\t\t\tattributes: user,\n\t\t\t},\n\t\t});\n\t} catch (err) {\n\t\tif (err instanceof ValidationError) {\n\t\t\treturn badRequest(err.message);\n\t\t}\n\n\t\treturn internalServerError(err);\n\t}\n});\n```\n\n## JSON:API Compliance\n\nThis router is designed for JSON:API applications and includes:\n\n- Structured error responses following JSON:API error object format\n- Support for JSON:API document structure\n\n```typescript\n// JSON:API compliant response\napp.get('/users/:id', ({ params }) => {\n\treturn json(\n\t\t{\n\t\t\tdata: {\n\t\t\t\ttype: 'users',\n\t\t\t\tid: params.id,\n\t\t\t\tattributes: {\n\t\t\t\t\tname: 'John Doe',\n\t\t\t\t\temail: 'john@example.com',\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\theaders: { 'Content-Type': 'application/vnd.api+json' },\n\t\t}\n\t);\n});\n```\n\n## Deployment\n\n### Cloudflare Workers\n\n```typescript\n// wrangler.toml\nname = \"my-api\"\nmain = \"src/index.ts\"\ncompatibility_date = \"2024-01-01\"\n\n# src/index.ts\nimport { json, router } from '@agilearn/router';\n\nconst app = router();\n\napp.get('/', () => json({ message: 'Hello World!' }));\n\nexport default app;\n```\n\nThen deploy:\n\n```bash\nnpx wrangler deploy\n```\n\n## License\n\nMIT\n\n## Contributing\n\nContributions are welcome! Please read our contributing guidelines and submit pull requests to our repository.\n","readmeFilename":"README.md"}