npm.io
1.0.0 • Published 4d ago

@lobomfz/ghostapi

Licence
MIT
Version
1.0.0
Deps
0
Size
6 kB
Vulns
0
Weekly
172

ghostapi

Mock http server with typed in-memory SQLite database. powered by Elysia. works with any Standard Schema library. uses Kysely for type-safe database queries.

bun add -d @lobomfz/ghostapi

Usage

your app probably calls external APIs using a base URL from env:

// src/billing.ts
const STRIPE_API = process.env.STRIPE_API; // https://api.stripe.com in prod

export async function updateSubscription(customerId: string, plan: string) {
  const res = await fetch(`${STRIPE_API}/customers/${customerId}/subscription`, {
    method: "POST",
    body: JSON.stringify({ plan }),
  });

  return res.json();
}

create a mock that handles those routes:

import { Mock } from "@lobomfz/ghostapi";
import { type } from "arktype";

const schema = type({
  id: "string",
  plan: "string",
});

const stripeMock = new Mock(
  { customers: schema },
  // db is fully typed based on your schemas
  // app is a full elysia instance
  (app, { db }) => {
    app.post(
      "/customers/:id/subscription",
      async ({ params, body }) => {
        await db
          .updateTable("customers")
          .set({ plan: body.plan })
          .where("id", "=", params.id)
          .execute();

        return db
          .selectFrom("customers")
          .selectAll()
          .where("id", "=", params.id)
          .executeTakeFirst();
      },
      { body: schema },
    );

    return {
      seedCustomer: (id: string, plan: string) =>
        db.insertInto("customers").values({ id, plan }).execute(),
    };
  },
);

in tests, set STRIPE_API=http://localhost:4100 and your code calls the mock transparently:

import { test, expect } from "bun:test";
// your production code
import { updateSubscription } from "../src/billing";

stripeMock.listen(4100);

test("update subscription", async () => {
  // seed data through helpers or directly via db
  await stripeMock.helpers.seedCustomer("cus_123", "free");

  const customer = await updateSubscription("cus_123", "pro");

  expect(customer.plan).toBe("pro");
});

API

new Mock<T, H>(schemas: T, setup: (app: Elysia, ctx: { db: Kysely<T>, schemas: T }) => H | void)

mock.db      // Kysely client
mock.helpers // return value from setup function
mock.listen(port: number): void
mock.reset(table?: keyof T): void

Notes

  • Booleans are stored as 0/1

Keywords