dsh-connect 0.7.2 → 0.8.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 (114) hide show
  1. package/README.md +68 -32
  2. package/README.zh.md +67 -31
  3. package/client/client.js +387 -0
  4. package/client/client.js.map +7 -0
  5. package/client/settings-client.mjs +177 -0
  6. package/examples/minimal.config.json +16 -0
  7. package/lib/channels/dingtalk/adapter.d.ts +59 -0
  8. package/lib/channels/dingtalk/adapter.d.ts.map +1 -0
  9. package/lib/channels/dingtalk/adapter.js +123 -0
  10. package/lib/channels/dingtalk/adapter.js.map +1 -0
  11. package/lib/channels/dingtalk/i18n.d.ts +14 -0
  12. package/lib/channels/dingtalk/i18n.d.ts.map +1 -0
  13. package/lib/channels/dingtalk/i18n.js +16 -0
  14. package/lib/channels/dingtalk/i18n.js.map +1 -0
  15. package/lib/channels/dingtalk/index.d.ts +127 -0
  16. package/lib/channels/dingtalk/index.d.ts.map +1 -0
  17. package/lib/channels/dingtalk/index.js +144 -0
  18. package/lib/channels/dingtalk/index.js.map +1 -0
  19. package/lib/channels/dingtalk/message.d.ts +49 -0
  20. package/lib/channels/dingtalk/message.d.ts.map +1 -0
  21. package/lib/channels/dingtalk/message.js +43 -0
  22. package/lib/channels/dingtalk/message.js.map +1 -0
  23. package/lib/channels/dingtalk/stomp.d.ts +36 -0
  24. package/lib/channels/dingtalk/stomp.d.ts.map +1 -0
  25. package/lib/channels/dingtalk/stomp.js +107 -0
  26. package/lib/channels/dingtalk/stomp.js.map +1 -0
  27. package/lib/channels/dingtalk/stream.d.ts +53 -0
  28. package/lib/channels/dingtalk/stream.d.ts.map +1 -0
  29. package/lib/channels/dingtalk/stream.js +199 -0
  30. package/lib/channels/dingtalk/stream.js.map +1 -0
  31. package/lib/channels/dingtalk/webhook.d.ts +84 -0
  32. package/lib/channels/dingtalk/webhook.d.ts.map +1 -0
  33. package/lib/channels/dingtalk/webhook.js +143 -0
  34. package/lib/channels/dingtalk/webhook.js.map +1 -0
  35. package/lib/channels/feishu/adapter.d.ts +139 -0
  36. package/lib/channels/feishu/adapter.d.ts.map +1 -0
  37. package/lib/channels/feishu/adapter.js +677 -0
  38. package/lib/channels/feishu/adapter.js.map +1 -0
  39. package/lib/channels/feishu/i18n.d.ts +28 -0
  40. package/lib/channels/feishu/i18n.d.ts.map +1 -0
  41. package/lib/channels/feishu/i18n.js +40 -0
  42. package/lib/channels/feishu/i18n.js.map +1 -0
  43. package/lib/channels/feishu/index.d.ts +61 -0
  44. package/lib/channels/feishu/index.d.ts.map +1 -0
  45. package/lib/channels/feishu/index.js +77 -0
  46. package/lib/channels/feishu/index.js.map +1 -0
  47. package/lib/channels/feishu/onboard.d.ts +16 -0
  48. package/lib/channels/feishu/onboard.d.ts.map +1 -0
  49. package/lib/channels/feishu/onboard.js +86 -0
  50. package/lib/channels/feishu/onboard.js.map +1 -0
  51. package/lib/channels/telegram/adapter.d.ts +70 -0
  52. package/lib/channels/telegram/adapter.d.ts.map +1 -0
  53. package/lib/channels/telegram/adapter.js +454 -0
  54. package/lib/channels/telegram/adapter.js.map +1 -0
  55. package/lib/channels/telegram/client.d.ts +115 -0
  56. package/lib/channels/telegram/client.d.ts.map +1 -0
  57. package/lib/channels/telegram/client.js +198 -0
  58. package/lib/channels/telegram/client.js.map +1 -0
  59. package/lib/channels/telegram/i18n.d.ts +14 -0
  60. package/lib/channels/telegram/i18n.d.ts.map +1 -0
  61. package/lib/channels/telegram/i18n.js +18 -0
  62. package/lib/channels/telegram/i18n.js.map +1 -0
  63. package/lib/channels/telegram/index.d.ts +46 -0
  64. package/lib/channels/telegram/index.d.ts.map +1 -0
  65. package/lib/channels/telegram/index.js +54 -0
  66. package/lib/channels/telegram/index.js.map +1 -0
  67. package/lib/channels/web/adapter.d.ts +103 -0
  68. package/lib/channels/web/adapter.d.ts.map +1 -0
  69. package/lib/channels/web/adapter.js +161 -0
  70. package/lib/channels/web/adapter.js.map +1 -0
  71. package/lib/channels/web/index.d.ts +47 -0
  72. package/lib/channels/web/index.d.ts.map +1 -0
  73. package/lib/channels/web/index.js +59 -0
  74. package/lib/channels/web/index.js.map +1 -0
  75. package/lib/index.d.ts +68 -11
  76. package/lib/index.d.ts.map +1 -1
  77. package/lib/index.js +141 -8
  78. package/lib/index.js.map +1 -1
  79. package/lib/runner.d.ts +1 -2
  80. package/lib/runner.d.ts.map +1 -1
  81. package/lib/runner.js.map +1 -1
  82. package/lib/service.d.ts +1 -1
  83. package/lib/service.d.ts.map +1 -1
  84. package/lib/service.js +1 -1
  85. package/lib/service.js.map +1 -1
  86. package/lib/settings/channels.d.ts +51 -0
  87. package/lib/settings/channels.d.ts.map +1 -0
  88. package/lib/settings/channels.js +101 -0
  89. package/lib/settings/channels.js.map +1 -0
  90. package/lib/settings/credential-store.d.ts +39 -0
  91. package/lib/settings/credential-store.d.ts.map +1 -0
  92. package/lib/settings/credential-store.js +68 -0
  93. package/lib/settings/credential-store.js.map +1 -0
  94. package/lib/settings/index.d.ts +14 -0
  95. package/lib/settings/index.d.ts.map +1 -0
  96. package/lib/settings/index.js +14 -0
  97. package/lib/settings/index.js.map +1 -0
  98. package/lib/settings/rpc-client.d.ts +36 -0
  99. package/lib/settings/rpc-client.d.ts.map +1 -0
  100. package/lib/settings/rpc-client.js +45 -0
  101. package/lib/settings/rpc-client.js.map +1 -0
  102. package/lib/settings/settings-model.d.ts +107 -0
  103. package/lib/settings/settings-model.d.ts.map +1 -0
  104. package/lib/settings/settings-model.js +110 -0
  105. package/lib/settings/settings-model.js.map +1 -0
  106. package/lib/settings/settings-rpc.d.ts +62 -0
  107. package/lib/settings/settings-rpc.d.ts.map +1 -0
  108. package/lib/settings/settings-rpc.js +90 -0
  109. package/lib/settings/settings-rpc.js.map +1 -0
  110. package/lib/settings/settings-service.d.ts +27 -0
  111. package/lib/settings/settings-service.d.ts.map +1 -0
  112. package/lib/settings/settings-service.js +103 -0
  113. package/lib/settings/settings-service.js.map +1 -0
  114. package/package.json +48 -6
@@ -0,0 +1,144 @@
1
+ /**
2
+ * DingTalk channel for DeepSeek Harness — two modes:
3
+ *
4
+ * 1. Webhook push (one-way): the DingTalk group custom robot (群自定义机器人)
5
+ * webhook can send text / markdown / @mention messages into a group. This
6
+ * exposes a push service (`ctx.dingtalk`) for task progress, results and
7
+ * alerts.
8
+ * 2. Stream mode (bidirectional, zero dependencies): with `stream.clientId`
9
+ * / `stream.clientSecret` set, a STOMP-over-WebSocket adapter is
10
+ * registered into `dsh-connect`, so group @-mentions / DMs trigger the
11
+ * agent and replies stream back. Menus are numbered text lists (the user
12
+ * answers with a number); proactive pushes still use the webhook service.
13
+ *
14
+ * @module dsh-connect/dingtalk
15
+ */
16
+ import { Service } from "@deepseek-ai/cordis";
17
+ import z from "@deepseek-ai/schemastery";
18
+ import { DingtalkWebhook } from "./webhook.js";
19
+ import { dingtalkMessages } from "./i18n.js";
20
+ import { DingtalkStreamAdapter } from "./adapter.js";
21
+ export { DingtalkWebhook, signDingtalk, verifyDingtalkSignature } from "./webhook.js";
22
+ export { dingtalkMessages } from "./i18n.js";
23
+ export { DingtalkStreamAdapter } from "./adapter.js";
24
+ export { DingtalkStreamClient, DEFAULT_STREAM_URL } from "./stream.js";
25
+ export { encodeFrame, decodeFrames, escapeHeader, unescapeHeader } from "./stomp.js";
26
+ export { buildConnectBody, buildMarkdownReplyBody, buildTextReplyBody, isAtMentioned, normalizeBotMessage, INBOUND_DESTINATION, REPLY_DESTINATION, } from "./message.js";
27
+ /** Plugin config; secrets may come from config or the DINGTALK_* environment. */
28
+ export const Config = z.object({
29
+ webhookUrl: z.string().role("secret"),
30
+ secret: z.string().role("secret"),
31
+ language: z.union([z.const("zh"), z.const("en")]),
32
+ /** Optional default @-mentions for every push (mobiles / user ids / all). */
33
+ defaultAt: z.object({
34
+ mobiles: z.array(z.string()),
35
+ userIds: z.array(z.string()),
36
+ all: z.boolean(),
37
+ }),
38
+ /** Stream mode (bidirectional): the DingTalk app's Client ID / Client Secret. */
39
+ stream: z.object({
40
+ clientId: z.string().role("secret"),
41
+ clientSecret: z.string().role("secret"),
42
+ url: z.string(),
43
+ requireMention: z.boolean(),
44
+ }),
45
+ });
46
+ /**
47
+ * The push service exposed on the Cordis context. Other plugins can inject
48
+ * `dingtalk` and call `sendMarkdown` / `sendText` to deliver into the group.
49
+ */
50
+ export class DingtalkService extends Service {
51
+ webhook;
52
+ t;
53
+ defaultAt;
54
+ constructor(ctx, config, logger) {
55
+ super(ctx, "dingtalk");
56
+ const webhookUrl = config.webhookUrl ?? process.env.DINGTALK_WEBHOOK_URL;
57
+ if (!webhookUrl) {
58
+ throw new Error(dingtalkMessages(config.language ?? "zh").webhookMissing);
59
+ }
60
+ this.t = dingtalkMessages(config.language ?? "zh");
61
+ this.defaultAt = config.defaultAt;
62
+ try {
63
+ this.webhook = new DingtalkWebhook({
64
+ webhookUrl,
65
+ ...(config.secret ?? process.env.DINGTALK_WEBHOOK_SECRET ? { secret: config.secret ?? process.env.DINGTALK_WEBHOOK_SECRET } : {}),
66
+ });
67
+ }
68
+ catch (error) {
69
+ logger?.warn?.(this.t.webhookInvalid);
70
+ throw error;
71
+ }
72
+ }
73
+ /** Push a markdown card into the DingTalk group. */
74
+ async sendMarkdown(title, text, at) {
75
+ const merged = at === undefined ? this.defaultAt : { ...this.defaultAt, ...at };
76
+ try {
77
+ await this.webhook.sendMarkdown(title, text, merged);
78
+ }
79
+ catch (error) {
80
+ this.ctx.logger?.warn?.(this.t.sendFailed(error instanceof Error ? error.message : String(error)));
81
+ }
82
+ }
83
+ /** Push plain text into the DingTalk group. */
84
+ async sendText(content, at) {
85
+ const merged = at === undefined ? this.defaultAt : { ...this.defaultAt, ...at };
86
+ try {
87
+ await this.webhook.sendText(content, merged);
88
+ }
89
+ catch (error) {
90
+ this.ctx.logger?.warn?.(this.t.sendFailed(error instanceof Error ? error.message : String(error)));
91
+ }
92
+ }
93
+ }
94
+ /**
95
+ * Register and start the DingTalk channel. `connect` may be undefined: when the
96
+ * stream credentials are absent, or when `connect` is not provided, DingTalk
97
+ * degrades to one-way webhook push (`ctx.dingtalk`). The webhook service is
98
+ * always constructed. `connect` is the already-constructed `ConnectService`
99
+ * instance (passed from the merged entry, not resolved via `ctx.get`).
100
+ */
101
+ export function register(connect, config = {}, ctx) {
102
+ // The DSH loader passes `null` for entries without an explicit config.
103
+ config = config ?? {};
104
+ // Stream mode (bidirectional): register a ChannelAdapter into dsh-connect.
105
+ const stream = config.stream ?? {};
106
+ const clientId = stream.clientId ?? process.env.DINGTALK_STREAM_CLIENT_ID;
107
+ const clientSecret = stream.clientSecret ?? process.env.DINGTALK_STREAM_CLIENT_SECRET;
108
+ if (clientId !== undefined && clientSecret !== undefined) {
109
+ if (connect === undefined) {
110
+ ctx.logger?.warn?.("connect-dingtalk: stream mode requires the dsh-connect service; skipping adapter");
111
+ }
112
+ else {
113
+ try {
114
+ const adapter = new DingtalkStreamAdapter({ ...stream, clientId, clientSecret, language: config.language }, ctx.logger);
115
+ connect.registerAdapter(adapter);
116
+ void adapter.start().catch((error) => {
117
+ ctx.logger?.warn?.(`connect-dingtalk: stream adapter start failed: ${String(error)}`);
118
+ });
119
+ }
120
+ catch (error) {
121
+ ctx.logger?.warn?.(`connect-dingtalk: stream adapter init failed: ${String(error)}`);
122
+ }
123
+ }
124
+ }
125
+ // Webhook push service (one-way). `Service` construction registers
126
+ // `ctx.dingtalk` automatically; it throws when no webhookUrl is configured.
127
+ try {
128
+ void new DingtalkService(ctx, config, ctx.logger);
129
+ }
130
+ catch (error) {
131
+ ctx.logger?.warn?.(`connect-dingtalk: init failed: ${String(error)}`);
132
+ }
133
+ }
134
+ /**
135
+ * Compatibility shell for the old split-plugin registration path (when `connect`
136
+ * is an already-active, separate plugin). The merged entry calls `register`
137
+ * directly instead, because `ctx.get("connect")` returns undefined inside this
138
+ * plugin's own `apply`.
139
+ */
140
+ export function apply(ctx, config = {}) {
141
+ const connect = ctx.get("connect");
142
+ register(connect, config, ctx);
143
+ }
144
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/channels/dingtalk/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Pure message normalization for the DingTalk stream mode: raw gateway
3
+ * payloads → dsh-connect `InboundMessage`, and STOMP reply bodies for the
4
+ * reply destination. Kept free of sockets so every branch is unit-testable.
5
+ * @module dsh-connect/channels/dingtalk/message
6
+ */
7
+ import type { InboundMessage } from "../../types.js";
8
+ /** Raw inbound message payload pushed by the stream gateway. */
9
+ export interface DingtalkBotMessage {
10
+ senderStaffId?: string;
11
+ senderNick?: string;
12
+ /** Stable conversation id ("cid…"). */
13
+ conversationId?: string;
14
+ /** "1" = single chat, "2" = group chat. */
15
+ conversationType?: string;
16
+ msgId?: string;
17
+ msgType?: string;
18
+ text?: {
19
+ content?: string;
20
+ };
21
+ /** True when the message @-mentioned the bot (group chats). */
22
+ isInAtList?: boolean;
23
+ /** Mentioned users when `isInAtList` is true. */
24
+ atUsers?: Array<{
25
+ dingtalkId?: string;
26
+ staffId?: string;
27
+ }>;
28
+ }
29
+ /** STOMP destination the gateway pushes inbound bot messages on. */
30
+ export declare const INBOUND_DESTINATION = "/v1.0/im/bot/messages/get";
31
+ /** STOMP destination replies are SENT to. */
32
+ export declare const REPLY_DESTINATION = "/v1.0/im/bot/messages/reply";
33
+ /** STOMP subscription id used for the inbound topic. */
34
+ export declare const INBOUND_SUBSCRIPTION = "inbound";
35
+ /** True when the message @-mentioned the bot (used for group requireMention). */
36
+ export declare function isAtMentioned(msg: DingtalkBotMessage): boolean;
37
+ /**
38
+ * Normalize a gateway payload into an `InboundMessage`. Returns `undefined`
39
+ * for payloads that cannot be routed (missing conversation/sender) or that
40
+ * carry no usable text body.
41
+ */
42
+ export declare function normalizeBotMessage(raw: DingtalkBotMessage, channel?: string): InboundMessage | undefined;
43
+ /** JSON body for a plain-text reply to a message. */
44
+ export declare function buildTextReplyBody(msgId: string, content: string): string;
45
+ /** JSON body for a markdown reply to a message. */
46
+ export declare function buildMarkdownReplyBody(msgId: string, title: string, text: string): string;
47
+ /** JSON body for the STOMP CONNECT frame. */
48
+ export declare function buildConnectBody(clientId: string, clientSecret: string): string;
49
+ //# sourceMappingURL=message.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../src/channels/dingtalk/message.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,gEAAgE;AAChE,MAAM,WAAW,kBAAkB;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5B,+DAA+D;IAC/D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iDAAiD;IACjD,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC5D;AAED,oEAAoE;AACpE,eAAO,MAAM,mBAAmB,8BAA8B,CAAC;AAC/D,6CAA6C;AAC7C,eAAO,MAAM,iBAAiB,gCAAgC,CAAC;AAC/D,wDAAwD;AACxD,eAAO,MAAM,oBAAoB,YAAY,CAAC;AAE9C,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,GAAG,EAAE,kBAAkB,GAAG,OAAO,CAE9D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,kBAAkB,EAAE,OAAO,SAAa,GAAG,cAAc,GAAG,SAAS,CAY7G;AAED,qDAAqD;AACrD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED,mDAAmD;AACnD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzF;AAED,6CAA6C;AAC7C,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAE/E"}
@@ -0,0 +1,43 @@
1
+ /** STOMP destination the gateway pushes inbound bot messages on. */
2
+ export const INBOUND_DESTINATION = "/v1.0/im/bot/messages/get";
3
+ /** STOMP destination replies are SENT to. */
4
+ export const REPLY_DESTINATION = "/v1.0/im/bot/messages/reply";
5
+ /** STOMP subscription id used for the inbound topic. */
6
+ export const INBOUND_SUBSCRIPTION = "inbound";
7
+ /** True when the message @-mentioned the bot (used for group requireMention). */
8
+ export function isAtMentioned(msg) {
9
+ return msg.isInAtList === true;
10
+ }
11
+ /**
12
+ * Normalize a gateway payload into an `InboundMessage`. Returns `undefined`
13
+ * for payloads that cannot be routed (missing conversation/sender) or that
14
+ * carry no usable text body.
15
+ */
16
+ export function normalizeBotMessage(raw, channel = "dingtalk") {
17
+ if (typeof raw.conversationId !== "string" || raw.conversationId === "")
18
+ return undefined;
19
+ if (typeof raw.senderStaffId !== "string" || raw.senderStaffId === "")
20
+ return undefined;
21
+ const text = raw.msgType === "text" ? (raw.text?.content ?? "") : "";
22
+ return {
23
+ channel,
24
+ chatKey: raw.conversationId,
25
+ chatType: raw.conversationType === "2" ? "group" : "p2p",
26
+ senderKey: raw.senderStaffId,
27
+ text,
28
+ ...(typeof raw.msgId === "string" && raw.msgId !== "" ? { replyRef: raw.msgId } : {}),
29
+ };
30
+ }
31
+ /** JSON body for a plain-text reply to a message. */
32
+ export function buildTextReplyBody(msgId, content) {
33
+ return JSON.stringify({ msgKey: "sampleText", msgParam: { content }, msgId });
34
+ }
35
+ /** JSON body for a markdown reply to a message. */
36
+ export function buildMarkdownReplyBody(msgId, title, text) {
37
+ return JSON.stringify({ msgKey: "sampleMarkdown", msgParam: { title, text }, msgId });
38
+ }
39
+ /** JSON body for the STOMP CONNECT frame. */
40
+ export function buildConnectBody(clientId, clientSecret) {
41
+ return JSON.stringify({ clientId, clientSecret, protocolVersion: "1.0" });
42
+ }
43
+ //# sourceMappingURL=message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message.js","sourceRoot":"","sources":["../../../src/channels/dingtalk/message.ts"],"names":[],"mappings":"AAyBA,oEAAoE;AACpE,MAAM,CAAC,MAAM,mBAAmB,GAAG,2BAA2B,CAAC;AAC/D,6CAA6C;AAC7C,MAAM,CAAC,MAAM,iBAAiB,GAAG,6BAA6B,CAAC;AAC/D,wDAAwD;AACxD,MAAM,CAAC,MAAM,oBAAoB,GAAG,SAAS,CAAC;AAE9C,iFAAiF;AACjF,MAAM,UAAU,aAAa,CAAC,GAAuB;IACnD,OAAO,GAAG,CAAC,UAAU,KAAK,IAAI,CAAC;AACjC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAuB,EAAE,OAAO,GAAG,UAAU;IAC/E,IAAI,OAAO,GAAG,CAAC,cAAc,KAAK,QAAQ,IAAI,GAAG,CAAC,cAAc,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAC1F,IAAI,OAAO,GAAG,CAAC,aAAa,KAAK,QAAQ,IAAI,GAAG,CAAC,aAAa,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IACxF,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACrE,OAAO;QACL,OAAO;QACP,OAAO,EAAE,GAAG,CAAC,cAAc;QAC3B,QAAQ,EAAE,GAAG,CAAC,gBAAgB,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK;QACxD,SAAS,EAAE,GAAG,CAAC,aAAa;QAC5B,IAAI;QACJ,GAAG,CAAC,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,IAAI,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtF,CAAC;AACJ,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,kBAAkB,CAAC,KAAa,EAAE,OAAe;IAC/D,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;AAChF,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,sBAAsB,CAAC,KAAa,EAAE,KAAa,EAAE,IAAY;IAC/E,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,gBAAgB,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;AACxF,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,gBAAgB,CAAC,QAAgB,EAAE,YAAoB;IACrE,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC,CAAC;AAC5E,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Minimal STOMP 1.x frame codec used by the DingTalk stream-mode gateway.
3
+ * Pure string logic (no sockets) so it can be unit-tested without a network:
4
+ * DingTalk's stream gateway speaks STOMP over WebSocket with JSON bodies —
5
+ * CONNECT / CONNECTED / SUBSCRIBE / MESSAGE / SEND / ERROR frames and bare
6
+ * newline heartbeats.
7
+ * @module dsh-connect/channels/dingtalk/stomp
8
+ */
9
+ /** One decoded STOMP frame. */
10
+ export interface StompFrame {
11
+ command: string;
12
+ headers: Record<string, string>;
13
+ body: string;
14
+ }
15
+ /**
16
+ * Escape a header value per STOMP rules: backslash, newline, carriage
17
+ * return and colon become \\, \n, \r, \c.
18
+ */
19
+ export declare function escapeHeader(value: string): string;
20
+ /** Reverse of {@link escapeHeader}. */
21
+ export declare function unescapeHeader(value: string): string;
22
+ /** Serialize one frame (command, header block, blank line, body, NUL). */
23
+ export declare function encodeFrame(command: string, headers: Record<string, string>, body?: string): string;
24
+ /** Result of feeding a chunk into the incremental decoder. */
25
+ export interface StompDecodeResult {
26
+ frames: StompFrame[];
27
+ /** Unconsumed tail (partial frame) to carry into the next feed. */
28
+ rest: string;
29
+ }
30
+ /**
31
+ * Incrementally decode STOMP frames from a string buffer. Frames are
32
+ * NUL-terminated; heartbeats (bare newlines) and other whitespace-only
33
+ * segments are skipped. Returns the decoded frames plus the leftover tail.
34
+ */
35
+ export declare function decodeFrames(buffer: string): StompDecodeResult;
36
+ //# sourceMappingURL=stomp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stomp.d.ts","sourceRoot":"","sources":["../../../src/channels/dingtalk/stomp.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,+BAA+B;AAC/B,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAYlD;AAED,uCAAuC;AACvC,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAepD;AAED,0EAA0E;AAC1E,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,IAAI,SAAK,GAAG,MAAM,CAO/F;AAED,8DAA8D;AAC9D,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,CAkC9D"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Minimal STOMP 1.x frame codec used by the DingTalk stream-mode gateway.
3
+ * Pure string logic (no sockets) so it can be unit-tested without a network:
4
+ * DingTalk's stream gateway speaks STOMP over WebSocket with JSON bodies —
5
+ * CONNECT / CONNECTED / SUBSCRIBE / MESSAGE / SEND / ERROR frames and bare
6
+ * newline heartbeats.
7
+ * @module dsh-connect/channels/dingtalk/stomp
8
+ */
9
+ /**
10
+ * Escape a header value per STOMP rules: backslash, newline, carriage
11
+ * return and colon become \\, \n, \r, \c.
12
+ */
13
+ export function escapeHeader(value) {
14
+ let out = "";
15
+ for (const ch of value) {
16
+ switch (ch) {
17
+ case "\\":
18
+ out += "\\\\";
19
+ break;
20
+ case "\n":
21
+ out += "\\n";
22
+ break;
23
+ case "\r":
24
+ out += "\\r";
25
+ break;
26
+ case ":":
27
+ out += "\\c";
28
+ break;
29
+ default: out += ch;
30
+ }
31
+ }
32
+ return out;
33
+ }
34
+ /** Reverse of {@link escapeHeader}. */
35
+ export function unescapeHeader(value) {
36
+ let out = "";
37
+ for (let i = 0; i < value.length; i++) {
38
+ const ch = value[i];
39
+ if (ch === "\\" && i + 1 < value.length) {
40
+ const next = value[++i];
41
+ if (next === "n")
42
+ out += "\n";
43
+ else if (next === "r")
44
+ out += "\r";
45
+ else if (next === "c")
46
+ out += ":";
47
+ else
48
+ out += "\\"; // "\\" escape sequence → a literal backslash
49
+ }
50
+ else {
51
+ out += ch;
52
+ }
53
+ }
54
+ return out;
55
+ }
56
+ /** Serialize one frame (command, header block, blank line, body, NUL). */
57
+ export function encodeFrame(command, headers, body = "") {
58
+ const lines = [command];
59
+ for (const [key, value] of Object.entries(headers)) {
60
+ lines.push(`${key}:${escapeHeader(value)}`);
61
+ }
62
+ lines.push("", body);
63
+ return `${lines.join("\n")}\0`;
64
+ }
65
+ /**
66
+ * Incrementally decode STOMP frames from a string buffer. Frames are
67
+ * NUL-terminated; heartbeats (bare newlines) and other whitespace-only
68
+ * segments are skipped. Returns the decoded frames plus the leftover tail.
69
+ */
70
+ export function decodeFrames(buffer) {
71
+ const frames = [];
72
+ let rest = buffer;
73
+ for (;;) {
74
+ // STOMP heartbeats are bare EOLs (not NUL-terminated): strip any leading
75
+ // newlines before the next frame so a heartbeat doesn't glue onto it.
76
+ rest = rest.replace(/^(?:\r?\n)+/, "");
77
+ const nul = rest.indexOf("\0");
78
+ if (nul === -1)
79
+ break;
80
+ const segment = rest.slice(0, nul);
81
+ rest = rest.slice(nul + 1);
82
+ if (segment.replace(/\r?\n/g, "").trim() === "")
83
+ continue; // NUL-terminated heartbeat / stray EOL
84
+ const normalized = segment.replace(/\r\n/g, "\n");
85
+ const nl = normalized.indexOf("\n");
86
+ const command = (nl === -1 ? normalized : normalized.slice(0, nl)).trim();
87
+ const headerPart = nl === -1 ? "" : normalized.slice(nl + 1);
88
+ const headers = {};
89
+ let bodyStart = -1;
90
+ const lines = headerPart.split("\n");
91
+ for (let i = 0; i < lines.length; i++) {
92
+ const line = lines[i];
93
+ if (line === "") {
94
+ bodyStart = i + 1;
95
+ break;
96
+ }
97
+ const colon = line.indexOf(":");
98
+ if (colon !== -1) {
99
+ headers[unescapeHeader(line.slice(0, colon))] = unescapeHeader(line.slice(colon + 1));
100
+ }
101
+ }
102
+ const body = bodyStart === -1 ? "" : lines.slice(bodyStart).join("\n");
103
+ frames.push({ command, headers, body });
104
+ }
105
+ return { frames, rest };
106
+ }
107
+ //# sourceMappingURL=stomp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stomp.js","sourceRoot":"","sources":["../../../src/channels/dingtalk/stomp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import { type DingtalkBotMessage } from "./message.js";
2
+ export interface DingtalkStreamOptions {
3
+ clientId: string;
4
+ clientSecret: string;
5
+ /** Gateway URL (default wss://api.dingtalk.com/connect). */
6
+ url?: string;
7
+ logger?: {
8
+ info?: (...args: unknown[]) => void;
9
+ warn?: (...args: unknown[]) => void;
10
+ error?: (...args: unknown[]) => void;
11
+ };
12
+ }
13
+ export declare const DEFAULT_STREAM_URL = "wss://api.dingtalk.com/connect";
14
+ /**
15
+ * STOMP-over-WebSocket gateway client. Usage:
16
+ * ```ts
17
+ * const client = new DingtalkStreamClient({ clientId, clientSecret });
18
+ * client.onInbound((raw) => console.log(raw.conversationId, raw.text?.content));
19
+ * await client.connect();
20
+ * await client.sendReply(msgId, buildTextReplyBody(msgId, "hi"));
21
+ * ```
22
+ */
23
+ export declare class DingtalkStreamClient {
24
+ private readonly clientId;
25
+ private readonly clientSecret;
26
+ private readonly url;
27
+ private readonly logger?;
28
+ private ws?;
29
+ private rest;
30
+ private heartbeat?;
31
+ private reconnectTimer?;
32
+ private backoffMs;
33
+ private closedByUs;
34
+ private messageHandler?;
35
+ constructor(options: DingtalkStreamOptions);
36
+ /** Register the inbound-message handler (called for every gateway push). */
37
+ onInbound(handler: (raw: DingtalkBotMessage) => void | Promise<void>): void;
38
+ /** Open the socket, perform the STOMP handshake and subscribe. Reconnect-safe. */
39
+ connect(): Promise<void>;
40
+ /** Send a reply to an inbound message (SEND frame to the reply topic). */
41
+ sendReply(msgId: string, body: string): Promise<void>;
42
+ /** Stop the client and cancel any scheduled reconnect. */
43
+ close(): void;
44
+ private onSocketOpen;
45
+ private onSocketMessage;
46
+ private onSocketClose;
47
+ private scheduleReconnect;
48
+ private handleFrame;
49
+ private sendFrame;
50
+ private startHeartbeat;
51
+ private stopHeartbeat;
52
+ }
53
+ //# sourceMappingURL=stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../../src/channels/dingtalk/stream.ts"],"names":[],"mappings":"AAcA,OAAO,EAKL,KAAK,kBAAkB,EACxB,MAAM,cAAc,CAAC;AAatB,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE;QACP,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;QACpC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;QACpC,KAAK,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;KACtC,CAAC;CACH;AAED,eAAO,MAAM,kBAAkB,mCAAmC,CAAC;AAUnE;;;;;;;;GAQG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAkC;IAC1D,OAAO,CAAC,EAAE,CAAC,CAAgB;IAC3B,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,SAAS,CAAC,CAAiB;IACnC,OAAO,CAAC,cAAc,CAAC,CAAiB;IACxC,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,cAAc,CAAC,CAAoD;gBAE/D,OAAO,EAAE,qBAAqB;IAO1C,4EAA4E;IAC5E,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,kBAAkB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAI3E,kFAAkF;IAC5E,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAqC9B,0EAA0E;IACpE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ3D,0DAA0D;IAC1D,KAAK,IAAI,IAAI;IAWb,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,WAAW;IAkCnB,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,aAAa;CAMtB"}