@xd-cell/worker-sdk
v0.2.0
Published
`@xd-cell/worker-sdk` 是 XD Cell 面向业务自定义 Worker 的 runtime SDK。它的目标是在 Worker 运行时提供一层足够薄、接近 Cloudflare API 心智的资源抽象,而不是把底层 KV、D1、R2、service binding、内部 gateway path 或 capability 格式直接暴露给业务。
Downloads
328
Readme
@xd-cell/worker-sdk
@xd-cell/worker-sdk 是 XD Cell 面向业务自定义 Worker 的 runtime SDK。它的目标是在 Worker 运行时提供一层足够薄、接近 Cloudflare API 心智的资源抽象,而不是把底层 KV、D1、R2、service binding、内部 gateway path 或 capability 格式直接暴露给业务。
业务代码应该面向本 SDK 的 runtime 资源编程。这样平台未来从 Cloudflare Workers 演进到其它 Worker-compatible 基础设施时,可以优先在 SDK 内适配,尽量减少业务 Worker 感知。
设计目标
- 保持 Cloudflare Worker 开发者熟悉的资源心智,例如
env.MY_KV.get()对应runtime.kv.get()。 - 对业务隐藏底层资源绑定、gateway、capability、内部 header、JWT 和 provider 资源 ID。
- 让 SDK 成为业务 Worker 与 XD Cell runtime 能力之间的稳定边界。
- 当前提供 KV、当前用户和办公网访问能力;D1、R2 等资源在 API 稳定前只作为规划方向,不提前暴露空 API。
- 只使用 Worker-compatible Web API,不依赖 Node.js、DOM、localStorage 或浏览器全局对象。
当前状态
本目录是独立 npm 包 @xd-cell/worker-sdk 的源码目录。Worker SDK 的 README、package.json、类型声明、docs/llms/* 和 BREAKING_CHANGES.md 随包发布,是业务 Worker 和 AI agent 理解 SDK 能力的真相源;源码和测试是仓库内校验真相源,不随 npm 包发布。
xd-cell skill / @xd-cell/skill 暂时仍是 XD Cell 发布与管理入口。skill 不复制 Worker SDK 领域产物,也不手写维护 SDK API 细节。agent 需要接入自定义 Worker 时,应让用户项目显式安装 @xd-cell/worker-sdk,再读取安装包内的 AI 文档和类型声明。
安装与导入
业务自定义 Worker 直接安装:
pnpm add @xd-cell/worker-sdkimport { createRuntime, getCurrentUser, readContext } from '@xd-cell/worker-sdk';如果 npm 包尚不可安装,不应从 skill 产物中寻找内置 SDK 副本;应暂停接入、使用用户项目已有实现,或在本 monorepo 内继续开发 apps/worker-sdk。
构建与发布流程
本包把构建、AI 文档生成和发布前校验拆开维护:
pnpm --dir apps/worker-sdk run build
pnpm --dir apps/worker-sdk run docs:llms
pnpm --dir apps/worker-sdk run pack:check
cd apps/worker-sdk && npm pack --dry-runbuild只生成dist。docs:llms只基于已存在的dist、README、package.json和BREAKING_CHANGES.md生成 AI 文档。pack:prepare执行build和docs:llms,并由prepack自动调用。pack:check执行build、docs:llms:check和pack:surface,用于 CI 或人工发布前确认文档未漂移,且 npm tarball 包含exports指向的运行时代码和类型声明。
核心用法
自定义 Worker 先创建 runtime,再像使用 Cloudflare 资源一样访问 SDK 暴露的资源对象:
import { createRuntime, getCurrentUser, readContext } from '@xd-cell/worker-sdk';
export default {
async fetch(request, env) {
const runtime = createRuntime({ request, env });
const context = readContext(request);
const user = getCurrentUser(request);
const message = await runtime.kv.get('app/message');
const config = await runtime.kv.get('app/config', { type: 'json' });
await runtime.kv.put('app/last-request', { traceId: context?.traceId ?? null }, { type: 'json' });
return Response.json({ config, message, user, traceId: context?.traceId ?? null });
},
};createRuntime({ request, env }) 返回业务 Worker 可用的资源集合。
readContext(request) 读取 router 注入的最小身份上下文,包括用户、站点、版本和 trace 信息。它不会暴露原始内部 JWT,也不是 data/KV 授权凭证。
getCurrentUser(request) 返回当前请求对应的已登录用户;匿名请求返回 null。用户字段用于业务展示和个性化,不能替代 router 的访问控制结论。
当前用户站点统一受平台 IP Check 保护。对于通过站点访问策略的已登录请求,router 默认提供 email、accountId、name、departments 和 employeeStatus;未来开放 public 站点前需要重新评估身份披露边界。
资源模型
当前公开资源:
runtime.kv:默认 KV namespace,适合配置、站点状态和跨请求共享数据。runtime.officeNet:平台授予的办公网访问能力,保留原生fetch请求和响应心智。
runtime.kv 的心智对齐 Cloudflare 的 env.MY_KV binding。业务代码不需要理解底层 site/user data scope,也不应该直接处理 capability。
规划资源:
runtime.d1:计划面向 D1 类 SQL 数据能力提供薄封装,但当前未公开。runtime.r2:计划面向 R2 类对象存储能力提供薄封装,但当前未公开。
D1/R2 公开前必须先明确资源命名、授权模型、类型声明、错误语义、README 示例、AI 文档和 BREAKING_CHANGES.md。
当前用户
自定义 Worker 可以读取 router 为当前请求注入的用户信息:
const user = getCurrentUser(request);
if (!user) {
return Response.json({ authenticated: false });
}
return Response.json({
authenticated: true,
user: {
id: user.id,
email: user.email,
accountId: user.accountId,
name: user.name,
departments: user.departments,
employeeStatus: user.employeeStatus,
},
});id是平台稳定用户 ID,不等同于可变邮箱或外部帐号 ID。accountId在旧登录态或身份源没有提供时可能为null。name来源于 SSOrealname;旧登录态或身份源没有提供时可能为null。departments只包含完整部门路径,例如心动/技术平台部/前端组;不包含原始 department ID。departments和employeeStatus是请求时业务上下文,不能由 Worker 用来替代平台 ACL、owner 或员工状态门禁。- 不要把用户资料、原始请求 header、cookie 或 session 写入日志。
办公网访问
只有平台已授予办公网能力的自定义 Worker 才能使用:
const response = await runtime.officeNet.fetch('https://internal.example.test/health');
if (!response.ok) {
const errorBody = response.status === 501 ? await response.clone().json().catch(() => null) : null;
if (errorBody?.error?.code === 'OFFICE_NET_UNAVAILABLE') {
return Response.json({ error: 'OFFICE_NET_UNAVAILABLE' }, { status: 501 });
}
return Response.json({ error: 'OFFICE_NET_REQUEST_FAILED' }, { status: response.status });
}runtime.officeNet.fetch() 原样接受 Request | string 和 RequestInit。能力存在时,runtime.officeNet 直接使用平台提供的原生 fetcher;SDK 不自动添加业务认证 header,不提供公网 fallback,也不把它当作通用代理。
能力未绑定时不会抛出缺少 binding 的异常,而是返回 status 为 501 的标准 Response,body 中的错误码为 OFFICE_NET_UNAVAILABLE。业务代码必须检查 response.ok,并且只有 status 和错误码同时匹配时才提示当前站点不支持办公网访问;内部 API 自身返回的其它 501 仍按普通请求失败处理。网络请求自身保留原生 fetch 的异常语义。
KV API
KV API 当前提供接近 Cloudflare KV 的最小子集:
const textValue = await runtime.kv.get('app/message');
const jsonValue = await runtime.kv.get('app/config', { type: 'json' });
await runtime.kv.put('app/message', 'hello', { expirationTtl: 60 });
await runtime.kv.put('app/config', { enabled: true }, { type: 'json', metadata: { owner: 'docs' } });
const configWithMetadata = await runtime.kv.getWithMetadata('app/config', { type: 'json' });
const appKeys = await runtime.kv.list({ prefix: 'app/' });
await runtime.kv.delete('app/message');当前差异:
get()默认按 text 读取,返回string | null,对齐 Cloudflare KV。put()默认按 text 写入,写 JSON 必须显式传入{ type: 'json' }。get(key, { type: 'json' })是 SDK 提供的 JSON convenience,返回解析后的对象或null。getWithMetadata()支持单 key 的 text / JSON 读取,返回{ value, metadata };metadata 只包含业务写入的用户 metadata,不包含平台内部字段。list()支持{ prefix, limit, cursor },返回 Cloudflare KV 风格的{ keys, list_complete, cursor };runtime.kv的 list 只枚举当前站点级 namespace。put()支持expirationTtl、expiration和metadata;expiration与expirationTtl不能同时使用,metadata 必须是 JSON 可序列化对象。- 当前不公开 bulk
get(keys)、bulkgetWithMetadata(keys)、cacheTtl、arrayBuffer和stream。这些能力需要额外的 gateway 协议、payload 限制和二进制/流式传输语义,后续单独评估。 - SDK 内部通过受控 gateway 和 capability 调用资源,业务代码不直接拿底层 KV binding。
运行时边界
- Runtime 服务绑定和 capability 必须来自 Worker bindings、secrets 或 router 注入的单请求 header。
- 平台 data/KV API 必须通过 Worker binding 提供的受控 gateway 调用。
runtime.kv表示默认 KV namespace;底层 scope 由平台决定,不作为业务 API 心智暴露。- 当前受 IP Check 保护的自定义 Worker 由平台部署流程授予
runtime.officeNet;未来 public 站点不授予该能力。业务 Worker 不能自行声明或创建能力,并且必须处理501+OFFICE_NET_UNAVAILABLE不支持响应。 - Worker 代码不能信任浏览器传入的平台相关 header;只读取 router 注入的上下文。
- 底层基础设施可以从 Cloudflare Workers 演进为其它 Worker-compatible runtime;业务代码应只依赖本包公开 API。
非目标
本包不承载:
- Browser SDK 或浏览器端 KV helper;
- runtime adapter、inline runtime source 或平台内部 Worker 生成模板;
xd-cellCLI、登录、发布、回滚或访问策略管理;- 公开 OpenAPI client;
- 直接暴露内部 JWT、capability、Cloudflare 资源 ID、namespace ID、bucket 名、database ID 或平台 secret;
- 未实现的 D1/R2 空壳 API;
- 用户级存储的独立公开资源模型。
- 通用网络代理、内网探测或浏览器端办公网访问能力。
Browser helper、runtime adapter、inline runtime source 和 user-scoped storage 不属于当前 Worker SDK 公共面。后续如果恢复为公开能力,应先单独评估包名、导出路径、README、类型声明、测试、兼容承诺和 BREAKING_CHANGES.md。
安全约束
- 不要把 capability、CLI token、发布 token、cookie、session 或 secret 写入源码、配置、日志、文档、截图或聊天内容。
- 不要绕过 SDK 直接调用内部 gateway path。
- 不要把
readContext(request)的结果当作 data/KV 授权凭证。 - 不要把
getCurrentUser(request)返回的部门或员工状态当作平台授权结论。 - 不要使用
runtime.officeNet创建通用代理,也不要在收到501+OFFICE_NET_UNAVAILABLE不支持响应时 fallback 到全局fetch。 - 不要把底层 Cloudflare binding、namespace ID、D1 database ID、R2 bucket 名写入业务代码作为公共契约。
迁移方向
新自定义 Worker 使用:
import { createRuntime, getCurrentUser, readContext } from '@xd-cell/worker-sdk';当前 public API 提供 KV、当前用户、请求上下文和办公网访问能力。旧草案中的品牌化 runtime 函数、data 入口、scope-specific KV 入口和 set() alias 不进入公共面。
每次发布前必须确认:
- 稳定的根导出、README、TypeScript 类型声明和测试已与源码同步;
BREAKING_CHANGES.md已说明当前包名、导入路径、公开 API、runtime 语义和安全边界是否变化;docs/llms/*已由包真相源重新生成并通过 drift check;- 从旧本地 helper 或旧 SDK 草案迁移到
@xd-cell/worker-sdkimport 的说明仍然准确; - 与
xd-cellskill release manifest 对齐的推荐版本和兼容关系仍然准确。
