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 🙏

© 2025 – Pkg Stats / Ryan Hefner

sunny-acl

v0.0.3

Published

![npm version](https://img.shields.io/npm/v/sunny-acl) ![npm downloads](https://img.shields.io/npm/dm/sunny-acl) ![license](https://img.shields.io/npm/l/sunny-acl)

Downloads

4

Readme

sunny-acl

npm version npm downloads license

基于 acljs 进行再封装,在原有功能基础上,提供根据 路由path 收集 resources 能力。

Installation

使用npm安装

npm i sunny-acl

使用yarn安装

yarn add sunny-acl

使用pnpm安装

pnpm add sunny-acl

Usages

集成用例

为react router的Router组件定一个共享history实例,后面方便和认证路由进行协同工作。 hashHistory.ts 文件内容为

import { createHashHistory } from 'history'
export default createHashHistory()

实现认证与授权逻辑。 integrate.ts 文件内容为

import { implement as AuthImplement } from 'sunny-auth'
import { Action, implement as ACLImplement, isAllowed } from 'sunny-acl'
import hashHistory from './hashHistory'

ACLImplement({
  ajaxPermissions: () =>
    Promise.resolve({
      roles: [
        { name: 'guest' },
        { name: 'member', parent: 'guest' },
        { name: 'admin' },
      ],
      resources: [{ name: 'home' }],
      rules: [
        {
          access: 'allow',
          role: 'admin',
          privileges: null,
          resources: null,
        },
        {
          access: 'allow',
          role: 'member',
          privileges: null,
          resources: ['home'],
        },
      ],
    }),
  getRole: () => sessionStorage.getItem('role'),
  getPaths: () => ['/dashboard'] // 如果有条件,可以将所有页面路由path集合在一起生成 resources
})

AuthImplement({
  authenticate: () => {
    const isLogin = () => {
      return sessionStorage.getItem('token')
        ? Promise.resolve()
        : Promise.reject()
    }
    return isLogin()
  },
  requireLogin: () => {
    hashHistory.push('/login')
  },
  authorize: isAllowed,
  deny: () => {
    console.debug('You are not allowed to go', history.location.pathname)
    alert('拒绝访问')
    hashHistory.goBack()
  },
})

使用路由组件拦截访问

import React, { FC } from 'react'
import { Router, Route, Switch } from 'react-router'
import { AuthRoute } from 'sunny-auth'
import { Action } from 'sunny-acl'
import hashHistory from './hashHistory'
import './integrate.ts' // 载入配置逻辑,使认证逻辑正常工作

declare module 'react-router' {
  interface RouteProps extends Action {}
}

const App: FC = () => (
  <Router history={hashHistory}>
    <Switch>
      <AuthRoute path={'/'} exact resource="home">Home Page</AuthRoute>
      <AuthRoute path={'/dashboard'}>Dashboard Page</AuthRoute>
      <Route path={'/login'}>
        Login Page
        <button onClick={() => {
          sessionStorage.setItem('token', 'xxx')
          // 随机设定一个角色
          sessionStorage.setItem('role', ['member', 'admin'].sort(() => .5 - Math.random()).pop())
          hashHistory.goBack()
        }}>登录</button>
      </Route>
    </Switch>
  </Router>
)

更多集成用例

将权限规则与组件、代码块进行关联

假设权限配置如下所示

import { Permissions } from 'sunny-acl'
const permissions: Permissions = {
  roles: [
    // ...
    { name: 'manager' },
    // ...
  ],
  resources: [
    // ...
    { name: 'product' }
    // ...
  ],
  rules: [
    // ...
    {
      access: 'allow',
      role: 'manager',
      privileges: ['add', 'delete'],
      resources: ['product'],
    },
    // ...
  ],
}

与组件绑定

import React, { FC } from 'react'
import { Privilege } from 'sunny-acl'

const Components: FC = () => <>
  <Privilege path="product/add"><button>添加</button></Privilege>
  <Privilege resource="product" privilege="delete"><button>删除</button></Privilege>
</>

与逻辑块关联

import React, { useEffect, FC } from 'react'
import { isAllowedSync } from 'sunny-acl'

const Components: FC = () => {
  useEffect(() => {
    if (isAllowedSync({ path: 'product/add' })) {
      // do something else
    }
  }, [])
  return <></>
}

How it works

资源和权限是集中声明,还是分散写在路由配置中?

集中和分散方式之间的比较

  • 资源和权限是集中声明
    • 由path解析器决定当前路由的resource、privilege信息
      • 无法提取信息时可以由路由配置作为补充
    • 需要预先定义ACL权限列表
      • 既然会由后端存储,那么分散写到路由配置中就不是个好的选择
  • 分散写在路由配置中
    • 由路由嵌套关系决定resource继承关系
    • 由路由决定当前是resource还是privilege
    • 需要遍历树形结构路由信息表来生成resource继承关系

最终决定

  • 考虑未来权限信息由后端存储,可以考虑先集中声明
  • path解析器作为确认resource、privilege主要方式,路由配置中携带这两个字段作为覆盖/补充
    • route path可以确定resource继承关系,确定privilege
      • 如果选择自动生成,无论是否为继承关系,resource关键词都不可以重复出现
  • 如果想要生成resources所有资源信息,可以遍历所有路由配置,结合path解析器后生成

Browser Compatibility

浏览器兼容性

Changelog

See CHANGELOG.md