起初在構建 MoeKoe Music 插件生態時,還沒有線上插件市場這個功能
後來在社區的建議下便有了這個插件市場 增加官方/社區插件倉庫以擴展產品功能
插件可以由社區開發,那插件市場應該怎麼管?
最直接的做法當然是把所有插件源碼都收進一個大倉庫裡。但這個方案越想越彆扭。每個插件都有自己的作者、自己的發佈節奏、自己的構建方式。把它們全塞進官方倉庫,不僅維護成本高,也會把責任邊界搞得很模糊。
所以這個倉庫最後沒有被設計成「插件源碼倉庫」,而是變成了一個「插件登記與索引倉庫」。它只做幾件事:
- 接收插件上架、更新、下架和舉報申請
- 自動做一輪基礎校驗和靜態識別
- 把人工審核通過時的插件快照記錄下來
- 維護客戶端可以讀取的
plugins.json - 順手把 README 裡的插件列表更新出來,方便人看
一個可追溯的登記簿:誰提交的、審核的是哪個版本、下載地址是什麼、是否有網絡或文件權限,都落在一份清楚的數據裡。
市場索引,而不是源碼倉庫
倉庫根目錄最重要的文件是 plugins.json。它就是插件市場真正消費的數據源。
{
"id": "custom-app-background",
"name": "自定義背景圖",
"description": "為MoeKoe Music提供自定義背景圖能力,支持透明度調節。",
"iconUrl": "...",
"version": "1.0.0",
"minversion": "1.6.1",
"...":"....",
"buildRequired": false,
"networkAccess": false,
"fileAccess": false,
"binaryContent": false,
"snapshot": {
"iconUrl": "...",
"repository": "MoeKoeMusic/custom-app-background-plugin",
"commitSha": "dbf72d38c8cf6b1d1cefdf8ce15798d565678995",
"downloadUrl": "hxx.zip",
"release": null
}
}
我不想讓市場記錄永遠指向插件倉庫「當前最新代碼」。因為作者今天提交的代碼,和審核那天看到的代碼,可能已經不是同一份東西了。插件市場真正應該承認的是:審核通過時的那個版本。
所以這個專案裡面有一個核心原則:
上架的不是一個會漂移的倉庫地址,而是一個已經鎖定的快照。
對於不需要編譯的插件,快照鎖到默認分支當時的 commit。對於需要編譯的插件,快照鎖到對應的 Release tag 和發行附件。這樣後面真出了問題,也能回頭知道當時到底審核了什麼。
Action 先跑,人最後拍板
用戶提交 Issue 時,需要選擇:
- 是「新上架」還是「更新插件」
- GitHub 倉庫地址
- 安裝前是否需要編譯
Action做自動校驗,然後把結果寫回 Issue 評論,同時給 Issue 打上 check-passed 或 check-failed 標籤。
自動化負責整理事實,人負責做最終判斷:
- 用戶用 Issue 模板提交插件
- Action 解析 Issue 表單
- 校驗倉庫、manifest、版本、作者權限
- 鎖定插件快照
- 自動評論校驗結果
- 維護者人工查看
- 維護者用
Close as completed關閉 Issue - 另一個 Action 讀取校驗結果,生成更新
plugins.json和README.md的 PR - PR 合併後,插件正式進入市場索引
這裡的「關閉方式」也被利用了起來。如果 Issue 是 Close as not planned,腳本不會執行入庫。也就是說,GitHub 原生的 Issue 狀態就被拿來當成了審核按鈕。
快照機制
如果用戶說「安裝前不需要編譯」:
- 讀取倉庫默認分支
- 拿到當前 commit sha
- 用這個 commit 去讀取
manifest.json - 生成固定 commit 的源碼 zip 地址
- 下載 zip,解壓後做權限掃描
- 生成
repository-tree類型快照
如果用戶說「需要編譯」:
- 找最新可用 Release
- 取 Release 裡的第一個附件
- 下載發行附件
- 解壓附件並讀取其中的
manifest.json - 生成
release-asset類型快照
這兩個路徑解決的是同一個問題:不管插件源頭怎麼發佈,最後都要得到一份可審核、可下載、可追溯的快照,不會因為最新倉庫的變動而導致用戶下載的插件非審核時的版本。
權限識別
安全審核這件事,不能只靠腳本拍腦袋。但腳本可以先幫維護者把風險點標出來:
- manifest 裡聲明了什麼權限
- 源碼或發行包裡是否出現了典型 API 或可執行文件
它不是只給出「有風險」這幾個字,而是會告訴你為什麼判斷有這個能力,比如:
- manifest 聲明了網絡訪問
- 源碼裡用了
fetch - 發現了
.exe、.dll、.node之類可執行內容 - 源碼裡用了
localStorage或indexedDB
這當然不是完美的安全掃描。它會有漏報,也可能有誤報。但它的定位不是取代人工審核,而是把維護者最應該多看一眼的地方提前圈出來。
它不是「審判官」,更像「標註筆」。
隱藏快照數據
校驗完成後,會在 Issue 下寫一條評論。評論裡除了人能讀懂的結果,還有一個隱藏的 payload。
它會生成類似這樣的 HTML 註解:
<!-- plugin-publish-snapshot:base64... -->
這個設計挺巧的。因為 GitHub Actions 的不同 workflow 之間不是一直共享內存的。上架校驗發生在 Issue 創建或編輯時,真正入庫發生在 Issue 被關閉時。中間可能隔了幾小時甚至幾天。
那關閉時怎麼知道當初校驗通過的是哪個快照?
答案就是:從 Issue 評論裡讀回來。
這讓 Issue 評論不只是「提示信息」,還變成了一份輕量的審核記錄。它不需要額外數據庫,也不用搭服務,直接借用了 GitHub 本身的記錄能力。
入庫動作
真正寫入 plugins.json 的腳本是 scripts/publish-plugin-close.js。
它先做幾道門:
- 當前事件必須是 publish 類 Issue
- Issue 必須是
state_reason === 'completed' - 關閉 Issue 的用戶必須是倉庫維護者
- 校驗評論裡的 payload 必須是
check-passed - payload 必須有鎖定的
downloadUrl
這幾道門保證了一個事情:普通用戶不能靠關閉 Issue 或偽造流程把插件寫進市場。
這裡有一個細節:更新插件時,會保留原作者,不會因為別人提交更新 Issue 就改掉作者字段。同時更新必須由原作者本人提交,倉庫地址也必須和現有記錄一致。
新的或更新後的插件會放到列表最前面。這個選擇也挺符合插件市場的直覺:最新通過審核的內容排在前面,用戶和維護者都更容易看到最近變化。
最後用當前 plugins.json 生成 Markdown 表格替換 README 中的插件列表。
下架和舉報
它的流程和上架很像:
- 用戶創建下架或舉報 Issue
plugin-moderation-validate.js校驗插件是否存在- 如果是作者主動下架,校驗提交人是否為作者
- 維護者人工審核
- 維護者用
Close as completed關閉 plugin-moderation-close.js把插件狀態改成delisted- 自動生成 PR 更新
plugins.json和 README
AI 審核
專案裡還有一個 publish-plugin-ai-audit.js,它會對插件快照做一次 AI 靜態審查。
這個腳本的思路是:
- 下載同一個快照
- 選擇最多 24 個候選文件
- 優先看
manifest.json、package.json、入口文件、網絡/文件/存儲相關文件 - 把內容傳給 AI 接口
- 要求 AI 返回固定 JSON
- 把審查結果寫回 Issue 評論
這裡我覺得比較好的地方是:AI 審核沒有被設計成「最終裁判」。它只是給維護者多一份參考。
這比「AI 說安全所以自動上架」靠譜得多。
為什麼不用數據庫或後台服務?
這個專案最有意思的地方,其實不是代碼多複雜,而是它盡量不引入額外系統。
它把 GitHub 自帶的東西用到了比較完整:
- Issue Form 當申請表
- Issue 評論當審查反饋和快照記錄
- Label 當自動校驗狀態
- Close reason 當人工審核信號
- Pull Request 當數據變更入口
plugins.json當市場索引- README 當公開展示頁
- Git 歷史當審計日誌
所以它不需要一個後台,不需要數據庫,也不需要單獨做管理面板。對於一個開源音樂播放器的插件市場來說,這個複雜度剛剛好。
ps: GitHub Actions真的好用,包括我之前的 阿珏のBlog 的国际化之路
結尾
回頭看這個專案,它並不是那種「架構很重」的插件平台。它更像一個長得很樸素、但每個步驟都能追溯的登記系統。
用戶通過 Issue 提交,Action 自動檢查,維護者人工確認,PR 合併生效。所有關鍵動作都留在 GitHub 上,所有市場數據都落在 plugins.json 裡。出問題時能查,更新時有記錄,下架時也不抹掉歷史。
它沒有試圖一步到位做成一個完整後台,而是先把插件市場最核心的信任鏈路搭起來。
一個社區插件生態,真正需要的第一件事可能不是華麗的頁面,而是一套大家都能看懂、能信任、能覆盤、能繼續改進的流程。
這個倉庫 MoeKoeMusic-Plugins 就是這樣來的。
當然以上這些都不是一步到位的,是一步一步更新完善到現在的結果的