import { afterEach, describe, expect, test } from "bun:test"; import type { Context } from "@wrnexus/core"; import { v } from "@wrnexus/validation"; import { serviceClient } from "../src/client.ts"; import { defineService, procedure } from "../src/contract.ts"; import { RPC_ERROR_CODES } from "../src/errors.ts"; import { implement } from "../src/server.ts"; import { inProcessTransport } from "../src/transport.ts"; const originalRpcSecret = process.env.WRNEXUS_RPC_SECRET; const originalAppName = process.env.WRNEXUS_APP_NAME; afterEach(() => { if (originalRpcSecret === undefined) delete process.env.WRNEXUS_RPC_SECRET; else process.env.WRNEXUS_RPC_SECRET = originalRpcSecret; if (originalAppName === undefined) delete process.env.WRNEXUS_APP_NAME; else process.env.WRNEXUS_APP_NAME = originalAppName; }); const billing = defineService({ name: "billing", procedures: { createInvoice: procedure .input(v.object({ amountCents: v.number() })) .output<{ invoiceId: string; forSubject: string }>() .permission("invoice:create") .build(), }, }); function wire(allowed: boolean) { const service = implement( billing, { createInvoice: async ({ amountCents }, ctx) => ({ invoiceId: `inv_${amountCents}`, forSubject: ctx.subject?.subjectId ?? "anon", }), }, { selfApp: "billing", checkPermission: async () => allowed }, ); return inProcessTransport({ "billing/createInvoice": (payload, identity) => service.invoke("createInvoice", payload, identity), }); } describe("RPC integration", () => { test("propagates identity and validates the callee permission", async () => { process.env.WRNEXUS_RPC_SECRET = "test-rpc-secret-at-least-32-chars-long"; process.env.WRNEXUS_APP_NAME = "web"; const client = serviceClient(billing, { app: "billing", as: { user: { id: "u1" }, tenant: { id: "acme" }, locals: {} } as unknown as Context, transport: wire(true), }); expect(await client.createInvoice({ amountCents: 250 })).toEqual({ invoiceId: "inv_250", forSubject: "u1", }); }); test("denies when the callee permission check refuses", async () => { process.env.WRNEXUS_RPC_SECRET = "test-rpc-secret-at-least-32-chars-long"; process.env.WRNEXUS_APP_NAME = "web"; const client = serviceClient(billing, { app: "billing", as: { user: { id: "u1" }, locals: {} } as unknown as Context, transport: wire(false), }); await expect(client.createInvoice({ amountCents: 1 })).rejects.toMatchObject({ code: RPC_ERROR_CODES.denied, }); }); });