Events

Events let apps react to external triggers. When something happens outside your system - an email arrives, a webhook fires, a calendar event starts - events let you handle it.

How Events Work

Events follow a pub/sub pattern:

  1. Source app defines events it can emit
  2. Subscriber app subscribes to those events
  3. When the event occurs, the subscriber's handler runs

This creates loose coupling between apps. The email app doesn't need to know who cares about new emails. It just emits events.

Defining Events

Events are defined in events.json:

{
  "new_email": {
    "description": "Fires when a new email arrives",
    "capabilities": ["storage", "event"],
    "tokens": {
      "@my-org/auth": {
        "account": ["accountId", "email"]
      }
    },
    "payload": {
      "type": "object",
      "properties": {
        "from": { "type": "string" },
        "subject": { "type": "string" },
        "snippet": { "type": "string" },
        "messageId": { "type": "string" }
      },
      "required": ["from", "subject", "messageId"]
    }
  }
}

Event Fields

Field Required What It Does
description Yes Explains when this event fires
capabilities Yes What event handlers can access
tokens Yes Token fields used for subscription matching
payload Yes Schema for the event data

Token-Based Matching

The tokens field determines who receives events. It specifies which token fields create the subscription key:

"tokens": {
  "@my-org/auth": {
    "account": ["accountId", "email"]
  }
}

This means:

Event Handlers

When you define events, you need three handler files:

src/events/new_email/
├── start.ts    # Runs when first subscriber joins
├── handler.ts  # Processes incoming triggers
└── stop.ts     # Runs when last subscriber leaves

start.ts

Called when the first subscriber subscribes. Use this to set up webhooks or polling:

export default async function start(
  capabilities: Capabilities
): Promise<void> {
  // Register webhook with external service
  await registerGmailWebhook({
    url: capabilities.webhookUrl,
    topic: 'new_email'
  });
}

handler.ts

Called when an external trigger arrives (like a webhook). Process the data and emit events:

export default async function handler(
  input: WebhookPayload,
  capabilities: Capabilities
): Promise<void> {
  // Parse the webhook data
  const email = parseGmailNotification(input);
  
  // Send event to matching subscribers
  await capabilities.event.send('new_email', {
    toSubscribers: {
      email: email.recipient
    },
    payload: {
      from: email.from,
      subject: email.subject,
      snippet: email.snippet,
      messageId: email.id
    }
  });
}

stop.ts

Called when the last subscriber unsubscribes. Clean up resources:

export default async function stop(
  capabilities: Capabilities
): Promise<void> {
  // Remove webhook registration
  await unregisterGmailWebhook();
}

Subscribing to Events

Other apps subscribe to events using the event capability:

export default async function subscribe_to_emails(
  input: Input,
  capabilities: Capabilities
): Promise<Output> {
  await capabilities.event.subscribe(
    '@my-org/email',      // Source app
    'new_email',          // Event name
    'handle_new_email'    // Handler tool in your app
  );
  
  return { subscribed: true };
}

When a new_email event fires, your handle_new_email tool runs with the event payload.

Handling Received Events

Create a tool to handle events you've subscribed to:

// src/tools/handle_new_email.ts
export default async function handle_new_email(
  input: NewEmailPayload,
  capabilities: Capabilities
): Promise<Output> {
  // Process the email event
  await capabilities.storage
    .use('@my-org/inbox')
    .put(`/notifications/${input.messageId}.json`, {
      from: input.from,
      subject: input.subject,
      received: Date.now()
    });
  
  return { processed: true };
}

Unsubscribing

Stop receiving events:

await capabilities.event.unsubscribe(
  '@my-org/email',
  'new_email'
);

Event Flow

Here's the complete flow when an email arrives:

  1. Gmail sends webhook to your email app's handler
  2. Handler parses the notification
  3. Handler calls event.send() with subscriber matching info
  4. Event service finds subscribers with matching tokens
  5. Each subscriber's handler tool runs with the payload
  6. Subscribers process the event independently

[IMAGE: Flow diagram showing External Trigger -> Handler -> Event Service -> Subscriber Tools]

Use Cases

Events are useful for:

Lifecycle Management

The start and stop handlers manage resources efficiently:

This means you don't have duplicate webhooks for multiple subscribers.