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

@everystack/cli

v0.2.2

Published

CLI and OTA updates for Expo apps on everystack

Readme

@everystack/cli

CLI and OTA updates for Expo apps on everystack. Database management (db:migrate, db:seed), OTA publishing, Expo Updates protocol (v0/v1), pluggable storage, RSA-SHA256 code signing, and channels.

Install

pnpm add @everystack/cli drizzle-orm structured-headers

For S3 storage:

pnpm add @aws-sdk/client-s3

Entry Points

| Import | Description | |--------|-------------| | @everystack/cli | Server: handler, storage adapters | | @everystack/cli/client | Client: UpdatesProvider, AppStateUpdateProvider | | @everystack/cli/schema | Drizzle tables (channels, releases, assets) |

Server: Handler

Creates a Web Standard handler implementing the Expo Updates manifest protocol:

import { createUpdatesHandler, createStorage } from '@everystack/cli';
import { db } from './db';

const storage = createStorage({
  type: 'filesystem',
  directory: './updates',
});

const handler = createUpdatesHandler({
  db,
  storage,
  baseUrl: 'https://myapp.com',
  basePath: '/api/updates',
  defaultChannel: 'production',
  auth: {
    verifyToken: async (token) => verifyJWT(token),
  },
  privateKey: process.env.CODE_SIGNING_PRIVATE_KEY, // PEM for RSA-SHA256
});

Mounting

// app/api/updates/[...path]+api.ts
export function GET(request: Request) { return handler(request); }
export function POST(request: Request) { return handler(request); }

Handler Endpoints

The handler serves:

  • Manifest requests — Expo Updates protocol v0/v1 manifest responses with multipart/mixed format
  • Asset downloads — Binary assets from your configured storage
  • Publish endpoint — Authenticated upload of new releases (used by the CLI)

Handler Options

interface UpdatesHandlerOptions {
  db: DrizzleDb;                // Drizzle instance
  storage: StorageAdapter;      // Filesystem or S3
  baseUrl: string;              // Public URL (for asset references in manifests)
  basePath?: string;            // URL prefix to strip
  auth?: {
    verifyToken: (token: string) => Promise<Record<string, unknown> | null>;
  };
  privateKey?: string;          // PEM for RSA-SHA256 code signing
  defaultChannel?: string;      // Default channel (default: 'production')
}

Storage Adapters

Filesystem

import { createStorage } from '@everystack/cli';

const storage = createStorage({
  type: 'filesystem',
  directory: './updates',
});

S3

const storage = createStorage({
  type: 's3',
  bucket: 'my-updates-bucket',
  region: 'us-east-1',
  endpoint: 'https://s3.us-east-1.amazonaws.com', // Optional
});

Custom Adapter

Implement the StorageAdapter interface:

interface StorageAdapter {
  put(key: string, data: Buffer | Uint8Array, contentType?: string): Promise<void>;
  get(key: string): Promise<{ data: Buffer; contentType: string } | null>;
  exists(key: string): Promise<boolean>;
  list(prefix: string): Promise<string[]>;
  delete(key: string): Promise<void>;
}

CLI

Publish updates, manage certificates, and channels from the command line.

Publish an Update

everystack update \
  --channel production \
  --message "Fix login bug" \
  --platform ios          # ios | android | web | all (default: all)

This bundles your app, uploads assets to storage, creates a release record, and signs the manifest.

Code Signing

Generate RSA key pair for manifest signing:

everystack certs:generate --output ./certs
# Creates ./certs/private-key.pem and ./certs/certificate.pem

everystack certs:configure --input ./certs --keyid main
# Configures your app to use the generated certificates

Channel Management

everystack channels list
everystack channels create --name staging
everystack channels create --name production

Database Management

These commands invoke your Lambda function directly via IAM (no database credentials exposed):

everystack db:migrate                   # Run Drizzle migrations
everystack db:seed                      # Seed database (dev only)
everystack db:psql --stage dev          # Open a psql session via Lambda

db:migrate and db:seed dispatch to your Lambda's onAction handler. db:psql proxies a PostgreSQL session through the Lambda, so your database credentials never leave AWS.

Client: React Native

UpdatesProvider

Wraps your app to check for and apply OTA updates:

import { UpdatesProvider } from '@everystack/cli/client';

function App() {
  return (
    <UpdatesProvider
      url="https://myapp.com/api/updates"
      channel="production"
      checkInterval={60000} // Check every 60 seconds
      onUpdateAvailable={(update) => {
        // Optional: prompt user or auto-apply
        console.log('Update available:', update.message);
      }}
      onUpdateApplied={() => {
        console.log('Update applied, restarting...');
      }}
    >
      <MyApp />
    </UpdatesProvider>
  );
}

AppStateUpdateProvider

Checks for updates when the app returns from background:

import { AppStateUpdateProvider } from '@everystack/cli/client';

function App() {
  return (
    <AppStateUpdateProvider url="https://myapp.com/api/updates" channel="production">
      <MyApp />
    </AppStateUpdateProvider>
  );
}

Schema

Add the updates tables to your Drizzle migrations:

import { channels, releases, assets } from '@everystack/cli/schema';

Tables:

  • channels — Named release channels (production, staging, etc.)
  • releases — Published update bundles with metadata
  • assets — Individual asset files referenced by releases

Expo Updates Protocol

The handler implements the full Expo Updates manifest protocol:

  • Protocol v0: Legacy format for older Expo SDK versions
  • Protocol v1: Modern multipart/mixed response format
  • Code signing: RSA-SHA256 signatures on manifest directives
  • Platform filtering: Serves platform-specific bundles based on request headers
  • Channel routing: Multiple release channels with independent version tracks

How It Works

  1. The Expo app sends a manifest request with platform, runtime version, and current update ID
  2. The handler finds the latest release for the requested channel and platform
  3. If a newer release exists, it returns a signed manifest with asset URLs
  4. The Expo runtime downloads assets and applies the update

Peer Dependencies

| Package | Version | Required | |---------|---------|----------| | drizzle-orm | >=0.30.0 | Yes | | structured-headers | ^1.0.0 | Yes (runtime dep) | | @aws-sdk/client-s3 | >=3.0.0 | For S3 storage | | expo-updates | >=0.25.0 | Client SDK | | react | >=18.0.0 | Client SDK | | react-native | >=18.0.0 | Client SDK |

License

MIT