Tasks are the main way that developers will interact with your Integration. They are the actions that developers will be able to perform in their jobs.
You should add a runTask() function to your integration, before adding individual Tasks. It will be used by all Tasks, and allows users to use any function in the official SDK as a Task.
export class Github implements TriggerIntegration { ... runTask<T, TResult extends Json<T> | void>( key: IntegrationTaskKey, //change Octokit to the official SDK for your integration callback: (client: Octokit, task: IOTask, io: IO) => Promise<TResult>, options?: RunTaskOptions, errorCallback?: RunTaskErrorCallback ): Promise<TResult> { if (!this._io) throw new Error("No IO"); if (!this._connectionKey) throw new Error("No connection key"); return this._io.runTask( key, (task, io) => { if (!this._client) throw new Error("No client"); return callback(this._client, task, io); }, { //change this to the slug for your integration (lowercase, no spaces) icon: "github", retry: retry.standardBackoff, ...(options ?? {}), connectionKey: this._connectionKey, }, errorCallback ); } ...}
Any tasks you add will use the runTask function you added above.
Remember we want to structure our integration to match the original SDK. If an SDK has a client.forms.get function, we want to add a myintegration.forms.get task.
This requires adding a bit of structure to the SDK, to add the Forms object, the get function and use runTask inside them.
In this example, we’ll add io.github.issues.create. This will allow users to create a GitHub issue in their jobs.
Comments inline are for instructional purposes only, and should not be included in your final code.
integration/github/issues.ts
import { IntegrationTaskKey } from "@trigger.dev/sdk";import { GitHubReturnType, GitHubRunTask, onError } from "./index";import { Octokit } from "octokit";export class Issues { //the runTask you created in the other file, we'll use this for all Tasks runTask: GitHubRunTask; constructor(runTask: GitHubRunTask) { this.runTask = runTask; } create( //this must be the first parameter, it's used to identify the task key: IntegrationTaskKey, //if possible use the official SDK type. Here we had to define our own. params: { title: string; owner: string; repo: string } //you must define the return type (it will be a promise, in this case grabbed from the official SDK) ): GitHubReturnType<Octokit["rest"]["issues"]["create"]> { //use runTask return this.runTask( key, async (client, task) => { //the official SDK is used here const result = await client.rest.issues.create({ owner: params.owner, repo: params.repo, title: params.title, }); return result.data; }, //all of these properties are displayed in the Trigger.dev dashboard { name: "Create Issue", params, //properties provide a great experience for developers debugging a Run properties: [ { label: "Owner", text: params.owner, }, { label: "Repo", text: params.repo, }, { label: "Title", text: params.title, }, ], }, //you can define a custom error function, or omit this. onError ); }}
Notice how the params are the second argument, that’s because the first argument is always the
task key. See our Keys and Resumability docs for more on
why this is important.
integrations/github/index.ts
//This type is used in the Issues class aboveexport type GitHubRunTask = InstanceType<typeof Github>["runTask"];export class Github implements TriggerIntegration { ... //this allows us to do `io.github.issues.create()` get issues() { //the bind is needed to preserve the `this` context return new Issues(this.runTask.bind(this)); } ...}