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

zapstand-mock

v0.1.0

Published

Local mock server for third-party APIs (uazapi WhatsApp first), with a per-project simulation UI and a global Studio. 100% local, no real connections.

Readme

zapstand

Local mock server for third-party APIs, with a per-project simulation UI and a global Studio. 100% local, no real connections, no Docker/Redis/PM2 required.

The first (and currently only) provider is uazapi — a faithful mock of the uazapi WhatsApp API: same routes, same payload field names, same HTTP status codes, and asynchronous webhooks — so you point your system-under-test at the mock by changing nothing but the BASE_URL.

npm install -g zapstand                          # once, globally
zapstand app create projeto-x --provider uazapi  # one app per project
zapstand start projeto-x                          # mock API + simulation UI
zapstand studio                                   # manage all apps in one place

Concepts

  • Provider — the implementation of one external API to mock (its routes, payloads, webhooks). v1 ships uazapi. New providers plug in as independent folders without touching the core — see CONTRIBUTING-PROVIDERS.md.
  • App — one project under test (e.g. projeto-x). Each app is bound to a provider at creation and has its own isolated data (SQLite DB + media): instances, contact profiles, conversations. Apps never see each other's data.
  • Instance (uazapi) — a simulated "connected number". An app can have many.
  • Mock Server — the provider's HTTP API, the thing your code calls.
  • Simulation UI — a WhatsApp-Web-style panel where you act as an external contact: create fictitious contacts and send them messages to your system, and watch your system's replies arrive in real time.
  • Studio — a global admin panel (Prisma-Studio style) listing every app of every provider, with create/remove for apps and instances.

Install

# from npm (once published)
npm install -g zapstand

# or from this repo
npm install
npm run build
npm link            # exposes the `zapstand` command globally

Requires Node.js ≥ 18. The only native dependency is better-sqlite3 (compiled on install).


Daily workflow

# 1. create an app for your project (seeds one connected instance + one contact)
zapstand app create chatbot-clinica --provider uazapi

# 2. start it (FOREGROUND — occupies the terminal, logs here, Ctrl+C to stop)
zapstand start chatbot-clinica
#   mock API:  http://localhost:4000
#   sim UI:    http://localhost:4000   (open in the browser)

# 3. point your system-under-test at the mock:
#      UAZAPI_BASE_URL=http://localhost:4000
#      token: copy it from the sim UI ⚙ Configurações (per instance)

# 4. open the sim UI, send a message as the contact → it arrives at your
#    system as a `messages` webhook. Your system replies via /send/text →
#    the reply shows up in the chat. Status ticks update live.

Run several projects at once by opening one terminal per app (this is the deliberate, PM2-free model). Or use --detach to background one:

zapstand start projeto-x --detach     # writes run.json + logs/out.log
zapstand logs projeto-x               # tail those logs
zapstand stop projeto-x               # stop the backgrounded process

CLI reference

| Command | Description | |---|---| | zapstand providers list | List available providers (v1: uazapi). | | zapstand app create <slug> --provider <name> | Create an app. --name <s>, --no-seed. | | zapstand app list | List apps with their provider. | | zapstand app remove <slug> | Remove an app and all its data. | | zapstand start <slug> | Start mock + UI in the foreground. --port <n>, --delay <ms>, --detach. | | zapstand stop <slug> | Stop a --detach'd app (foreground apps stop with Ctrl+C). | | zapstand ps | List apps currently running (via health-check). | | zapstand logs <slug> | Tail a --detach'd app's logs. -n <lines>. | | zapstand studio | Open the global Studio. --port <n> (default 4500). |

How "is it running?" is detected

No PID files, no OS signals. Each app exposes GET /__health; zapstand ps and the Studio probe the app's last-known port (stored in apps.json) with a short timeout. This works identically for foreground and --detach apps and never reports a stale process as alive.

There is no auto-restart and no clustering — by design. If an app stops, it stays stopped until you run zapstand start again.


Storage layout

Everything lives under ZAPSTAND_HOME (default ~/.zapstand):

~/.zapstand/
  apps.json                 # registry: slug, name, provider, createdAt, lastPort
  apps/
    projeto-x/              # provider: uazapi
      db.sqlite             # instances, contacts, conversations, messages
      media/                # uploaded media for this app
      logs/                 # out.log / err.log (only when --detach)
      run.json              # pid/port/startedAt of the current run

Set ZAPSTAND_HOME to move all apps at once (external disk, network volume, etc.). Each app is a self-contained subfolder; creating/removing one never affects another.


Environment variables

See .env.example. Summary:

| Variable | Default | Purpose | |---|---|---| | ZAPSTAND_HOME | ~/.zapstand | Root for all app data. | | ZAPSTAND_DELAY_MS | 600 | Default webhook/status-transition latency. |


Quality-of-life for testing

  • Reset state: the sim UI ⚙ → Resetar estado do app, or POST http://localhost:<port>/__reset. Clears that app only.
  • Live request log: every inbound API call and outbound webhook is printed in the terminal and streamed to the sim UI's Logs tab.
  • Fault injection: send any /send/* call with header x-zapstand-simulate: error | blocked | timeout (or a "simulate" field in the body) to exercise your error handling.

uazapi mock — what's implemented

Routes faithful to the real API (auth header token, destination field number, message ids id/messageid, status enum Sent/Delivered/Read, messageTimestamp in milliseconds). Full request/response examples are in docs/UAZAPI-ROUTES.md:

  • Instances: POST /instance/create, POST /instance/connect, GET /instance/status, POST /instance/disconnect, DELETE /instance, GET /instance/all, POST /instance/presence
  • Sending: POST /send/text, /send/media, /send/location, /send/contact, /send/menu
  • Messages: POST /message/markread, /message/presence, /message/react
  • Chats/contacts: POST /chat/find, POST /message/find, POST /chat/read, GET /contacts, POST /contacts/list, POST /chat/check
  • Blocking: POST /chat/block, GET /chat/blocklist
  • Webhooks: POST /webhook, GET /webhook; async delivery of messages, messages_update, connection, blocks

Webhook envelope caveat. uazapi's public docs do not pin down the exact delivered webhook body. zapstand uses the best-supported format ({ EventType, event, token, owner, instance, <payload> }); if your real integration expects something different, it's a one-place change in src/providers/uazapi/webhooks.ts. See the note there and in the routes doc.


Develop

npm run build          # builds server (tsc) + both UIs (vite) into dist/
npm run dev:server     # tsc --watch for the backend
npm run typecheck      # type-check without emitting

# Frontend hot-reload while an app runs on :4000 (uazapi UI):
npx vite --config src/providers/uazapi/ui/vite.config.ts
# Studio hot-reload while `zapstand studio` runs on :4500:
npx vite --config src/web/studio/vite.config.ts

License

MIT