Repository navigation
Expand file tree
/
Copy pathfastify.ts
More file actions
57 lines (50 loc) · 1.89 KB
/
Copy pathfastify.ts
File metadata and controls
57 lines (50 loc) · 1.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import Fastify, { type FastifyInstance } from "fastify";
import { handleWebhook, type Ledger } from "./webhook.js";
import type { RunningApp } from "./running.js";
/**
* Fastify 5.
*
* Fastify parses JSON itself, so the raw body has to be asked for. Replacing
* the `application/json` parser with one that returns the `Buffer` untouched
* does that - and doing it inside a plugin keeps the replacement scoped to the
* webhook routes. Fastify's encapsulation means the rest of the application
* keeps its normal JSON parsing; registered at the root instead, every route
* would receive Buffers.
*/
export function createFastifyApp(ledger: Ledger): FastifyInstance {
const app = Fastify({ logger: false });
void app.register(async (webhooks) => {
webhooks.addContentTypeParser(
"application/json",
{ parseAs: "buffer" },
(_request, body, done) => done(null, body),
);
webhooks.post("/webhooks", async (request, reply) => {
const raw = Buffer.isBuffer(request.body) ? request.body : Buffer.alloc(0);
const signature = request.headers["x-signature"];
const result = handleWebhook(
ledger,
raw,
typeof signature === "string" ? signature : undefined,
);
return reply.code(result.status).send(result.body);
});
});
return app;
}
/**
* Listens on an ephemeral loopback port.
*
* Pass the host explicitly. Fastify's default is `localhost`, which it binds
* on every address the name resolves to; that works, but it makes the address
* the test should use a question about the machine's resolver. `listen`
* resolves to the address it bound, so there is no `address()` to parse.
*/
export async function startFastify(ledger: Ledger): Promise<RunningApp> {
const app = createFastifyApp(ledger);
const baseUrl = await app.listen({ port: 0, host: "127.0.0.1" });
return {
baseUrl,
close: () => app.close(),
};
}