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

@crvouga/mockingbird-service-pharmetika

v1.0.2

Published

Stateful mock of the Pharmetika compounding-pharmacy provider portal: clinics, patients, medication-order validate / EPCS prepare / submit / lookup, the v7 cancel, the medication-template catalog, and status webhooks.

Downloads

427

Readme

@crvouga/mockingbird-service-pharmetika

Stateful mock of the Pharmetika compounding-pharmacy provider portal for test suites: clinic and patient lookup, patient create, medication-order validate / EPCS prepare / submit / lookup, the v7 cancel, the medication-template catalog, and the status webhooks the pharmacy posts back. Orders move only when a test says so (an admin transition or an auto-advance path on the mock clock).

  • Operation coverage: SUPPORT.md
  • The vendor publishes no spec: the contract (openapi.yaml) is hand-authored from the wire shapes our consumer reads and writes (pharmetika-fulfillment.adapter.ts, pharmetika-live.client.ts, and the bodies recorded in the adapter's spec).
  • The success rule. Every body carries Pharmetika's success flag. Only true or 1 is success: the mock answers business failures (unknown patient, controlled substance on submit, a reused order id, …) as HTTP 200 with success: 0 and messages: [{message, type}], the case our adapter guards against.

Install

npm install -D @crvouga/mockingbird-service-pharmetika

ESM only. Node >= 22 or Bun >= 1.2. No native dependencies. Serve it with npx mockingbird-pharmetika serve, createServer from ./server (Node), or createRuntime with any Fetch server.

Usage

Point PHARMETIKA_API_URL at the mock and give the app any PHARMETIKA_API_TOKEN (or pin one with --api-token). Set PHARMETIKA_WEBHOOK_SECRET in the app and pass the same value as --webhook-secret. PHARMETIKA_PRACTITIONER_IDENTIFIER can be any string; PHARMETIKA_CLINIC_NAME=Acme picks the seeded clinic.

npx mockingbird-pharmetika serve --port 8801 \
  --webhook-url http://127.0.0.1:3000/prescriptions/webhooks/pharmetika \
  --webhook-secret "$PHARMETIKA_WEBHOOK_SECRET" \
  --auto-advance "2000:data_entry,shipped,completed"
import { createRuntime } from "@crvouga/mockingbird-service-pharmetika"

const pmk = createRuntime({
  webhooks: { url: "http://127.0.0.1:3000/prescriptions/webhooks/pharmetika", secret: "whsec" },
})
const admin = (path: string, body: unknown) =>
  pmk.fetch(
    new Request(`http://pharmetika.test/__admin${path}`, {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify(body),
    }),
  )

// …the app validates and submits PUT /api/v5/provider_portal/medication_order/id/<uuid>/submit…

// Move the order the way the pharmacy would; each step posts the status webhook.
await admin("/orders/<uuid>/transition", { to: "data_entry" })
await admin("/orders/<uuid>/transition", { to: "shipped", tracking_id: "1Z999" })
await admin("/orders/<uuid>/transition", { to: "completed" })

Routes

All provider-portal routes need x-pmk-authentication-token (any non-empty token unless tokens is set); a missing or rejected token is 401 {success: 0, messages}.

| Route | Behaviour | | --- | --- | | GET /api/v5/provider_portal/clinic/clinic_list | {success: 1, data: [{identifier, data: {name}}]}. Seeded with Acme and Acme West. | | GET /api/v5/provider_portal/provider/patient_list | {success: 1, data: [{patient_id, demographics: {first_name, last_name, DOB, email, phone_primary, line_1, postal_code}}]}. Starts with one sandbox patient (id 1, "Sandbox Patient"). | | POST /api/v5/provider_portal/patient/create_new | A FHIR Patient plus clinic_identifier. Created: {success: true, patient_id, messages: [{message: "Added Patient!"}]}. Same first/last name and DOB as an existing patient: {success: 0, duplicate_entry_count, duplicate_entries: [...]} (our adapter adopts the match). | | PUT …/medication_order/id/{uuid}/validate | Dry run. Checks the clinic, the patient id, each product_identifier against the templates, and a non-empty sig ("Please provide instructions"). Answers data: {controlled_substance_list_count, medication_list: [{…entry, medication_order_entry_identifier, controlled, control_level}]}; a scheduled product (testosterone is C-III) sets controlled. | | PUT …/medication_order/id/{uuid} | EPCS prepare (needs prepared_by). Parks the order at pending_prescriber_approval; it is never submitted. The prescriber "signs" with an admin transition to signed. | | PUT …/medication_order/id/{uuid}/submit | Creates the order at prescription_entered. A controlled substance is refused (success: 0). Idempotent by the UUIDv7: a resubmit of the same clinic / patient / products / quantities / sigs (our adapter regenerates date_issued and entry ids on every attempt, so those are ignored) answers as the first did; different contents under a used id is 409 {success: 0}; a concurrent submit of the same id is 409. | | GET …/medication_order/id/{uuid} | {success: 1, data: {order_status, medication_order_identifier, electronic_prescription_order_number, data: {order_status, …, ancillary_order_data: {medication_order_status: {workflow_status, tracking_id}}}}}; unknown ids 404. | | PUT /api/v7/provider_portal/medication_order/entry/cancel | {note, prescriber_order_number: <uuid>} → {success: 1, messages: []} until the order ships; afterwards (or unknown) success: 0. Emits the webhook. | | GET /api/pharmetika/provider_access/profile/medication_templates | {success: 1, data: [{template_identifier, medication_display_name, description, map_dose_to_product: {dose: product_identifier}, qty_options, default_sigs, available_states, controlled}]}. Accepts the token, Basic (PHARMETIKA_USERNAME/PASSWORD, any pair unless basic is set), or no credentials (unless anonymousCatalog: false) — our client's three fallbacks. |

Webhooks

Every status change posts to --webhook-url with header x-pharmetika-webhook-secret: <secret> (plain equality, as our receiver checks). The body shape follows the namespace's webhookVariant, one per field fallback our receiver reads:

| Variant | Body | | --- | --- | | workflow_status (default) | {event_type, event_data: {electronic_prescription_order_number, medication_order_identifier, medication_order_status: {workflow_status, tracking_id}, tracking_id?, updated_at}} | | status | {event_type, event_data: {medication_order_identifier, status, tracking_id?}} | | flat | {medication_order_identifier, medication_order_workflow_status, tracking_id?} |

Both id fields carry our UUIDv7 (the receiver looks payments up by it). Non-2xx answers are retried (immediately, 5 s, 5 min, 30 min, 2 h). GET /__admin/webhooks lists deliveries, GET /__admin/webhooks/events the payloads, POST /__admin/webhooks/flush runs pending retries, PUT /__admin/webhook-endpoints sets per-namespace receivers.

Status map

Transitions set workflow_status verbatim, so any string works. The ones our mapper knows:

| Workflow status | Our status | | --- | --- | | completed, shipped-received, delivered | delivered | | shipped, Completed Orders | shipped | | cancelled | cancelled | | data_entry*, lab_formulation, contacting_patient, compounding*, filled, dispensed, dispense_checked, dispense_verified, order_reconciliation, shipping, signed, verified, checked, ready, ready-ship, Complete Processing | processing | | anything else (prescription_entered, pending_prescriber_approval) | submitted |

Shipped-or-later statuses generate a tracking_id when none is given; a tracking id promotes submitted/processing to shipped in our receiver.

Admin (beyond the standard contract)

| Route | Effect | | --- | --- | | POST /__admin/orders/:uuid/transition | {to, tracking_id?}: set the workflow status and emit the webhook. | | GET /__admin/orders | The namespace's orders (ids and statuses only). | | GET /__admin/patients, POST /__admin/patients | Read or seed the roster: {patient_id?, clinic_identifier?, demographics: {first_name, last_name, DOB, …}}. | | PUT /__admin/templates | Replace the medication templates ({templates: [...]}). | | GET/PUT /__admin/settings | {tokens?, basic?, anonymousCatalog?, webhookVariant?, autoAdvance?: {afterMs, path} \| null} for the calling namespace. | | POST /__admin/tick | Apply due auto-advance steps (the served mock ticks every 100 ms). Orders awaiting prescriber approval never auto-advance. |

Fault presets (POST /__admin/faults {"preset": "<name>", "count"?: n}; GET /__admin/faults/presets):

| Preset | Effect | | --- | --- | | validate_success_zero, submit_success_zero, prepare_success_zero, lookup_success_zero | HTTP 200 with success: 0 and a message | | validate_422 | 422 {success: 0, messages: [{message: "Please provide instructions"}]} | | success_boolean | successes answer success: true instead of 1 | | success_string | successes answer success: "1" (our client reads it as failure) | | cancel_success_true | cancel answers success: true (our cancel accepts only 1) | | submitted_but_500 | submit records the order, then answers 500; the retry replays success | | patient_create_duplicate, patient_create_500 | the create is refused as a duplicate (naming the patient), or fails | | clinic_list_keyed | clinic_list answers data as an object keyed by identifier | | controlled_count_string, controlled_nested_requests | validate's controlled-substance signal as a string count, or under data.medication_requests | | unauthorized, server_error | 401 on every call; 500 on every provider-portal call | | webhook_duplicate, webhook_reorder, webhook_drop | delivery faults on the next status webhooks |

Namespaces

Our backend's fetch cannot add headers, so a namespace can be chosen three ways: x-mockingbird-namespace, a /ns/<name> prefix on PHARMETIKA_API_URL, or by credential: PUT /__admin/credentials {"credentials": {"<PHARMETIKA_API_TOKEN>": "<namespace>"}} (the Basic username works the same way for the catalog client).

Deliberately not modelled

  • Real fulfilment timing and the pharmacy's internal queue: nothing moves on its own unless autoAdvance is set.
  • EPCS signing itself (two-factor, DEA checks): an admin transition to signed stands for it.
  • Sigs, demographics on orders, documents and reason-for-compounding are validated, never stored or echoed; only the roster keeps the demographics patient_list returns.
  • The live catalog: the default templates are synthesised in the fields the live client parses (no sandbox recording exists); pass templates or PUT /__admin/templates to load recorded rows.
  • Refills, reauthorizations and multi-order shipments.

API

| Export | Kind | Description | | --- | --- | --- | | PharmetikaAPI | class | The in-process mock: fetch(request), reset(), transition(uuid, {to, tracking_id?}), tick(), orders(), webhookBody(order). Options: sqlite, now, namespace, templates, clinics, patients, settings, onWebhook. | | createRuntime | function | The mock with the full service contract (health, admin, namespaces, credentials, presets, webhooks). Options: webhooks: {url, secret, retryDelaysMs?, fetch?}, settings, templates, clinics, patients, tickMs, clock, seed, adminKey, onLog. | | PHARMETIKA_PRESETS | object | Every named fault preset. | | PHARMETIKA_NAMESPACE | string | The service name, "pharmetika". | | TOKEN_HEADER | string | "x-pmk-authentication-token". | | WEBHOOK_SECRET_HEADER | string | "x-pharmetika-webhook-secret". | | tokenCredential | function | The credential a request carries (portal token, else Basic username), for namespace mapping. | | DEFAULT_TEMPLATES, DEFAULT_CLINICS, SANDBOX_PATIENT | values | The seed catalog, clinics and roster patient. | | KNOWN_STATUSES, SUBMITTED_STATUS, PENDING_APPROVAL_STATUS | values | Documented workflow statuses. | | document, operationIds, supportedOperationIds | values | The vendored OpenAPI contract and its operation ids. | | createServer, serveTarget, DEFAULT_PORT (./server) | Node | Serve over node:http (auto-advance ticks every 100 ms); the serve CLI target; port 8801. |

Part of mockingbird.