Skip to main content

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 answers 404;
  • maxBodySize: maximum body size in bytes, 5 MiB by default. Past it, the server answers 413;
  • 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)
})