遷移到外掛 CLI

本頁內容

本指南面向針對先前 definePlugin() 形態撰寫的 沙箱 外掛作者。請依序處理破壞性變更。它們都不會改變 hook 或路由在執行時期的行為;它們改變的是外掛的宣告、建置與發佈方式。

有關每個套件的完整變更清單,請參閱 發行頁面 上的對應項目。

破壞性變更

重新命名:@emdash-cms/registry-cli 現為 @emdash-cms/plugin-cli

早期版本將 CLI 作為 @emdash-cms/registry-cli 發行,二進位為 emdash-registry。

該套件現為 @emdash-cms/plugin-cli,二進位為 emdash-plugin。舊套件不再發行。

我該做什麼?

取代依賴:

pnpm remove @emdash-cms/registry-cli
pnpm add -D @emdash-cms/plugin-cli

在所有呼叫處將 emdash-registry 取代為 emdash-plugin。每個子命令保持名稱不變(bundle、publish、login、whoami、switch、validate),並新增 init、build 和 dev。參見 The plugin CLI。

重新命名:capability 名稱使用 resource-first 拼寫

早期清單使用諸如 read:content 和 network:fetch 的 capability 名稱。創作清單僅接受目前名稱,不過執行時期在相容視窗內仍會正規化已發佈套件中的舊名稱。

我該做什麼?

在清單中取代每個舊名稱:

早期名稱目前名稱
network:fetchnetwork:request
network:fetch:anynetwork:request:unrestricted
read:contentcontent:read
write:contentcontent:write
read:mediamedia:read
write:mediamedia:write
read:usersusers:read
email:providehooks.email-transport:register
email:intercepthooks.email-events:register
page:injecthooks.page-fragments:register

對 network:request 使用非空的 allowedHosts 列表。僅當操作員在執行時期選擇目標時,才對 network:request:unrestricted 使用空列表。Capabilities and security 說明了目前權限與網路規則。

變更:沙箱外掛使用明確 SandboxedPlugin 註解

早期版本用從 emdash 匯入的 definePlugin() 包裝外掛的 hook 與路由,並由手工註解每個處理程序的參數。

沙箱外掛將其定義賦給 SandboxedPlugin 類型的常數,並將該常數作為 default 匯出。用 import type 從 emdash/plugin 匯入該類型;打包器會抹除該匯入。同一子路徑還匯出輕量執行時期輔助函式 pluginRoute() 和 pluginResponse()。TypeScript 從 hook 或路由名稱推斷每個處理程序的 event 和 ctx,因此處理程序參數無需註解。明確註解還能在隔離的套件管理器配置下保持產生宣告的可攜性。

我該做什麼?

對外掛原始檔做四處變更。取代匯入:

import { definePlugin, type ContentHookEvent, type PluginContext } from "emdash";
import type { SandboxedPlugin } from "emdash/plugin";

將 definePlugin() 包裝器取代為明確類型的常數:

export default definePlugin({ /* hooks, routes */ });
const plugin: SandboxedPlugin = { /* hooks, routes */ };

export default plugin;

從每個處理程序中移除參數註解:

handler: async (event: ContentHookEvent, ctx: PluginContext) => {
handler: async (event, ctx) => {

結果是一個 default 匯出的物件:

import type { SandboxedPlugin } from "emdash/plugin";

const plugin: SandboxedPlugin = {
	hooks: {
		"content:beforeSave": {
			handler: async (event, ctx) => {
				return event.content;
			},
		},
	},
};

export default plugin;

要在輔助函式中命名事件類型,請從 emdash/plugin 匯入:

import type { ContentHookEvent, PluginContext } from "emdash/plugin";

處理程序的 event 始終是該 hook 的規範類型。用更窄的介面註解處理程序將不再通過類型檢查。對依賴的欄位在執行時期用 typeof 檢查或守衛進行驗證,這是對來自類型系統之外的資料的正確做法。

變更:外掛是一個 src/plugin.ts 加上 emdash-plugin.jsonc

早期版本將外掛拆成兩個檔案:src/index.ts 回傳 PluginDescriptor(id、version、capabilities、storage、entrypoint),src/sandbox-entry.ts 儲存 hook 與路由。

外掛現在是一個執行時期檔案 src/plugin.ts(hook 與路由),以及一個手寫清單 emdash-plugin.jsonc(身分與信任契約)。entrypoint 和 format 欄位已移除;建置會接線它們。

我該做什麼?

依上述形態將 hook 與路由移入 src/plugin.ts。將描述符中繼資料移入 package.json 旁的 emdash-plugin.jsonc。描述符 id 成為清單 slug;capabilities、allowedHosts 和 storage 保持形態;version 從 package.json 讀取,因此省略它。

以下範例顯示宣告了一個儲存集合的描述符的清單等價物:

{
	"$schema": "./node_modules/@emdash-cms/plugin-cli/schemas/emdash-plugin.schema.json",

	"slug": "plugin-hello",
	"publisher": "did:plc:abc123def456",

	"license": "MIT",
	"author": { "name": "Jane Doe", "url": "https://example.com" },
	"security": { "email": "security@example.com" },

	"capabilities": [],
	"allowedHosts": [],
	"storage": { "events": { "indexes": ["timestamp"] } }
}

每個欄位見 The plugin manifest,publisher 欄位見 Publisher pinning。

在 package.json 中,將 "./sandbox" 匯出指向建置後的執行時期檔案:

"./sandbox": "./dist/sandbox-entry.mjs"
"./sandbox": "./dist/plugin.mjs"

將清單加入 files,以便隨套件一起發佈:

"files": ["dist"]
"files": ["dist", "emdash-plugin.jsonc"]

變更:用 emdash-plugin build 建置

早期版本用手工撰寫的 tsdown 指令碼建置兩個原始檔。

emdash-plugin build 讀取 emdash-plugin.jsonc 和 src/plugin.ts 並輸出 dist/ 產物。emdash-plugin dev 監視並重建。

我該做什麼?

取代建置指令碼並新增監視指令碼:

"scripts": {
	"build": "tsdown src/index.ts src/sandbox-entry.ts --format esm --dts --clean"
	"build": "emdash-plugin build",
	"dev": "emdash-plugin dev"
}

然後驗證並建置:

emdash-plugin validate
emdash-plugin build

移除:從 emdash 匯出的標準格式類型與函式

早期版本從 emdash 匯出 StandardPluginDefinition、StandardHookHandler、StandardHookEntry、StandardRouteHandler、StandardRouteEntry 以及函式 isStandardPluginDefinition。

這些已移除。它們是先前 definePlugin 形態的輔助別名。

我該做什麼?

對相同目的使用 emdash/plugin 中的 SandboxedPlugin。沙箱外掛的匯出定義已由其 SandboxedPlugin 註解定型,因此沒有 isStandardPluginDefinition 的替代;如需識別外掛,請依結構({ hooks?, routes? })判斷。

重新命名:sandbox-runner 控制碼使用 SandboxedPluginInstance

這僅影響自訂 SandboxRunner 的作者,例如 @emdash-cms/cloudflare。大多數外掛作者可跳過。

面向作者的 SandboxedPlugin 類型可從 emdash/plugin 創作入口取得。SandboxRunner.load 回傳的執行時期控制碼從 emdash 匯出為 SandboxedPluginInstance。

我該做什麼?

若你從 emdash 匯入 SandboxedPlugin 以類型化 sandbox runner 或持有執行時期外掛控制碼,請將匯入改為 SandboxedPluginInstance:

import type { SandboxedPlugin } from "emdash";
import type { SandboxedPluginInstance } from "emdash";

告知使用者

安裝你外掛的站點也需要變更匯入。引導他們使用新形態:去掉花括號和 ()。

import { helloPlugin } from "@my-org/plugin-hello";
import hello from "@my-org/plugin-hello";

export default defineConfig({
	integrations: [
		emdash({
			sandboxed: [helloPlugin()],
			sandboxed: [hello],
		}),
	],
});

若外掛透過工廠接受組態,請將該組態移到管理設定頁面,並從 ctx.settings 讀取。沙箱外掛描述符是普通物件,無法接收建構函式選項。參見 Settings。

驗證已遷移的外掛

執行外掛測試、驗證創作清單,並執行完整的建置與打包檢查:

pnpm test
pnpm exec emdash-plugin validate
pnpm exec emdash-plugin build
pnpm exec emdash-plugin bundle --validate-only

然後將本機套件安裝到開發站點,並演練每個已遷移的 hook 與路由。建置可以確認名稱與形態,但無法確認路由回傳預期資料,或 hook 正確保留內容。

下一步