← All @molecule/* packages · App templates

@molecule/api-permissions-custom

Provider bond · permissions · API (Node) · v1.0.1 · Apache-2.0

Simple in-memory role-based permissions provider for molecule.dev

npm install @molecule/api-permissions-custom

npm · Source on GitHub · Implements @molecule/api-permissions

How it works

@molecule/api-permissions-custom is a provider bond on the API (Node) side: it implements the permissions core interface (@molecule/api-permissions) with a concrete vendor or library behind it.

Your code calls the core; you wire this provider once at startup. Swapping vendors later is one line in that wiring, not a rewrite.

import { setProvider } from '@molecule/api-permissions'
import { provider } from '@molecule/api-permissions-custom'

setProvider(provider)

// Or create a custom instance
import { createProvider } from '@molecule/api-permissions-custom'

const perms = createProvider({ wildcards: true })
setProvider(perms)

Works with: @molecule/api-permissions

Reference

Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit src/index.ts JSDoc, not this file.

Simple in-memory role-based permissions provider for molecule.dev.

Provides role-based and attribute-based access control (RBAC/ABAC) using pure in-memory storage with no external dependencies. Supports wildcard matching on actions/resources and basic ABAC condition evaluation. Ideal for development, testing, or single-instance deployments.

Quick Start

import { setProvider } from '@molecule/api-permissions'
import { provider } from '@molecule/api-permissions-custom'

setProvider(provider)

// Or create a custom instance
import { createProvider } from '@molecule/api-permissions-custom'

const perms = createProvider({ wildcards: true })
setProvider(perms)

Type

provider

Installation

npm install @molecule/api-permissions-custom @molecule/api-permissions

API

Interfaces

CreateRole

Input for creating a new role.

interface CreateRole {
  /** Human-readable name of the role. */
  name: string
  /** Optional description of the role's purpose. */
  description?: string
  /** Permissions to assign to the role. */
  permissions: Permission[]
}

CustomPermissionsOptions

Configuration options for the custom permissions provider.

interface CustomPermissionsOptions {
  /**
   * Whether wildcard (`*`) matching is enabled for actions and resources.
   * When enabled, a permission with action `*` or resource `*` matches any
   * action or resource respectively.
   *
   * @defaultValue true
   */
  wildcards?: boolean
}

Permission

A permission granting an action on a resource, optionally with conditions.

interface Permission {
  /** Unique identifier for this permission. */
  id: string
  /** The action this permission grants (e.g. `read`, `write`, `delete`). */
  action: string
  /** The resource this permission applies to (e.g. `project`, `user`, `*`). */
  resource: string
  /** Optional ABAC conditions that must be met for this permission to apply. */
  conditions?: Record<string, unknown>
}

PermissionsProvider

Permissions provider interface.

All permissions providers must implement this interface to provide authorization checking, role management, and permission assignment.

interface PermissionsProvider {
  /**
   * Checks whether a subject is allowed to perform an action on a resource.
   *
   * @param subject - The entity requesting access (e.g. user ID).
   * @param action - The action being requested (e.g. `read`, `write`).
   * @param resource - The resource being accessed (e.g. `project`).
   * @param context - Optional ABAC context attributes for condition evaluation.
   * @returns `true` if the subject is authorized.
   */
  can(
    subject: string,
    action: string,
    resource: string,
    context?: Record<string, unknown>,
  ): Promise<boolean>
  /**
   * Assigns a role to a subject, optionally within a scope.
   *
   * @param subject - The entity to assign the role to.
   * @param role - The role name to assign.
   * @param scope - Optional scope for the assignment (e.g. `org:123`).
   */
  assign(subject: string, role: string, scope?: string): Promise<void>
  /**
   * Revokes a role from a subject, optionally within a scope.
   *
   * @param subject - The entity to revoke the role from.
   * @param role - The role name to revoke.
   * @param scope - Optional scope for the revocation.
   */
  revoke(subject: string, role: string, scope?: string): Promise<void>
  /**
   * Retrieves all roles assigned to a subject.
   *
   * @param subject - The entity to look up roles for.
   * @returns The roles assigned to the subject.
   */
  getRoles(subject: string): Promise<Role[]>
  /**
   * Creates a new role definition.
   *
   * @param role - The role definition to create.
   * @returns The created role with an assigned `id`.
   */
  createRole(role: CreateRole): Promise<Role>
  /**
   * Deletes a role definition by ID.
   *
   * @param roleId - The ID of the role to delete.
   */
  deleteRole(roleId: string): Promise<void>
  /**
   * Retrieves all permissions granted by a role.
   *
   * @param role - The role name to look up permissions for.
   * @returns The permissions granted by the role.
   */
  getPermissions(role: string): Promise<Permission[]>
  /**
   * Adds a permission to an existing role.
   *
   * @param role - The role name to add the permission to.
   * @param permission - The permission to add.
   */
  addPermission(role: string, permission: Permission): Promise<void>
  /**
   * Removes a permission from a role.
   *
   * @param role - The role name to remove the permission from.
   * @param permissionId - The ID of the permission to remove.
   */
  removePermission(role: string, permissionId: string): Promise<void>
}

Role

A role grouping one or more permissions, optionally scoped.

interface Role {
  /** Unique identifier for this role. */
  id: string
  /** Human-readable name of the role (e.g. `admin`, `editor`). */
  name: string
  /** Optional description of the role's purpose. */
  description?: string
  /** Permissions granted by this role. */
  permissions: Permission[]
  /** Optional scope restricting where this role applies (e.g. `org:123`). */
  scope?: string
}

Functions

createProvider(options)

Creates a custom in-memory permissions provider implementing the PermissionsProvider interface. All state is stored in memory — no external services or libraries are required.

function createProvider(options?: CustomPermissionsOptions): PermissionsProvider
  • options — Optional provider configuration.

Returns: A PermissionsProvider backed by in-memory storage.

Constants

provider

Default custom permissions provider instance. Lazily initialises on first property access with default options.

const provider: PermissionsProvider

Core Interface

Implements @molecule/api-permissions interface.

Bond Wiring

Setup function to register this provider with the core interface:

import { setProvider } from '@molecule/api-permissions'
import { provider } from '@molecule/api-permissions-custom'

export function setupPermissionsCustom(): void {
  setProvider(provider)
}

Injection Notes

Requirements

Peer dependencies:

  • @molecule/api-permissions ^1.0.1

Runtime Dependencies

  • @molecule/api-permissions

E2E Tests

Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual screens/flows, and check every box off one by one. A box you can't check is an integration bug to fix — not a skip:

  • A user whose role HAS a permission can perform the gated action through the UI; a user whose role lacks it cannot.
  • Denial is enforced SERVER-SIDE: attempting the gated action anyway (or reloading after the attempt) shows nothing changed — hiding the button alone is not enforcement.
  • Role-gated screens/navigation are unreachable for unauthorized roles (redirect or clear denial — never a blank page or leaked data).
  • Assigning a role through the app's admin surface grants the new abilities, and revoking it removes them.
  • The same checks hold against OWNED resources: a permitted role still cannot act on another user's private records unless the app intends it.