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

@akku-work/consent-sdk-react

v0.1.0-beta.1

Published

Akku Consent - React bindings and consent surfaces for an authenticated host application.

Readme

@akku-work/consent-sdk-react

React bindings and consent surfaces for an authenticated host application.

This package renders. @akku-work/consent-sdk-auth decides — it resolves each published purpose to a legal basis, a validity window and an outcome, and this package draws that. Nothing here evaluates expiry, derives a basis, or decides whether a purpose needs asking; if you find yourself adding logic of that kind here, it belongs on the other side.

Install

npm install @akku-work/consent-sdk-react @akku-work/consent-sdk-auth

@akku-work/consent-sdk-auth and react are peer dependencies. The auth SDK is a peer rather than a dependency on purpose: your app must end up with exactly one ConsentManager. Two copies each hold their own onChange listeners and their own view of the subject's decisions, so a write through one would never notify the other.

Wiring

import { ConsentManager } from "@akku-work/consent-sdk-auth";
import { ConsentProvider } from "@akku-work/consent-sdk-react";

const manager = new ConsentManager({
  apiHost: "https://consent.nova.example",
  siteKey: "sk_live_9f2c…",
  applicationId: "nova-bank-web",
  getSubjectToken: () => session.fetchConsentToken(),
});

<ConsentProvider manager={manager}>
  <App />
</ConsentProvider>;

No userId is ever passed. Identity travels only inside the host-signed subject token, and the backend derives the subject by verifying it — a userId handed over from the browser is a claim, not a credential.

Gating a feature

const { isGranted, loading } = useConsent();

if (isGranted("device.analytics")) trackDashboardView();

isGranted is false while loading and false for a key the policy does not declare. This is a gate, and a gate that opens because the answer has not arrived yet is not a gate. Read loading alongside it when you need to tell "no" from "not yet".

The four surfaces

Which one to use is a property of the moment, not of the purpose.

| Surface | Use for | | --- | --- | | AskModal | One purpose, at the moment it matters. Blocks, so a user action must provoke it. | | DisclosureModal | A collection point, fired when a form opens. Discloses, then captures. | | AskSnackbar | A low-stakes ask that must not interrupt. | | PreferenceSheet | The standing entry point. Every toggle is an immediate write. |

// Renders nothing at all when there is nothing to ask — already decided and still valid, a basis
// that is never prompted, or a key the policy does not declare. Mount it where the question belongs
// and let it decide whether to appear.
<AskModal purposeKey="email.marketing" source="profile" />

source is required and is stamped on the ledger event. It records where consent was captured, which is what makes a consent record auditable after the fact.

Rules these components will not let you break

These are not style choices. Each one is a way a consent UI can misrepresent what a person chose.

  • The legal basis decides the control. consent gets a toggle; necessary and legal_obligation render as "Always on" with no control at all. You cannot pass a prop to override this — offering a switch for something that cannot be switched off is the commonest way a consent UI lies.
  • Nothing is pre-ticked. DisclosureModal starts every choice unanswered and will not save until something is answered. A pre-ticked box is not consent, and an empty save would log a consent event for a decision nobody made.
  • A dismissal is never an answer. Escape, the backdrop and "Later" record nothing. Silence is not consent, and it is not a refusal either.
  • No auto-dismiss timer on the snackbar. A surface that fades into a decision turns inaction into one.
  • Decline is never de-emphasised. Accept and decline take the same button treatment; equal prominence is a contract requirement.
  • The preference sheet has no Save button. Every toggle writes immediately, because a preference centre with unsaved changes is one that loses them — and a withdrawal has to take effect when it is asked for.
  • A failed read never renders as "you have no choices." The error is shown and the last known state is kept. An unreachable API must not blank the screen or break the page around it.

Styling

Import the stylesheet. The package ships its own look:

import "@akku-work/consent-sdk-react/styles.css";

This is not optional, and the package deliberately does not leave it to you. An earlier version shipped class names and no CSS, on the reasoning that a host app has its own design system. That was wrong: decline must never be de-emphasised relative to accept, and a requirement enforced only by a comment in someone else's stylesheet is not enforced. Here both buttons take their height, size and weight from the same rule — only background differs — so there is no separate declaration to override.

Retheme with custom properties rather than by rewriting rules:

:root {
  --akku-iris-500: #0d9488;   /* accent */
  --akku-iris-600: #0f766e;   /* accent, hover */
  --akku-ink: #0f172a;
  --akku-font-sans: "Your Face", system-ui, sans-serif;
}

Every class also carries display with !important. That is not defensiveness for its own sake: a page-level * { display: none } reset would otherwise hide consent controls, and a surface a visitor cannot see is a consent request that never happened. The same defence exists in @akku-work/consent-sdk, where the bug was made twice.

The primitives (PurposeRow, LegalBasisPill, ConsentToggle, SurfaceHeader, SurfaceFooter, ReasonBanner, PurposeKeyMeta) are exported so you can compose a surface of your own without re-deriving the rules above and getting one wrong.

Known limit

Expiry does not currently fire on the authenticated plane. Its consent record carries one updatedAt for the whole record rather than a per-purpose timestamp, so a decision cannot be aged individually — and deriving it from the record-level timestamp would lapse a purpose answered yesterday because a different one was answered a year ago. validityDays is published, displayed and carried through; it simply does not yet cause a re-ask here. Tracked on AK-8494.

Licence

Proprietary. See LICENSE — publication on npm grants no licence to use this software.