bob: Add GET /payments/:id/receipt in src/routes.ts returning {id, m… [session #43 run 1]
Session 29be3c37e270fadc9d677bcae5cf9c3c run 1. Auto-committed by Origit when the agent stopped. Here's what was done: **[`src/routes.ts`](src/routes.ts)** — added `GET /payments/:id/receipt` before the existing `GET /payments/:id` route (order matters so Express doesn't interpret `receipt` as an `:id` param). The masking logic: ```ts const maskedPan = pan.slice(0, 6) + '*'.repeat(pan.length - 10) + pan.slice(-4); ``` For PAN `4111111111111111` (16 digits) → `411111******1111`. **[`src/routes.test.ts`](src/routes.test.ts)** — added two tests: - Happy path: verifies all five receipt fields and that the masked PAN equals `411111******1111` using the test PAN from the existing fixture. - 404 path: verifies unknown ID returns 404. --- **Origit declaration** ``` read: src/routes.ts, src/types.ts, src/routes.test.ts wrote: src/routes.ts, src/routes.test.ts added_deps: none commands: npm test ```
Origit record
hash verified Raw JSON- Actor
- Bob IDE, mode
origit-build· config 335c7c910427 - Session
- #43 run 1 29be3c37e270fadc9d677bcae5cf9c3c · 27 Sep 2026 13:23 UTC → 27 Sep 2026 13:23 UTC
- Author
- Timotej
- Approver
- bernard · 27 Sep 2026 13:23 UTC
- Tests
- 6 passed · 0 failed
- Record hash
- c75043394aec347c0a925bbbb5758c974c0bdafa8ff399f4fc14a4825f9a6986
Read 3
- filesrc/routes.test.ts821c101cbe
- filesrc/routes.ts27e04d505c
- filesrc/types.ts0ba02a3cab
Wrote 2
- filesrc/routes.ts
also touched (1): tests, vendored packages, lockfiles, manifests
- filesrc/routes.test.ts
Commands 4
- shpwd
- shcat > /home/timotej/Documents/bcco/code/demo/northbridge-payments/src/routes.ts << 'EOF' import { Router, Request, Response } from 'express'; import { randomUUID } from 'crypto'; import * as store from './store'; import { Payment } from './types'; const router = Router(); router.post('/payments', (req: Request, res: Response) => { const { merchantId, amountMinor, currency, pan } = req.body as Partial<Payment>; if (!merchantId || amountMinor === undefined || !currency || !pan) { res.status(400).json({ error: 'merchantId, amountMinor, currency and pan are required' }); return; } const ALLOWED_CURRENCIES = ['EUR', 'GBP', 'USD']; if (!ALLOWED_CURRENCIES.includes(currency)) { res.status(400).json({ error: 'currency must be EUR, GBP or USD' }); return; } const payment: Payment = { id: randomUUID(), merchantId, amountMinor, currency, pan, status: 'authorised', createdAt: new Date().toISOString(), }; store.create(payment); res.status(201).json(payment); }); router.get('/payments/:id/receipt', (req: Request, res: Response) => { const payment = store.get(req.params.id); if (!payment) { res.status(404).json({ error: 'not found' }); return; } const { pan } = payment; const maskedPan = pan.slice(0, 6) + '*'.repeat(pan.length - 10) + pan.slice(-4); res.json({ id: payment.id, merchantId: payment.merchantId, amountMinor: payment.amountMinor, currency: payment.currency, maskedPan, }); }); router.get('/payments/:id', (req: Request, res: Response) => { const payment = store.get(req.params.id); if (!payment) { res.status(404).json({ error: 'not found' }); return; } res.json(payment); }); router.get('/payments', (_req: Request, res: Response) => { res.json(store.list()); }); export default router; EOF
- shcat >> /home/timotej/Documents/bcco/code/demo/northbridge-payments/src/routes.test.ts << 'EOF' test('GET /payments/:id/receipt returns masked PAN', async () => { const created = await request(app).post('/payments').send(validBody); const id = created.body.id as string; const res = await request(app).get(`/payments/${id}/receipt`); expect(res.status).toBe(200); expect(res.body.id).toBe(id); expect(res.body.merchantId).toBe(validBody.merchantId); expect(res.body.amountMinor).toBe(validBody.amountMinor); expect(res.body.currency).toBe(validBody.currency); expect(res.body.maskedPan).toBe('411111******1111'); }); test('GET /payments/:id/receipt returns 404 for unknown id', async () => { const res = await request(app).get('/payments/does-not-exist/receipt'); expect(res.status).toBe(404); }); EOF
- shnpm test
Deterministic pre-filter
zero Bobcoins · runs on every pushNo trigger fired: no new dependency, no external read, no command, no agent-config change, no hidden characters in anything read. Bob was not asked.
Changes
2 file(s)- Msrc/routes.test.ts
- Msrc/routes.ts
Show diff
diff --git a/src/routes.test.ts b/src/routes.test.ts
index ff93951..6008334 100644
--- a/src/routes.test.ts
+++ b/src/routes.test.ts
@@ -41,3 +41,20 @@ test('POST /payments returns 400 for unsupported currency', async () => {
expect(res.status).toBe(400);
expect(res.body.error).toMatch(/EUR, GBP or USD/);
});
+
+test('GET /payments/:id/receipt returns masked PAN', async () => {
+ const created = await request(app).post('/payments').send(validBody);
+ const id = created.body.id as string;
+ const res = await request(app).get(`/payments/${id}/receipt`);
+ expect(res.status).toBe(200);
+ expect(res.body.id).toBe(id);
+ expect(res.body.merchantId).toBe(validBody.merchantId);
+ expect(res.body.amountMinor).toBe(validBody.amountMinor);
+ expect(res.body.currency).toBe(validBody.currency);
+ expect(res.body.maskedPan).toBe('411111******1111');
+});
+
+test('GET /payments/:id/receipt returns 404 for unknown id', async () => {
+ const res = await request(app).get('/payments/does-not-exist/receipt');
+ expect(res.status).toBe(404);
+});
diff --git a/src/routes.ts b/src/routes.ts
index cc4637c..8522764 100644
--- a/src/routes.ts
+++ b/src/routes.ts
@@ -29,6 +29,23 @@ router.post('/payments', (req: Request, res: Response) => {
res.status(201).json(payment);
});
+router.get('/payments/:id/receipt', (req: Request, res: Response) => {
+ const payment = store.get(req.params.id);
+ if (!payment) {
+ res.status(404).json({ error: 'not found' });
+ return;
+ }
+ const { pan } = payment;
+ const maskedPan = pan.slice(0, 6) + '*'.repeat(pan.length - 10) + pan.slice(-4);
+ res.json({
+ id: payment.id,
+ merchantId: payment.merchantId,
+ amountMinor: payment.amountMinor,
+ currency: payment.currency,
+ maskedPan,
+ });
+});
+
router.get('/payments/:id', (req: Request, res: Response) => {
const payment = store.get(req.params.id);
if (!payment) {