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

@savannahanddelta/sentinel

v0.1.1

Published

Sentinel presence SDK — privacy-first, provider-agnostic face presence for the web

Readme

@savannahanddelta/sentinel

Privacy-first presence guard. Your camera never leaves your device.

Sentinel watches whether the right person is in front of the screen. When they leave, it blurs or locks your content. When they return, it unblurs. All face processing runs locally in WASM — no video, no images, no biometric data is ever transmitted.


Install

npm install @savannahanddelta/sentinel

You also need the MediaPipe provider:

npm install @savannahanddelta/sentinel-provider-mediapipe

Quick start

import { Sentinel } from '@savannahanddelta/sentinel'
import { MediaPipeProvider } from '@savannahanddelta/sentinel-provider-mediapipe'

const sentinel = new Sentinel({
  provider: new MediaPipeProvider(),
  guards: [
    {
      selector: '#document-viewer',  // CSS selector of the element to protect
      action: 'blur',                // 'blur' | 'lock' | 'frost'
      threshold_ms: 3000,            // how long absent before triggering
      recovery: 'auto',              // 'auto' | 'face' | 'pin'
    }
  ]
})

sentinel.on('absent', ({ duration_ms }) => {
  console.log(`User has been away for ${duration_ms}ms`)
})

sentinel.on('present', () => {
  console.log('User returned')
})

sentinel.on('spoof', () => {
  console.log('Static image detected — locking')
})

await sentinel.start()

That's it. Sentinel will:

  • Ask for camera permission on start()
  • Detect presence continuously at 2–8 fps (adaptive)
  • Blur #document-viewer after 3 seconds of absence
  • Unblur automatically when the user returns
  • Fire spoof if a printed photo or static image is detected

Guard actions

| Action | Behaviour | Best for | |--------|-----------|----------| | blur | CSS backdrop blur over the element | Stepped away briefly | | frost | Heavy blur + dark tint | Sensitive content | | lock | Solid black overlay, manual recovery | High-security documents |

Recovery modes

| Recovery | Behaviour | |----------|-----------| | auto | Uncovers as soon as face returns | | face | Requires face re-verification to unlock | | pin | Shows PIN prompt (your UI handles unlock via sentinel.unlock(selector)) |


Multiple guards

Protect different parts of the page differently:

const sentinel = new Sentinel({
  provider: new MediaPipeProvider(),
  guards: [
    {
      selector: '#boardpack-viewer',
      action: 'blur',
      threshold_ms: 3000,
      recovery: 'auto',
    },
    {
      selector: '#vote-panel',
      action: 'lock',
      threshold_ms: 0,       // instant — cannot vote while away
      recovery: 'face',
    },
    {
      selector: '#resolution-text',
      action: 'frost',
      threshold_ms: 5000,
      recovery: 'auto',
    }
  ]
})

await sentinel.start()

The sidebar, navbar, and any unguarded elements remain fully interactive.


Heartbeat logging

Send presence events to your server for audit trails and compliance:

const sentinel = new Sentinel({
  provider: new MediaPipeProvider(),
  serverUrl: 'https://your-app.com/api/sentinel/heartbeat',
  guards: [{ selector: '#doc', action: 'blur', threshold_ms: 3000, recovery: 'auto' }]
})

await sentinel.start()

Each heartbeat is a small JSON object — no biometric data:

{
  "session_id": "uuid",
  "ts": 1711180800000,
  "present": true,
  "liveness_score": 0.94,
  "identity_score": 0.0,
  "absence_ms": 0,
  "provider": "[email protected]"
}

Swapping the provider

Sentinel's detection model is pluggable. If a better model ships, swap it without changing anything else:

import { Sentinel } from '@savannahanddelta/sentinel'
import { ONNXProvider } from '@savannahanddelta/sentinel-provider-onnx'

const sentinel = new Sentinel({
  provider: new ONNXProvider({ modelUrl: '/models/my-face-model.onnx' }),
  guards: [{ selector: '#doc', action: 'blur', threshold_ms: 3000, recovery: 'auto' }]
})

await sentinel.start()

Or implement your own:

import type { IPresenceProvider, PresenceFrame } from '@savannahanddelta/sentinel'

class MyProvider implements IPresenceProvider {
  readonly name = 'my-provider'
  readonly version = '1.0.0'
  readonly capabilities = { landmarks: false, gaze: false, head_pose: false, eye_openness: false }

  async load() { /* load your model */ }
  async detect(frame: VideoFrame): Promise<PresenceFrame> {
    return { faceDetected: true, confidence: 0.95, processingTimeMs: 12 }
  }
  isLoaded() { return true }
  unload() {}
}

const sentinel = new Sentinel({ provider: new MyProvider(), guards: [...] })

React example

import { useEffect, useRef } from 'react'
import { Sentinel } from '@savannahanddelta/sentinel'
import { MediaPipeProvider } from '@savannahanddelta/sentinel-provider-mediapipe'

export function ProtectedDocument({ children }: { children: React.ReactNode }) {
  const sentinelRef = useRef<Sentinel | null>(null)

  useEffect(() => {
    const sentinel = new Sentinel({
      provider: new MediaPipeProvider(),
      guards: [{
        selector: '#protected-content',
        action: 'blur',
        threshold_ms: 5000,
        recovery: 'auto',
      }]
    })

    sentinel.start().catch(console.error)
    sentinelRef.current = sentinel

    return () => sentinelRef.current?.stop()
  }, [])

  return (
    <div id="protected-content">
      {children}
    </div>
  )
}

Privacy

  • All face detection runs in the browser via WASM
  • No video frames, images, or facial landmarks are transmitted
  • The only data that leaves the device is the heartbeat signal: { present, liveness_score, absence_ms } — three numbers
  • Camera permission is requested explicitly and can be revoked at any time via sentinel.stop()
  • No biometric data is stored unless you explicitly enable identity mode

Browser support

| Browser | Support | |---------|---------| | Chrome / Edge 88+ | Full | | Firefox 90+ | Full | | Safari 15.4+ | Full | | Mobile Chrome | Full | | Mobile Safari | Full |

Requires getUserMedia (HTTPS or localhost).


Packages

| Package | Description | |---------|-------------| | @savannahanddelta/sentinel | Core SDK — install this | | @savannahanddelta/sentinel-provider-mediapipe | MediaPipe face detection (default) | | @savannahanddelta/sentinel-provider-onnx | ONNX runtime — bring your own model | | @savannahanddelta/sentinel-types | TypeScript types (auto-installed) |


License

Business Source License 1.1 — free for non-commercial use. Commercial use requires a licence. See LICENSE.

Built by Savanna Technologies · Kisumu, Kenya