An astronaut, on the moon, fashioning a large hook to a long rope.

    Hooked on Webhooks

    TLDR

    Triplit database events can now be sent to outside APIs with the new webhooks feature, now in developer preview.

    Webhooks: Developer Preview

    As mentioned last week, we're working on a feature that will allow you to subscribe to events in a Triplit database via webhooks. We're excited to announce that we've released a developer preview of this feature on the Triplit Server. This preview is available in development (i.e. using triplit dev) and for self-hosted instances of Triplit. We'll be rolling it out to our hosted customers in the coming weeks while we collect your feedback.

    Configuration

    Webhooks for Triplit servers are configured with a simple JSON object that specifies the URLs to send events to, the collections to watch, and the events ("inserts", "updates", and "deletes") to watch for. Here's an example configuration:

    {
      "https://my-api.dev/webhook": {
        "todos": { "inserts": true, "updates": true, "deletes": true }
      }
    }
    

    CLI

    You can then push this configuration to your Triplit server with the triplit webhooks push command. The server will save the configuration to storage and begin sending events to the specified URLs.

    You can view a server's current webhook configuration with the triplit webhooks print command.

    You can remove a webhook configuration from a server with the triplit webhooks clear command.

    Security

    Webhooks are sent with a 'x-triplit-signature' header that contains a HMAC256 signature of the payload. It is signed with a symmetric secret, the TRIPLIT_WEBHOOK_SECRET environmental variable. This variable must be set in your env for webhooks to send. Here's a simple example of how you might verify the signature in Node.js:

    import { Hono } from 'hono';
    import * as crypto from 'crypto';
    
    const app = new Hono();
    
    app.post('/', async (c) => {
      const body = await c.req.text();
      const secret = process.env.TRIPLIT_WEBHOOK_SECRET;
      const secretBytes = Buffer.from(secret, 'base64');
    
      const signature = c.req.header('x-triplit-signature');
      if (!signature) {
        return c.text('No signature');
      }
    
      const hash = crypto
        .createHmac('sha256', secretBytes)
        .update(body)
        .digest('base64');
    
      const isVerified = crypto.timingSafeEqual(
        Buffer.from(signature),
        Buffer.from(hash)
      );
    
      // If the signature is verified, process the webhook
    
      return c.text('OK');
    });
    
    export default app;
    

    Payload

    Based on the configuration above, the webhook would send a payload like this when a todo is inserted:

    {
      "collectionName": "todos",
      "inserts": [
        {
          "id": "123",
          "text": "Buy milk",
          "completed": false
        }
      ],
      "updates": [],
      "deletes": []
    }
    

    Other improvements

    • Addressed an issue preventing queries from connecting from some React apps running in development mode.
    • Increased the limit on the size of bulk inserts to a Triplit server to 100 MB.
    • Fixed a memory leak in @triplit/db.