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

@devfellowship/ux-paths-routes

v0.1.0

Published

The DFL UX Paths route extractor: read an app repo's routing (a React-Router <Routes> tree, an Expo Router or Next app-router file tree) and emit the routes it serves, each with the source file that renders it.

Readme

@devfellowship/ux-paths-routes

Read an app repo's routing and print the routes it serves — each with the source file that renders it. No schema, no validator, no flows tooling: the route extractor and what the extractor needs.

npm install @devfellowship/ux-paths-routes
npx ux-paths-routes . --convention react-router --format lines
/
/admin
/admin/completion
…

What it reads

Three conventions, auto-detected in this order:

| Convention | How the route is found | |---|---| | Expo Router | the file path — app/profile/settings.tsx/profile/settings | | Next.js app router | the file path of a page.* file — app/studio/[id]/page.tsx/studio/:id | | React Router | the SOURCE is parsed — the route lives in a JSX expression, not in the path |

The React-Router adapter uses the TypeScript compiler's own parser, never a regex and never a model. It reads nested and layout routes, element={<RequireAuth><Page/></RequireAuth>} (the page is the innermost component; the wrappers become guards[]), lazy(() => import('./P')) as well as static imports, <Route index>, :param, the * catch-all, path={SOME_CONST} where the constant is a string literal in this file or exported by another module, <Navigate> (reported separately — a redirect renders no screen), and barrel re-exports (import { Auth } from '../pages' is followed to the file that defines Auth, because that is the file the screen must point at).

A regex gets most of this wrong in ways that produce a WRONG answer rather than a missing one. Children of <Route path="/admin"> are declared with RELATIVE paths, so a grep for path="…" reports roster where the app serves /admin/roster. And path={GUEST_ROUTE_PATH} is an identifier, so a grep skips it silently and never notices the route disappearing.

What it never does: guess

  • A route whose COMPONENT cannot be resolved comes back with component_file: null and an unresolved_reason. It is never dropped: the app serves that URL either way, and the route list stays correct.
  • A route whose PATH cannot be read is worse — route then holds the parent's path, which is wrong rather than incomplete. That entry carries path_unreadable: true, and --format lines refuses on it (exit 2) rather than print it.
  • --format lines also refuses an empty list. A consumer that compares this output against a declared route set reads "no routes" as "every declared route is stale".

API

import { resolveRoutes } from '@devfellowship/ux-paths-routes';

const result = resolveRoutes('/path/to/app', { convention: 'react-router' });
// result.convention   'react-router' | 'expo-router' | 'next-app-router' | 'unknown'
// result.router_file  the file the <Routes> tree was read from
// result.routes[]     { route, component_file, guards?, index?, layout?, … }
// result.redirects[]  <Navigate> routes — declared, but they render no screen
// result.unresolved[] the subset of routes[] carrying an unresolved_reason

The package is ESM-only. Do not reach for it with createRequire(…).resolve('@devfellowship/ux-paths-routes') — an ESM-only package with an exports map has no require condition, and Node answers ERR_PACKAGE_PATH_NOT_EXPORTED, which reads like a broken install. Use the bin, or await import(…). ./package.json IS exported, so a caller that needs to locate the install can read the manifest.

CLI

ux-paths-routes [repoPath] [options]

  --convention <name>      auto | expo-router | next-app-router | react-router
  --router-file <path>     React Router only: repo-relative file holding <Routes>
  --format <name>          json (default) | lines
  --pretty                 JSON only: indent
  --full                   JSON only: the whole result, not just routes[]

Exit codes: 0 ok, 1 the arguments or the repo could not be read, 2 (--format lines) the routing was read but the answer would be wrong or empty.

Notes, warnings and the unresolved list go to stderr, so stdout stays exactly the routes.

In CI

This is what a ux-paths guard calls to learn the routes the code actually serves:

- name: Extract the routes the code actually serves
  run: |
    set -euo pipefail
    mkdir -p /tmp/ux-paths-tools && cd /tmp/ux-paths-tools
    npm init -y >/dev/null 2>&1
    npm install --no-save --no-audit --no-fund @devfellowship/ux-paths-routes@^0.1.0
    cd "$GITHUB_WORKSPACE"
    /tmp/ux-paths-tools/node_modules/.bin/ux-paths-routes . \
      --convention react-router --format lines > "$RUNNER_TEMP/routes.txt"

A directory of its own, rather than the repo's node_modules, is deliberate: a blocking gate that needs a full application install (and the token that install needs) ends up permanently red for reasons that have nothing to do with the map.

Dependencies

One: typescript, the JSX parser. It is loaded on first use, not at import time, so a caller that only resolves an Expo Router tree never pays for it.

Where it lives

Source: devfellowship/dfl-ux-paths, directory routes/. The dfl-ux-paths CLI re-exports this package rather than keeping a copy, so there is one implementation of the adapter and one test suite behind it.

Its sibling @devfellowship/ux-paths-spec carries the other half — the v1 JSON Schema, the types generated from it, and a zero-dependency validate().

MIT.