src/index.ts

This is where the client should live.

We’re adopting the naming convention of naming the class after the service, without a suffix or prefix. We prefer the exported name be Slack instead of something like SlackIntegration or SlackConnector

Example: GitHub

Comments are for instructional purposes only and should be removed in your implementation.

import { ConnectionAuth, IO, TriggerIntegration } from "@trigger.dev/sdk";
//the official GitHub SDK
import { Octokit } from "octokit";

//define the options that will be passed to the constructor
export type GithubIntegrationOptions = {
  //this is required
  id: string;
  //GitHub can use OAuth or Personal Access Tokens, so this is optional
  token?: string;
};

export class Github implements TriggerIntegration {
  private _options: GithubIntegrationOptions;
  private _client?: Octokit;
  private _io?: IO;
  private _connectionKey?: string;

  constructor(private options: GithubIntegrationOptions) {
    //if the token key is present but undefined, throw an error
    //this is NOT the same as just: if (!options.token)
    //it's a common user bug where an env var is used for the token but hasn't been set
    if (Object.keys(options).includes("token") && !options.token) {
      throw `Can't create GitHub integration (${options.id}) as token was undefined`;
    }

    this._options = options;
  }

  //this is used internally to identify the integration
  get id() {
    return this.options.id;
  }

  //this is used internally to identify the integration, and display nicely in the dashboard
  get metadata() {
    return { name: "GitHub", id: "github" };
  }

  //the two possible options are "LOCAL" or "HOSTED"
  //LOCAL means that the client is using local auth (like a token)
  //HOSTED means that the client is using hosted auth (like OAuth)
  //GitHub supports both, and we use the presence of the token to determine which one to use
  get authSource() {
    return this._options.token ? ("LOCAL" as const) : ("HOSTED" as const);
  }

  //before the `run()` method is called on a Job, this function gets invoked
  //this is important because the authentication data is dynamic, and can change (like OAuth credentials refreshing)
  cloneForRun(io: IO, connectionKey: string, auth?: ConnectionAuth) {
    const github = new Github(this._options);
    github._io = io;
    github._connectionKey = connectionKey;

    if (this._options.token) {
      github._client = new Octokit({
        auth: this._options.token,
        retry: {
          enabled: false,
        },
      });
    } else {
      if (!auth) {
        throw new Error("No auth");
      }

      github._client = new Octokit({
        auth: auth.accessToken,
        retry: {
          enabled: false,
        },
      });
    }

    return github;
  }
}

The TriggerIntegration interface requires three properties and one method to be implemented:

id
string
required

The id that uniquely identifies the Integration. This should always be passed through the constructor options.

metadata
object
required
authSource
LOCAL | HOSTED
required

“LOCAL” should be returned for API keys. “HOSTED” should be returned for OAuth.

cloneForRun
function
required

This method is called before the run() method is called on a Job. This is important because the authentication data is dynamic, and can change (like OAuth credentials refreshing). This method should return a new instance of the Integration, with the new authentication data, io, and connectionKey set so they can be used by runTask and any Triggers.