mcpField
T
trigger-realtime

trigger-realtime

github.com/triggerdotdev開発352.9k 回インストール1 週間前に更新
リポジトリ

trigger-realtime について

Trigger.dev のフロントエンドでリアルタイム更新やストリームを扱うためのガイドです。React、Next.js、Remix の開発者向けに、実行状態の購読、ブラウザーからのタスク起動、ストリーム入出力を説明します。

主な機能

  1. 01実行状態のリアルタイム購読
  2. 02AI・テキストストリームの表示
  3. 03ブラウザーからのタスク起動
  4. 04実行中タスクへの入力送信
  5. 05React での待機トークン完了

活用シーン

  1. 01フロントエンドでのタスク進捗表示
  2. 02AI 出力ストリームの画面構築
  3. 03ブラウザーからのタスク送信と追跡
  4. 04画面を通じたタスク承認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/triggerdotdev/skills --skill trigger-realtime

インストール後、Claude Code で/trigger-realtimeを入力して読み込まれたか確認します。

詳細

リアルタイムとフロントエンド

Trigger.dev の実行状態とストリームを利用する側の機能です。実行のライブ更新を読み取り、AI/テキストストリームを表示し、ブラウザーからタスクをトリガーします。フックは @trigger.dev/react-hooks から、トークンの発行とバックエンドでのサブスクリプションは @trigger.dev/sdk から利用します。

セットアップ

npm add @trigger.dev/react-hooks   # frontend hooks (React/Next.js/Remix)
# @trigger.dev/sdk is already installed for the backend

処理の流れは常に同じです。バックエンドでスコープ付きトークンを発行し、フロントエンドに渡して、フックでサブスクライブします。

// backend (API route / server action)
import { auth } from "@trigger.dev/sdk";

const publicAccessToken = await auth.createPublicToken({
  scopes: { read: { runs: ["run_1234"] } }, // a token with no scopes is useless
});
// frontend
"use client";
import { useRealtimeRun } from "@trigger.dev/react-hooks";

export function RunStatus({ runId, publicAccessToken }: { runId: string; publicAccessToken: string }) {
  const { run, error } = useRealtimeRun(runId, { accessToken: publicAccessToken });
  if (error) return <div>Error: {error.message}</div>;
  if (!run) return <div>Loading...</div>;
  return <div>Run: {run.status}</div>;
}

トークンには 2 種類あります。Public Access Tokens(読み取り/サブスクライブ用。auth.createPublicToken で発行)と Trigger Tokens(ブラウザーからのトリガー用。1 回限りで、auth.createTriggerPublicToken で発行)です。どちらも有効期限はデフォルトで 15 分です。

主なパターン

1. 実行をサブスクライブしてメタデータの進捗を表示する

metadata は Record<string, DeserializedJson> なので、ネストされた値にはキャストが必要です。

"use client";
import { useRealtimeRun } from "@trigger.dev/react-hooks";
import type { myTask } from "@/trigger/myTask";

export function Progress({ runId, publicAccessToken }: { runId: string; publicAccessToken: string }) {
  const { run, error } = useRealtimeRun<typeof myTask>(runId, { accessToken: publicAccessToken });
  if (error) return <div>Error: {error.message}</div>;
  if (!run) return <div>Loading...</div>;
  const progress = run.metadata?.progress as { percentage?: number } | undefined;
  return <div>{run.status}: {progress?.percentage ?? 0}%</div>;
}

実行の完了時に処理を行うには、onComplete: (run, error) => {} を渡します。

2. skipColumns を使ったステータスのみのサブスクリプション

バッジやプログレスバーでは、payload/output は必要ありません。これらをスキップすると、通信データ量を減らし、「Large HTTP Payload」の警告を回避できます。

const { run } = useRealtimeRun(runId, {
  accessToken: publicAccessToken,
  skipColumns: ["payload", "output"],
});

次の項目は任意にスキップできます:payload、output、metadata、startedAt、delayUntil、queuedAt、expiredAt、completedAt、number、isTest、usageDurationMs、costInCents、baseCostInCents、ttl、payloadType、outputType、runTags、error。

3. Trigger Token を使ってブラウザーからトリガーする

ここでの accessToken は Public Access Token ではなく、Trigger Token(auth.createTriggerPublicToken)です。

"use client";
import { useTaskTrigger } from "@trigger.dev/react-hooks";
import type { myTask } from "@/trigger/myTask";

export function TriggerButton({ triggerToken }: { triggerToken: string }) {
  const { submit, handle, isLoading } = useTaskTrigger<typeof myTask>("my-task", {
    accessToken: triggerToken,
  });
  if (handle) return <div>Run ID: {handle.id}</div>;
  return (
    <button onClick={() => submit({ foo: "bar" }, { tags: ["user:123"] })} disabled={isLoading}>
      {isLoading ? "Triggering..." : "Run"}
    </button>
  );
}

submit(payload, options?) は、バックエンドの trigger 呼び出しと同じオプションを受け取ります。

4. 1 つのフックでトリガーとサブスクライブを行う
"use client";
import { useRealtimeTaskTrigger } from "@trigger.dev/react-hooks";
import type { myTask } from "@/trigger/myTask";

export function Runner({ publicAccessToken }: { publicAccessToken: string }) {
  const { submit, run, isLoading } = useRealtimeTaskTrigger<typeof myTask>("my-task", {
    accessToken: publicAccessToken,
  });
  if (run) return <div>{run.status}</div>;
  return <button onClick={() => submit({ foo: "bar" })} disabled={isLoading}>Run</button>;
}

タスクのストリームも利用する場合は、useRealtimeTaskTriggerWithStreams<typeof myTask, STREAMS> を使用します({ submit, run, streams, error, isLoading } が返されます)。

5. AI/テキストストリームを利用する(SDK 4.1.0 以降、推奨)

useRealtimeStream には、完全な型安全性を確保するために定義済みのストリームを渡すか、runId と任意のストリームキーを渡します。{ parts, error } が返されます。

"use client";
import { useRealtimeStream } from "@trigger.dev/react-hooks";
import { aiStream } from "@/trigger/streams"; // a defined stream -> typed parts

export function StreamView({ runId, publicAccessToken }: { runId: string; publicAccessToken: string }) {
  const { parts, error } = useRealtimeStream(aiStream, runId, {
    accessToken: publicAccessToken,
    timeoutInSeconds: 300, // default 60
    onData: (chunk) => console.log(chunk),
  });
  if (error) return <div>Error: {error.message}</div>;
  if (!parts) return <div>Loading...</div>;
  return <div>{parts.join("")}</div>;
}

定義済みのストリームがない場合は、useRealtimeStream<string>(runId, "ai-output", { accessToken }) を使うか、キーを省略してデフォルトのストリームを使用できます。その他のオプション:baseURL、startIndex、throttleInMs(デフォルトは 16)。実行とすべてのストリームを同時に取得する必要がある場合は、従来の useRealtimeRunWithStreams(runId, options) フックも引き続き使用できます。

6. 実行中のタスクに入力を返す
"use client";
import { useInputStreamSend } from "@trigger.dev/react-hooks";
import { approval } from "@/trigger/streams";

export function ApprovalForm({ runId, accessToken }: { runId: string; accessToken: string }) {
  const { send, isLoading, isReady } = useInputStreamSend(approval.id, runId, { accessToken });
  return (
    <button disabled={!isReady || isLoading} onClick={() => send({ approved: true })}>
      Approve
    </button>
  );
}
7. React から待機トークンを完了する
// backend: create the token, return id + publicAccessToken to the frontend
import { wait } from "@trigger.dev/sdk";
const token = await wait.createToken({ timeout: "10m" });
return { tokenId: token.id, publicToken: token.publicAccessToken };
"use client";
import { useWaitToken } from "@trigger.dev/react-hooks";

export function Approve({ tokenId, publicToken }: { tokenId: string; publicToken: string }) {
  const { complete } = useWaitToken(tokenId, { accessToken: publicToken });
  return <button onClick={() => complete({ approved: true })}>Approve</button>;
}
8. バックエンドからサブスクライブする(非同期イテレーター)
import { runs, tasks } from "@trigger.dev/sdk";
import type { myTask } from "./trigger/my-task";

const handle = await tasks.trigger("my-task", { some: "data" });
for await (const run of runs.subscribeToRun<typeof myTask>(handle.id)) {
  console.log(run.payload.some, run.output?.some); // typed
}

runs.subscribeToRun は実行が完了すると終了するため、ループは自動的に終了します。

よくある間違い

  1. 重大:パブリックアクセストークンを使ってブラウザーからトリガーする。 createPublicToken で取得した読み取りトークンではタスクをトリガーできません。

    • 誤り:useTaskTrigger("my-task", { accessToken: publicAccessTokenFromCreatePublicToken })
    • 正しい方法:auth.createTriggerPublicToken("my-task") で単回使用のトリガートークンを発行し、それを渡します。
  2. スコープのないトークン。 スコープのないトークンでは何も認可されないため、すべての subscribe が 403 になります。

    • 誤り:await auth.createPublicToken()
    • 正しい方法:await auth.createPublicToken({ scopes: { read: { runs: ["run_1234"] } } })
  3. ライブ更新に useRun/SWR でポーリングする。 useRun は SWR ベースの管理 API フック(ライブ状態には推奨されません)です。使用する場合は、ポーリングを停止するために refreshInterval: 0 を設定します。

    • 誤り:進行状況の追跡に useRun(runId, { refreshInterval: 1000 }) を使う
    • 正しい方法:useRealtimeRun(runId, { accessToken }) を使う(ポーリングも WebSocket のセットアップも不要です)
  4. "use client" を忘れる。 リアルタイム/トリガーフックはサーバーコンポーネントでは実行できません。

    • 誤り:useRealtimeRun を使う Next.js App Router のサーバーコンポーネント
    • 正しい方法:これらのフックを使うコンポーネントの先頭に "use client"; を記述します。
  5. 描画しない payload/output を送る。

    • 誤り:ステータスバッジに useRealtimeRun(runId, { accessToken }) を使う(大きなペイロードがネットワーク経由で送信されます)
    • 正しい方法:useRealtimeRun(runId, { accessToken, skipColumns: ["payload", "output"] }) を使います
  6. ハンドルが存在する前にサブスクライブする。

    • 誤り:ガードせずに useRealtimeRun(handle, { accessToken: handle?.publicAccessToken }) を使う
    • 正しい方法:enabled: !!handle を追加し、トリガーからハンドルが返された後にのみサブスクライブします。

参考資料

関連スキル:

  • タスク側については trigger-tasks を参照してください:streams.define()、metadata.set()、wait.createToken。
  • チャットエージェントについては trigger-authoring-chat-agent と trigger-chat-agent-advanced を参照してください。これらはこのリアルタイムストリームを基盤としています。

参考ドキュメントは同じパッケージ内のこのスキルの隣に含まれています。インストール済みバージョンに固定されたドキュメントを、ネットワークを使わずローカルで読んでください。上記の sources: frontmatter には、このスキルが参照するすべてのドキュメントが記載されており、いずれも @trigger.dev/sdk/docs/ の下にあります。まず次を確認してください:

  • @trigger.dev/sdk/docs/realtime/react-hooks/subscribe.mdx
  • @trigger.dev/sdk/docs/realtime/react-hooks/streams.mdx
  • @trigger.dev/sdk/docs/realtime/auth.mdx
  • @trigger.dev/sdk/docs/realtime/run-object.mdx(リアルタイムの run オブジェクトは、useRun が返す管理 API オブジェクトとは異なります)

バージョン

このスキルは @trigger.dev/sdk に同梱されており、node_modules から直接読み込まれるため、インストール済みの SDK バージョンと常に一致します(隣接する package.json を参照)。これらの API の完全なドキュメントも、@trigger.dev/sdk/docs/ の下に同梱されています。

コメント