@zhin.js/adapter-milky 3.0.2 → 4.0.1

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 (71) hide show
  1. package/CHANGELOG.md +443 -0
  2. package/README.md +35 -121
  3. package/adapters/milky.ts +68 -0
  4. package/lib/endpoint.d.ts +7 -0
  5. package/lib/endpoint.js +6 -0
  6. package/lib/index.d.ts +3 -0
  7. package/lib/index.js +3 -0
  8. package/lib/milky-agent-deps.d.ts +24 -0
  9. package/lib/milky-agent-deps.js +30 -0
  10. package/lib/milky-auth.d.ts +3 -0
  11. package/lib/milky-auth.js +30 -0
  12. package/lib/protocol.d.ts +162 -0
  13. package/lib/protocol.js +337 -0
  14. package/lib/sse-client.d.ts +20 -0
  15. package/lib/sse-client.js +85 -0
  16. package/lib/sse-endpoint.d.ts +50 -0
  17. package/lib/sse-endpoint.js +261 -0
  18. package/lib/webhook-endpoint.d.ts +40 -0
  19. package/lib/webhook-endpoint.js +212 -0
  20. package/lib/ws-endpoint.d.ts +42 -0
  21. package/lib/ws-endpoint.js +320 -0
  22. package/lib/ws-types.d.ts +11 -0
  23. package/lib/ws-types.js +1 -0
  24. package/lib/wss-endpoint.d.ts +40 -0
  25. package/lib/wss-endpoint.js +263 -0
  26. package/package.json +43 -20
  27. package/plugin.ts +8 -0
  28. package/schema.json +36 -0
  29. package/src/endpoint.ts +26 -0
  30. package/src/index.ts +59 -57
  31. package/src/milky-agent-deps.ts +44 -8
  32. package/src/milky-auth.ts +29 -0
  33. package/src/protocol.ts +491 -0
  34. package/src/sse-client.ts +106 -0
  35. package/src/sse-endpoint.ts +318 -0
  36. package/src/webhook-endpoint.ts +262 -0
  37. package/src/ws-endpoint.ts +373 -0
  38. package/src/ws-types.ts +12 -0
  39. package/src/wss-endpoint.ts +305 -0
  40. package/lib/src/adapter.js +0 -99
  41. package/lib/src/adapter.js.map +0 -1
  42. package/lib/src/api.js +0 -48
  43. package/lib/src/api.js.map +0 -1
  44. package/lib/src/endpoint-sse.js +0 -197
  45. package/lib/src/endpoint-sse.js.map +0 -1
  46. package/lib/src/endpoint-webhook.js +0 -189
  47. package/lib/src/endpoint-webhook.js.map +0 -1
  48. package/lib/src/endpoint-ws.js +0 -264
  49. package/lib/src/endpoint-ws.js.map +0 -1
  50. package/lib/src/endpoint-wss.js +0 -227
  51. package/lib/src/endpoint-wss.js.map +0 -1
  52. package/lib/src/index.js +0 -45
  53. package/lib/src/index.js.map +0 -1
  54. package/lib/src/milky-agent-deps.js +0 -10
  55. package/lib/src/milky-agent-deps.js.map +0 -1
  56. package/lib/src/segment-mapper.js +0 -2
  57. package/lib/src/segment-mapper.js.map +0 -1
  58. package/lib/src/types.js +0 -5
  59. package/lib/src/types.js.map +0 -1
  60. package/lib/src/utils.js +0 -169
  61. package/lib/src/utils.js.map +0 -1
  62. package/plugin.yml +0 -3
  63. package/src/adapter.ts +0 -111
  64. package/src/api.ts +0 -63
  65. package/src/endpoint-sse.ts +0 -232
  66. package/src/endpoint-webhook.ts +0 -225
  67. package/src/endpoint-ws.ts +0 -300
  68. package/src/endpoint-wss.ts +0 -272
  69. package/src/segment-mapper.ts +0 -1
  70. package/src/types.ts +0 -73
  71. package/src/utils.ts +0 -182
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@zhin.js/adapter-milky",
3
- "version": "3.0.2",
4
- "description": "Zhin.js adapter for Milky protocol",
3
+ "version": "4.0.1",
4
+ "description": "Zhin.js Milky adapter for Plugin Runtime (WebSocket client)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
7
7
  "types": "./lib/index.d.ts",
@@ -13,13 +13,14 @@
13
13
  }
14
14
  },
15
15
  "files": [
16
+ "adapters",
17
+ "plugin.ts",
18
+ "schema.json",
16
19
  "src",
17
20
  "lib",
18
- "client",
19
- "dist",
20
- "plugin.yml",
21
+ "agent",
21
22
  "README.md",
22
- "agent"
23
+ "CHANGELOG.md"
23
24
  ],
24
25
  "keywords": [
25
26
  "zhin",
@@ -37,29 +38,32 @@
37
38
  "directory": "plugins/adapters/milky"
38
39
  },
39
40
  "dependencies": {
40
- "eventsource": "^2.0.2",
41
- "ws": "^8.21.0"
41
+ "ws": "^8.21.0",
42
+ "@zhin.js/adapter": "1.0.1",
43
+ "@zhin.js/core": "1.3.5",
44
+ "@zhin.js/host-http": "1.0.1",
45
+ "@zhin.js/logger": "1.0.75",
46
+ "@zhin.js/plugin-runtime": "1.0.1"
42
47
  },
43
48
  "devDependencies": {
44
- "@types/eventsource": "^1.1.15",
45
49
  "@types/node": "^26.1.0",
46
50
  "@types/ws": "^8.18.1",
47
51
  "typescript": "^6.0.3",
52
+ "vitest": "^4.1.10",
48
53
  "zod": "^4.4.3",
49
- "@zhin.js/cli": "1.0.93",
50
- "@zhin.js/client": "2.0.5",
51
- "@zhin.js/host-router": "2.0.3",
52
- "zhin.js": "4.1.2",
53
- "@zhin.js/agent": "1.0.3"
54
+ "@zhin.js/agent": "1.0.4",
55
+ "@zhin.js/host-http": "1.0.1"
54
56
  },
55
57
  "peerDependencies": {
56
58
  "zod": "^4.0.0",
57
- "@zhin.js/host-router": "2.0.3",
58
- "zhin.js": "4.1.2",
59
- "@zhin.js/agent": "1.0.3"
59
+ "@zhin.js/adapter": "1.0.1",
60
+ "@zhin.js/core": "1.3.5",
61
+ "@zhin.js/plugin-runtime": "1.0.1",
62
+ "zhin.js": "4.1.3",
63
+ "@zhin.js/agent": "1.0.4"
60
64
  },
61
65
  "peerDependenciesMeta": {
62
- "@zhin.js/host-router": {
66
+ "zhin.js": {
63
67
  "optional": true
64
68
  },
65
69
  "@zhin.js/agent": {
@@ -74,11 +78,30 @@
74
78
  "email": "admin@liucl.cn",
75
79
  "url": "https://github.com/lc-cn"
76
80
  },
81
+ "publishConfig": {
82
+ "access": "public",
83
+ "registry": "https://registry.npmjs.org"
84
+ },
77
85
  "engines": {
78
86
  "node": "^20.19.0 || >=22.12.0"
79
87
  },
88
+ "zhin": {
89
+ "protocol": 1,
90
+ "type": "plugin",
91
+ "entry": "./plugin.ts",
92
+ "engine": "^1.0.0",
93
+ "runtime": "trusted",
94
+ "features": [
95
+ {
96
+ "package": "@zhin.js/adapter",
97
+ "api": "^1.0.0"
98
+ }
99
+ ],
100
+ "plugins": []
101
+ },
80
102
  "scripts": {
81
- "build": "zhin build",
82
- "clean": "rimraf lib"
103
+ "build": "tsc",
104
+ "clean": "rimraf lib",
105
+ "test": "NODE_OPTIONS=--experimental-strip-types vitest run --root ../../.. plugins/adapters/milky/tests"
83
106
  }
84
107
  }
package/plugin.ts ADDED
@@ -0,0 +1,8 @@
1
+ import { definePlugin } from '@zhin.js/plugin-runtime';
2
+
3
+ export default definePlugin({
4
+ name: 'milky',
5
+ metadata: {
6
+ displayName: 'Milky Adapter',
7
+ },
8
+ });
package/schema.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "additionalProperties": false,
5
+ "properties": {
6
+ "connection": {
7
+ "type": "string",
8
+ "enum": ["ws", "sse", "webhook", "wss"],
9
+ "default": "ws",
10
+ "description": "ws (default), sse (EventSource client), webhook or wss (webhook/wss via httpHostToken)"
11
+ },
12
+ "name": {
13
+ "type": "string",
14
+ "default": "milky-bot"
15
+ },
16
+ "baseUrl": {
17
+ "type": "string",
18
+ "description": "Milky HTTP API base URL (required); WS event path is derived as ws(s)://host/event"
19
+ },
20
+ "path": {
21
+ "type": "string",
22
+ "description": "Path for webhook / reverse-wss"
23
+ },
24
+ "access_token": {
25
+ "type": "string"
26
+ },
27
+ "reconnect_interval": {
28
+ "type": "number",
29
+ "default": 5000
30
+ },
31
+ "heartbeat_interval": {
32
+ "type": "number",
33
+ "default": 30000
34
+ }
35
+ }
36
+ }
@@ -0,0 +1,26 @@
1
+ export {
2
+ MilkyWsEndpoint,
3
+ type MilkyWsEndpointOptions,
4
+ } from './ws-endpoint.js';
5
+
6
+ export {
7
+ MilkyWebhookEndpoint,
8
+ type MilkyWebhookEndpointOptions,
9
+ } from './webhook-endpoint.js';
10
+
11
+ export {
12
+ MilkyWssEndpoint,
13
+ type MilkyWssEndpointOptions,
14
+ } from './wss-endpoint.js';
15
+
16
+ export {
17
+ MilkySseEndpoint,
18
+ type MilkySseEndpointOptions,
19
+ type CreateMilkySseStream,
20
+ } from './sse-endpoint.js';
21
+
22
+ export type { MilkyWsSocket, MilkyWsCreateOptions } from './ws-types.js';
23
+
24
+ export { verifyMilkyAccessToken, readRequestBody } from './milky-auth.js';
25
+
26
+ export { openSseStream, consumeSseBuffer } from './sse-client.js';
package/src/index.ts CHANGED
@@ -1,59 +1,61 @@
1
- /**
2
- * Milky 适配器入口:单一适配器,支持 WS/SSE/Webhook/反向 WS,依赖 router 注册
3
- */
4
- import { usePlugin, createSceneManagementTools, registerDefaultScenePlatformPermitChecker, type Plugin, type Context, type ToolFeature, type ISceneManagement } from 'zhin.js';
5
- import type { Router } from '@zhin.js/host-router';
6
- import { MilkyAdapter } from './adapter.js';
1
+ export {
2
+ buildSendAction,
3
+ buildSseConnectOptions,
4
+ buildWsConnectOptions,
5
+ callApi,
6
+ extractInboundAudioUrl,
7
+ formatInboundContent,
8
+ formatInboundMessageId,
9
+ formatInboundTarget,
10
+ formatOutboundMessageId,
11
+ formatOutboundSegments,
12
+ isMentioned,
13
+ isMessageReceiveEvent,
14
+ parseMessageReceiveData,
15
+ parseMilkyMessageId,
16
+ parseSendTarget,
17
+ resolveMilkyConfig,
18
+ senderNickname,
19
+ type MilkyAdapterConfig,
20
+ type MilkyApiClientOptions,
21
+ type MilkyApiResponse,
22
+ type MilkyConfigBase,
23
+ type MilkyEndpointConfig,
24
+ type MilkyEvent,
25
+ type MilkyIncomingMessage,
26
+ type MilkyIncomingSegment,
27
+ type MilkyOutgoingSegment,
28
+ type MilkySseConfig,
29
+ type MilkyWebhookConfig,
30
+ type MilkyWireSegment,
31
+ type MilkyWsConfig,
32
+ type MilkyWssConfig,
33
+ type ParsedSendTarget,
34
+ type ResolvedMilkyConfig,
35
+ } from './protocol.js';
7
36
 
8
- import { setMilkyAgentDeps } from './milky-agent-deps.js';
37
+ export {
38
+ MilkySseEndpoint,
39
+ MilkyWebhookEndpoint,
40
+ MilkyWssEndpoint,
41
+ MilkyWsEndpoint,
42
+ consumeSseBuffer,
43
+ openSseStream,
44
+ readRequestBody,
45
+ verifyMilkyAccessToken,
46
+ type CreateMilkySseStream,
47
+ type MilkySseEndpointOptions,
48
+ type MilkyWebhookEndpointOptions,
49
+ type MilkyWssEndpointOptions,
50
+ type MilkyWsCreateOptions,
51
+ type MilkyWsEndpointOptions,
52
+ type MilkyWsSocket,
53
+ } from './endpoint.js';
9
54
 
10
- export * from './types.js';
11
- export { callApi } from './api.js';
12
- export * from './utils.js';
13
- export { MilkyWsClient } from './endpoint-ws.js';
14
- export { MilkySseClient } from './endpoint-sse.js';
15
- export { MilkyWebhookEndpoint } from './endpoint-webhook.js';
16
- export { MilkyWssServer } from './endpoint-wss.js';
17
- export { MilkyAdapter, type MilkyBot } from './adapter.js';
18
-
19
- declare module 'zhin.js' {
20
- namespace Plugin {
21
- interface Contexts {
22
- router: import('@zhin.js/host-router').Router;
23
- }
24
- }
25
- interface Adapters {
26
- milky: MilkyAdapter;
27
- }
28
- }
29
-
30
- const plugin = usePlugin();
31
- const { provide, useContext } = plugin;
32
- provide({
33
- name: 'milky',
34
- description: 'Milky Adapter(WS 正向 / SSE / Webhook / 反向 WS)',
35
- mounted: async (p: Plugin) => {
36
- const adapter = new MilkyAdapter(p);
37
- await adapter.start();
38
- return adapter;
39
- },
40
- dispose: async (adapter: MilkyAdapter) => {
41
- await adapter.stop();
42
- },
43
- } as unknown as Context<'milky'>);
44
-
45
- useContext('tool', 'milky', (toolService: ToolFeature, milky: MilkyAdapter) => {
46
- const disposers: (() => void)[] = [];
47
- disposers.push(registerDefaultScenePlatformPermitChecker('milky'));
48
- setMilkyAgentDeps({
49
- getEndpoint: (endpointId) => {
50
- const endpoint = milky.endpoints.get(endpointId);
51
- if (!endpoint) throw new Error(`Endpoint ${endpointId} 不存在`);
52
- return endpoint;
53
- },
54
- getAdapter: () => milky,
55
- });
56
- const sceneTools = createSceneManagementTools(milky as unknown as ISceneManagement, 'milky');
57
- disposers.push(...sceneTools.map(t => toolService.addTool(t, plugin.name)));
58
- return () => disposers.forEach(d => d());
59
- });
55
+ export {
56
+ getMilkyAgentDeps,
57
+ registerMilkyAgentEndpoint,
58
+ setMilkyAgentDeps,
59
+ type MilkyAgentDeps,
60
+ type MilkyAgentEndpoint,
61
+ } from './milky-agent-deps.js';
@@ -1,17 +1,53 @@
1
- import type { MilkyAdapter, MilkyBot } from './adapter.js';
1
+ /**
2
+ * Agent tool deps for milky (scene management / callApi).
3
+ * Endpoints register themselves on start; tools look up by config name / endpoint id.
4
+ */
5
+
6
+ export interface MilkyAgentEndpoint {
7
+ callApi(action: string, params?: Record<string, unknown>): Promise<unknown>;
8
+ kickMember(groupId: number, userId: number, rejectAddRequest?: boolean): Promise<boolean>;
9
+ muteMember(groupId: number, userId: number, duration?: number): Promise<boolean>;
10
+ muteAll(groupId: number, enable?: boolean): Promise<boolean>;
11
+ setAdmin(groupId: number, userId: number, enable?: boolean): Promise<boolean>;
12
+ setCard(groupId: number, userId: number, card: string): Promise<boolean>;
13
+ setTitle(groupId: number, userId: number, title: string): Promise<boolean>;
14
+ setGroupName(groupId: number, name: string): Promise<boolean>;
15
+ getMemberList(groupId: number): Promise<unknown[]>;
16
+ getGroupInfo(groupId: number): Promise<unknown>;
17
+ recallMessage?(id: string): Promise<void>;
18
+ }
2
19
 
3
20
  export interface MilkyAgentDeps {
4
- getEndpoint: (endpointId: string) => MilkyBot;
5
- getAdapter: () => MilkyAdapter;
21
+ getEndpoint: (endpointId: string) => MilkyAgentEndpoint;
6
22
  }
7
23
 
8
- let _deps: MilkyAgentDeps | null = null;
24
+ const endpoints = new Map<string, MilkyAgentEndpoint>();
25
+ let override: MilkyAgentDeps | null = null;
26
+
27
+ export function registerMilkyAgentEndpoint(
28
+ endpointId: string,
29
+ endpoint: MilkyAgentEndpoint,
30
+ ): () => void {
31
+ endpoints.set(endpointId, endpoint);
32
+ return () => {
33
+ if (endpoints.get(endpointId) === endpoint) {
34
+ endpoints.delete(endpointId);
35
+ }
36
+ };
37
+ }
9
38
 
10
- export function setMilkyAgentDeps(deps: MilkyAgentDeps): void {
11
- _deps = deps;
39
+ /** Optional override used by tests / transitional callers. Pass `null` to clear. */
40
+ export function setMilkyAgentDeps(deps: MilkyAgentDeps | null): void {
41
+ override = deps;
12
42
  }
13
43
 
14
44
  export function getMilkyAgentDeps(): MilkyAgentDeps {
15
- if (!_deps) throw new Error('milky agent deps not initialized');
16
- return _deps;
45
+ if (override) return override;
46
+ return {
47
+ getEndpoint(endpointId: string): MilkyAgentEndpoint {
48
+ const registered = endpoints.get(endpointId);
49
+ if (!registered) throw new Error(`Endpoint ${endpointId} 不存在`);
50
+ return registered;
51
+ },
52
+ };
17
53
  }
@@ -0,0 +1,29 @@
1
+ import type { IncomingMessage } from 'node:http';
2
+
3
+ export function verifyMilkyAccessToken(accessToken: string | undefined, request: IncomingMessage): boolean {
4
+ if (!accessToken) return true;
5
+ const auth = request.headers.authorization ?? '';
6
+ if (auth === `Bearer ${accessToken}`) return true;
7
+ try {
8
+ const url = new URL(request.url ?? '/', 'http://localhost');
9
+ if (url.searchParams.get('access_token') === accessToken) return true;
10
+ } catch {
11
+ /* ignore */
12
+ }
13
+ return false;
14
+ }
15
+
16
+ export async function readRequestBody(request: IncomingMessage): Promise<string> {
17
+ const chunks: Buffer[] = [];
18
+ let size = 0;
19
+ for await (const chunk of request) {
20
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
21
+ size += buffer.length;
22
+ if (size > 1_048_576) {
23
+ request.destroy();
24
+ throw new Error('Request body exceeds 1MB');
25
+ }
26
+ chunks.push(buffer);
27
+ }
28
+ return Buffer.concat(chunks).toString('utf8');
29
+ }