{"_id":"@corrodekit/next-routes","_rev":"4-a9e744c9c04d549c880c3d22154728a0","name":"@corrodekit/next-routes","dist-tags":{"latest":"0.2.1"},"versions":{"0.1.0":{"name":"@corrodekit/next-routes","version":"0.1.0","keywords":["nextjs","next","routes","type-safe","typesafe","codegen","app-router","pages-router","routing","ghost-strings"],"author":"","license":"MIT","_id":"@corrodekit/next-routes@0.1.0","maintainers":[{"name":"corroding","email":"corrode.app@gmail.com"}],"bin":{"corrode-routes":"dist/cli.js"},"dist":{"shasum":"5c7321e607571e11af2d57f1d823929c89ef7c13","tarball":"https://registry.npmjs.org/@corrodekit/next-routes/-/next-routes-0.1.0.tgz","fileCount":13,"integrity":"sha512-ujwfqnhkw7XVAhNXuzKACDJlftH+bGZPwH2zdhdO13Ahoj1oy4pC2u0fLJEH19czwg3+bxF6UptYFd1PQTcs2A==","signatures":[{"sig":"MEUCIH5SrBqEisKxVf3A/U8i4cmsOTTbhhN90edsFXcOPXmvAiEAmP6p9sa43p0Foaxq69/1K/Cy8NUfuCdteJK1veTQQ8w=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":46186},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"78af24a90af61b42f36c193e3aa5ea52a69daa19","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"corroding","email":"corrode.app@gmail.com"},"_npmVersion":"11.6.0","description":"Auto-generate type-safe route manifests for Next.js. Eliminate ghost strings.","directories":{},"_nodeVersion":"22.14.0","dependencies":{"chokidar":"^4.0.3"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","vitest":"^4.1.8","typescript":"^6.0.3","@types/node":"^25.9.1"},"peerDependencies":{"next":">=13.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/next-routes_0.1.0_1780357099054_0.21440677113628026","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@corrodekit/next-routes","version":"0.1.1","keywords":["nextjs","next","routes","type-safe","typesafe","codegen","app-router","pages-router","routing","ghost-strings"],"author":"","license":"MIT","_id":"@corrodekit/next-routes@0.1.1","maintainers":[{"name":"corroding","email":"corrode.app@gmail.com"}],"bin":{"corrode-routes":"dist/cli.js"},"dist":{"shasum":"2b49243f533ef208869e1c0b02d6d2e0f66c5574","tarball":"https://registry.npmjs.org/@corrodekit/next-routes/-/next-routes-0.1.1.tgz","fileCount":13,"integrity":"sha512-nKEbkiXcTGRSccoCW+ohH02Dpn7VY+0yYLtBZsZv/9hzGq6RkAteI2mKi0dbfY4ngy6y7Y8HV6jkPkHnEU9CvA==","signatures":[{"sig":"MEUCIQD8wxevUMrIgA/wDF+2EBTJgc/a2lAcoQCWSFCZwBA89wIgOh1BG4sgINvRPKA4kWMTSR+/f6/WbBB5SrdSt8JPFs8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":46276},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"288a08d2132ffb43a0f6e972b6eaea75ac08d6f5","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"corroding","email":"corrode.app@gmail.com"},"_npmVersion":"11.6.0","description":"Auto-generate type-safe route manifests for Next.js. Eliminate ghost strings.","directories":{},"_nodeVersion":"22.14.0","dependencies":{"chokidar":"^4.0.3"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","vitest":"^4.1.8","typescript":"^6.0.3","@types/node":"^25.9.1"},"peerDependencies":{"next":">=13.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/next-routes_0.1.1_1780359806130_0.22094228515924108","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@corrodekit/next-routes","version":"0.1.2","keywords":["nextjs","next","routes","type-safe","typesafe","codegen","app-router","pages-router","routing","ghost-strings"],"author":"","license":"MIT","_id":"@corrodekit/next-routes@0.1.2","maintainers":[{"name":"corroding","email":"corrode.app@gmail.com"}],"bin":{"corrode-routes":"dist/cli.js"},"dist":{"shasum":"d2f09e7f8e896197e9c45a9456af8f3d0b4f5f1b","tarball":"https://registry.npmjs.org/@corrodekit/next-routes/-/next-routes-0.1.2.tgz","fileCount":13,"integrity":"sha512-Ty3idwUzriyVUP9E41ALi4LPTVK85FTG3kxLvmcl9slzLurGmscPZH1CKAxvXRz9nvRlHYKjh8cT97Qf2JGUyQ==","signatures":[{"sig":"MEYCIQCnAIOwHqeZR7SYkgBivzJM1bRt6SBMAhv4FZJMevWWTQIhANaEHlqE3+NpqpPA8bnVW2eg5oyDxICsTAfgbeY0K8Nn","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":51757},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"9e140544619aa1df6733ed9bd38d758a32c86b7a","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"corroding","email":"corrode.app@gmail.com"},"_npmVersion":"11.6.0","description":"Auto-generate type-safe route manifests for Next.js. Eliminate ghost strings.","directories":{},"_nodeVersion":"22.14.0","dependencies":{"chokidar":"^4.0.3"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","vitest":"^4.1.8","typescript":"^6.0.3","@types/node":"^25.9.1"},"peerDependencies":{"next":">=13.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/next-routes_0.1.2_1780397011874_0.6312892000039396","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@corrodekit/next-routes","version":"0.2.1","description":"Auto-generate type-safe route manifests for Next.js. Eliminate ghost strings.","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"bin":{"corrode-routes":"dist/cli.js"},"scripts":{"build":"tsup","dev":"tsup --watch","test":"vitest run","test:watch":"vitest","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"keywords":["nextjs","next","routes","type-safe","typesafe","codegen","app-router","pages-router","routing","ghost-strings"],"author":"","license":"MIT","engines":{"node":">=18.0.0"},"peerDependencies":{"next":">=13.0.0"},"peerDependenciesMeta":{"next":{"optional":true}},"dependencies":{"chokidar":"^4.0.3"},"devDependencies":{"@types/node":"^25.9.1","tsup":"^8.5.1","typescript":"^6.0.3","vitest":"^4.1.8"},"_id":"@corrodekit/next-routes@0.2.1","gitHead":"df16aab7e619ee92a10723b7067047f58c33328c","_nodeVersion":"22.14.0","_npmVersion":"11.6.0","dist":{"integrity":"sha512-ERtf38qlMPp5RxSN+tVja1IrxdMZCCE1cLFo3ZKnQBnDUES9GYbrFOVeBMI0gDZd2/tVbSlNPbN+pIFHmPdTuA==","shasum":"3015806471ccf4fb974a9005cd42cc23700d1f04","tarball":"https://registry.npmjs.org/@corrodekit/next-routes/-/next-routes-0.2.1.tgz","fileCount":13,"unpackedSize":53314,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCovurIXITR/MalCVuU5jctLMkKWkjLGaf9HTixYMi5XgIgWTQcwF1IJ300nZxK6FaI8g6OcUDdX2SJbMx7KEdtP1M="}]},"_npmUser":{"name":"corroding","email":"corrode.app@gmail.com"},"directories":{},"maintainers":[{"name":"corroding","email":"corrode.app@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/next-routes_0.2.1_1787578619027_0.9540445293559718"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-01T23:38:18.864Z","modified":"2026-08-24T13:36:59.344Z","0.1.0":"2026-06-01T23:38:19.197Z","0.1.1":"2026-06-02T00:23:26.281Z","0.1.2":"2026-06-02T10:43:32.048Z","0.2.1":"2026-08-24T13:36:59.163Z"},"license":"MIT","keywords":["nextjs","next","routes","type-safe","typesafe","codegen","app-router","pages-router","routing","ghost-strings"],"description":"Auto-generate type-safe route manifests for Next.js. Eliminate ghost strings.","maintainers":[{"name":"corroding","email":"corrode.app@gmail.com"}],"readme":"# @corrodekit/next-routes - Next.js Route Manifest Generator\n\nA minimal overhead routing manifest generator for Next.js. This package **auto-generates type-safe route manifests**, eliminating type-unsafe routes. It scans your `app/` and `pages/` directories, understands route groups, dynamic slugs, and catch-alls, and produces a statically typed `ROUTES` dictionary at both dev-time and build-time.\n\nNo more silent runtime errors. Just reliable, type-checked routes that scale with your project.\n\n---\n\n## The Problem\n\nNext.js has a **type-unsafe routes** or **magic string routes** problem. When navigating between pages, you hardcode route paths as strings:\n\n```typescript\nrouter.push(\"/dashboard/analytics\"); // What if you rename the folder?\n```\n\nIf you ever rename a folder, move a page, or restructure your app — **nothing breaks at compile time**. The bug silently ships to production.\n\n## The Solution\n\n`@corrodekit/next-routes` automatically scans your `app/` and `pages/` directories and generates a statically-typed `ROUTES` object. Every route path becomes a **type-safe constant** — rename a folder and TypeScript catches it instantly.\n\n---\n\n## Features\n\n- **Zero Runtime Overhead** — Generates a static TypeScript file with `as const` assertions\n- **Auto-Detection** — Scans `src/app`, `app`, `src/pages`, and `pages` automatically\n- **Next.js Base Path Support** — Reads `basePath` from `next.config.ts/js` and applies it\n- **Change-Detection Writes** — Only writes when routes actually change, preventing infinite dev server loops\n- **Stable Alphabetical Output** — Keys in the generated file are sorted alphabetically, so adding a page is a small git diff instead of a full reshuffle\n- **Route Groups & Interceptors** — Correctly handles `(group)` transparency and skips `(.)` interceptors\n- **Cross-Platform Watching** — Uses [chokidar](https://github.com/paulmillr/chokidar) for reliable file watching on Windows, macOS, and Linux\n- **Security Hardened** — Path boundary enforcement, prototype pollution protection, symlink-safe traversal, and bundler-proof output serialization\n\n---\n\n## Requirements\n\n- **Node.js** >= 18.0.0\n- **Next.js** >= 13.0.0\n\n---\n\n## Installation\n\n```bash\nnpm install @corrodekit/next-routes\n```\n\n---\n\n## Quick Start\n\n### 1. Programmatic Hook in `next.config.ts` (Recommended)\n\nInvoke the watcher directly in your Next.js config so routes are generated **before** compilation begins:\n\n```typescript\n// next.config.ts\nimport type { NextConfig } from \"next\";\nimport { startRouteWatcher } from \"@corrodekit/next-routes\";\n\nconst nextConfig: NextConfig = {\n  // Your config\n};\n\n// Starts watching in development — dormant in production\nstartRouteWatcher();\n\nexport default nextConfig;\n```\n\nWith optional overrides:\n\n```typescript\n// Optional\nstartRouteWatcher({\n  outputPath: \"src/app/generated/routes.ts\", // Programmatic override (optional)\n  routerType: \"both\",\n});\n```\n\n### 2. Pre-Build Script in `package.json`\n\nGenerate routes before the production build:\n\n```json\n{\n  \"scripts\": {\n    \"dev\": \"next dev\",\n    \"build\": \"corrode-routes && next build\"\n  }\n}\n```\n\n### 3. CLI\n\n```bash\n# One-shot generation\nnpx corrode-routes\n\n# Watch mode\nnpx corrode-routes --watch\n\n# Custom output path\nnpx corrode-routes --output src/routes.ts\n\n# Scan both app and pages directories\nnpx corrode-routes --router-type both\n```\n\n---\n\n## Output Example\n\nGiven this folder structure:\n\n```\napp/\n  page.tsx\n  auth/\n    login/page.tsx\n    forgot-password/page.tsx\n  dashboard/\n    page.tsx\n    analytics/page.tsx\n    catalog/tracks/[id]/page.tsx\n```\n\nThe generated file:\n\n```typescript\n/**\n * Auto-generated Route Paths By @corrodekit/next-routes\n * Docs: https://github.com/corrodeapp/next-routes\n *\n * ──────────────────────────────────────────────────────────\n * ⚠️  DO NOT MANUALLY EDIT THIS FILE — IT IS AUTO-GENERATED\n * ──────────────────────────────────────────────────────────\n */\n\nexport const ROUTES = {\n  AUTH: {\n    FORGOT_PASSWORD: \"/auth/forgot-password\",\n    LOGIN: \"/auth/login\",\n  },\n  DASHBOARD: {\n    ANALYTICS: \"/dashboard/analytics\",\n    CATALOG: {\n      TRACKS: {\n        ID: (params: { id: string | number }) =>\n          `/dashboard/catalog/tracks/${params.id}`,\n      },\n    },\n    ROOT: \"/dashboard\",\n  },\n  HOME: \"/\",\n} as const;\n\nexport type RoutePath = typeof ROUTES;\n```\n\nNow you can use it with full type safety:\n\n```typescript\nimport { ROUTES } from \"@/app/router-path\";\n\nrouter.push(ROUTES.DASHBOARD.ANALYTICS);\nrouter.push(ROUTES.DASHBOARD.CATALOG.TRACKS.ID({ id: 42 }));\n```\n\n---\n\n## Configuration\n\nBy default, the package auto-detects everything. You can customize behavior by creating a `routes.config.json` in your project root:\n\n```json\n{\n  \"outputPath\": \"src/app/generated/routes.ts\",\n  \"routerType\": \"auto\",\n  \"ignore\": [\"_components\", \"__tests__\"]\n}\n```\n\n### Config Options\n\n| Option       | Type                                   | Default                    | Description                                         |\n| :----------- | :------------------------------------- | :------------------------- | :-------------------------------------------------- |\n| `appDir`     | `string`                               | _Auto-detected_            | Custom path to the App Router directory.            |\n| `pagesDir`   | `string`                               | _Auto-detected_            | Custom path to the Pages Router directory.          |\n| `outputPath` | `string`                               | `\"src/app/router-path.ts\"` | Target file path for the generated TypeScript file. |\n| `basePath`   | `string`                               | _Auto-detected_            | Prepends a prefix path to all routes.               |\n| `ignore`     | `string[]`                             | `[]`                       | Extra folder names to skip during scanning.         |\n| `routerType` | `\"app\" \\| \"pages\" \\| \"both\" \\| \"auto\"` | `\"auto\"`                   | Restricts parsing to a specific router pattern.     |\n\n### Router Type Resolution\n\n- **`\"auto\"` (Default)** — Detects which directory exists. Prioritizes `app/` if present.\n- **`\"app\"`** — Only scans the App Router (`app/` or `src/app/`).\n- **`\"pages\"`** — Only scans the Pages Router (`pages/` or `src/pages/`).\n- **`\"both\"`** — Scans both directories and merges into a single route dictionary.\n\n---\n\n## CLI Reference\n\n```\ncorrode-routes [options]\n\nOptions:\n  --watch              Watch for file changes and regenerate routes\n  --output <path>      Custom output file path (default: auto-detected)\n  --base-path <path>   Base path prefix for all routes\n  --router-type <type> Router type: app, pages, both, auto (default: auto)\n  --help               Show this help message\n```\n\n---\n\n## Package Structure\n\n```\n@corrodekit/next-routes/\n├── src/\n│   ├── types.ts          # Shared interfaces, type guards, and config schemas\n│   ├── helpers.ts        # Utility functions (debounce, key generation, ignore logic)\n│   ├── security.ts       # Security utilities (path boundaries, sanitization, symlinks)\n│   ├── detection.ts      # Auto-detection of app/pages dirs, basePath, config loading\n│   ├── traversal.ts      # Pure directory scanners (App Router + Pages Router)\n│   ├── builder.ts        # Nested tree builder (flat record → hierarchy)\n│   ├── stringifier.ts    # TypeScript code-generator (tree → TS source string)\n│   ├── core.ts           # Main orchestrator (scan → build → write)\n│   ├── watcher.ts        # File watcher (chokidar-powered, cross-platform)\n│   ├── cli.ts            # CLI entry point (arg parsing + dispatch)\n│   └── index.ts          # Public API barrel export\n├── tests/\n│   ├── helpers.test.ts\n│   ├── builder.test.ts\n│   ├── stringifier.test.ts\n│   ├── traversal.test.ts\n│   ├── security.test.ts\n│   └── stable-order.test.ts\n├── package.json\n├── tsconfig.json\n├── tsup.config.ts\n├── LICENSE\n└── README.md\n```\n\n---\n\n## How It Works\n\n```mermaid\ngraph TD\n    A[npm run dev / next dev] --> B[Next.js boots Node process]\n    B --> C[next.config.ts evaluated]\n    C --> D[startRouteWatcher runs]\n    D --> E[Scan folders & write router-path.ts]\n    E --> F[Chokidar watches for changes]\n    F -->|File change detected| E\n    E --> G[Next.js Bundler starts]\n    G --> H[Page compilation is 100% type-safe]\n```\n\n---\n\n## Internal Architecture\n\nIf you are exploring the codebase, the package is built using strict single-responsibility modules:\n\n```mermaid\ngraph LR\n    CLI[cli.ts] --> Core[core.ts]\n    CLI --> Watcher[watcher.ts]\n    Watcher --> Core\n    Core --> Detection[detection.ts]\n    Core --> Traversal[traversal.ts]\n    Core --> Builder[builder.ts]\n    Core --> Stringifier[stringifier.ts]\n    Traversal --> Helpers[helpers.ts]\n    Traversal --> Security[security.ts]\n    Detection --> Security\n    Detection --> Types[types.ts]\n    Index[index.ts] --> Core\n    Index --> Watcher\n```\n\n---\n\n## License\n\n[MIT](./LICENSE)\n","readmeFilename":"readme.md"}