前端开发
前端接入 Trigger.dev 实时能力:订阅 run…
在 React/Next.js/Remix 或 BFF 中需要实时显示 Trigger.dev run 状态/元数据/AI 文本流、发送输入、完成 wait token,或从浏览器触发任务时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
前端接入 Trigger.dev 实时能特定
解决思路
- 安装前端 hooks 包:`npm add @trigger.dev/react-hooks`;后端已有 `@trigger.dev/sdk`。固定流程:后端 mint scoped token -> 传给前端 -> 前端用 hook 订阅。
- 后端创建 Public Access Token(读/订阅):从 `@trigger.dev/sdk` 导入 `auth`,调用 `await auth.createPublicToken({ scopes: { read: { runs: ["run_1234"] } } })`;无 scopes 的 token 无效。将 `publicAccessToken` 传给前端。
- 前端订阅 run 状态:在组件顶部加 `"use client";`,从 `@trigger.dev/react-hooks` 导入 `useRealtimeRun`;调用 `const { run, error } = useRealtimeRun(runId, { accessToken: publicAccessToken });`;处理 `error` 和 loading,渲染 `run.status`。
- 区分两种 token:Public Access Tokens 用于 read/subscribe,由 `auth.createPublicToken` 创建;Trigger Tokens 用于从浏览器触发任务,单次使用,由 `auth.createTriggerPublicToken` 创建;两者默认 15 分钟过期。
- 订阅 run 并渲染 metadata 进度:用 `useRealtimeRun<typeof myTask>(runId, { accessToken: publicAccessToken })`;`metadata` 是 `Record<string, DeserializedJson>`,嵌套值需断言,例如 `const progress = run.metadata?.progress as { percentage?: number } | undefined;`;渲染 `run.status` 与 `progress?.percentage ?? 0`;可传 `onComplete: (run, error) => {}` 在完成时响应。
- 只订阅状态字段用 `skipColumns`:对 badge 或进度条不需要 `payload`/`output` 时,调用 `useRealtimeRun(runId, { accessToken: publicAccessToken, skipColumns: ["payload", "output"] })`,减少 wire size 并避免 "Large HTTP Payload" 警告;可跳过的字段包括 `payload`, `output`, `metadata`, `startedAt`, `delayUntil`, `queuedAt`, `expiredAt`, `completedAt`, `number`, `isTest`, `usageDurationMs`, `costInCents`, `baseCostInCents`, `ttl`, `payloadType`, `outputType`, `runTags`, `error`。
- 从浏览器触发任务:用 Trigger Token,不是 Public Access Token;从 `@trigger.dev/react-hooks` 导入 `useTaskTrigger`;调用 `const { submit, handle, isLoading } = useTaskTrigger<typeof myTask>("my-task", { accessToken: triggerToken });`;`submit(payload, options?)` 接收与后端 `trigger` 调用相同 options;用 `handle.id` 显示 run ID。
- 触发并同时订阅一个 hook:用 `useRealtimeTaskTrigger<typeof myTask>("my-task", { accessToken: publicAccessToken })`,返回 `{ submit, run, isLoading }`;当也需要该任务的 streams 时用 `useRealtimeTaskTriggerWithStreams<typeof myTask, STREAMS>`,返回 `{ submit, run, streams, error, isLoading }`。
- 消费 AI/text stream(SDK 4.1.0+,推荐):用 `useRealtimeStream`,传已定义 stream 以获得完整类型安全,或传 `runId` 加可选 stream key;返回 `{ parts, error }`。示例:`const { parts, error } = useRealtimeStream(aiStream, runId, { accessToken: publicAccessToken, timeoutInSeconds: 300, onData: (chunk) => console.log(chunk) });`;`timeoutInSeconds` 默认 60;无定义 stream 时用 `useRealtimeStream<string>(runId, "ai-output", { accessToken })`,省略 key 使用默认 stream;其他 options:`baseURL`, `startIndex`, `throttleInMs`(默认 16);仍支持 legacy `useRealtimeRunWithStreams(runId, options)` 同时获取 run 和所有 streams。
- 向运行中的任务发送输入:从 `@trigger.dev/react-hooks` 导入 `useInputStreamSend`;调用 `const { send, isLoading, isReady } = useInputStreamSend(approval.id, runId, { accessToken });`;按钮禁用条件 `!isReady || isLoading`,点击执行 `send({ approved: true })`。
- 从 React 完成 wait token:后端用 `wait.createToken({ timeout: "10m" })` 创建 token,返回 `{ tokenId: token.id, publicToken: token.publicAccessToken }` 给前端;前端从 `@trigger.dev/react-hooks` 导入 `useWaitToken`,调用 `const { complete } = useWaitToken(tokenId, { accessToken: publicToken });`,用 `complete({ approved: true })` 完成。
- 从后端用 async iterators 订阅:从 `@trigger.dev/sdk` 导入 `runs, tasks`;`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); }`;`runs.subscribeToRun` 在 run 完成时结束,循环自行退出。
- 避免用 Public Access Token 触发任务:错误 `useTaskTrigger("my-task", { accessToken: publicAccessTokenFromCreatePublicToken })`;正确用 `auth.createTriggerPublicToken("my-task")` mint 单次 Trigger Token 并传入。
- 不要创建无 scopes 的 token:错误 `await auth.createPublicToken()`;正确 `await auth.createPublicToken({ scopes: { read: { runs: ["run_1234"] } } })`,否则每次 subscribe 403。
- 不要用 `useRun`/SWR 轮询做实时更新:`useRun` 是基于 SWR 的管理 API hook,不推荐用于 live state;若仍使用,设 `refreshInterval: 0` 停止轮询;正确用 `useRealtimeRun(runId, { accessToken })`,无需轮询或 WebSocket setup。
- 不要忘记 `"use client"`:实时/触发 hooks 不能在 server component 运行;在 Next.js App Router 中,任何使用这些 hooks 的组件顶部加 `"use client";`。
- 不要传输不渲染的 `payload`/`output`:状态 badge 错误用 `useRealtimeRun(runId, { accessToken })`;正确加 `skipColumns: ["payload", "output"]`。
- 不要在 handle 存在前订阅:错误 `useRealtimeRun(handle, { accessToken: handle?.publicAccessToken })` 无 guard;正确加 `enabled: !!handle`,只在 trigger 返回 handle 后订阅。
- 需要后端任务侧能力时,参考 sibling skill `trigger-tasks`:`streams.define()`, `metadata.set()`, `wait.createToken`;聊天代理参考 `trigger-authoring-chat-agent` 与 `trigger-chat-agent-advanced`,它们构建在这些 realtime streams 上。
- 查文档时本地读取,不走网络:参考文档随 skill 同包,位于 `@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`(realtime run object 与 `useRun` 返回的管理 API object 不同)。
- 版本:该 skill 打包在 `@trigger.dev/sdk` 内,从 `node_modules` 直接读取,始终匹配安装的 SDK 版本(见相邻 `package.json`);完整文档在同包 `@trigger.dev/sdk/docs/` 下。
适用边界 · 注意事项
- 不适用于编写后端任务本身:`streams.define` / `metadata.set` / `wait.createToken` 的任务侧属于 `trigger-tasks`。
- 不适用于服务端组件或非 React 客户端环境:这些 hooks 需要客户端组件,例如 Next.js App Router 必须加 `"use client"`。
- 不适用于用管理 API/SWR 轮询历史 run 的场景:实时状态应使用 `useRealtimeRun`,而不是 `useRun`/SWR 轮询。