npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@izzyjs/route

v2.2.0

Published

Use your AdonisJs routes in your Inertia.js application

Readme

@izzyjs/route

GitHub Actions Status Coverage Status npm version License

Use your named AdonisJS routes in JavaScript — like Ziggy does for Laravel, but for AdonisJS and Inertia.

It gives you a route() helper on the client with full TypeScript inference: route names are autocompleted, required parameters are enforced at compile time, and you never hardcode a URL again.

Works with AdonisJS v6 and v7.

Installation

node ace add @izzyjs/route

That single command installs the package and configures everything: the provider, the middleware, the Japa plugin, the config/izzyjs.ts file, and an initial route generation.

npm install @izzyjs/route
node ace configure @izzyjs/route

The configure step does the same wiring as node ace add.

Regenerating routes

Route definitions (and their TypeScript types) are generated from your named routes:

node ace izzy:routes

To regenerate automatically whenever the dev server starts, register the dev hook in adonisrc.ts:

// adonisrc.ts — AdonisJS v7 (assembler v8)
{
  hooks: {
    devServerStarted: [() => import('@izzyjs/route/dev_hook')],
  },
}
// adonisrc.ts — AdonisJS v6 (assembler v7)
{
  unstable_assembler: {
    onDevServerStarted: [() => import('@izzyjs/route/dev_hook')],
  },
}

Exposing routes to the browser

Add the @routes() tag to your Edge layout, before your app scripts:

<!-- resources/views/inertia_layout.edge -->
<!doctype html>
<html>
  <head>
    @routes()
    @vite(['resources/js/app.js'])
  </head>
  <body>
    @inertia()
  </body>
</html>

This injects your (filtered) route list into the page so route() can resolve names at runtime.

Configuration

config/izzyjs.ts is created for you. baseUrl is required — it's what powers the url property (complete URLs with protocol and domain):

// config/izzyjs.ts
import { defineConfig } from '@izzyjs/route'

export default defineConfig({
  baseUrl: process.env.APP_URL || 'http://localhost:3333',

  routes: {
    // Pick one: `only` or `except`. Setting both disables filtering.
    // only: ['home', 'posts.*'],
    except: ['_debugbar.*', 'admin.*'],

    // Optional named groups (see "Route groups" below)
    groups: {
      admin: ['admin.*', 'users.*'],
      public: ['home', 'about', 'contact'],
    },
  },
})

Filtering routes

Every route you expose is visible in the HTML source, so filter out what the client doesn't need. Patterns support * wildcards: admin.* matches admin.login, admin.users.index, and so on.

Note: Filtering is not a security measure. Routes that shouldn't be publicly reachable must be protected by authentication, whether they appear in the client list or not.

Usage

import { route } from '@izzyjs/route/client'

// Route without parameters
route('users.index').path // "/users"

// Route with parameters
route('users.show', { params: { id: '1' } }).path // "/users/1"

TypeScript enforces the parameters for you:

route('users.show', { params: { id: '123' } }) // ✅
route('users.show') // ❌ compile error: missing required param `id`
route('users.show', { params: { slug: 'x' } }) // ❌ compile error: unknown param

Options

The second argument accepts params, qs (query string), prefix, and hash:

const url = route('users.show', {
  params: { id: '1' },
  qs: { page: '2' },
  prefix: '/api/v1',
  hash: 'profile',
})

url.path // "/api/v1/users/1?page=2#profile"
url.url // "https://example.com/api/v1/users/1?page=2#profile"
url.method // "get"
url.pattern // "/users/:id"
url.name // "users.show"
url.qs // URLSearchParams
url.hash // "profile"

The returned object extends String, so you can use it directly wherever a string is expected (e.g. href in Inertia's <Link>).

Optional parameters

Optional parameters (:slug? in your AdonisJS route) can simply be omitted:

// router.get('/posts/:id/:slug?', ...).as('posts.show')
route('posts.show', { params: { id: '123', slug: 'my-post' } }).path // "/posts/123/my-post"
route('posts.show', { params: { id: '123' } }).path // "/posts/123"

// router.get('/posts/:category?', ...).as('posts.index')
route('posts.index', { params: { category: 'tech' } }).path // "/posts/tech"
route('posts.index').path // "/posts"

Complete URLs and multi-domain apps

path is always relative; url includes protocol and host, built from baseUrl:

const user = route('users.show', { params: { id: '123' } })

user.path // "/users/123"
user.url // "https://example.com/users/123"

When a route is registered under a specific domain (AdonisJS router.group().domain(...)), url uses that domain instead of the baseUrl host — the protocol and port still come from baseUrl:

route('home').url // "https://example.com/"          (domain: root)
route('api.users.index').url // "https://api.example.com/users"  (domain: api.example.com)

If baseUrl is invalid, url falls back to the relative path.

Checking the current route

route() with no arguments returns a helper for inspecting the current request:

route().current() // "/users/1" — the current path
route().current('users.show', { id: '1' }) // true/false — match by name + params
route().current('users.*') // true/false — wildcard match
route().current('/users/*') // true/false — wildcard on the path

Matching by name is domain-aware. If admin.login and user.login both resolve to /login on different subdomains, route().current('admin.login') is only true when you're actually on the admin subdomain:

// On admin.example.com/login
route().current('admin.login') // true
route().current('user.login') // false

has() and params

route().has('users.show') // true — the named route exists
route().has('users.*') // true — at least one route matches

route().params // { id: '1' } — params extracted from the current URL

Route groups

Groups defined in your config are exported alongside the generated routes:

import { routes, groups } from '@izzyjs/route/routes'

routes // every exposed route
groups.admin // only the routes matching the `admin` group patterns
groups.public // only the `public` group

Heads up: routes and groups live in @izzyjs/route/routes (the generated file), not @izzyjs/route/client. The groups export always exists — it's an empty object when no groups are configured.

Builder: typed HTTP requests

builder combines route resolution with a fetch-based HTTP client, so you can call your own API without hardcoding URLs:

import builder from '@izzyjs/route/builder'

const result = await builder('users.show', { id: '123' })
  .withQs({ include: 'profile' })
  .request()
  .successType<User>()
  .failedType<ApiError>()
  .run()

if (result.data) {
  console.log(result.data) // typed as User
} else {
  console.log(result.error) // typed as ApiError
}

run() never throws — it always resolves to { data, error } where exactly one is set.

Sending data (POST/PUT/PATCH):

const result = await builder('users.store')
  .request()
  .withData({ name: 'John Doe', email: '[email protected]' })
  .successType<User>()
  .run()

Builder methods:

| Method | Purpose | | -------------------- | ------------------------------------------------ | | withQs(qs) | Add query string parameters | | withHash(hash) | Add a hash fragment | | withPrefix(prefix) | Prepend a path prefix | | route() | Return the resolved Route (no request made) | | request(config?) | Create the request (headers, timeout, etc.) | | withData(data) | Set the request body | | successType<T>() | Type the success payload | | failedType<T>() | Type the error payload | | run() | Execute and resolve to { data, error } |

The HTTP client automatically:

  • sends the XSRF-TOKEN cookie back as the X-XSRF-TOKEN header (CSRF protection)
  • detects Content-Type from the body (JSON, FormData, File, Blob, ArrayBuffer, plain text)
  • times out after 30s (configurable via request({ timeout }))
// Per-request configuration
await builder('users.show', { id: '123' })
  .request({
    headers: { Authorization: 'Bearer token' },
    credentials: 'include',
  })
  .run()

Testing

The configure step registers a Japa plugin that loads your named routes into the test environment, so route() works inside your tests without a running server.

Contributing

Contributions are welcome — see the Contribution Guidelines and Code of Conduct.

License

MIT License © IzzyJs