feat(arcrun): add kbdb_upsert_block component for idempotent block writes
對應 mira 7B.3f:per-entity index-entry 維護需要「找有則 PATCH 沒找到 POST」, arcrun workflow 沒 IF/branch 能力(已知限制 #1 + 新 P1 #1),用 kbdb_upsert_block 零件把分支邏輯封進零件內:GET /blocks?page_name=X → user_id filter → 找到 PATCH 沒找到 POST。 page_name 當 idempotency key,未來其他「找有則改沒則建」場景共用。 SDD:polaris/mira/.agents/specs/mira-app/design.md §3.5.12.4.1 matrix/arcrun/.agents/specs/arcrun/arcrun.md 三-A P1 #1 + 三-B 新零件加入紀錄
This commit is contained in:
@@ -69,8 +69,205 @@ P0 全部清除才啟動封測。
|
|||||||
| 6 | acr creds push 實測 | ✅ 完成 | /register 回傳 encryption_key,acr init 自動存入 config(CLI 1.0.9)|
|
| 6 | acr creds push 實測 | ✅ 完成 | /register 回傳 encryption_key,acr init 自動存入 config(CLI 1.0.9)|
|
||||||
| 7 | Google Sheets 真實寫入 | ⚠️ 部分驗證 | credential 注入已驗證;實際 Sheets 寫入需真實 OAuth token |
|
| 7 | Google Sheets 真實寫入 | ⚠️ 部分驗證 | credential 注入已驗證;實際 Sheets 寫入需真實 OAuth token |
|
||||||
| 8 | 第三方服務認證 recipe | ✅ 完成 | 20 個服務(Notion/Slack/GitHub/OpenAI 等),CLI 1.1.0 |
|
| 8 | 第三方服務認證 recipe | ✅ 完成 | 20 個服務(Notion/Slack/GitHub/OpenAI 等),CLI 1.1.0 |
|
||||||
|
| **9** | **cypher-executor outbound HTTP fetch 全失效** | ✅ **已解決 2026-05-13**(CF 同 zone 自循環死鎖,改走 workers.dev)| 詳見下方專段 |
|
||||||
|
| **10** | **multi-node chain context propagation 漏失** | ✅ **已解決 2026-05-13**(ON_SUCCESS/ON_FAIL/IF/ON_CLICK 沒 spread baseCtx)| 詳見下方專段 |
|
||||||
|
|
||||||
**目前狀況**:P0 全部完成。Google Sheets 實際寫入可由封測者用真實 token 驗證,不阻塞啟動。
|
**目前狀況**:P0 全部解決。
|
||||||
|
- #9 修復方式:component worker URL 從 `*.arcrun.dev`(同 cypher zone)改走 `arcrun-{name}.{WORKER_SUBDOMAIN}.workers.dev`(避開同 zone 自循環)
|
||||||
|
- #10 修復方式:4 個 edge type 補 `{...baseCtx, ...result}`,跟 PIPE/FOREACH 一致
|
||||||
|
|
||||||
|
兩個 P0 解完 mira 7 節點 workflow 端對端通(含真 Claude 16 秒呼叫)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ✅ P0 #9(2026-05-13 已解決):cypher-executor outbound fetch 全失效
|
||||||
|
|
||||||
|
**完整事件報告(含誤判路徑)**:[docs/incidents/2026-05-13-cypher-outbound-522.md](../../../docs/incidents/2026-05-13-cypher-outbound-522.md)
|
||||||
|
|
||||||
|
**修復方式**:cypher-executor fetch component worker 從 `*.arcrun.dev`(同 zone)改走 `arcrun-{name}.{WORKER_SUBDOMAIN}.workers.dev`。對外 `cypher.arcrun.dev` 不變,用戶 0 感知。
|
||||||
|
|
||||||
|
**改動檔案**(2026-05-13):
|
||||||
|
- `cypher-executor/src/lib/component-loader.ts`:`wasmWorkerUrl(canonicalId, subdomain)` 簽名加 subdomain 參數 + URL pattern 改 workers.dev
|
||||||
|
- `cypher-executor/src/actions/auth-dispatcher.ts`:同步新簽名
|
||||||
|
- `cypher-executor/src/types.ts`:`Bindings` 加 `WORKER_SUBDOMAIN: string`
|
||||||
|
- `cypher-executor/wrangler.toml`:`[vars]` 加 `WORKER_SUBDOMAIN = "uncle6-me"`
|
||||||
|
- 5 個 component worker 在 dashboard 啟用 workers.dev URL(kbdb-get / kbdb-ingest / kbdb-create-block / kbdb-patch-block / claude-api,**未來新 component 也都要開**)
|
||||||
|
|
||||||
|
**驗證**:cypher-executor → kbdb-get / claude-api 從 522 → 200。mira `acr run wiki_synthesis` 5 節點 workflow 跑通前 3 節點(kbdb_get chain)。
|
||||||
|
|
||||||
|
**Self-hosted fork 注意**:必須改 `wrangler.toml [vars] WORKER_SUBDOMAIN` 為自己的 CF 帳號 subdomain,並把所有 component worker 在 dashboard 啟用 workers.dev URL。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ✅ P0 #10(2026-05-13 已解決):multi-node chain context propagation 漏失
|
||||||
|
|
||||||
|
**現象**:cypher binding workflow 從第 2 個節點開始,原始 input context(top-level `api_key` / `mira_token` 等)丟失,下游節點 `{{api_key}}` 模板原文未替換傳給零件 → 401 Unauthorized 或類似錯。
|
||||||
|
|
||||||
|
**測試重現**:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
flow:
|
||||||
|
- "input >> ON_SUCCESS >> n1"
|
||||||
|
- "n1 >> ON_SUCCESS >> n2"
|
||||||
|
config:
|
||||||
|
n1: { component: kbdb_get, api_key: "{{api_key}}", block_id: "{{b1}}" }
|
||||||
|
n2: { component: kbdb_get, api_key: "{{api_key}}", block_id: "{{b2}}" }
|
||||||
|
context: { api_key: "ak_xxx", b1: "...", b2: "..." }
|
||||||
|
```
|
||||||
|
|
||||||
|
n1 收到 ctx 含 `api_key / b1 / b2` ✓ → 跑通。
|
||||||
|
n2 收到的 ctx 只有 `n1.output spread`(blocks/count/success/block_id),**`api_key / b1 / b2` 不見**,`{{api_key}}` 原文傳到零件回 401。
|
||||||
|
|
||||||
|
**根因**:`graph-executor.ts` 在 PIPE / FOREACH 邊類型已修「baseCtx ∪ result」,但 **ON_SUCCESS / ON_FAIL / IF / ON_CLICK 四個 edge type 沒套同模式**,直接把 `result` 當下游 ctx 傳,丟掉原始 context。
|
||||||
|
|
||||||
|
**修法**(`cypher-executor/src/graph-executor.ts` line 407 / 415 / 423 / 472):
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 改前
|
||||||
|
result = await this.executeNode(nextNode, graph, result, ...);
|
||||||
|
|
||||||
|
// 改後(同 PIPE/FOREACH 模式)
|
||||||
|
const baseCtx = (typeof context === 'object' && context !== null) ? context as Record<string, unknown> : {};
|
||||||
|
const baseResult = (typeof result === 'object' && result !== null) ? result as Record<string, unknown> : {};
|
||||||
|
const mergedCtx = { ...baseCtx, ...baseResult };
|
||||||
|
result = await this.executeNode(nextNode, graph, mergedCtx, ...);
|
||||||
|
```
|
||||||
|
|
||||||
|
**驗證**:mira `acr run wiki_synthesis` 7 節點 workflow 端對端跑通(16 秒,含真 Claude 呼叫)。每個節點都拿到正確 `api_key` 不再 401。
|
||||||
|
|
||||||
|
**歷史脈絡**:類似問題 2026-05-07 commit e8fca33 在 FOREACH edge 已修一次("FOREACH preserves outer context"),但當時沒同步處理另外 4 個 edge type。本次補完。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ✅ P0 #10 補完三個衍生問題(2026-05-13 晚 ~ 2026-05-14)
|
||||||
|
|
||||||
|
P0 #10 修完後 mira 嘗試做 wiki 多段結構,又踩出三個 cypher binding 設計缺陷。**都是同一天解掉**。
|
||||||
|
|
||||||
|
#### A. interpolateData() 不遞迴 nested object
|
||||||
|
|
||||||
|
**現象**:`set` / `kbdb_create_block` 的 `values: { text: "{{classify.data.text}}" }`、`tags_json: ["facet:{{paragraph.facet}}"]` 等 nested config 內的 `{{x}}` 不被替換,原文傳給零件。
|
||||||
|
|
||||||
|
**根因**:`interpolateData()` 只 iterate top-level,對非 string 值(object / array)直接 pass-through 不下沉。
|
||||||
|
|
||||||
|
**修法**:拆 `interpolateString` + `interpolateValue`(遞迴 object / array),`interpolateData` 改 call `interpolateValue`。
|
||||||
|
|
||||||
|
**測試**:`set values: { text: "hello {{name}}", arr: ["item {{name}}"] }` 帶 `name=world` → 全展開。
|
||||||
|
|
||||||
|
#### B. ctx 沒存上游 output 的 node id namespace
|
||||||
|
|
||||||
|
**現象**:`{{classify.data.text}}` 找不到上游 classify 的 output;只能用 `{{data.text}}`(直接 spread 取),但會被下個節點覆蓋,多節點 chain 用不了。
|
||||||
|
|
||||||
|
**根因**:`propagateCtx` 只把上游 result spread 進 ctx,沒額外存 `[node.id]: result`。
|
||||||
|
|
||||||
|
**修法**:`propagateCtx` 改回傳 `{ ...baseCtx, ...baseResult, [upstreamNodeId]: upstreamResult }`。讓下游能用 `{{node_id.data.text}}` 從 namespace 取,永不被覆蓋。
|
||||||
|
|
||||||
|
**測試**:5 節點 chain 用 `{{load_schema.blocks.0.content}}` / `{{classify.data.text}}` 全展開。
|
||||||
|
|
||||||
|
#### C. FOREACH 找 iterable 只看 result,不看 ctx + 不看 nested
|
||||||
|
|
||||||
|
**現象**:mira wiki_synthesis 雙重 FOREACH(外層 `對每個 paragraph`、內層 `對每個 triplet`),外層 OK,內層跑 0 次。
|
||||||
|
|
||||||
|
**根因 (C1)**:`getIterableFromContext(result, key)` 只看當前節點 output。`result` 是 `create_paragraph` output(`{data, success}`),不含 paragraphs。但 `paragraphs` 早就在 ctx 從 classify spread 來。
|
||||||
|
|
||||||
|
**根因 (C2)**:當外層 FOREACH 把 `paragraph` item 注入 ctx,內層 FOREACH 要找 `paragraph.triplets`。`getIterableFromContext` 只看 top-level,看不到 `paragraph` 物件裡的 `triplets`。
|
||||||
|
|
||||||
|
**修法**:
|
||||||
|
- (C1) FOREACH `result` 找不到 iterable → fallback 找 `context`
|
||||||
|
- (C2) `getIterableFromContext` 加一輪「掃 ctx 內每個 object 找 nested key」
|
||||||
|
|
||||||
|
**測試**:mira wiki_synthesis 3 層樹(wiki-page → paragraphs → triplets)端對端跑通,KBDB 內驗證 `物理 AI` wiki 有 2 段 paragraph + 4 個 triplet,parent_id 正確接到對應 paragraph。
|
||||||
|
|
||||||
|
#### Edge type 一致化
|
||||||
|
|
||||||
|
抽 `propagateCtx(context, result, upstreamNodeId)` helper,5 個 edge type(PIPE / ON_SUCCESS / ON_FAIL / IF / ON_CLICK / FOREACH)全部用同一 function 組下游 ctx。**未來新 edge type 必須用這 helper**,避免再漏。
|
||||||
|
|
||||||
|
#### CLI validator 同步
|
||||||
|
|
||||||
|
`cli/src/lib/yaml-parser.ts` validateRelations 加 regex 支援 `對每個 X` / `FOREACH X` 迭代器命名(之前 validator 字串完全比對擋住,但 graph-builder 執行端早已支援)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 三-A、P1 待改進(不擋封測,但 mira 已踩到)
|
||||||
|
|
||||||
|
#### P1 #1:workflow 缺 IF/branch 能力(2026-05-14 mira 7B.3f 提出)
|
||||||
|
|
||||||
|
**現象**:mira 想做「找有則 PATCH 沒則 CREATE」(index-entry upsert),arcrun 目前只有 `ON_SUCCESS` + `對每個 X`(FOREACH)+ 已存在但壞掉的 `if_control`(見已知限制 #1),沒有 `>> ON_TRUE >>` / `>> ON_FALSE >>` 條件路由。
|
||||||
|
|
||||||
|
**短期 workaround**(已採用,2026-05-14):建 `kbdb_upsert_block` 零件,把分支邏輯封進零件內部(GET by page_name → 找到 PATCH 沒找到 POST)。caller 看到的是單純的 upsert 介面。
|
||||||
|
|
||||||
|
**長期解**:升 `if_control` false branch 路由 / 加 `>> ON_TRUE >>` edge type,讓 workflow 層可表達分支。對未來所有「找則改否則建」/「條件分流」場景都會撞到,不只 mira。
|
||||||
|
|
||||||
|
**位置**:cypher-executor/src/graph-executor.ts edge type 處理(5 個 edge type 抽出 `propagateCtx` 後新增 IF 應該不難)+ cli/src/lib/yaml-parser.ts validator。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 三-B、新零件加入紀錄
|
||||||
|
|
||||||
|
| 日期 | 零件 | 動機 | 對應 SDD |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 2026-05-14 | `kbdb_upsert_block` | mira 7B.3f index-entry per-entity upsert,繞過 workflow 缺 IF/branch 能力(P1 #1)。內部 GET by page_name → 找到 PATCH 沒找到 POST。page_name 當 idempotency key。 | polaris/mira/.agents/specs/mira-app/design.md §3.5.12.4.1 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 原 P0 #9 調查紀錄(保留作歷史參考)
|
||||||
|
|
||||||
|
**現象**:cypher-executor 的 `makeHttpRunner` (`cypher-executor/src/lib/component-loader.ts:142`) 對任何 outbound URL fetch 都回 CF **522 (origin timeout, ~1000ms)**。
|
||||||
|
|
||||||
|
**測試矩陣**(mira repo `polaris/mira/arcrun/wiki_synthesis.yaml` 端對端壓測時發現):
|
||||||
|
|
||||||
|
| 路徑 | 結果 | 證明 |
|
||||||
|
|---|---|---|
|
||||||
|
| 本機 curl → kbdb-get.arcrun.dev | 200 (22ms) | KBDB worker 本身健康 |
|
||||||
|
| cypher-executor → kbdb-get.arcrun.dev (HTTP) | **522** (1002ms) | outbound HTTP fetch 壞 |
|
||||||
|
| cypher-executor → claude-api.arcrun.dev (HTTP) | **522** | 同 zone 也壞 |
|
||||||
|
| cypher-executor → httpbin.org (外部) | **522** | 不只是 same-account loop |
|
||||||
|
| cypher-executor → string_ops (Service Binding) | 200 ✅ | SVC_* 路徑正常 |
|
||||||
|
| acr run hello (built-in via SB) | ✅ | hello.yaml 仍跑得通 |
|
||||||
|
|
||||||
|
**衍生小 bug**:`set` 零件 input schema 變了(要 `assignments` 陣列或 `values` 物件,不是 `value`)。tests/arcrun-test/hello.yaml 跑 string_ops 沒踩到。
|
||||||
|
|
||||||
|
**影響範圍(封測啟動阻擋)**:
|
||||||
|
|
||||||
|
- 任何用戶 workflow 含 outbound HTTP 都壞:
|
||||||
|
- 用戶 `acr recipe push` 後 trigger → 打外部 API 全 522(推翻 P0 #2 4/18 紀錄)
|
||||||
|
- 用戶要存資料進 arcrun 內建 KBDB → 522(mira 7B.3c 卡這裡)
|
||||||
|
- 任何 auth primitive 走獨立 Worker URL 路徑 → 522
|
||||||
|
- Google Sheets 寫入 → 522(推翻 P0 #7「待真實 OAuth 驗證」評估,根本還沒到 OAuth 步驟就壞)
|
||||||
|
- 只有「全內建邏輯零件 + 純 service binding」workflow 還能跑
|
||||||
|
|
||||||
|
**根因(2026-05-13 確認):5/8-5/9 9 次 manual `wrangler deploy` 把含 WIP bug 的 cypher-executor 推上 prod**
|
||||||
|
|
||||||
|
調查路徑(按時序):
|
||||||
|
|
||||||
|
1. 一開始懷疑 free tier CPU cap(10ms / invocation)→ 對照測試「5 節點 SB chain」跑了 2.2 秒卻通過,**推翻**
|
||||||
|
2. 換懷疑 CF zone 規則 / Bot Fight Mode → dashboard bindings 乾淨無攔截,**推翻**
|
||||||
|
3. 用戶補繳費恢復 Workers Paid → 重測仍全 522,**徹底排除付費假設**
|
||||||
|
4. 看 dashboard Version History:5/8 4 次 + 5/9 5 次 = **9 次 manual `wrangler deploy by uncle6.me`**
|
||||||
|
5. 對照 GitHub Actions:4/24 後完全沒 deploy(最後是 commit e222116 `fix(wasi-shim)`)
|
||||||
|
6. 對照 git:本機 main **領先 origin/main 3 commits 未 push**,含:
|
||||||
|
- `497f92a feat(arcrun): recipe system + resumable workflow + component registry canon`
|
||||||
|
- `e8fca33 feat(cypher): 3-node wiki workflow end-to-end (FOREACH + nested interp + unified parsing)`
|
||||||
|
- `519423c feat(arcrun): mira wiki page with tag filter + accumulated WIP`(自描含 `cypher-executor: auth-dispatcher / wasi-shim adjustments (WIP)`)
|
||||||
|
|
||||||
|
**結論**:那 9 次 manual deploy 把上面 3 個 unpushed commit 的 cypher-executor 改動推上 prod,其中至少一個改動破壞了 outbound fetch(最可能是 519423c WIP 內的 wasi-shim / auth-dispatcher 改動)。GitHub Actions 因為沒 push 沒跑,CI 沒 catch,4/18-4/24 那段 SDD「驗證通過」的紀錄是 truth,現在 prod 是壞的版本。
|
||||||
|
|
||||||
|
**為何 SB 路徑沒事 / HTTP 路徑全死**:SB 走 cypher-executor 內部 service binding API(`env.SVC_X.fetch()`),不經過 outbound HTTP code path。HTTP 路徑走 `makeHttpRunner` (component-loader.ts:142) 的 `fetch(url, ...)`,這條路被 WIP code 弄壞。具體壞在哪要 diff 那 3 個 commit 的 cypher-executor 改動才知道。
|
||||||
|
|
||||||
|
**驗證 wrangler tail 證據**:trigger 任何 outbound HTTP 的 graph,cypher-executor 自己 `wallTime: 497ms, cpuTime: 2ms, outcome: ok`、無 logs、無 exceptions。代表 cypher-executor 把「fetch 失敗的 522 response」當作 component 正常輸出包回 client,自己沒撞任何錯。
|
||||||
|
|
||||||
|
**解法(三選一)**:
|
||||||
|
|
||||||
|
- **A. Rollback prod 到 4/24 的 e222116** — CF dashboard → arcrun-cypher-executor → Deployments → 找 4/24 那筆 → Rollback。5 分鐘恢復 outbound fetch,丟失 wiki workflow / recipe / resumable 等 cypher 端 WIP 改動(但前端、registry components、KBDB blocks 都不丟,因為它們是別的 worker / 別的儲存)。**richblack 操作。**
|
||||||
|
- **B. Diff 3 個 unpushed commit 找出壞掉的改動修掉** — 不丟功能,但要動 src code 走 SDD 協議,30min - 數小時。
|
||||||
|
- **C. 架構切換**(mira 老闆 2026-05-13 提的):sub-workflow 自殺交棒模式,cypher-executor 不再做集中 graph executor。從根本繞開「cypher-executor 一個 invocation 跑長 graph」這條脆弱路徑。一勞永逸但是大改。
|
||||||
|
|
||||||
|
**衍生小 bug 仍要修**(跟付費無關):`set` 零件 input schema 變了(要 `assignments` 陣列或 `values` 物件,不是 `value`)。要嘛 update set 零件 contract 容錯,要嘛文件化新 schema。
|
||||||
|
|
||||||
|
**為什麼這直接擋封測**:
|
||||||
|
|
||||||
|
封測場景 Step 6「網頁 POST → 結果存 Google Sheets」走 google_sheets 零件 (HTTP outbound to googleapis.com)。如果 cypher-executor outbound 全壞,**封測者跑任何含外部 API 的 workflow 都會 522**,不是「Google Sheets 實際寫入未驗證」級別的小事。
|
||||||
|
|
||||||
|
**也直接擋 mira**:[polaris/mira/.agents/specs/mira-app/tasks.md] 7B.3c-f(wiki 合成 workflow)卡這裡。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -84,7 +281,7 @@ P0 全部清除才啟動封測。
|
|||||||
|
|
||||||
## 五、已知限制(封測期間不修)
|
## 五、已知限制(封測期間不修)
|
||||||
|
|
||||||
1. `if_control` false branch 不路由(條件 false 時後續節點不執行)
|
1. `if_control` false branch 不路由(條件 false 時後續節點不執行)→ 升級計畫見 P1 #1,2026-05-14 mira 用 `kbdb_upsert_block` workaround
|
||||||
2. 多節點 context 不自動解包(上游輸出 flat merge,下游需從 `data.result` 取值)
|
2. 多節點 context 不自動解包(上游輸出 flat merge,下游需從 `data.result` 取值)
|
||||||
3. 用戶自製邏輯零件(Phase 5)封測後才實作
|
3. 用戶自製邏輯零件(Phase 5)封測後才實作
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "arcrun-kbdb-upsert-block",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"dependencies": {
|
||||||
|
"hono": "^4.7.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@cloudflare/workers-types": "^4.20250408.0",
|
||||||
|
"typescript": "^5.4.0",
|
||||||
|
"wrangler": "^4.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
+898
@@ -0,0 +1,898 @@
|
|||||||
|
lockfileVersion: '9.0'
|
||||||
|
|
||||||
|
settings:
|
||||||
|
autoInstallPeers: true
|
||||||
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
|
importers:
|
||||||
|
|
||||||
|
.:
|
||||||
|
dependencies:
|
||||||
|
hono:
|
||||||
|
specifier: ^4.7.0
|
||||||
|
version: 4.12.18
|
||||||
|
devDependencies:
|
||||||
|
'@cloudflare/workers-types':
|
||||||
|
specifier: ^4.20250408.0
|
||||||
|
version: 4.20260511.1
|
||||||
|
typescript:
|
||||||
|
specifier: ^5.4.0
|
||||||
|
version: 5.9.3
|
||||||
|
wrangler:
|
||||||
|
specifier: ^4.0.0
|
||||||
|
version: 4.90.1(@cloudflare/workers-types@4.20260511.1)
|
||||||
|
|
||||||
|
packages:
|
||||||
|
|
||||||
|
'@cloudflare/kv-asset-handler@0.5.0':
|
||||||
|
resolution: {integrity: sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==}
|
||||||
|
engines: {node: '>=22.0.0'}
|
||||||
|
|
||||||
|
'@cloudflare/unenv-preset@2.16.1':
|
||||||
|
resolution: {integrity: sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==}
|
||||||
|
peerDependencies:
|
||||||
|
unenv: 2.0.0-rc.24
|
||||||
|
workerd: '>1.20260305.0 <2.0.0-0'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
workerd:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@cloudflare/workerd-darwin-64@1.20260508.1':
|
||||||
|
resolution: {integrity: sha512-IT3r6VgiSwIesL4AJbxjgxvIxwWZqM7BKkhYAzOKHl4GF2M0TxeOahUIXd+CYXVZgHX8ceEg+MXbEehPelJyNg==}
|
||||||
|
engines: {node: '>=16'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@cloudflare/workerd-darwin-arm64@1.20260508.1':
|
||||||
|
resolution: {integrity: sha512-JTVsisOJPcNKw0qovPjqyBWYahfdhUh7/9NICiG5wxaEQ45PYKdoqNq0hOAAIqvqoxsKZBvTgcPTJREPqk7avA==}
|
||||||
|
engines: {node: '>=16'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@cloudflare/workerd-linux-64@1.20260508.1':
|
||||||
|
resolution: {integrity: sha512-zO38pCc27YlsZiPYcaZnosy0/t7abXrRU3VEO1oKfUvnaCpHgphDG+VsrmHL+kntda6hrtNwg2jLeMAqqIjnjw==}
|
||||||
|
engines: {node: '>=16'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@cloudflare/workerd-linux-arm64@1.20260508.1':
|
||||||
|
resolution: {integrity: sha512-XhJa780Ia6MNIrtxn/ruZHS79b9pu5EKPfRNReaUqxy8erPT2fs93axMfFoS9kIkcaRRj/1TOUKcTeAMoywY7w==}
|
||||||
|
engines: {node: '>=16'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@cloudflare/workerd-windows-64@1.20260508.1':
|
||||||
|
resolution: {integrity: sha512-QdDOK3B/Ul1s3QmIwDrFyx9230to6LsNmWcVR8w+TYjNZuRPzqQBgusp78LO7MlqCoEl9dvIcN00jkJnLtBSfw==}
|
||||||
|
engines: {node: '>=16'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@cloudflare/workers-types@4.20260511.1':
|
||||||
|
resolution: {integrity: sha512-FA+si7cOq9i/gtCHhIc0XJL0l1F/ApF+m00752Aj7WZFJrj3ZulT2T8/+rT3BabMT0QEnqFEGIqCgrmqhgEfMg==}
|
||||||
|
|
||||||
|
'@cspotcode/source-map-support@0.8.1':
|
||||||
|
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
'@emnapi/runtime@1.10.0':
|
||||||
|
resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==}
|
||||||
|
|
||||||
|
'@esbuild/aix-ppc64@0.27.3':
|
||||||
|
resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [aix]
|
||||||
|
|
||||||
|
'@esbuild/android-arm64@0.27.3':
|
||||||
|
resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/android-arm@0.27.3':
|
||||||
|
resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/android-x64@0.27.3':
|
||||||
|
resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/darwin-arm64@0.27.3':
|
||||||
|
resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@esbuild/darwin-x64@0.27.3':
|
||||||
|
resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@esbuild/freebsd-arm64@0.27.3':
|
||||||
|
resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@esbuild/freebsd-x64@0.27.3':
|
||||||
|
resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@esbuild/linux-arm64@0.27.3':
|
||||||
|
resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-arm@0.27.3':
|
||||||
|
resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-ia32@0.27.3':
|
||||||
|
resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-loong64@0.27.3':
|
||||||
|
resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [loong64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-mips64el@0.27.3':
|
||||||
|
resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [mips64el]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-ppc64@0.27.3':
|
||||||
|
resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-riscv64@0.27.3':
|
||||||
|
resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-s390x@0.27.3':
|
||||||
|
resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-x64@0.27.3':
|
||||||
|
resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/netbsd-arm64@0.27.3':
|
||||||
|
resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [netbsd]
|
||||||
|
|
||||||
|
'@esbuild/netbsd-x64@0.27.3':
|
||||||
|
resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [netbsd]
|
||||||
|
|
||||||
|
'@esbuild/openbsd-arm64@0.27.3':
|
||||||
|
resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [openbsd]
|
||||||
|
|
||||||
|
'@esbuild/openbsd-x64@0.27.3':
|
||||||
|
resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [openbsd]
|
||||||
|
|
||||||
|
'@esbuild/openharmony-arm64@0.27.3':
|
||||||
|
resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [openharmony]
|
||||||
|
|
||||||
|
'@esbuild/sunos-x64@0.27.3':
|
||||||
|
resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [sunos]
|
||||||
|
|
||||||
|
'@esbuild/win32-arm64@0.27.3':
|
||||||
|
resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@esbuild/win32-ia32@0.27.3':
|
||||||
|
resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@esbuild/win32-x64@0.27.3':
|
||||||
|
resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@img/colour@1.1.0':
|
||||||
|
resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
'@img/sharp-darwin-arm64@0.34.5':
|
||||||
|
resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@img/sharp-darwin-x64@0.34.5':
|
||||||
|
resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-darwin-arm64@1.2.4':
|
||||||
|
resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-darwin-x64@1.2.4':
|
||||||
|
resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-arm64@1.2.4':
|
||||||
|
resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-arm@1.2.4':
|
||||||
|
resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-ppc64@1.2.4':
|
||||||
|
resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-riscv64@1.2.4':
|
||||||
|
resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-s390x@1.2.4':
|
||||||
|
resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-x64@1.2.4':
|
||||||
|
resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linuxmusl-arm64@1.2.4':
|
||||||
|
resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linuxmusl-x64@1.2.4':
|
||||||
|
resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@img/sharp-linux-arm64@0.34.5':
|
||||||
|
resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-linux-arm@0.34.5':
|
||||||
|
resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-linux-ppc64@0.34.5':
|
||||||
|
resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-linux-riscv64@0.34.5':
|
||||||
|
resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-linux-s390x@0.34.5':
|
||||||
|
resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-linux-x64@0.34.5':
|
||||||
|
resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-linuxmusl-arm64@0.34.5':
|
||||||
|
resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@img/sharp-linuxmusl-x64@0.34.5':
|
||||||
|
resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@img/sharp-wasm32@0.34.5':
|
||||||
|
resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [wasm32]
|
||||||
|
|
||||||
|
'@img/sharp-win32-arm64@0.34.5':
|
||||||
|
resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@img/sharp-win32-ia32@0.34.5':
|
||||||
|
resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@img/sharp-win32-x64@0.34.5':
|
||||||
|
resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@jridgewell/resolve-uri@3.1.2':
|
||||||
|
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
|
||||||
|
engines: {node: '>=6.0.0'}
|
||||||
|
|
||||||
|
'@jridgewell/sourcemap-codec@1.5.5':
|
||||||
|
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
|
||||||
|
|
||||||
|
'@jridgewell/trace-mapping@0.3.9':
|
||||||
|
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
|
||||||
|
|
||||||
|
'@poppinss/colors@4.1.6':
|
||||||
|
resolution: {integrity: sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==}
|
||||||
|
|
||||||
|
'@poppinss/dumper@0.6.5':
|
||||||
|
resolution: {integrity: sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==}
|
||||||
|
|
||||||
|
'@poppinss/exception@1.2.3':
|
||||||
|
resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==}
|
||||||
|
|
||||||
|
'@sindresorhus/is@7.2.0':
|
||||||
|
resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
'@speed-highlight/core@1.2.15':
|
||||||
|
resolution: {integrity: sha512-BMq1K3DsElxDWawkX6eLg9+CKJrTVGCBAWVuHXVUV2u0s2711qiChLSId6ikYPfxhdYocLNt3wWwSvDiTvFabw==}
|
||||||
|
|
||||||
|
blake3-wasm@2.1.5:
|
||||||
|
resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==}
|
||||||
|
|
||||||
|
cookie@1.1.1:
|
||||||
|
resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
detect-libc@2.1.2:
|
||||||
|
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
error-stack-parser-es@1.0.5:
|
||||||
|
resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==}
|
||||||
|
|
||||||
|
esbuild@0.27.3:
|
||||||
|
resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
fsevents@2.3.3:
|
||||||
|
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||||
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
hono@4.12.18:
|
||||||
|
resolution: {integrity: sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ==}
|
||||||
|
engines: {node: '>=16.9.0'}
|
||||||
|
|
||||||
|
kleur@4.1.5:
|
||||||
|
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
miniflare@4.20260508.0:
|
||||||
|
resolution: {integrity: sha512-h3aG+PA8jEH76V4ZtBAbs3g7kjMfHJUF8hPvxeeajLTKwir+G+dqfBODg5yF9MT29LqrZKCRQRqzfHPWX4kCIg==}
|
||||||
|
engines: {node: '>=22.0.0'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
path-to-regexp@6.3.0:
|
||||||
|
resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==}
|
||||||
|
|
||||||
|
pathe@2.0.3:
|
||||||
|
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
|
||||||
|
|
||||||
|
semver@7.8.0:
|
||||||
|
resolution: {integrity: sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
sharp@0.34.5:
|
||||||
|
resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
|
||||||
|
supports-color@10.2.2:
|
||||||
|
resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
tslib@2.8.1:
|
||||||
|
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||||
|
|
||||||
|
typescript@5.9.3:
|
||||||
|
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
|
||||||
|
engines: {node: '>=14.17'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
undici@7.24.8:
|
||||||
|
resolution: {integrity: sha512-6KQ/+QxK49Z/p3HO6E5ZCZWNnCasyZLa5ExaVYyvPxUwKtbCPMKELJOqh7EqOle0t9cH/7d2TaaTRRa6Nhs4YQ==}
|
||||||
|
engines: {node: '>=20.18.1'}
|
||||||
|
|
||||||
|
unenv@2.0.0-rc.24:
|
||||||
|
resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==}
|
||||||
|
|
||||||
|
workerd@1.20260508.1:
|
||||||
|
resolution: {integrity: sha512-VlnjyH3AjVddpSK7J54nsCVgf8i2733pl8GjKttfNi7vN/hEjjAk20d2b1nDToOLKvRQpTewRnVkqaaeGHCaAw==}
|
||||||
|
engines: {node: '>=16'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
wrangler@4.90.1:
|
||||||
|
resolution: {integrity: sha512-u2KrieKSMfRM0toTst/CfDtcRraeoVjmcExcMWgILM/ytq3qcDhuOAULoZSyPHzma43lfLJy1BC544drFyqe1A==}
|
||||||
|
engines: {node: '>=22.0.0'}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
'@cloudflare/workers-types': ^4.20260508.1
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@cloudflare/workers-types':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
ws@8.18.0:
|
||||||
|
resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
bufferutil: ^4.0.1
|
||||||
|
utf-8-validate: '>=5.0.2'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
bufferutil:
|
||||||
|
optional: true
|
||||||
|
utf-8-validate:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
youch-core@0.3.3:
|
||||||
|
resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==}
|
||||||
|
|
||||||
|
youch@4.1.0-beta.10:
|
||||||
|
resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==}
|
||||||
|
|
||||||
|
snapshots:
|
||||||
|
|
||||||
|
'@cloudflare/kv-asset-handler@0.5.0': {}
|
||||||
|
|
||||||
|
'@cloudflare/unenv-preset@2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260508.1)':
|
||||||
|
dependencies:
|
||||||
|
unenv: 2.0.0-rc.24
|
||||||
|
optionalDependencies:
|
||||||
|
workerd: 1.20260508.1
|
||||||
|
|
||||||
|
'@cloudflare/workerd-darwin-64@1.20260508.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@cloudflare/workerd-darwin-arm64@1.20260508.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@cloudflare/workerd-linux-64@1.20260508.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@cloudflare/workerd-linux-arm64@1.20260508.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@cloudflare/workerd-windows-64@1.20260508.1':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@cloudflare/workers-types@4.20260511.1': {}
|
||||||
|
|
||||||
|
'@cspotcode/source-map-support@0.8.1':
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/trace-mapping': 0.3.9
|
||||||
|
|
||||||
|
'@emnapi/runtime@1.10.0':
|
||||||
|
dependencies:
|
||||||
|
tslib: 2.8.1
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/aix-ppc64@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/android-arm64@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/android-arm@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/android-x64@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/darwin-arm64@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/darwin-x64@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/freebsd-arm64@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/freebsd-x64@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-arm64@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-arm@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-ia32@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-loong64@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-mips64el@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-ppc64@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-riscv64@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-s390x@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-x64@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/netbsd-arm64@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/netbsd-x64@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/openbsd-arm64@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/openbsd-x64@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/openharmony-arm64@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/sunos-x64@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/win32-arm64@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/win32-ia32@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/win32-x64@0.27.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/colour@1.1.0': {}
|
||||||
|
|
||||||
|
'@img/sharp-darwin-arm64@0.34.5':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-darwin-arm64': 1.2.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-darwin-x64@0.34.5':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-darwin-x64': 1.2.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-darwin-arm64@1.2.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-darwin-x64@1.2.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-arm64@1.2.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-arm@1.2.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-ppc64@1.2.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-riscv64@1.2.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-s390x@1.2.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-x64@1.2.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linuxmusl-arm64@1.2.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linuxmusl-x64@1.2.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-arm64@0.34.5':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-arm64': 1.2.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-arm@0.34.5':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-arm': 1.2.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-ppc64@0.34.5':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-ppc64': 1.2.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-riscv64@0.34.5':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-riscv64': 1.2.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-s390x@0.34.5':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-s390x': 1.2.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-x64@0.34.5':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-x64': 1.2.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linuxmusl-arm64@0.34.5':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linuxmusl-arm64': 1.2.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linuxmusl-x64@0.34.5':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linuxmusl-x64': 1.2.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-wasm32@0.34.5':
|
||||||
|
dependencies:
|
||||||
|
'@emnapi/runtime': 1.10.0
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-win32-arm64@0.34.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-win32-ia32@0.34.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-win32-x64@0.34.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@jridgewell/resolve-uri@3.1.2': {}
|
||||||
|
|
||||||
|
'@jridgewell/sourcemap-codec@1.5.5': {}
|
||||||
|
|
||||||
|
'@jridgewell/trace-mapping@0.3.9':
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|
||||||
|
'@poppinss/colors@4.1.6':
|
||||||
|
dependencies:
|
||||||
|
kleur: 4.1.5
|
||||||
|
|
||||||
|
'@poppinss/dumper@0.6.5':
|
||||||
|
dependencies:
|
||||||
|
'@poppinss/colors': 4.1.6
|
||||||
|
'@sindresorhus/is': 7.2.0
|
||||||
|
supports-color: 10.2.2
|
||||||
|
|
||||||
|
'@poppinss/exception@1.2.3': {}
|
||||||
|
|
||||||
|
'@sindresorhus/is@7.2.0': {}
|
||||||
|
|
||||||
|
'@speed-highlight/core@1.2.15': {}
|
||||||
|
|
||||||
|
blake3-wasm@2.1.5: {}
|
||||||
|
|
||||||
|
cookie@1.1.1: {}
|
||||||
|
|
||||||
|
detect-libc@2.1.2: {}
|
||||||
|
|
||||||
|
error-stack-parser-es@1.0.5: {}
|
||||||
|
|
||||||
|
esbuild@0.27.3:
|
||||||
|
optionalDependencies:
|
||||||
|
'@esbuild/aix-ppc64': 0.27.3
|
||||||
|
'@esbuild/android-arm': 0.27.3
|
||||||
|
'@esbuild/android-arm64': 0.27.3
|
||||||
|
'@esbuild/android-x64': 0.27.3
|
||||||
|
'@esbuild/darwin-arm64': 0.27.3
|
||||||
|
'@esbuild/darwin-x64': 0.27.3
|
||||||
|
'@esbuild/freebsd-arm64': 0.27.3
|
||||||
|
'@esbuild/freebsd-x64': 0.27.3
|
||||||
|
'@esbuild/linux-arm': 0.27.3
|
||||||
|
'@esbuild/linux-arm64': 0.27.3
|
||||||
|
'@esbuild/linux-ia32': 0.27.3
|
||||||
|
'@esbuild/linux-loong64': 0.27.3
|
||||||
|
'@esbuild/linux-mips64el': 0.27.3
|
||||||
|
'@esbuild/linux-ppc64': 0.27.3
|
||||||
|
'@esbuild/linux-riscv64': 0.27.3
|
||||||
|
'@esbuild/linux-s390x': 0.27.3
|
||||||
|
'@esbuild/linux-x64': 0.27.3
|
||||||
|
'@esbuild/netbsd-arm64': 0.27.3
|
||||||
|
'@esbuild/netbsd-x64': 0.27.3
|
||||||
|
'@esbuild/openbsd-arm64': 0.27.3
|
||||||
|
'@esbuild/openbsd-x64': 0.27.3
|
||||||
|
'@esbuild/openharmony-arm64': 0.27.3
|
||||||
|
'@esbuild/sunos-x64': 0.27.3
|
||||||
|
'@esbuild/win32-arm64': 0.27.3
|
||||||
|
'@esbuild/win32-ia32': 0.27.3
|
||||||
|
'@esbuild/win32-x64': 0.27.3
|
||||||
|
|
||||||
|
fsevents@2.3.3:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
hono@4.12.18: {}
|
||||||
|
|
||||||
|
kleur@4.1.5: {}
|
||||||
|
|
||||||
|
miniflare@4.20260508.0:
|
||||||
|
dependencies:
|
||||||
|
'@cspotcode/source-map-support': 0.8.1
|
||||||
|
sharp: 0.34.5
|
||||||
|
undici: 7.24.8
|
||||||
|
workerd: 1.20260508.1
|
||||||
|
ws: 8.18.0
|
||||||
|
youch: 4.1.0-beta.10
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- bufferutil
|
||||||
|
- utf-8-validate
|
||||||
|
|
||||||
|
path-to-regexp@6.3.0: {}
|
||||||
|
|
||||||
|
pathe@2.0.3: {}
|
||||||
|
|
||||||
|
semver@7.8.0: {}
|
||||||
|
|
||||||
|
sharp@0.34.5:
|
||||||
|
dependencies:
|
||||||
|
'@img/colour': 1.1.0
|
||||||
|
detect-libc: 2.1.2
|
||||||
|
semver: 7.8.0
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-darwin-arm64': 0.34.5
|
||||||
|
'@img/sharp-darwin-x64': 0.34.5
|
||||||
|
'@img/sharp-libvips-darwin-arm64': 1.2.4
|
||||||
|
'@img/sharp-libvips-darwin-x64': 1.2.4
|
||||||
|
'@img/sharp-libvips-linux-arm': 1.2.4
|
||||||
|
'@img/sharp-libvips-linux-arm64': 1.2.4
|
||||||
|
'@img/sharp-libvips-linux-ppc64': 1.2.4
|
||||||
|
'@img/sharp-libvips-linux-riscv64': 1.2.4
|
||||||
|
'@img/sharp-libvips-linux-s390x': 1.2.4
|
||||||
|
'@img/sharp-libvips-linux-x64': 1.2.4
|
||||||
|
'@img/sharp-libvips-linuxmusl-arm64': 1.2.4
|
||||||
|
'@img/sharp-libvips-linuxmusl-x64': 1.2.4
|
||||||
|
'@img/sharp-linux-arm': 0.34.5
|
||||||
|
'@img/sharp-linux-arm64': 0.34.5
|
||||||
|
'@img/sharp-linux-ppc64': 0.34.5
|
||||||
|
'@img/sharp-linux-riscv64': 0.34.5
|
||||||
|
'@img/sharp-linux-s390x': 0.34.5
|
||||||
|
'@img/sharp-linux-x64': 0.34.5
|
||||||
|
'@img/sharp-linuxmusl-arm64': 0.34.5
|
||||||
|
'@img/sharp-linuxmusl-x64': 0.34.5
|
||||||
|
'@img/sharp-wasm32': 0.34.5
|
||||||
|
'@img/sharp-win32-arm64': 0.34.5
|
||||||
|
'@img/sharp-win32-ia32': 0.34.5
|
||||||
|
'@img/sharp-win32-x64': 0.34.5
|
||||||
|
|
||||||
|
supports-color@10.2.2: {}
|
||||||
|
|
||||||
|
tslib@2.8.1:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
typescript@5.9.3: {}
|
||||||
|
|
||||||
|
undici@7.24.8: {}
|
||||||
|
|
||||||
|
unenv@2.0.0-rc.24:
|
||||||
|
dependencies:
|
||||||
|
pathe: 2.0.3
|
||||||
|
|
||||||
|
workerd@1.20260508.1:
|
||||||
|
optionalDependencies:
|
||||||
|
'@cloudflare/workerd-darwin-64': 1.20260508.1
|
||||||
|
'@cloudflare/workerd-darwin-arm64': 1.20260508.1
|
||||||
|
'@cloudflare/workerd-linux-64': 1.20260508.1
|
||||||
|
'@cloudflare/workerd-linux-arm64': 1.20260508.1
|
||||||
|
'@cloudflare/workerd-windows-64': 1.20260508.1
|
||||||
|
|
||||||
|
wrangler@4.90.1(@cloudflare/workers-types@4.20260511.1):
|
||||||
|
dependencies:
|
||||||
|
'@cloudflare/kv-asset-handler': 0.5.0
|
||||||
|
'@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260508.1)
|
||||||
|
blake3-wasm: 2.1.5
|
||||||
|
esbuild: 0.27.3
|
||||||
|
miniflare: 4.20260508.0
|
||||||
|
path-to-regexp: 6.3.0
|
||||||
|
unenv: 2.0.0-rc.24
|
||||||
|
workerd: 1.20260508.1
|
||||||
|
optionalDependencies:
|
||||||
|
'@cloudflare/workers-types': 4.20260511.1
|
||||||
|
fsevents: 2.3.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- bufferutil
|
||||||
|
- utf-8-validate
|
||||||
|
|
||||||
|
ws@8.18.0: {}
|
||||||
|
|
||||||
|
youch-core@0.3.3:
|
||||||
|
dependencies:
|
||||||
|
'@poppinss/exception': 1.2.3
|
||||||
|
error-stack-parser-es: 1.0.5
|
||||||
|
|
||||||
|
youch@4.1.0-beta.10:
|
||||||
|
dependencies:
|
||||||
|
'@poppinss/colors': 4.1.6
|
||||||
|
'@poppinss/dumper': 0.6.5
|
||||||
|
'@speed-highlight/core': 1.2.15
|
||||||
|
cookie: 1.1.1
|
||||||
|
youch-core: 0.3.3
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/**
|
||||||
|
* arcrun WASM 零件 Worker (kbdb_upsert_block)
|
||||||
|
* POST / → JSON input → WASM (WASI preview1) → JSON output
|
||||||
|
* SDD: polaris/mira/.agents/specs/mira-app/design.md §3.5.12.4.1
|
||||||
|
* matrix/arcrun/.agents/specs/arcrun/arcrun.md 三-B 新零件加入紀錄
|
||||||
|
*/
|
||||||
|
|
||||||
|
import componentWasm from '../component.wasm' assert { type: 'webassembly' };
|
||||||
|
import { Hono } from 'hono';
|
||||||
|
import { cors } from 'hono/cors';
|
||||||
|
import { createWasiShim, type WasiHostFunctions } from '../../../cypher-executor/src/lib/wasi-shim';
|
||||||
|
|
||||||
|
const app = new Hono();
|
||||||
|
app.use('*', cors());
|
||||||
|
|
||||||
|
app.get('/', (c) => c.json({ ok: true, component: 'kbdb_upsert_block' }));
|
||||||
|
|
||||||
|
app.post('/', async (c) => {
|
||||||
|
let input: unknown;
|
||||||
|
try {
|
||||||
|
input = await c.req.json();
|
||||||
|
} catch {
|
||||||
|
return c.json({ success: false, error: 'request body must be JSON' }, 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await runWasm(input);
|
||||||
|
return c.json(result);
|
||||||
|
} catch (e) {
|
||||||
|
return c.json(
|
||||||
|
{ success: false, error: e instanceof Error ? e.message : String(e) },
|
||||||
|
500,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default app;
|
||||||
|
|
||||||
|
async function runWasm(input: unknown): Promise<unknown> {
|
||||||
|
const hostFunctions: WasiHostFunctions = {
|
||||||
|
http_request: async (url, method, headersJson, body) => {
|
||||||
|
const headers: Record<string, string> = {};
|
||||||
|
if (headersJson) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(headersJson);
|
||||||
|
if (parsed && typeof parsed === 'object') {
|
||||||
|
for (const [k, v] of Object.entries(parsed as Record<string, unknown>)) {
|
||||||
|
if (typeof v === 'string') headers[k] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
const init: RequestInit = { method, headers };
|
||||||
|
if (body && method.toUpperCase() !== 'GET' && method.toUpperCase() !== 'HEAD') {
|
||||||
|
init.body = body;
|
||||||
|
}
|
||||||
|
const res = await fetch(url, init);
|
||||||
|
return await res.text();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const shim = createWasiShim(JSON.stringify(input), hostFunctions);
|
||||||
|
const instance = await WebAssembly.instantiate(
|
||||||
|
componentWasm as WebAssembly.Module,
|
||||||
|
shim.imports,
|
||||||
|
);
|
||||||
|
shim.setMemory(instance.exports.memory as WebAssembly.Memory);
|
||||||
|
await shim.run(instance);
|
||||||
|
|
||||||
|
const stdout = shim.getStdout().trim();
|
||||||
|
const stderr = shim.getStderr().trim();
|
||||||
|
if (stderr) console.error('[kbdb_upsert_block wasm stderr]', stderr);
|
||||||
|
if (!stdout) throw new Error('WASM component produced no output');
|
||||||
|
return JSON.parse(stdout);
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "ES2022",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"lib": ["ES2022"],
|
||||||
|
"types": ["@cloudflare/workers-types"],
|
||||||
|
"strict": true,
|
||||||
|
"noEmit": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
name = "arcrun-kbdb-upsert-block"
|
||||||
|
main = "src/index.ts"
|
||||||
|
compatibility_date = "2025-02-19"
|
||||||
|
compatibility_flags = ["nodejs_compat"]
|
||||||
|
|
||||||
|
[vars]
|
||||||
|
COMPONENT_ID = "kbdb_upsert_block"
|
||||||
|
|
||||||
|
[[routes]]
|
||||||
|
pattern = "kbdb-upsert-block.arcrun.dev/*"
|
||||||
|
zone_name = "arcrun.dev"
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
canonical_id: "kbdb_upsert_block"
|
||||||
|
display_name: "KBDB Upsert Block"
|
||||||
|
category: "data"
|
||||||
|
version: "v1"
|
||||||
|
wasi_target: "preview1"
|
||||||
|
stability: "floating"
|
||||||
|
runtime_compat:
|
||||||
|
- "cf-workers"
|
||||||
|
- "workerd"
|
||||||
|
- "wazero"
|
||||||
|
constraints:
|
||||||
|
max_size_kb: 2048
|
||||||
|
max_cold_start_ms: 50
|
||||||
|
no_network_syscall: false
|
||||||
|
no_filesystem_syscall: true
|
||||||
|
io_model: "stdin_stdout_json"
|
||||||
|
input_schema:
|
||||||
|
type: object
|
||||||
|
required: [api_key, page_name, content]
|
||||||
|
properties:
|
||||||
|
api_key:
|
||||||
|
type: string
|
||||||
|
description: KBDB partner key(ak_xxx)
|
||||||
|
page_name:
|
||||||
|
type: string
|
||||||
|
description: 當 idempotency key。內部用 GET /blocks?page_name= 查找。
|
||||||
|
content:
|
||||||
|
type: string
|
||||||
|
description: block 內容(PATCH 時覆寫,CREATE 時新建)
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
description: block type(建立時用,PATCH 時忽略)
|
||||||
|
parent_id:
|
||||||
|
type: string
|
||||||
|
description: 父 block id(建立時用,PATCH 時忽略)
|
||||||
|
user_id:
|
||||||
|
type: string
|
||||||
|
description: 建立時帶入 + lookup 時用來 filter(同 page_name 多 user 共存場景)
|
||||||
|
source:
|
||||||
|
type: string
|
||||||
|
description: 來源標記
|
||||||
|
tags_json:
|
||||||
|
type: string
|
||||||
|
description: tags JSON 字串(PATCH 時轉 array、CREATE 時直傳)
|
||||||
|
kbdb_url:
|
||||||
|
type: string
|
||||||
|
description: KBDB API base(預設 https://kbdb.finally.click)
|
||||||
|
output_schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
success:
|
||||||
|
type: boolean
|
||||||
|
action:
|
||||||
|
type: string
|
||||||
|
enum: [created, patched]
|
||||||
|
description: 實際做了哪個動作
|
||||||
|
data:
|
||||||
|
type: object
|
||||||
|
description: KBDB 回傳(含 block id 等)
|
||||||
|
error:
|
||||||
|
type: string
|
||||||
|
phase:
|
||||||
|
type: string
|
||||||
|
enum: [lookup, patch, create]
|
||||||
|
description: 出錯在哪個階段
|
||||||
|
gherkin_tests:
|
||||||
|
- scenario: "缺 page_name"
|
||||||
|
given: '{"api_key":"ak_x","content":"hi"}'
|
||||||
|
then_contains: '"success":false'
|
||||||
|
- scenario: "建立新 block"
|
||||||
|
given: '{"api_key":"ak_x","page_name":"new-page-uniq","content":"hello"}'
|
||||||
|
then_contains: '"action":"created"'
|
||||||
|
- scenario: "PATCH 既有 block"
|
||||||
|
given: '{"api_key":"ak_x","page_name":"existing-page","content":"updated"}'
|
||||||
|
then_contains: '"action":"patched"'
|
||||||
|
tags: [data, storage, kbdb, upsert, primitive, idempotent]
|
||||||
|
description: |
|
||||||
|
Upsert:用 page_name 當 idempotency key。內部 GET 找有沒有同 page_name 的 block,
|
||||||
|
找到就 PATCH 不到就 POST 新建。解 arcrun workflow 缺 IF/branch 能力的缺口
|
||||||
|
(arcrun.md P1 #1)。mira 7B.3f index-entry per-entity 維護是第一個使用者。
|
||||||
|
config_example: |
|
||||||
|
upsert_index_entry:
|
||||||
|
api_key: "{{api_key}}"
|
||||||
|
page_name: "index-{{entity}}"
|
||||||
|
parent_id: "{{mira_wiki_index_entities_id}}"
|
||||||
|
type: "index-entry"
|
||||||
|
user_id: "inkstone_mira_tools"
|
||||||
|
source: "ai-canon-wiki"
|
||||||
|
content: "{{compose_index_entry.data.text}}"
|
||||||
|
tags_json: '["mira-wiki", "ai-generated", "index"]'
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
module kbdb_upsert_block
|
||||||
|
|
||||||
|
go 1.21
|
||||||
@@ -0,0 +1,271 @@
|
|||||||
|
// kbdb_upsert_block — 用 page_name 當 idempotency key 做 upsert
|
||||||
|
// 內部:GET /blocks?page_name=X → user_id filter → 找到 PATCH /blocks/:id 沒找到 POST /blocks
|
||||||
|
// 解 arcrun workflow 沒 IF/branch 能力的缺口(arcrun.md P1 #1)
|
||||||
|
// 對應 SDD:polaris/mira/.agents/specs/mira-app/design.md §3.5.12.4.1
|
||||||
|
//
|
||||||
|
//go:build tinygo
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:wasmimport u6u http_request
|
||||||
|
func hostHttpRequest(
|
||||||
|
urlPtr uintptr, urlLen uint32,
|
||||||
|
methodPtr uintptr, methodLen uint32,
|
||||||
|
headersPtr uintptr, headersLen uint32,
|
||||||
|
bodyPtr uintptr, bodyLen uint32,
|
||||||
|
outPtr uintptr, outLenPtr uintptr,
|
||||||
|
) uint32
|
||||||
|
|
||||||
|
type Input struct {
|
||||||
|
KBDBUrl string `json:"kbdb_url"` // optional
|
||||||
|
APIKey string `json:"api_key"` // 必填
|
||||||
|
PageName string `json:"page_name"` // 必填,當 idempotency key
|
||||||
|
Content string `json:"content"` // 必填
|
||||||
|
Type string `json:"type"` // optional(建立時用,PATCH 時忽略)
|
||||||
|
ParentID string `json:"parent_id"` // optional(建立時用,PATCH 時忽略)
|
||||||
|
UserID string `json:"user_id"` // optional(建立時用 + lookup filter)
|
||||||
|
Source string `json:"source"` // optional
|
||||||
|
TagsJSON string `json:"tags_json"` // optional(完整覆寫)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummy [1]byte
|
||||||
|
|
||||||
|
func safePtr(b []byte) (uintptr, uint32) {
|
||||||
|
if len(b) == 0 {
|
||||||
|
return uintptr(unsafe.Pointer(&dummy[0])), 0
|
||||||
|
}
|
||||||
|
return uintptr(unsafe.Pointer(&b[0])), uint32(len(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeError(msg string) {
|
||||||
|
out, _ := json.Marshal(map[string]interface{}{"success": false, "error": msg})
|
||||||
|
os.Stdout.Write(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeResult(action string, data map[string]interface{}) {
|
||||||
|
out, _ := json.Marshal(map[string]interface{}{
|
||||||
|
"success": true,
|
||||||
|
"action": action,
|
||||||
|
"data": data,
|
||||||
|
})
|
||||||
|
os.Stdout.Write(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// urlEncode:跟 kbdb_get 一致,避免引入 net/url
|
||||||
|
func urlEncode(s string) string {
|
||||||
|
var out []byte
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
c := s[i]
|
||||||
|
if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') ||
|
||||||
|
c == '-' || c == '_' || c == '.' || c == '~' {
|
||||||
|
out = append(out, c)
|
||||||
|
} else {
|
||||||
|
const hex = "0123456789ABCDEF"
|
||||||
|
out = append(out, '%', hex[c>>4], hex[c&0x0f])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func httpCall(method, url string, headers map[string]string, body []byte) ([]byte, uint32) {
|
||||||
|
headersBytes, _ := json.Marshal(headers)
|
||||||
|
urlBytes := []byte(url)
|
||||||
|
methodBytes := []byte(method)
|
||||||
|
|
||||||
|
outBuf := make([]byte, 1<<20) // 1MB
|
||||||
|
var outLen uint32
|
||||||
|
|
||||||
|
urlPtr, urlLen := safePtr(urlBytes)
|
||||||
|
methodPtr, methodLen := safePtr(methodBytes)
|
||||||
|
headersPtr, headersLenU := safePtr(headersBytes)
|
||||||
|
bodyPtr, bodyLenU := safePtr(body)
|
||||||
|
|
||||||
|
result := hostHttpRequest(
|
||||||
|
urlPtr, urlLen,
|
||||||
|
methodPtr, methodLen,
|
||||||
|
headersPtr, headersLenU,
|
||||||
|
bodyPtr, bodyLenU,
|
||||||
|
uintptr(unsafe.Pointer(&outBuf[0])), uintptr(unsafe.Pointer(&outLen)),
|
||||||
|
)
|
||||||
|
return outBuf[:outLen], result
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
raw, err := io.ReadAll(os.Stdin)
|
||||||
|
if err != nil {
|
||||||
|
writeError("failed to read stdin: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var input Input
|
||||||
|
if err := json.Unmarshal(raw, &input); err != nil {
|
||||||
|
writeError("invalid input JSON: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.APIKey == "" {
|
||||||
|
writeError("api_key 必填")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if input.PageName == "" {
|
||||||
|
writeError("page_name 必填(upsert 的 idempotency key)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if input.Content == "" {
|
||||||
|
writeError("content 必填")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
kbdbURL := input.KBDBUrl
|
||||||
|
if kbdbURL == "" {
|
||||||
|
kbdbURL = "https://kbdb.finally.click"
|
||||||
|
}
|
||||||
|
|
||||||
|
headers := map[string]string{
|
||||||
|
"Authorization": "Bearer " + input.APIKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Step 1:lookup by page_name ────────────────────────────────────
|
||||||
|
lookupURL := kbdbURL + "/blocks?page_name=" + urlEncode(input.PageName) +
|
||||||
|
"&limit=" + strconv.Itoa(10)
|
||||||
|
lookupResp, callResult := httpCall("GET", lookupURL, headers, nil)
|
||||||
|
if callResult != 0 {
|
||||||
|
writeError("KBDB lookup failed (host_http_request returned non-zero)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var lookupParsed struct {
|
||||||
|
Blocks []map[string]interface{} `json:"blocks"`
|
||||||
|
Count int `json:"count"`
|
||||||
|
Error interface{} `json:"error"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(lookupResp, &lookupParsed); err != nil {
|
||||||
|
writeError("KBDB lookup returned non-JSON: " + string(lookupResp))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if lookupParsed.Error != nil {
|
||||||
|
errBytes, _ := json.Marshal(map[string]interface{}{
|
||||||
|
"success": false,
|
||||||
|
"error": lookupParsed.Error,
|
||||||
|
"phase": "lookup",
|
||||||
|
})
|
||||||
|
os.Stdout.Write(errBytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Step 2:找符合 user_id 的第一筆 ──────────────────────────────
|
||||||
|
var existing map[string]interface{}
|
||||||
|
for _, b := range lookupParsed.Blocks {
|
||||||
|
if input.UserID == "" {
|
||||||
|
existing = b
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if uid, ok := b["user_id"].(string); ok && uid == input.UserID {
|
||||||
|
existing = b
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Step 3:分支寫入 ───────────────────────────────────────────────
|
||||||
|
postHeaders := map[string]string{
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": "Bearer " + input.APIKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
if existing != nil {
|
||||||
|
// PATCH 路徑
|
||||||
|
existingID, _ := existing["id"].(string)
|
||||||
|
if existingID == "" {
|
||||||
|
writeError("lookup 找到 block 但 id 為空")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
patchBody := make(map[string]interface{})
|
||||||
|
patchBody["content"] = input.Content
|
||||||
|
if input.Source != "" {
|
||||||
|
patchBody["source"] = input.Source
|
||||||
|
}
|
||||||
|
if input.TagsJSON != "" {
|
||||||
|
// PATCH endpoint 用 tags array 不是 tags_json string
|
||||||
|
var tagsArr []string
|
||||||
|
if err := json.Unmarshal([]byte(input.TagsJSON), &tagsArr); err == nil {
|
||||||
|
patchBody["tags"] = tagsArr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
patchBodyBytes, _ := json.Marshal(patchBody)
|
||||||
|
|
||||||
|
patchURL := kbdbURL + "/blocks/" + existingID
|
||||||
|
patchResp, callResult := httpCall("PATCH", patchURL, postHeaders, patchBodyBytes)
|
||||||
|
if callResult != 0 {
|
||||||
|
writeError("KBDB PATCH failed (host_http_request returned non-zero)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var patchParsed map[string]interface{}
|
||||||
|
if err := json.Unmarshal(patchResp, &patchParsed); err != nil {
|
||||||
|
writeError("KBDB PATCH returned non-JSON: " + string(patchResp))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, hasErr := patchParsed["error"]; hasErr {
|
||||||
|
errBytes, _ := json.Marshal(map[string]interface{}{
|
||||||
|
"success": false,
|
||||||
|
"error": patchParsed["error"],
|
||||||
|
"phase": "patch",
|
||||||
|
})
|
||||||
|
os.Stdout.Write(errBytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeResult("patched", patchParsed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CREATE 路徑
|
||||||
|
postBody := make(map[string]interface{})
|
||||||
|
postBody["content"] = input.Content
|
||||||
|
postBody["page_name"] = input.PageName
|
||||||
|
if input.Type != "" {
|
||||||
|
postBody["type"] = input.Type
|
||||||
|
}
|
||||||
|
if input.ParentID != "" {
|
||||||
|
postBody["parent_id"] = input.ParentID
|
||||||
|
}
|
||||||
|
if input.UserID != "" {
|
||||||
|
postBody["user_id"] = input.UserID
|
||||||
|
}
|
||||||
|
if input.Source != "" {
|
||||||
|
postBody["source"] = input.Source
|
||||||
|
}
|
||||||
|
if input.TagsJSON != "" {
|
||||||
|
postBody["tags_json"] = input.TagsJSON
|
||||||
|
}
|
||||||
|
postBodyBytes, _ := json.Marshal(postBody)
|
||||||
|
|
||||||
|
postURL := kbdbURL + "/blocks"
|
||||||
|
postResp, callResult := httpCall("POST", postURL, postHeaders, postBodyBytes)
|
||||||
|
if callResult != 0 {
|
||||||
|
writeError("KBDB POST failed (host_http_request returned non-zero)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var postParsed map[string]interface{}
|
||||||
|
if err := json.Unmarshal(postResp, &postParsed); err != nil {
|
||||||
|
writeError("KBDB POST returned non-JSON: " + string(postResp))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, hasErr := postParsed["error"]; hasErr {
|
||||||
|
errBytes, _ := json.Marshal(map[string]interface{}{
|
||||||
|
"success": false,
|
||||||
|
"error": postParsed["error"],
|
||||||
|
"phase": "create",
|
||||||
|
})
|
||||||
|
os.Stdout.Write(errBytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeResult("created", postParsed)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user