# wicket A webhook-to-SSE gateway. Receives webhook POSTs, delivers them to subscribers as Server-Sent Events. ## How it works The entire HTTP API is two verbs on the same path: ``` POST / → publish an event GET / Accept: text/event-stream → subscribe (SSE stream) ``` The path is an arbitrary topic name. Path separators create a hierarchy — subscribing to a prefix gets you all events underneath it: ``` GET /github.com/chrisguidry/docketeer → just docketeer events GET /github.com/chrisguidry/ → all chrisguidry repo events GET /github.com/ → all GitHub events GET / → everything ``` A POST to `/github.com/chrisguidry/docketeer` delivers to all four subscribers above. ## Zero configuration by default wicket works out of the box with no configuration — any path accepts POSTs and SSE connections. A YAML configuration file layers in authentication only where needed: ```yaml paths: github.com/chrisguidry/docketeer: verify: hmac-sha256 secret: "the-github-webhook-secret" signature_header: X-Hub-Signature-256 subscribe_secret: "token-for-docketeer-subscribers" ``` Values support environment variable interpolation via `$VAR` or `${VAR}` syntax, so secrets can come from the environment rather than being hardcoded: ```yaml paths: github.com/chrisguidry/docketeer: verify: hmac-sha256 secret: "${WEBHOOK_SECRET}" signature_header: X-Hub-Signature-256 subscribe_secret: "${SUBSCRIBE_TOKEN}" ``` - Unconfigured paths accept POSTs without verification - Configured paths verify webhook signatures and reject invalid ones - Subscribe secrets require `Authorization: Bearer ` for SSE connections - Configuration is hot-reloaded on file change or SIGHUP ## Browser support CORS headers are sent on all responses, so browser apps can POST events and subscribe via `EventSource`. One limitation: the browser's `EventSource` API doesn't support custom headers, so browser clients can only subscribe to paths without a `subscribe_secret`. Protected paths are for server-to-server use. ## Event format Every event is wrapped in an envelope and delivered as SSE: ``` id: unique-event-id data: {"id":"...","timestamp":"...","path":"github.com/chrisguidry/docketeer","headers":{...},"payload":{...}} ``` Subscribers can reconnect with `Last-Event-ID` to replay missed events from an in-memory ring buffer (default 1000 events). ## Filtering Optional query params filter events on the subscribe side: ``` GET /github.com/chrisguidry/docketeer?filter=payload.ref:refs/heads/main ``` Simple dot-path equality matching. Multiple filters are AND'd. ## Usage ```bash wicket # listen on :8080, no configuration wicket -address :9090 # custom listen address wicket -configuration wicket.yaml # with webhook verification wicket -buffer-size 5000 # larger replay buffer ``` ## Building ```bash go build -o wicket . ``` Or with Docker: ```bash docker build -t wicket . ``` ## Why the name "wicket"? A "wicket" is a [small door or gate](https://en.wiktionary.org/wiki/wicket) next to a larger one.