mcpField
W
webhooks

webhooks

github.com/editframe开发19125 次安装2 周前更新
代码仓库

关于 webhooks

为服务器应用接收 Editframe webhook 通知提供指南和代码模式,涵盖签名验证、持久化接收、重复事件处理,以及渲染、文件和流水线事件负载。

主要功能

  1. 01配置 HTTPS webhook URL 和事件主题
  2. 02验证原始请求体的 HMAC-SHA256 签名
  3. 03响应前持久化接收事件
  4. 04处理重复及乱序投递
  5. 05说明渲染、文件和流水线主题

适用场景

  1. 01接收 Editframe 渲染状态更新
  2. 02处理文件生命周期通知
  3. 03跟踪流水线运行、步骤和审核

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/editframe/skills --skill webhooks

安装后在 Claude Code 中输入/webhooks确认已加载。

详细介绍

Webhooks

当服务器需要在客户端连接非活跃时接收通知,请使用 webhooks。

对于实时进度显示或一次性渲染,请使用 getRenderProgress 或 getFileProcessingProgress。这些函数会使用事件流。

SDK 中没有用于注册 webhook 的函数。请通过控制面板(API → API Keys,或 editframe.com/resource/api_keys)为 API 密钥配置 webhook。设置 Webhook URL(必须使用 HTTPS),并选择要接收的 Webhook Events(主题)。创建或更新密钥时,控制面板会生成 Webhook Secret,用于对投递进行签名。复制此密钥,并与 API 密钥一同保存。

处理 Webhook

在接受请求前验证签名并校验载荷。返回成功前先持久化事件。

示例接受一个由应用程序定义的 acceptEvent 函数。该函数必须先将事件提交到持久化收件箱或队列,然后其 Promise 才能完成。

import express from "express";
import crypto from "node:crypto";

type WebhookEvent = { topic: string; data: Record<string, unknown> };
type AcceptEvent = (event: WebhookEvent, fingerprint: string) => Promise<void>;

export function createWebhookRouter(secret: string, acceptEvent: AcceptEvent) {
  if (!secret) throw new Error("Webhook secret is required");
  const router = express.Router();

  router.post("/webhooks/editframe", express.raw({ type: "*/*" }), async (req, res) => {
    const signature = req.get("x-webhook-signature");
    const rawBody = req.body;
    if (!signature || !/^[a-f0-9]{64}$/i.test(signature)) {
      return res.status(401).send("Invalid signature");
    }
    if (!Buffer.isBuffer(rawBody)) {
      return res.status(400).send("Raw body required");
    }

    const expected = crypto.createHmac("sha256", secret).update(rawBody).digest();
    if (!crypto.timingSafeEqual(Buffer.from(signature, "hex"), expected)) {
      return res.status(401).send("Invalid signature");
    }

    let payload: WebhookEvent;
    try {
      const value = JSON.parse(rawBody.toString("utf-8"));
      if (!value || typeof value.topic !== "string" || !value.data ||
          typeof value.data !== "object" || Array.isArray(value.data)) {
        return res.status(400).send("Invalid payload");
      }
      payload = value;
    } catch {
      return res.status(400).send("Invalid JSON");
    }

    const fingerprint = crypto.createHash("sha256").update(rawBody).digest("hex");
    try {
      await acceptEvent(payload, fingerprint);
      return res.status(200).send("OK");
    } catch {
      return res.status(500).send("Event not accepted");
    }
  });

  return router;
}

将此路由器挂载在解析请求正文的中间件(例如 express.json())之前。此类中间件会消耗已签名的字节。

保持持久化接收过程简短;投递 HTTP 超时时间为 30 秒。之后由工作进程处理已存储的事件。

对于已接受的重复事件,返回成功。将存储故障记录到应用程序日志中,但不要暴露密钥或已签名的正文。

每个请求都包含 X-Webhook-Signature:原始 JSON 正文的十六进制编码 HMAC-SHA256。重新序列化 JSON 可能会生成不同的签名。

载荷

{ topic: string, data: {...} }
渲染主题:render.created、render.pending、render.rendering、render.completed、render.failed

data 包含 id、status、created_at、completed_at、failed_at、width、height、fps、byte_size、duration_ms、md5、metadata、expires_at(null = 永久)、download_url(完成后填充)、error(失败时填充)。

文件主题:file.created、file.uploading、file.processing、file.ready、file.failed、file.updated

data 包含 id、type(video/image/caption)、status、filename、byte_size、md5、mime_type、width、height、expires_at。对于不属于其他文件主题的文件状态更改,Editframe 会发送 file.updated。

Pipeline 主题

Editframe 会为每个组织启用 pipelines。Editframe 只向已启用 pipelines 的组织发送 pipeline 主题。如需获取 pipelines,请向 Editframe 介绍您的素材:https://editframe.com/factory#contact。

主题Editframe 发送时机data
pipeline_run.created创建运行时(pending)。运行
pipeline_run.started运行开始执行其步骤时(running)。运行
pipeline_run.retried重试状态为 failed 或 cancelled 的运行时。运行
pipeline_run.completed运行成功时。运行
pipeline_run.failed、pipeline_run.filtered、pipeline_run.cancelled运行以相应状态结束时。运行
pipeline_step.started步骤开始时。步骤
pipeline_step.progress分段步骤的 watermark_ms 增加时。每个步骤每 10 秒最多发送一个事件。步骤
pipeline_step.waiting_external端点返回 202,或 redact_render 步骤开始渲染时。该步骤会等待回调或渲染完成。步骤
pipeline_step.waiting_review审核步骤创建审核任务时。步骤
pipeline_step.retrying可重试的失败后,或重试运行后,步骤即将开始新一轮尝试时。步骤
pipeline_step.completed、pipeline_step.failed、pipeline_step.skipped、pipeline_step.cancelled步骤成功、失败、跳过或取消时。步骤
pipeline_review.decided用户或 API 密钥批准或拒绝审核时。审核
pipeline_review.expired审核在没有决策的情况下过期时。审核
pipeline_group.created创建状态为 open 或 closed 的组时。组
pipeline_group.closed一个打开的组被关闭,且其中部分运行尚未完成时。组
pipeline_group.completed已关闭组中的所有运行均完成时。组
pipeline_group.reopened重试某个运行后,已完成的组再次变为 closed 时。组
file.receiving流式上传开始时。文件
file.sealed流式上传封存时。对于流式上传,此主题取代 file.processing。文件
  • 运行 data:id、pipeline_id、pipeline_version、pipeline_digest、group_id、file_id、external_id、metadata、status、sequence、created_at、completed_at、error。
  • 步骤 data:id、pipeline_run_id、run_metadata、step_key、namespace、type、status、attempt、sequence、started_at、completed_at、watermark_ms、review_task_id、error。
  • 审核 data:id、pipeline_run_id、run_metadata、step_run_id、step_key、attempt、status(approved、rejected 或 expired)、decision({ decision, decided_by: { type, id }, reason },或过期后的 null)、sequence、created_at、expires_at、decided_at。事件不包含批准时的更正内容。使用 getPipelineReview 获取审核内容。
  • 组 data:id、pipeline_id、pipeline_version、external_id、metadata、status、completion_count、runs(total、succeeded、failed、filtered、cancelled)、created_at、closed_at、completed_at。
  • metadata 和 run_metadata 包含创建运行或组时的 metadata。
  • 只有在筛选器或审核停止所有分支时,运行才会以 filtered 状态结束。若某个分支停止,但最终步骤成功,则会发送 pipeline_run.completed。每个跳过的步骤都会发送 pipeline_step.skipped。
  • 文件 data 的字段与其他文件主题相同。
  • error 为 null 或 { message, code }。

请遵守以下规则:

  • 在 API key 上选择每个流水线主题。Editframe 不会发送该 key 未列出的主题。
  • 使用该 API key 创建运行和分组。Editframe 只会将运行、步骤和审核主题发送到创建该运行的 API key,并且只会将分组主题发送到创建该分组的 API key。
  • 运行使用创建它的 API key。对于由用户在仪表板中启动的运行,该 key 是用户在 Webhooks 下选择的 key。如果用户未选择任何 key,运行不会发送任何 webhook。
  • 使用 sequence 对同一运行的运行、步骤和审核事件排序。投递可能会乱序到达。
  • 预期同一 attempt 可能再次收到 pipeline_step.started。等待空闲工作线程槽位的步骤开始时会再次发送该事件。
  • 步骤创建或变为就绪时不会发送事件,审核任务打开时也不会发送审核事件。pipeline_step.waiting_review 会通知审核任务。
  • 关闭一个所有运行都已完成的分组时,只会收到 pipeline_group.completed。收到 pipeline_group.reopened 后,预期会再次收到 pipeline_group.completed。

对于已启用流水线的组织,仪表板中的 API key 表单会在 Pipeline events 下列出流水线主题。保存表单时,会保留表单未列出的主题。仪表板中的运行页面会列出该运行及其步骤的 webhook 事件和每次投递尝试。

旧版主题

Editframe 仍会发送这些与已弃用的按类型文件 API 相关的主题。请勿基于这些主题构建新的集成。

image_file.created、isobmff_file.created、isobmff_track.created、unprocessed_file.created。

投递与重复处理

每个事件都会作为一次 HTTP POST 到达。投递可能重复;请勿假定事件有序,也不要假定重试次数没有上限。

data.id 用于标识资源,而非投递。多个生命周期事件可以共享该 ID,重复更新也可能共享同一主题。

使用请求体指纹,在端点配置的 API key 范围内识别相同的投递。将其与已接受的事件原子地存储。

相同的请求体无法区分内容完全相同的独立事件。请围绕资源状态或应用拥有的转换键来设计业务操作。

请勿将资源 ID 或主题与 ID 的组合用作永久通知去重键。

监控失败的投递,并通过 API 对重要资源状态进行对账。收到投递确认并不代表业务处理成功。

测试

在仪表板中更改 API key 的 Webhook URL。随后 Editframe 会向新 URL 发送一个测试事件:

{ topic: "webhook.test", data: { id: "<API key ID>", org_id: "<organization ID>" } }

该事件携带 X-Webhook-Signature,其值来自该 key 的 webhook secret。在处理程序中接受 webhook.test 主题。

若要测试渲染或文件主题,请创建真实渲染或上传一个小文件。

本地开发时,可以通过隧道公开开发服务器,例如使用 ngrok http 3000。测试期间,将 API key 的 Webhook URL 指向隧道 URL。

发送反馈

向 Editframe 反馈问题和改进建议:

  • 如果 Editframe 或此 skill 导致问题,请找到解决方法并继续任务。之后报告问题和解决方法。
  • 如果你发现也能帮助其他任务的改进,而不仅限于当前任务,请发送建议。例如,建议改进说明、补充示例、更合适的默认设置或新功能。

每个不同的问题或建议分别提交一份报告。如果报告提交失败,请继续任务。

curl -sS https://editframe.com/api/v1/feedback \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $EDITFRAME_API_KEY" \
  --data-binary @- <<'JSON'
{
  "category": "bug",
  "skill": "webhooks",
  "summary": "One line that names the problem or the suggestion",
  "details": "For a problem: steps, expected result, actual result, and errors. For a suggestion: the change and how it helps.",
  "workaround": "The workaround that you used. Omit this field for a suggestion."
}
JSON

将 category 设置为 bug、documentation、feature_request、performance 或 other。API key 为可选项。不提供 key 的报告将以匿名方式提交。请勿在报告中填写密钥、API key 或个人数据。所有字段、限制和响应详见 editframe-api skill。

评论

支持 Markdown