缺「部署一顆 Cloudflare Worker」的 recipe——出貨線有 2 站因此搬不上 Arcrun #90

Open
opened 2026-08-11 11:52:39 +00:00 by Leo · 2 comments
Owner

需求來源:Leo/arcrun-rag#77(D73)。

要什麼

一個 recipe:把一顆 Worker 部署到指定 Cloudflare 帳號(CF 有 Workers Script Upload API,Arcrun 打得到)。
帳號與憑證走 credential 中心({{credential.*}},D36)。

哪幾站需要它

deploy(安裝器)/mail-relay(代寄信那台)。

沒有它會退回什麼形態

這兩站只能靠某台機器跑本機部署指令。
⚠️ 附帶一個真實成本:mail-relay 就是因為長期不在出貨線上,prod 從沒被推過,
使用者按「忘記密碼」打到 404(Leo/arcrun-rag#38#69#25)。
站點越依賴「某台機器上的某個人記得跑」,就越容易整站消失在出貨清單外。

需求來源:`Leo/arcrun-rag#77`(D73)。 ## 要什麼 一個 recipe:把一顆 Worker 部署到指定 Cloudflare 帳號(CF 有 Workers Script Upload API,Arcrun 打得到)。 帳號與憑證走 credential 中心(`{{credential.*}}`,D36)。 ## 哪幾站需要它 `deploy`(安裝器)/`mail-relay`(代寄信那台)。 ## 沒有它會退回什麼形態 這兩站只能靠某台機器跑本機部署指令。 ⚠️ 附帶一個真實成本:`mail-relay` 就是因為長期不在出貨線上,prod 從沒被推過, 使用者按「忘記密碼」打到 404(`Leo/arcrun-rag#38`/`#69`/`#25`)。 **站點越依賴「某台機器上的某個人記得跑」,就越容易整站消失在出貨清單外。**
Leo added the
s
todo
p
high
labels 2026-08-11 11:55:48 +00:00
Author
Owner

[arcrun CC] 回報:Cloudflare Worker 部署能力現況

已做(真的落地在 leo21c 現役實例上)

auth-recipe cloudflare_workers 已註冊,實測輸出:

$ curl -s https://arcrun-cypher-executor.leo21c.workers.dev/auth-recipes/cloudflare_workers
{"success":true,"recipe":{"kind":"auth_recipe","service":"cloudflare_workers","primitive":"static_key",
 "base_url":"https://api.cloudflare.com/client/v4",
 "inject":{"header":{"Authorization":"Bearer {{secret.cf_api_token}}"}}, ...}}

這顆是通用的(CF Workers/D1/KV 等管理 API 都吃同一種 Bearer token),不只服務這張票。

發現一個結構性問題(誠實記錄,不是我沒寫對)

原本想比照 #89 做一個 cf_worker_deploy recipe,但讀了 cypher-executor/src/lib/component-loader.tsmakeRecipeRunner 才發現:recipe 引擎的 body 一律 JSON.stringify(無論走 body_templaterecipe.body/還是 fallback 拿 ctx 當 body,三條路徑最後都是 JSON 字串)。

但 Cloudflare Workers Script Upload API(PUT /accounts/{id}/workers/scripts/{name})的 body 必須是:

  • classic 格式:原始 JS 原始碼(Content-Type: application/javascript,body=純文字,不是 JSON),或
  • 現代 ES module + bindings 格式deploy/mail-relay 兩站的實際部署八成是這種,因為本 repo 自己的 worker 都是 ES module):multipart/form-data(metadata JSON part + script part)

兩者都不是「JSON body」,跟 recipe 抽象的假設對不上——這不是 recipe schema 能修的事,是這支 API 的形狀跟這個引擎的 body 模型天生不合。

正解(07-thin-shell §3.5「第三方 API 缺能力」路徑,非腹語術)

不硬塞進 recipe,改用 http_request 零件直接打(它原生支援 string body,見 registry/components/http_request/main.goBody/BodyJSON 兩種模式,不經過 recipe wrapper):

  • header:Authorization: Bearer {{credential.cf_api_token}}——這是 D36 的 credential 模板機制,跟 recipe/auth_service 是兩條獨立管道,不需要透過 recipe 才能用,工作流作者可以直接在 http_request 節點的 config 裡寫
  • 若目標需要 bindings/compatibility_flags(現代格式):上游加一個 code 節點組 multipart/form-data body——這是純資料編碼(沒有更好的 YAML 表達方式),不是業務邏輯替代,屬合法局部整形,不算腹語術

已備妥 cf_worker_deploy_simple.yaml(classic 格式限定版本,同樣卡在 #89 講的那個人類 consent 閘,未註冊):

canonical_id: cf_worker_deploy_simple
display_name: Cloudflare Worker Deploy (single-file, classic format)
description: >-
  PUT /accounts/{account_id}/workers/scripts/{script_name} 部署單檔 Worker(CF「classic Service
  Worker」格式,非 ES module)。_path 帶 /{account_id}/workers/scripts/{script_name}。
  auth: cloudflare_workers static_key(Bearer token)。
  ⚠️ 已知限制:這個 recipe 走 arcrun 的「body 一律 JSON」引擎行為,只適合仍接受 classic 格式的
  簡單場景;需要 bindings 的部署請走上面說的 http_request + code 節點 multipart 補丁。
endpoint: https://api.cloudflare.com/client/v4/accounts{{_path}}
method: PUT
auth_service: cloudflare_workers
headers:
  Content-Type: application/javascript

需要總管/leo 確認一件事

deploy(安裝器)/mail-relay 這兩站現有的 wrangler.toml 是否用了 bindings/compatibility_flags?如果是(大概率),classic 版本的 recipe 幫不上忙,直接走 http_request+multipart code 節點會比硬做一個「假裝支援」的 recipe 誠實。我沒有這兩站的部署細節,沒法自己判斷。

CP 狀態:◐ 半通

auth 能力已備好且通用可重用;「部署」本身的正確形態取決於上面那個待確認的問題,我不猜答案。

[arcrun CC] 回報:Cloudflare Worker 部署能力現況 ## 已做(真的落地在 leo21c 現役實例上) **auth-recipe `cloudflare_workers` 已註冊**,實測輸出: ``` $ curl -s https://arcrun-cypher-executor.leo21c.workers.dev/auth-recipes/cloudflare_workers {"success":true,"recipe":{"kind":"auth_recipe","service":"cloudflare_workers","primitive":"static_key", "base_url":"https://api.cloudflare.com/client/v4", "inject":{"header":{"Authorization":"Bearer {{secret.cf_api_token}}"}}, ...}} ``` 這顆是通用的(CF Workers/D1/KV 等管理 API 都吃同一種 Bearer token),不只服務這張票。 ## 發現一個結構性問題(誠實記錄,不是我沒寫對) 原本想比照 #89 做一個 `cf_worker_deploy` recipe,但讀了 `cypher-executor/src/lib/component-loader.ts` 的 `makeRecipeRunner` 才發現:**recipe 引擎的 body 一律 `JSON.stringify`**(無論走 `body_template`/`recipe.body`/還是 fallback 拿 ctx 當 body,三條路徑最後都是 JSON 字串)。 但 Cloudflare Workers Script Upload API(`PUT /accounts/{id}/workers/scripts/{name}`)的 body 必須是: - **classic 格式**:原始 JS 原始碼(`Content-Type: application/javascript`,body=純文字,不是 JSON),或 - **現代 ES module + bindings 格式**(`deploy`/`mail-relay` 兩站的實際部署八成是這種,因為本 repo 自己的 worker 都是 ES module):`multipart/form-data`(metadata JSON part + script part) 兩者都不是「JSON body」,跟 recipe 抽象的假設對不上——**這不是 recipe schema 能修的事**,是這支 API 的形狀跟這個引擎的 body 模型天生不合。 ## 正解(07-thin-shell §3.5「第三方 API 缺能力」路徑,非腹語術) 不硬塞進 recipe,改用 `http_request` 零件直接打(它原生支援 string body,見 `registry/components/http_request/main.go` 的 `Body`/`BodyJSON` 兩種模式,不經過 recipe wrapper): - header:`Authorization: Bearer {{credential.cf_api_token}}`——這是 D36 的 credential 模板機制,跟 recipe/auth_service 是**兩條獨立管道**,不需要透過 recipe 才能用,工作流作者可以直接在 `http_request` 節點的 config 裡寫 - 若目標需要 bindings/compatibility_flags(現代格式):上游加一個 `code` 節點組 multipart/form-data body——這是純資料編碼(沒有更好的 YAML 表達方式),不是業務邏輯替代,屬合法局部整形,不算腹語術 已備妥 `cf_worker_deploy_simple.yaml`(classic 格式限定版本,同樣卡在 #89 講的那個人類 consent 閘,未註冊): ```yaml canonical_id: cf_worker_deploy_simple display_name: Cloudflare Worker Deploy (single-file, classic format) description: >- PUT /accounts/{account_id}/workers/scripts/{script_name} 部署單檔 Worker(CF「classic Service Worker」格式,非 ES module)。_path 帶 /{account_id}/workers/scripts/{script_name}。 auth: cloudflare_workers static_key(Bearer token)。 ⚠️ 已知限制:這個 recipe 走 arcrun 的「body 一律 JSON」引擎行為,只適合仍接受 classic 格式的 簡單場景;需要 bindings 的部署請走上面說的 http_request + code 節點 multipart 補丁。 endpoint: https://api.cloudflare.com/client/v4/accounts{{_path}} method: PUT auth_service: cloudflare_workers headers: Content-Type: application/javascript ``` ## 需要總管/leo 確認一件事 `deploy`(安裝器)/`mail-relay` 這兩站現有的 wrangler.toml 是否用了 bindings/compatibility_flags?如果是(大概率),classic 版本的 recipe 幫不上忙,直接走 http_request+multipart code 節點會比硬做一個「假裝支援」的 recipe 誠實。我沒有這兩站的部署細節,沒法自己判斷。 ## CP 狀態:◐ 半通 auth 能力已備好且通用可重用;「部署」本身的正確形態取決於上面那個待確認的問題,我不猜答案。
Author
Owner

[arcrun CC] 追加:兩站的真實形態 + 明確建議(總管查證後轉交)

deploy(安裝器)——確認是 bindings 形態,而且根本不是一次 API 呼叫

products/arcrun-rag/installer/wrangler.jsonc 檔頭註解自己寫著:

  • "main": "src/index.js"9 把 KV binding + 1 顆 D1 binding
  • 部署動作是 Cloudflare Deploy 按鈕 + Builds 讀這份設定,跑
    node scripts/deploy-all.mjs && npx wrangler deploy

⇒ classic 單檔格式(我原本備的 cf_worker_deploy_simple)完全幫不上忙,這點我判斷對了。但更根本的問題是:這站的部署從來就不是「打一次 Workers Script Upload API」,是一整套「開 9+1 個資源 → 跑 migration → wrangler deploy」的 CI 流程。recipe(一次 HTTP 呼叫)這個抽象本身,不管 body 是 JSON 還是 multipart,都裝不下「一整個 Builds 流程」。「把 deploy 這站搬上 Arcrun」這個題目本身可能問錯了層次——它不是缺一顆零件,是這個站的部署機制跟「Arcrun 工作流呼叫一次 API」不同構型。

mail-relay——找到一條強線索,但不是 100% 確認,標成「線索待確認」而非「未知」

products/arcrun-rag 裡沒有獨立叫 mail-relay 的 wrangler 設定,但 installer/ship.stations.yaml(出貨線自己的站表,line 296-306)裡 mail-relay 條目寫:

理由: 同 deploy——wrangler deploy 需要本機部署憑證。

這已經先telling 我們:mail-relay 的部署形態被出貨線自己歸類成「跟 deploy 同款」(bindings 型,非單檔)。往下找,products/arcrun-rag/landing/wrangler.toml 是目前唯一帶 send_email binding(Cloudflare Email Service)的 worker(arcrun-landing,「landing page + 啟動碼中央服務」);matrix/arcruncypher-executor/src/routes/portal.ts:845/922 讀的是 env.PORTAL_MAIL_RELAY_BASE(一個外部 base URL,不是 binding 名),指向某個獨立跑的「代寄信」服務。

這條線索沒有完全對上arcrun-landing 處理的是「啟動碼信」(signup 驗證碼),cypher-executor 要打的 PORTAL_MAIL_RELAY_BASE 是「忘記密碼」代寄——兩者是否共用同一顆 worker,我沒有把握斷言,只能說兩者都是 send_email binding 型(Cloudflare Email Service binding,不是單純打第三方 mail API),這點不管最後是不是同一顆 worker 都成立。建議由總管或知道 mail-relay 實際部署位置的人一句話確認它是不是 arcrun-landing(或另一顆我沒找到的 worker),我不替它假設。

明確建議:這張票該不該繼續做 recipe?

不建議繼續把 deploymail-relay 硬塞進「一顆 API recipe」的形狀,理由:

  1. deploy:本質是 CI 流程,不是一次 API 呼叫。recipe 模型(HTTP call)在结构上就裝不下。
  2. mail-relay(若真是 send_email binding 型):Email Service binding 是部署時宣告的 binding,不是 Workers Script Upload API 之外還能單獨用一次 REST 呼叫加開的東西——一樣需要走 wrangler deploy 才能生效,不是「打一個 API」能解決的缺口。
  3. 兩者的真正共同缺口,其實跟 recipe 完全無關:是「有沒有一個能從 Arcrun 觸發、免本機憑證的方式去跑 wrangler deploy(或等效的 Builds 流程)」。這個問題比「寫一個 recipe」大得多,值得另外開票討論(例如:CF Workers Builds 是否像 Pages 一樣有 Deploy Hook webhook 可以單純 POST 觸發?我沒有把握——Pages 確定有,Workers Builds 我沒查證過,不確定;若有,那才是這兩站真正能收斂成「一個 recipe」的路,且比重寫整個部署管線務實得多)。

已交付、仍然有效、建議保留的部分cloudflare_workers auth-recipe(Bearer token 注入)已註冊在 leo21c 上,這是通用能力,服務的是「任何走標準 JSON body 的 CF 管理 API」(DNS records/D1 query/KV 讀寫等),跟 deploymail-relay 這兩個特例無關但仍然是净收穫,不建議撤掉。

這張票的收斂建議:#90 原本假設的「9 站裡有 2 站缺 CF Worker 部署 recipe」這個判斷需要修正——這 2 站缺的不是 recipe,是「免本機憑證觸發部署」這個更大的能力,是否存在(Deploy Hook)待查。若查無此路,這兩站可能得先留在「物理限制」那類(跟 preflightgithub-release 同組),而不是「缺零件」。

[arcrun CC] 追加:兩站的真實形態 + 明確建議(總管查證後轉交) ## ① `deploy`(安裝器)——確認是 bindings 形態,而且根本不是一次 API 呼叫 `products/arcrun-rag/installer/wrangler.jsonc` 檔頭註解自己寫著: - `"main": "src/index.js"` + **9 把 KV binding + 1 顆 D1 binding** - 部署動作是 **Cloudflare Deploy 按鈕 + Builds** 讀這份設定,跑 `node scripts/deploy-all.mjs && npx wrangler deploy` ⇒ classic 單檔格式(我原本備的 `cf_worker_deploy_simple`)完全幫不上忙,這點我判斷對了。但更根本的問題是:**這站的部署從來就不是「打一次 Workers Script Upload API」**,是一整套「開 9+1 個資源 → 跑 migration → wrangler deploy」的 CI 流程。recipe(一次 HTTP 呼叫)這個抽象本身,不管 body 是 JSON 還是 multipart,都裝不下「一整個 Builds 流程」。**「把 deploy 這站搬上 Arcrun」這個題目本身可能問錯了層次**——它不是缺一顆零件,是這個站的部署機制跟「Arcrun 工作流呼叫一次 API」不同構型。 ## ② `mail-relay`——找到一條強線索,但不是 100% 確認,標成「線索待確認」而非「未知」 `products/arcrun-rag` 裡沒有獨立叫 `mail-relay` 的 wrangler 設定,但 `installer/ship.stations.yaml`(出貨線自己的站表,line 296-306)裡 mail-relay 條目寫: > 理由: 同 deploy——`wrangler deploy` 需要本機部署憑證。 這已經先telling 我們:mail-relay 的部署形態被出貨線自己歸類成「跟 deploy 同款」(bindings 型,非單檔)。往下找,`products/arcrun-rag/landing/wrangler.toml` 是目前唯一帶 `send_email` binding(Cloudflare Email Service)的 worker(`arcrun-landing`,「landing page + 啟動碼中央服務」);`matrix/arcrun` 的 `cypher-executor/src/routes/portal.ts:845/922` 讀的是 `env.PORTAL_MAIL_RELAY_BASE`(一個外部 base URL,不是 binding 名),指向某個獨立跑的「代寄信」服務。 **這條線索沒有完全對上**:`arcrun-landing` 處理的是「啟動碼信」(signup 驗證碼),cypher-executor 要打的 `PORTAL_MAIL_RELAY_BASE` 是「忘記密碼」代寄——兩者是否共用同一顆 worker,我沒有把握斷言,只能說**兩者都是 `send_email` binding 型**(Cloudflare Email Service binding,不是單純打第三方 mail API),這點不管最後是不是同一顆 worker 都成立。**建議由總管或知道 mail-relay 實際部署位置的人一句話確認它是不是 `arcrun-landing`(或另一顆我沒找到的 worker),我不替它假設。** ## 明確建議:這張票該不該繼續做 recipe? **不建議繼續把 `deploy`/`mail-relay` 硬塞進「一顆 API recipe」的形狀**,理由: 1. `deploy`:本質是 CI 流程,不是一次 API 呼叫。recipe 模型(HTTP call)在结构上就裝不下。 2. `mail-relay`(若真是 send_email binding 型):Email Service binding 是**部署時宣告的 binding**,不是 Workers Script Upload API 之外還能單獨用一次 REST 呼叫加開的東西——一樣需要走 wrangler deploy 才能生效,不是「打一個 API」能解決的缺口。 3. 兩者的真正共同缺口,其實跟 recipe 完全無關:**是「有沒有一個能從 Arcrun 觸發、免本機憑證的方式去跑 `wrangler deploy`(或等效的 Builds 流程)」**。這個問題比「寫一個 recipe」大得多,值得另外開票討論(例如:CF Workers Builds 是否像 Pages 一樣有 Deploy Hook webhook 可以單純 POST 觸發?我沒有把握——Pages 確定有,Workers Builds 我沒查證過,不確定;若有,那才是這兩站真正能收斂成「一個 recipe」的路,且比重寫整個部署管線務實得多)。 **已交付、仍然有效、建議保留的部分**:`cloudflare_workers` auth-recipe(Bearer token 注入)已註冊在 leo21c 上,這是通用能力,服務的是「任何走標準 JSON body 的 CF 管理 API」(DNS records/D1 query/KV 讀寫等),跟 `deploy`/`mail-relay` 這兩個特例無關但仍然是净收穫,不建議撤掉。 **這張票的收斂建議**:#90 原本假設的「9 站裡有 2 站缺 CF Worker 部署 recipe」這個判斷需要修正——這 2 站缺的不是 recipe,是「免本機憑證觸發部署」這個更大的能力,是否存在(Deploy Hook)待查。若查無此路,這兩站可能得先留在「物理限制」那類(跟 `preflight`/`github-release` 同組),而不是「缺零件」。
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Leo/Arcrun#90