mcpField
N
nango-function-builder

nango-function-builder

github.com/nangohq开发3120 次安装10 周前更新
代码仓库

关于 nango-function-builder

用于构建和验证可部署的 Nango TypeScript actions 与 syncs。它要求检查项目结构,为 sync 明确增量检查点和删除策略,并在部署前执行 dryrun 与测试。

主要功能

  1. 01构建 Nango actions 和 syncs
  2. 02要求为 sync 规划检查点与删除策略
  3. 03检查 TypeScript 项目结构及注册方式
  4. 04使用 Nango dryrun 验证函数
  5. 05在部署前生成并运行测试

适用场景

  1. 01为服务商 API 请求创建 action
  2. 02构建定时或 webhook 驱动的 sync
  3. 03修改 Zero YAML TypeScript 项目中的函数

安装

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

$npx skills add https://github.com/nangohq/skills --skill nango-function-builder

安装后在 Claude Code 中输入/nango-function-builder确认已加载。

附带文件references/actions.mdreferences/syncs.md

详细介绍

Nango 函数构建器

使用可重复的模式和验证步骤,构建可部署的 Nango 函数(操作和同步)。

适用场景

  • 用户想要构建或修改 Nango 函数
  • 用户想要在 Nango 中构建操作
  • 用户想要在 Nango 中构建同步

同步策略门槛(写代码前必须完成)

如果任务是同步,请先阅读 references/syncs.md,再写代码,并首先说明以下其中一种方案:

  • 检查点方案:
    • 变更来源(updated_at、modified_since、变更记录端点、游标、分页令牌、偏移量/页码、since_id 或 webhook)
    • 检查点架构
    • 检查点如何改变提供方请求或恢复状态
    • 请求仍会遍历完整数据集,还是只返回变更的行
    • 删除策略
  • 全量刷新阻碍:
    • 文档或示例载荷中说明的确切提供方限制
    • 检查点为何无法在此处发挥作用

无效的同步实现:

  • 因为更简单而进行全量刷新
  • 调用 saveCheckpoint(),却不调用 getCheckpoint()
  • 读取或保存检查点,却未在请求参数或分页状态中使用它
  • 在新同步中使用 syncType: 'incremental' 或 nango.lastSyncDate
  • 在使用仅返回变更数据的检查点(modified_after、updated_after、变更记录端点)时使用 trackDeletesStart() / trackDeletesEnd()。这类请求会省略未变更的行,因此 trackDeletesEnd() 会错误地删除这些行。
  • 在已明确包含已删除记录事件的增量同步中使用 trackDeletesStart() / trackDeletesEnd()

选择方案

操作:

  • 一次性、由用户触发的请求,使用 createAction() 构建
  • 写代码前阅读 references/actions.md

同步:

  • 定时或由 webhook 驱动的缓存更新,使用 createSync() 构建
  • 先完成同步策略门槛
  • 写代码前阅读 references/syncs.md

工作流(推荐)

  1. 确定这是操作还是同步。
  2. 阅读相应的参考文件:references/actions.md 或 references/syncs.md。
  3. 对于同步,检查提供方文档或载荷中的检查点和删除信息,确定端点返回的是完整数据还是变更的行,并完成同步策略门槛。
  4. 收集所需输入和外部值。对于连接查找、凭据或发现,请使用 Nango HTTP API。
  5. 确认这是 Zero YAML TypeScript 项目(no nango.yaml),并且你位于 Nango 根目录(存在 .nango/)。
  6. 在 {integrationId}/actions/ 或 {integrationId}/syncs/ 下创建或更新函数,应用此处的架构和大小写规则,然后在 index.ts 中注册。
  7. 使用 nango dryrun ... --validate -e dev --no-interactive --auto-confirm 验证。
  8. 如果验证无法通过,请停止并报告缺失的外部状态或输入。
  9. 验证通过后,运行 nango dryrun ... --save,然后运行 nango generate:tests,再运行 npm test。
  10. 仅在收到请求时,使用 nango deploy dev 部署。

必需输入(缺失时询问用户)

始终需要:

  • 集成 ID(提供方名称)
  • 连接 ID(用于 dryrun)
  • 脚本名称(kebab-case)
  • API 参考 URL 或示例响应

特定操作需要:

  • 用例摘要
  • 输入参数
  • 输出字段
  • 如有需要,提供元数据 JSON
  • 用于 dryrun --input 和模拟数据的测试输入 JSON(必需;无输入操作请使用 {})

特定同步需要:

  • 模型名称(单数,PascalCase)
  • 频率(每小时、每 5 分钟等)
  • 检查点架构(时间戳、游标、页令牌、偏移量/页码、since_id 或组合形式)
  • 检查点如何改变提供方请求或恢复状态
  • 删除策略(已删除记录端点/Webhook,或说明为何必须完整刷新)
  • 如果提议完整刷新,请从文档/示例响应中指出阻止使用检查点的具体提供方限制
  • 如有需要,提供元数据 JSON(team_id、workspace_id)

如果缺少任何必需的外部值,请先检查仓库和提供方文档,然后提出有针对性的问题。对于同步,只要提供方支持,就选择检查点和删除策略。如果找不到可行的检查点策略,请在编写完整刷新方案前明确说明原因。

前置条件(编写代码前完成)

确认 TypeScript 项目(无 nango.yaml)

此技能仅支持使用 createAction()/createSync() 的 TypeScript 项目。

ls nango.yaml 2>/dev/null && echo "YAML PROJECT DETECTED" || echo "OK - No nango.yaml"

如果看到 YAML PROJECT DETECTED:

  • 立即停止。
  • 告知用户先升级到 TypeScript 格式。
  • 不要尝试混用 YAML 和 TypeScript。

参考:https://nango.dev/docs/implementation-guides/platform/migrations/migrate-to-zero-yaml

验证 Nango 项目根目录

确认 Nango 根目录后再创建文件:

ls -la .nango/ 2>/dev/null && pwd && echo "IN NANGO PROJECT ROOT" || echo "NOT in Nango root"

如果看到 NOT in Nango root:

  • 切换到包含 .nango/ 的目录
  • 重新运行检查
  • 不要使用绝对路径作为变通方法

所有文件路径都必须相对于 Nango 根目录。在 Nango 根目录内创建带额外前缀的文件,会生成嵌套目录并导致构建失败。

项目结构和命名

./
|-- .nango/
|-- index.ts
|-- hubspot/
|   |-- actions/
|   |   `-- create-contact.ts
|   `-- syncs/
|       `-- fetch-contacts.ts
`-- slack/
    `-- actions/
        `-- post-message.ts
  • 提供方目录:小写(hubspot、slack)
  • 操作文件:kebab-case(create-contact.ts)
  • 同步文件:kebab-case(许多团队使用 fetch- 前缀,但并非必需)
  • 每个文件包含一个函数(操作或同步)
  • 必须在 index.ts 中导入所有操作和同步
在 index.ts 中注册脚本(必需)

仅使用副作用导入(不使用默认/命名导入)。包含 .js 扩展名。

// index.ts
import './github/actions/get-top-contributor.js';
import './github/syncs/fetch-issues.js';

注册不正确的表现:文件可以编译,但会看到 No entry points found in index.ts...,或者该函数始终不会出现。

不可妥协的规则

共享平台限制
  • 无 YAML 的 TypeScript 项目使用 createAction() / createSync(),而不是 nango.yaml。
  • 使用副作用导入(import './<path>.js')在 index.ts 中注册每个操作/同步。
  • 不能添加任意软件包。使用相对导入;内置模块包括 zod、crypto/node:crypto 和 url/node:url。
  • 在函数代码之外,使用 Nango HTTP API 查询连接、凭证并发起代理调用。不要臆造 CLI 令牌/连接命令。
  • 在每个提供方调用上方添加 API 文档链接注释。
  • 操作输出不得超过 2MB。
  • HTTP 重试默认值为 0;应审慎设置 retries,尤其是写入操作。
同步规则
  • 同步记录需要稳定的字符串 id。
  • 新同步应定义 checkpoint 架构,先调用 nango.getCheckpoint(),并在每页或每批处理后调用 nango.saveCheckpoint()。
  • 只有在检查点会改变请求或恢复状态(since、updated_after、cursor、page_token、offset、page、since_id 等)时才有效。不使用检查点却保存它,不算增量同步。
  • 新同步不得使用 syncType: 'incremental' 或 nango.lastSyncDate。
  • 默认使用 nango.paginate(...) + nango.batchSave(...)。当 cursor、link 或 offset 分页方式适用时,避免手动使用 while (true) 循环。
  • 提供商返回删除记录、墓碑记录或删除 Webhook 时,优先使用 batchDelete()。
  • 仅当提供商无法返回变更、删除记录或恢复状态,或数据集很小时,才使用全量刷新。
  • 使用全量刷新时,引用文档或有效负载中对提供商限制的确切说明。“这样更简单”并不足以作为理由。
  • deleteRecordsFromPreviousExecutions() 已弃用。全量刷新时,在获取或保存数据前调用 trackDeletesStart(),且仅在成功完成全量获取和保存后调用 trackDeletesEnd()。
  • 切勿将 trackDeletesStart() / trackDeletesEnd() 与仅获取变更的检查点(modified_after、updated_after、变更记录端点等)搭配使用。它们会遗漏未变更的记录,因此 trackDeletesEnd() 会将这些记录删除。
  • 带检查点的全量刷新仍是全量刷新。仅在完成整个全量窗口的那次运行中调用 trackDeletesEnd()。
约定
  • 字段大小写应与外部 API 一致。透传字段保留提供商的大小写;非透传字段应采用该 API 中占多数的大小写风格。
  • 优先使用明确的字段名称。
  • 为 ID、时间戳、枚举和 URL 添加 .describe() 示例。
  • 避免使用 any;改用内联映射类型。
  • 优先使用静态 Nango 端点路径(避免在公开的端点中使用 :id / {id});通过输入参数传递 ID。
  • 列表操作应公开 cursor 和下一游标字段,并采用该 API 中占多数的大小写风格(next_cursor、nextCursor 等)。
  • 仅在需要自定义验证或日志记录时使用 nango.zodValidateInput();否则依靠架构和 nango dryrun --validate。
架构语义
  • 非必填输入默认使用 .optional()。
  • 仅当 null 有实际含义时才使用 .nullable(),通常用于表示更新时清除字段;如果调用方也可能省略该字段,则添加 .optional()。
  • 原始提供商架构应与提供商保持一致:省略的字段使用 .optional(),显式的 null 使用 .nullable(),仅当提供商确实两种情况都有时才使用 .nullish()。
  • 最终操作输出和规范化同步模型应优先使用 .optional();除非 null 有实际意义,否则将上游的 null 规范化为省略。
  • 生成的架构默认对非必填输入和规范化输出使用 .optional();只有上游约定有依据时才放宽限制。
  • 优先使用 .nullable(),而不是 z.union([z.null(), T]) 或 z.union([T, z.null()])。
  • 仅当输出架构允许时才返回 null。
  • 默认情况下,z.object() 会剥离未知键。对于提供商透传数据,使用 z.object({}).passthrough()、z.record(z.unknown()) 或带最少精化的 z.unknown()。
字段命名和大小写规则
  • 使用符合 API 中占多数大小写风格的明确后缀:ID(user_id、userId)、名称(channel_name、channelName)、电子邮件(user_email、userEmail)、URL(callback_url、callbackUrl)和时间戳(created_at、createdAt)。

映射示例(API 使用了不同的参数名称):

const InputSchema = z.object({
    userId: z.string()
});

const config: ProxyConfiguration = {
    endpoint: 'users.info',
    params: {
        user: input.userId
    },
    retries: 3
};

如果 API 使用 snake_case,则改用 user_id。目标是保持 API 一致性。

Dryrun、模拟数据和测试(必需)

必需的循环(不要跳过步骤):

  1. 运行 nango dryrun ... --validate -e dev --no-interactive --auto-confirm,直到通过。
  2. Actions:始终传入 --input '{...}'(无输入的 action 使用 --input '{}')。
  3. Syncs:需要模拟恢复运行时,使用 --checkpoint '{...}'。
  4. 如果验证无法通过,请停止并说明所需但缺失的外部状态或输入。
  5. 验证通过后,运行 nango dryrun ... --save -e dev --no-interactive --auto-confirm,生成 <script-name>.test.json。
  6. 运行 nango generate:tests,然后运行 npm test。

硬性规则:

  • 将 <script-name>.test.json 视为生成的输出。绝不要创建、编辑、重命名或移动它(包括记录的 hash 字段)。
  • 如果模拟数据有误或已过时,请修复代码并使用 --save 重新记录。
  • 不要在 *.test.json 中硬编码错误负载;对于 404/401/429/超时情况,请使用带有 vi.spyOn(...) 的 Vitest 测试。
  • Connection ID 是第二个位置参数;不要使用 --connection-id。
  • 当多个 integration 中的脚本名称重叠时,使用 --integration-id <integration-id>。
  • 对于新的增量 sync,优先使用 --checkpoint;--lastSyncDate 是旧模式。
  • 如果 nango 不在 PATH 中,请使用 npx nango ...。
  • CLI 升级提示可能会阻塞自动化;必要时设置 NANGO_CLI_UPGRADE_MODE=ignore。

参考:https://nango.dev/docs/implementation-guides/platform/functions/testing

参考资料

  • Action 模式、CRUD 示例、元数据用法和 ActionError 示例:references/actions.md
  • Sync 模式、具体的 checkpoint 示例、删除策略和完整刷新回退方案:references/syncs.md

Nango 文档速查链接

部署(可选)

将 functions 部署到 Nango 账户中的环境:

nango deploy dev

# Deploy only one function
nango deploy --action <action-name> dev
nango deploy --sync <sync-name> dev

参考:https://nango.dev/docs/implementation-guides/use-cases/actions/implement-an-action

API 文档无法正常显示时

如果网页抓取返回的文档不完整(由 JS 渲染):

  • 请用户提供示例响应
  • 参考仓库中现有的 actions/syncs
  • 使用 --validate 运行 dryrun,直到通过;然后使用 --save 运行 dryrun,接着运行 nango generate:tests

最终检查清单

Action:

  • 已验证 Nango 根目录
  • 已参考 references/actions.md 中的 Action 模式
  • 架构和类型清晰,缺失值规则符合服务提供方与规范化契约
  • createAction() 在需要时包含端点、输入、输出和作用域
  • 字段使用透传大小写格式或 API 的主要大小写格式
  • 服务提供方调用包含 API 文档链接注释,并使用有明确意图的重试
  • 对预期失败使用 nango.ActionError
  • 已在 index.ts 中注册
  • Dryrun 使用 --validate -e dev --no-interactive --auto-confirm --input '{...}' 成功
  • 在运行 --validate 后,通过 nango dryrun ... --save 生成了 <action-name>.test.json
  • 已运行 nango generate:tests,且 npm test 通过

Sync:

  • 已验证 Nango 根目录
  • 已参考 references/syncs.md 中的 Sync 模式
  • 已定义模型映射,ID 为稳定字符串,规范化模型优先使用 .optional(),除非需要区分 null
  • 优先选择增量同步;除非文档或负载明确证明全量刷新合理,否则需使用检查点架构
  • 在开始时读取 nango.getCheckpoint(),并在每个页面或批次后运行 nango.saveCheckpoint()
  • 检查点数据会改变服务提供方请求或恢复状态(since、updated_after、cursor、page_token、offset、page、since_id 等)
  • 仅同步变更记录的检查点同步(modified_after、updated_after、变更记录端点)不使用 trackDeletesStart() / trackDeletesEnd()
  • 如果未使用检查点,响应会准确说明为何不存在可行的检查点策略
  • 原始服务提供方架构会正确建模字段省略与 null 的区别,字段使用透传大小写格式或 API 的主要大小写格式
  • 除非 API 确实无法适配 Nango 分页器,否则使用 nango.paginate()
  • 删除策略与同步类型相符:仅当服务提供方明确返回删除记录时,增量同步才使用 batchDelete();否则,全量刷新回退方案会在获取/保存前调用 trackDeletesStart(),且仅在成功完成全量获取并保存后调用 trackDeletesEnd()
  • 按需处理元数据
  • 已在 index.ts 中注册
  • Dryrun 使用 --validate -e dev --no-interactive --auto-confirm 成功
  • 在运行 --validate 后,通过 nango dryrun ... --save 生成了 <sync-name>.test.json
  • 已运行 nango generate:tests,且 npm test 通过

评论

支持 Markdown