Skip to main content

Overview

The @databite/connectors package provides ready-to-use connectors for popular services like Slack, Trello, GitHub, and more. Each connector includes built-in authentication flows, type-safe configuration, and comprehensive action and sync implementations.

Installation

npm install @databite/connectors @databite/build @databite/flow @databite/types
Peer Dependencies:
npm install zod typescript

Available Connectors

Slack Connector

Connect to Slack workspaces for messaging, channel management, and user synchronization.

Features

  • OAuth 2.0 authentication flow
  • Automatic token refresh
  • Type-safe configuration with Zod schemas
  • Extensible with custom actions and syncs

Configuration

import { slackConnector } from "@databite/connectors";

// Integration config
const integrationConfig = {
  clientId: "your-slack-client-id",
  clientSecret: "your-slack-client-secret",
  redirectUri: "https://your-app.com/auth/slack/callback",
};

// Connection config (set during authentication)
const connectionConfig = {
  accessToken: "xoxb-...",
  refreshToken: "xoxr-...",
};

Usage

// Create an integration
const slackIntegration = slackConnector.createIntegration(
  "My Slack Integration",
  integrationConfig
);

// The connector includes built-in authentication flow
// Use with @databite/connect for UI integration
import { ConnectModal } from "@databite/connect";

function SlackConnect() {
  return (
    <ConnectModal
      open={isOpen}
      onOpenChange={setIsOpen}
      integration={slackIntegration}
      onAuthSuccess={(integration, config) => {
        console.log("Slack connected:", config);
      }}
    />
  );
}

Trello Connector

Connect to Trello boards for project management and task tracking.

Features

  • API key authentication
  • Type-safe configuration with Zod schemas
  • Extensible with custom actions and syncs
  • Built-in authentication flow

Configuration

import { trelloConnector } from "@databite/connectors";

// Integration config (empty for Trello)
const integrationConfig = {};

// Connection config (set during authentication)
const connectionConfig = {
  apiKey: "your-trello-api-key",
};

Usage

// Create an integration
const trelloIntegration = trelloConnector.createIntegration(
  "My Trello Integration",
  integrationConfig
);

// The connector includes built-in authentication flow
// Use with @databite/connect for UI integration
import { ConnectModal } from "@databite/connect";

function TrelloConnect() {
  return (
    <ConnectModal
      open={isOpen}
      onOpenChange={setIsOpen}
      integration={trelloIntegration}
      onAuthSuccess={(integration, config) => {
        console.log("Trello connected:", config);
      }}
    />
  );
}

Usage Examples

Basic Connector Usage

import { slackConnector, trelloConnector } from "@databite/connectors";
import { createIntegration, createConnection } from "@databite/build";

// Create a Slack integration
const slackIntegration = slackConnector.createIntegration(
  "My Slack Integration",
  {
    clientId: "your-client-id",
    clientSecret: "your-client-secret",
    redirectUri: "https://your-app.com/auth/slack/callback",
  }
);

// Create a connection
const slackConnection = createConnection({
  integrationId: slackIntegration.id,
  config: {
    accessToken: "xoxb-...",
    teamId: "T1234567890",
    teamName: "My Workspace",
  },
});

// Send a message
await slackConnector.actions.sendMessage.handler(
  {
    channel: "#general",
    text: "Hello from my app!",
  },
  slackConnection
);

Using Multiple Connectors

import { slackConnector, trelloConnector } from "@databite/connectors";

class MultiConnectorService {
  private connections = new Map<string, any>();

  async setupConnections() {
    // Setup Slack connection
    const slackConnection = await this.setupSlackConnection();
    this.connections.set("slack", slackConnection);

    // Setup Trello connection
    const trelloConnection = await this.setupTrelloConnection();
    this.connections.set("trello", trelloConnection);
  }

  async createTaskInTrelloAndNotifySlack(taskData: any) {
    // Create card in Trello
    const trelloConnection = this.connections.get("trello");
    const card = await trelloConnector.actions.createCard.handler(
      {
        name: taskData.title,
        desc: taskData.description,
        idList: taskData.listId,
      },
      trelloConnection
    );

    // Notify in Slack
    const slackConnection = this.connections.get("slack");
    await slackConnector.actions.sendMessage.handler(
      {
        channel: taskData.slackChannel,
        text: `New task created: ${card.name}`,
        blocks: [
          {
            type: "section",
            text: {
              type: "mrkdwn",
              text: `*New Task Created*\n*Title:* ${card.name}\n*Trello Link:* ${card.url}`,
            },
          },
        ],
      },
      slackConnection
    );

    return card;
  }

  private async setupSlackConnection() {
    // Your Slack authentication logic
    return {
      accessToken: "xoxb-...",
      teamId: "T1234567890",
      teamName: "My Workspace",
    };
  }

  private async setupTrelloConnection() {
    // Your Trello authentication logic
    return {
      accessToken: "trello-access-token",
      userId: "trello-user-id",
      username: "trello-username",
    };
  }
}

Data Synchronization

import { slackConnector, trelloConnector } from "@databite/connectors";

class DataSyncService {
  async syncAllData() {
    const results = {
      slack: await this.syncSlackData(),
      trello: await this.syncTrelloData(),
    };

    console.log("Sync completed:", results);
    return results;
  }

  private async syncSlackData() {
    const connection = await this.getSlackConnection();

    const [users, channels, messages] = await Promise.all([
      slackConnector.syncs.syncUsers.handler(connection),
      slackConnector.syncs.syncChannels.handler(connection),
      slackConnector.syncs.syncMessages.handler(connection),
    ]);

    return {
      users: users.length,
      channels: channels.length,
      messages: messages.length,
    };
  }

  private async syncTrelloData() {
    const connection = await this.getTrelloConnection();

    const [boards, cards, members] = await Promise.all([
      trelloConnector.syncs.syncBoards.handler(connection),
      trelloConnector.syncs.syncCards.handler(connection),
      trelloConnector.syncs.syncMembers.handler(connection),
    ]);

    return {
      boards: boards.length,
      cards: cards.length,
      members: members.length,
    };
  }
}

Error Handling

import { slackConnector } from "@databite/connectors";

class SlackService {
  async sendMessageSafely(messageData: any, connection: any) {
    try {
      const result = await slackConnector.actions.sendMessage.handler(
        messageData,
        connection
      );

      console.log("Message sent successfully:", result);
      return result;
    } catch (error) {
      if (error.message.includes("channel_not_found")) {
        console.error("Channel not found, creating it...");
        await this.createChannelAndRetry(messageData, connection);
      } else if (error.message.includes("not_authed")) {
        console.error("Authentication failed, refreshing token...");
        await this.refreshConnection(connection);
      } else {
        console.error("Unexpected error:", error);
        throw error;
      }
    }
  }

  private async createChannelAndRetry(messageData: any, connection: any) {
    // Create the channel first
    await slackConnector.actions.createChannel.handler(
      {
        name: messageData.channel.replace("#", ""),
        isPrivate: false,
      },
      connection
    );

    // Retry sending the message
    return await slackConnector.actions.sendMessage.handler(
      messageData,
      connection
    );
  }
}

Configuration

Environment Variables

Set up your environment variables for each connector:
# Slack
SLACK_CLIENT_ID=your-slack-client-id
SLACK_CLIENT_SECRET=your-slack-client-secret
SLACK_REDIRECT_URI=https://your-app.com/auth/slack/callback

# Trello
TRELLO_API_KEY=your-trello-api-key
TRELLO_API_TOKEN=your-trello-api-token

Connector Configuration

import { slackConnector, trelloConnector } from "@databite/connectors";

// Configure Slack connector
const slackConfig = {
  clientId: process.env.SLACK_CLIENT_ID!,
  clientSecret: process.env.SLACK_CLIENT_SECRET!,
  redirectUri: process.env.SLACK_REDIRECT_URI!,
};

// Configure Trello connector
const trelloConfig = {
  apiKey: process.env.TRELLO_API_KEY!,
  apiToken: process.env.TRELLO_API_TOKEN!,
};

Best Practices

1. Use Type-Safe Configuration

import { slackConnector } from "@databite/connectors";
import { z } from "zod";

// Define your configuration schema
const slackConfigSchema = z.object({
  clientId: z.string().min(1),
  clientSecret: z.string().min(1),
  redirectUri: z.string().url(),
});

// Validate configuration
const slackConfig = slackConfigSchema.parse({
  clientId: process.env.SLACK_CLIENT_ID,
  clientSecret: process.env.SLACK_CLIENT_SECRET,
  redirectUri: process.env.SLACK_REDIRECT_URI,
});

2. Implement Proper Error Handling

class ConnectorService {
  async executeActionSafely<T>(
    connector: any,
    actionName: string,
    params: any,
    connection: any
  ): Promise<T | null> {
    try {
      const action = connector.actions[actionName];
      if (!action) {
        throw new Error(`Action ${actionName} not found`);
      }

      return await action.handler(params, connection);
    } catch (error) {
      console.error(`Action ${actionName} failed:`, error);

      // Implement retry logic or fallback behavior
      if (this.shouldRetry(error)) {
        return await this.retryAction(
          connector,
          actionName,
          params,
          connection
        );
      }

      return null;
    }
  }

  private shouldRetry(error: any): boolean {
    // Implement retry logic based on error type
    return (
      error.message.includes("rate_limit") || error.message.includes("timeout")
    );
  }
}

3. Use Connection Pooling

class ConnectionManager {
  private connections = new Map<string, any>();
  private connectionLocks = new Map<string, Promise<any>>();

  async getConnection(connectorId: string, connectionId: string) {
    const key = `${connectorId}-${connectionId}`;

    if (this.connections.has(key)) {
      return this.connections.get(key);
    }

    if (this.connectionLocks.has(key)) {
      return await this.connectionLocks.get(key);
    }

    const connectionPromise = this.createConnection(connectorId, connectionId);
    this.connectionLocks.set(key, connectionPromise);

    try {
      const connection = await connectionPromise;
      this.connections.set(key, connection);
      return connection;
    } finally {
      this.connectionLocks.delete(key);
    }
  }

  private async createConnection(connectorId: string, connectionId: string) {
    // Your connection creation logic
  }
}

Testing

Unit Testing Connectors

import { slackConnector } from "@databite/connectors";

describe("Slack Connector", () => {
  const mockConnection = {
    accessToken: "mock-token",
    teamId: "T1234567890",
    teamName: "Test Workspace",
  };

  it("should send a message", async () => {
    const result = await slackConnector.actions.sendMessage.handler(
      {
        channel: "#test",
        text: "Test message",
      },
      mockConnection
    );

    expect(result.ok).toBe(true);
    expect(result.message).toBeDefined();
  });

  it("should create a channel", async () => {
    const result = await slackConnector.actions.createChannel.handler(
      {
        name: "test-channel",
        isPrivate: false,
      },
      mockConnection
    );

    expect(result.ok).toBe(true);
    expect(result.channel).toBeDefined();
  });
});

Integration Testing

import { slackConnector, trelloConnector } from "@databite/connectors";

describe("Multi-Connector Integration", () => {
  it("should create Trello card and notify Slack", async () => {
    const trelloConnection = await createTrelloConnection();
    const slackConnection = await createSlackConnection();

    // Create Trello card
    const card = await trelloConnector.actions.createCard.handler(
      {
        name: "Test Card",
        desc: "Test Description",
        idList: "test-list-id",
      },
      trelloConnection
    );

    // Notify Slack
    const message = await slackConnector.actions.sendMessage.handler(
      {
        channel: "#general",
        text: `New card created: ${card.name}`,
      },
      slackConnection
    );

    expect(card.id).toBeDefined();
    expect(message.ok).toBe(true);
  });
});
I