Installation
Install
The package installs from its repository, with a GitHub account that has access to it. It is built on install:
npm install github:FCAgreatgoals/lfp-webhooks
It is then imported as @fca.gg/lfp-webhooks.
Standalone server
Enough when the bot exposes nothing else over HTTP:
import { createReceiver } from '@fca.gg/lfp-webhooks'
import { listen } from '@fca.gg/lfp-webhooks/node'
const receiver = createReceiver({ secret: process.env.LFP_WEBHOOKS_SECRET })
await listen(receiver, 8080, { path: '/hooks/lfp' })
listen() and createServer() options:
path: the path listened on,/by default. Any other route answers404;maxBodySize: maximum body size in bytes, 5 MiB by default. Past it, the server answers413;host: the address to listen on (listen()only).
createServer(receiver, options) returns the node:http server without opening it, and listen() resolves once the port is listening.
Express
The body must arrive raw: express.json() would have consumed and re-serialized it, which would invalidate the signature.
import express from 'express'
import { createReceiver } from '@fca.gg/lfp-webhooks'
import { lfpWebhooks } from '@fca.gg/lfp-webhooks/express'
const app = express()
const receiver = createReceiver({ secret: process.env.LFP_WEBHOOKS_SECRET })
app.post('/hooks/lfp', express.raw({ type: 'application/json' }), lfpWebhooks(receiver))
Without a raw body, the middleware answers 500 and explains what to mount.
Fastify
import { createReceiver } from '@fca.gg/lfp-webhooks'
import { registerLfpWebhooks } from '@fca.gg/lfp-webhooks/fastify'
const receiver = createReceiver({ secret: process.env.LFP_WEBHOOKS_SECRET })
registerLfpWebhooks(app, receiver, { path: '/hooks/lfp' })
registerLfpWebhooks registers the content type parser that keeps the raw body. If your application already has one for application/json, pass contentTypeParser: false and provide a Buffer in request.body yourself.
Your own server
handle() assumes nothing about the server: give it the raw body and the headers, it returns the status and body to send back.
const { status, body } = receiver.handle(rawBody, headers)
The response goes out right away, and handlers run afterwards, in a queue.
Receiver options
createReceiver({
secret, // HMAC signature secret; without it, the signature is not checked
token, // token expected in `Authorization: Bearer <token>`
dedupeSize, // delivery IDs remembered (512 by default, 0 disables)
onError, // handler errors (console.error by default)
})
See Security to choose between signature and token.
Shutting down cleanly
receiver.flush() resolves once every accepted delivery has been processed: wait for it before exiting the process, or in your tests.
process.on('SIGTERM', async () => {
await receiver.flush()
process.exit(0)
})