@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.
Files changed (70) hide show
  1. package/README.md +139 -0
  2. package/lib/adapter.d.ts +123 -0
  3. package/lib/adapter.d.ts.map +1 -0
  4. package/lib/adapter.js +355 -0
  5. package/lib/adapter.js.map +1 -0
  6. package/lib/ai-card.d.ts +64 -0
  7. package/lib/ai-card.d.ts.map +1 -0
  8. package/lib/ai-card.js +150 -0
  9. package/lib/ai-card.js.map +1 -0
  10. package/lib/auth/device-registration.d.ts +18 -0
  11. package/lib/auth/device-registration.d.ts.map +1 -0
  12. package/lib/auth/device-registration.js +147 -0
  13. package/lib/auth/device-registration.js.map +1 -0
  14. package/lib/config.d.ts +119 -0
  15. package/lib/config.d.ts.map +1 -0
  16. package/lib/config.js +75 -0
  17. package/lib/config.js.map +1 -0
  18. package/lib/definition.d.ts +53 -0
  19. package/lib/definition.d.ts.map +1 -0
  20. package/lib/definition.js +227 -0
  21. package/lib/definition.js.map +1 -0
  22. package/lib/image-hydrator.d.ts +213 -0
  23. package/lib/image-hydrator.d.ts.map +1 -0
  24. package/lib/image-hydrator.js +244 -0
  25. package/lib/image-hydrator.js.map +1 -0
  26. package/lib/inbound.d.ts +38 -0
  27. package/lib/inbound.d.ts.map +1 -0
  28. package/lib/inbound.js +158 -0
  29. package/lib/inbound.js.map +1 -0
  30. package/lib/index.d.ts +49 -0
  31. package/lib/index.d.ts.map +1 -0
  32. package/lib/index.js +123 -0
  33. package/lib/index.js.map +1 -0
  34. package/lib/manifest.d.ts +23 -0
  35. package/lib/manifest.d.ts.map +1 -0
  36. package/lib/manifest.js +34 -0
  37. package/lib/manifest.js.map +1 -0
  38. package/lib/mapper.d.ts +36 -0
  39. package/lib/mapper.d.ts.map +1 -0
  40. package/lib/mapper.js +175 -0
  41. package/lib/mapper.js.map +1 -0
  42. package/lib/media-mime.d.ts +14 -0
  43. package/lib/media-mime.d.ts.map +1 -0
  44. package/lib/media-mime.js +32 -0
  45. package/lib/media-mime.js.map +1 -0
  46. package/lib/official-upstream.d.ts +143 -0
  47. package/lib/official-upstream.d.ts.map +1 -0
  48. package/lib/official-upstream.js +425 -0
  49. package/lib/official-upstream.js.map +1 -0
  50. package/lib/openapi-port.d.ts +190 -0
  51. package/lib/openapi-port.d.ts.map +1 -0
  52. package/lib/openapi-port.js +2 -0
  53. package/lib/openapi-port.js.map +1 -0
  54. package/lib/outbound.d.ts +69 -0
  55. package/lib/outbound.d.ts.map +1 -0
  56. package/lib/outbound.js +148 -0
  57. package/lib/outbound.js.map +1 -0
  58. package/lib/stream-upstream.d.ts +77 -0
  59. package/lib/stream-upstream.d.ts.map +1 -0
  60. package/lib/stream-upstream.js +303 -0
  61. package/lib/stream-upstream.js.map +1 -0
  62. package/lib/transport.d.ts +37 -0
  63. package/lib/transport.d.ts.map +1 -0
  64. package/lib/transport.js +73 -0
  65. package/lib/transport.js.map +1 -0
  66. package/lib/upstream.d.ts +60 -0
  67. package/lib/upstream.d.ts.map +1 -0
  68. package/lib/upstream.js +61 -0
  69. package/lib/upstream.js.map +1 -0
  70. package/package.json +46 -0
@@ -0,0 +1,69 @@
1
+ /***
2
+ * Outbound sending: channel message -> dingtalk payload -> upstream.
3
+ *
4
+ * Two explicit send paths:
5
+ * - REPLY: the target carries an inbound `sessionWebhook` (or the upstream is
6
+ * the legacy gateway, which has no proactive path). sessionWebhook belongs
7
+ * ONLY to the current inbound reply — never a durable outbox route.
8
+ * - PROACTIVE: a target with no reply context / an arbitrary conversation id
9
+ * is sent through the official proactive OpenAPI port (`sendProactiveText`,
10
+ * and proactive media via `uploadMedia` + `sendMedia`) — never via a stale
11
+ * sessionWebhook.
12
+ *
13
+ * Capability flags (`outboxCapabilities`) fail CLOSED: they only read
14
+ * `true` when the matching official path is actually wired. Streaming replies go
15
+ * through `DingTalkCardReply`; this sender is the buffered fallback path
16
+ * (`adapter.send`) used when no card was created.
17
+ */
18
+ import type { ChannelLogger, ChannelTarget, OutboundMessage, SendResult } from '@krischoichoi/channel-core';
19
+ import type { DingTalkUpstream } from './upstream.js';
20
+ import type { DingTalkOpenApiPort, OutboxCapabilities } from './openapi-port.js';
21
+ export interface OutboundSenderOptions {
22
+ /**
23
+ * Reply-path upstream (sessionWebhook for official mode, legacy /message/send
24
+ * for gateway mode). Used for replies and for the no-proactive fallback.
25
+ */
26
+ reply: DingTalkUpstream;
27
+ logger: ChannelLogger;
28
+ /**
29
+ * Proactive OpenAPI port (official proactive path). Absent in gateway mode ->
30
+ * proactive capabilities are false (fail closed).
31
+ */
32
+ proactive?: DingTalkOpenApiPort;
33
+ /**
34
+ * Resolved proactive capability flags. Provided by the adapter;
35
+ * defaults to all-false (fail closed) when not supplied.
36
+ */
37
+ capabilities?: OutboxCapabilities;
38
+ interactiveTemplateId?: string;
39
+ interactiveTextParam?: string;
40
+ interactiveActionsParam?: string;
41
+ }
42
+ export declare class OutboundSender {
43
+ private readonly reply;
44
+ private readonly logger;
45
+ private readonly proactive?;
46
+ private readonly capabilities;
47
+ private readonly interactiveTemplateId?;
48
+ private readonly interactiveTextParam;
49
+ private readonly interactiveActionsParam;
50
+ private readonly interactiveCards;
51
+ constructor(options: OutboundSenderOptions);
52
+ /** Proactive capability flags the harness outbox reads. */
53
+ get outboxCapabilities(): OutboxCapabilities;
54
+ /**
55
+ * Send one channel message. REPLIES (sessionWebhook present) go through the
56
+ * reply upstream; PROACTIVE targets use the official proactive API; gateway
57
+ * mode (no proactive port) falls back to the reply upstream /message/send.
58
+ * Media-carrying proactive messages go through upload + sendMedia.
59
+ */
60
+ send(target: ChannelTarget, message: OutboundMessage): Promise<SendResult>;
61
+ edit(target: ChannelTarget, messageId: string, message: OutboundMessage): Promise<SendResult>;
62
+ /**
63
+ * Inspect an outbound message for a single sendable binary (file/image/image-like)
64
+ * part already carrying trusted bytes (`localData`). Returns undefined for pure
65
+ * text messages.
66
+ */
67
+ private proactiveMediaPart;
68
+ }
69
+ //# sourceMappingURL=outbound.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbound.d.ts","sourceRoot":"","sources":["../src/outbound.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EACV,aAAa,EACb,aAAa,EAEb,eAAe,EACf,UAAU,EACX,MAAM,4BAA4B,CAAC;AAGpC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EACV,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;AAQ3B,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,KAAK,EAAE,gBAAgB,CAAC;IACxB,MAAM,EAAE,aAAa,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAChC;;;OAGG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAsB;IACjD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAClD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAS;IAChD,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAS;IAC9C,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAS;IACjD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqE;gBAE1F,OAAO,EAAE,qBAAqB;IAU1C,2DAA2D;IAC3D,IAAI,kBAAkB,IAAI,kBAAkB,CAE3C;IAED;;;;;OAKG;IACG,IAAI,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC;IAuF1E,IAAI,CAAC,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC;IAiBnG;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;CAiB3B"}
@@ -0,0 +1,148 @@
1
+ import { ChannelSendError } from '@krischoichoi/channel-core';
2
+ import { toTextPayload } from './mapper.js';
3
+ export class OutboundSender {
4
+ reply;
5
+ logger;
6
+ proactive;
7
+ capabilities;
8
+ interactiveTemplateId;
9
+ interactiveTextParam;
10
+ interactiveActionsParam;
11
+ interactiveCards = new Map();
12
+ constructor(options) {
13
+ this.reply = options.reply;
14
+ this.logger = options.logger;
15
+ this.proactive = options.proactive;
16
+ this.capabilities = options.capabilities ?? { proactiveText: false, proactiveMedia: false };
17
+ this.interactiveTemplateId = options.interactiveTemplateId?.trim() || undefined;
18
+ this.interactiveTextParam = options.interactiveTextParam ?? 'text';
19
+ this.interactiveActionsParam = options.interactiveActionsParam ?? 'actions';
20
+ }
21
+ /** Proactive capability flags the harness outbox reads. */
22
+ get outboxCapabilities() {
23
+ return { ...this.capabilities };
24
+ }
25
+ /**
26
+ * Send one channel message. REPLIES (sessionWebhook present) go through the
27
+ * reply upstream; PROACTIVE targets use the official proactive API; gateway
28
+ * mode (no proactive port) falls back to the reply upstream /message/send.
29
+ * Media-carrying proactive messages go through upload + sendMedia.
30
+ */
31
+ async send(target, message) {
32
+ const probe = (target.raw ?? {});
33
+ const isReply = typeof probe.sessionWebhook === 'string' && probe.sessionWebhook !== '';
34
+ try {
35
+ if (message.actions?.length) {
36
+ if (!this.proactive || !this.interactiveTemplateId || !this.capabilities.proactiveText) {
37
+ throw new ChannelSendError('dingtalk interactive card template is not configured');
38
+ }
39
+ const text = toTextPayload(target, message).content;
40
+ const result = await this.proactive.sendInteractiveCard({
41
+ target,
42
+ templateId: this.interactiveTemplateId,
43
+ text,
44
+ actions: message.actions,
45
+ textParam: this.interactiveTextParam,
46
+ actionsParam: this.interactiveActionsParam,
47
+ });
48
+ this.interactiveCards.set(result.outTrackId, { text, actions: message.actions });
49
+ // `outTrackId` is the stable identifier accepted by the official PUT
50
+ // update API; keep it as the contract messageId for later edits.
51
+ return { delivered: true, messageId: result.outTrackId, raw: result.raw };
52
+ }
53
+ if (isReply || !this.proactive) {
54
+ // REPLY path (sessionWebhook) — or gateway fallback (no proactive port).
55
+ const payload = toTextPayload(target, message);
56
+ const response = await this.reply.sendText(target, payload.content);
57
+ return { delivered: true, raw: response };
58
+ }
59
+ // PROACTIVE path: official proactive API.
60
+ const robotCode = (probe.robotCode ?? '').trim() || undefined;
61
+ const conversationType = target.conversationType;
62
+ const media = this.proactiveMediaPart(message);
63
+ if (media) {
64
+ if (!this.capabilities.proactiveMedia) {
65
+ throw new ChannelSendError('dingtalk proactive media is not enabled; message carries binary content with no reply context');
66
+ }
67
+ const agentId = robotCode;
68
+ if (!agentId) {
69
+ throw new ChannelSendError('dingtalk proactive send requires a robotCode in target.raw');
70
+ }
71
+ const uploaded = await this.proactive.uploadMedia({
72
+ robotCode: agentId,
73
+ fileName: media.fileName,
74
+ mimeType: media.mimeType,
75
+ data: media.localData,
76
+ mediaType: media.msgtype,
77
+ target,
78
+ });
79
+ const result = await this.proactive.sendMedia({
80
+ conversationId: String(target.conversationId),
81
+ robotCode: agentId,
82
+ mediaId: uploaded.mediaId,
83
+ msgtype: media.msgtype,
84
+ name: media.fileName,
85
+ conversationType,
86
+ });
87
+ return { delivered: true, raw: result.raw };
88
+ }
89
+ if (!this.capabilities.proactiveText) {
90
+ throw new ChannelSendError('dingtalk proactive text is not enabled');
91
+ }
92
+ if (!robotCode) {
93
+ throw new ChannelSendError('dingtalk proactive send requires a robotCode in target.raw');
94
+ }
95
+ const text = toTextPayload(target, message).content;
96
+ const result = await this.proactive.sendProactiveText({
97
+ conversationId: String(target.conversationId),
98
+ robotCode,
99
+ text,
100
+ conversationType,
101
+ });
102
+ return { delivered: true, raw: result.raw };
103
+ }
104
+ catch (error) {
105
+ this.logger.error(`[channel-dingtalk] send failed to '${target.conversationId}'`, error instanceof Error ? error.message : error);
106
+ throw new ChannelSendError(`dingtalk send failed: ${error instanceof Error ? error.message : String(error)}`);
107
+ }
108
+ }
109
+ async edit(target, messageId, message) {
110
+ if (!this.proactive)
111
+ throw new ChannelSendError('dingtalk interactive card update is unavailable');
112
+ const known = this.interactiveCards.get(messageId);
113
+ if (!known)
114
+ throw new ChannelSendError('dingtalk cannot edit an unknown interactive card');
115
+ const text = message.text ?? known.text;
116
+ const actions = message.actions ?? [];
117
+ const raw = await this.proactive.updateInteractiveCard({
118
+ outTrackId: messageId,
119
+ text,
120
+ actions,
121
+ textParam: this.interactiveTextParam,
122
+ actionsParam: this.interactiveActionsParam,
123
+ });
124
+ this.interactiveCards.set(messageId, { text, actions });
125
+ return { delivered: true, messageId, raw };
126
+ }
127
+ /**
128
+ * Inspect an outbound message for a single sendable binary (file/image/image-like)
129
+ * part already carrying trusted bytes (`localData`). Returns undefined for pure
130
+ * text messages.
131
+ */
132
+ proactiveMediaPart(message) {
133
+ if (!message.parts || message.parts.length !== 1)
134
+ return undefined;
135
+ const part = message.parts[0];
136
+ if (!part || (part.type !== 'file' && part.type !== 'image'))
137
+ return undefined;
138
+ if (!part.localData)
139
+ return undefined;
140
+ return {
141
+ msgtype: part.type === 'image' ? 'image' : 'file',
142
+ localData: part.localData,
143
+ mimeType: part.mimeType,
144
+ fileName: part.name ?? (part.type === 'file' ? 'file' : 'image'),
145
+ };
146
+ }
147
+ }
148
+ //# sourceMappingURL=outbound.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbound.js","sourceRoot":"","sources":["../src/outbound.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ import type { ChannelTarget } from '@krischoichoi/channel-core';
2
+ import type { CardCreateResult, DingTalkUpstream } from './upstream.js';
3
+ /** Downstream headers of a stream message (subset of the SDK shape). */
4
+ export interface DingTalkStreamHeaders {
5
+ /** Subscription topic (e.g. TOPIC_ROBOT for robot messages). */
6
+ topic?: string;
7
+ /** Event id; dedup fallback when the payload omits a msgId. */
8
+ eventId?: string;
9
+ /** Server-side message id of the downstream frame. */
10
+ messageId?: string;
11
+ }
12
+ /** The downstream message shape the stream client delivers to listeners. */
13
+ export interface DingTalkStreamMessage {
14
+ headers?: DingTalkStreamHeaders;
15
+ /** JSON-encoded payload (the SDK delivers `data` as a string). */
16
+ data?: string;
17
+ }
18
+ /**
19
+ * Minimal structural client surface consumed by the driver. The real SDK
20
+ * `DWClient` satisfies it (connect / disconnect / registerCallbackListener);
21
+ * tests inject a fake without a WebSocket.
22
+ */
23
+ export interface DingTalkStreamClient {
24
+ /** Open the stream WebSocket and register subscriptions with the server. */
25
+ connect(): Promise<void>;
26
+ /** Close the stream WebSocket (sync in the real SDK). */
27
+ disconnect(): void;
28
+ /** Subscribe to one downstream topic (robot messages by default). */
29
+ registerCallbackListener(topic: string, callback: (message: DingTalkStreamMessage) => void | Promise<void>): unknown;
30
+ /**
31
+ * Acknowledge one downstream frame so the stream server does not retry it
32
+ * (~60s retry window). The real SDK's `DWClient` implements this as
33
+ * `socketCallBackResponse(messageId, result)`.
34
+ */
35
+ socketCallBackResponse(messageId: string, response: unknown): void;
36
+ }
37
+ export interface DingTalkStreamUpstreamOptions {
38
+ /** The stream-mode client (real DWClient or injected fake). */
39
+ client: DingTalkStreamClient;
40
+ /** Outbound delegate selected by the adapter (official API or legacy gateway). */
41
+ outbound: DingTalkUpstream;
42
+ /** Invoked after the stream connection is established (connection state). */
43
+ onConnected?: () => void;
44
+ }
45
+ /**
46
+ * Map one SDK downstream message into the gateway raw shape consumed by the
47
+ * inbound mapper (`{ type, msgId, eventId, senderId, conversationId, content,
48
+ * ... }`). Returns `undefined` when the payload is absent or not JSON.
49
+ */
50
+ export declare function toGatewayRaw(message: DingTalkStreamMessage): Record<string, unknown> | undefined;
51
+ /**
52
+ * Acknowledge one robot callback frame. ACK means "the message was reliably
53
+ * received and submitted to the inbound pipeline" — not "the LLM finished
54
+ * answering". A frame without a server `messageId` cannot be acked.
55
+ */
56
+ export declare function ackRobotMessage(client: DingTalkStreamClient, message: DingTalkStreamMessage): void;
57
+ export declare function toCardInteractionRaw(message: DingTalkStreamMessage): Record<string, unknown> | undefined;
58
+ /** Stream-mode implementation of `DingTalkUpstream` (inbound via SDK). */
59
+ export declare class DingTalkStreamUpstream implements DingTalkUpstream {
60
+ private readonly options;
61
+ /** The listener is registered once per client; reconnect reuses it. */
62
+ private listenerRegistered;
63
+ private onMessage?;
64
+ constructor(options: DingTalkStreamUpstreamOptions);
65
+ /**
66
+ * Connect the stream client, route inbound robot messages into the gateway
67
+ * raw shape, and keep the stream open until `signal` aborts.
68
+ */
69
+ receive(signal: AbortSignal, onMessage: (raw: unknown) => void): Promise<void>;
70
+ private registerListenerOnce;
71
+ sendText(target: ChannelTarget, text: string): Promise<unknown>;
72
+ createCard(target: ChannelTarget, text: string): Promise<CardCreateResult>;
73
+ updateCard(cardId: string, text: string): Promise<unknown>;
74
+ finishCard(cardId: string, text?: string): Promise<unknown>;
75
+ failCard(cardId: string, reason?: string): Promise<unknown>;
76
+ }
77
+ //# sourceMappingURL=stream-upstream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-upstream.d.ts","sourceRoot":"","sources":["../src/stream-upstream.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGxE,wEAAwE;AACxE,MAAM,WAAW,qBAAqB;IACpC,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,4EAA4E;AAC5E,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,qBAAqB,CAAC;IAChC,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,4EAA4E;IAC5E,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,yDAAyD;IACzD,UAAU,IAAI,IAAI,CAAC;IACnB,qEAAqE;IACrE,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,qBAAqB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;IACrH;;;;OAIG;IACH,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;CACpE;AAED,MAAM,WAAW,6BAA6B;IAC5C,+DAA+D;IAC/D,MAAM,EAAE,oBAAoB,CAAC;IAC7B,kFAAkF;IAClF,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAqFD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAgFhG;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,oBAAoB,EAC5B,OAAO,EAAE,qBAAqB,GAC7B,IAAI,CAIN;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CA4BxG;AAED,0EAA0E;AAC1E,qBAAa,sBAAuB,YAAW,gBAAgB;IAKjD,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJpC,uEAAuE;IACvE,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,SAAS,CAAC,CAAyB;gBAEd,OAAO,EAAE,6BAA6B;IAEnE;;;OAGG;IACG,OAAO,CACX,MAAM,EAAE,WAAW,EACnB,SAAS,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,GAChC,OAAO,CAAC,IAAI,CAAC;IA0BhB,OAAO,CAAC,oBAAoB;IAsB5B,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI/D,UAAU,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAI1E,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI1D,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI3D,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAG5D"}
@@ -0,0 +1,303 @@
1
+ /**
2
+ * DingTalk stream-mode upstream driver (official `dingtalk-stream` SDK).
3
+ *
4
+ * This driver replaces only the INBOUND leg of the legacy self-hosted gateway
5
+ * integration: robot messages arrive over the DingTalk Stream Mode WebSocket
6
+ * (CALLBACK downstream messages on `TOPIC_ROBOT`, payload JSON-encoded in
7
+ * `message.data`) and are mapped into the SAME raw shape the gateway
8
+ * long-poll driver produces (`{ type, msgId, senderId, conversationId,
9
+ * content, ... }`), so the existing mapper + dedup pipeline is untouched.
10
+ *
11
+ * OUTBOUND is deliberately delegated: message send / AI Card create/update are
12
+ * HTTP calls, not part of the stream SDK. `DingTalkStreamUpstream` forwards
13
+ * every outbound method to an injected `DingTalkUpstream`; SDK mode injects
14
+ * the official `sessionWebhook` / OpenAPI driver, while gateway mode uses its
15
+ * legacy HTTP driver.
16
+ *
17
+ * Credentials never appear in this module and are never logged. Live
18
+ * verification against a real DingTalk app (AppKey/AppSecret) is a manual
19
+ * step — the offline tests inject a fake stream client.
20
+ *
21
+ * Ack note: the stream server may retry a callback after ~60s without a
22
+ * response. The SDK's `DWClient` exposes `socketCallBackResponse(messageId,
23
+ * result)` for exactly this purpose; this driver ACKs each successfully
24
+ * parsed + submitted robot message (message "reliably received", NOT "LLM
25
+ * turn finished") so the platform does not redeliver it. Malformed payloads
26
+ * are deliberately NOT acked, so the platform can retry / surface the error.
27
+ */
28
+ import { TOPIC_CARD, TOPIC_ROBOT } from 'dingtalk-stream';
29
+ import { z } from 'zod';
30
+ // Validate the untrusted JSON frame before any field access. The schema only
31
+ // covers fields consumed by this adapter; `.passthrough()` preserves the
32
+ // platform's additional media fields for the existing mapper logic.
33
+ const dingtalkStreamRobotMessageSchema = z.object({
34
+ msgId: z.string().optional(),
35
+ senderStaffId: z.string().optional(),
36
+ senderId: z.string().optional(),
37
+ conversationId: z.string().optional(),
38
+ conversationType: z.string().optional(),
39
+ sessionWebhook: z.string().optional(),
40
+ robotCode: z.string().optional(),
41
+ isInAtList: z.boolean().optional(),
42
+ msgtype: z.string().optional(),
43
+ text: z.object({ content: z.string().optional() }).optional(),
44
+ content: z.unknown().optional(),
45
+ richText: z.object({ richTextList: z.array(z.unknown()).optional() }).optional(),
46
+ picture: z.object({ url: z.string().optional(), picMediaId: z.string().optional(), downloadCode: z.string().optional() }).optional(),
47
+ audio: z.object({ duration: z.number().optional(), url: z.string().optional(), downloadCode: z.string().optional() }).optional(),
48
+ video: z.object({ duration: z.number().optional(), url: z.string().optional(), downloadCode: z.string().optional() }).optional(),
49
+ file: z.object({ fileName: z.string().optional(), url: z.string().optional(), downloadCode: z.string().optional() }).optional(),
50
+ link: z.object({ title: z.string().optional(), text: z.string().optional(), picUrl: z.string().optional() }).optional(),
51
+ }).passthrough();
52
+ /** Resolve the media content container (mirrors the official connector's
53
+ * `resolveContent`): `data.content` as an object, or a parsed JSON string. */
54
+ function resolveContent(data) {
55
+ const raw = data.content;
56
+ if (raw == null)
57
+ return undefined;
58
+ if (typeof raw === 'object')
59
+ return raw;
60
+ if (typeof raw === 'string') {
61
+ try {
62
+ const parsed = JSON.parse(raw);
63
+ if (parsed && typeof parsed === 'object')
64
+ return parsed;
65
+ }
66
+ catch {
67
+ // fall through
68
+ }
69
+ }
70
+ return undefined;
71
+ }
72
+ function richTextList(data, content) {
73
+ const current = content?.richText;
74
+ const legacy = data.richText?.richTextList;
75
+ const list = Array.isArray(current) ? current : Array.isArray(legacy) ? legacy : [];
76
+ return list.filter((item) => !!item && typeof item === 'object');
77
+ }
78
+ /**
79
+ * Map one SDK downstream message into the gateway raw shape consumed by the
80
+ * inbound mapper (`{ type, msgId, eventId, senderId, conversationId, content,
81
+ * ... }`). Returns `undefined` when the payload is absent or not JSON.
82
+ */
83
+ export function toGatewayRaw(message) {
84
+ if (typeof message.data !== 'string')
85
+ return undefined;
86
+ let parsed;
87
+ try {
88
+ parsed = JSON.parse(message.data);
89
+ }
90
+ catch {
91
+ return undefined;
92
+ }
93
+ const result = dingtalkStreamRobotMessageSchema.safeParse(parsed);
94
+ if (!result.success)
95
+ return undefined;
96
+ const data = result.data;
97
+ const raw = {
98
+ type: data.msgtype,
99
+ msgId: data.msgId,
100
+ eventId: message.headers?.eventId,
101
+ senderId: data.senderStaffId ?? data.senderId,
102
+ conversationId: data.conversationId,
103
+ conversationType: data.conversationType,
104
+ sessionWebhook: data.sessionWebhook,
105
+ robotCode: data.robotCode,
106
+ // Preserve the official activation fact under the channel-neutral name
107
+ // consumed by the mapper. Do not infer it from message text.
108
+ ...(typeof data.isInAtList === 'boolean' ? { mentionedBot: data.isInAtList } : {}),
109
+ };
110
+ // Media fields follow the documented robot-message schema (oracle:
111
+ // @dingtalk-real-ai/dingtalk-connector@0.8.24). Media messages carry their
112
+ // content in `data.content` (object or JSON string) whose actionable field
113
+ // is `downloadCode`; picture may also carry `pictureUrl` / `picMediaId`.
114
+ // The `data.<type>?.url` shapes are kept for gateway-mode compatibility.
115
+ // The mapper turns these into image/audio/video/file parts.
116
+ const content = resolveContent(data);
117
+ switch (data.msgtype) {
118
+ case 'text':
119
+ raw.content = data.text?.content;
120
+ break;
121
+ case 'picture': {
122
+ raw.picUrl = content?.pictureUrl ?? data.picture?.url;
123
+ raw.picMediaId = content?.picMediaId ?? data.picture?.picMediaId;
124
+ raw.picDownloadCode = content?.downloadCode ?? data.picture?.downloadCode;
125
+ break;
126
+ }
127
+ case 'richText': {
128
+ const items = richTextList(data, content);
129
+ raw.content = items
130
+ .filter((item) => item.type !== 'skill' && !item.skillData)
131
+ .map((item) => typeof item.text === 'string' ? item.text : '')
132
+ .join('');
133
+ raw.richTextImages = items.flatMap((item) => {
134
+ const pictureUrl = typeof item.pictureUrl === 'string' ? item.pictureUrl : undefined;
135
+ const downloadCode = typeof item.downloadCode === 'string' && (item.type === 'picture' || !item.type)
136
+ ? item.downloadCode
137
+ : undefined;
138
+ return pictureUrl || downloadCode ? [{ pictureUrl, downloadCode }] : [];
139
+ });
140
+ break;
141
+ }
142
+ case 'audio':
143
+ raw.mediaUrl = content?.url ?? data.audio?.url;
144
+ raw.downloadCode = content?.downloadCode ?? data.audio?.downloadCode;
145
+ raw.durationMs = content?.duration ?? data.audio?.duration;
146
+ break;
147
+ case 'video':
148
+ raw.mediaUrl = content?.url ?? data.video?.url;
149
+ raw.downloadCode = content?.downloadCode ?? data.video?.downloadCode;
150
+ raw.durationMs = content?.duration ?? data.video?.duration;
151
+ break;
152
+ case 'file':
153
+ raw.mediaUrl = content?.url ?? data.file?.url;
154
+ raw.downloadCode = content?.downloadCode ?? data.file?.downloadCode;
155
+ raw.title = content?.fileName ?? data.file?.fileName;
156
+ break;
157
+ case 'link':
158
+ raw.title = data.link?.title;
159
+ raw.content = data.link?.text;
160
+ break;
161
+ default:
162
+ // Keep the SDK msgtype; the mapper reports unknown types as unsupported.
163
+ break;
164
+ }
165
+ return raw;
166
+ }
167
+ /**
168
+ * Acknowledge one robot callback frame. ACK means "the message was reliably
169
+ * received and submitted to the inbound pipeline" — not "the LLM finished
170
+ * answering". A frame without a server `messageId` cannot be acked.
171
+ */
172
+ export function ackRobotMessage(client, message) {
173
+ const messageId = message.headers?.messageId;
174
+ if (!messageId)
175
+ return;
176
+ client.socketCallBackResponse(messageId, { success: true });
177
+ }
178
+ export function toCardInteractionRaw(message) {
179
+ if (typeof message.data !== 'string')
180
+ return undefined;
181
+ let parsed;
182
+ try {
183
+ parsed = JSON.parse(message.data);
184
+ }
185
+ catch {
186
+ return undefined;
187
+ }
188
+ const schema = z.object({
189
+ outTrackId: z.string().min(1),
190
+ userId: z.string().min(1),
191
+ openConversationId: z.string().min(1).optional(),
192
+ cardActionData: z.object({
193
+ cardPrivateData: z.object({ params: z.record(z.string(), z.unknown()).optional() }).optional(),
194
+ }).default({}),
195
+ }).passthrough();
196
+ const result = schema.safeParse(parsed);
197
+ if (!result.success)
198
+ return undefined;
199
+ const params = result.data.cardActionData.cardPrivateData?.params ?? {};
200
+ const action = typeof params.action === 'string' ? params.action : typeof params.actionId === 'string' ? params.actionId : undefined;
201
+ if (!action)
202
+ return undefined;
203
+ return {
204
+ type: 'interaction',
205
+ msgId: message.headers?.messageId ?? result.data.outTrackId,
206
+ eventId: message.headers?.eventId,
207
+ senderId: result.data.userId,
208
+ conversationId: result.data.openConversationId ?? result.data.userId,
209
+ conversationType: result.data.openConversationId ? '2' : '1',
210
+ interactionId: result.data.outTrackId,
211
+ action,
212
+ value: params,
213
+ };
214
+ }
215
+ /** Stream-mode implementation of `DingTalkUpstream` (inbound via SDK). */
216
+ export class DingTalkStreamUpstream {
217
+ options;
218
+ /** The listener is registered once per client; reconnect reuses it. */
219
+ listenerRegistered = false;
220
+ onMessage;
221
+ constructor(options) {
222
+ this.options = options;
223
+ }
224
+ /**
225
+ * Connect the stream client, route inbound robot messages into the gateway
226
+ * raw shape, and keep the stream open until `signal` aborts.
227
+ */
228
+ async receive(signal, onMessage) {
229
+ this.onMessage = onMessage;
230
+ this.registerListenerOnce();
231
+ try {
232
+ await this.options.client.connect();
233
+ }
234
+ catch (error) {
235
+ // Abort-driven teardown exits gracefully; other failures propagate to
236
+ // the adapter, which owns reconnect/backoff.
237
+ if (signal.aborted)
238
+ return;
239
+ throw error;
240
+ }
241
+ if (signal.aborted) {
242
+ this.options.client.disconnect();
243
+ return;
244
+ }
245
+ // dingtalk-stream v2 resolves connect() after a failed connection attempt
246
+ // and schedules its own retry. Do not report a healthy channel until its
247
+ // actual socket is open.
248
+ if (this.options.client.connected === false) {
249
+ throw new Error('dingtalk stream connection was not established');
250
+ }
251
+ this.options.onConnected?.();
252
+ await waitForAbort(signal);
253
+ this.options.client.disconnect();
254
+ }
255
+ registerListenerOnce() {
256
+ if (this.listenerRegistered)
257
+ return;
258
+ this.options.client.registerCallbackListener(TOPIC_ROBOT, (message) => {
259
+ if (!this.onMessage)
260
+ return;
261
+ const raw = toGatewayRaw(message);
262
+ if (raw === undefined)
263
+ return; // malformed payload: do not ack (platform retries / error observation)
264
+ this.onMessage(raw);
265
+ // ACK after submitting to the inbound pipeline ("reliably received"),
266
+ // never after the LLM turn completes.
267
+ ackRobotMessage(this.options.client, message);
268
+ });
269
+ this.options.client.registerCallbackListener(TOPIC_CARD, (message) => {
270
+ const raw = toCardInteractionRaw(message);
271
+ if (raw === undefined)
272
+ return;
273
+ this.onMessage?.(raw);
274
+ if (message.headers?.messageId) {
275
+ this.options.client.socketCallBackResponse(message.headers.messageId, { success: true });
276
+ }
277
+ });
278
+ this.listenerRegistered = true;
279
+ }
280
+ sendText(target, text) {
281
+ return this.options.outbound.sendText(target, text);
282
+ }
283
+ createCard(target, text) {
284
+ return this.options.outbound.createCard(target, text);
285
+ }
286
+ updateCard(cardId, text) {
287
+ return this.options.outbound.updateCard(cardId, text);
288
+ }
289
+ finishCard(cardId, text) {
290
+ return this.options.outbound.finishCard(cardId, text);
291
+ }
292
+ failCard(cardId, reason) {
293
+ return this.options.outbound.failCard(cardId, reason);
294
+ }
295
+ }
296
+ function waitForAbort(signal) {
297
+ if (signal.aborted)
298
+ return Promise.resolve();
299
+ return new Promise((resolve) => {
300
+ signal.addEventListener('abort', () => resolve(), { once: true });
301
+ });
302
+ }
303
+ //# sourceMappingURL=stream-upstream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-upstream.js","sourceRoot":"","sources":["../src/stream-upstream.ts"],"names":[],"mappings":"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"}