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

@caisson-sh/access-review

v0.3.6

Published

Audit-prep access-review campaigns: a WORM-logged, per-reviewee attested approve/revoke decision record over an imported membership snapshot, opened on a jobs-riding cadence and closed on completion or deadline.

Readme

@caisson-sh/access-review

Audit-prep access-review campaigns — a reviewer attests, per user, that access is still appropriate, and every decision is WORM-logged so an auditor can prove the review actually happened. ADR-0371 (module lock).

Apache-2.0. Install it on its own, or alongside the rest of the compliance modules.

What it gives you

  • A WORM-logged decision record, not a plain log. Every approve/revoke decision appends to the tenant's existing @caisson-sh/audit-worm chain — no new anchoring primitive. A dropped or patched decision is tamper-evident: chain.verify catches it, the same guarantee every other WORM-logged module in this repo carries.
  • A typed MembershipSnapshotSource port. One shape ({ reviewerId, reviewees }) three trivial adapters implement: createCsvMembershipSnapshotSource, createJsonMembershipSnapshotSource, createInMemoryMembershipSnapshotSource. Same shape discipline @caisson-sh/compliance-core's EvidenceCollector uses — read() is pure, the loader's own I/O stays outside the typed boundary.
  • Flag-never-guess close. A campaign closes only when it is COMPLETE (every reviewee decided) or DUE (past its deadline) — never both, never neither. At close, every undecided reviewee lands in unresolved; it is never counted as approved.
  • A jobs-riding schedule. defineCampaignOpenTask / defineCampaignCloseTask are @caisson-sh/jobs TaskDefinitions — register them on a JobQueue (the shipped in-memory driver in dev/test; Trigger.dev in prod) and enqueue through enqueueCampaignOpen / enqueueCampaignClose, which set an overlap-safe singletonKey. Which reviewers are due for a fresh cycle, and which open campaigns are past their deadline, is the caller's own recurring scheduler's concern — this package only runs the operation once told who.

Use

import {
  createCsvMembershipSnapshotSource,
  openCampaign,
  recordDecision,
  closeCampaign,
} from "@caisson-sh/access-review";
import { AuditChainStore, LocalArtifactStore } from "@caisson-sh/audit-worm";

const chain = new AuditChainStore({
  db,
  store: new LocalArtifactStore(wormDir),
});
const deps = { db, chain };

const snapshot = createCsvMembershipSnapshotSource(
  csvText,
  "reviewer-9",
).read();
const campaign = await openCampaign(deps, {
  accountId,
  reviewerId: snapshot.reviewerId,
  reviewees: snapshot.reviewees,
  deadlineMs: 30 * 24 * 60 * 60 * 1000, // 30-day review window
});

await recordDecision(deps, {
  accountId,
  campaignId: campaign.id,
  revieweeId: snapshot.reviewees[0],
  decision: "approve",
});

// Closes once every reviewee has decided, or once the deadline passes — whichever comes first.
const closed = await closeCampaign(deps, {
  accountId,
  campaignId: campaign.id,
});
closed.unresolved; // reviewees with no recorded decision — never treated as approved

Scheduling

import { createInMemoryQueue } from "@caisson-sh/jobs";
import {
  defineCampaignOpenTask,
  defineCampaignCloseTask,
  enqueueCampaignOpen,
  enqueueCampaignClose,
} from "@caisson-sh/access-review";

const queue = createInMemoryQueue([
  defineCampaignOpenTask(deps),
  defineCampaignCloseTask(deps),
]);

// A recurring cadence (cron / your own scheduler) enqueues one open per reviewer due for a cycle:
await enqueueCampaignOpen(queue, {
  accountId,
  reviewerId,
  reviewees,
  deadlineMs: 30 * 24 * 60 * 60 * 1000,
});

// A deadline sweep enqueues a close attempt for every open campaign it finds past its window;
// `closeCampaign` refuses a premature close, so an eager or redundant poll is harmless.
await enqueueCampaignClose(queue, { accountId, campaignId });

Migration

src/migrations/0001_access_review_campaign.sql — the roster table. closed_at is the only app-updatable column after insert (the reviewer, roster, and deadline are immutable once opened); the decision trail itself lives entirely on the audit chain, never in this table.

Roadmap (v2, named — not built here)

A GitHub org/team connector implementing the SAME MembershipSnapshotSource port, pulling a live roster instead of an imported CSV/JSON file. No live IdP/SaaS connector ships in this package.

Out of scope

No reviewer-facing UI/portal — this is a data model plus a scheduling task; rendering a review queue or an attestation screen is a consuming app's job. No live IdP/SaaS connectors. No HR/ personnel data beyond the decision record itself.