koishi-plugin-media-luna 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/client/api.ts +36 -86
  2. package/client/components/ChannelsView.vue +28 -208
  3. package/client/components/GenerateView.vue +46 -11
  4. package/client/components/HistoryGallery.vue +47 -12
  5. package/client/components/PresetsView.vue +26 -200
  6. package/client/components/SettingsView.vue +26 -0
  7. package/client/components/TasksView.vue +15 -68
  8. package/client/composables/index.ts +14 -0
  9. package/client/composables/useDataFetch.ts +102 -0
  10. package/client/composables/useDialog.ts +58 -0
  11. package/client/composables/useLoading.ts +84 -0
  12. package/client/composables/usePagination.ts +110 -0
  13. package/client/constants/categories.ts +36 -0
  14. package/client/constants/index.ts +5 -0
  15. package/client/constants/phases.ts +44 -0
  16. package/client/styles/shared.css +42 -0
  17. package/client/types.ts +73 -0
  18. package/dist/index.js +1 -1
  19. package/dist/style.css +1 -1
  20. package/lib/core/api/plugin-api.d.ts.map +1 -1
  21. package/lib/core/api/plugin-api.js +31 -0
  22. package/lib/core/api/plugin-api.js.map +1 -1
  23. package/lib/core/medialuna.service.d.ts.map +1 -1
  24. package/lib/core/medialuna.service.js +16 -12
  25. package/lib/core/medialuna.service.js.map +1 -1
  26. package/lib/core/pipeline/generation-pipeline.d.ts +4 -0
  27. package/lib/core/pipeline/generation-pipeline.d.ts.map +1 -1
  28. package/lib/core/pipeline/generation-pipeline.js +61 -20
  29. package/lib/core/pipeline/generation-pipeline.js.map +1 -1
  30. package/lib/core/plugin-loader.d.ts +42 -0
  31. package/lib/core/plugin-loader.d.ts.map +1 -1
  32. package/lib/core/plugin-loader.js +204 -1
  33. package/lib/core/plugin-loader.js.map +1 -1
  34. package/lib/core/request.service.d.ts +4 -1
  35. package/lib/core/request.service.d.ts.map +1 -1
  36. package/lib/core/request.service.js +11 -1
  37. package/lib/core/request.service.js.map +1 -1
  38. package/lib/core/types.d.ts +10 -0
  39. package/lib/core/types.d.ts.map +1 -1
  40. package/lib/plugins/README.md +716 -0
  41. package/lib/plugins/cache/middleware.d.ts.map +1 -1
  42. package/lib/plugins/cache/middleware.js +2 -0
  43. package/lib/plugins/cache/middleware.js.map +1 -1
  44. package/lib/plugins/task/middleware.d.ts.map +1 -1
  45. package/lib/plugins/task/middleware.js +20 -2
  46. package/lib/plugins/task/middleware.js.map +1 -1
  47. package/lib/types/index.d.ts +4 -0
  48. package/lib/types/index.d.ts.map +1 -1
  49. package/package.json +1 -1
@@ -0,0 +1,716 @@
1
+ # Media Luna 插件开发指南
2
+
3
+ ## 概述
4
+
5
+ Media Luna 采用插件化架构,所有功能(缓存、预设、计费、连接器等)都以插件形式实现。本文档介绍如何开发 Media Luna 插件。
6
+
7
+ ## 快速开始
8
+
9
+ ### 最小插件示例
10
+
11
+ ```typescript
12
+ import { definePlugin } from '../core'
13
+
14
+ export default definePlugin({
15
+ id: 'my-plugin',
16
+ name: '我的插件',
17
+ description: '插件描述',
18
+ version: '1.0.0',
19
+
20
+ async onLoad(ctx) {
21
+ ctx.logger.info('插件已加载')
22
+ }
23
+ })
24
+ ```
25
+
26
+ ### 插件目录结构
27
+
28
+ ```
29
+ src/plugins/my-plugin/
30
+ ├── index.ts # 插件入口,导出 definePlugin()
31
+ ├── config.ts # 配置类型和字段定义
32
+ ├── service.ts # 服务类(可选)
33
+ ├── middleware.ts # 中间件定义(可选)
34
+ └── README.md # 插件文档(可选)
35
+ ```
36
+
37
+ ---
38
+
39
+ ## 插件定义 (PluginDefinition)
40
+
41
+ ### 完整接口
42
+
43
+ ```typescript
44
+ interface PluginDefinition {
45
+ // ===== 基础信息 =====
46
+ id: string // 唯一标识符(必须)
47
+ name: string // 显示名称(必须)
48
+ description?: string // 描述
49
+ version?: string // 版本号
50
+ dependencies?: string[] // 依赖的其他插件 ID
51
+
52
+ // ===== 配置 =====
53
+ configFields?: ConfigField[] // 配置字段定义(自动生成 UI)
54
+ configDefaults?: Record<string, any> // 默认配置值
55
+
56
+ // ===== 功能注册 =====
57
+ services?: ServiceDefinition[] // 服务
58
+ middlewares?: MiddlewareDefinition[] // 中间件
59
+ connector?: ConnectorDefinition // 连接器(每个插件最多一个)
60
+
61
+ // ===== UI =====
62
+ settingsActions?: SettingsAction[] // 设置面板操作按钮
63
+
64
+ // ===== 生命周期 =====
65
+ onLoad?: (ctx: PluginContext) => Promise<void> | void
66
+ onUnload?: () => Promise<void> | void
67
+ }
68
+ ```
69
+
70
+ ---
71
+
72
+ ## 配置系统
73
+
74
+ ### 配置字段类型
75
+
76
+ ```typescript
77
+ interface ConfigField {
78
+ key: string // 配置键名
79
+ label: string // 显示标签
80
+ type: 'text' | 'number' | 'boolean' | 'select' | 'password' | 'textarea'
81
+ default?: any // 默认值
82
+ description?: string // 字段说明
83
+ placeholder?: string // 占位符
84
+ options?: Array<{ label: string; value: any }> // select 类型的选项
85
+ showWhen?: { field: string; value: any } // 条件显示
86
+ }
87
+ ```
88
+
89
+ ### 示例
90
+
91
+ ```typescript
92
+ export const myConfigFields: ConfigField[] = [
93
+ {
94
+ key: 'enabled',
95
+ label: '启用插件',
96
+ type: 'boolean',
97
+ default: true
98
+ },
99
+ {
100
+ key: 'apiKey',
101
+ label: 'API 密钥',
102
+ type: 'password',
103
+ description: '从服务商获取的 API Key'
104
+ },
105
+ {
106
+ key: 'mode',
107
+ label: '工作模式',
108
+ type: 'select',
109
+ default: 'auto',
110
+ options: [
111
+ { label: '自动', value: 'auto' },
112
+ { label: '手动', value: 'manual' }
113
+ ]
114
+ },
115
+ {
116
+ key: 'endpoint',
117
+ label: '自定义端点',
118
+ type: 'text',
119
+ placeholder: 'https://api.example.com',
120
+ showWhen: { field: 'mode', value: 'manual' } // 仅在 mode='manual' 时显示
121
+ }
122
+ ]
123
+ ```
124
+
125
+ ### 配置热重载
126
+
127
+ 配置通过 Proxy 代理实现热重载。服务中访问配置时,始终获取最新值:
128
+
129
+ ```typescript
130
+ class MyService {
131
+ private config: MyPluginConfig
132
+
133
+ constructor(ctx: Context, config: MyPluginConfig) {
134
+ this.config = config // 这是一个 Proxy
135
+ }
136
+
137
+ doSomething() {
138
+ // 每次访问都是最新配置,无需手动刷新
139
+ if (this.config.enabled) {
140
+ // ...
141
+ }
142
+ }
143
+ }
144
+ ```
145
+
146
+ ### 插件配置 vs 连接器配置
147
+
148
+ Media Luna 有两种配置,理解它们的区别很重要:
149
+
150
+ | 类型 | 作用域 | 存储位置 | 使用场景 |
151
+ |-----|-------|---------|---------|
152
+ | **插件配置** (configFields) | 全局 | `data/media-luna/config.yaml` | 插件级功能开关、全局参数 |
153
+ | **连接器配置** (connector.configFields) | 渠道级 | 数据库 (渠道表) | 每个渠道的 API 配置 |
154
+
155
+ **插件配置**:
156
+ - 在「设置 → 扩展插件」中配置
157
+ - 所有渠道共享同一份配置
158
+ - 适用于:缓存目录、同步间隔、功能开关等
159
+
160
+ ```typescript
161
+ // 插件配置示例
162
+ configFields: [
163
+ { key: 'enabled', label: '启用', type: 'boolean' },
164
+ { key: 'cacheDir', label: '缓存目录', type: 'text' }
165
+ ]
166
+ ```
167
+
168
+ **连接器配置**:
169
+ - 在「渠道管理 → 编辑渠道」中配置
170
+ - 每个渠道可以有不同的配置
171
+ - 适用于:API Key、端点地址、模型名称等
172
+
173
+ ```typescript
174
+ // 连接器配置示例
175
+ connector: {
176
+ id: 'my-api',
177
+ configFields: [
178
+ { key: 'apiKey', label: 'API Key', type: 'password' },
179
+ { key: 'model', label: '模型', type: 'select', options: [...] }
180
+ ]
181
+ }
182
+ ```
183
+
184
+ ---
185
+
186
+ ## 服务 (Service)
187
+
188
+ 服务是单例对象,供其他中间件或插件使用。
189
+
190
+ ### 定义服务
191
+
192
+ ```typescript
193
+ interface ServiceDefinition {
194
+ name: string // 服务名称(全局唯一)
195
+ factory: (ctx: PluginContext) => any // 工厂函数
196
+ }
197
+ ```
198
+
199
+ ### 示例
200
+
201
+ ```typescript
202
+ // service.ts
203
+ export class MyService {
204
+ private ctx: Context
205
+ private config: MyPluginConfig
206
+
207
+ constructor(ctx: Context, config: MyPluginConfig) {
208
+ this.ctx = ctx
209
+ this.config = config
210
+ }
211
+
212
+ async doWork(): Promise<string> {
213
+ return `Using API: ${this.config.apiKey}`
214
+ }
215
+ }
216
+
217
+ // index.ts
218
+ export default definePlugin({
219
+ id: 'my-plugin',
220
+ services: [
221
+ {
222
+ name: 'myService',
223
+ factory: (ctx) => {
224
+ const config = ctx.getConfig<MyPluginConfig>()
225
+ return new MyService(ctx.ctx, config)
226
+ }
227
+ }
228
+ ]
229
+ })
230
+ ```
231
+
232
+ ### 使用服务
233
+
234
+ 在中间件或其他插件中:
235
+
236
+ ```typescript
237
+ // 在中间件中
238
+ async execute(mctx: MiddlewareContext, next) {
239
+ const myService = mctx.getService<MyService>('myService')
240
+ if (myService) {
241
+ await myService.doWork()
242
+ }
243
+ return next()
244
+ }
245
+
246
+ // 在 PluginContext 中
247
+ async onLoad(ctx) {
248
+ const otherService = ctx.getService<OtherService>('otherService')
249
+ }
250
+ ```
251
+
252
+ ---
253
+
254
+ ## 中间件 (Middleware)
255
+
256
+ 中间件参与生成请求的处理流程。
257
+
258
+ ### 执行阶段
259
+
260
+ ```
261
+ lifecycle-prepare → 准备阶段(校验、预处理)
262
+ lifecycle-pre-request → 请求前(预设应用、提示词处理)
263
+ lifecycle-request → 请求阶段(调用连接器生成)
264
+ lifecycle-post-request → 请求后(缓存、后处理)
265
+ lifecycle-finalize → 完成阶段(计费结算、任务记录)
266
+ ```
267
+
268
+ ### 定义中间件
269
+
270
+ ```typescript
271
+ interface MiddlewareDefinition {
272
+ name: string // 中间件名称(必须唯一)
273
+ displayName: string // 显示名称
274
+ description?: string // 描述
275
+ phase: MiddlewarePhase // 执行阶段
276
+ category?: string // 所属插件 ID(用于配置关联)
277
+ priority?: number // 同阶段内的优先级(越小越先执行)
278
+
279
+ // 依赖声明
280
+ runBefore?: string[] // 在这些中间件之前运行
281
+ runAfter?: string[] // 在这些中间件之后运行
282
+
283
+ execute: (mctx: MiddlewareContext, next: () => Promise<MiddlewareRunStatus>)
284
+ => Promise<MiddlewareRunStatus>
285
+ }
286
+ ```
287
+
288
+ ### 中间件上下文 (MiddlewareContext)
289
+
290
+ ```typescript
291
+ interface MiddlewareContext {
292
+ // Koishi 上下文
293
+ ctx: Context
294
+ session: Session | null
295
+
296
+ // 请求数据
297
+ prompt: string // 原始提示词
298
+ files: FileData[] // 输入文件
299
+ parameters: Record<string, any> // 请求参数
300
+
301
+ // 渠道信息
302
+ channelId: number
303
+ channel: ChannelConfig | null
304
+
305
+ // 输出(由中间件填充)
306
+ output: OutputAsset[] | null
307
+
308
+ // 用户标识
309
+ uid: number | null
310
+
311
+ // 跨中间件数据共享
312
+ store: Map<string, any>
313
+
314
+ // 方法
315
+ getMiddlewareConfig<T>(name: string): Promise<T | null>
316
+ setMiddlewareLog(name: string, data: any): void
317
+ getService<T>(name: string): T | undefined
318
+ }
319
+ ```
320
+
321
+ ### 返回状态
322
+
323
+ ```typescript
324
+ enum MiddlewareRunStatus {
325
+ CONTINUE = 'continue', // 继续执行后续中间件
326
+ STOP = 'stop', // 停止执行(正常终止)
327
+ SKIPPED = 'skipped' // 跳过(条件不满足)
328
+ }
329
+ ```
330
+
331
+ ### 示例
332
+
333
+ ```typescript
334
+ import { MiddlewareDefinition, MiddlewareRunStatus } from '../../core'
335
+
336
+ export function createMyMiddleware(): MiddlewareDefinition {
337
+ return {
338
+ name: 'my-middleware',
339
+ displayName: '我的中间件',
340
+ description: '处理某些逻辑',
341
+ phase: 'lifecycle-pre-request',
342
+ category: 'my-plugin', // 关联到 my-plugin 的配置
343
+ priority: 50,
344
+
345
+ async execute(mctx, next) {
346
+ // 获取配置
347
+ const config = await mctx.getMiddlewareConfig<MyPluginConfig>('my-plugin')
348
+ if (!config?.enabled) {
349
+ return next() // 未启用则跳过
350
+ }
351
+
352
+ // 处理逻辑
353
+ mctx.logger.info('Processing prompt: %s', mctx.prompt)
354
+
355
+ // 修改 prompt
356
+ // mctx.prompt = processedPrompt
357
+
358
+ // 使用 store 共享数据
359
+ mctx.store.set('myData', { processed: true })
360
+
361
+ // 记录日志(会显示在任务详情中)
362
+ mctx.setMiddlewareLog('my-middleware', {
363
+ processed: true,
364
+ originalLength: mctx.prompt.length
365
+ })
366
+
367
+ return next()
368
+ }
369
+ }
370
+ }
371
+ ```
372
+
373
+ ---
374
+
375
+ ## 连接器 (Connector)
376
+
377
+ 连接器提供实际的生成能力(调用 AI 服务)。
378
+
379
+ ### 定义连接器
380
+
381
+ ```typescript
382
+ interface ConnectorDefinition {
383
+ id: string // 连接器 ID
384
+ name: string // 显示名称
385
+ description?: string // 描述
386
+ supportedTypes: MediaType[] // 支持的媒体类型: 'image' | 'audio' | 'video' | 'text'
387
+
388
+ configFields?: ConfigField[] // 渠道级配置字段
389
+
390
+ generate: (
391
+ request: ConnectorRequest,
392
+ config: Record<string, any>
393
+ ) => Promise<ConnectorResponse>
394
+ }
395
+ ```
396
+
397
+ ### 示例
398
+
399
+ ```typescript
400
+ export const myConnector: ConnectorDefinition = {
401
+ id: 'my-api',
402
+ name: 'My API',
403
+ description: '调用 My API 生成图片',
404
+ supportedTypes: ['image'],
405
+
406
+ configFields: [
407
+ { key: 'apiUrl', label: 'API 地址', type: 'text', default: 'https://api.example.com' },
408
+ { key: 'apiKey', label: 'API Key', type: 'password' },
409
+ { key: 'model', label: '模型', type: 'text', default: 'default' }
410
+ ],
411
+
412
+ async generate(request, config) {
413
+ const { prompt, parameters } = request
414
+ const { apiUrl, apiKey, model } = config
415
+
416
+ const response = await fetch(`${apiUrl}/generate`, {
417
+ method: 'POST',
418
+ headers: {
419
+ 'Authorization': `Bearer ${apiKey}`,
420
+ 'Content-Type': 'application/json'
421
+ },
422
+ body: JSON.stringify({ prompt, model, ...parameters })
423
+ })
424
+
425
+ const data = await response.json()
426
+
427
+ return {
428
+ success: true,
429
+ outputs: [
430
+ { kind: 'image', url: data.imageUrl }
431
+ ]
432
+ }
433
+ }
434
+ }
435
+
436
+ // index.ts
437
+ export default definePlugin({
438
+ id: 'connector-my-api',
439
+ name: 'My API 连接器',
440
+ connector: myConnector
441
+ })
442
+ ```
443
+
444
+ ---
445
+
446
+ ## 生命周期钩子
447
+
448
+ ### onLoad
449
+
450
+ 插件加载时调用,可用于:
451
+ - 注册 Koishi 命令
452
+ - 注册 HTTP 路由
453
+ - 注册 Console API
454
+ - 初始化资源
455
+
456
+ ```typescript
457
+ async onLoad(ctx) {
458
+ // ctx.ctx 是 Koishi Context
459
+ // ctx.logger 是插件专用 logger
460
+ // ctx.getConfig() 获取配置
461
+ // ctx.getService() 获取其他服务
462
+
463
+ // 注册 HTTP 路由
464
+ ctx.ctx.inject(['server'], (injectedCtx) => {
465
+ injectedCtx.server.get('/my-plugin/status', (koaCtx) => {
466
+ koaCtx.body = { status: 'ok' }
467
+ })
468
+ })
469
+
470
+ // 注册 Console API
471
+ const console = ctx.ctx.console as any
472
+ console.addListener('media-luna/my-plugin/action', async (params) => {
473
+ // 处理前端请求
474
+ return { success: true, data: { ... } }
475
+ })
476
+
477
+ // 清理回调
478
+ ctx.onDispose(() => {
479
+ // 插件卸载时执行
480
+ })
481
+ }
482
+ ```
483
+
484
+ ### onUnload
485
+
486
+ 插件卸载时调用,用于清理资源。
487
+
488
+ ---
489
+
490
+ ## 设置面板操作
491
+
492
+ 在插件设置页面添加操作按钮:
493
+
494
+ ```typescript
495
+ settingsActions: [
496
+ {
497
+ name: 'sync',
498
+ label: '立即同步',
499
+ type: 'primary', // 'primary' | 'default' | 'error'
500
+ icon: 'sync', // Koishi 图标名
501
+ apiEvent: 'media-luna/my-plugin/sync' // 点击时触发的 Console 事件
502
+ },
503
+ {
504
+ name: 'clear',
505
+ label: '清空数据',
506
+ type: 'error',
507
+ icon: 'delete',
508
+ apiEvent: 'media-luna/my-plugin/clear'
509
+ }
510
+ ]
511
+ ```
512
+
513
+ 需要在 `onLoad` 中注册对应的 API:
514
+
515
+ ```typescript
516
+ async onLoad(ctx) {
517
+ const console = ctx.ctx.console as any
518
+
519
+ console.addListener('media-luna/my-plugin/sync', async () => {
520
+ // 执行同步
521
+ return { success: true, data: { message: '同步完成' } }
522
+ })
523
+ }
524
+ ```
525
+
526
+ ---
527
+
528
+ ## 完整插件示例
529
+
530
+ ```typescript
531
+ // src/plugins/my-plugin/index.ts
532
+
533
+ import { definePlugin, MiddlewareRunStatus } from '../../core'
534
+ import type { MiddlewareContext } from '../../core'
535
+
536
+ interface MyPluginConfig {
537
+ enabled: boolean
538
+ prefix: string
539
+ maxLength: number
540
+ }
541
+
542
+ const defaultConfig: MyPluginConfig = {
543
+ enabled: true,
544
+ prefix: '[Enhanced] ',
545
+ maxLength: 1000
546
+ }
547
+
548
+ class MyService {
549
+ constructor(private config: MyPluginConfig) {}
550
+
551
+ enhance(text: string): string {
552
+ if (!this.config.enabled) return text
553
+ const prefixed = this.config.prefix + text
554
+ return prefixed.slice(0, this.config.maxLength)
555
+ }
556
+ }
557
+
558
+ export default definePlugin({
559
+ id: 'my-plugin',
560
+ name: '我的增强插件',
561
+ description: '为提示词添加前缀',
562
+ version: '1.0.0',
563
+
564
+ configFields: [
565
+ { key: 'enabled', label: '启用', type: 'boolean', default: true },
566
+ { key: 'prefix', label: '前缀', type: 'text', default: '[Enhanced] ' },
567
+ { key: 'maxLength', label: '最大长度', type: 'number', default: 1000 }
568
+ ],
569
+ configDefaults: defaultConfig,
570
+
571
+ services: [
572
+ {
573
+ name: 'myEnhancer',
574
+ factory: (ctx) => new MyService(ctx.getConfig<MyPluginConfig>())
575
+ }
576
+ ],
577
+
578
+ middlewares: [
579
+ {
580
+ name: 'my-enhancer',
581
+ displayName: '提示词增强',
582
+ phase: 'lifecycle-pre-request',
583
+ category: 'my-plugin',
584
+ priority: 10,
585
+
586
+ async execute(mctx: MiddlewareContext, next) {
587
+ const service = mctx.getService<MyService>('myEnhancer')
588
+ if (service) {
589
+ const original = mctx.prompt
590
+ mctx.prompt = service.enhance(mctx.prompt)
591
+ mctx.setMiddlewareLog('my-enhancer', {
592
+ original,
593
+ enhanced: mctx.prompt
594
+ })
595
+ }
596
+ return next()
597
+ }
598
+ }
599
+ ],
600
+
601
+ async onLoad(ctx) {
602
+ ctx.logger.info('My plugin loaded with config: %o', ctx.getConfig())
603
+ }
604
+ })
605
+ ```
606
+
607
+ ---
608
+
609
+ ## 注意事项
610
+
611
+ ### 1. 插件 ID 命名规范
612
+
613
+ - 使用 kebab-case:`my-plugin`, `connector-openai`
614
+ - 连接器插件建议以 `connector-` 开头
615
+
616
+ ### 2. 配置键与插件 ID
617
+
618
+ 中间件通过 `category` 字段关联到插件配置。确保:
619
+ - 中间件的 `category` 与插件 `id` 一致
620
+ - 或者使用 `getMiddlewareConfig(pluginId)` 时传入正确的插件 ID
621
+
622
+ ### 3. 服务命名
623
+
624
+ 服务名称全局唯一,建议使用插件 ID 作为前缀:
625
+ - `myPlugin` 或 `my-plugin-service`
626
+
627
+ ### 4. 错误处理
628
+
629
+ 中间件中抛出的错误会导致整个请求失败。对于非致命错误,建议:
630
+ - 记录日志
631
+ - 设置 middlewareLog
632
+ - 继续执行 `next()`
633
+
634
+ ```typescript
635
+ async execute(mctx, next) {
636
+ try {
637
+ // 可能失败的操作
638
+ } catch (e) {
639
+ mctx.setMiddlewareLog('my-middleware', { error: e.message })
640
+ // 非致命错误,继续执行
641
+ }
642
+ return next()
643
+ }
644
+ ```
645
+
646
+ ---
647
+
648
+ ## 内置插件参考
649
+
650
+ 查看以下内置插件作为开发参考:
651
+
652
+ | 插件 | 说明 | 关键特性 |
653
+ |-----|------|---------|
654
+ | `cache` | 缓存管理 | 服务 + 多中间件 + HTTP 路由 |
655
+ | `preset` | 预设系统 | 服务 + 远程同步 + 数据库 |
656
+ | `billing` | 计费系统 | 双中间件(预扣/结算) |
657
+ | `task` | 任务记录 | 数据库操作 + 统计 |
658
+ | `connector-*` | 各连接器 | 连接器定义示例 |
659
+
660
+ ---
661
+
662
+ ## 外部插件(第三方插件)
663
+
664
+ Media Luna 支持从 npm 模块加载第三方插件。
665
+
666
+ ### 外部插件格式
667
+
668
+ 外部插件需要是一个 npm 包,默认导出 `PluginDefinition`:
669
+
670
+ ```typescript
671
+ // koishi-plugin-media-luna-xxx/src/index.ts
672
+ import { definePlugin } from 'koishi-plugin-media-luna'
673
+
674
+ export default definePlugin({
675
+ id: 'my-external-plugin',
676
+ name: '我的外部插件',
677
+ // ... 其他配置
678
+ })
679
+ ```
680
+
681
+ ### 加载外部插件
682
+
683
+ 通过 API 或配置加载:
684
+
685
+ ```typescript
686
+ // 通过 API 加载
687
+ await ctx.mediaLuna.pluginLoader.addExternalPlugin('koishi-plugin-media-luna-xxx')
688
+
689
+ // 通过配置(config.yaml)
690
+ externalPlugins:
691
+ - koishi-plugin-media-luna-xxx
692
+ - ./path/to/local/plugin
693
+ ```
694
+
695
+ ### 前端 API
696
+
697
+ ```typescript
698
+ import { pluginApi } from '@koishijs/plugin-media-luna/client'
699
+
700
+ // 获取已加载的外部插件
701
+ const externals = await pluginApi.externalList()
702
+
703
+ // 添加外部插件
704
+ await pluginApi.externalAdd('koishi-plugin-media-luna-xxx')
705
+
706
+ // 移除外部插件
707
+ await pluginApi.externalRemove('koishi-plugin-media-luna-xxx')
708
+ ```
709
+
710
+ ---
711
+
712
+ ## TODO / 已知限制
713
+
714
+ 1. **前端扩展组件** - 目前仅支持配置表单,自定义 Vue 组件尚未完善
715
+ 2. **插件热重载** - 配置热重载已支持,但插件代码变更需要重启
716
+ 3. **Koishi 命令封装** - 需要手动在 onLoad 中注册
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../src/plugins/cache/middleware.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,oBAAoB,EAIrB,MAAM,YAAY,CAAA;AA0EnB;;;GAGG;AACH,wBAAgB,4BAA4B,IAAI,oBAAoB,CAyEnE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,oBAAoB,CAwF9D"}
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../src/plugins/cache/middleware.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,oBAAoB,EAIrB,MAAM,YAAY,CAAA;AA0EnB;;;GAGG;AACH,wBAAgB,4BAA4B,IAAI,oBAAoB,CA0EnE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,oBAAoB,CAyF9D"}