
Alchemy v2.0.0-beta.56 深度解析230 个 Cloudflare 资源、unsafe nuke 与 S3 状态存储【免费下载链接】t3code项目地址: https://gitcode.com/GitHub_Trending/t3/t3code本文基于 alchemyInfrastructure-as-Effectsv2.0.0-beta.56 版本发布说明展开核心讲解该版本将 Cloudflare 提供商从 22 个资源扩展到 230 个的实现路径、Provider.list生命周期操作与alchemy unsafe nuke命令、GitHub.events事件源、以及 S3 后端状态存储等关键能力。读完本文你将掌握如何用一个 Effect 程序描述完整的 Zero Trust 部署、如何用测试驱动的方式批量生成云端资源、如何在 Worker 中订阅 GitHub 事件并校验签名以及如何为 AWS 栈配置远程状态后端。版本概览一次跨越 542 个文件的 Cloudflare 资源扩张v2.0.0-beta.56 是 alchemy 的一次里程碑式发布Cloudflare 提供商覆盖的资源类型从22 个跃升至 230 个。这一轮扩张由单个 PR 落地累计约 10.1 万行代码、横跨 542 个文件并新增了189 个 live-test 测试套件——每个套件都针对真实 Cloudflare 账户运行。最终覆盖超过一百个 Cloudflare 服务包括Zero Trust 全家桶Access、Tunnels、Devices、Gateway、DLP网络与流量Magic Transit、Magic Network Monitoring、Load Balancing、SpectrumDNS 与安全DNS、DNS Firewall、SSL/TLS 与证书、API Shield、Bot Management、Page Shield、Turnstile边缘计算Workers for Platforms、Snippets、Zaraz、Waiting Rooms、Logpush其他长尾服务Registrar、Addressing、Alerting 等从仓库源码结构看这一扩张在 Cloudflare 目录 中体现得尤为直观Access/、Tunnel/、Devices/、Gateway/、Dlp/、MagicTransit/、MagicNetworkMonitoring/、LoadBalancer/、WaitingRoom/、Logpush/、Spectrum/、Turnstile/、ApiShield/、BotManagement/、PageShield/、WorkersForPlatforms/、Snippets/、Zaraz/、Registrar/、Alerting/等子目录均已落地为独立资源模块每个子目录内的.ts文件即对应一个个可声明、可计划、可部署的资源类型。用一段 Effect 代码部署完整 Zero Trust 网络资源类型覆盖的意义不止于数量。它意味着一个完整的 Zero Trust 部署——隧道、私有网络路由、身份门控的应用、WARP 设备配置——现在只需要一个 Effect 程序。Zero Trust 资源由 Andy Jefferson 在贡献 PR 中完成// 一个仅能通过 WARP Access 访问的私有网络 const tunnel yield* Cloudflare.Tunnel(Corp, { ingress: [ { hostname: dashboard.example.com, service: http://localhost:3000 }, { service: http_status:404 }, ], }); yield* Cloudflare.TunnelRoute(PrivateNet, { tunnelId: tunnel.tunnelId, network: 10.4.0.0/16, }); const allowCorp yield* Cloudflare.AccessPolicy(AllowCorp, { name: Allow corp users, decision: allow, include: [{ emailDomain: { domain: example.com } }], }); yield* Cloudflare.AccessApplication(Dashboard, { type: self_hosted, domain: dashboard.example.com, sessionDuration: 24h, policies: [allowCorp.policyId], }); yield* Cloudflare.DeviceDefaultProfile(Default, { mode: exclude, splitTunnelExclude: [{ address: 10.0.0.0/8, description: RFC1918 }], excludeOfficeIps: true, });这段代码的要点Cloudflare.Tunnel声明隧道及其 ingress 规则dashboard.example.com转发到本机 3000 端口其余请求返回 HTTP 404Cloudflare.TunnelRoute把10.4.0.0/16私有网段路由进隧道Cloudflare.AccessPolicy定义仅允许 example.com 域邮箱用户的访问策略返回的policyId直接注入AccessApplicationCloudflare.DeviceDefaultProfile配置 WARP 设备默认配置文件将 RFC1918 私网段10.0.0.0/8排除在隧道之外并开启excludeOfficeIps。资源之间通过tunnel.tunnelId、allowCorp.policyId等输出属性互相引用形成依赖图。这正是 alchemy基础设施即 Effect的核心体验没有 YAML没有第二个运行时基础设施声明与业务逻辑同处一个类型安全的 Effect 程序里见 README。实现路径测试驱动的 SDK 飞轮230 个资源不是手工一行行写的。发布说明揭示了背后的方法论资源由 AI Agent 集群按服务逐个实现每个 Agent 针对 distilled——alchemy 自研的生成式 Cloudflare SDK——工作。每个 Agent 先实现一个服务的资源然后对真实 API 做 live-test当测试撞上类型没有覆盖的 API 行为时修复被写进 SDK成为类型化错误补丁typed-error patch而不是在消费端加一个 catch 块// distilled/packages/cloudflare/patches/turnstile/getWidget.json { errors: { WidgetNotFound: [{ code: 10404 }, { code: 10407 }], Forbidden: [{ status: 403 }] } }这个补丁文件的含义当 Turnstile 的getWidget接口返回错误码10404或10407时SDK 应将其识别为类型化的WidgetNotFound错误返回 HTTP 403 时识别为Forbidden。这样一来API 的真实行为就以类型的形式被记录下来惠及 SDK 的每一个未来消费者——错误处理是编译期可见的 Effect 错误而非运行时猜测。把这个循环跑在 288 个 live-test 套件上效果显著SDK 的补丁集从一个发布周期内的369 个增长到 1,087 个操作覆盖 Cloudflare 114 个服务中的 94 个。每个补丁都是一条API 实际如何表现的类型化记录。这个循环的完整故事——闭环、补丁以及驱动它们的工厂——记录在 Looping the Generation of IaC and SDKs 一文中感兴趣的读者可以继续深入。Feature FlagsCloudflare.FlagshipAppCloudflare 的 Flagship 特性开关feature flag服务在本版本以完整资源形态落地并附带了 Effect 原生的 Worker 绑定。声明应用及其开关const app yield* Cloudflare.FlagshipApp(Flags, {}); yield* Cloudflare.FlagshipFlag(NewCheckout, { appId: app.appId, key: new-checkout, defaultVariation: off, variations: { off: false, on: true }, });从 App.ts 源码 可以看到资源实现细节AppProps仅含可选的name字段省略时按${app}-${stage}-${id}生成唯一名称AppAttributes返回服务端生成的appId——它跨更新保持稳定作为 flag、Worker 绑定以及所有求值调用的作用域标识此外还有accountId、createdAt、updatedAt、updatedBy等元数据应用名称可原地修改但appId一旦生成永不变更。FlagshipApp.bind(app)把绑定挂到外围 Worker 上并返回一个运行时客户端用于求值export const App Cloudflare.FlagshipApp(Flags, {}); export default Cloudflare.Worker( FlagsWorker, { main: import.meta.filename }, Effect.gen(function* () { const flags yield* Cloudflare.FlagshipApp.bind(App); return { fetch: Effect.gen(function* () { const enabled yield* flags.getBooleanValue(new-checkout, false, { userId: user-42, }); return HttpServerResponse.text(enabled ? on : off); }), }; }).pipe(Effect.provide(Cloudflare.FlagshipBindingLive)), );关键设计运行时Flagship绑定的每一个方法都被镜像为 Effect源码中ReadFlags、ReadFlagsBinding、ReadFlagsHttpClient、ReadFlagsLocal等模块共同支撑了这条链路因此 Worker 代码里无需Effect.tryPromise包装即可直接yield*调用异步 Workers 则可以把 app 绑定在env上直接使用原始绑定。Provider.list与alchemy unsafe nukelist()枚举环境的全部实时资源本版本为 Provider 引入了新的生命周期操作list()它枚举当前账户/区域/Zone 中该类型的所有实时资源返回的每一项都与read产出的Attributes形状一致因此可以直接被删除。这为后续的清理能力打下了基础。alchemy unsafe nuke一键清空测试环境基于list()构建的alchemy unsafe nuke命令枚举 profile 下所有 Provider 能看到的资源并全部删除。当 230 种资源类型都可枚举时清理一个被烧毁的测试账户就变成一行命令alchemy unsafe nuke \ --include Cloudflare.* \ --filter resource.workerName alchemy-state-store \ --dry-run命令的完整语义在 nuke 文档 中有详尽说明这里提炼关键点--include/--exclude接受provider-ID globpicomatch 语法如Cloudflare.*、Cloudflare.Worker可重复指定--exclude在--include之后应用--filter接受JavaScript 表达式求值时resource在作用域内另有合成的Type、LogicalId字段表达式为 truthy 的资源会被赦免spared不会被删除表达式抛异常或非布尔值时按 false 处理--dry-run只预览不删除--yes跳过确认提示该命令刻意从--help中隐藏——它删除的是真实基础设施危险操作不该被轻易发现。nuke 的安全边界nuke 的破坏力远超一般认知需要特别注意它不限定于某个 stack、stage 或状态存储stack 文件仅用于发现注册了哪些 Provider随后每个 Provider 的list()会枚举该账户/区域/Zone 中的所有同类型资源——包括 alchemy 从未创建过的资源——并全部删除不可撤销状态存储全程不被读写枚举只基于实时云状态删除后状态条目会残留为 stale需要用alchemy state clear清理幸存清单nuke.singleton设置始终存在的配置其 delete 只是重置默认值、nuke.skip资源没有真实删除 API 的资源、被--include/--exclude过滤掉的 Provider、被--filter赦免的资源、以及删除持续失败的资源会在运行结束时汇报删除采用多轮扫描每轮尝试所有剩余资源失败的进入下一轮依赖顺序无需构建图即可自然浮现当某轮无进展时停止并报告N resource(s) could not be deleted--concurrency控制 Provider 并行扫描/删除数默认 160表示不限制——但通常更慢因为会触发 Provider 侧限流与重试退避同一 Provider 内的资源始终并发删除--timeout是每个list/delete调用的 per-Provider 超时默认 120 秒防止单个慢 Provider 拖垮整次运行。大多数情况下你真正想要的是alchemy destroy见 destroy 文档——它是 stack 作用域、状态驱动的正规卸载方式unsafe nuke是烧毁测试环境的最后手段。GitHub 仓库与 Webhook 事件GitHub.Repository稳定 ID 驱动的收敛式仓库管理Justin Bennett 贡献了GitHub.Repository资源——完整的仓库生命周期管理其核心亮点是一个收敛式 reconcilerconverging reconciler它按稳定的数字 ID 读取仓库。这意味着即使有人在 stack 之外把仓库重命名了状态也不会被污染不会因为 name 变化而误判为删除重建const repo yield* GitHub.Repository(internal-tools, { owner: my-org, name: internal-tools, visibility: private, deleteBranchOnMerge: true, });GitHub.events把仓库变成 Worker 的事件源在Repository之上GitHub.events把一个仓库变成 Cloudflare Workers 的事件源。在 Worker 的 init 阶段订阅会顺带配置一个指向 Worker URL 的GitHub.Webhook运行时每次投递都用常数时间的 HMAC-SHA256 签名校验验证然后以完全类型化的 payload交到你的 handler 手中const secret yield* Config.redacted(GITHUB_WEBHOOK_SECRET); // event.name 被收窄为 push | pull_request yield* GitHub.events({ owner: my-org, repository: my-repo, events: [push, pull_request], secret, }).subscribe((event) Effect.log(received ${event.name} (${event.id})), );从 RepositoryEventSource.ts 源码 可以看到事件源的类型系统设计GitHubEventName源自octokit/webhooks的EmitterWebhookEventName并排除event.action变体如pull_request.opened——因为 Webhook 按裸事件名配置WebhookEventName GitHubEventName | **订阅所有事件events默认[push]WebhookEvent是完整的可辨识联合discriminated union以name为判别键每个事件都有完全类型化的payloadSelectedEvent类型会把联合收窄到你选中的事件集合因此switch (event.name)可以穷尽收窄event.payloadsecret是Redacted.Redactedstring如Config.redacted产生配置后事件源会用该 secret 配置 Webhook运行时拒绝X-Hub-Signature-256头不匹配的投递——强烈建议设置否则任何知道投递 URL 的人都能伪造事件。事件源的使用也体现在 github/events 文档 中除了GitHub.events文档中的consumeRepositoryEvents这种高层抽象还有更底层的GitHub.Webhook资源——它管理 Webhook 自身的生命周期首次部署时创建、后续部署原地更新、销毁时删除url接受Outputstring从而可以指向同栈内的 Worker 资源。值得注意的是Cloudflare.Workers.GitHubRepositoryEventSourceLive目前是RepositoryEventSource契约的唯一实现暂无 AWS Lambda 事件源在其他宿主上仍可直接用GitHub.Webhook指向任意投递 URL但路由与签名校验需要自己实现。S3 状态存储AWS.state()AWS 栈在本版本获得了一等公民的远程状态后端与 Cloudflare 的Cloudflare.state()对齐const Stack Alchemy.Stack( my-stack, { providers: AWS.providers(), state: AWS.state() }, Effect.gen(function* () { // ... }), );从 AWS/StateStore/State.ts 源码 可以确认状态布局与默认行为状态对象存放于s3://{bucket}/{prefix}{stack}/{stage}/{fqn}.json默认桶是自动创建的账户区域级account-regional桶命名遵循alchemy-state-{accountId}-{region}-an约定自定义名称也必须符合prefix-accountId-region-an的账户区域命名空间约束prefix指定桶内键前缀默认即桶根尾部/会自动补上桶默认启用AES256服务端加密encryption可覆盖同 stage 前缀下还有一个__stack_output__.json记账对象存放 stack 已解析的 outputlist结果在 FQN 解码前必须把它过滤掉批量删除遵循 S3 单次DeleteObjects最多 1000 个键的上限DELETE_BATCH_SIZE 1000。关键设计凭证解析与桶创建都被推迟到第一次状态操作时才发生——因此构造 Layer 的阶段完全不会触碰 AWS。这意味着alchemy plan在没有任何 AWS 凭证的情况下也能快速完成 diff只在真正读写状态时才发起网络请求。本版本其他改进bundle: falseonCloudflare.Worker原样上传预先构建好的mainbyte-for-byte不做 rolldown 打包、不做压缩支持用 glob 形式的rules选择附加模块。这是 OpenNext 等外部打包产物的标准工作路径。alchemy plan近即时启动warm 启动从 8.2s 降到 1.8s手段是懒加载 TUI 和 vite 插件、延迟 distilled schema 的构建。稳定输出属性当首个域名未变化时worker.url跨部署保持稳定下游引用它的资源如 Webhook 投递 URL不再出现幽灵更新同理worker.durableObjectNamespaces在 DO 类集合未变化时保持稳定。Lambda 函数 URL 支持完整配置url: { authType: AWS_IAM, cors, invokeMode: RESPONSE_STREAM }IAM 认证的 URL 会省略公开的权限声明。alchemy dev韧性改进apply 失败时保持存活记录完整原因而非静默退出。StaticSite 转发dev.env含 Redacted 密钥给外部 dev-server 命令本地 assets binding 在alchemy dev中不再返回 500。Drizzle drift 检测按 plan/apply 周期缓存drizzle-kit 的交互式重命名提示只出现一次不再挂死alchemy dev。延伸阅读围绕本版本的各项能力仓库内提供了完整的文档与源码可供继续深入Looping the Generation of IaC and SDKs——资源工厂与 SDK 生成闭环的完整故事Concepts › Providers——Provider 抽象与生命周期操作Concepts › State Store——状态存储概念CLI guide——CLI 全景nuke 命令文档——unsafe nuke的完整参数表与安全边界Webhooks events——GitHub Webhook 资源与 Worker 事件源的使用指南Deploy a Lambda Function——Lambda 部署指南Cloudflare Flagship App 源码——特性开关资源的属性与绑定实现AWS S3 State 源码——S3 状态后端的默认值与状态布局GitHub RepositoryEventSource 源码——事件源的类型系统与签名校验【免费下载链接】t3code项目地址: https://gitcode.com/GitHub_Trending/t3/t3code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考