Plugin SDK reference
การทดสอบ Plugin
เอกสารอ้างอิงสำหรับยูทิลิตี รูปแบบ และการบังคับใช้ lint สำหรับการทดสอบ Plugin ของ OpenClaw
ยูทิลิตีสำหรับการทดสอบ
พาธย่อยเหล่านี้เป็นจุดเริ่มต้นซอร์สภายในรีโพสำหรับการทดสอบ Plugin แบบรวมมากับ OpenClaw เอง พาธเหล่านี้ไม่ได้เป็น export ใน package.json ที่เผยแพร่สำหรับ Plugin ของบุคคลที่สาม และอาจนำเข้า Vitest หรือการขึ้นต่อกันสำหรับการทดสอบอื่น ๆ ที่ใช้เฉพาะภายในรีโพ
shouldAckReaction, removeAckReactionAfterReply,} from "openclaw/plugin-sdk/channel-feedback"; bundledPluginRoot, createCliRuntimeCapture, typedCases,} from "openclaw/plugin-sdk/test-fixtures"; สำหรับการทดสอบ Plugin แบบรวมมากับระบบรายการใหม่ ให้เลือกใช้พาธย่อยที่เจาะจงเหล่านี้ ส่วน barrel แบบกว้าง openclaw/plugin-sdk/testing และนามแฝง openclaw/plugin-sdk/test-utils มีไว้เพื่อความเข้ากันได้กับระบบเดิมเท่านั้น: pnpm run lint:plugins:no-extension-test-core-imports (scripts/check-no-extension-test-core-imports.ts) จะปฏิเสธการนำเข้ารายการใหม่จากทั้งสองรายการในไฟล์ทดสอบส่วนขยาย และทั้งสองรายการยังคงมีไว้เฉพาะสำหรับการทดสอบบันทึกความเข้ากันได้เท่านั้น
export ที่พร้อมใช้งาน
| การส่งออก | วัตถุประสงค์ |
|---|---|
createTestPluginApi |
สร้าง API จำลองขั้นต่ำสำหรับ Plugin เพื่อใช้ในการทดสอบหน่วยการลงทะเบียนโดยตรง นำเข้าจาก plugin-sdk/plugin-test-api |
AUTH_PROFILE_RUNTIME_CONTRACT |
ฟิกซ์เจอร์สัญญาโปรไฟล์การยืนยันตัวตนที่ใช้ร่วมกันสำหรับอะแดปเตอร์รันไทม์เอเจนต์แบบเนทีฟ นำเข้าจาก plugin-sdk/agent-runtime-test-contracts |
DELIVERY_NO_REPLY_RUNTIME_CONTRACT |
ฟิกซ์เจอร์สัญญาการระงับการส่งที่ใช้ร่วมกันสำหรับอะแดปเตอร์รันไทม์เอเจนต์แบบเนทีฟ นำเข้าจาก plugin-sdk/agent-runtime-test-contracts |
OUTCOME_FALLBACK_RUNTIME_CONTRACT |
ฟิกซ์เจอร์สัญญาการจำแนกประเภททางเลือกสำรองที่ใช้ร่วมกันสำหรับอะแดปเตอร์รันไทม์เอเจนต์แบบเนทีฟ นำเข้าจาก plugin-sdk/agent-runtime-test-contracts |
createParameterFreeTool |
สร้างฟิกซ์เจอร์สคีมาของเครื่องมือแบบไดนามิกสำหรับการทดสอบสัญญารันไทม์แบบเนทีฟ นำเข้าจาก plugin-sdk/agent-runtime-test-contracts |
expectChannelInboundContextContract |
ตรวจยืนยันรูปแบบบริบทขาเข้าของช่องทาง นำเข้าจาก plugin-sdk/channel-contract-testing |
installChannelOutboundPayloadContractSuite |
ติดตั้งกรณีทดสอบสัญญาเพย์โหลดขาออกของช่องทาง นำเข้าจาก plugin-sdk/channel-contract-testing |
createStartAccountContext |
สร้างบริบทวงจรชีวิตของบัญชีช่องทาง นำเข้าจาก plugin-sdk/channel-test-helpers |
installChannelActionsContractSuite |
ติดตั้งกรณีทดสอบสัญญาการดำเนินการกับข้อความช่องทางแบบทั่วไป นำเข้าจาก plugin-sdk/channel-test-helpers |
installChannelSetupContractSuite |
ติดตั้งกรณีทดสอบสัญญาการตั้งค่าช่องทางแบบทั่วไป นำเข้าจาก plugin-sdk/channel-test-helpers |
installChannelStatusContractSuite |
ติดตั้งกรณีทดสอบสัญญาสถานะช่องทางแบบทั่วไป นำเข้าจาก plugin-sdk/channel-test-helpers |
expectDirectoryIds |
ตรวจยืนยันรหัสไดเรกทอรีของช่องทางจากฟังก์ชันแสดงรายการไดเรกทอรี นำเข้าจาก plugin-sdk/channel-test-helpers |
assertBundledChannelEntries |
ตรวจยืนยันว่าจุดแรกเข้าของช่องทางที่รวมมาให้เปิดเผยสัญญาสาธารณะที่คาดไว้ นำเข้าจาก plugin-sdk/channel-test-helpers |
formatEnvelopeTimestamp |
จัดรูปแบบตราเวลาของเอนเวโลปให้กำหนดผลลัพธ์ได้แน่นอน นำเข้าจาก plugin-sdk/channel-test-helpers |
expectPairingReplyText |
ตรวจยืนยันข้อความตอบกลับการจับคู่และแยกรหัสออกมา นำเข้าจาก plugin-sdk/channel-test-helpers |
describePluginRegistrationContract |
ติดตั้งการตรวจสอบสัญญาการลงทะเบียน Plugin นำเข้าจาก plugin-sdk/plugin-test-contracts |
registerSingleProviderPlugin |
ลงทะเบียน Plugin ผู้ให้บริการหนึ่งรายการในการทดสอบเบื้องต้นของตัวโหลด นำเข้าจาก plugin-sdk/plugin-test-runtime |
registerProviderPlugin |
บันทึกผู้ให้บริการทุกประเภทจาก Plugin หนึ่งรายการ นำเข้าจาก plugin-sdk/plugin-test-runtime |
registerProviderPlugins |
บันทึกการลงทะเบียนผู้ให้บริการจาก Plugin หลายรายการ นำเข้าจาก plugin-sdk/plugin-test-runtime |
requireRegisteredProvider |
ตรวจยืนยันว่าคอลเลกชันผู้ให้บริการมีรหัสที่กำหนด นำเข้าจาก plugin-sdk/plugin-test-runtime |
createRuntimeEnv |
สร้างสภาพแวดล้อมรันไทม์ CLI/Plugin แบบจำลอง นำเข้าจาก plugin-sdk/plugin-test-runtime |
createPluginRuntimeMock |
สร้างพื้นผิวรันไทม์ของ Plugin แบบจำลอง นำเข้าจาก plugin-sdk/plugin-test-runtime |
createPluginSetupWizardStatus |
สร้างตัวช่วยสถานะการตั้งค่าสำหรับ Plugin ช่องทาง นำเข้าจาก plugin-sdk/plugin-test-runtime |
createTestWizardPrompter |
สร้างตัวแจ้งคำถามของตัวช่วยตั้งค่าแบบจำลอง นำเข้าจาก plugin-sdk/plugin-test-runtime |
createRuntimeTaskFlow |
สร้างสถานะโฟลว์งานรันไทม์ที่แยกต่างหาก นำเข้าจาก plugin-sdk/plugin-test-runtime |
runProviderCatalog |
เรียกใช้ฮุกแค็ตตาล็อกผู้ให้บริการพร้อมการขึ้นต่อกันสำหรับการทดสอบ นำเข้าจาก plugin-sdk/plugin-test-runtime |
resolveProviderWizardOptions |
หาค่าตัวเลือกของตัวช่วยตั้งค่าผู้ให้บริการในการทดสอบสัญญา นำเข้าจาก plugin-sdk/plugin-test-runtime |
resolveProviderModelPickerEntries |
หาค่ารายการตัวเลือกโมเดลของผู้ให้บริการในการทดสอบสัญญา นำเข้าจาก plugin-sdk/plugin-test-runtime |
buildProviderPluginMethodChoice |
สร้างรหัสตัวเลือกของตัวช่วยผู้ให้บริการสำหรับการตรวจยืนยัน นำเข้าจาก plugin-sdk/plugin-test-runtime |
setProviderWizardProvidersResolverForTest |
แทรกตัวแก้ค่าผู้ให้บริการของตัวช่วยผู้ให้บริการสำหรับการทดสอบแบบแยกส่วน นำเข้าจาก plugin-sdk/plugin-test-runtime |
describeOpenAIProviderRuntimeContract |
ติดตั้งการตรวจสอบสัญญารันไทม์ของตระกูลผู้ให้บริการ นำเข้าจาก plugin-sdk/provider-test-contracts |
expectPassthroughReplayPolicy |
ตรวจยืนยันว่านโยบายการเล่นซ้ำของผู้ให้บริการส่งผ่านเครื่องมือและข้อมูลเมตาที่ผู้ให้บริการเป็นเจ้าของ นำเข้าจาก plugin-sdk/provider-test-contracts |
runRealtimeSttLiveTest |
เรียกใช้การทดสอบผู้ให้บริการ STT แบบเรียลไทม์บนระบบจริงด้วยฟิกซ์เจอร์เสียงที่ใช้ร่วมกัน นำเข้าจาก plugin-sdk/provider-test-contracts |
normalizeTranscriptForMatch |
ปรับเอาต์พุตข้อความถอดเสียงจากระบบจริงให้เป็นมาตรฐานก่อนการตรวจยืนยันแบบคลุมเครือ นำเข้าจาก plugin-sdk/provider-test-contracts |
expectExplicitVideoGenerationCapabilities |
ตรวจยืนยันว่าผู้ให้บริการวิดีโอประกาศความสามารถของโหมดการสร้างอย่างชัดเจน นำเข้าจาก plugin-sdk/provider-test-contracts |
expectExplicitMusicGenerationCapabilities |
ตรวจยืนยันว่าผู้ให้บริการเพลงประกาศความสามารถในการสร้าง/แก้ไขอย่างชัดเจน นำเข้าจาก plugin-sdk/provider-test-contracts |
mockSuccessfulDashscopeVideoTask |
ติดตั้งการตอบกลับงานวิดีโอที่เข้ากันได้กับ DashScope และสำเร็จ นำเข้าจาก plugin-sdk/provider-test-contracts |
getProviderHttpMocks |
เข้าถึงม็อก HTTP/การยืนยันตัวตนของผู้ให้บริการสำหรับ Vitest ที่ต้องเลือกใช้โดยชัดแจ้ง นำเข้าจาก plugin-sdk/provider-http-test-mocks |
installProviderHttpMockCleanup |
รีเซ็ตม็อก HTTP/การยืนยันตัวตนของผู้ให้บริการหลังการทดสอบแต่ละครั้ง นำเข้าจาก plugin-sdk/provider-http-test-mocks |
installCommonResolveTargetErrorCases |
กรณีทดสอบที่ใช้ร่วมกันสำหรับการจัดการข้อผิดพลาดในการแก้ค่าเป้าหมาย นำเข้าจาก plugin-sdk/channel-target-testing |
shouldAckReaction |
ตรวจสอบว่าช่องทางควรเพิ่มรีแอ็กชันรับทราบหรือไม่ นำเข้าจาก plugin-sdk/channel-feedback |
removeAckReactionAfterReply |
ลบรีแอ็กชันรับทราบหลังส่งการตอบกลับแล้ว นำเข้าจาก plugin-sdk/channel-feedback |
createTestRegistry |
สร้างฟิกซ์เจอร์รีจิสทรี Plugin ช่องทาง นำเข้าจาก plugin-sdk/plugin-test-runtime หรือ plugin-sdk/channel-test-helpers |
createEmptyPluginRegistry |
สร้างฟิกซ์เจอร์รีจิสทรี Plugin ว่างเปล่า นำเข้าจาก plugin-sdk/plugin-test-runtime หรือ plugin-sdk/channel-test-helpers |
setActivePluginRegistry |
ติดตั้งฟิกซ์เจอร์รีจิสทรีสำหรับการทดสอบรันไทม์ของ Plugin นำเข้าจาก plugin-sdk/plugin-test-runtime หรือ plugin-sdk/channel-test-helpers |
createRequestCaptureJsonFetch |
บันทึกคำขอ fetch แบบ JSON ในการทดสอบตัวช่วยสื่อ นำเข้าจาก plugin-sdk/test-env |
withServer |
เรียกใช้การทดสอบกับเซิร์ฟเวอร์ HTTP ภายในที่ใช้แล้วทิ้งได้ นำเข้าจาก plugin-sdk/test-env |
createMockIncomingRequest |
สร้างออบเจ็กต์คำขอ HTTP ขาเข้าขั้นต่ำ นำเข้าจาก plugin-sdk/test-env |
withFetchPreconnect |
เรียกใช้การทดสอบ fetch โดยติดตั้งฮุก preconnect แล้ว นำเข้าจาก plugin-sdk/test-env |
withEnv / withEnvAsync |
แพตช์ตัวแปรสภาพแวดล้อมชั่วคราว นำเข้าจาก plugin-sdk/test-env |
createTempHomeEnv / withTempHome / withTempDir |
สร้างฟิกซ์เจอร์การทดสอบระบบไฟล์แบบแยกส่วน นำเข้าจาก plugin-sdk/test-env |
createMockServerResponse |
สร้างม็อกการตอบกลับของเซิร์ฟเวอร์ HTTP ขั้นต่ำ นำเข้าจาก plugin-sdk/test-env |
createProviderUsageFetch |
สร้างฟิกซ์เจอร์ fetch การใช้งานผู้ให้บริการ นำเข้าจาก plugin-sdk/test-env |
useFrozenTime / useRealTime |
หยุดและคืนค่าตัวจับเวลาสำหรับการทดสอบที่ไวต่อเวลา นำเข้าจาก plugin-sdk/test-env |
createCliRuntimeCapture |
บันทึกเอาต์พุตรันไทม์ของ CLI ในการทดสอบ นำเข้าจาก plugin-sdk/test-fixtures |
importFreshModule |
นำเข้าโมดูล ESM ด้วยโทเค็นคิวรีใหม่เพื่อข้ามแคชโมดูล นำเข้าจาก plugin-sdk/test-fixtures |
bundledPluginRoot / bundledPluginFile |
หาค่าพาธฟิกซ์เจอร์ซอร์สหรือ dist ของ Plugin ที่รวมมาให้ นำเข้าจาก plugin-sdk/test-fixtures |
mockNodeBuiltinModule |
ติดตั้งม็อกโมดูลในตัวของ Node แบบขอบเขตแคบสำหรับ Vitest นำเข้าจาก plugin-sdk/test-node-mocks |
createSandboxTestContext |
สร้างบริบทการทดสอบแซนด์บ็อกซ์ นำเข้าจาก plugin-sdk/test-fixtures |
writeSkill |
เขียนฟิกซ์เจอร์ของ Skills นำเข้าจาก plugin-sdk/test-fixtures |
makeAgentAssistantMessage |
สร้างฟิกซ์เจอร์ข้อความทรานสคริปต์ของเอเจนต์ นำเข้าจาก plugin-sdk/test-fixtures |
peekSystemEvents / resetSystemEventsForTest |
ตรวจสอบและรีเซ็ตฟิกซ์เจอร์เหตุการณ์ของระบบ นำเข้าจาก plugin-sdk/test-fixtures |
sanitizeTerminalText |
ทำความสะอาดเอาต์พุตของเทอร์มินัลสำหรับการตรวจสอบยืนยัน นำเข้าจาก plugin-sdk/test-fixtures |
countLines / hasBalancedFences |
ตรวจสอบยืนยันรูปแบบเอาต์พุตของการแบ่งส่วน นำเข้าจาก plugin-sdk/test-fixtures |
typedCases |
รักษาชนิดลิเทอรัลสำหรับการทดสอบแบบขับเคลื่อนด้วยตาราง นำเข้าจาก plugin-sdk/test-fixtures |
ชุดการทดสอบสัญญาของ Plugin ที่รวมมาให้ยังใช้พาธย่อยสำหรับการทดสอบของ SDK เหล่านี้ด้วย สำหรับตัวช่วย fixture ของรีจิสทรี แมนิเฟสต์ อาร์ติแฟกต์สาธารณะ และรันไทม์ที่ใช้เฉพาะในการทดสอบ
ส่วนชุดการทดสอบเฉพาะแกนหลักที่ขึ้นอยู่กับรายการ OpenClaw ที่รวมมาให้ จะยังคงอยู่ภายใต้
src/plugins/contracts
ชนิดข้อมูล
พาธย่อยสำหรับการทดสอบเฉพาะด้านยังส่งออกชนิดข้อมูลที่มีประโยชน์ในไฟล์ทดสอบซ้ำด้วย:
ChannelAccountSnapshot, ChannelGatewayContext,} from "openclaw/plugin-sdk/channel-contract"; การแก้ไขเป้าหมายในการทดสอบ
ใช้ installCommonResolveTargetErrorCases เพื่อเพิ่มกรณีข้อผิดพลาดมาตรฐานสำหรับ
การแก้ไขเป้าหมายของช่องทาง:
describe("my-channel target resolution", () => { installCommonResolveTargetErrorCases({ resolveTarget: ({ to, mode, allowFrom }) => { // Your channel's target resolution logic return myChannelResolveTarget({ to, mode, allowFrom }); }, implicitAllowFrom: ["user1", "user2"], }); // Add channel-specific test cases it("should resolve @username targets", () => { // ... });});รูปแบบการทดสอบ
การทดสอบสัญญาการลงทะเบียน
การทดสอบหน่วยที่ส่งม็อก api ซึ่งเขียนขึ้นเองไปยัง register(api) จะไม่ได้
ทดสอบเกตการยอมรับของตัวโหลด OpenClaw เพิ่มการทดสอบควันแบบใช้ตัวโหลดอย่างน้อยหนึ่งรายการ
สำหรับแต่ละพื้นผิวการลงทะเบียนที่ Plugin ของคุณต้องพึ่งพา โดยเฉพาะ
ฮุกและความสามารถแบบเอกสิทธิ์ เช่น หน่วยความจำ
ตัวโหลดจริงจะทำให้การลงทะเบียน Plugin ล้มเหลวเมื่อขาดข้อมูลเมตาที่จำเป็น หรือ
Plugin เรียก API ของความสามารถที่ตนไม่ได้เป็นเจ้าของ ตัวอย่างเช่น
api.registerHook(...) ต้องมีชื่อฮุก และ
api.registerMemoryCapability(...) ต้องให้แมนิเฟสต์ของ Plugin หรือรายการที่ส่งออก
ประกาศ kind: "memory"
การทดสอบการเข้าถึงการกำหนดค่ารันไทม์
ควรใช้ม็อกรันไทม์ Plugin ที่ใช้ร่วมกันจาก openclaw/plugin-sdk/plugin-test-runtime
ม็อก runtime.config.loadConfig() และ runtime.config.writeConfigFile(...)
จะส่งข้อผิดพลาดตามค่าเริ่มต้น เพื่อให้การทดสอบตรวจพบการใช้งาน API ความเข้ากันได้
ที่เลิกแนะนำใหม่ ให้แทนที่ม็อกเหล่านั้นเฉพาะเมื่อการทดสอบครอบคลุมพฤติกรรม
ความเข้ากันได้แบบเดิมอย่างชัดเจนเท่านั้น
การทดสอบหน่วย Plugin ช่องทาง
describe("my-channel plugin", () => { it("should resolve account from config", () => { const cfg = { channels: { "my-channel": { token: "test-token", allowFrom: ["user1"], }, }, }; const account = myPlugin.setup.resolveAccount(cfg, undefined); expect(account.token).toBe("test-token"); }); it("should inspect account without materializing secrets", () => { const cfg = { channels: { "my-channel": { token: "test-token" }, }, }; const inspection = myPlugin.setup.inspectAccount(cfg, undefined); expect(inspection.configured).toBe(true); expect(inspection.tokenStatus).toBe("available"); // No token value exposed expect(inspection).not.toHaveProperty("token"); });});การทดสอบหน่วย Plugin ผู้ให้บริการ
describe("my-provider plugin", () => { it("should resolve dynamic models", () => { const model = myProvider.resolveDynamicModel({ modelId: "custom-model-v2", // ... context }); expect(model.id).toBe("custom-model-v2"); expect(model.provider).toBe("my-provider"); expect(model.api).toBe("openai-completions"); }); it("should return catalog when API key is available", async () => { const result = await myProvider.catalog.run({ resolveProviderApiKey: () => ({ apiKey: "test-key" }), // ... context }); expect(result?.provider?.models).toHaveLength(2); });});การม็อกรันไทม์ของ Plugin
สำหรับโค้ดที่ใช้ createPluginRuntimeStore ให้ม็อกรันไทม์ในการทดสอบ:
const store = createPluginRuntimeStore<PluginRuntime>({ pluginId: "test-plugin", errorMessage: "test runtime not set",}); // In test setupconst mockRuntime = { agent: { resolveAgentDir: vi.fn().mockReturnValue("/tmp/agent"), // ... other mocks }, config: { current: vi.fn(() => ({}) as const), mutateConfigFile: vi.fn(), replaceConfigFile: vi.fn(), }, // ... other namespaces} as unknown as PluginRuntime; store.setRuntime(mockRuntime); // After testsstore.clearRuntime();การทดสอบด้วยสตับต่ออินสแตนซ์
ควรใช้สตับต่ออินสแตนซ์แทนการแก้ไขโพรโทไทป์:
// Preferred: per-instance stubconst client = new MyChannelClient();client.sendMessage = vi.fn().mockResolvedValue({ id: "msg-1" }); // Avoid: prototype mutation// MyChannelClient.prototype.sendMessage = vi.fn();การทดสอบสัญญา (Plugin ภายในรีโพ)
Plugin ที่รวมมาให้มีการทดสอบสัญญาเพื่อตรวจสอบความเป็นเจ้าของการลงทะเบียน:
pnpm test src/plugins/contracts/การทดสอบเหล่านี้ยืนยัน:
- Plugin ใดลงทะเบียนผู้ให้บริการใด
- Plugin ใดลงทะเบียนผู้ให้บริการเสียงพูดใด
- ความถูกต้องของรูปแบบการลงทะเบียน
- การปฏิบัติตามสัญญารันไทม์
การเรียกใช้การทดสอบแบบจำกัดขอบเขต
สำหรับ Plugin เฉพาะรายการ:
pnpm test <bundled-plugin-root>/my-channel/สำหรับการทดสอบสัญญาเท่านั้น:
pnpm test src/plugins/contracts/shape.contract.test.tspnpm test src/plugins/contracts/auth-choice.contract.test.tspnpm test src/plugins/contracts/runtime-seams.contract.test.tsการบังคับใช้ลินต์ (Plugin ภายในรีโพ)
scripts/run-additional-boundary-checks.mjs เรียกใช้ชุดการตรวจสอบขอบเขตการนำเข้า
lint:plugins:* ใน CI โดยแต่ละรายการยังสามารถเรียกใช้แยกต่างหากในเครื่องได้:
| คำสั่ง | สิ่งที่บังคับใช้ |
|---|---|
pnpm run lint:plugins:no-monolithic-plugin-sdk-entry-imports |
Plugin ที่รวมมาให้ไม่สามารถนำเข้าบาร์เรลราก openclaw/plugin-sdk แบบรวมศูนย์ได้ |
pnpm run lint:plugins:no-extension-src-imports |
ไฟล์ส่วนขยายสำหรับการใช้งานจริงไม่สามารถนำเข้าทรี src/** ของรีโพโดยตรง (../../src/...) ได้ |
pnpm run lint:plugins:no-extension-test-core-imports |
ไฟล์ทดสอบส่วนขยายไม่สามารถนำเข้า openclaw/plugin-sdk/testing, plugin-sdk/test-utils หรือตัวช่วยทดสอบเฉพาะแกนหลักอื่น ๆ ได้ |
Plugin ภายนอกไม่อยู่ภายใต้กฎลินต์เหล่านี้ แต่แนะนำให้ปฏิบัติตาม รูปแบบเดียวกัน
การกำหนดค่าการทดสอบ
OpenClaw ใช้ Vitest 4 พร้อมการรายงานความครอบคลุม V8 เพื่อให้ข้อมูล สำหรับการทดสอบ Plugin:
# Run all testspnpm test # Run specific plugin testspnpm test <bundled-plugin-root>/my-channel/src/channel.test.ts # Run with a specific test name filterpnpm test <bundled-plugin-root>/my-channel/ -t "resolves account" # Run with coveragepnpm test:coverageหากการเรียกใช้ในเครื่องทำให้หน่วยความจำตึงตัว:
OPENCLAW_VITEST_MAX_WORKERS=1 pnpm testเนื้อหาที่เกี่ยวข้อง
- ภาพรวม SDK -- ข้อตกลงการนำเข้า
- Plugin ช่องทางของ SDK -- อินเทอร์เฟซ Plugin ช่องทาง
- Plugin ผู้ให้บริการของ SDK -- ฮุกของ Plugin ผู้ให้บริการ
- การสร้าง Plugin -- คู่มือเริ่มต้นใช้งาน