@krischoichoi/channel-dingtalk 0.6.0
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/README.md +139 -0
- package/lib/adapter.d.ts +123 -0
- package/lib/adapter.d.ts.map +1 -0
- package/lib/adapter.js +355 -0
- package/lib/adapter.js.map +1 -0
- package/lib/ai-card.d.ts +64 -0
- package/lib/ai-card.d.ts.map +1 -0
- package/lib/ai-card.js +150 -0
- package/lib/ai-card.js.map +1 -0
- package/lib/auth/device-registration.d.ts +18 -0
- package/lib/auth/device-registration.d.ts.map +1 -0
- package/lib/auth/device-registration.js +147 -0
- package/lib/auth/device-registration.js.map +1 -0
- package/lib/config.d.ts +119 -0
- package/lib/config.d.ts.map +1 -0
- package/lib/config.js +75 -0
- package/lib/config.js.map +1 -0
- package/lib/definition.d.ts +53 -0
- package/lib/definition.d.ts.map +1 -0
- package/lib/definition.js +227 -0
- package/lib/definition.js.map +1 -0
- package/lib/image-hydrator.d.ts +213 -0
- package/lib/image-hydrator.d.ts.map +1 -0
- package/lib/image-hydrator.js +244 -0
- package/lib/image-hydrator.js.map +1 -0
- package/lib/inbound.d.ts +38 -0
- package/lib/inbound.d.ts.map +1 -0
- package/lib/inbound.js +158 -0
- package/lib/inbound.js.map +1 -0
- package/lib/index.d.ts +49 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +123 -0
- package/lib/index.js.map +1 -0
- package/lib/manifest.d.ts +23 -0
- package/lib/manifest.d.ts.map +1 -0
- package/lib/manifest.js +34 -0
- package/lib/manifest.js.map +1 -0
- package/lib/mapper.d.ts +36 -0
- package/lib/mapper.d.ts.map +1 -0
- package/lib/mapper.js +175 -0
- package/lib/mapper.js.map +1 -0
- package/lib/media-mime.d.ts +14 -0
- package/lib/media-mime.d.ts.map +1 -0
- package/lib/media-mime.js +32 -0
- package/lib/media-mime.js.map +1 -0
- package/lib/official-upstream.d.ts +143 -0
- package/lib/official-upstream.d.ts.map +1 -0
- package/lib/official-upstream.js +425 -0
- package/lib/official-upstream.js.map +1 -0
- package/lib/openapi-port.d.ts +190 -0
- package/lib/openapi-port.d.ts.map +1 -0
- package/lib/openapi-port.js +2 -0
- package/lib/openapi-port.js.map +1 -0
- package/lib/outbound.d.ts +69 -0
- package/lib/outbound.d.ts.map +1 -0
- package/lib/outbound.js +148 -0
- package/lib/outbound.js.map +1 -0
- package/lib/stream-upstream.d.ts +77 -0
- package/lib/stream-upstream.d.ts.map +1 -0
- package/lib/stream-upstream.js +303 -0
- package/lib/stream-upstream.js.map +1 -0
- package/lib/transport.d.ts +37 -0
- package/lib/transport.d.ts.map +1 -0
- package/lib/transport.js +73 -0
- package/lib/transport.js.map +1 -0
- package/lib/upstream.d.ts +60 -0
- package/lib/upstream.d.ts.map +1 -0
- package/lib/upstream.js +61 -0
- package/lib/upstream.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
import { ChannelError, SecureRemoteMediaFetcher } from '@krischoichoi/channel-core';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { sniffImageMime } from './media-mime.js';
|
|
4
|
+
import { DEFAULT_DINGTALK_INTERACTIVE_TEMPLATE_ID } from './config.js';
|
|
5
|
+
const DINGTALK_API = 'https://api.dingtalk.com';
|
|
6
|
+
const DINGTALK_OAPI = 'https://oapi.dingtalk.com';
|
|
7
|
+
const AI_CARD_TEMPLATE_ID = DEFAULT_DINGTALK_INTERACTIVE_TEMPLATE_ID;
|
|
8
|
+
const tokenSchema = z.object({
|
|
9
|
+
accessToken: z.string().trim().min(1),
|
|
10
|
+
expireIn: z.coerce.number().positive().optional(),
|
|
11
|
+
}).passthrough();
|
|
12
|
+
const mediaUploadSchema = z.object({
|
|
13
|
+
mediaId: z.string().min(1).optional(),
|
|
14
|
+
media_id: z.string().min(1).optional(),
|
|
15
|
+
mediaIdV2: z.string().min(1).optional(),
|
|
16
|
+
}).passthrough();
|
|
17
|
+
const robotSendResponseSchema = z.object({
|
|
18
|
+
messageId: z.string().min(1).optional(),
|
|
19
|
+
processQueryKey: z.string().min(1).optional(),
|
|
20
|
+
}).passthrough();
|
|
21
|
+
const replyTargetSchema = z.object({
|
|
22
|
+
sessionWebhook: z.string().url().optional(),
|
|
23
|
+
conversationType: z.string().optional(),
|
|
24
|
+
conversationId: z.string().min(1).optional(),
|
|
25
|
+
senderId: z.string().min(1).optional(),
|
|
26
|
+
robotCode: z.string().min(1).optional(),
|
|
27
|
+
}).passthrough();
|
|
28
|
+
/**
|
|
29
|
+
* Official DingTalk OpenAPI port implementation (rename of the former
|
|
30
|
+
* `DingTalkOfficialUpstream`). Implements the small `DingTalkOpenApiPort`
|
|
31
|
+
* plus the `DingTalkUpstream` outbound surface it always had.
|
|
32
|
+
*
|
|
33
|
+
* The legacy name `DingTalkOfficialUpstream` is preserved as an alias below so
|
|
34
|
+
* existing import/call sites and tests keep compiling unchanged.
|
|
35
|
+
*/
|
|
36
|
+
export class DingTalkOpenApiPortImpl {
|
|
37
|
+
options;
|
|
38
|
+
now;
|
|
39
|
+
cachedToken;
|
|
40
|
+
inputingCards = new Set();
|
|
41
|
+
secureFetch;
|
|
42
|
+
constructor(options) {
|
|
43
|
+
this.options = options;
|
|
44
|
+
this.now = options.now ?? Date.now;
|
|
45
|
+
this.secureFetch = options.secureFetch ?? new SecureRemoteMediaFetcher();
|
|
46
|
+
}
|
|
47
|
+
async receive() {
|
|
48
|
+
throw new ChannelError('CHANNEL_ERROR', 'official DingTalk outbound driver does not receive messages');
|
|
49
|
+
}
|
|
50
|
+
/** Reply path: sessionWebhook is ONLY for the current inbound reply. */
|
|
51
|
+
async sendText(target, text) {
|
|
52
|
+
const targetData = this.targetData(target);
|
|
53
|
+
const sessionWebhook = targetData.sessionWebhook;
|
|
54
|
+
if (!sessionWebhook) {
|
|
55
|
+
throw new ChannelError('CHANNEL_ERROR', 'dingtalk reply is missing the inbound sessionWebhook');
|
|
56
|
+
}
|
|
57
|
+
return this.options.transport.request(sessionWebhook, {
|
|
58
|
+
method: 'POST',
|
|
59
|
+
headers: { 'x-acs-dingtalk-access-token': await this.getAccessToken() },
|
|
60
|
+
body: { msgtype: 'text', text: { content: text } },
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get (and cache) the application access token. Official behavior basis:
|
|
65
|
+
* DingTalk OpenAPI `POST /v1.0/oauth2/accessToken` (the official connector's
|
|
66
|
+
* token acquisition, mirrored here).
|
|
67
|
+
*/
|
|
68
|
+
async getAccessToken() {
|
|
69
|
+
const now = this.now();
|
|
70
|
+
if (this.cachedToken && this.cachedToken.expiresAt > now + 60_000)
|
|
71
|
+
return this.cachedToken.value;
|
|
72
|
+
const clientId = this.options.clientId?.trim();
|
|
73
|
+
const clientSecret = this.options.clientSecret?.trim();
|
|
74
|
+
if (!clientId || !clientSecret) {
|
|
75
|
+
throw new ChannelError('CHANNEL_ERROR', 'dingtalk official outbound requires clientId and clientSecret');
|
|
76
|
+
}
|
|
77
|
+
const raw = await this.options.transport.request(`${DINGTALK_API}/v1.0/oauth2/accessToken`, {
|
|
78
|
+
method: 'POST',
|
|
79
|
+
body: { appKey: clientId, appSecret: clientSecret },
|
|
80
|
+
});
|
|
81
|
+
const parsed = tokenSchema.safeParse(raw);
|
|
82
|
+
if (!parsed.success) {
|
|
83
|
+
throw new ChannelError('CHANNEL_ERROR', 'dingtalk access token response is invalid');
|
|
84
|
+
}
|
|
85
|
+
const expireInMs = (parsed.data.expireIn ?? 7200) * 1000;
|
|
86
|
+
this.cachedToken = { value: parsed.data.accessToken, expiresAt: now + expireInMs };
|
|
87
|
+
return this.cachedToken.value;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Proactive plain-text robot send: official proactive API,
|
|
91
|
+
* never sessionWebhook. Official behavior basis: DingTalk robot message send
|
|
92
|
+
* (`POST /v1.0/robot/groupMessages/send` for groups;
|
|
93
|
+
* `POST /v1.0/robot/oToMessages/batchSend` for single chat), msgKey `sampleText`,
|
|
94
|
+
* msgParam `{ "content": ... }` — mirrors the official connector's proactive
|
|
95
|
+
* robot message path. Payload contract from the official connector.
|
|
96
|
+
*/
|
|
97
|
+
async sendProactiveText(input) {
|
|
98
|
+
const key = input.conversationType === 'dm' ? 'oToMessages/batchSend' : 'groupMessages/send';
|
|
99
|
+
const token = await this.getAccessToken();
|
|
100
|
+
const body = input.conversationType === 'dm'
|
|
101
|
+
? { robotCode: input.robotCode, userIds: [input.conversationId], msgKey: 'sampleText', msgParam: JSON.stringify({ content: input.text }) }
|
|
102
|
+
: { openConversationId: input.conversationId, robotCode: input.robotCode, msgKey: 'sampleText', msgParam: JSON.stringify({ content: input.text }) };
|
|
103
|
+
const raw = await this.options.transport.request(`${DINGTALK_API}/v1.0/robot/${key}`, {
|
|
104
|
+
method: 'POST',
|
|
105
|
+
headers: { 'x-acs-dingtalk-access-token': token },
|
|
106
|
+
body,
|
|
107
|
+
});
|
|
108
|
+
const parsed = robotSendResponseSchema.safeParse(raw);
|
|
109
|
+
const messageId = parsed.success ? parsed.data.messageId : undefined;
|
|
110
|
+
return { messageId, raw };
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Upload a media file. Official behavior basis:
|
|
114
|
+
* DingTalk media upload `POST /media/upload?access_token=...&type=image|file`
|
|
115
|
+
* as used by the connector. Standard `FormData` delegates multipart framing
|
|
116
|
+
* to fetch instead of reproducing a platform protocol in this package.
|
|
117
|
+
*/
|
|
118
|
+
async uploadMedia(input) {
|
|
119
|
+
const token = await this.getAccessToken();
|
|
120
|
+
const form = new FormData();
|
|
121
|
+
form.append('media', new Blob([input.data], { type: input.mimeType ?? 'application/octet-stream' }), input.fileName);
|
|
122
|
+
const raw = await this.options.transport.request(`${DINGTALK_OAPI}/media/upload?access_token=${encodeURIComponent(token)}&type=${input.mediaType}`, { method: 'POST', body: form });
|
|
123
|
+
const parsed = mediaUploadSchema.safeParse(raw);
|
|
124
|
+
if (!parsed.success) {
|
|
125
|
+
throw new ChannelError('CHANNEL_ERROR', 'dingtalk media upload response is missing mediaId');
|
|
126
|
+
}
|
|
127
|
+
const mediaId = parsed.data.mediaId ?? parsed.data.media_id ?? parsed.data.mediaIdV2;
|
|
128
|
+
if (!mediaId) {
|
|
129
|
+
throw new ChannelError('CHANNEL_ERROR', 'dingtalk media upload response is missing mediaId');
|
|
130
|
+
}
|
|
131
|
+
return { mediaId };
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Send an uploaded mediaId as a robot image/file message.
|
|
135
|
+
* Official behavior basis: DingTalk robot message send with msgKey
|
|
136
|
+
* `sampleImageMsg` with `{ photoURL: mediaId }` for images, and
|
|
137
|
+
* `sampleFile` with `{ mediaId, fileName, fileType }` for files, matching
|
|
138
|
+
* the connector's verified proactive paths.
|
|
139
|
+
*/
|
|
140
|
+
async sendMedia(input) {
|
|
141
|
+
const key = input.conversationType === 'dm' ? 'oToMessages/batchSend' : 'groupMessages/send';
|
|
142
|
+
const token = await this.getAccessToken();
|
|
143
|
+
const msgParam = input.msgtype === 'image'
|
|
144
|
+
? JSON.stringify({ photoURL: input.mediaId })
|
|
145
|
+
: JSON.stringify({
|
|
146
|
+
mediaId: input.mediaId,
|
|
147
|
+
fileName: input.name ?? 'file',
|
|
148
|
+
fileType: extensionOf(input.name),
|
|
149
|
+
});
|
|
150
|
+
const msgKey = input.msgtype === 'image' ? 'sampleImageMsg' : 'sampleFile';
|
|
151
|
+
const body = input.conversationType === 'dm'
|
|
152
|
+
? { robotCode: input.robotCode, userIds: [input.conversationId], msgKey, msgParam }
|
|
153
|
+
: { openConversationId: input.conversationId, robotCode: input.robotCode, msgKey, msgParam };
|
|
154
|
+
const raw = await this.options.transport.request(`${DINGTALK_API}/v1.0/robot/${key}`, {
|
|
155
|
+
method: 'POST',
|
|
156
|
+
headers: { 'x-acs-dingtalk-access-token': token },
|
|
157
|
+
body,
|
|
158
|
+
});
|
|
159
|
+
const messageId = raw?.messageId;
|
|
160
|
+
return { messageId, raw };
|
|
161
|
+
}
|
|
162
|
+
async sendInteractiveCard(input) {
|
|
163
|
+
const targetData = this.targetData(input.target);
|
|
164
|
+
const robotCode = targetData.robotCode ?? this.options.clientId;
|
|
165
|
+
if (!robotCode)
|
|
166
|
+
throw new ChannelError('CHANNEL_ERROR', 'dingtalk interactive card is missing robotCode');
|
|
167
|
+
const openConversationId = targetData.conversationId ?? String(input.target.conversationId);
|
|
168
|
+
const outTrackId = `action_${this.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
169
|
+
const cardParamMap = {
|
|
170
|
+
[input.textParam]: input.text,
|
|
171
|
+
[input.actionsParam]: JSON.stringify(input.actions.flatMap((row) => row.actions.map((action) => ({
|
|
172
|
+
id: action.id,
|
|
173
|
+
label: action.label,
|
|
174
|
+
style: action.style ?? 'default',
|
|
175
|
+
})))),
|
|
176
|
+
};
|
|
177
|
+
const raw = await this.options.transport.request(`${DINGTALK_API}/v1.0/im/interactiveCards/send`, {
|
|
178
|
+
method: 'POST',
|
|
179
|
+
headers: { 'x-acs-dingtalk-access-token': await this.getAccessToken() },
|
|
180
|
+
body: {
|
|
181
|
+
cardTemplateId: input.templateId,
|
|
182
|
+
openConversationId,
|
|
183
|
+
outTrackId,
|
|
184
|
+
robotCode,
|
|
185
|
+
cardData: { cardParamMap },
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
const parsed = robotSendResponseSchema.safeParse(raw);
|
|
189
|
+
const messageId = parsed.success ? (parsed.data.processQueryKey ?? parsed.data.messageId) : undefined;
|
|
190
|
+
return { messageId, outTrackId, raw };
|
|
191
|
+
}
|
|
192
|
+
async updateInteractiveCard(input) {
|
|
193
|
+
const cardParamMap = {
|
|
194
|
+
[input.textParam]: input.text,
|
|
195
|
+
[input.actionsParam]: JSON.stringify(input.actions.flatMap((row) => row.actions.map((action) => ({
|
|
196
|
+
id: action.id,
|
|
197
|
+
label: action.label,
|
|
198
|
+
style: action.style ?? 'default',
|
|
199
|
+
})))),
|
|
200
|
+
};
|
|
201
|
+
return this.options.transport.request(`${DINGTALK_API}/v1.0/im/interactiveCards`, {
|
|
202
|
+
method: 'PUT',
|
|
203
|
+
headers: { 'x-acs-dingtalk-access-token': await this.getAccessToken() },
|
|
204
|
+
body: { outTrackId: input.outTrackId, cardData: { cardParamMap } },
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
async createCard(target, _text) {
|
|
208
|
+
const targetData = this.targetData(target);
|
|
209
|
+
const token = await this.getAccessToken();
|
|
210
|
+
const cardId = `card_${this.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
211
|
+
await this.options.transport.request(`${DINGTALK_API}/v1.0/card/instances`, {
|
|
212
|
+
method: 'POST',
|
|
213
|
+
headers: { 'x-acs-dingtalk-access-token': token },
|
|
214
|
+
body: {
|
|
215
|
+
cardTemplateId: AI_CARD_TEMPLATE_ID,
|
|
216
|
+
outTrackId: cardId,
|
|
217
|
+
cardData: { cardParamMap: { config: JSON.stringify({ autoLayout: true }) } },
|
|
218
|
+
callbackType: 'STREAM',
|
|
219
|
+
imGroupOpenSpaceModel: { supportForward: true },
|
|
220
|
+
imRobotOpenSpaceModel: { supportForward: true },
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
await this.options.transport.request(`${DINGTALK_API}/v1.0/card/instances/deliver`, {
|
|
224
|
+
method: 'POST',
|
|
225
|
+
headers: { 'x-acs-dingtalk-access-token': token },
|
|
226
|
+
body: this.cardDelivery(cardId, target, targetData),
|
|
227
|
+
});
|
|
228
|
+
return { cardId };
|
|
229
|
+
}
|
|
230
|
+
async updateCard(cardId, text) {
|
|
231
|
+
await this.ensureCardInputing(cardId, text);
|
|
232
|
+
return this.options.transport.request(`${DINGTALK_API}/v1.0/card/streaming`, {
|
|
233
|
+
method: 'PUT',
|
|
234
|
+
headers: { 'x-acs-dingtalk-access-token': await this.getAccessToken() },
|
|
235
|
+
body: {
|
|
236
|
+
outTrackId: cardId,
|
|
237
|
+
guid: `${this.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
238
|
+
key: 'msgContent',
|
|
239
|
+
content: text,
|
|
240
|
+
isFull: true,
|
|
241
|
+
isFinalize: false,
|
|
242
|
+
isError: false,
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
async finishCard(cardId, text = '') {
|
|
247
|
+
await this.ensureCardInputing(cardId, text);
|
|
248
|
+
const result = await this.options.transport.request(`${DINGTALK_API}/v1.0/card/streaming`, {
|
|
249
|
+
method: 'PUT',
|
|
250
|
+
headers: { 'x-acs-dingtalk-access-token': await this.getAccessToken() },
|
|
251
|
+
body: {
|
|
252
|
+
outTrackId: cardId,
|
|
253
|
+
guid: `${this.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
254
|
+
key: 'msgContent',
|
|
255
|
+
content: text,
|
|
256
|
+
isFull: true,
|
|
257
|
+
isFinalize: true,
|
|
258
|
+
isError: false,
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
this.inputingCards.delete(cardId);
|
|
262
|
+
return result;
|
|
263
|
+
}
|
|
264
|
+
async failCard(cardId, reason) {
|
|
265
|
+
await this.ensureCardInputing(cardId, reason ?? '');
|
|
266
|
+
const result = await this.options.transport.request(`${DINGTALK_API}/v1.0/card/streaming`, {
|
|
267
|
+
method: 'PUT',
|
|
268
|
+
headers: { 'x-acs-dingtalk-access-token': await this.getAccessToken() },
|
|
269
|
+
body: {
|
|
270
|
+
outTrackId: cardId,
|
|
271
|
+
guid: `${this.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
272
|
+
key: 'msgContent',
|
|
273
|
+
content: reason ?? '',
|
|
274
|
+
isFull: true,
|
|
275
|
+
isFinalize: true,
|
|
276
|
+
isError: true,
|
|
277
|
+
},
|
|
278
|
+
});
|
|
279
|
+
this.inputingCards.delete(cardId);
|
|
280
|
+
return result;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Resolve an opaque DingTalk media handle (mediaId / downloadCode) into
|
|
284
|
+
* trusted bytes. Official behavior basis: the connector's
|
|
285
|
+
* `downloadMediaByCode` / `getFileDownloadUrl` — POST
|
|
286
|
+
* `/v1.0/robot/messageFiles/download` with `{ downloadCode, robotCode }`
|
|
287
|
+
* and the application access token returns `{ downloadUrl }`; the URL is
|
|
288
|
+
* then fetched as raw bytes (responseType arraybuffer). A genuine http(s)
|
|
289
|
+
* `ref` is fetched directly. Fails closed with a typed error when an opaque
|
|
290
|
+
* ref lacks the per-message `downloadCode` context.
|
|
291
|
+
*/
|
|
292
|
+
async resolveMedia(ref, options) {
|
|
293
|
+
const isOpaqueRef = !/^https?:\/\//i.test(ref);
|
|
294
|
+
const downloadUrl = await this.getMediaDownloadUrl(ref, options);
|
|
295
|
+
if (!downloadUrl) {
|
|
296
|
+
throw new ChannelError('CHANNEL_ERROR', 'dingtalk resolveMedia: opaque ref requires per-message downloadCode context (official messageFiles/download API)');
|
|
297
|
+
}
|
|
298
|
+
const result = await this.secureFetch.fetchBounded(downloadUrl, {
|
|
299
|
+
maxBytes: 100 * 1024 * 1024,
|
|
300
|
+
idleTimeoutMs: 15_000,
|
|
301
|
+
timeoutMs: 60_000,
|
|
302
|
+
// DingTalk's authenticated messageFiles/download endpoint can return a
|
|
303
|
+
// short-lived http:// CDN URL. Permit that scheme only for an opaque
|
|
304
|
+
// handle resolved by this trusted API; direct HTTP refs remain blocked.
|
|
305
|
+
allowHttp: isOpaqueRef,
|
|
306
|
+
signal: options?.signal,
|
|
307
|
+
});
|
|
308
|
+
return {
|
|
309
|
+
data: result.data,
|
|
310
|
+
mimeType: result.mimeType ?? sniffImageMime(result.data),
|
|
311
|
+
size: result.data.byteLength,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Resolve an opaque DingTalk media handle into a download URL. Official
|
|
316
|
+
* behavior basis: the connector's `getFileDownloadUrl` — POST
|
|
317
|
+
* `/v1.0/robot/messageFiles/download` with `{ downloadCode, robotCode }`
|
|
318
|
+
* and `x-acs-dingtalk-access-token`. A genuine http(s) ref is returned
|
|
319
|
+
* as-is. Returns `undefined` (fail closed) when an opaque ref lacks the
|
|
320
|
+
* downloadCode context.
|
|
321
|
+
*/
|
|
322
|
+
async getMediaDownloadUrl(ref, options) {
|
|
323
|
+
// Genuine http(s) locator: hand it straight back (nothing to resolve).
|
|
324
|
+
if (/^https?:\/\//i.test(ref))
|
|
325
|
+
return ref;
|
|
326
|
+
const embeddedDownloadCode = ref.startsWith('downloadCode:') ? ref.slice('downloadCode:'.length) : undefined;
|
|
327
|
+
const downloadCode = options?.downloadCode ?? embeddedDownloadCode;
|
|
328
|
+
if (!downloadCode)
|
|
329
|
+
return undefined;
|
|
330
|
+
const token = await this.getAccessToken();
|
|
331
|
+
const raw = await this.options.transport.request(`${DINGTALK_API}/v1.0/robot/messageFiles/download`, {
|
|
332
|
+
method: 'POST',
|
|
333
|
+
headers: { 'x-acs-dingtalk-access-token': token },
|
|
334
|
+
// Match the official connector exactly: robotCode is the configured
|
|
335
|
+
// application AppKey/clientId, not the callback's robotCode field.
|
|
336
|
+
body: { downloadCode, robotCode: String(this.options.clientId) },
|
|
337
|
+
timeoutMs: 30_000,
|
|
338
|
+
}, options?.signal);
|
|
339
|
+
const downloadUrl = raw?.downloadUrl;
|
|
340
|
+
return typeof downloadUrl === 'string' && downloadUrl.length > 0 ? downloadUrl : undefined;
|
|
341
|
+
}
|
|
342
|
+
async ensureCardInputing(cardId, text) {
|
|
343
|
+
if (this.inputingCards.has(cardId))
|
|
344
|
+
return;
|
|
345
|
+
await this.options.transport.request(`${DINGTALK_API}/v1.0/card/instances`, {
|
|
346
|
+
method: 'PUT',
|
|
347
|
+
headers: { 'x-acs-dingtalk-access-token': await this.getAccessToken() },
|
|
348
|
+
body: {
|
|
349
|
+
outTrackId: cardId,
|
|
350
|
+
cardData: {
|
|
351
|
+
cardParamMap: {
|
|
352
|
+
flowStatus: 'INPUTING',
|
|
353
|
+
msgContent: text,
|
|
354
|
+
staticMsgContent: '',
|
|
355
|
+
sys_full_json_obj: JSON.stringify({ order: ['msgContent'] }),
|
|
356
|
+
config: JSON.stringify({ autoLayout: true }),
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
},
|
|
360
|
+
});
|
|
361
|
+
this.inputingCards.add(cardId);
|
|
362
|
+
}
|
|
363
|
+
targetData(target) {
|
|
364
|
+
const parsed = replyTargetSchema.safeParse(target.raw);
|
|
365
|
+
if (!parsed.success)
|
|
366
|
+
return {};
|
|
367
|
+
return parsed.data;
|
|
368
|
+
}
|
|
369
|
+
cardDelivery(cardId, target, targetData) {
|
|
370
|
+
const robotCode = targetData.robotCode ?? this.options.clientId;
|
|
371
|
+
if (!robotCode)
|
|
372
|
+
throw new ChannelError('CHANNEL_ERROR', 'dingtalk card delivery is missing robotCode');
|
|
373
|
+
if (target.conversationType === 'group' || targetData.conversationType === '2') {
|
|
374
|
+
const conversationId = targetData.conversationId ?? String(target.conversationId);
|
|
375
|
+
return {
|
|
376
|
+
outTrackId: cardId,
|
|
377
|
+
userIdType: 1,
|
|
378
|
+
openSpaceId: `dtv1.card//IM_GROUP.${conversationId}`,
|
|
379
|
+
imGroupOpenDeliverModel: { robotCode },
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
const userId = targetData.senderId;
|
|
383
|
+
if (!userId)
|
|
384
|
+
throw new ChannelError('CHANNEL_ERROR', 'dingtalk card delivery is missing senderId');
|
|
385
|
+
return {
|
|
386
|
+
outTrackId: cardId,
|
|
387
|
+
userIdType: 1,
|
|
388
|
+
openSpaceId: `dtv1.card//IM_ROBOT.${userId}`,
|
|
389
|
+
imRobotOpenDeliverModel: {
|
|
390
|
+
spaceType: 'IM_ROBOT',
|
|
391
|
+
robotCode,
|
|
392
|
+
extension: { dynamicSummary: 'true' },
|
|
393
|
+
},
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Official-behavior basis for every port method: maps a port method
|
|
399
|
+
* name to the corresponding official connector implementation location / behavior
|
|
400
|
+
* oracle, or an explicit `@upstream-gap` / `@deprecated` marker with a reason.
|
|
401
|
+
* The port-inventory test asserts every interface method has a non-empty entry
|
|
402
|
+
* here (shape + marker presence).
|
|
403
|
+
*/
|
|
404
|
+
export const OFFICIAL_BASIS = {
|
|
405
|
+
getAccessToken: "oracle=@dingtalk-real-ai/dingtalk-connector@0.8.24 :: DingTalk OpenAPI POST /v1.0/oauth2/accessToken token acquisition (mirrors official connector token flow)",
|
|
406
|
+
sendProactiveText: "oracle=@dingtalk-real-ai/dingtalk-connector@0.8.24 :: robot message proactive send (groupMessages/send | oToMessages/batchSend, msgKey=sampleText) — payload contract from official connector",
|
|
407
|
+
uploadMedia: "oracle=@dingtalk-real-ai/dingtalk-connector@0.8.24 :: OAPI POST /media/upload?access_token=...&type=image|file multipart(media) — official connector media path",
|
|
408
|
+
sendMedia: "oracle=@dingtalk-real-ai/dingtalk-connector@0.8.24 :: image msgKey=sampleImageMsg msgParam={photoURL:mediaId}; file msgKey=sampleFile msgParam={mediaId,fileName,fileType}",
|
|
409
|
+
createCard: "oracle=@dingtalk-real-ai/dingtalk-connector@0.8.24 :: AI Card POST /v1.0/card/instances + deliver (template 02fcf2f4-5e02-4a85-b672-46d1f715543e.schema)",
|
|
410
|
+
updateCard: "oracle=@dingtalk-real-ai/dingtalk-connector@0.8.24 :: AI Card PUT /v1.0/card/streaming update (isFinalize=false)",
|
|
411
|
+
finishCard: "oracle=@dingtalk-real-ai/dingtalk-connector@0.8.24 :: AI Card PUT /v1.0/card/streaming finalize (isFinalize=true)",
|
|
412
|
+
failCard: "oracle=@dingtalk-real-ai/dingtalk-connector@0.8.24 :: AI Card PUT /v1.0/card/streaming error (isError=true)",
|
|
413
|
+
resolveMedia: "oracle=@dingtalk-real-ai/dingtalk-connector@0.8.24 :: connector downloadMediaByCode/getFileDownloadUrl — POST /v1.0/robot/messageFiles/download {downloadCode,robotCode} -> downloadUrl -> GET raw bytes (message-handler); http(s) refs fetched directly",
|
|
414
|
+
getMediaDownloadUrl: "oracle=@dingtalk-real-ai/dingtalk-connector@0.8.24 :: connector getFileDownloadUrl — POST /v1.0/robot/messageFiles/download {downloadCode,robotCode} -> {downloadUrl} (message-handler)",
|
|
415
|
+
sendInteractiveCard: "official @dingtalk-real-ai/dingtalk-connector-compatible DingTalk interactiveCards API POST /v1.0/im/interactiveCards/send (Card Platform template + cardParamMap)",
|
|
416
|
+
updateInteractiveCard: "official @dingtalk-real-ai/dingtalk-connector-compatible DingTalk interactiveCards API PUT /v1.0/im/interactiveCards (outTrackId + cardData.cardParamMap)",
|
|
417
|
+
};
|
|
418
|
+
/** Legacy alias (rename): `DingTalkOfficialUpstream` -> `DingTalkOpenApiPortImpl`. */
|
|
419
|
+
export const DingTalkOfficialUpstream = DingTalkOpenApiPortImpl;
|
|
420
|
+
function extensionOf(fileName) {
|
|
421
|
+
const name = fileName?.trim() ?? '';
|
|
422
|
+
const index = name.lastIndexOf('.');
|
|
423
|
+
return index > -1 && index < name.length - 1 ? name.slice(index + 1).toLowerCase() : 'file';
|
|
424
|
+
}
|
|
425
|
+
//# sourceMappingURL=official-upstream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"official-upstream.js","sourceRoot":"","sources":["../src/official-upstream.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DingTalkOpenApiPort — the thin official DingTalk OpenAPI port.
|
|
3
|
+
*
|
|
4
|
+
* Two layers make up the DingTalk adapter:
|
|
5
|
+
*
|
|
6
|
+
* DingTalkStreamPort -> dingtalk-stream SDK (own module: stream-upstream.ts)
|
|
7
|
+
* DingTalkOpenApiPort -> official DingTalk OpenAPI (this port)
|
|
8
|
+
*
|
|
9
|
+
* This port is deliberately SMALL. It is the outbound counterpart to
|
|
10
|
+
* the stream callbacks: everything that is an HTTP call back into DingTalk
|
|
11
|
+
* (access token, proactive robot messages, media upload/send, AI Card
|
|
12
|
+
* create/update/finish, opaque-mediaId resolution) lives here.
|
|
13
|
+
*
|
|
14
|
+
* Behavior oracle: the official connector
|
|
15
|
+
* `@dingtalk-real-ai/dingtalk-connector@0.8.24`. Its npm exports are only
|
|
16
|
+
* `.` and `./bundled` and its root entry depends on OpenClaw, so the package
|
|
17
|
+
* cannot be used as a host-neutral SDK today. Therefore THIS adapter
|
|
18
|
+
* re-implements the thin OpenAPI calls itself — mirroring the connector's
|
|
19
|
+
* token / HTTP patterns — and records the corresponding official-behavior basis
|
|
20
|
+
* on every method (`DingTalkOpenApiPortImpl.OFFICIAL_BASIS`). If the connector
|
|
21
|
+
* later exposes host-neutral `./media` / `./messaging` / `./openapi`
|
|
22
|
+
* subpaths, the internal implementation is swapped out without touching the
|
|
23
|
+
* adapter.
|
|
24
|
+
*
|
|
25
|
+
* No second DingTalk SDK is introduced. The port never
|
|
26
|
+
* hand-writes a Stream websocket protocol — that is dingtalk-stream's job.
|
|
27
|
+
*/
|
|
28
|
+
import type { ChannelTarget } from '@krischoichoi/channel-core';
|
|
29
|
+
/**
|
|
30
|
+
* Capability flags the harness outbox reads to decide whether proactive sends
|
|
31
|
+
* are available. Fails CLOSED: a feature is only `true` when its
|
|
32
|
+
* official OAPI path is actually implemented and wired by the adapter.
|
|
33
|
+
*/
|
|
34
|
+
export interface OutboxCapabilities {
|
|
35
|
+
/** Proactive plain-text send to a conversationId via the official OAPI. */
|
|
36
|
+
proactiveText: boolean;
|
|
37
|
+
/** Proactive media (image/file) send via official upload + media send. */
|
|
38
|
+
proactiveMedia: boolean;
|
|
39
|
+
}
|
|
40
|
+
/** Result of `getAccessToken`. Kept intentionally minimal. */
|
|
41
|
+
export interface AccessTokenResult {
|
|
42
|
+
accessToken: string;
|
|
43
|
+
expireInMs: number;
|
|
44
|
+
}
|
|
45
|
+
/** Credentials + optional clock used to mint the application access token. */
|
|
46
|
+
export interface DingTalkOpenApiCredentials {
|
|
47
|
+
clientId?: string;
|
|
48
|
+
clientSecret?: string;
|
|
49
|
+
/** Injectable clock for token-expiry caching (tests). */
|
|
50
|
+
now?: () => number;
|
|
51
|
+
}
|
|
52
|
+
/** Target of a proactive robot message. */
|
|
53
|
+
export interface ProactiveTextInput {
|
|
54
|
+
/** Robot's open conversation id (group) or, for a DM, the recipient userId. */
|
|
55
|
+
conversationId: string;
|
|
56
|
+
/** The robot code (usually the AppKey). */
|
|
57
|
+
robotCode: string;
|
|
58
|
+
/** Plain text to send. */
|
|
59
|
+
text: string;
|
|
60
|
+
/** `'group'` uses robot groupMessages/send; `'dm'` uses oToMessages/batchSend. */
|
|
61
|
+
conversationType?: 'dm' | 'group';
|
|
62
|
+
}
|
|
63
|
+
/** Payload to upload a media file via the official robot file-upload endpoint. */
|
|
64
|
+
export interface MediaUploadInput {
|
|
65
|
+
/** Robot code (usually the AppKey). */
|
|
66
|
+
robotCode: string;
|
|
67
|
+
/** File name used to carry the correct content type and display name. */
|
|
68
|
+
fileName: string;
|
|
69
|
+
/** MIME type of the uploaded bytes (used as the request content type). */
|
|
70
|
+
mimeType?: string;
|
|
71
|
+
/** The raw bytes of the file to upload. */
|
|
72
|
+
data: Uint8Array;
|
|
73
|
+
/** DingTalk OAPI upload category. */
|
|
74
|
+
mediaType: 'image' | 'file';
|
|
75
|
+
/** Target conversation, when the platform requires an agentId/space for upload. */
|
|
76
|
+
target?: ChannelTarget;
|
|
77
|
+
}
|
|
78
|
+
/** Result of a successful media upload: a DingTalk `mediaId`. */
|
|
79
|
+
export interface MediaUploadResult {
|
|
80
|
+
mediaId: string;
|
|
81
|
+
}
|
|
82
|
+
/** Send an already-uploaded media id as a robot image/file message. */
|
|
83
|
+
export interface MediaSendInput {
|
|
84
|
+
/** Robot's open conversation id (group) or, for a DM, the recipient userId. */
|
|
85
|
+
conversationId: string;
|
|
86
|
+
/** The robot code (usually the AppKey). */
|
|
87
|
+
robotCode: string;
|
|
88
|
+
/** The `mediaId` returned by `uploadMedia`. */
|
|
89
|
+
mediaId: string;
|
|
90
|
+
/** `image` -> `sampleImageMsg`; `file` -> `sampleFile`. */
|
|
91
|
+
msgtype: 'image' | 'file';
|
|
92
|
+
/** Display file name for the file-message path. */
|
|
93
|
+
name?: string;
|
|
94
|
+
/** `'group'` -> robot groupMessages/send; `'dm'` -> oToMessages/batchSend. */
|
|
95
|
+
conversationType?: 'dm' | 'group';
|
|
96
|
+
}
|
|
97
|
+
/** Result of any proactive / media robot message send. */
|
|
98
|
+
export interface RobotMessageSendResult {
|
|
99
|
+
/** The platform message id when reported. */
|
|
100
|
+
messageId?: string;
|
|
101
|
+
/** Raw platform response for diagnostics. */
|
|
102
|
+
raw?: unknown;
|
|
103
|
+
}
|
|
104
|
+
/** One opaque-platform-handle resolution: locator -> trusted bytes. */
|
|
105
|
+
export interface ResolvedMedia {
|
|
106
|
+
/** Trusted bytes already downloaded by the platform upstream. */
|
|
107
|
+
data: Uint8Array;
|
|
108
|
+
/** MIME type hint, when the platform reports one. */
|
|
109
|
+
mimeType?: string;
|
|
110
|
+
/** Byte size, when known. */
|
|
111
|
+
size?: number;
|
|
112
|
+
}
|
|
113
|
+
/** The thin official DingTalk OpenAPI port. */
|
|
114
|
+
export interface DingTalkOpenApiPort {
|
|
115
|
+
/** Mint (and cache) the application access token. */
|
|
116
|
+
getAccessToken(): Promise<string>;
|
|
117
|
+
/** Send a proactive plain-text message to a conversation. */
|
|
118
|
+
sendProactiveText(input: ProactiveTextInput): Promise<RobotMessageSendResult>;
|
|
119
|
+
/** Upload a media file, returning the DingTalk mediaId. */
|
|
120
|
+
uploadMedia(input: MediaUploadInput): Promise<MediaUploadResult>;
|
|
121
|
+
/** Send an uploaded mediaId as a robot image/file message. */
|
|
122
|
+
sendMedia(input: MediaSendInput): Promise<RobotMessageSendResult>;
|
|
123
|
+
sendInteractiveCard(input: {
|
|
124
|
+
target: ChannelTarget;
|
|
125
|
+
templateId: string;
|
|
126
|
+
text: string;
|
|
127
|
+
actions: import('@krischoichoi/channel-core').OutboundActionRow[];
|
|
128
|
+
textParam: string;
|
|
129
|
+
actionsParam: string;
|
|
130
|
+
}): Promise<{
|
|
131
|
+
messageId?: string;
|
|
132
|
+
outTrackId: string;
|
|
133
|
+
raw?: unknown;
|
|
134
|
+
}>;
|
|
135
|
+
updateInteractiveCard(input: {
|
|
136
|
+
outTrackId: string;
|
|
137
|
+
text: string;
|
|
138
|
+
actions: import('@krischoichoi/channel-core').OutboundActionRow[];
|
|
139
|
+
textParam: string;
|
|
140
|
+
actionsParam: string;
|
|
141
|
+
}): Promise<unknown>;
|
|
142
|
+
/** Create an AI Card with initial content. */
|
|
143
|
+
createCard(target: ChannelTarget, text: string): Promise<{
|
|
144
|
+
cardId: string;
|
|
145
|
+
}>;
|
|
146
|
+
/** Update an AI Card's body text. */
|
|
147
|
+
updateCard(cardId: string, text: string): Promise<unknown>;
|
|
148
|
+
/** Finalize an AI Card. */
|
|
149
|
+
finishCard(cardId: string, text?: string): Promise<unknown>;
|
|
150
|
+
/**
|
|
151
|
+
* Resolve an opaque platform handle (a DingTalk mediaId / downloadCode) into
|
|
152
|
+
* trusted bytes. Official behavior basis: the connector's
|
|
153
|
+
* `downloadMediaByCode` / `getFileDownloadUrl` — POST
|
|
154
|
+
* `/v1.0/robot/messageFiles/download` with `{ downloadCode, robotCode }`
|
|
155
|
+
* returns a `downloadUrl`, which is then fetched as raw bytes. A genuine
|
|
156
|
+
* http(s) `ref` is fetched directly. Throws a typed error when the ref is
|
|
157
|
+
* opaque and no `downloadCode` context is available (fail closed, no
|
|
158
|
+
* invented download protocol).
|
|
159
|
+
*/
|
|
160
|
+
resolveMedia(ref: string, options?: {
|
|
161
|
+
signal?: AbortSignal;
|
|
162
|
+
name?: string;
|
|
163
|
+
/** Per-message download code from the inbound callback (official schema). */
|
|
164
|
+
downloadCode?: string;
|
|
165
|
+
/** Robot code (AppKey); required for the official download API. */
|
|
166
|
+
robotCode?: string;
|
|
167
|
+
}): Promise<ResolvedMedia>;
|
|
168
|
+
/**
|
|
169
|
+
* Resolve an opaque platform handle into a download URL, when the platform
|
|
170
|
+
* can hand one back. Optional refinement of `resolveMedia`.
|
|
171
|
+
*/
|
|
172
|
+
getMediaDownloadUrl?(ref: string, options?: {
|
|
173
|
+
signal?: AbortSignal;
|
|
174
|
+
downloadCode?: string;
|
|
175
|
+
robotCode?: string;
|
|
176
|
+
}): Promise<string | undefined>;
|
|
177
|
+
}
|
|
178
|
+
/** A minimal, injectable subset of the port used by inbound hydration. */
|
|
179
|
+
export interface MediaResolverLike {
|
|
180
|
+
/** Resolve one opaque media handle into trusted bytes. */
|
|
181
|
+
resolveMedia(ref: string, options?: {
|
|
182
|
+
signal?: AbortSignal;
|
|
183
|
+
name?: string;
|
|
184
|
+
/** Per-message download code from the inbound callback (official schema). */
|
|
185
|
+
downloadCode?: string;
|
|
186
|
+
/** Robot code (AppKey); required for the official download API. */
|
|
187
|
+
robotCode?: string;
|
|
188
|
+
}): Promise<ResolvedMedia>;
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=openapi-port.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi-port.d.ts","sourceRoot":"","sources":["../src/openapi-port.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi-port.js","sourceRoot":"","sources":["../src/openapi-port.ts"],"names":[],"mappings":""}
|