@zhin.js/adapter-dingtalk 6.0.2 → 6.0.3

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @zhin.js/adapter-dingtalk
2
2
 
3
+ ## 6.0.3
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [afc0e66]
8
+ - Updated dependencies [2e41ad5]
9
+ - Updated dependencies [9f57124]
10
+ - @zhin.js/core@1.5.2
11
+ - @zhin.js/adapter@1.1.5
12
+ - @zhin.js/im-contract@1.0.1
13
+ - @zhin.js/plugin-runtime@1.1.3
14
+ - @zhin.js/command@1.0.7
15
+ - @zhin.js/host-http@1.0.6
16
+ - @zhin.js/agent@1.1.3
17
+ - zhin.js@6.0.2
18
+
3
19
  ## 6.0.2
4
20
 
5
21
  ### Patch Changes
package/README.md CHANGED
@@ -24,8 +24,8 @@ pnpm add @zhin.js/adapter-dingtalk
24
24
  - `@zhin.js/plugin-runtime` — `plugin.ts`(`definePlugin`)
25
25
  - 配置经插件 `schema.json` 落到 `plugins.<instanceKey>`
26
26
 
27
- 入站:`gateway.receive({ adapter, target: conversationId, content: text, sender, metadata })`
28
- 出站:`send({ target, payload })` → sessionWebhook 或 `/robot/send`
27
+ 入站:`gateway.receive({ conversation: ConversationRef, message: { conversation, id }, content: text, sender, metadata })`
28
+ 出站:`send({ conversation, payload })` → sessionWebhook 或 `/robot/send`
29
29
 
30
30
  ## 前置条件
31
31
 
package/lib/endpoint.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * DingTalkEndpoint — lifecycle, outbound, admit, OpenAPI helpers for agent tools.
3
3
  */
4
- import type { EndpointInstance } from '@zhin.js/adapter';
4
+ import type { EndpointInstance, EndpointSendRequest } from '@zhin.js/adapter';
5
5
  import type { MessageGateway } from '@zhin.js/core/runtime';
6
6
  import type { HttpHost } from '@zhin.js/host-http';
7
7
  import type { CapabilityId } from '@zhin.js/plugin-runtime';
@@ -38,10 +38,7 @@ export declare class DingTalkEndpoint implements EndpointInstance {
38
38
  open(): void;
39
39
  close(): void;
40
40
  stop(): Promise<void>;
41
- send({ target, payload }: {
42
- readonly target: string;
43
- readonly payload: unknown;
44
- }): Promise<string>;
41
+ send({ conversation, payload }: EndpointSendRequest): Promise<string>;
45
42
  /** Test / internal: admit a parsed event when open (non-webhook path). */
46
43
  admit(event: DingTalkEvent | DingTalkMessage): void;
47
44
  getUserInfo(userId: string): Promise<unknown>;
package/lib/endpoint.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { formatCompact, getLogger } from '@zhin.js/logger';
2
2
  import { registerDingtalkAgentEndpoint } from './dingtalk-agent-deps.js';
3
3
  import { normalizeDingtalkSenderForPermit } from './platform-permit.js';
4
- import { formatInboundContent, formatOutboundBody, generateMessageId, isDingtalkBotMentioned, resolveChatType, resolveSender, resolveTarget, } from './protocol.js';
4
+ import { dingtalkInboundConversation, formatInboundContent, formatOutboundBody, generateMessageId, isDingtalkBotMentioned, resolveChatType, resolveSender, } from './protocol.js';
5
5
  import { registerDingTalkWebhookRoutes } from './webhook.js';
6
6
  const logger = getLogger('dingtalk');
7
7
  /**
@@ -66,9 +66,9 @@ export class DingTalkEndpoint {
66
66
  this.#started = false;
67
67
  logger.debug(formatCompact({ op: 'disconnect', endpoint: this.#options.config.name }));
68
68
  }
69
- async send({ target, payload }) {
69
+ async send({ conversation, payload }) {
70
70
  const content = formatOutboundBody(payload);
71
- const sessionWebhook = this.#sessionWebhooks.get(target);
71
+ const sessionWebhook = this.#sessionWebhooks.get(conversation.id);
72
72
  if (sessionWebhook) {
73
73
  const response = await this.#fetch(sessionWebhook, {
74
74
  method: 'POST',
@@ -83,7 +83,7 @@ export class DingTalkEndpoint {
83
83
  op: 'send',
84
84
  endpoint: this.#options.config.name,
85
85
  via: 'sessionWebhook',
86
- to: target,
86
+ to: conversation.id,
87
87
  }));
88
88
  return data.msgId || `${Date.now()}`;
89
89
  }
@@ -100,7 +100,7 @@ export class DingTalkEndpoint {
100
100
  if (data.errcode !== 0) {
101
101
  throw new Error(`Failed to send message: ${data.errmsg}`);
102
102
  }
103
- logger.debug(formatCompact({ op: 'send', endpoint: this.#options.config.name, to: target }));
103
+ logger.debug(formatCompact({ op: 'send', endpoint: this.#options.config.name, to: conversation.id }));
104
104
  return data.msgId || `${Date.now()}`;
105
105
  }
106
106
  /** Test / internal: admit a parsed event when open (non-webhook path). */
@@ -110,15 +110,14 @@ export class DingTalkEndpoint {
110
110
  if (event.sessionWebhook && event.conversationId) {
111
111
  this.#sessionWebhooks.set(event.conversationId, event.sessionWebhook);
112
112
  }
113
- const target = resolveTarget(event);
113
+ const conversation = dingtalkInboundConversation(String(this.#options.id), event);
114
114
  const chatType = resolveChatType(event.conversationType);
115
115
  const permit = normalizeDingtalkSenderForPermit({ isAdmin: event.isAdmin === true });
116
116
  void this.#options.gateway.receive({
117
- adapter: this.#options.id,
118
- target,
117
+ conversation,
118
+ message: { conversation, id: generateMessageId(event) },
119
119
  content: formatInboundContent(event),
120
120
  sender: resolveSender(event),
121
- id: generateMessageId(event),
122
121
  metadata: Object.freeze({
123
122
  msgtype: event.msgtype,
124
123
  chatType,
@@ -132,7 +131,7 @@ export class DingTalkEndpoint {
132
131
  }).catch((err) => {
133
132
  logger.warn(formatCompact({
134
133
  op: 'dingtalk_gateway_receive_failed',
135
- target,
134
+ conversationId: conversation.id,
136
135
  error: err instanceof Error ? err.message : String(err),
137
136
  }));
138
137
  });
package/lib/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { formatInboundContent, formatOutboundBody, generateMessageId, headerValue, normalizeWebhookPath, readTextBody, resolveChatType, resolveDingTalkConfig, resolveSender, resolveTarget, verifySignature, type AccessToken, type DingTalkAdapterConfig, type DingTalkApiResponse, type DingTalkEvent, type DingTalkMessage, type DingTalkSendBody, type DingTalkWireSegment, type ResolvedDingTalkConfig, } from './protocol.js';
1
+ export { dingtalkInboundConversation, formatInboundContent, formatOutboundBody, generateMessageId, headerValue, normalizeWebhookPath, readTextBody, resolveChatType, resolveDingTalkConfig, resolveSender, verifySignature, type AccessToken, type DingTalkAdapterConfig, type DingTalkApiResponse, type DingTalkEvent, type DingTalkMessage, type DingTalkSendBody, type DingTalkWireSegment, type ResolvedDingTalkConfig, } from './protocol.js';
2
2
  export { DingTalkEndpoint, type DingTalkEndpointOptions, type DingTalkFetch, } from './endpoint.js';
3
3
  export { registerDingTalkWebhookRoutes, handleDingTalkWebhookRequest, type DingTalkWebhookHandler, } from './webhook.js';
4
4
  export { getDingtalkAgentDeps, registerDingtalkAgentEndpoint, setDingtalkAgentDeps, type DingtalkAgentDeps, type DingtalkAgentEndpoint, } from './dingtalk-agent-deps.js';
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { formatInboundContent, formatOutboundBody, generateMessageId, headerValue, normalizeWebhookPath, readTextBody, resolveChatType, resolveDingTalkConfig, resolveSender, resolveTarget, verifySignature, } from './protocol.js';
1
+ export { dingtalkInboundConversation, formatInboundContent, formatOutboundBody, generateMessageId, headerValue, normalizeWebhookPath, readTextBody, resolveChatType, resolveDingTalkConfig, resolveSender, verifySignature, } from './protocol.js';
2
2
  export { DingTalkEndpoint, } from './endpoint.js';
3
3
  export { registerDingTalkWebhookRoutes, handleDingTalkWebhookRequest, } from './webhook.js';
4
4
  export { getDingtalkAgentDeps, registerDingtalkAgentEndpoint, setDingtalkAgentDeps, } from './dingtalk-agent-deps.js';
package/lib/protocol.d.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  * Canonicalization is owned by gateway/core before endpoint.send.
4
4
  */
5
5
  import type { IncomingMessage } from 'node:http';
6
+ import type { ConversationRef } from '@zhin.js/im-contract';
6
7
  /** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
7
8
  export interface DingTalkAdapterConfig {
8
9
  readonly name?: string;
@@ -104,7 +105,12 @@ export interface DingTalkSendBody {
104
105
  export declare function resolveDingTalkConfig(config?: DingTalkAdapterConfig): ResolvedDingTalkConfig;
105
106
  export declare function normalizeWebhookPath(path: string): string;
106
107
  export declare function resolveChatType(conversationType?: string): 'group' | 'private';
107
- export declare function resolveTarget(msg: DingTalkMessage): string;
108
+ /**
109
+ * 入站归一化 → ConversationRef:`conversationType: '2'` 为群会话(kind 'group'),
110
+ * 其余为单聊(kind 'private');会话原生 id 取 conversationId,缺省回退 senderId。
111
+ * 钉钉无 guild/频道容器概念,不产生 parent。
112
+ */
113
+ export declare function dingtalkInboundConversation(endpointId: string, msg: DingTalkMessage): ConversationRef;
108
114
  export declare function resolveSender(msg: DingTalkMessage): string;
109
115
  export declare function generateMessageId(msg: DingTalkMessage): string;
110
116
  /** Build inbound text for MessageGateway.receive. */
package/lib/protocol.js CHANGED
@@ -53,8 +53,17 @@ export function normalizeWebhookPath(path) {
53
53
  export function resolveChatType(conversationType) {
54
54
  return conversationType === '2' ? 'group' : 'private';
55
55
  }
56
- export function resolveTarget(msg) {
57
- return msg.conversationId || msg.senderId || 'unknown';
56
+ /**
57
+ * 入站归一化 ConversationRef:`conversationType: '2'` 为群会话(kind 'group'),
58
+ * 其余为单聊(kind 'private');会话原生 id 取 conversationId,缺省回退 senderId。
59
+ * 钉钉无 guild/频道容器概念,不产生 parent。
60
+ */
61
+ export function dingtalkInboundConversation(endpointId, msg) {
62
+ return {
63
+ endpoint: { id: endpointId, adapter: endpointId.split('\0')[0] ?? endpointId },
64
+ kind: resolveChatType(msg.conversationType),
65
+ id: msg.conversationId || msg.senderId || 'unknown',
66
+ };
58
67
  }
59
68
  export function resolveSender(msg) {
60
69
  return msg.senderId || msg.senderStaffId || 'unknown';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/adapter-dingtalk",
3
- "version": "6.0.2",
3
+ "version": "6.0.3",
4
4
  "description": "Zhin.js DingTalk (钉钉) adapter for Plugin Runtime (HTTP webhook)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -33,21 +33,22 @@
33
33
  "directory": "plugins/adapters/dingtalk"
34
34
  },
35
35
  "dependencies": {
36
- "@zhin.js/adapter": "1.1.4",
37
- "@zhin.js/command": "1.0.6",
38
- "@zhin.js/core": "1.5.1",
39
- "@zhin.js/host-http": "1.0.5",
36
+ "@zhin.js/adapter": "1.1.5",
37
+ "@zhin.js/command": "1.0.7",
38
+ "@zhin.js/core": "1.5.2",
39
+ "@zhin.js/host-http": "1.0.6",
40
+ "@zhin.js/im-contract": "1.0.1",
40
41
  "@zhin.js/logger": "1.0.75",
41
- "@zhin.js/plugin-runtime": "1.1.2"
42
+ "@zhin.js/plugin-runtime": "1.1.3"
42
43
  },
43
44
  "peerDependencies": {
44
45
  "zod": "^4.0.0",
45
- "@zhin.js/adapter": "1.1.4",
46
- "@zhin.js/agent": "1.1.2",
47
- "@zhin.js/core": "1.5.1",
48
- "@zhin.js/host-http": "1.0.5",
49
- "@zhin.js/plugin-runtime": "1.1.2",
50
- "zhin.js": "6.0.1"
46
+ "@zhin.js/adapter": "1.1.5",
47
+ "@zhin.js/agent": "1.1.3",
48
+ "@zhin.js/core": "1.5.2",
49
+ "@zhin.js/host-http": "1.0.6",
50
+ "@zhin.js/plugin-runtime": "1.1.3",
51
+ "zhin.js": "6.0.2"
51
52
  },
52
53
  "peerDependenciesMeta": {
53
54
  "zhin.js": {
@@ -65,8 +66,8 @@
65
66
  "typescript": "^6.0.3",
66
67
  "vitest": "^4.1.10",
67
68
  "zod": "^4.4.3",
68
- "@zhin.js/agent": "1.1.2",
69
- "zhin.js": "6.0.1"
69
+ "@zhin.js/agent": "1.1.3",
70
+ "zhin.js": "6.0.2"
70
71
  },
71
72
  "files": [
72
73
  "adapters",
package/src/endpoint.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * DingTalkEndpoint — lifecycle, outbound, admit, OpenAPI helpers for agent tools.
3
3
  */
4
- import type { EndpointInstance } from '@zhin.js/adapter';
4
+ import type { EndpointInstance, EndpointSendRequest } from '@zhin.js/adapter';
5
5
  import type { MessageGateway } from '@zhin.js/core/runtime';
6
6
  import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
7
7
  import { formatCompact, getLogger } from '@zhin.js/logger';
@@ -9,13 +9,13 @@ import type { CapabilityId } from '@zhin.js/plugin-runtime';
9
9
  import { registerDingtalkAgentEndpoint } from './dingtalk-agent-deps.js';
10
10
  import { normalizeDingtalkSenderForPermit } from './platform-permit.js';
11
11
  import {
12
+ dingtalkInboundConversation,
12
13
  formatInboundContent,
13
14
  formatOutboundBody,
14
15
  generateMessageId,
15
16
  isDingtalkBotMentioned,
16
17
  resolveChatType,
17
18
  resolveSender,
18
- resolveTarget,
19
19
  type AccessToken,
20
20
  type DingTalkApiResponse,
21
21
  type DingTalkEvent,
@@ -116,9 +116,9 @@ export class DingTalkEndpoint implements EndpointInstance {
116
116
  logger.debug(formatCompact({ op: 'disconnect', endpoint: this.#options.config.name }));
117
117
  }
118
118
 
119
- async send({ target, payload }: { readonly target: string; readonly payload: unknown }): Promise<string> {
119
+ async send({ conversation, payload }: EndpointSendRequest): Promise<string> {
120
120
  const content = formatOutboundBody(payload);
121
- const sessionWebhook = this.#sessionWebhooks.get(target);
121
+ const sessionWebhook = this.#sessionWebhooks.get(conversation.id);
122
122
  if (sessionWebhook) {
123
123
  const response = await this.#fetch(sessionWebhook, {
124
124
  method: 'POST',
@@ -133,7 +133,7 @@ export class DingTalkEndpoint implements EndpointInstance {
133
133
  op: 'send',
134
134
  endpoint: this.#options.config.name,
135
135
  via: 'sessionWebhook',
136
- to: target,
136
+ to: conversation.id,
137
137
  }));
138
138
  return (data.msgId as string) || `${Date.now()}`;
139
139
  }
@@ -151,7 +151,7 @@ export class DingTalkEndpoint implements EndpointInstance {
151
151
  if (data.errcode !== 0) {
152
152
  throw new Error(`Failed to send message: ${data.errmsg}`);
153
153
  }
154
- logger.debug(formatCompact({ op: 'send', endpoint: this.#options.config.name, to: target }));
154
+ logger.debug(formatCompact({ op: 'send', endpoint: this.#options.config.name, to: conversation.id }));
155
155
  return (data.msgId as string) || `${Date.now()}`;
156
156
  }
157
157
 
@@ -161,15 +161,14 @@ export class DingTalkEndpoint implements EndpointInstance {
161
161
  if (event.sessionWebhook && event.conversationId) {
162
162
  this.#sessionWebhooks.set(event.conversationId, event.sessionWebhook);
163
163
  }
164
- const target = resolveTarget(event);
164
+ const conversation = dingtalkInboundConversation(String(this.#options.id), event);
165
165
  const chatType = resolveChatType(event.conversationType);
166
166
  const permit = normalizeDingtalkSenderForPermit({ isAdmin: event.isAdmin === true });
167
167
  void this.#options.gateway.receive({
168
- adapter: this.#options.id,
169
- target,
168
+ conversation,
169
+ message: { conversation, id: generateMessageId(event) },
170
170
  content: formatInboundContent(event),
171
171
  sender: resolveSender(event),
172
- id: generateMessageId(event),
173
172
  metadata: Object.freeze({
174
173
  msgtype: event.msgtype,
175
174
  chatType,
@@ -183,7 +182,7 @@ export class DingTalkEndpoint implements EndpointInstance {
183
182
  }).catch((err) => {
184
183
  logger.warn(formatCompact({
185
184
  op: 'dingtalk_gateway_receive_failed',
186
- target,
185
+ conversationId: conversation.id,
187
186
  error: err instanceof Error ? err.message : String(err),
188
187
  }));
189
188
  });
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export {
2
+ dingtalkInboundConversation,
2
3
  formatInboundContent,
3
4
  formatOutboundBody,
4
5
  generateMessageId,
@@ -8,7 +9,6 @@ export {
8
9
  resolveChatType,
9
10
  resolveDingTalkConfig,
10
11
  resolveSender,
11
- resolveTarget,
12
12
  verifySignature,
13
13
  type AccessToken,
14
14
  type DingTalkAdapterConfig,
package/src/protocol.ts CHANGED
@@ -7,6 +7,7 @@ import { createHmac, timingSafeEqual } from 'node:crypto';
7
7
  import type { IncomingMessage } from 'node:http';
8
8
 
9
9
  import { isMediaRef } from '@zhin.js/core';
10
+ import type { ConversationRef } from '@zhin.js/im-contract';
10
11
  import { formatCompact, getLogger } from '@zhin.js/logger';
11
12
 
12
13
  const logger = getLogger('dingtalk');
@@ -154,8 +155,17 @@ export function resolveChatType(conversationType?: string): 'group' | 'private'
154
155
  return conversationType === '2' ? 'group' : 'private';
155
156
  }
156
157
 
157
- export function resolveTarget(msg: DingTalkMessage): string {
158
- return msg.conversationId || msg.senderId || 'unknown';
158
+ /**
159
+ * 入站归一化 ConversationRef:`conversationType: '2'` 为群会话(kind 'group'),
160
+ * 其余为单聊(kind 'private');会话原生 id 取 conversationId,缺省回退 senderId。
161
+ * 钉钉无 guild/频道容器概念,不产生 parent。
162
+ */
163
+ export function dingtalkInboundConversation(endpointId: string, msg: DingTalkMessage): ConversationRef {
164
+ return {
165
+ endpoint: { id: endpointId, adapter: endpointId.split('\0')[0] ?? endpointId },
166
+ kind: resolveChatType(msg.conversationType),
167
+ id: msg.conversationId || msg.senderId || 'unknown',
168
+ };
159
169
  }
160
170
 
161
171
  export function resolveSender(msg: DingTalkMessage): string {