Skip to content

Bun + Hono + Postgres

Thin Hono fetch adapter over the checkout kernel with explicit Postgres migrate and storeFactory.

Updated View as Markdown

@paykernel/example-bun-hono-postgres is a private workspace host (private: true). It is not published. HTTP mapping is the same thin Hono adapter as Bun + Hono + SQLite. The difference is how tests and the listen script obtain stores.

Source: examples/bun-hono-postgres (README).

Postgres here means durable inbox / recon / idempotency tables on a shared cluster (@paykernel/store-postgres/pg). The charge gateway is still the kernel mock. No published adapter declares coordinationScope: "multi-region". This host is still one Hono process.

HTTP mapping

src/app.ts matches the sqlite Hono host: createCheckoutHandlers + honoWebhook from @paykernel/integration-hono. Stripe HMAC is verified on Request.text(). Never c.req.json() on /webhooks/stripe. Status codes come from mapInboxOutcome, not @paykernel/webhooks. Never fulfill in onWebhookVerified.

Routes (same as other hosts):

Method Path Notes
POST /payments Create order + mock charge
POST /webhooks/stripe Raw body + stripe-signature
GET /orders/:orderId Order book
POST /internal/reconcile Test hook. Do not deploy.
POST /internal/provider-paid Test hook. Do not deploy.
GET /internal/create-count Test hook. Do not deploy.

Tests pass { enableTestHooks: true }. Listen does not. Without the flag, internal routes return 404.

Listen (Postgres required)

src/index.ts uses the typed /pg API ({ client: pool }), matching Getting started and the store-postgres README:

import { createCheckoutKernel } from "@paykernel/example-checkout-kernel";
import {
  createPgPostgresExecutor,
  createPostgresStoresFromPg,
  migratePostgresAdapter,
} from "@paykernel/store-postgres/pg";
import { Pool } from "pg";

const pgUrl = process.env.PAYMENTS_SDK_PG_URL ?? process.env.DATABASE_URL;
const pool = new Pool({ connectionString: pgUrl });
const executor = createPgPostgresExecutor(pool);
// Ops/CI only — migrate explicitly before kernel, never on import/request
await migratePostgresAdapter(executor);
const stores = createPostgresStoresFromPg({ client: pool });
const kernel = await createCheckoutKernel({
  storeFactory: async () => ({
    ...stores,
    close: () => {
      void pool?.end();
    },
  }),
});

createPostgresStoresFromPg is { client, clock?, namespace? } — not { executor } (packages/store-postgres/src/drivers/pg.ts).

Without PAYMENTS_SDK_PG_URL / DATABASE_URL the process exits. Set ALLOW_MEMORY_FALLBACK=1 to fall back to the kernel’s in-memory SQLite (dev only, not a Postgres RC):

PAYMENTS_SDK_PG_URL=postgres://payments:payments@127.0.0.1:54329/payments_sdk bun src/index.ts
# or
ALLOW_MEMORY_FALLBACK=1 bun src/index.ts

Listen does not enable test hooks. Do not deploy this example as-is.

Tests

Live Postgres is required for the checkout suite. When PAYMENTS_SDK_PG_URL (or DATABASE_URL) is unset, that suite is describe.skipIf — same honesty as packages/store-postgres/docs/testing.md.

docker compose -f ../../packages/store-postgres/docker-compose.yml up -d
PAYMENTS_SDK_PG_URL=postgres://payments:payments@127.0.0.1:54329/payments_sdk bun test

From the monorepo root with no PG env, bun test examples/bun-hono-postgres still runs the test-hook honesty tests and skips the live Postgres case.

Tests call createHonoCheckoutApp(kernel) and app.fetch. They do not start a listener.

The honesty tests still construct createCheckoutKernel() with no Postgres factory (in-memory sqlite) to assert /internal/* is 404 without enableTestHooks.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close