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

svelte-permit-core

v1.0.1

Published

Core RBAC implementation for Permit with Svelte

Readme

🛡️ Svelte Permit Core

Svelte component wrappers for enterprise-grade access control
Role-based permissions, group inheritance, and extensible validation powered by permit-core

License: MIT Svelte TypeScript

A robust Svelte integration for permit-core that provides:

  • Svelte-native components for guarding routes, components, menus, and dropdowns
  • Hierarchical permissions with role/group inheritance
  • Type-safe API with full TypeScript support
  • Reactive contexts via Svelte stores

Live Demo

Try the full feature demo: svelte-permit-core.pages.dev

Core Engine

This library wraps the core authorization engine: permit-core

Features ✨

  • Role & Group Management

    • Define roles and groups (with inheritance) using permit-core
    • Provide active account via a Svelte store
  • Permission Types

    • 🚦 Route access control
    • 🧩 Component-level permission granularity (view/edit)
    • 📋 Menu visibility management
    • 🔽 Dropdown options visibility
  • Developer Experience

    • Works with Svelte 5 snippets and runes
    • Clear contexts for access control
    • TypeScript-friendly

Installation 💻

npm install svelte-permit-core

Requirements:

  • Node >= 18.20.4
  • Svelte 5

Quick Start 🚀

1) Import modules

<script lang="ts">
	import AccessControlProvider from 'svelte-permit-core';
	import { ComponentAccessControl, DropdownAccessControl, MenuAccessControl, RouteAccessControl } from 'svelte-permit-core';

	import { createRole, createGroup, createRoutePermission, createComponentPermission, createMenuPermission, createDropdownPermission } from 'permit-core';
	import { readable } from 'svelte/store';
</script>

2) Create roles and groups

const admin = createRole('admin');
const editor = createRole('editor');
const viewer = createRole('viewer');

const adminGroup = createGroup('admin-group');
const contentGroup = createGroup('content-group', adminGroup); // inherits from adminGroup

const roles = [admin, editor, viewer];
const groups = [adminGroup, contentGroup];

3) Define permissions

// Group-level permissions (inheritance)
const groupPermissions = {
  [adminGroup.getCode()]: {
    navigation: createRoutePermission(adminGroup, [{ route: /.*/ }]),
    component:  createComponentPermission(adminGroup, [{ identifier: /.*/, actions: ['view', 'edit'] }]),
    dropdown:   createDropdownPermission(adminGroup, [{ identifier: /.*/, list: /.*/ }]),
    menu:       createMenuPermission(adminGroup, [{ identifier: 'main-menu', list: /.*/ }]),
  },
  [contentGroup.getCode()]: {
    navigation: createRoutePermission(contentGroup, [{ route: '/admin', exclude: true }]),
    component:  createComponentPermission(contentGroup, [
      { identifier: 'admin-panel', actions: ['edit'], exclude: true },
      { identifier: 'content-panel', actions: ['view', 'edit'] }
    ]),
    dropdown:   createDropdownPermission(contentGroup, [
      { identifier: 'actions-dropdown', list: ['delete-user', 'change-role', 'reset-password'], exclude: true }
    ]),
    menu:       createMenuPermission(contentGroup, [
      { identifier: 'main-menu', list: ['analytics', 'admin'], exclude: true }
    ]),
  }
};

// Role-level permissions
const rolePermissions = {
  [admin.getCode()]: {
    navigation: createRoutePermission(admin, [{ route: /.*/ }]),
    component:  createComponentPermission(admin, [{ identifier: /.*/, actions: ['view', 'edit'] }]),
    dropdown:   createDropdownPermission(admin, [{ identifier: /.*/, list: /.*/ }]),
    menu:       createMenuPermission(admin, [{ identifier: 'main-menu', list: /.*/ }]),
  },
  [editor.getCode()]: {
    navigation: createRoutePermission(editor, [{ route: '/content' }]),
    component:  createComponentPermission(editor, [
      { identifier: 'admin-panel', actions: ['view'] },
      { identifier: 'content-panel', actions: ['view', 'edit'] }
    ]),
    dropdown:   createDropdownPermission(editor, [
      { identifier: 'actions-dropdown', list: ['edit-user', 'reset-password'] }
    ]),
    menu:       createMenuPermission(editor, [
      { identifier: 'main-menu', list: ['dashboard', 'content', 'settings'] }
    ]),
  },
  [viewer.getCode()]: {
    navigation: createRoutePermission(viewer, []),
    component:  createComponentPermission(viewer, [{ identifier: 'content-panel', actions: ['view'] }]),
    menu:       createMenuPermission(viewer, [{ identifier: 'main-menu', list: ['dashboard'] }]),
  }
};

4) Provide the active account

type Account = { role: string; groupFlag?: string } | null;

// Example: replace with your auth/user store
const account = readable<Account>({ role: 'admin', groupFlag: 'content-group' });

5) Wrap your app with the provider

<AccessControlProvider {roles} {groups} account={account}>
	<!-- your app -->
</AccessControlProvider>

6) Guard UI with access control components

  • Route guard:
<RouteAccessControl route="/admin">
  {#snippet children({ role, route })}
    <p>Access granted to {route}</p>
  {/snippet}
  {#snippet fallback({ role, route })}
    <p>Access denied to {route}</p>
  {/snippet}
</RouteAccessControl>
  • Component guard:
<ComponentAccessControl identifier="content-panel">
  {#snippet children({ isEditable, role })}
    <button disabled={!isEditable}>Edit content</button>
  {/snippet}
  {#snippet fallback({ role })}
    <p>You do not have access to this component.</p>
  {/snippet}
</ComponentAccessControl>
  • Menu guard:
<script lang="ts">
  const menuItems = ['dashboard', 'content', 'analytics', 'admin', 'settings'] as const;
</script>

<ul>
  <MenuAccessControl identifier="main-menu" menuList={menuItems}>
    {#snippet children({ isEditable, menu })}
      <li class={!isEditable ? 'hidden' : ''}>{menu}</li>
    {/snippet}
  </MenuAccessControl>
</ul>
  • Dropdown guard:
<script lang="ts">
  const actions = ['edit-user', 'delete-user', 'reset-password', 'change-role'] as const;
</script>

<ul>
  <DropdownAccessControl identifier="actions-dropdown" list={actions}>
    {#snippet children({ isEditable, item })}
      <li>
        <span class={isEditable ? 'text-green-600' : 'text-red-600'}>
          {item}
        </span>
      </li>
    {/snippet}
  </DropdownAccessControl>
</ul>

Documentation 📚

Core Concepts

| Concept | Description | | -------------- | ------------------------------------------------ | | Role | Defines user permissions and privileges | | Group | Organizes roles; supports hierarchical inheritance | | Permission | Rule set for a specific resource type | | Action | Operation to be validated (route, component, etc.) | | Validator | Applies permission rules to the action |

Components

| Component | Purpose | | ----------------------------- | ------------------------------------------------- | | AccessControlProvider | Initializes access control and exposes contexts | | RouteAccessControl | Conditionally renders based on route access | | ComponentAccessControl | Guards a UI fragment (view/edit) | | MenuAccessControl | Filters a menu list for the active role/group | | DropdownAccessControl | Filters a dropdown list for the active role/group |

AccessControlProvider

  • Props:

    • roles: Role[] — registered roles
    • groups: Group[] — registered groups (with optional inheritance)
    • account: Readable<{ role: string; groupFlag?: string } | null> — current account state
    • children: Snippet — subtree to render with provided contexts
  • Contexts exposed to descendants:

    • AccessControl: initialized access control instance
    • CurrentAccessRole: Writable<Role | null>
    • CurrentAccessRoleGroup: Writable<Group | null>

Route Permissions

<RouteAccessControl route="/admin">
  {#snippet children({ role, route })}
    <p>Welcome to {route}</p>
  {/snippet}
  {#snippet fallback()}
    <p>Not authorized</p>
  {/snippet}
</RouteAccessControl>

Component Permissions

<ComponentAccessControl identifier="admin-panel">
  {#snippet children({ isEditable })}
    <button disabled={!isEditable}>Edit</button>
  {/snippet}
</ComponentAccessControl>

Menu Permissions

<MenuAccessControl identifier="main-menu" menuList={['dashboard', 'settings']}>
  {#snippet children({ isEditable, menu })}
    <li class:hidden={!isEditable}>{menu}</li>
  {/snippet}
</MenuAccessControl>

Dropdown Permissions

<DropdownAccessControl identifier="actions-dropdown" list={['edit-user', 'delete-user']}>
  {#snippet children({ isEditable, item })}
    <button disabled={!isEditable}>{item}</button>
  {/snippet}
</DropdownAccessControl>

How Roles and Groups Work

  • Roles hold permissions for route, component, menu, and dropdown checks.
  • Groups can be assigned to roles and may inherit from other groups, enabling hierarchical policies.
  • If a group includes a permission, roles assigned to that group inherit it without duplicating the rule at the role level.

Contributing 🤝

  1. Fork the repository
  2. Create your feature branch: git checkout -b feat/your-feature
  3. Commit your changes: git commit -m "feat(scope): add something"
  4. Push to the branch: git push origin feat/your-feature
  5. Open a pull request

Commit Message Guidelines

<type>(<scope>): <subject>

<body>

<footer>

Example:

feat(permissions): add dropdown guard

- Implement DropdownAccessControl
- Add examples to README
- Wire to AccessControlProvider

Resolves: #123

License 📄

This project is licensed under the MIT License - see the LICENSE file for details.

Changelog 📜

v1.0.0

  • Initial Svelte integration for permit-core
  • AccessControlProvider, RouteAccessControl, ComponentAccessControl, MenuAccessControl, DropdownAccessControl
  • Svelte 5 snippets and TypeScript support