import { expect, test } from "bun:test"; import { configurePaymentFromConfig } from "../src/config.ts"; import { configurePaymentApi } from "../src/http.ts"; import { GET, POST } from "../src/runtime-api.ts"; import { memoryPaymentStore } from "../src/store.ts"; function request(path: string, body?: unknown) { return new Request(`https://app.test${path}`, { method: body ? "POST" : "GET", headers: body ? { "content-type": "application/json" } : undefined, body: body ? JSON.stringify(body) : undefined, }); } test("package APIs use server subjects and never expose gateway secrets", async () => { configurePaymentFromConfig( { default: "testGateway", environment: "test", gateways: { testGateway: { provider: "sandbox", secret: "server-only" } }, }, memoryPaymentStore(), ); configurePaymentApi({ subject: (ctx) => ctx.user?.id }); const providers = await GET({ req: request("/api/payments/providers") }); const providerBody = await providers.text(); expect(providers.status).toBe(200); expect(providerBody).toContain("testGateway"); expect(providerBody).toContain('"provider":"sandbox"'); expect(providerBody).not.toContain("server-only"); const denied = await POST({ req: request("/api/payments/intents", { subject: "attacker-selected", amount: 500, currency: "USD", idempotencyKey: "anonymous", }), }); expect(denied.status).toBe(403); const created = await POST({ req: request("/api/payments/intents", { subject: "attacker-selected", amount: 500, currency: "USD", idempotencyKey: "owned", }), user: { id: "user-1" }, }); expect(created.status).toBe(201); const payment = await created.json(); expect(payment.id).toStartWith("pay_"); expect(JSON.stringify(payment)).not.toContain("server-only"); const listed = await GET({ req: request("/api/payments/intents"), user: { id: "user-1" }, }); expect((await listed.json()).payments).toHaveLength(1); }); test("administrative payment APIs deny by default", async () => { configurePaymentApi({ subject: () => "user-1" }); const response = await POST({ req: request("/api/payments/reconcile", {}), user: { id: "user-1" }, }); expect(response.status).toBe(403); });