A Gleam WebSocket consumer for AT Protocol Jetstream events.
1# goose 2 3[![Package Version](https://img.shields.io/hexpm/v/goose)](https://hex.pm/packages/goose) 4[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/goose/) 5 6A Gleam WebSocket consumer for AT Protocol Jetstream events. 7 8```sh 9gleam add goose 10``` 11 12## Quick Start 13 14```gleam 15import goose 16import gleam/io 17 18pub fn main() { 19 // Use default config with automatic retry logic 20 let config = goose.default_config() 21 22 goose.start_consumer(config, fn(json_event) { 23 let event = goose.parse_event(json_event) 24 25 case event { 26 goose.CommitEvent(did, time_us, commit) -> { 27 io.println("Commit: " <> commit.operation <> " in " <> commit.collection) 28 } 29 goose.IdentityEvent(did, time_us, identity) -> { 30 io.println("Identity: " <> identity.handle) 31 } 32 goose.AccountEvent(did, time_us, account) -> { 33 io.println("Account updated: " <> did) 34 } 35 goose.UnknownEvent(_) -> { 36 io.println("Unknown event type") 37 } 38 } 39 }) 40} 41``` 42 43### Custom Configuration 44 45```gleam 46import goose 47import gleam/option 48 49pub fn main() { 50 let config = goose.JetstreamConfig( 51 endpoint: "wss://jetstream2.us-east.bsky.network/subscribe", 52 wanted_collections: ["app.bsky.feed.post", "app.bsky.feed.like"], 53 wanted_dids: [], 54 cursor: option.None, 55 max_message_size_bytes: option.None, 56 compress: True, 57 require_hello: False, 58 ) 59 60 goose.start_consumer(config, handle_event) 61} 62``` 63 64## Configuration Options 65 66**Note:** Goose automatically handles connection failures with exponential backoff retry logic (1s, 2s, 4s, 8s, 16s, 32s, capped at 60s). All connections automatically retry on failure and reconnect on disconnection. 67 68### `wanted_collections` 69An array of Collection NSIDs to filter which records you receive (default: empty = all collections) 70 71- Supports NSID path prefixes like `app.bsky.graph.*` or `app.bsky.*` 72- The prefix before `.*` must pass NSID validation 73- Incomplete prefixes like `app.bsky.graph.fo*` are not supported 74- Account and Identity events are always received regardless of this filter 75- Maximum 100 collections/prefixes 76 77**Example:** 78```gleam 79wanted_collections: ["app.bsky.feed.post", "app.bsky.graph.*"] 80``` 81 82### `wanted_dids` 83An array of Repo DIDs to filter which records you receive (default: empty = all repos) 84 85- Maximum 10,000 DIDs 86 87**Example:** 88```gleam 89wanted_dids: ["did:plc:example123", "did:plc:example456"] 90``` 91 92### `cursor` 93A unix microseconds timestamp to begin playback from 94 95- Absent cursor or future timestamp results in live-tail operation 96- When reconnecting, use `time_us` from your most recently processed event 97- Consider subtracting a few seconds as a buffer to ensure gapless playback 98 99**Example:** 100```gleam 101cursor: option.Some(1234567890123456) 102``` 103 104### `max_message_size_bytes` 105The maximum size of a payload that this client would like to receive 106 107- Zero means no limit 108- Negative values are treated as zero 109- Default: 0 (no maximum size) 110 111**Example:** 112```gleam 113max_message_size_bytes: option.Some(1048576) // 1MB limit 114``` 115 116### `compress` 117Enable zstd compression for WebSocket frames 118 119- Set to `True` to enable compression 120- Default: `False` 121- Uses zstandard compression with Jetstream's custom dictionary 122- Reduces bandwidth by approximately 50% 123- Messages are automatically decompressed before reaching your callback 124- Requires the `ezstd` library (automatically handled as a dependency) 125 126**Example:** 127```gleam 128compress: True 129``` 130 131**Note:** Compression is transparent to your application - compressed messages are automatically decompressed before being passed to your event handler. The bandwidth savings occur on the wire between the server and your client. 132 133### `require_hello` 134Pause replay/live-tail until server receives a `SubscriberOptionsUpdatePayload` 135 136- Set to `True` to require initial handshake 137- Default: `False` 138 139**Example:** 140```gleam 141require_hello: True 142``` 143 144## Full Configuration Example 145 146```gleam 147import goose 148import gleam/option 149 150let config = goose.JetstreamConfig( 151 endpoint: "wss://jetstream2.us-east.bsky.network/subscribe", 152 wanted_collections: ["app.bsky.feed.post", "app.bsky.graph.*"], 153 wanted_dids: ["did:plc:example123"], 154 cursor: option.Some(1234567890123456), 155 max_message_size_bytes: option.Some(2097152), // 2MB 156 compress: True, 157 require_hello: False, 158) 159 160goose.start_consumer(config, handle_event) 161``` 162 163Further documentation can be found at <https://hexdocs.pm/goose>. 164 165## Development 166 167```sh 168gleam build # Build the project 169gleam test # Run the tests 170```