关于 nango-function-builder
用于构建和验证可部署的 Nango TypeScript actions 与 syncs。它要求检查项目结构,为 sync 明确增量检查点和删除策略,并在部署前执行 dryrun 与测试。
主要功能
- 01构建 Nango actions 和 syncs
- 02要求为 sync 规划检查点与删除策略
- 03检查 TypeScript 项目结构及注册方式
- 04使用 Nango dryrun 验证函数
- 05在部署前生成并运行测试
适用场景
- 01为服务商 API 请求创建 action
- 02构建定时或 webhook 驱动的 sync
- 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
工作流(推荐)
- 确定这是操作还是同步。
- 阅读相应的参考文件:
references/actions.md或references/syncs.md。 - 对于同步,检查提供方文档或载荷中的检查点和删除信息,确定端点返回的是完整数据还是变更的行,并完成同步策略门槛。
- 收集所需输入和外部值。对于连接查找、凭据或发现,请使用 Nango HTTP API。
- 确认这是 Zero YAML TypeScript 项目(
no nango.yaml),并且你位于 Nango 根目录(存在.nango/)。 - 在
{integrationId}/actions/或{integrationId}/syncs/下创建或更新函数,应用此处的架构和大小写规则,然后在index.ts中注册。 - 使用
nango dryrun ... --validate -e dev --no-interactive --auto-confirm验证。 - 如果验证无法通过,请停止并报告缺失的外部状态或输入。
- 验证通过后,运行
nango dryrun ... --save,然后运行nango generate:tests,再运行npm test。 - 仅在收到请求时,使用
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、模拟数据和测试(必需)
必需的循环(不要跳过步骤):
- 运行
nango dryrun ... --validate -e dev --no-interactive --auto-confirm,直到通过。 - Actions:始终传入
--input '{...}'(无输入的 action 使用--input '{}')。 - Syncs:需要模拟恢复运行时,使用
--checkpoint '{...}'。 - 如果验证无法通过,请停止并说明所需但缺失的外部状态或输入。
- 验证通过后,运行
nango dryrun ... --save -e dev --no-interactive --auto-confirm,生成<script-name>.test.json。 - 运行
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 运行时 SDK 参考:https://nango.dev/docs/reference/functions
- 实现 action:https://nango.dev/docs/implementation-guides/use-cases/actions/implement-an-action
- 实现 sync:https://nango.dev/docs/implementation-guides/use-cases/syncs/implement-a-sync
- Checkpoint:https://nango.dev/docs/implementation-guides/use-cases/syncs/checkpoints
- 删除检测(完整与增量):https://nango.dev/docs/implementation-guides/use-cases/syncs/deletion-detection
- 测试集成(dryrun、--save、Vitest):https://nango.dev/docs/implementation-guides/platform/functions/testing
- Nango HTTP API 参考:https://nango.dev/docs/reference/api
部署(可选)
将 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通过