Events
The @arrow-labs/auth-sdk/events subpath lets a first-party backend consume platform events from its dedicated queue. It has one runtime dependency, rabbitmq-client (auto-reconnecting), and is Node-only.
The consumer attaches to your queue arrowlabs.events.{your_client_id} — it never declares or binds topology (the platform owns that). See Platform events for the model.
import { createEventConsumer } from '@arrow-labs/auth-sdk/events';
const consumer = createEventConsumer({ url: process.env.AMQP_URL!, // amqps://user:pass@host:5671 clientId: 'your-client-id', // → queue arrowlabs.events.your-client-id concurrency: 10, // handlers in flight; default 10 onError: (err, envelope) => logger.error({ err, eventId: envelope?.event_id }, 'handler failed'),}) .on('user.registered', async (payload, envelope) => { // payload is fully typed (UserRegisteredPayload): user_id, email, display_name, roles, … await provisionAccount(payload.user_id, payload.email); }) .on('user.suspended', async (payload) => { await disableAccount(payload.user_id); // payload: { user_id, reason } }) .onUnhandled((envelope) => { logger.debug({ type: envelope.event_type }, 'no handler'); });
await consumer.start();// on shutdown:await consumer.stop();Delivery & failure
Section titled “Delivery & failure”- Ack on success. When a handler resolves, the message is acknowledged.
- Failure → dead-letter, no requeue. If a handler throws (or the body can’t be decoded), the message is nacked without requeue and routed to the dead-letter queue — no poison-message loops. Failed events are inspectable from the admin portal’s DLQ view.
Idempotency
Section titled “Idempotency”Events are at-least-once. Make handlers idempotent; wire event_id to your own store via the optional deduplicator hook:
createEventConsumer({ url, clientId, deduplicator: { isDuplicate: (id) => redis.sismember('processed_events', id), // checked before the handler markProcessed: (id) => redis.sadd('processed_events', id), // after the handler succeeds },});isDuplicate short-circuits to an ack (handler skipped); markProcessed runs after the handler resolves, before the ack. The SDK ships no storage — the seam is yours.
The full catalogue is exported as PlatformEventType, with EventEnvelope, EventPayloadMap, and each *Payload interface.