{"_id":"@anil-labs/vue-routing","_rev":"2-2c37fa4fccb993f62397b1599f2fe652","name":"@anil-labs/vue-routing","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@anil-labs/vue-routing","version":"0.1.0","keywords":["vue","vue-router","router","routing","laravel","typescript","middleware"],"author":{"url":"https://github.com/anilkumarthakur60","name":"Anil Kumar Thakur"},"license":"MIT","_id":"@anil-labs/vue-routing@0.1.0","maintainers":[{"name":"anilkumarthakur","email":"anilkumarthakur60@gmail.com"}],"homepage":"https://github.com/anilkumarthakur60/vue-routing#readme","bugs":{"url":"https://github.com/anilkumarthakur60/vue-routing/issues"},"dist":{"shasum":"69f6ba3b12b6b4b300b2a18479445ebb6d828bd2","tarball":"https://registry.npmjs.org/@anil-labs/vue-routing/-/vue-routing-0.1.0.tgz","fileCount":7,"integrity":"sha512-FHEkjtSQ4XfydTUhGRUamgRHc75tZw2iwTwglwQjUMkAQVs/AdG258cheMftaW8EAjx/8MXCyjHpu0CPuqQT2g==","signatures":[{"sig":"MEYCIQDRLgHiCZbC0QHV+ng1sLoe27Smy+eMQakXPRI/uMxZagIhALQCy7LKUWgGEusw24fgNZjWq/tGBZYMJWU0UqeckFSA","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":151164},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20.19.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"7717c38390a566ec6d14eeeaa97cad078294f6e9","scripts":{"dev":"vite","lint":"eslint .","test":"vitest run","build":"tsup","format":"prettier --write .","preview":"vite preview","docs:dev":"vitepress dev docs","lint:fix":"eslint . --fix","typecheck":"vue-tsc -b","build:demo":"vue-tsc -b && vite build --config vite.demo.config.ts","docs:build":"vitepress build docs","test:watch":"vitest","docs:preview":"vitepress preview docs","format:check":"prettier --check .","preview:demo":"vite preview --config vite.demo.config.ts","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"anilkumarthakur","email":"anilkumarthakur60@gmail.com"},"repository":{"url":"git+https://github.com/anilkumarthakur60/vue-routing.git","type":"git"},"_npmVersion":"11.11.0","description":"Laravel-inspired, fully-typed declarative routing for Vue 3 — a fluent wrapper over vue-router.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.5.34","tsup":"^8.5.1","vite":"^8.0.12","eslint":"^10.4.1","vitest":"^3.2.4","vue-tsc":"^3.2.8","prettier":"^3.8.3","happy-dom":"^20.0.0","vitepress":"^1.6.4","@eslint/js":"^10.0.1","typescript":"~6.0.2","vue-router":"^4.6.4","@types/node":"^24.12.3","@vue/tsconfig":"^0.9.1","@vue/test-utils":"^2.4.10","eslint-plugin-vue":"^10.9.1","typescript-eslint":"^8.60.0","@vitejs/plugin-vue":"^6.0.6","@vitest/coverage-v8":"^3.2.4","@vue/eslint-config-prettier":"^10.2.0","@vue/eslint-config-typescript":"^14.7.0"},"peerDependencies":{"vue":"^3.5.0","vue-router":"^4.5.0"},"_npmOperationalInternal":{"tmp":"tmp/vue-routing_0.1.0_1780537831985_0.6382485333718524","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@anil-labs/vue-routing","version":"0.1.1","type":"module","description":"Laravel-inspired, fully-typed declarative routing for Vue 3 — a fluent wrapper over vue-router.","keywords":["vue","vue-router","router","routing","laravel","typescript","middleware"],"license":"MIT","author":{"name":"Anil Kumar Thakur","url":"https://github.com/anilkumarthakur60"},"repository":{"type":"git","url":"git+https://github.com/anilkumarthakur60/vue-routing.git"},"homepage":"https://github.com/anilkumarthakur60/vue-routing#readme","bugs":{"url":"https://github.com/anilkumarthakur60/vue-routing/issues"},"engines":{"node":">=20.19.0"},"publishConfig":{"access":"public"},"sideEffects":false,"main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"scripts":{"dev":"vite","build":"tsup","prepublishOnly":"npm run build","preview":"vite preview","build:demo":"vue-tsc -b && vite build --config vite.demo.config.ts","preview:demo":"vite preview --config vite.demo.config.ts","typecheck":"vue-tsc -b","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","lint":"eslint .","lint:fix":"eslint . --fix","format":"prettier --write .","format:check":"prettier --check .","docs:dev":"vitepress dev docs","docs:build":"vitepress build docs","docs:preview":"vitepress preview docs"},"peerDependencies":{"vue":"^3.5.0","vue-router":"^4.5.0 || ^5.0.0"},"devDependencies":{"@eslint/js":"^10.0.1","@types/node":"^25.9.1","@vitejs/plugin-vue":"^6.0.7","@vitest/coverage-v8":"^4.1.8","@vue/eslint-config-prettier":"^10.2.0","@vue/eslint-config-typescript":"^14.7.0","@vue/test-utils":"^2.4.10","@vue/tsconfig":"^0.9.1","eslint":"^10.4.1","eslint-plugin-vue":"^10.9.2","happy-dom":"^20.10.1","prettier":"^3.8.3","tsup":"^8.5.1","typescript":"~6.0.3","typescript-eslint":"^8.60.1","vite":"^8.0.16","vitepress":"^1.6.4","vitest":"^4.1.8","vue":"^3.5.35","vue-router":"^5.1.0","vue-tsc":"^3.3.3"},"gitHead":"c5f57b495edc62251439037c356909ccf2bce24b","_id":"@anil-labs/vue-routing@0.1.1","_nodeVersion":"24.14.1","_npmVersion":"11.11.0","dist":{"integrity":"sha512-igFc8voFAsrQM4MkovJxASiOI9MVLN60GRh3z2Ql+gDHcY9QcNMOu4YPjsV1GwE+Q/+0zMQIXZ5eZl84DMHDGQ==","shasum":"372f23d7da1f797cfbb48b26c3579f178026b658","tarball":"https://registry.npmjs.org/@anil-labs/vue-routing/-/vue-routing-0.1.1.tgz","fileCount":7,"unpackedSize":151174,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDGHhgM3n9Nzl9L8v+TcIrjLRKBzpxUAgCxzEIGEOM5vgIgOB2kMwgYwoW01CxdBYtTtu2iCK/h7qWnBmMIY/eSPdQ="}]},"_npmUser":{"name":"anilkumarthakur","email":"anilkumarthakur60@gmail.com"},"directories":{},"maintainers":[{"name":"anilkumarthakur","email":"anilkumarthakur60@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/vue-routing_0.1.1_1780541923969_0.24431159838356598"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-04T01:50:31.853Z","modified":"2026-06-04T02:58:44.251Z","0.1.0":"2026-06-04T01:50:32.125Z","0.1.1":"2026-06-04T02:58:44.125Z"},"bugs":{"url":"https://github.com/anilkumarthakur60/vue-routing/issues"},"author":{"name":"Anil Kumar Thakur","url":"https://github.com/anilkumarthakur60"},"license":"MIT","homepage":"https://github.com/anilkumarthakur60/vue-routing#readme","keywords":["vue","vue-router","router","routing","laravel","typescript","middleware"],"repository":{"type":"git","url":"git+https://github.com/anilkumarthakur60/vue-routing.git"},"description":"Laravel-inspired, fully-typed declarative routing for Vue 3 — a fluent wrapper over vue-router.","maintainers":[{"name":"anilkumarthakur","email":"anilkumarthakur60@gmail.com"}],"readme":"# @anil-labs/vue-routing\n\nLaravel-inspired, fully-typed declarative routing for **Vue 3** — a thin, ergonomic wrapper over [`vue-router`](https://router.vuejs.org/). Define routes with a fluent `Route` facade (groups, layouts, middleware, resources, constraints, named routes, model bindings) and let the package build the `vue-router` tree for you.\n\n```ts\nRoute.middleware(auth)\n  .layout(MainLayout)\n  .group(() => {\n    Route.redirect('', '/dashboard')\n    Route.view('dashboard', () => import('@/pages/Dashboard.vue')).name('dashboard')\n    Route.resource('users', UsersPage, { only: ['index', 'show'] })\n  })\n```\n\n## Install\n\n```bash\nnpm i @anil-labs/vue-routing\n```\n\n`vue` (^3.5) and `vue-router` (^4.5) are **peer dependencies** — provide them in your app.\n\n## Quick start\n\n**`router/web.ts`** — declare routes:\n\n```ts\nimport { Route } from '@anil-labs/vue-routing'\nimport MainLayout from '@/layouts/MainLayout.vue'\nimport auth from '@/middleware/auth'\n\nRoute.middleware(auth)\n  .layout(MainLayout)\n  .group(() => {\n    Route.redirect('', '/dashboard')\n    Route.view('dashboard', () => import('@/pages/Dashboard.vue')).name('dashboard')\n\n    Route.prefix('users')\n      .asPrefix('users')\n      .group(() => {\n        Route.view('', () => import('@/pages/Users.vue')).name('index')\n      })\n  })\n\nRoute.fallback(() => import('@/pages/NotFound.vue'))\n\nexport default Route.getRoutes()\n```\n\n**`router/index.ts`** — create the router:\n\n```ts\nimport { createAppRouter, Route } from '@anil-labs/vue-routing'\nimport routes from './web'\n\nexport default createAppRouter({\n  routes,\n  historyMode: 'history', // 'history' | 'hash' | 'memory'\n  bindings: Route.getBindings(), // optional: enable model bindings\n})\n```\n\n> **GET-only.** This is a client-side router: every route is reached by\n> navigation. There are no `post`/`put`/`delete` verbs — those are server\n> concerns. The only verb is `get` (plus `view`, `redirect`, `fallback`,\n> `resource`).\n\n## Features\n\n| Capability        | API                                                                                           |\n| ----------------- | --------------------------------------------------------------------------------------------- |\n| Routes            | `Route.get(uri, component)`, `Route.view(uri, component, props?)`                             |\n| Redirects         | `Route.redirect(from, to, status?)`, `Route.permanentRedirect(from, to)`                      |\n| Named routes      | `.name('x')` / `.as('x')`, plus group `name()`/`asPrefix()` prefixes                          |\n| Groups            | `Route.middleware(...).prefix(...).group(cb)`                                                 |\n| Layouts (nested)  | `Route.layout(Comp).group(cb)` — wraps routes in `<router-view>` parents                      |\n| Middleware        | per-route `.middleware(...)` / `.withoutMiddleware(...)`, group-level, auto-merged            |\n| Param constraints | `.where({...})`, `.whereNumber/whereAlpha/whereAlphaNumeric/whereUuid/whereUlid/whereIn(...)` |\n| Global patterns   | `Route.pattern(name, regex)` / `Route.patterns({...})`                                        |\n| Resources         | `Route.resource(name, comp, opts?)` → navigable `index`/`create`/`show`/`edit` only           |\n| Model bindings    | `Route.bind(param, resolver)` / `Route.model(...)` + `.missing(handler)`                      |\n| Subdomains        | `Route.domain('{account}.example.com').group(cb)`                                             |\n| URL generation    | `Route.route(name, params?)` → string                                                         |\n| Inspection        | `Route.has(name)`, `Route.toList()`, `Route.list()`                                           |\n\n### Laravel-style parameters\n\nBoth `{param}` and `vue-router` `:param` syntaxes work and interoperate:\n\n```ts\nRoute.get('users/{id}', UserPage).whereNumber('id').name('users.show')\nRoute.get('user/{name?}', UserPage).name('user') // optional\nRoute.get('posts/{post:slug}', PostPage).name('posts.show') // custom key\n```\n\n### Model bindings\n\n```ts\nRoute.get('users/{user}', UserPage)\n  .name('users.show')\n  .missing(() => ({ name: 'users.index' }))\n\nRoute.bind('user', (value) => fetchUser(value)) // return null ⇒ triggers missing()\n```\n\nResolved models are exposed in components via the `useBoundModels` composable:\n\n```ts\nimport { useBoundModels } from '@anil-labs/vue-routing'\nconst models = useBoundModels<{ user: User }>()\n// models.value.user\n```\n\n> Laravel's _implicit_ (type-hint) binding can't exist client-side — there's no\n> reflection or DB. Use explicit `Route.bind()` / `Route.model()` resolvers.\n\n### Composables\n\n`useRouteName()`, `useRouteAction()`, `useIsRoute(name)`, `useBoundModels<T>()`, `useSubdomainParams()` — all reactive; call within `setup()`.\n\n## Type safety\n\nWritten in strict TypeScript with **zero `any`**. The package augments\n`vue-router`'s `RouteMeta`, so `to.meta.middleware`, `to.meta.bound`, etc. are\ntyped everywhere — in this package and in your app.\n\n## Not applicable in an SPA\n\nThese Laravel routing features are server-side concerns and are intentionally\n**not** implemented: HTTP verbs other than GET, CSRF, form-method spoofing, rate\nlimiting, route caching, CORS, and controller dispatch (your component _is_ the\nhandler).\n\n## Demo\n\nA full interactive demo lives in [`demo/`](./demo) and exercises every feature —\nlayouts, middleware (auth/guest/log), redirects, optional & constrained params,\nresources, model binding with `missing()`, URL generation, the route table, and 404. It imports the package by its published name.\n\n```bash\nnpm run dev           # run the demo locally\nnpm run build:demo    # build the demo SPA into demo-dist/\nnpm run preview:demo  # preview the production build\n```\n\n### Deploy the demo to Vercel\n\nThe repo includes [`vercel.json`](./vercel.json), which points Vercel at the demo\nbuild and adds the SPA fallback rewrite (required for vue-router history mode):\n\n```json\n{\n  \"buildCommand\": \"npm run build:demo\",\n  \"outputDirectory\": \"demo-dist\",\n  \"rewrites\": [{ \"source\": \"/(.*)\", \"destination\": \"/index.html\" }]\n}\n```\n\n- **Dashboard:** import the repo at [vercel.com/new](https://vercel.com/new) — it\n  auto-detects `vercel.json`, so no manual settings are needed.\n- **CLI:** `npm i -g vercel && vercel` (then `vercel --prod`).\n\n> The default `npm run build` is the **library** build (for npm publishing). The\n> demo uses a separate config (`vite.demo.config.ts`), so the two never collide.\n\n## Documentation\n\nFull docs are built with VitePress in [`docs/`](./docs):\n\n```bash\nnpm run docs:dev      # serve docs locally\nnpm run docs:build    # build static docs\n```\n\n## Development\n\n```bash\nnpm run dev           # run the demo app (demo/)\nnpm test              # vitest (tests/)\nnpm run typecheck     # vue-tsc\nnpm run build         # bundle + .d.ts into dist/\nnpm run lint          # eslint\nnpm run format        # prettier --write\nnpm run format:check  # prettier --check\n```\n\n## Continuous integration & releases\n\nGitHub Actions workflows live in [`.github/workflows`](./.github/workflows):\n\n| Workflow                                                | Trigger                    | What it does                                                         |\n| ------------------------------------------------------- | -------------------------- | -------------------------------------------------------------------- |\n| **CI** (`ci.yml`)                                       | push to `main`, PRs        | lint, format check, typecheck, test, build lib + demo (Node 20 & 22) |\n| **Release** (`release.yml`)                             | a published GitHub Release | verify, build, `npm publish` (public, with provenance)               |\n| **Docs** (`docs.yml`)                                   | push to `main`             | build VitePress and deploy to GitHub Pages                           |\n| **Dependabot auto-merge** (`dependabot-auto-merge.yml`) | Dependabot PRs             | approve + auto-merge patch/minor bumps (majors stay manual)          |\n\nDependencies are kept current by [`dependabot.yml`](./.github/dependabot.yml)\n(weekly npm + GitHub Actions updates, grouped by type).\n\nOne-time setup:\n\n1. **Publishing** — add an npm token as the repo secret **`NPM_TOKEN`**\n   (Settings → Secrets and variables → Actions). To release: bump the version,\n   then publish a GitHub Release/tag — the workflow runs `npm publish`.\n   (`publishConfig` already sets `access: public` + provenance.)\n2. **Docs (GitHub Pages)** — Settings → Pages → Source: **GitHub Actions**. The\n   docs base path is set automatically to `/<repo>/` in CI.\n3. **Demo (Vercel)** — handled by Vercel's native Git integration via\n   [`vercel.json`](./vercel.json); no workflow or secret needed.\n4. **Auto-merge** — enable **Settings → General → Allow auto-merge**, and add a\n   branch-protection rule on `main` requiring the CI checks. Auto-merge then\n   waits for green CI before merging Dependabot's patch/minor PRs.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}