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

@hex-di/guard-react

v0.1.1

Published

React integration for @hex-di/guard — SubjectProvider, Can/Cannot components, and authorization hooks

Readme

@hex-di/guard-react

React integration for @hex-di/guard -- a SubjectProvider, declarative Can/Cannot components, and a full set of authorization hooks with Suspense support.

Features

  • SubjectProvider -- provides the authenticated subject to the component tree via React context
  • Can / Cannot -- declarative components that render children based on policy evaluation
  • Suspense-aware hooks -- useSubject, useCan, usePolicy, usePolicies suspend while the subject loads
  • Deferred hooks -- non-suspending variants (useSubjectDeferred, useCanDeferred, usePolicyDeferred, usePoliciesDeferred) return loading state
  • Isolated contexts -- createGuardHooks() factory for multi-tenant or multi-scope scenarios with independent contexts

Installation

pnpm add @hex-di/guard-react

Dependencies: @hex-di/guard

Peer dependency: react >= 18

Quick Start

import { SubjectProvider, Can, useCan } from "@hex-di/guard-react";
import { hasPermission, createPermission } from "@hex-di/guard";

const WriteDocuments = createPermission("WriteDocuments");

function App({ currentUser }) {
  return (
    <SubjectProvider subject={currentUser}>
      <Suspense fallback={<Loading />}>
        <Dashboard />
      </Suspense>
    </SubjectProvider>
  );
}

function Dashboard() {
  return (
    <Can policy={hasPermission(WriteDocuments)} fallback={<ReadOnlyBanner />}>
      <EditButton />
    </Can>
  );
}

SubjectProvider

Provides the current authenticated subject to all descendant components. The subject is frozen on mount to prevent TOCTOU mutations.

Pass "loading" while the subject is being resolved asynchronously -- child hooks will suspend (or report loading state for deferred variants).

import { SubjectProvider } from "@hex-di/guard-react";

function App({ user, isLoading }) {
  return (
    <SubjectProvider subject={isLoading ? "loading" : user}>
      <Suspense fallback={<Spinner />}>
        <ProtectedContent />
      </Suspense>
    </SubjectProvider>
  );
}

Components

Can

Renders children when the subject satisfies the given policy. Suspends while the subject is loading (works with React.Suspense). Renders fallback (or nothing) when access is denied.

import { Can } from "@hex-di/guard-react";
import { hasPermission } from "@hex-di/guard";

<Can policy={hasPermission(WriteDocuments)} fallback={<AccessDenied />}>
  <EditForm />
</Can>;

Cannot

Renders children when the subject does NOT satisfy the given policy. Useful for showing fallback UI for unauthorized users.

import { Cannot } from "@hex-di/guard-react";
import { hasPermission } from "@hex-di/guard";

<Cannot policy={hasPermission(AdminAccess)}>
  <ReadOnlyBanner />
</Cannot>;

Hooks

Every hook throws MissingSubjectProviderError if used outside a SubjectProvider.

Suspending hooks

These hooks suspend the component while the subject is loading. Wrap them in a <Suspense> boundary.

import { useSubject, useCan, usePolicy, usePolicies } from "@hex-di/guard-react";

// Get the current subject (suspends while loading)
const subject = useSubject();

// Check a single policy (returns boolean)
const canEdit = useCan(hasPermission(WriteDocuments));

// Get the full Decision object
const decision = usePolicy(hasPermission(WriteDocuments));
// decision.kind === "allow" | "deny"

// Evaluate multiple named policies at once
const decisions = usePolicies({
  canRead: hasPermission(ReadDocuments),
  canWrite: hasPermission(WriteDocuments),
});
// decisions.canRead.kind === "allow"

Deferred hooks

These hooks never suspend. They return loading state instead, making them suitable for non-Suspense architectures.

import {
  useSubjectDeferred,
  useCanDeferred,
  usePolicyDeferred,
  usePoliciesDeferred,
} from "@hex-di/guard-react";

// Returns the subject or null while loading
const subject = useSubjectDeferred();

// Returns { allowed: boolean, loading: boolean }
const { allowed, loading } = useCanDeferred(hasPermission(WriteDocuments));

// Returns { decision: Decision | undefined, loading: boolean }
const { decision, loading } = usePolicyDeferred(hasPermission(WriteDocuments));

// Returns Record<string, PolicyResult>
const results = usePoliciesDeferred({
  canRead: hasPermission(ReadDocuments),
  canWrite: hasPermission(WriteDocuments),
});

Isolated Contexts

For multi-tenant or multi-scope applications, createGuardHooks() creates an independent React context with its own provider and hook set, preventing cross-context subject leakage.

import { createGuardHooks } from "@hex-di/guard-react";

const TenantA = createGuardHooks();
const TenantB = createGuardHooks();

function App() {
  return (
    <>
      <TenantA.SubjectProvider subject={tenantAUser}>
        <TenantADashboard />
      </TenantA.SubjectProvider>
      <TenantB.SubjectProvider subject={tenantBUser}>
        <TenantBDashboard />
      </TenantB.SubjectProvider>
    </>
  );
}

function TenantADashboard() {
  const canEdit = TenantA.useCan(hasPermission(WriteDocs));
  // ...
}

API Reference

Provider

| Export | Kind | Description | | ----------------- | --------- | ------------------------------------------ | | SubjectProvider | component | Provides the subject to the component tree | | SubjectContext | context | Raw React context (advanced usage) |

Components

| Export | Kind | Description | | -------- | --------- | --------------------------------------- | | Can | component | Renders children when policy is allowed | | Cannot | component | Renders children when policy is denied |

Suspending Hooks

| Export | Kind | Description | | ----------------------- | ---- | ---------------------------------------------------------------------- | | useSubject() | hook | Returns the current subject; suspends while loading | | useCan(policy) | hook | Returns true if subject satisfies the policy; suspends while loading | | usePolicy(policy) | hook | Returns the Decision object; suspends while loading | | usePolicies(policies) | hook | Evaluates multiple named policies; suspends while loading |

Deferred Hooks

| Export | Kind | Description | | ------------------------------- | ---- | ---------------------------------------------------------------- | | useSubjectDeferred() | hook | Returns subject or null while loading; never suspends | | useCanDeferred(policy) | hook | Returns CanResult ({ allowed, loading }); never suspends | | usePolicyDeferred(policy) | hook | Returns PolicyResult ({ decision, loading }); never suspends | | usePoliciesDeferred(policies) | hook | Returns Record<string, PolicyResult>; never suspends |

Factory

| Export | Kind | Description | | -------------------- | -------- | ----------------------------------------------------------- | | createGuardHooks() | function | Creates an isolated context with its own provider and hooks |

Types

| Export | Kind | Description | | ---------------------- | ---- | ------------------------------------------------------- | | SubjectState | type | TSubject \| "loading" | | CanResult | type | { allowed: boolean; loading: boolean } | | PolicyResult | type | { decision: Decision \| undefined; loading: boolean } | | GuardHooks | type | Return type of createGuardHooks() | | SubjectProviderProps | type | Props for SubjectProvider | | CanProps | type | Props for Can | | CannotProps | type | Props for Cannot |

Errors

| Export | Kind | Description | | ----------------------------- | ----- | ---------------------------------------------------- | | MissingSubjectProviderError | class | Thrown when a hook is used outside SubjectProvider |

Related Packages

| Package | Description | | -------------------------- | ------------------------------------------------------------- | | @hex-di/guard | Core guard library: permissions, roles, policies, evaluation | | @hex-di/guard-testing | Test utilities: memory adapters, fixtures, conformance suites | | @hex-di/guard-validation | GxP validation protocols (IQ/OQ/PQ) and traceability matrix |

License

MIT