@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 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ export interface DingTalkUpstreamManifest {
2
+ reference: string;
3
+ testedVersion: string;
4
+ versionRange: string;
5
+ strategy: 'sdk' | 'source';
6
+ }
7
+ /** Official SDK consumed by the upstream driver, when one is used. */
8
+ export interface DingTalkSdkManifest {
9
+ /** npm package name of the official SDK. */
10
+ package: string;
11
+ /** Version the adapter was verified against. */
12
+ testedVersion: string;
13
+ }
14
+ export interface DingTalkManifest {
15
+ id: 'dingtalk';
16
+ adapterVersion: string;
17
+ upstream: DingTalkUpstreamManifest;
18
+ sdk: DingTalkSdkManifest | undefined;
19
+ status: 'tested';
20
+ }
21
+ /** Current manifest: inbound via the official dingtalk-stream SDK. */
22
+ export declare const manifest: DingTalkManifest;
23
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,KAAK,GAAG,QAAQ,CAAC;CAC5B;AAED,sEAAsE;AACtE,MAAM,WAAW,mBAAmB;IAClC,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,UAAU,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,wBAAwB,CAAC;IACnC,GAAG,EAAE,mBAAmB,GAAG,SAAS,CAAC;IACrC,MAAM,EAAE,QAAQ,CAAC;CAClB;AAED,sEAAsE;AACtE,eAAO,MAAM,QAAQ,EAAE,gBActB,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * DingTalk upstream compatibility manifest (M2 + SDK driver).
3
+ *
4
+ * Records the upstream reference and tested version so `channels doctor` and
5
+ * the upgrade pipeline can govern compatibility without re-verifying by hand.
6
+ *
7
+ * Strategy: 'sdk' — inbound rides the official `dingtalk-stream` SDK
8
+ * (WebSocket stream mode). Outbound (message send / AI Card) is not part of
9
+ * the stream SDK; it uses the message-scoped `sessionWebhook` and DingTalk's
10
+ * official AI Card OpenAPI through the shared HTTP transport.
11
+ *
12
+ * Status 'tested' is justified by the Channel Contract + fixture tests plus
13
+ * the SDK-mode offline tests (fake stream client) passing — fully offline.
14
+ * Live verification against a real DingTalk app (AppKey/AppSecret) is a
15
+ * manual step.
16
+ */
17
+ import pkg from '../package.json' with { type: 'json' };
18
+ /** Current manifest: inbound via the official dingtalk-stream SDK. */
19
+ export const manifest = {
20
+ id: 'dingtalk',
21
+ adapterVersion: pkg.version,
22
+ upstream: {
23
+ reference: 'open-dingtalk/dingtalk-stream-sdk-nodejs (https://github.com/open-dingtalk/dingtalk-stream-sdk-nodejs)',
24
+ testedVersion: '2.1.5',
25
+ versionRange: '2.1.5',
26
+ strategy: 'sdk',
27
+ },
28
+ sdk: {
29
+ package: 'dingtalk-stream',
30
+ testedVersion: '2.1.5',
31
+ },
32
+ status: 'tested',
33
+ };
34
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,GAAG,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAyBxD,sEAAsE;AACtE,MAAM,CAAC,MAAM,QAAQ,GAAqB;IACxC,EAAE,EAAE,UAAU;IACd,cAAc,EAAE,GAAG,CAAC,OAAO;IAC3B,QAAQ,EAAE;QACR,SAAS,EAAE,wGAAwG;QACnH,aAAa,EAAE,OAAO;QACtB,YAAY,EAAE,OAAO;QACrB,QAAQ,EAAE,KAAK;KAChB;IACD,GAAG,EAAE;QACH,OAAO,EAAE,iBAAiB;QAC1B,aAAa,EAAE,OAAO;KACvB;IACD,MAAM,EAAE,QAAQ;CACjB,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Pure payload mapping (no I/O): platform raw payloads → Channel Contract,
3
+ * and outbound Channel messages → dingtalk text payloads.
4
+ *
5
+ * Raw payloads only ever ride along in `event.raw` for debugging — core and
6
+ * the harness bridge never depend on their shape (red line 6).
7
+ *
8
+ * DingTalk-ish raw shapes are protocol-level and deliberately simple, e.g.:
9
+ * ```json
10
+ * { "type": "text", "msgId": "msg_1", "senderId": "user_123",
11
+ * "conversationId": "conv_456", "content": "hello" }
12
+ * ```
13
+ */
14
+ import type { AccountId, ChannelId, MessageReceived, InteractionReceived, OutboundMessage } from '@krischoichoi/channel-core';
15
+ export interface DingTalkInboundMeta {
16
+ channel: ChannelId;
17
+ accountId: AccountId;
18
+ }
19
+ /** Stable hash for ids when the gateway omits a msgId. */
20
+ export declare function simpleHash(input: string): string;
21
+ /** Map one raw dingtalk message into the stable channel event shape. */
22
+ export declare function mapInbound(raw: unknown, meta: DingTalkInboundMeta): MessageReceived;
23
+ export declare function mapInteraction(raw: unknown, meta: DingTalkInboundMeta): InteractionReceived;
24
+ /** Outbound dingtalk payload; buffered strategy → single text message. */
25
+ export interface DingTalkTextPayload {
26
+ to: string;
27
+ type: 'text';
28
+ content: string;
29
+ }
30
+ /** Convert an outbound channel message into a dingtalk text payload. */
31
+ export declare function toTextPayload(target: {
32
+ conversationId: string;
33
+ }, message: OutboundMessage): DingTalkTextPayload;
34
+ /** Dedup identity for raw payloads (webhook retries share one msgId/eventId). */
35
+ export declare function dedupKey(raw: unknown): string;
36
+ //# sourceMappingURL=mapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapper.d.ts","sourceRoot":"","sources":["../src/mapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EACV,SAAS,EACT,SAAS,EAIT,eAAe,EACf,mBAAmB,EACnB,eAAe,EAEhB,MAAM,4BAA4B,CAAC;AAIpC,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,SAAS,CAAC;IACnB,SAAS,EAAE,SAAS,CAAC;CACtB;AAmDD,0DAA0D;AAC1D,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMhD;AAED,wEAAwE;AACxE,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,mBAAmB,GAAG,eAAe,CA4BnF;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,mBAAmB,GAAG,mBAAmB,CAyB3F;AAiDD,0EAA0E;AAC1E,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,MAAM,EAAE;IAAE,cAAc,EAAE,MAAM,CAAA;CAAE,EAAE,OAAO,EAAE,eAAe,GAAG,mBAAmB,CAkC/G;AAED,iFAAiF;AACjF,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAG7C"}
package/lib/mapper.js ADDED
@@ -0,0 +1,175 @@
1
+ import { ChannelError, textParts } from '@krischoichoi/channel-core';
2
+ import { z } from 'zod';
3
+ const dingtalkRawSchema = z.object({
4
+ type: z.string().optional(),
5
+ msgId: z.string().optional(),
6
+ eventId: z.string().optional(),
7
+ senderId: z.string().optional(),
8
+ conversationId: z.string().optional(),
9
+ conversationType: z.string().optional(),
10
+ content: z.string().optional(),
11
+ mentionedBot: z.boolean().optional(),
12
+ }).passthrough();
13
+ function parseDingTalkRaw(raw) {
14
+ const parsed = dingtalkRawSchema.safeParse(raw);
15
+ if (!parsed.success) {
16
+ throw new ChannelError('CHANNEL_ERROR', 'dingtalk inbound payload is invalid');
17
+ }
18
+ return parsed.data;
19
+ }
20
+ /** True only for genuine http(s) locators. */
21
+ function isHttpUrl(locator) {
22
+ return typeof locator === 'string' && /^https?:\/\//i.test(locator);
23
+ }
24
+ /** Stable hash for ids when the gateway omits a msgId. */
25
+ export function simpleHash(input) {
26
+ let hash = 0;
27
+ for (let i = 0; i < input.length; i += 1) {
28
+ hash = (hash * 31 + input.charCodeAt(i)) | 0;
29
+ }
30
+ return Math.abs(hash).toString(36);
31
+ }
32
+ /** Map one raw dingtalk message into the stable channel event shape. */
33
+ export function mapInbound(raw, meta) {
34
+ const value = parseDingTalkRaw(raw);
35
+ const sender = (value.senderId ?? 'unknown');
36
+ // DingTalk payloads carry a conversation id; fall back to the sender when
37
+ // the gateway omits it (direct/one-off payloads).
38
+ const conversationId = (value.conversationId ?? sender);
39
+ const messageId = value.msgId
40
+ ? value.msgId
41
+ : `dt-${simpleHash(`${sender}:${value.content ?? ''}:${value.type ?? 'unknown'}`)}`;
42
+ return {
43
+ type: 'message.received',
44
+ channel: meta.channel,
45
+ accountId: meta.accountId,
46
+ conversation: {
47
+ id: conversationId,
48
+ type: value.conversationType === '2' ? 'group' : 'dm',
49
+ },
50
+ sender: { id: sender },
51
+ message: {
52
+ id: messageId,
53
+ content: partsFor(value),
54
+ createdAt: Date.now(),
55
+ ...(value.mentionedBot !== undefined ? { activation: { mentionedBot: value.mentionedBot } } : {}),
56
+ },
57
+ raw,
58
+ };
59
+ }
60
+ export function mapInteraction(raw, meta) {
61
+ const parsed = z.object({
62
+ type: z.literal('interaction'),
63
+ senderId: z.string().min(1),
64
+ conversationId: z.string().min(1),
65
+ conversationType: z.string().optional(),
66
+ interactionId: z.string().min(1),
67
+ action: z.string().min(1),
68
+ value: z.unknown().optional(),
69
+ }).passthrough().safeParse(raw);
70
+ if (!parsed.success)
71
+ throw new ChannelError('CHANNEL_ERROR', 'dingtalk interaction payload is invalid');
72
+ return {
73
+ type: 'interaction.received',
74
+ channel: meta.channel,
75
+ accountId: meta.accountId,
76
+ conversation: {
77
+ id: parsed.data.conversationId,
78
+ type: parsed.data.conversationType === '2' ? 'group' : 'dm',
79
+ },
80
+ sender: { id: parsed.data.senderId },
81
+ interactionId: parsed.data.interactionId,
82
+ action: parsed.data.action,
83
+ value: parsed.data.value,
84
+ raw,
85
+ };
86
+ }
87
+ function partsFor(raw) {
88
+ switch (raw.type) {
89
+ case 'text':
90
+ return textParts(raw.content ?? '');
91
+ case 'image':
92
+ case 'picture': {
93
+ // Official robot picture messages carry an opaque picMediaId/downloadCode
94
+ // (NOT a URL): resourceRef holds the opaque handle, url only a genuine
95
+ // http(s) URL. Resolving resourceRef is the upstream's job.
96
+ const url = isHttpUrl(raw.picUrl) ? raw.picUrl : undefined;
97
+ const opaque = raw.picMediaId ?? raw.picDownloadCode ?? (raw.picUrl ? raw.picUrl : undefined);
98
+ return [{ type: 'image', ...(url ? { url } : opaque ? { resourceRef: opaque } : {}), alt: raw.title }];
99
+ }
100
+ case 'richText': {
101
+ const parts = textParts(raw.content ?? '');
102
+ for (const image of raw.richTextImages ?? []) {
103
+ const url = isHttpUrl(image.pictureUrl) ? image.pictureUrl : undefined;
104
+ const resourceRef = image.downloadCode ? `downloadCode:${image.downloadCode}` : undefined;
105
+ parts.push({ type: 'image', ...(url ? { url } : resourceRef ? { resourceRef } : {}) });
106
+ }
107
+ return parts.length > 0
108
+ ? parts
109
+ : [{ type: 'unsupported', reason: "empty dingtalk richText message" }];
110
+ }
111
+ case 'audio':
112
+ case 'voice': {
113
+ const url = isHttpUrl(raw.mediaUrl) ? raw.mediaUrl : undefined;
114
+ const opaque = raw.downloadCode ?? (raw.mediaUrl ? raw.mediaUrl : undefined);
115
+ return [{ type: 'audio', ...(url ? { url } : opaque ? { resourceRef: opaque } : {}), durationMs: raw.durationMs }];
116
+ }
117
+ case 'video': {
118
+ const url = isHttpUrl(raw.mediaUrl) ? raw.mediaUrl : undefined;
119
+ const opaque = raw.downloadCode ?? (raw.mediaUrl ? raw.mediaUrl : undefined);
120
+ return [{ type: 'video', ...(url ? { url } : opaque ? { resourceRef: opaque } : {}), durationMs: raw.durationMs }];
121
+ }
122
+ case 'file': {
123
+ const url = isHttpUrl(raw.mediaUrl) ? raw.mediaUrl : undefined;
124
+ const opaque = raw.downloadCode ?? (raw.mediaUrl ? raw.mediaUrl : undefined);
125
+ return [{ type: 'file', ...(url ? { url } : opaque ? { resourceRef: opaque } : {}), name: raw.title }];
126
+ }
127
+ case 'link':
128
+ return textParts(raw.title ?? raw.content ?? '');
129
+ default:
130
+ return [{ type: 'unsupported', reason: `unknown dingtalk type '${raw.type ?? 'undefined'}'` }];
131
+ }
132
+ }
133
+ /** Convert an outbound channel message into a dingtalk text payload. */
134
+ export function toTextPayload(target, message) {
135
+ const segments = [];
136
+ if (message.text)
137
+ segments.push(message.text);
138
+ if (message.parts) {
139
+ for (const part of message.parts) {
140
+ switch (part.type) {
141
+ case 'text':
142
+ segments.push(part.text);
143
+ break;
144
+ case 'image':
145
+ segments.push(part.alt ? `[image: ${part.alt}]` : '[image]');
146
+ break;
147
+ case 'audio':
148
+ segments.push('[audio]');
149
+ break;
150
+ case 'video':
151
+ segments.push('[video]');
152
+ break;
153
+ case 'file':
154
+ segments.push(part.name ? `[file: ${part.name}]` : '[file]');
155
+ break;
156
+ case 'location':
157
+ segments.push(`[location: ${part.latitude},${part.longitude}]`);
158
+ break;
159
+ case 'card':
160
+ segments.push(`[card: ${part.kind}]`);
161
+ break;
162
+ case 'unsupported':
163
+ segments.push('[unsupported content]');
164
+ break;
165
+ }
166
+ }
167
+ }
168
+ return { to: target.conversationId, type: 'text', content: segments.join('') };
169
+ }
170
+ /** Dedup identity for raw payloads (webhook retries share one msgId/eventId). */
171
+ export function dedupKey(raw) {
172
+ const value = parseDingTalkRaw(raw);
173
+ return value.msgId ?? value.eventId ?? `dt-${simpleHash(JSON.stringify(value))}`;
174
+ }
175
+ //# sourceMappingURL=mapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapper.js","sourceRoot":"","sources":["../src/mapper.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Minimal raster-image MIME sniffing for media bytes downloaded from the
3
+ * DingTalk download API.
4
+ *
5
+ * This is NOT a platform protocol: it is a local content-sniffing helper so
6
+ * the Harness `saveImage()` seam receives a valid raster `ImageMediaType`
7
+ * (the message-converter only commits an image when a raster MIME is known).
8
+ * The official connector does the same thing (ext derives from the response
9
+ * content-type); here we sniff magic bytes because the shared transport
10
+ * returns raw bytes without headers.
11
+ */
12
+ /** Raster MIME sniffed from the leading magic bytes, if recognized. */
13
+ export declare function sniffImageMime(data: Uint8Array): 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif' | undefined;
14
+ //# sourceMappingURL=media-mime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-mime.d.ts","sourceRoot":"","sources":["../src/media-mime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,uEAAuE;AACvE,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,WAAW,GAAG,YAAY,GAAG,YAAY,GAAG,WAAW,GAAG,SAAS,CAgBpH"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Minimal raster-image MIME sniffing for media bytes downloaded from the
3
+ * DingTalk download API.
4
+ *
5
+ * This is NOT a platform protocol: it is a local content-sniffing helper so
6
+ * the Harness `saveImage()` seam receives a valid raster `ImageMediaType`
7
+ * (the message-converter only commits an image when a raster MIME is known).
8
+ * The official connector does the same thing (ext derives from the response
9
+ * content-type); here we sniff magic bytes because the shared transport
10
+ * returns raw bytes without headers.
11
+ */
12
+ /** Raster MIME sniffed from the leading magic bytes, if recognized. */
13
+ export function sniffImageMime(data) {
14
+ if (data.byteLength < 8)
15
+ return undefined;
16
+ // PNG: 89 50 4E 47 0D 0A 1A 0A
17
+ if (data[0] === 0x89 && data[1] === 0x50 && data[2] === 0x4e && data[3] === 0x47)
18
+ return 'image/png';
19
+ // JPEG: FF D8 FF
20
+ if (data[0] === 0xff && data[1] === 0xd8 && data[2] === 0xff)
21
+ return 'image/jpeg';
22
+ // GIF: 'GIF8'
23
+ if (data[0] === 0x47 && data[1] === 0x49 && data[2] === 0x46 && data[3] === 0x38)
24
+ return 'image/gif';
25
+ // WebP: 'RIFF' .... 'WEBP'
26
+ if (data[0] === 0x52 && data[1] === 0x49 && data[2] === 0x46 && data[3] === 0x46 &&
27
+ data[8] === 0x57 && data[9] === 0x45 && data[10] === 0x42 && data[11] === 0x50) {
28
+ return 'image/webp';
29
+ }
30
+ return undefined;
31
+ }
32
+ //# sourceMappingURL=media-mime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-mime.js","sourceRoot":"","sources":["../src/media-mime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,uEAAuE;AACvE,MAAM,UAAU,cAAc,CAAC,IAAgB;IAC7C,IAAI,IAAI,CAAC,UAAU,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1C,+BAA+B;IAC/B,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI;QAAE,OAAO,WAAW,CAAC;IACrG,iBAAiB;IACjB,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI;QAAE,OAAO,YAAY,CAAC;IAClF,cAAc;IACd,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI;QAAE,OAAO,WAAW,CAAC;IACrG,2BAA2B;IAC3B,IACE,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI;QAC5E,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC,KAAK,IAAI,EAC9E,CAAC;QACD,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,143 @@
1
+ /***
2
+ * Official DingTalk OpenAPI port implementation.
3
+ *
4
+ * Positioned as `DingTalkOpenApiPortImpl`: it is the thin
5
+ * implementation of `DingTalkOpenApiPort`, and it also implements the
6
+ * `DingTalkUpstream` outbound surface so `DingTalkStreamUpstream` can keep
7
+ * delegating to it unchanged. Stream-mode reply messages carry a short-lived
8
+ * sessionWebhook used ONLY for the current inbound reply; AI Cards
9
+ * and proactive sends use the documented DingTalk OpenAPI with an application
10
+ * access token. Neither path requires the legacy local gateway.
11
+ *
12
+ * Behavior oracle / payload contract:
13
+ * `@dingtalk-real-ai/dingtalk-connector@0.8.24`.
14
+ * Every port method records its official-behavior basis in
15
+ * `DingTalkOpenApiPortImpl.OFFICIAL_BASIS` (and its own docblock). Methods with
16
+ * no official-behavior basis are marked `@upstream-gap` / `@deprecated` with a
17
+ * reason (delete any protocol with no official basis).
18
+ */
19
+ import type { ChannelTarget, OutboundActionRow } from '@krischoichoi/channel-core';
20
+ import type { CardCreateResult, DingTalkUpstream } from './upstream.js';
21
+ import type { HttpTransport } from './transport.js';
22
+ import type { RemoteMediaFetchLike } from './image-hydrator.js';
23
+ import type { DingTalkOpenApiPort, DingTalkOpenApiCredentials, MediaSendInput, MediaUploadInput, MediaUploadResult, ProactiveTextInput, ResolvedMedia, RobotMessageSendResult } from './openapi-port.js';
24
+ export interface DingTalkOfficialUpstreamOptions extends DingTalkOpenApiCredentials {
25
+ transport: HttpTransport;
26
+ /** Shared host safety boundary for short-lived DingTalk download URLs. */
27
+ secureFetch?: RemoteMediaFetchLike;
28
+ }
29
+ /**
30
+ * Official DingTalk OpenAPI port implementation (rename of the former
31
+ * `DingTalkOfficialUpstream`). Implements the small `DingTalkOpenApiPort`
32
+ * plus the `DingTalkUpstream` outbound surface it always had.
33
+ *
34
+ * The legacy name `DingTalkOfficialUpstream` is preserved as an alias below so
35
+ * existing import/call sites and tests keep compiling unchanged.
36
+ */
37
+ export declare class DingTalkOpenApiPortImpl implements DingTalkOpenApiPort, DingTalkUpstream {
38
+ private readonly options;
39
+ private readonly now;
40
+ private cachedToken?;
41
+ private readonly inputingCards;
42
+ private readonly secureFetch;
43
+ constructor(options: DingTalkOfficialUpstreamOptions);
44
+ receive(): Promise<void>;
45
+ /** Reply path: sessionWebhook is ONLY for the current inbound reply. */
46
+ sendText(target: ChannelTarget, text: string): Promise<unknown>;
47
+ /**
48
+ * Get (and cache) the application access token. Official behavior basis:
49
+ * DingTalk OpenAPI `POST /v1.0/oauth2/accessToken` (the official connector's
50
+ * token acquisition, mirrored here).
51
+ */
52
+ getAccessToken(): Promise<string>;
53
+ /**
54
+ * Proactive plain-text robot send: official proactive API,
55
+ * never sessionWebhook. Official behavior basis: DingTalk robot message send
56
+ * (`POST /v1.0/robot/groupMessages/send` for groups;
57
+ * `POST /v1.0/robot/oToMessages/batchSend` for single chat), msgKey `sampleText`,
58
+ * msgParam `{ "content": ... }` — mirrors the official connector's proactive
59
+ * robot message path. Payload contract from the official connector.
60
+ */
61
+ sendProactiveText(input: ProactiveTextInput): Promise<RobotMessageSendResult>;
62
+ /**
63
+ * Upload a media file. Official behavior basis:
64
+ * DingTalk media upload `POST /media/upload?access_token=...&type=image|file`
65
+ * as used by the connector. Standard `FormData` delegates multipart framing
66
+ * to fetch instead of reproducing a platform protocol in this package.
67
+ */
68
+ uploadMedia(input: MediaUploadInput): Promise<MediaUploadResult>;
69
+ /**
70
+ * Send an uploaded mediaId as a robot image/file message.
71
+ * Official behavior basis: DingTalk robot message send with msgKey
72
+ * `sampleImageMsg` with `{ photoURL: mediaId }` for images, and
73
+ * `sampleFile` with `{ mediaId, fileName, fileType }` for files, matching
74
+ * the connector's verified proactive paths.
75
+ */
76
+ sendMedia(input: MediaSendInput): Promise<RobotMessageSendResult>;
77
+ sendInteractiveCard(input: {
78
+ target: ChannelTarget;
79
+ templateId: string;
80
+ text: string;
81
+ actions: OutboundActionRow[];
82
+ textParam: string;
83
+ actionsParam: string;
84
+ }): Promise<{
85
+ messageId?: string;
86
+ outTrackId: string;
87
+ raw?: unknown;
88
+ }>;
89
+ updateInteractiveCard(input: {
90
+ outTrackId: string;
91
+ text: string;
92
+ actions: OutboundActionRow[];
93
+ textParam: string;
94
+ actionsParam: string;
95
+ }): Promise<unknown>;
96
+ createCard(target: ChannelTarget, _text: string): Promise<CardCreateResult>;
97
+ updateCard(cardId: string, text: string): Promise<unknown>;
98
+ finishCard(cardId: string, text?: string): Promise<unknown>;
99
+ failCard(cardId: string, reason?: string): Promise<unknown>;
100
+ /**
101
+ * Resolve an opaque DingTalk media handle (mediaId / downloadCode) into
102
+ * trusted bytes. Official behavior basis: the connector's
103
+ * `downloadMediaByCode` / `getFileDownloadUrl` — POST
104
+ * `/v1.0/robot/messageFiles/download` with `{ downloadCode, robotCode }`
105
+ * and the application access token returns `{ downloadUrl }`; the URL is
106
+ * then fetched as raw bytes (responseType arraybuffer). A genuine http(s)
107
+ * `ref` is fetched directly. Fails closed with a typed error when an opaque
108
+ * ref lacks the per-message `downloadCode` context.
109
+ */
110
+ resolveMedia(ref: string, options?: {
111
+ signal?: AbortSignal;
112
+ name?: string;
113
+ downloadCode?: string;
114
+ robotCode?: string;
115
+ }): Promise<ResolvedMedia>;
116
+ /**
117
+ * Resolve an opaque DingTalk media handle into a download URL. Official
118
+ * behavior basis: the connector's `getFileDownloadUrl` — POST
119
+ * `/v1.0/robot/messageFiles/download` with `{ downloadCode, robotCode }`
120
+ * and `x-acs-dingtalk-access-token`. A genuine http(s) ref is returned
121
+ * as-is. Returns `undefined` (fail closed) when an opaque ref lacks the
122
+ * downloadCode context.
123
+ */
124
+ getMediaDownloadUrl(ref: string, options?: {
125
+ signal?: AbortSignal;
126
+ downloadCode?: string;
127
+ robotCode?: string;
128
+ }): Promise<string | undefined>;
129
+ private ensureCardInputing;
130
+ private targetData;
131
+ private cardDelivery;
132
+ }
133
+ /**
134
+ * Official-behavior basis for every port method: maps a port method
135
+ * name to the corresponding official connector implementation location / behavior
136
+ * oracle, or an explicit `@upstream-gap` / `@deprecated` marker with a reason.
137
+ * The port-inventory test asserts every interface method has a non-empty entry
138
+ * here (shape + marker presence).
139
+ */
140
+ export declare const OFFICIAL_BASIS: Record<string, string>;
141
+ /** Legacy alias (rename): `DingTalkOfficialUpstream` -> `DingTalkOpenApiPortImpl`. */
142
+ export declare const DingTalkOfficialUpstream: typeof DingTalkOpenApiPortImpl;
143
+ //# sourceMappingURL=official-upstream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"official-upstream.d.ts","sourceRoot":"","sources":["../src/official-upstream.ts"],"names":[],"mappings":"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"}