EdgeOne Makers TypeScript SDK
面向 EdgeOne Makers 项目、环境变量、制品部署与租户 token 的 Node.js 20+ 仅 ESM 客户端。不支持浏览器运行时。
npm 包名:@edgeone/makers-sdk · 版本 0.2.0 · 合同 0.1.42 · MIT License
安装
npm install @edgeone/makers-sdk
import { Makers } from "@edgeone/makers-sdk";
Makers
构造
const makers = new Makers({
token: process.env.MAKERS_API_TOKEN,
region: "china",
});
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
token | string | 否 | — | EdgeOne Makers API Token。未传 credentials 时必填 |
region | "china" | "global" | 否 | API Token:自动探测;AK/SK:china | API Token:china → pages-api.cloud.tencent.com/v1;global → pages-api.edgeone.ai/v1;AK/SK 映射见下文 |
timeout | number | 否 | 30 | 单次请求超时,秒 |
retries | number | 否 | 3 | 查询类最大重试次数;写操作不重试 |
logger | Logger | 否 | — | 需实现 debug、info、warn、error |
credentials | { secretId, secretKey } | 否 | — | 腾讯云 API 凭证。传入后改走云 API 通道,并可调用归属校验、CNAME 与证书方法。两个字段都必须是非空字符串。不是 STS Token |
zoneId | string | 传 credentials 时必填 | — | Makers 站点 ID。传 credentials 时必填;未传 credentials 却传入时抛出 ValidationError |
自动探测先试 china 再试 global,结果按 Makers 实例缓存。只在 API Token 通道请求时探测。
云 API 凭证
const makers = new Makers({
credentials: {
secretId: process.env.TENCENTCLOUD_SECRET_ID!,
secretKey: process.env.TENCENTCLOUD_SECRET_KEY!,
},
zoneId: process.env.EDGEONE_MAKERS_ZONE_ID,
region: "global",
});
传入 credentials 与 zoneId 后,项目、环境变量、部署、自定义域名的创建、查询、删除,以及 tokens.create 走云 API 通道:向 https://teo.tencentcloudapi.com 调用 DescribePagesResources、CreatePagesResources、ModifyPagesResources 或 DeletePagesResources,请求体顶层带 Makers 站点 ZoneId。只传 token 时走 Pages API。两条通道的方法签名与返回结果相同,云 API 通道失败后不会改用 API Token 通道重试。
zoneId 是 Makers 站点 ID,SDK 不会自动查找。可以调用云 API DescribeZones 并按 zone-type=pages 过滤获取(开通 Makers 时会自动创建名为 default-pages-zone 的站点),或从 DescribePagesProjects 读取项目的 ZoneId。账号有多个 Makers 站点时,为每个站点各构造一个 Makers;项目相关调用必须使用项目所属的站点。
传入 credentials 与 zoneId 时,region: "china" 对应网关 X-TC-Region: ap-guangzhou,region: "global" 对应 ap-singapore;省略时默认广州,不探测 Pages 主机或其他 Region。同时传 token 时仍优先 AK/SK,失败后不切换通道或 Region,查询重试保持原 Region。项目 area 与客户端 region 独立。六个直接 teo 域名 / 证书方法仍不发送 X-TC-Region,主机与签名保持不变。
兼容性说明:此前 AK/SK 下显式 global 被忽略,现在会实际选择新加坡;省略 region 的行为不变。新加坡映射已通过协议回归测试,国际账号现网端到端验证仍待完成;Region 选择不保证账号权限或服务可用性。
项目、环境变量、部署、全部 domains 方法与 tokens.create 均支持只传云 API 凭证。云 API 凭证应留在平台侧,不要传给用租户 token 构造的 Makers。
公开成员
| 成员 | 类型 | 说明 |
|---|---|---|
makers.projects | Projects | 项目与环境变量操作 |
makers.deployments | Deployments | 部署操作 |
makers.tokens | Tokens | 签发租户 token(tokens.create) |
makers.domains | Domains | 自定义域名:创建、查询、删除、归属校验、CNAME 检查与证书 |
makers.region | Region | undefined | 只读;配置值或已探测到的值 |
Tokens
用主 API Token 或账号的云 API 凭证(credentials + zoneId)签发租户 token,再用返回的 token 构造新的 Makers 去管理该租户的项目。tokens.create 必填 tenantId、name、expiresIn,返回 { token, tokenId, expired }。
expiresIn 是相对秒,不是 unix 时间戳。返回的 expired 是后端过期时间(unix 秒)。
必须用主 API Token 或账号的云 API 凭证调用 tokens.create。传入 credentials 时调用 CreatePagesResources,Interface 为 pages:CreatePagesUserApiToken;只传 token 时走 Pages API。同一租户 ID 在两条通道上返回同一个租户 token。SDK 不会判断当前 token 是主 Token 还是租户 token,也不会拦截子 Token 再签发。v1 不提供 token 的 list、get 或 delete。
对同一 tenantId 再次调用 tokens.create 是幂等的:返回同一 token 与 tokenId,仅 expired 可能刷新。
tokens.create(options)
const platform = new Makers({
token: process.env.MAKERS_API_TOKEN,
});
const { token, tokenId, expired } = await platform.tokens.create({
tenantId: "user-open-id",
name: "user-open-id",
expiresIn: 86400,
});
const user = new Makers({ token });
const { projectId } = await user.projects.create({ name: "my-site" });
await user.deployments.deploy({
projectId,
artifact: { files: { "index.html": "<h1>Hello</h1>" } },
});
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
tenantId | string | 是 | 租户标识;非空,最长 64 |
name | string | 是 | Token 名称;1–128 个字符 |
expiresIn | number | 是 | 有效期,相对秒(整数 10–315360000),不是 unix 时间戳 |
返回 { token, tokenId, expired }。expired 是后端过期时间(unix 秒)。非法入参在发请求前抛 ValidationError。
Projects
projects.create(options)
创建项目。返回 { projectId },不含完整模型——需要名称、域名等信息须再调 get。
const { projectId } = await makers.projects.create({
name: "docs-site",
area: "overseas",
initialEnvVars: [{ key: "API_URL", value: "https://example.com" }],
});
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
name | string | 是 | 与账号内已有项目重名时,目前抛 MakersError,code 为 ResourceUnavailable |
area | "mainland" | "overseas" | "global" | 否 | 加速区域;不传则不发送 |
initialEnvVars | EnvVar[] | 否 | 建项目时同时设环境变量 |
projects.list(options?)
const page = await makers.projects.list({
name: "docs",
page: 0,
pageSize: 20,
order: { field: "createdOn", direction: "desc" },
});
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
projectIds | string[] | — | 按 ID 过滤 |
name | string | — | 按名称过滤 |
status | string | — | 按状态过滤 |
provider | string | — | 按 Provider 过滤 |
page | number | 0 | 从 0 开始 |
pageSize | number | 20 | 1–100 |
order | { field, direction } | — | field: "createdOn" 或 "modifiedOn";direction: "asc" 或 "desc" |
返回 Page<Project>:{ items, page, pageSize, total, hasNext }。
projects.listAll(options?)
for await (const project of makers.projects.listAll()) {
console.log(project.projectId, project.name);
}
与 list 同参数但无 page。返回 AsyncIterable<Project>。
projects.get({ projectId })
查询单个项目的完整模型。这是唯一能拿到 presetDomain(Production 域名)的地方。
const project = await makers.projects.get({ projectId });
console.log(project.presetDomain);
projects.update(options)
更新项目设置。只传入要改的字段,不传不清空。
await makers.projects.update({
projectId,
name: "new-name",
rootDir: ".",
outputDir: "dist",
buildCmd: "npm run build",
installCmd: "npm install",
framework: "other",
nodejsVersion: "20",
});
| 参数 | 类型 | 说明 |
|---|---|---|
projectId | string | 必填 |
name | string | 项目名称 |
rootDir | string | 根目录 |
outputDir | string | 输出目录 |
buildCmd | string | 构建命令 |
installCmd | string | 安装命令 |
framework | string | 框架标识 |
nodejsVersion | string | Node.js 版本 |
projects.delete({ projectId })
删除项目。不可恢复。
环境变量
方法位于 makers.projects。公开字段:key、value、可选 comment。改项目变量使用 setEnvs;deploy 不接受环境变量。
这些方法管理项目变量,不管理环境资源。不提供 env 或作用域选择:传入自定义部署 Slug 不会增加分环境变量能力。SDK 不公开环境资源的创建、查询、修改或删除方法。
projects.listEnvs({ projectId })
返回 EnvVar[]。值自动加入脱敏名单。
projects.setEnvs({ projectId, envVars })
批量 upsert。内部先读后写,非原子操作。重复 key 在发请求前抛 ValidationError。
await makers.projects.setEnvs({
projectId,
envVars: [
{ key: "API_URL", value: "https://example.com", comment: "origin" },
],
});
projects.deleteEnvs({ projectId, keys })
按 key 删除。重复 key 抛 ValidationError。每个 key 发送为 { Key, Value: "-" };Value 只是占位,不参与匹配。
Deployments
deployments.deploy(options)
部署制品。必须且只能传一种变体:
| 变体 | 类型 | 行为 |
|---|---|---|
files | Record<string, string | Uint8Array> | SDK 在内存中打 Zip |
directory | string(可选 excludePatterns: string[]) | SDK 打包目录 |
archive | string(Zip 路径) | 安全校验后直接上传 |
// 内联文件
await makers.deployments.deploy({
projectId,
artifact: { files: { "index.html": "<h1>ok</h1>" } },
wait: true,
});
// 应用源码(项目根)
await makers.deployments.deploy({
projectId,
artifact: { directory: "." },
wait: true,
});
// 静态构建输出
await makers.deployments.deploy({
projectId,
artifact: { directory: "./dist", excludePatterns: ["**/*.map"] },
});
// 预构建 CLI 产物
await makers.deployments.deploy({
projectId,
artifact: { directory: "./.edgeone" },
wait: true,
});
// Zip 文件
await makers.deployments.deploy({
projectId,
artifact: { archive: "./site.zip" },
});
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
projectId | string | — | 必填 |
artifact | Artifact | — | 必填;三种变体互斥 |
env | string | "Production" | 非空环境 Slug,例如 "Production"、"Preview" 或 "Staging"。Preview 要求已有 Production 部署 |
wait | boolean | false | 为 true 时轮询到终态 |
timeout | number | 900 | 最长等待时间(秒,15 分钟) |
pollInterval | number | 5 | 轮询间隔(秒) |
onUploadProgress | 回调 | — | 上传完成后触发一次 |
onStatusChange | 回调 | — | 每次状态变更触发 |
返回 Deployment。wait: false 时只有 deploymentId、projectId、env 三个字段,那不是可打开的站点链接。wait: true 到达 Success 后,previewUrl 是可打开链接,且会过期。
注意:此处 timeout 是整体等待预算(默认 900 秒),与 new Makers({ timeout: 30 }) 的单请求超时含义不同。
自定义环境:SDK 在两种认证通道上原样透传 env,不转换大小写,也不去除首尾空白。空字符串、纯空白和非字符串会在打包或请求之前抛出 ValidationError。只有精确的 "Preview" 会执行已有生产部署的前置检查。自定义环境应提前创建;deploy 不会创建或检查环境资源,后端错误仍按 SDK 原有规则处理。公开接口文档目前只列出 Production / Preview;自定义 Slug 透传属于 SDK 扩展,不保证后端支持、环境隔离或页面可访问。
// Staging must already exist. This does not create an environment or set variables.
const deployment = await makers.deployments.deploy({
projectId,
env: "Staging",
artifact: { files: { "index.html": "<h1>Staging</h1>" } },
});
目录输入:传入一个目录。常见输入是应用源码(项目根)、静态构建输出(该目录根上必须有 index.html),或预构建的 Makers/SSR 产物(本地 CLI build 后传 ./.edgeone)。应用源码是 SDK 的常规路径:SDK 按默认忽略规则打包上传,不在本地编译,也不会自己执行 npm run build 或 edgeone makers build。Upload 项目上传后,Pages 后端可能会跑 edgeone makers build。SDK 不会跑框架适配器。默认忽略是固定名单,不读 .gitignore。调用者提供的 archive 原样上传。
目录安全:拒绝符号链接;自动忽略 .git、node_modules、artifact 根下的 .edgeone 目录、.env、日志、临时文件和系统文件。非 .edgeone directory 还会忽略任一以 . 开头的路径段;.well-known 会保留。更深路径中的 .edgeone 会保留。传入名为 .edgeone 的目录时按 CLI 布局打包(<父目录名>/.edgeone/...,上一级有 edgeone.json 则一并打入),并保留嵌套 node_modules 与隐藏文件。其它 directory 仍在任意深度丢掉 node_modules。默认忽略是固定名单,不是读 .gitignore。excludePatterns 追加 POSIX glob,不支持取反 (!)。
deployments.wait(options)
轮询至终态:Success、Failed、Timeout、Cancelled、Invalid。到达 Success 后,previewUrl 是可打开站点 URL(默认上传项目会签名),且会过期。get / list / wait: false 不会签名。
const result = await makers.deployments.wait({
projectId,
deploymentId,
timeout: 900,
pollInterval: 5,
onStatusChange: (event) => console.log(event.deployment.status),
});
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
projectId | string | — | 必填 |
deploymentId | string | — | 必填 |
timeout | number | 900 | 超时抛 DeploymentTimeoutError;不会取消线上部署 |
pollInterval | number | 5 | |
onStatusChange | 回调 | — |
deployments.list(options)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
projectId | string | — | 必填 |
status | string[] | — | 按状态过滤 |
timeRange | { start, end } | — | ISO 8601 |
repoBranch | string[] | — | 按分支过滤 |
page | number | 0 | |
pageSize | number | 20 | |
order | { field, direction } | — |
deployments.listAll(options)
与 list 同参数但无 page。返回 AsyncIterable<Deployment>。
deployments.get({ projectId, deploymentId })
查询单个部署。不存在时抛 NotFoundError。
deployments.getLog({ projectId, deploymentId })
返回 { logUrl } —— 构建日志地址。
自定义域名
自定义域名的创建、查询、删除按 Makers 的通道调用。传入 credentials 时走云 API 通道:创建为 CreatePagesResources,Interface 为 pages:CreatePagesZoneCustomDomain;查询为 DescribePagesResources,Interface 为 pages:DescribePagesZoneCustomDomains;删除为 DeletePagesResources,Interface 为 pages:DeletePagesProjectCustomDomains。只传 token 时走 Pages API。两条通道的参数与返回结果相同。归属校验、CNAME 检查、免费证书的申请和检查,以及证书查询与下发是直接 teo Action,始终需要 credentials。
credentials 可选。传入时 secretId 与 secretKey 都必须是非空字符串,并且必须提供 zoneId,否则构造时抛出 ValidationError。凭证对象不接受 STS Token,云 API 请求也不发送 X-TC-Token。未传凭证时,verifyOwnership、checkCname、applyFreeCertificate、checkFreeCertificate、listHostCertificates 与 modifyCertificate 在发请求前抛出 ValidationError。
checkCname、applyFreeCertificate、checkFreeCertificate、listHostCertificates 与 modifyCertificate 的 zoneId 可选。未传或为 null 时,把构造时的 zoneId 作为 ZoneId 发送;传入时发送调用值,用于项目属于其他 Makers 站点的域名。该站点是域名所属项目的 Makers 站点。
projectId、domain、domains、zoneId、recordNames 或 hosts 为空时,在发请求前抛出 ValidationError。list、verifyOwnership、checkCname、checkFreeCertificate 与 listHostCertificates 按查询重试。create、delete、applyFreeCertificate 与 modifyCertificate 不重试。
domains.create({ projectId, domain })
调用 CreatePagesZoneCustomDomain。只返回 { domain, id }。id 取响应 Id;Id 缺失或不是字符串时为 null。Domain 缺失或不是字符串时抛出 MakersError。空字符串仍作为 domain 返回。不返回查询字段,也不会为补齐字段再发请求。
domains.list({ projectId, domain? })
调用 DescribePagesZoneCustomDomains。projectId 必填。domain 可选,只有传入时才发送 Domain。返回 PagesDomains 数组。每一行含 type、domain、forceRedirectHttps、redirectStatusCode、currentCname、mainDomain、status、ownershipVerification、cname、area、zoneId。传入 domain 时只保留该域名的行。业务参数不带 ZoneId;云 API 通道由四大接口在请求体顶层带上 Makers 站点 ZoneId。字符串在值为 null、缺失或不是字符串时为 null,空字符串保持空字符串。redirectStatusCode 在缺失、null 或不是有限数字时为 null,数字 0 保持 0。响应含 ForceRedirect 对象时,forceRedirectHttps 取 Switch,redirectStatusCode 取 RedirectStatusCode,不再读取平铺的 ForceRedirectHTTPS 与 RedirectStatusCode。没有该对象时仍读取平铺字段。校验子对象为 null 时保持 null;子对象存在时,其中的字符串按同样的空值规则。没有 PagesDomains、但顶层有 Domain 字符串时,视为一行。
domains.delete({ projectId, domains })
调用 DeletePagesProjectCustomDomains。domains 至少包含一个非空域名,以 CustomDomains 发送。成功时没有业务字段。
domains.verifyOwnership({ domain })
调用 VerifyOwnership,发往 https://teo.tencentcloudapi.com(服务 teo,版本 2022-09-01)。请求体只有 { Domain }。不发送 X-TC-Region 或 X-TC-Token。region: "global" 仍使用这个主机。
返回 { status, message }。status 为 success 或 fail,校验没通过也是业务结果。message 优先取 Message,没有则取 Result;成功时可以为空。结果不含 requestId。
HTTP 200 且响应含 Response.Error,以及非 2xx,都会抛错。AuthFailure 开头为 AuthError,包含 Invalid 为 ValidationError,包含 NotFound 为 NotFoundError,RequestLimitExceeded 为 RateLimitError,其余为 MakersError。requestId 只出现在异常上。
domains.checkCname({ zoneId?, recordNames })
调用 CheckCnameStatus,发往 https://teo.tencentcloudapi.com(服务 teo,版本 2022-09-01)。请求体为 { ZoneId, RecordNames }。recordNames 至少包含一个非空域名。不发送 X-TC-Region 或 X-TC-Token。region: "global" 仍使用这个主机。
返回 { cnameStatus }。每一项为 { recordName, cname, status }。status 按后端原值返回,不改写。active、moved、invalid 保持原样。结果不含 requestId。云 API 失败与 verifyOwnership 使用同一套错误映射。
domains.applyFreeCertificate({ zoneId?, domain, verificationMethod })
调用 ApplyFreeCertificate,发往 https://teo.tencentcloudapi.com(服务 teo,版本 2022-09-01)。请求体为 { ZoneId, Domain, VerificationMethod }。verificationMethod 只能是 dns_challenge 或 http_challenge,其他值在发请求前抛出 ValidationError。不发送 X-TC-Region 或 X-TC-Token。region: "global" 仍使用这个主机。该方法不重试。
返回 { dnsVerification, fileVerification }。字段与查询自定义域名时的 DNS、文件校验子对象相同。缺哪一个,该字段就为 null。结果不含 requestId。
domains.checkFreeCertificate({ zoneId?, domain })
调用 CheckFreeCertificateVerification,发往 https://teo.tencentcloudapi.com(服务 teo,版本 2022-09-01)。请求体为 { ZoneId, Domain }。不发送 X-TC-Region 或 X-TC-Token。region: "global" 仍使用这个主机。该方法按查询重试。
返回 { commonName, expireTime, signatureAlgorithm }。expireTime 保持后端字符串。结果不含 requestId。OperationDenied.FreeCertificateVerificationIsEmpty 抛出 MakersError。其他云 API 失败与 verifyOwnership 使用同一套错误映射。
domains.listHostCertificates(options?)
调用 DescribeHostCertificates,发往 https://teo.tencentcloudapi.com(服务 teo,版本 2022-09-01)。options 为 { zoneId?, filters? },可以省略。请求体为 { ZoneId },传入 filters 时再带 Filters。每一项为 { name, values },发送为 { Name, Values }。只有调用方传入 fuzzy 时才发送 Fuzzy。该方法用 Offset 与 Limit 100 读取全部分页并返回所有行,不接受 page 或 offset。不发送 X-TC-Region 或 X-TC-Token。region: "global" 仍使用这个主机。该方法按查询重试。
返回 { certificates, totalCount }。每个证书为 { host, mode, hostCertInfo }。hostCertInfo 的每一项为 { alias, certId, deployTime, expireTime, signAlgo, status, type }。mode 按后端原值返回,disable 不会改写成 disabled。不返回 ClientCertInfo 与 UpstreamCertInfo。结果不含 requestId。
domains.modifyCertificate({ zoneId?, hosts, mode })
调用 ModifyHostsCertificate,发往 https://teo.tencentcloudapi.com(服务 teo,版本 2022-09-01)。请求体为 { ZoneId, Hosts, Mode }。hosts 至少包含一个非空域名。mode 只能是 disable、eofreecert 或 eofreecert_manual,其他值在发请求前抛出 ValidationError。不发送 ServerCertInfo、X-TC-Region 或 X-TC-Token。region: "global" 仍使用这个主机。该方法不重试。
成功时没有业务字段。
数据模型
Project
| 字段 | 类型 | 必有 | 说明 |
|---|---|---|---|
projectId | string | 是 | |
name | string | 是 | 同一账号下唯一 |
status | string | 是 | |
area | ProjectArea | 否 | "mainland" / "overseas" / "global" |
presetDomain | string | 否 | Production 域名;刚建的项目可能还没分配 |
createdOn | string | 是 | ISO 8601 |
modifiedOn | string | 是 | ISO 8601 |
Deployment
| 字段 | 类型 | 必有 | 说明 |
|---|---|---|---|
deploymentId | string | 是 | |
projectId | string | 是 | |
env | string | 是 | 后端返回的环境 Slug,原样保留 |
status | string | 否 | 终态:Success / Failed / Timeout / Cancelled / Invalid |
previewUrl | string | 否 | wait Success 后为可打开站点 URL(会过期)。get / wait: false 可能仍是后端原始 URL,不可直接打开。 |
code | number | 否 | 构建退出码,0 表示成功 |
createdOn | string | 否 | wait: false 时不返回 |
modifiedOn | string | 否 | wait: false 时不返回 |
Token
| 字段 | 类型 | 必有 | 说明 |
|---|---|---|---|
token | string | 是 | 租户 API token;用来构造用户侧 Makers |
tokenId | string | 是 | Token 标识 |
expired | number | 是 | 后端过期时间(unix 秒) |
EnvVar
| 字段 | 类型 | 必有 |
|---|---|---|
key | string | 是 |
value | string | 是 |
comment | string | 否 |
回调
UploadProgressEvent:{ uploadedBytes, totalBytes, completedFiles, totalFiles }
StatusChangeEvent:{ deployment: Deployment, previousStatus: string | null }
错误处理
所有错误继承 MakersError,公开字段:code、message、requestId、httpStatus、cause。
| 异常类 | 触发条件 |
|---|---|
AuthError | Code 105 或 HTTP 401 |
ValidationError | Code 含 "Invalid" 或 HTTP 400 |
NotFoundError | Code 含 "NotFound" 或 HTTP 404 |
ConflictError | Code 含 "Conflict" 或 HTTP 409 |
RateLimitError | Code 110 或 HTTP 429 |
UploadError | COS 上传失败 |
TimeoutError | 请求超时 |
DeploymentTimeoutError | 等待部署终态超时(继承 TimeoutError) |
import { MakersError, NotFoundError, DeploymentTimeoutError } from "@edgeone/makers-sdk";
try {
await makers.projects.get({ projectId: "missing" });
} catch (error) {
if (error instanceof NotFoundError) {
console.error(error.code, error.requestId, error.httpStatus);
}
}
重试策略
查询类请求遇到网络错误、HTTP 408/429/5xx 或外层 Code: 110 时最多重试 retries 次(默认 3)。退避策略为全抖动指数退避、上限 10 秒,优先读 Retry-After 头。创建、更新和 COS 凭证请求不重试。
开发
npm install
npm run build
npm test