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

@zanzojs/angular

v0.1.3

Published

Angular 19 Signals-first adapter for Zanzo ReBAC.

Readme

@zanzojs/angular

npm version Angular Compatible

Angular bindings for ZanzoJS. O(1) permission checks on the frontend powered entirely by Angular Signals, with zero network requests after hydration.

How it works

The server compiles a flat permission map (snapshot) once per user. The frontend receives it (via SSR integration or XHR), hydrates the ZanzoService, and evaluates every permission check as a highly-optimized, reactive Signal.

🚀 Edge & SSR Ready

The Angular adapter is fully compatible with Angular SSR running on the Edge (e.g., Cloudflare Workers). Use TransferState as documented below to seamlessly hydrate permissions from server to client without extra network roundtrips.

Installation

pnpm add @zanzojs/core@latest @zanzojs/angular@latest

Note: This adapter requires Angular 19+ due to its heavy reliance on the modern Signals API and standalone components.

Step-by-Step Guide

1. Configure the Provider

Provide the Zanzo core configuration at the root of your application (app.config.ts), supplying your typed schema. If utilizing SSR, configure an optional snapshotKey to automatically hydrate state from the server.

import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideZanzo } from '@zanzojs/angular';
import { schema } from './zanzo.config';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideZanzo({
      schema, // Required: Type-safe schema definition
      unauthorizedRoute: '/unauthorized', // Default fallback for Guards
      snapshotKey: 'ZANZO_SNAPSHOT' // Optional: TransferState key for SSR hydration
    })
  ]
};

2. Hydrate the Service

If you aren't using SSR automatic hydration, inject ZanzoService to hydrate the snapshot manually once the user authenticates.

import { Component, inject } from '@angular/core';
import { ZanzoService } from '@zanzojs/angular';
import type { schema } from '../zanzo.config';

@Component({
  selector: 'app-login',
  standalone: true,
  template: `<button (click)="login()">Login</button>`
})
export class LoginComponent {
  // Pass your schema type for strict auto-completion
  private zanzo = inject<ZanzoService<typeof schema>>(ZanzoService);

  async login() {
    const snapshot = await fetchUserPermissions(); 
    // Hydrate the service. All Signals will instantly react across the app.
    this.zanzo.hydrate(snapshot);
  }

  logout() {
    this.zanzo.clear(); // Revokes everything instantly
  }
}

3. Check Permissions in Templates

Zanzo provides multiple utilities to check permissions seamlessly in Angular templates.

Using the *zanzoIf Directive

A structural directive that conditionally renders elements based on permissions. Supports else blocks just like *ngIf.

<div *zanzoIf="{ action: 'edit', resource: 'Document:123' }; else noEdit">
  <button>Edit Document</button>
</div>

<ng-template #noEdit>
  <p>You do not have permission to edit this.</p>
</ng-template>

Using the canUse Pipe

A pure pipe that resolves to a reactive Angular Signal returning a boolean.

<!-- Disables the button if the user is not an admin on Document:123 -->
<!-- Note: The pipe returns a Signal, so you must invoke it with () in the template -->
<button [disabled]="!('admin' | canUse:'Document:123')()">
  Delete Document
</button>

To use these in your Standalone Components, add them to your imports array:

import { Component } from '@angular/core';
import { ZanzoIfDirective, CanUsePipe } from '@zanzojs/angular';

@Component({
  standalone: true,
  imports: [ZanzoIfDirective, CanUsePipe],
  templateUrl: './my.component.html'
})
export class MyComponent {}

4. Direct Signal Usage

For programmatic logic, ZanzoService.can() returns an Angular Signal<boolean> allowing you to reactively trigger effects or compute states.

import { Component, inject, effect } from '@angular/core';
import { ZanzoService } from '@zanzojs/angular';
import type { schema } from '../zanzo.config';

@Component({ /* ... */ })
export class DocumentActions {
  private zanzo = inject<ZanzoService<typeof schema>>(ZanzoService);
  
  // O(1) reactive lookup
  canDelete = this.zanzo.can('delete', 'Document:123');

  constructor() {
    effect(() => {
      if (this.canDelete()) {
        console.log("User currently has delete permissions.");
      }
    });
  }
}

5. Protect Routes with zanzoGuard

Zanzo ships with a functional Router Guard to protect your Angular routes. It evaluates permissions synchronously.

import { Routes } from '@angular/router';
import { zanzoGuard } from '@zanzojs/angular';

export const routes: Routes = [
  {
    path: 'admin/billing',
    component: BillingComponent,
    canActivate: [zanzoGuard('admin', 'Organization:acme')], // Route protection
    // To specify a custom redirect route for this specific guard:
    // canActivate: [zanzoGuard('admin', 'Organization:acme', '/upgrade-plan')]
  }
];

Best Practices & Security

Client-side Security Warning

[!WARNING] UX Only: Client-side permission checks are purely for UI/UX purposes (e.g., hiding a button). Since snapshots are evaluated strictly in the browser memory, they can be manipulated by a malicious user. Always perform a secondary authorization check on the backend before executing any sensitive mutation or delivering protected data.

Documentation

For backend setup and database adapters, see the ZanzoJS Monorepo.