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

@pactor-app/router

v1.20.0

Published

Pactor router: menu registry, path matcher, navigation bridge and React Router dynamic route bindings

Readme

@pactor-app/router

Pactor 的路由模块:菜单模型与 MenuRegistry、极简路径匹配(PathMatcher)、导航桥接(NavigationBridge / MemoryNavigation)、@pactor-app/runtime RouterAdapter 桥接,以及 React Router 动态路由绑定(<DynamicDslRoute>)。

菜单声明 path + pageId(不绑定 React 组件),Dynamic Router 把 URL 解析为 pageId 与路由上下文;页面资源加载(pageId → loadPage)由应用组合层串联,不在本包。

安装

npm install @pactor-app/router
# 或
pnpm add @pactor-app/router

核心入口(@pactor-app/router)零 React 依赖,可纯 Node 使用与测试;React 绑定在独立子入口 @pactor-app/router/react,仅该子入口需要 peer 依赖 react >=18react-router-dom >=6(开发基准为 react-router-dom v7,仅用 v6/v7 共有的稳定 API)。

示例

import {
  MenuRegistry,
  MemoryNavigation,
  createRouterAdapter,
  resolveRoute,
} from '@pactor-app/router';

const registry = new MenuRegistry([
  {
    id: 'customer',
    type: 'group',
    title: '客户管理',
    children: [
      { id: 'customer-list', type: 'page', title: '客户列表', path: '/customers', pageId: 'customer-list' },
      {
        id: 'customer-edit', type: 'page', title: '编辑客户',
        path: '/customers/:id/edit', pageId: 'customer-edit',
        hidden: true, activeMenu: 'customer-list',
      },
    ],
  },
]);

// 1. URL → RouteContext(隐藏详情页参与匹配,activeMenu 指向列表页)
const route = resolveRoute(registry, { pathname: '/customers/123/edit', search: '?tab=risk' });
// → { path, params: { id: '123' }, query: { tab: 'risk' }, pageId: 'customer-edit',
//     menuId: 'customer-edit', activeMenu: 'customer-list' }

// 2. 桥接 @pactor-app/runtime:DSL navigate 动作驱动导航
const navigation = new MemoryNavigation();
const runtime = createPageRuntime(pageDsl, {
  router: createRouterAdapter(navigation), // navigate(to) → bridge.push(to)
  route: { params: route.params, query: route.query }, // ${route.params.id} 可求值
});

React 绑定(@pactor-app/router/react):

import { DynamicDslRoute, useReactRouterBridge } from '@pactor-app/router/react';
import { Route, Routes } from 'react-router-dom';

<Routes>
  <Route
    path="*"
    element={
      <DynamicDslRoute
        registry={registry}
        render={({ pageId, route }) => <DslPage pageId={pageId} route={route} />}
        fallback={<NotFound />}
        forbidden={<Forbidden />}
        permissionChecker={permissionStore}
      />
    }
  />
</Routes>

功能一览

  • MenuItem:对齐设计文档第 30 节字段(id/type/title/icon/order/path/pageId/permission/hidden/disabled/external/target/keepAlive/badge/activeMenu/defaultOpen/breadcrumb/tab/children),permission 用 @pactor-app/core 的 PermissionConfig
  • MenuRegistry:由菜单树构建可见菜单树(tree(),过滤 hidden)+ 扁平可路由条目列表(list(),非 group 且有 path,按 order 排序、未指定者保持声明顺序在后);findById(含 group 与隐藏项)、findByPath(按 list() 顺序模式匹配,隐藏页参与,未命中 null)。
  • PathMatchermatch(pattern, pathname) 仅支持静态段与 :param 段,整路径精确匹配(段数一致),不支持 * 与可选段;parseQuery(search) 解析查询串;resolveRoute(registry, location) 产出 RouteContext(path/params/query/pageId/menuId/activeMenu,activeMenu 取菜单项 activeMenu ?? 自身 id)。
  • NavigationBridge / MemoryNavigationgetLocation / push / replace / subscribe(返回退订函数);MemoryNavigation 为纯 Node 内存历史栈实现,另支持 back()
  • createRouterAdapter(bridge):结构化兼容 @pactor-app/runtime RouterAdapternavigate(to)bridge.push(to)
  • <DynamicDslRoute>(子入口 @pactor-app/router/react):useLocation 驱动重新解析——未命中渲染 fallback(404)、配置 permissionChecker(@pactor-app/permission checkPagePermission 守卫)且无权限渲染 forbidden(403),否则 render({ pageId, route })
  • useReactRouterBridge():把 useNavigate / useLocation 包装为 NavigationBridge(React Router 自身驱动重渲染,subscribe 为 no-op)。

文档

完整文档见 https://github.com/426-330/pactor/tree/main/docspnpm docs:dev 本地启动文档站)。

License

MIT