dingtalk-manager 1.0.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/LICENSE +21 -0
- package/README.md +267 -0
- package/dist/client.d.ts +15 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/errors.d.ts +13 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +307 -0
- package/dist/index.js.map +12 -0
- package/dist/types.d.ts +132 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils.d.ts +19 -0
- package/dist/utils.d.ts.map +1 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 buwai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# dingtalk-manager
|
|
2
|
+
|
|
3
|
+
钉钉工作通知 API 客户端,支持 Node.js/Bun。通过工作通知 API 向钉钉用户发送 Markdown 和文本消息。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# npm
|
|
9
|
+
npm install dingtalk-manager
|
|
10
|
+
|
|
11
|
+
# yarn
|
|
12
|
+
yarn add dingtalk-manager
|
|
13
|
+
|
|
14
|
+
# bun
|
|
15
|
+
bun add dingtalk-manager
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## 快速开始
|
|
19
|
+
|
|
20
|
+
### 方式一:直接传入凭证
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { DingTalk } from 'dingtalk-manager';
|
|
24
|
+
|
|
25
|
+
const client = new DingTalk({
|
|
26
|
+
credentials: {
|
|
27
|
+
appKey: 'your-app-key',
|
|
28
|
+
appSecret: 'your-app-secret',
|
|
29
|
+
agentId: 'your-agent-id',
|
|
30
|
+
userId: 'target-user-id',
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// 发送 Markdown 消息
|
|
35
|
+
const result = await client.sendMarkdown('标题', '**加粗** 内容\n- 项目 1\n- 项目 2');
|
|
36
|
+
|
|
37
|
+
if (result.success) {
|
|
38
|
+
console.log('消息已发送!Task ID:', result.taskId);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// 发送文本消息
|
|
42
|
+
await client.sendText('纯文本消息');
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 方式二:环境变量
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
export DINGTALK_APP_KEY="your-app-key"
|
|
49
|
+
export DINGTALK_APP_SECRET="your-app-secret"
|
|
50
|
+
export DINGTALK_AGENT_ID="your-agent-id"
|
|
51
|
+
export DINGTALK_USER_ID="target-user-id"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { DingTalk } from 'dingtalk-manager';
|
|
56
|
+
|
|
57
|
+
const client = new DingTalk();
|
|
58
|
+
await client.sendMarkdown('标题', '内容');
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 方式三:凭证文件
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import { DingTalk } from 'dingtalk-manager';
|
|
65
|
+
|
|
66
|
+
const client = new DingTalk({
|
|
67
|
+
credentialsPath: '/path/to/credentials.json',
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
await client.sendMarkdown('标题', '内容');
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
凭证文件格式 (`credentials.json`):
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"appKey": "your-app-key",
|
|
78
|
+
"appSecret": "your-app-secret",
|
|
79
|
+
"agentId": "your-agent-id",
|
|
80
|
+
"userId": "target-user-id"
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## API 参考
|
|
85
|
+
|
|
86
|
+
### `new DingTalk(options?)`
|
|
87
|
+
|
|
88
|
+
创建 DingTalk 客户端实例。
|
|
89
|
+
|
|
90
|
+
| 参数 | 类型 | 说明 |
|
|
91
|
+
|--------|------|-------------|
|
|
92
|
+
| `credentials` | `DingTalkCredentials` | 直接传入凭证(优先级最高) |
|
|
93
|
+
| `credentialsPath` | `string` | 凭证 JSON 文件路径 |
|
|
94
|
+
| `tokenCacheDir` | `string` | access_token 缓存目录(默认:`os.tmpdir()`) |
|
|
95
|
+
|
|
96
|
+
### `client.sendMarkdown(title, content)`
|
|
97
|
+
|
|
98
|
+
发送 Markdown 消息。
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
const result = await client.sendMarkdown('报告', `
|
|
102
|
+
## 每日报告
|
|
103
|
+
|
|
104
|
+
- 任务 1: 完成 ✅
|
|
105
|
+
- 任务 2: 待处理 ⏳
|
|
106
|
+
|
|
107
|
+
**总计**: 2 个任务
|
|
108
|
+
`);
|
|
109
|
+
|
|
110
|
+
console.log(result.success); // true
|
|
111
|
+
console.log(result.taskId); // '123456789'
|
|
112
|
+
console.log(result.error); // undefined(成功时)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### `client.sendText(content)`
|
|
116
|
+
|
|
117
|
+
发送纯文本消息。
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
const result = await client.sendText('你好,这是一条纯文本消息。');
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### `client.getSendResult(taskId)`
|
|
124
|
+
|
|
125
|
+
查询消息发送状态。
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
const status = await client.getSendResult('123456789');
|
|
129
|
+
|
|
130
|
+
console.log(status.success); // true
|
|
131
|
+
console.log(status.readUserIdList); // ['user1', 'user2'] 已读用户
|
|
132
|
+
console.log(status.unreadUserIdList); // ['user3'] 未读用户
|
|
133
|
+
console.log(status.forbiddenList); // [{ code: '143106', userid: 'user4', count: 1 }] 被限流用户
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### `DingTalk.getForbiddenCodeInfo(code)`
|
|
137
|
+
|
|
138
|
+
获取错误码的可读描述。
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
const info = DingTalk.getForbiddenCodeInfo('143106');
|
|
142
|
+
// {
|
|
143
|
+
// description: '应用重复消息发送限超限(同一用户每天只能接收一条相同内容的消息)',
|
|
144
|
+
// solution: '修改消息内容后重新发送,或等待明天自动重置'
|
|
145
|
+
// }
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### `client.getAccessToken()`
|
|
149
|
+
|
|
150
|
+
获取 access_token(带缓存)。通常不需要直接调用,但如有需要可以使用。
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
const token = await client.getAccessToken();
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## 错误码
|
|
157
|
+
|
|
158
|
+
| 错误码 | 描述 | 解决方案 |
|
|
159
|
+
|------|-------------|----------|
|
|
160
|
+
| 143103 | 企业应用消息发送QPM超限 | 稍后重试,或优化发送频率 |
|
|
161
|
+
| 143104 | 企业每分钟发送QPM超限 | 稍后重试,或优化发送频率 |
|
|
162
|
+
| 143105 | 应用发送日限超限 | 已达每日上限,明天再试 |
|
|
163
|
+
| 143106 | 重复消息发送限超限 | 修改消息内容,或等待明天 |
|
|
164
|
+
|
|
165
|
+
## 错误处理
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
import { DingTalk, DingTalkError, TokenError, MessageError, CredentialError } from 'dingtalk-manager';
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
const client = new DingTalk();
|
|
172
|
+
const result = await client.sendMarkdown('标题', '内容');
|
|
173
|
+
|
|
174
|
+
if (!result.success) {
|
|
175
|
+
console.error('发送失败:', result.error);
|
|
176
|
+
}
|
|
177
|
+
} catch (error) {
|
|
178
|
+
if (error instanceof CredentialError) {
|
|
179
|
+
console.error('凭证无效:', error.message);
|
|
180
|
+
} else if (error instanceof TokenError) {
|
|
181
|
+
console.error('Token 错误:', error.message);
|
|
182
|
+
} else if (error instanceof DingTalkError) {
|
|
183
|
+
console.error('钉钉错误:', error.message);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Token 缓存
|
|
189
|
+
|
|
190
|
+
access_token 会自动缓存以减少 API 调用。Token 有效期为 2 小时,本库会提前 5 分钟刷新。
|
|
191
|
+
|
|
192
|
+
默认缓存位置:`os.tmpdir()/dingtalk-token-cache.json`
|
|
193
|
+
|
|
194
|
+
自定义缓存目录:
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
const client = new DingTalk({
|
|
198
|
+
credentials: { /* ... */ },
|
|
199
|
+
tokenCacheDir: '/custom/cache/directory',
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## 开发
|
|
204
|
+
|
|
205
|
+
### 安装依赖
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
bun install
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### 可用命令
|
|
212
|
+
|
|
213
|
+
| 命令 | 说明 |
|
|
214
|
+
|------|------|
|
|
215
|
+
| `bun run build` | 完整构建(清理 → 编译 JS → 生成类型声明) |
|
|
216
|
+
| `bun run build:clean` | 清理 `dist/` 目录 |
|
|
217
|
+
| `bun run build:js` | 编译 TypeScript 到 ES Module JS(使用 Bun) |
|
|
218
|
+
| `bun run build:types` | 生成 `.d.ts` 类型声明文件(使用 tsc) |
|
|
219
|
+
| `bun test` | 运行所有测试 |
|
|
220
|
+
| `bun run test:watch` | 监听模式运行测试(文件变化自动重跑) |
|
|
221
|
+
| `bun run release` | 构建并发布到 npm |
|
|
222
|
+
| `bun run release:dry` | 模拟发布(检查打包内容,不实际上传) |
|
|
223
|
+
|
|
224
|
+
### 命令详解
|
|
225
|
+
|
|
226
|
+
#### 构建相关
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
# 完整构建流程
|
|
230
|
+
bun run build
|
|
231
|
+
# 等同于依次执行:
|
|
232
|
+
# 1. bun run build:clean → 删除 dist/ 目录
|
|
233
|
+
# 2. bun run build:js → 编译 src/index.ts 到 dist/index.js
|
|
234
|
+
# 3. bun run build:types → 生成 dist/*.d.ts 类型声明
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
#### 测试相关
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
# 运行测试
|
|
241
|
+
bun test
|
|
242
|
+
|
|
243
|
+
# 监听模式(开发时推荐)
|
|
244
|
+
bun run test:watch
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
#### 发布相关
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
# 模拟发布(检查打包内容、文件大小等)
|
|
251
|
+
bun run release:dry
|
|
252
|
+
|
|
253
|
+
# 正式发布(会自动执行 prepublishOnly 钩子)
|
|
254
|
+
npm publish
|
|
255
|
+
# 或使用封装命令
|
|
256
|
+
bun run release
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**注意**:`npm publish` 会自动触发 `prepublishOnly` 钩子,先执行 `bun run build && bun test`,确保构建和测试都通过后才发布。
|
|
260
|
+
|
|
261
|
+
## 环境要求
|
|
262
|
+
|
|
263
|
+
- Node.js >= 18.0.0 或 Bun >= 1.0.0
|
|
264
|
+
|
|
265
|
+
## 许可证
|
|
266
|
+
|
|
267
|
+
MIT
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DingTalkOptions, SendMessageResult, SendResult } from './types.js';
|
|
2
|
+
export declare class DingTalk {
|
|
3
|
+
private credentials;
|
|
4
|
+
private tokenManager;
|
|
5
|
+
constructor(options?: DingTalkOptions);
|
|
6
|
+
getAccessToken(): Promise<string>;
|
|
7
|
+
sendMarkdown(title: string, content: string): Promise<SendMessageResult>;
|
|
8
|
+
sendText(content: string): Promise<SendMessageResult>;
|
|
9
|
+
getSendResult(taskId: string): Promise<SendResult>;
|
|
10
|
+
static getForbiddenCodeInfo(code: string): {
|
|
11
|
+
description: string;
|
|
12
|
+
solution: string;
|
|
13
|
+
} | null;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EAEf,iBAAiB,EACjB,UAAU,EAIX,MAAM,YAAY,CAAC;AAMpB,qBAAa,QAAQ;IACnB,OAAO,CAAC,WAAW,CAAsB;IACzC,OAAO,CAAC,YAAY,CAAe;gBAEvB,OAAO,CAAC,EAAE,eAAe;IAK/B,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAiCjC,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IA0CxE,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAuCrD,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IA2CxD,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;CAG5F"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare class DingTalkError extends Error {
|
|
2
|
+
constructor(message: string);
|
|
3
|
+
}
|
|
4
|
+
export declare class TokenError extends DingTalkError {
|
|
5
|
+
constructor(message: string);
|
|
6
|
+
}
|
|
7
|
+
export declare class MessageError extends DingTalkError {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
export declare class CredentialError extends DingTalkError {
|
|
11
|
+
constructor(message: string);
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,aAAc,SAAQ,KAAK;gBAC1B,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,UAAW,SAAQ,aAAa;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,YAAa,SAAQ,aAAa;gBACjC,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,eAAgB,SAAQ,aAAa;gBACpC,OAAO,EAAE,MAAM;CAI5B"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { DingTalk } from './client.js';
|
|
2
|
+
export type { DingTalkOptions, DingTalkCredentials, SendMessageResult, SendResult, ForbiddenInfo, ForbiddenCodeInfo, TokenCache, } from './types.js';
|
|
3
|
+
export { DingTalkError, TokenError, MessageError, CredentialError } from './errors.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,UAAU,GACX,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
// src/utils.ts
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
|
|
6
|
+
// src/errors.ts
|
|
7
|
+
class DingTalkError extends Error {
|
|
8
|
+
constructor(message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "DingTalkError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class TokenError extends DingTalkError {
|
|
15
|
+
constructor(message) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = "TokenError";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
class MessageError extends DingTalkError {
|
|
22
|
+
constructor(message) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = "MessageError";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
class CredentialError extends DingTalkError {
|
|
29
|
+
constructor(message) {
|
|
30
|
+
super(message);
|
|
31
|
+
this.name = "CredentialError";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// src/utils.ts
|
|
36
|
+
var ENV_KEYS = {
|
|
37
|
+
APP_KEY: "DINGTALK_APP_KEY",
|
|
38
|
+
APP_SECRET: "DINGTALK_APP_SECRET",
|
|
39
|
+
AGENT_ID: "DINGTALK_AGENT_ID",
|
|
40
|
+
USER_ID: "DINGTALK_USER_ID"
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
class TokenManager {
|
|
44
|
+
cacheDir;
|
|
45
|
+
cacheFile;
|
|
46
|
+
constructor(cacheDir) {
|
|
47
|
+
this.cacheDir = cacheDir ?? tmpdir();
|
|
48
|
+
this.cacheFile = join(this.cacheDir, "dingtalk-token-cache.json");
|
|
49
|
+
}
|
|
50
|
+
load() {
|
|
51
|
+
try {
|
|
52
|
+
if (!existsSync(this.cacheFile)) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
const content = readFileSync(this.cacheFile, "utf-8");
|
|
56
|
+
return JSON.parse(content);
|
|
57
|
+
} catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
save(cache) {
|
|
62
|
+
try {
|
|
63
|
+
if (!existsSync(this.cacheDir)) {
|
|
64
|
+
mkdirSync(this.cacheDir, { recursive: true, mode: 448 });
|
|
65
|
+
}
|
|
66
|
+
writeFileSync(this.cacheFile, JSON.stringify(cache, null, 2), { mode: 384 });
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.error("Failed to cache DingTalk token:", error instanceof Error ? error.message : String(error));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
isValid(cache) {
|
|
72
|
+
return cache !== null && cache.expiresAt > Date.now();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function loadCredentials(options) {
|
|
76
|
+
if (options?.credentials) {
|
|
77
|
+
validateCredentials(options.credentials);
|
|
78
|
+
return options.credentials;
|
|
79
|
+
}
|
|
80
|
+
if (options?.credentialsPath) {
|
|
81
|
+
const creds = loadFromFile(options.credentialsPath);
|
|
82
|
+
if (creds) {
|
|
83
|
+
validateCredentials(creds);
|
|
84
|
+
return creds;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const envCreds = loadFromEnv();
|
|
88
|
+
if (envCreds) {
|
|
89
|
+
validateCredentials(envCreds);
|
|
90
|
+
return envCreds;
|
|
91
|
+
}
|
|
92
|
+
throw new CredentialError("DingTalk credentials not found. Provide credentials via options.credentials, options.credentialsPath, or environment variables (DINGTALK_APP_KEY, DINGTALK_APP_SECRET, DINGTALK_AGENT_ID, DINGTALK_USER_ID)");
|
|
93
|
+
}
|
|
94
|
+
function loadFromEnv() {
|
|
95
|
+
const appKey = process.env[ENV_KEYS.APP_KEY];
|
|
96
|
+
const appSecret = process.env[ENV_KEYS.APP_SECRET];
|
|
97
|
+
const agentId = process.env[ENV_KEYS.AGENT_ID];
|
|
98
|
+
const userId = process.env[ENV_KEYS.USER_ID];
|
|
99
|
+
if (appKey && appSecret && agentId && userId) {
|
|
100
|
+
return { appKey, appSecret, agentId, userId };
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
function loadFromFile(path) {
|
|
105
|
+
try {
|
|
106
|
+
if (!existsSync(path)) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
const content = readFileSync(path, "utf-8");
|
|
110
|
+
const data = JSON.parse(content);
|
|
111
|
+
return {
|
|
112
|
+
appKey: data.appKey,
|
|
113
|
+
appSecret: data.appSecret,
|
|
114
|
+
agentId: data.agentId,
|
|
115
|
+
userId: data.userId ?? data.userid
|
|
116
|
+
};
|
|
117
|
+
} catch {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function validateCredentials(creds) {
|
|
122
|
+
const missing = [];
|
|
123
|
+
if (!creds.appKey)
|
|
124
|
+
missing.push("appKey");
|
|
125
|
+
if (!creds.appSecret)
|
|
126
|
+
missing.push("appSecret");
|
|
127
|
+
if (!creds.agentId)
|
|
128
|
+
missing.push("agentId");
|
|
129
|
+
if (!creds.userId)
|
|
130
|
+
missing.push("userId");
|
|
131
|
+
if (missing.length > 0) {
|
|
132
|
+
throw new CredentialError(`Missing required credentials: ${missing.join(", ")}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
var FORBIDDEN_CODES = {
|
|
136
|
+
"143103": {
|
|
137
|
+
description: "企业应用消息发送QPM(每分钟请求数)超限",
|
|
138
|
+
solution: "请稍后重试,或优化发送频率"
|
|
139
|
+
},
|
|
140
|
+
"143104": {
|
|
141
|
+
description: "企业每分钟发送QPM超限",
|
|
142
|
+
solution: "请稍后重试,或优化发送频率"
|
|
143
|
+
},
|
|
144
|
+
"143105": {
|
|
145
|
+
description: "应用发送日限超限(自建应用: 500条/天/用户, ISV应用: 50条/天/用户)",
|
|
146
|
+
solution: "已达到每日发送上限,请明天再试"
|
|
147
|
+
},
|
|
148
|
+
"143106": {
|
|
149
|
+
description: "应用重复消息发送限超限(同一用户每天只能接收一条相同内容的消息)",
|
|
150
|
+
solution: "修改消息内容后重新发送,或等待明天自动重置"
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
function getForbiddenCodeInfo(code) {
|
|
154
|
+
return FORBIDDEN_CODES[code] ?? null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// src/client.ts
|
|
158
|
+
var TOKEN_EXPIRY_BUFFER_SECONDS = 300;
|
|
159
|
+
|
|
160
|
+
class DingTalk {
|
|
161
|
+
credentials;
|
|
162
|
+
tokenManager;
|
|
163
|
+
constructor(options) {
|
|
164
|
+
this.credentials = loadCredentials(options);
|
|
165
|
+
this.tokenManager = new TokenManager(options?.tokenCacheDir);
|
|
166
|
+
}
|
|
167
|
+
async getAccessToken() {
|
|
168
|
+
const cached = this.tokenManager.load();
|
|
169
|
+
if (this.tokenManager.isValid(cached)) {
|
|
170
|
+
return cached.accessToken;
|
|
171
|
+
}
|
|
172
|
+
const url = `https://oapi.dingtalk.com/gettoken?appkey=${encodeURIComponent(this.credentials.appKey)}&appsecret=${encodeURIComponent(this.credentials.appSecret)}`;
|
|
173
|
+
const response = await fetch(url, { method: "GET" });
|
|
174
|
+
if (!response.ok) {
|
|
175
|
+
throw new TokenError(`Failed to get access token: HTTP ${response.status}`);
|
|
176
|
+
}
|
|
177
|
+
const data = await response.json();
|
|
178
|
+
if (data.errcode !== 0) {
|
|
179
|
+
throw new TokenError(`Failed to get access token: ${data.errmsg ?? "Unknown error"}`);
|
|
180
|
+
}
|
|
181
|
+
if (!data.access_token) {
|
|
182
|
+
throw new TokenError("Access token missing in response");
|
|
183
|
+
}
|
|
184
|
+
const expiresInSeconds = data.expires_in ?? 7200;
|
|
185
|
+
this.tokenManager.save({
|
|
186
|
+
accessToken: data.access_token,
|
|
187
|
+
expiresAt: Date.now() + (expiresInSeconds - TOKEN_EXPIRY_BUFFER_SECONDS) * 1000
|
|
188
|
+
});
|
|
189
|
+
return data.access_token;
|
|
190
|
+
}
|
|
191
|
+
async sendMarkdown(title, content) {
|
|
192
|
+
try {
|
|
193
|
+
const accessToken = await this.getAccessToken();
|
|
194
|
+
const url = `https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2?access_token=${accessToken}`;
|
|
195
|
+
const body = {
|
|
196
|
+
agent_id: this.credentials.agentId,
|
|
197
|
+
userid_list: this.credentials.userId,
|
|
198
|
+
msg: {
|
|
199
|
+
msgtype: "markdown",
|
|
200
|
+
markdown: {
|
|
201
|
+
title,
|
|
202
|
+
text: content
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
const response = await fetch(url, {
|
|
207
|
+
method: "POST",
|
|
208
|
+
headers: { "Content-Type": "application/json" },
|
|
209
|
+
body: JSON.stringify(body)
|
|
210
|
+
});
|
|
211
|
+
if (!response.ok) {
|
|
212
|
+
return { success: false, error: `HTTP ${response.status}` };
|
|
213
|
+
}
|
|
214
|
+
const data = await response.json();
|
|
215
|
+
if (data.errcode !== 0) {
|
|
216
|
+
return { success: false, error: data.errmsg ?? `Error code: ${data.errcode}` };
|
|
217
|
+
}
|
|
218
|
+
return { success: true, taskId: data.task_id?.toString() };
|
|
219
|
+
} catch (error) {
|
|
220
|
+
return {
|
|
221
|
+
success: false,
|
|
222
|
+
error: error instanceof Error ? error.message : String(error)
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
async sendText(content) {
|
|
227
|
+
try {
|
|
228
|
+
const accessToken = await this.getAccessToken();
|
|
229
|
+
const url = `https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2?access_token=${accessToken}`;
|
|
230
|
+
const body = {
|
|
231
|
+
agent_id: this.credentials.agentId,
|
|
232
|
+
userid_list: this.credentials.userId,
|
|
233
|
+
msg: {
|
|
234
|
+
msgtype: "text",
|
|
235
|
+
text: { content }
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
const response = await fetch(url, {
|
|
239
|
+
method: "POST",
|
|
240
|
+
headers: { "Content-Type": "application/json" },
|
|
241
|
+
body: JSON.stringify(body)
|
|
242
|
+
});
|
|
243
|
+
if (!response.ok) {
|
|
244
|
+
return { success: false, error: `HTTP ${response.status}` };
|
|
245
|
+
}
|
|
246
|
+
const data = await response.json();
|
|
247
|
+
if (data.errcode !== 0) {
|
|
248
|
+
return { success: false, error: data.errmsg ?? `Error code: ${data.errcode}` };
|
|
249
|
+
}
|
|
250
|
+
return { success: true, taskId: data.task_id?.toString() };
|
|
251
|
+
} catch (error) {
|
|
252
|
+
return {
|
|
253
|
+
success: false,
|
|
254
|
+
error: error instanceof Error ? error.message : String(error)
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
async getSendResult(taskId) {
|
|
259
|
+
try {
|
|
260
|
+
const accessToken = await this.getAccessToken();
|
|
261
|
+
const url = `https://oapi.dingtalk.com/topapi/message/corpconversation/getsendresult?access_token=${accessToken}`;
|
|
262
|
+
const body = {
|
|
263
|
+
agent_id: this.credentials.agentId,
|
|
264
|
+
task_id: Number(taskId)
|
|
265
|
+
};
|
|
266
|
+
const response = await fetch(url, {
|
|
267
|
+
method: "POST",
|
|
268
|
+
headers: { "Content-Type": "application/json" },
|
|
269
|
+
body: JSON.stringify(body)
|
|
270
|
+
});
|
|
271
|
+
if (!response.ok) {
|
|
272
|
+
return { success: false, error: `HTTP ${response.status}` };
|
|
273
|
+
}
|
|
274
|
+
const data = await response.json();
|
|
275
|
+
if (data.errcode !== 0) {
|
|
276
|
+
return { success: false, error: data.errmsg ?? `Error code: ${data.errcode}` };
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
success: true,
|
|
280
|
+
invalidUserIdList: data.send_result?.invalid_user_id_list,
|
|
281
|
+
forbiddenUserIdList: data.send_result?.forbidden_user_id_list,
|
|
282
|
+
failedUserIdList: data.send_result?.failed_user_id_list,
|
|
283
|
+
readUserIdList: data.send_result?.read_user_id_list,
|
|
284
|
+
unreadUserIdList: data.send_result?.unread_user_id_list,
|
|
285
|
+
forbiddenList: data.send_result?.forbidden_list
|
|
286
|
+
};
|
|
287
|
+
} catch (error) {
|
|
288
|
+
return {
|
|
289
|
+
success: false,
|
|
290
|
+
error: error instanceof Error ? error.message : String(error)
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
static getForbiddenCodeInfo(code) {
|
|
295
|
+
return getForbiddenCodeInfo(code);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
export {
|
|
299
|
+
TokenError,
|
|
300
|
+
MessageError,
|
|
301
|
+
DingTalkError,
|
|
302
|
+
DingTalk,
|
|
303
|
+
CredentialError
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
//# debugId=7AFD9129F0A4FCB764756E2164756E21
|
|
307
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/utils.ts", "../src/errors.ts", "../src/client.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport type { DingTalkCredentials, DingTalkOptions, TokenCache } from './types.js';\nimport { CredentialError } from './errors.js';\n\nconst ENV_KEYS = {\n APP_KEY: 'DINGTALK_APP_KEY',\n APP_SECRET: 'DINGTALK_APP_SECRET',\n AGENT_ID: 'DINGTALK_AGENT_ID',\n USER_ID: 'DINGTALK_USER_ID',\n} as const;\n\nexport class TokenManager {\n private cacheDir: string;\n private cacheFile: string;\n\n constructor(cacheDir?: string) {\n this.cacheDir = cacheDir ?? tmpdir();\n this.cacheFile = join(this.cacheDir, 'dingtalk-token-cache.json');\n }\n\n load(): TokenCache | null {\n try {\n if (!existsSync(this.cacheFile)) {\n return null;\n }\n const content = readFileSync(this.cacheFile, 'utf-8');\n return JSON.parse(content) as TokenCache;\n } catch {\n return null;\n }\n }\n\n save(cache: TokenCache): void {\n try {\n if (!existsSync(this.cacheDir)) {\n mkdirSync(this.cacheDir, { recursive: true, mode: 0o700 });\n }\n writeFileSync(this.cacheFile, JSON.stringify(cache, null, 2), { mode: 0o600 });\n } catch (error) {\n console.error('Failed to cache DingTalk token:', error instanceof Error ? error.message : String(error));\n }\n }\n\n isValid(cache: TokenCache | null): cache is TokenCache {\n return cache !== null && cache.expiresAt > Date.now();\n }\n}\n\nexport function loadCredentials(options?: DingTalkOptions): DingTalkCredentials {\n if (options?.credentials) {\n validateCredentials(options.credentials);\n return options.credentials;\n }\n\n if (options?.credentialsPath) {\n const creds = loadFromFile(options.credentialsPath);\n if (creds) {\n validateCredentials(creds);\n return creds;\n }\n }\n\n const envCreds = loadFromEnv();\n if (envCreds) {\n validateCredentials(envCreds);\n return envCreds;\n }\n\n throw new CredentialError(\n 'DingTalk credentials not found. Provide credentials via options.credentials, options.credentialsPath, or environment variables (DINGTALK_APP_KEY, DINGTALK_APP_SECRET, DINGTALK_AGENT_ID, DINGTALK_USER_ID)'\n );\n}\n\nfunction loadFromEnv(): DingTalkCredentials | null {\n const appKey = process.env[ENV_KEYS.APP_KEY];\n const appSecret = process.env[ENV_KEYS.APP_SECRET];\n const agentId = process.env[ENV_KEYS.AGENT_ID];\n const userId = process.env[ENV_KEYS.USER_ID];\n\n if (appKey && appSecret && agentId && userId) {\n return { appKey, appSecret, agentId, userId };\n }\n return null;\n}\n\nfunction loadFromFile(path: string): DingTalkCredentials | null {\n try {\n if (!existsSync(path)) {\n return null;\n }\n const content = readFileSync(path, 'utf-8');\n const data = JSON.parse(content);\n return {\n appKey: data.appKey,\n appSecret: data.appSecret,\n agentId: data.agentId,\n userId: data.userId ?? data.userid,\n };\n } catch {\n return null;\n }\n}\n\nfunction validateCredentials(creds: DingTalkCredentials): void {\n const missing: string[] = [];\n if (!creds.appKey) missing.push('appKey');\n if (!creds.appSecret) missing.push('appSecret');\n if (!creds.agentId) missing.push('agentId');\n if (!creds.userId) missing.push('userId');\n\n if (missing.length > 0) {\n throw new CredentialError(`Missing required credentials: ${missing.join(', ')}`);\n }\n}\n\nexport const FORBIDDEN_CODES: Record<string, { description: string; solution: string }> = {\n '143103': {\n description: '企业应用消息发送QPM(每分钟请求数)超限',\n solution: '请稍后重试,或优化发送频率',\n },\n '143104': {\n description: '企业每分钟发送QPM超限',\n solution: '请稍后重试,或优化发送频率',\n },\n '143105': {\n description: '应用发送日限超限(自建应用: 500条/天/用户, ISV应用: 50条/天/用户)',\n solution: '已达到每日发送上限,请明天再试',\n },\n '143106': {\n description: '应用重复消息发送限超限(同一用户每天只能接收一条相同内容的消息)',\n solution: '修改消息内容后重新发送,或等待明天自动重置',\n },\n};\n\nexport function getForbiddenCodeInfo(code: string): { description: string; solution: string } | null {\n return FORBIDDEN_CODES[code] ?? null;\n}\n",
|
|
6
|
+
"export class DingTalkError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'DingTalkError';\n }\n}\n\nexport class TokenError extends DingTalkError {\n constructor(message: string) {\n super(message);\n this.name = 'TokenError';\n }\n}\n\nexport class MessageError extends DingTalkError {\n constructor(message: string) {\n super(message);\n this.name = 'MessageError';\n }\n}\n\nexport class CredentialError extends DingTalkError {\n constructor(message: string) {\n super(message);\n this.name = 'CredentialError';\n }\n}\n",
|
|
7
|
+
"import type {\n DingTalkOptions,\n DingTalkCredentials,\n SendMessageResult,\n SendResult,\n TokenResponse,\n SendResponse,\n SendResultResponse,\n} from './types.js';\nimport { TokenManager, loadCredentials, getForbiddenCodeInfo } from './utils.js';\nimport { TokenError, MessageError } from './errors.js';\n\nconst TOKEN_EXPIRY_BUFFER_SECONDS = 300;\n\nexport class DingTalk {\n private credentials: DingTalkCredentials;\n private tokenManager: TokenManager;\n\n constructor(options?: DingTalkOptions) {\n this.credentials = loadCredentials(options);\n this.tokenManager = new TokenManager(options?.tokenCacheDir);\n }\n\n async getAccessToken(): Promise<string> {\n const cached = this.tokenManager.load();\n if (this.tokenManager.isValid(cached)) {\n return cached.accessToken;\n }\n\n const url = `https://oapi.dingtalk.com/gettoken?appkey=${encodeURIComponent(this.credentials.appKey)}&appsecret=${encodeURIComponent(this.credentials.appSecret)}`;\n\n const response = await fetch(url, { method: 'GET' });\n\n if (!response.ok) {\n throw new TokenError(`Failed to get access token: HTTP ${response.status}`);\n }\n\n const data = (await response.json()) as TokenResponse;\n\n if (data.errcode !== 0) {\n throw new TokenError(`Failed to get access token: ${data.errmsg ?? 'Unknown error'}`);\n }\n\n if (!data.access_token) {\n throw new TokenError('Access token missing in response');\n }\n\n const expiresInSeconds = data.expires_in ?? 7200;\n this.tokenManager.save({\n accessToken: data.access_token,\n expiresAt: Date.now() + (expiresInSeconds - TOKEN_EXPIRY_BUFFER_SECONDS) * 1000,\n });\n\n return data.access_token;\n }\n\n async sendMarkdown(title: string, content: string): Promise<SendMessageResult> {\n try {\n const accessToken = await this.getAccessToken();\n const url = `https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2?access_token=${accessToken}`;\n\n const body = {\n agent_id: this.credentials.agentId,\n userid_list: this.credentials.userId,\n msg: {\n msgtype: 'markdown',\n markdown: {\n title,\n text: content,\n },\n },\n };\n\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n return { success: false, error: `HTTP ${response.status}` };\n }\n\n const data = (await response.json()) as SendResponse;\n\n if (data.errcode !== 0) {\n return { success: false, error: data.errmsg ?? `Error code: ${data.errcode}` };\n }\n\n return { success: true, taskId: data.task_id?.toString() };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n async sendText(content: string): Promise<SendMessageResult> {\n try {\n const accessToken = await this.getAccessToken();\n const url = `https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2?access_token=${accessToken}`;\n\n const body = {\n agent_id: this.credentials.agentId,\n userid_list: this.credentials.userId,\n msg: {\n msgtype: 'text',\n text: { content },\n },\n };\n\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n return { success: false, error: `HTTP ${response.status}` };\n }\n\n const data = (await response.json()) as SendResponse;\n\n if (data.errcode !== 0) {\n return { success: false, error: data.errmsg ?? `Error code: ${data.errcode}` };\n }\n\n return { success: true, taskId: data.task_id?.toString() };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n async getSendResult(taskId: string): Promise<SendResult> {\n try {\n const accessToken = await this.getAccessToken();\n const url = `https://oapi.dingtalk.com/topapi/message/corpconversation/getsendresult?access_token=${accessToken}`;\n\n const body = {\n agent_id: this.credentials.agentId,\n task_id: Number(taskId),\n };\n\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n return { success: false, error: `HTTP ${response.status}` };\n }\n\n const data = (await response.json()) as SendResultResponse;\n\n if (data.errcode !== 0) {\n return { success: false, error: data.errmsg ?? `Error code: ${data.errcode}` };\n }\n\n return {\n success: true,\n invalidUserIdList: data.send_result?.invalid_user_id_list,\n forbiddenUserIdList: data.send_result?.forbidden_user_id_list,\n failedUserIdList: data.send_result?.failed_user_id_list,\n readUserIdList: data.send_result?.read_user_id_list,\n unreadUserIdList: data.send_result?.unread_user_id_list,\n forbiddenList: data.send_result?.forbidden_list,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n static getForbiddenCodeInfo(code: string): { description: string; solution: string } | null {\n return getForbiddenCodeInfo(code);\n }\n}\n"
|
|
8
|
+
],
|
|
9
|
+
"mappings": "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",
|
|
10
|
+
"debugId": "7AFD9129F0A4FCB764756E2164756E21",
|
|
11
|
+
"names": []
|
|
12
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DingTalk credentials for API authentication
|
|
3
|
+
*/
|
|
4
|
+
export interface DingTalkCredentials {
|
|
5
|
+
/** DingTalk application AppKey */
|
|
6
|
+
appKey: string;
|
|
7
|
+
/** DingTalk application AppSecret */
|
|
8
|
+
appSecret: string;
|
|
9
|
+
/** DingTalk application AgentId */
|
|
10
|
+
agentId: string;
|
|
11
|
+
/** User ID to receive messages */
|
|
12
|
+
userId: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Options for configuring the DingTalk client
|
|
16
|
+
*/
|
|
17
|
+
export interface DingTalkOptions {
|
|
18
|
+
/**
|
|
19
|
+
* Direct credentials configuration
|
|
20
|
+
* Takes priority over credentialsPath
|
|
21
|
+
*/
|
|
22
|
+
credentials?: DingTalkCredentials;
|
|
23
|
+
/**
|
|
24
|
+
* Path to credentials JSON file
|
|
25
|
+
* File should contain: { appKey, appSecret, agentId, userId }
|
|
26
|
+
* @default undefined (uses environment variables)
|
|
27
|
+
*/
|
|
28
|
+
credentialsPath?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Directory to cache access tokens
|
|
31
|
+
* @default os.tmpdir() for safety
|
|
32
|
+
*/
|
|
33
|
+
tokenCacheDir?: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Internal token cache structure
|
|
37
|
+
*/
|
|
38
|
+
export interface TokenCache {
|
|
39
|
+
/** Cached access token */
|
|
40
|
+
accessToken: string;
|
|
41
|
+
/** Expiration timestamp in milliseconds */
|
|
42
|
+
expiresAt: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Result of sending a message
|
|
46
|
+
*/
|
|
47
|
+
export interface SendMessageResult {
|
|
48
|
+
/** Whether the message was sent successfully */
|
|
49
|
+
success: boolean;
|
|
50
|
+
/** Task ID for tracking message delivery (available on success) */
|
|
51
|
+
taskId?: string;
|
|
52
|
+
/** Error message (available on failure) */
|
|
53
|
+
error?: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Information about a forbidden/limited user
|
|
57
|
+
*/
|
|
58
|
+
export interface ForbiddenInfo {
|
|
59
|
+
/** Error code */
|
|
60
|
+
code: string;
|
|
61
|
+
/** Count of forbidden messages */
|
|
62
|
+
count: number;
|
|
63
|
+
/** User ID that was forbidden */
|
|
64
|
+
userid: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Result of querying message delivery status
|
|
68
|
+
*/
|
|
69
|
+
export interface SendResult {
|
|
70
|
+
/** Whether the query was successful */
|
|
71
|
+
success: boolean;
|
|
72
|
+
/** List of user IDs who read the message */
|
|
73
|
+
readUserIdList?: string[];
|
|
74
|
+
/** List of user IDs who haven't read the message */
|
|
75
|
+
unreadUserIdList?: string[];
|
|
76
|
+
/** List of user IDs for whom sending failed */
|
|
77
|
+
failedUserIdList?: string[];
|
|
78
|
+
/** List of invalid user IDs */
|
|
79
|
+
invalidUserIdList?: string[];
|
|
80
|
+
/** List of user IDs who were rate-limited */
|
|
81
|
+
forbiddenUserIdList?: string[];
|
|
82
|
+
/** Detailed forbidden information with error codes */
|
|
83
|
+
forbiddenList?: ForbiddenInfo[];
|
|
84
|
+
/** Error message (available on failure) */
|
|
85
|
+
error?: string;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Information about a DingTalk error code
|
|
89
|
+
*/
|
|
90
|
+
export interface ForbiddenCodeInfo {
|
|
91
|
+
/** Human-readable description of the error */
|
|
92
|
+
description: string;
|
|
93
|
+
/** Suggested solution for the error */
|
|
94
|
+
solution: string;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* DingTalk API response for token endpoint
|
|
98
|
+
*/
|
|
99
|
+
export interface TokenResponse {
|
|
100
|
+
errcode?: number;
|
|
101
|
+
errmsg?: string;
|
|
102
|
+
access_token?: string;
|
|
103
|
+
expires_in?: number;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* DingTalk API response for message sending
|
|
107
|
+
*/
|
|
108
|
+
export interface SendResponse {
|
|
109
|
+
errcode?: number;
|
|
110
|
+
errmsg?: string;
|
|
111
|
+
task_id?: number;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* DingTalk API response for message status query
|
|
115
|
+
*/
|
|
116
|
+
export interface SendResultResponse {
|
|
117
|
+
errcode?: number;
|
|
118
|
+
errmsg?: string;
|
|
119
|
+
send_result?: {
|
|
120
|
+
invalid_user_id_list?: string[];
|
|
121
|
+
forbidden_user_id_list?: string[];
|
|
122
|
+
failed_user_id_list?: string[];
|
|
123
|
+
read_user_id_list?: string[];
|
|
124
|
+
unread_user_id_list?: string[];
|
|
125
|
+
forbidden_list?: Array<{
|
|
126
|
+
code: string;
|
|
127
|
+
count: number;
|
|
128
|
+
userid: string;
|
|
129
|
+
}>;
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { DingTalkCredentials, DingTalkOptions, TokenCache } from './types.js';
|
|
2
|
+
export declare class TokenManager {
|
|
3
|
+
private cacheDir;
|
|
4
|
+
private cacheFile;
|
|
5
|
+
constructor(cacheDir?: string);
|
|
6
|
+
load(): TokenCache | null;
|
|
7
|
+
save(cache: TokenCache): void;
|
|
8
|
+
isValid(cache: TokenCache | null): cache is TokenCache;
|
|
9
|
+
}
|
|
10
|
+
export declare function loadCredentials(options?: DingTalkOptions): DingTalkCredentials;
|
|
11
|
+
export declare const FORBIDDEN_CODES: Record<string, {
|
|
12
|
+
description: string;
|
|
13
|
+
solution: string;
|
|
14
|
+
}>;
|
|
15
|
+
export declare function getForbiddenCodeInfo(code: string): {
|
|
16
|
+
description: string;
|
|
17
|
+
solution: string;
|
|
18
|
+
} | null;
|
|
19
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAUnF,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAS;gBAEd,QAAQ,CAAC,EAAE,MAAM;IAK7B,IAAI,IAAI,UAAU,GAAG,IAAI;IAYzB,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAW7B,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,GAAG,KAAK,IAAI,UAAU;CAGvD;AAED,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,mBAAmB,CAuB9E;AA4CD,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAiBrF,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAEnG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dingtalk-manager",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "DingTalk work notification API client for Node.js/Bun - send markdown and text messages",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md",
|
|
18
|
+
"LICENSE"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "bun run build:clean && bun run build:js && bun run build:types",
|
|
22
|
+
"build:clean": "rm -rf dist",
|
|
23
|
+
"build:js": "bun build ./src/index.ts --outdir ./dist --target node --format esm --sourcemap --external commander",
|
|
24
|
+
"build:types": "tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
25
|
+
"test": "bun test",
|
|
26
|
+
"test:watch": "bun test --watch",
|
|
27
|
+
"prepublishOnly": "bun run build && bun test",
|
|
28
|
+
"release": "bun run build && npm publish",
|
|
29
|
+
"release:dry": "npm publish --dry-run"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"dingtalk",
|
|
33
|
+
"钉钉",
|
|
34
|
+
"notification",
|
|
35
|
+
"work-notify",
|
|
36
|
+
"message",
|
|
37
|
+
"markdown"
|
|
38
|
+
],
|
|
39
|
+
"author": "buwai",
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "https://github.com/buwai/dingtalk-manager.git"
|
|
44
|
+
},
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/buwai/dingtalk-manager/issues"
|
|
47
|
+
},
|
|
48
|
+
"homepage": "https://github.com/buwai/dingtalk-manager#readme",
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=18.0.0"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@types/bun": "latest",
|
|
54
|
+
"typescript": "^5.3.0"
|
|
55
|
+
}
|
|
56
|
+
}
|