hik-iot-sdk 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.
Files changed (50) hide show
  1. package/README.md +467 -0
  2. package/dist/core/__tests__/crypto.test.d.ts +1 -0
  3. package/dist/core/__tests__/crypto.test.js +68 -0
  4. package/dist/core/auth.d.ts +51 -0
  5. package/dist/core/auth.js +292 -0
  6. package/dist/core/config.d.ts +31 -0
  7. package/dist/core/config.js +11 -0
  8. package/dist/core/crypto.d.ts +12 -0
  9. package/dist/core/crypto.js +88 -0
  10. package/dist/core/errors.d.ts +45 -0
  11. package/dist/core/errors.js +61 -0
  12. package/dist/core/http.d.ts +29 -0
  13. package/dist/core/http.js +134 -0
  14. package/dist/index.d.ts +8 -0
  15. package/dist/index.js +10 -0
  16. package/dist/modules/access/access.schema.d.ts +2307 -0
  17. package/dist/modules/access/access.schema.js +353 -0
  18. package/dist/modules/access/access.service.d.ts +55 -0
  19. package/dist/modules/access/access.service.js +145 -0
  20. package/dist/modules/access/access.types.d.ts +307 -0
  21. package/dist/modules/access/access.types.js +3 -0
  22. package/dist/modules/access/index.d.ts +2 -0
  23. package/dist/modules/access/index.js +20 -0
  24. package/dist/modules/card/card.schema.d.ts +27 -0
  25. package/dist/modules/card/card.schema.js +12 -0
  26. package/dist/modules/card/card.service.d.ts +10 -0
  27. package/dist/modules/card/card.service.js +50 -0
  28. package/dist/modules/card/card.types.d.ts +18 -0
  29. package/dist/modules/card/card.types.js +2 -0
  30. package/dist/modules/device/device.schema.d.ts +258 -0
  31. package/dist/modules/device/device.schema.js +44 -0
  32. package/dist/modules/device/device.service.d.ts +14 -0
  33. package/dist/modules/device/device.service.js +69 -0
  34. package/dist/modules/device/device.types.d.ts +46 -0
  35. package/dist/modules/device/device.types.js +2 -0
  36. package/dist/modules/face/face.schema.d.ts +27 -0
  37. package/dist/modules/face/face.schema.js +12 -0
  38. package/dist/modules/face/face.service.d.ts +9 -0
  39. package/dist/modules/face/face.service.js +42 -0
  40. package/dist/modules/face/face.types.d.ts +17 -0
  41. package/dist/modules/face/face.types.js +2 -0
  42. package/dist/modules/person/person.schema.d.ts +270 -0
  43. package/dist/modules/person/person.schema.js +42 -0
  44. package/dist/modules/person/person.service.d.ts +16 -0
  45. package/dist/modules/person/person.service.js +88 -0
  46. package/dist/modules/person/person.types.d.ts +65 -0
  47. package/dist/modules/person/person.types.js +2 -0
  48. package/dist/sdk.d.ts +60 -0
  49. package/dist/sdk.js +106 -0
  50. package/package.json +29 -0
package/README.md ADDED
@@ -0,0 +1,467 @@
1
+ # 海康互联 IoT SDK
2
+
3
+ 海康互联开放平台 Node.js TypeScript SDK,提供门禁设备的人员、人脸、卡片管理及远程控门等功能。
4
+
5
+ ## 特性
6
+
7
+ - **强类型** - 完整的 TypeScript 类型定义
8
+ - **自动鉴权** - 自动管理 access_token,无需手动处理
9
+ - **自动重试** - Token 过期自动刷新并重试请求
10
+ - **数据校验** - 使用 zod 对所有 API 返回值进行校验
11
+ - **业务模型** - 面向业务模型设计,而非 HTTP 接口
12
+ - **日志支持** - 使用 pino 进行日志记录
13
+
14
+ ## 安装
15
+
16
+ ```bash
17
+ npm install @qiang9996/hik-iot-sdk
18
+ ```
19
+
20
+ ## 快速开始
21
+
22
+ ```typescript
23
+ import { HikSdk } from '@qiang9996/hik-iot-sdk';
24
+
25
+ const sdk = new HikSdk({
26
+ appKey: 'your-app-key',
27
+ appSecret: 'your-app-secret',
28
+ userName: 'your-phone-number', // 登录手机号
29
+ password: 'your-password', // 登录密码
30
+ });
31
+
32
+ // 一键创建人员并绑定人脸和卡片
33
+ const result = await sdk.createPersonWithFaceAndCard({
34
+ deviceSerial: 'your-device-serial',
35
+ employeeNo: 'EMP001',
36
+ name: '张三',
37
+ faceURL: 'https://example.com/face.jpg',
38
+ cardNo: '12345678',
39
+ permanentValid: true,
40
+ });
41
+
42
+ // 远程开门
43
+ await sdk.device.openDoor('your-device-serial');
44
+ ```
45
+
46
+ ## API 文档
47
+
48
+ ### 初始化
49
+
50
+ ```typescript
51
+ const sdk = new HikSdk({
52
+ appKey: string; // 应用 AppKey
53
+ appSecret: string; // 应用 AppSecret
54
+ userName: string; // 登录手机号
55
+ password: string; // 登录密码
56
+ redirectUrl?: string; // 重定向回调地址(可选,需在应用安全设置中配置)
57
+ baseUrl?: string; // API 基础地址(默认:https://open-api.hikiot.com)
58
+ timeout?: number; // 请求超时时间(默认:30000ms)
59
+ });
60
+
61
+ // 获取当前登录用户信息
62
+ const userInfo = sdk.getUserInfo();
63
+ // { teamNo: '团队编号', personNo: '成员编号', accountNo: '账号' }
64
+ ```
65
+
66
+ ### 人员管理 (sdk.person)
67
+
68
+ ```typescript
69
+ // 添加/更新人员
70
+ await sdk.person.create({
71
+ deviceSerial: 'device-serial',
72
+ employeeNo: 'EMP001',
73
+ name: '张三',
74
+ userType: 'normal', // normal | visitor | blackList
75
+ permanentValid: true, // 是否永久有效
76
+ enableBeginTime: '2024-01-01T00:00:00',
77
+ enableEndTime: '2037-12-31T23:59:59',
78
+ doorRight: [1], // 门权限
79
+ doorRightPlan: [{ doorNo: 1, planTemplateId: [1] }],
80
+ password: '123456', // 开门密码(可选)
81
+ });
82
+
83
+ // 删除人员
84
+ await sdk.person.delete({
85
+ deviceSerial: 'device-serial',
86
+ employeeNo: 'EMP001',
87
+ });
88
+
89
+ // 批量删除人员
90
+ await sdk.person.batchDelete({
91
+ deviceSerial: 'device-serial',
92
+ employeeNos: ['EMP001', 'EMP002'],
93
+ });
94
+
95
+ // 查询人员
96
+ const result = await sdk.person.search({
97
+ deviceSerial: 'device-serial',
98
+ keyword: 'EMP001',
99
+ page: 1,
100
+ size: 20,
101
+ });
102
+
103
+ // 获取单个人员
104
+ const person = await sdk.person.get('device-serial', 'EMP001');
105
+ ```
106
+
107
+ ### 人脸管理 (sdk.face)
108
+
109
+ ```typescript
110
+ // 添加/更新人脸
111
+ await sdk.face.add({
112
+ deviceSerial: 'device-serial',
113
+ employeeNo: 'EMP001',
114
+ faceURL: 'https://example.com/face.jpg', // 图片需小于200KB
115
+ });
116
+
117
+ // 删除人脸
118
+ await sdk.face.delete({
119
+ deviceSerial: 'device-serial',
120
+ employeeNo: 'EMP001',
121
+ });
122
+ ```
123
+
124
+ ### 卡片管理 (sdk.card)
125
+
126
+ ```typescript
127
+ // 添加/更新卡片
128
+ await sdk.card.add({
129
+ deviceSerial: 'device-serial',
130
+ employeeNo: 'EMP001',
131
+ cardNo: '12345678',
132
+ cardType: 'normalCard', // normalCard | hijackCard | superCard | ...
133
+ });
134
+
135
+ // 删除卡片
136
+ await sdk.card.delete({
137
+ deviceSerial: 'device-serial',
138
+ cardNo: '12345678',
139
+ });
140
+
141
+ // 批量删除卡片
142
+ await sdk.card.batchDelete({
143
+ deviceSerial: 'device-serial',
144
+ cardNos: ['12345678', '87654321'],
145
+ });
146
+ ```
147
+
148
+ ### 设备管理 (sdk.device)
149
+
150
+ ```typescript
151
+ // 远程开门
152
+ await sdk.device.openDoor('device-serial', 1);
153
+
154
+ // 远程关门(受控)
155
+ await sdk.device.closeDoor('device-serial', 1);
156
+
157
+ // 设置常开
158
+ await sdk.device.setDoorAlwaysOpen('device-serial', 1);
159
+
160
+ // 设置常闭
161
+ await sdk.device.setDoorAlwaysClose('device-serial', 1);
162
+
163
+ // 查询门控状态
164
+ const status = await sdk.device.getDoorStatus({
165
+ deviceSerial: 'device-serial',
166
+ });
167
+
168
+ // 查询设备容量
169
+ const storage = await sdk.device.getStorageCount({
170
+ deviceSerial: 'device-serial',
171
+ });
172
+
173
+ // 清空设备数据
174
+ await sdk.device.clearStorage({
175
+ deviceSerial: 'device-serial',
176
+ opts: ['supportUserInfo', 'supportCardInfo'],
177
+ });
178
+ ```
179
+
180
+ ### 门禁应用 API (sdk.access)
181
+
182
+ 门禁应用 API 提供基于 SaaS 应用层面的权限管理,与硬件设备 API 互补。
183
+
184
+ ```typescript
185
+ // ============ 权限配置 ============
186
+ // 添加权限配置
187
+ const authorityConfigId = await sdk.access.addAuthorityConfig({
188
+ personNo: 'ZHAxxxx',
189
+ timePlanIds: ['1'],
190
+ deviceGroupNo: 'SBZ001',
191
+ password: '123456',
192
+ dynamicCode: false,
193
+ });
194
+
195
+ // 查询权限配置列表
196
+ const configs = await sdk.access.getAuthorityConfigPage('__UNI__E32B021', 1, 20);
197
+
198
+ // 查询权限配置详情
199
+ const config = await sdk.access.getAuthorityConfigDetail(authorityConfigId);
200
+
201
+ // 删除权限配置
202
+ await sdk.access.deleteAuthorityConfig(authorityConfigId);
203
+
204
+ // ============ 设备分组 ============
205
+ // 查询设备分组
206
+ const groups = await sdk.access.getDeviceGroupPage(1, 20);
207
+
208
+ // 创建设备分组
209
+ await sdk.access.saveDeviceGroup({
210
+ deviceGroupName: '一楼门禁',
211
+ deviceGroupType: 1,
212
+ deviceSerials: ['L12345678'],
213
+ });
214
+
215
+ // ============ 通行权限查询 ============
216
+ // 查询人员与设备权限关系
217
+ const personDevices = await sdk.access.getPersonDevicePage({
218
+ personName: '张三',
219
+ page: 1,
220
+ size: 20,
221
+ });
222
+
223
+ // 查询未下发信息
224
+ const waitIssue = await sdk.access.getWaitIssueInfo('L12345678');
225
+
226
+ // 查询临时密码列表
227
+ const passwords = await sdk.access.listPassword();
228
+
229
+ // ============ 下发操作 ============
230
+ // 手动下发
231
+ await sdk.access.manualIssue({ deviceSerials: ['L12345678'] });
232
+
233
+ // 选择下发
234
+ await sdk.access.selectIssue({ issueNos: ['issue-no-1'] });
235
+
236
+ // 覆盖下发
237
+ await sdk.access.coverIssue({});
238
+
239
+ // ============ 开门记录 ============
240
+ // 查询开门记录
241
+ const events = await sdk.access.getAccessEventPage({
242
+ startDate: '2024-01-01 00:00:00',
243
+ endDate: '2024-12-31 23:59:59',
244
+ deviceSerials: ['L12345678'],
245
+ page: 1,
246
+ size: 20,
247
+ });
248
+
249
+ // 查询开门记录详情
250
+ const eventDetail = await sdk.access.getAccessEventDetail('origin-id');
251
+
252
+ // 获取认证图片 URL
253
+ const picUrl = await sdk.access.getAuthPicUrl({ originId: 'origin-id', deviceSerial: 'L12345678' });
254
+
255
+ // 远程开门(应用层面)
256
+ await sdk.access.remoteOpenDoor('L12345678');
257
+
258
+ // ============ 时间计划 ============
259
+ // 查询时间计划列表
260
+ const timePlans = await sdk.access.getTimePlanList();
261
+
262
+ // 查询时间计划详情
263
+ const timePlan = await sdk.access.getTimePlanDetail(1);
264
+
265
+ // 添加时间计划
266
+ await sdk.access.addTimePlan({ timePlanName: '工作日', timePlanType: 1 });
267
+
268
+ // 删除时间计划
269
+ await sdk.access.deleteTimePlan(1);
270
+
271
+ // ============ 节假日组 ============
272
+ // 查询节假日组列表
273
+ const holidays = await sdk.access.getHolidayGroupList();
274
+
275
+ // 添加节假日组
276
+ await sdk.access.addHolidayGroup({ holidayGroupName: '春节', holidayGroupDetail: [...] });
277
+ ```
278
+
279
+ ### 便捷方法
280
+
281
+ ```typescript
282
+ // 一键创建人员并绑定人脸
283
+ const result = await sdk.createPersonWithFace({
284
+ deviceSerial: 'device-serial',
285
+ employeeNo: 'EMP001',
286
+ name: '张三',
287
+ faceURL: 'https://example.com/face.jpg',
288
+ });
289
+
290
+ // 一键创建人员并绑定人脸和卡片
291
+ const result = await sdk.createPersonWithFaceAndCard({
292
+ deviceSerial: 'device-serial',
293
+ employeeNo: 'EMP001',
294
+ name: '张三',
295
+ faceURL: 'https://example.com/face.jpg',
296
+ cardNo: '12345678',
297
+ });
298
+
299
+ // 完整删除人员(包括人脸)
300
+ await sdk.deletePersonComplete('device-serial', 'EMP001');
301
+ ```
302
+
303
+ ## 远程核验事件服务
304
+
305
+ SDK 提供了远程核验事件处理示例,用于接收海康互联平台推送的 `DoorRemoteCheck` 事件,并根据白名单决定是否放行。
306
+
307
+ ```bash
308
+ # 运行远程核验事件服务
309
+ npx tsx examples/mock.ts
310
+ ```
311
+
312
+ 服务默认监听 `8080` 端口,接收加密事件回调并自动解密。需要在海康互联开放平台配置:
313
+
314
+ 1. **事件订阅** → 添加 `门禁远程核验` 事件
315
+ 2. **加密策略** → 配置 `Encrypt Key` 和 `Verification Token`
316
+ 3. **回调地址** → 设置为服务的公网地址(如 `https://your-domain/callback`)
317
+
318
+ 环境变量配置:
319
+
320
+ ```bash
321
+ export HIK_APP_KEY="your-app-key"
322
+ export HIK_APP_SECRET="your-app-secret"
323
+ export HIK_USER_NAME="your-phone-number"
324
+ export HIK_PASSWORD="your-password"
325
+ export HIK_ENCRYPT_KEY="your-encrypt-key" # 事件解密用
326
+ export HIK_VERIFICATION_TOKEN="your-token" # 事件验证用
327
+ ```
328
+
329
+ ## 错误处理
330
+
331
+ ```typescript
332
+ import { HikError, HikDeviceError, HikAuthError, ERROR_CODES } from '@qiang9996/hik-iot-sdk';
333
+
334
+ try {
335
+ await sdk.person.create({ ... });
336
+ } catch (error) {
337
+ if (error instanceof HikDeviceError) {
338
+ // 设备相关错误 (160xxx)
339
+ console.error('设备错误:', error.code, error.message, error.detail);
340
+ } else if (error instanceof HikAuthError) {
341
+ // 认证错误
342
+ console.error('认证错误:', error.message);
343
+ } else if (error instanceof HikError) {
344
+ // 其他 API 错误
345
+ console.error('API错误:', error.code, error.message);
346
+ }
347
+ }
348
+ ```
349
+
350
+ ### 常见错误码
351
+
352
+ | 错误码 | 说明 |
353
+ |--------|------|
354
+ | 0 | 操作成功 |
355
+ | 400015 | AppAccessToken 无效 |
356
+ | 400019 | UserAccessToken 无效 |
357
+ | 160001 | 设备不存在 |
358
+ | 160101 | 设备离线 |
359
+ | 160102 | 设备超时 |
360
+ | 160104 | 设备不支持该功能 |
361
+ | 160112 | 人员已被删除 |
362
+ | 160116 | 人员数量已达上限 |
363
+ | 160117 | 照片未检测到人脸 |
364
+
365
+ ## 示例说明
366
+
367
+ `examples/` 目录提供了多种使用示例:
368
+
369
+ | 示例文件 | 说明 |
370
+ |---------|------|
371
+ | `demo.ts` | 综合交互式示例,支持菜单选择运行门禁应用 API、人员管理或设备控制示例 |
372
+ | `quick-start.ts` | 最简快速开始示例,展示一键创建人员并绑定人脸和卡片 |
373
+ | `face-access-demo.ts` | 人脸与门禁设备管理示例 |
374
+ | `access-demo.ts` | 门禁应用 API 示例 |
375
+ | `mock.ts` | 远程核验事件 Web 服务示例,接收海康事件回调并处理 |
376
+
377
+ 运行示例:
378
+
379
+ ```bash
380
+ # 设置环境变量
381
+ export HIK_APP_KEY="your-app-key"
382
+ export HIK_APP_SECRET="your-app-secret"
383
+ export HIK_USER_NAME="your-phone-number"
384
+ export HIK_PASSWORD="your-password"
385
+ export HIK_DEVICE_SERIAL="your-device-serial"
386
+
387
+ # 运行综合示例(交互式菜单)
388
+ npx tsx examples/demo.ts
389
+
390
+ # 直接运行指定示例
391
+ npx tsx examples/demo.ts 1 # 门禁应用 API
392
+ npx tsx examples/demo.ts 2 # 人员/人脸/卡片管理
393
+ npx tsx examples/demo.ts 3 # 设备控制
394
+
395
+ # 运行远程核验服务
396
+ npx tsx examples/mock.ts
397
+ ```
398
+
399
+ ## 数据加密
400
+
401
+ 海康互联开放平台默认开启数据加密,SDK 会自动处理请求加密和响应解密:
402
+
403
+ - **API 请求/响应加密**:使用 RSA 私钥(App Secret)加密,SDK 自动处理
404
+ - **事件订阅加密**:使用 AES-256-CBC 加密,需配置 `Encrypt Key`
405
+
406
+ 如需关闭加密(不推荐),可在初始化时设置:
407
+
408
+ ```typescript
409
+ const sdk = new HikSdk({
410
+ appKey: 'your-app-key',
411
+ appSecret: 'your-app-secret',
412
+ userName: 'your-phone-number',
413
+ password: 'your-password',
414
+ enableEncrypt: false, // 关闭加密
415
+ });
416
+ ```
417
+
418
+ ## 项目结构
419
+
420
+ ```
421
+ src/
422
+ ├── core/ # 核心模块
423
+ │ ├── auth.ts # 认证管理(App/User Token)
424
+ │ ├── config.ts # 配置校验
425
+ │ ├── crypto.ts # RSA 加密/解密
426
+ │ ├── http.ts # HTTP 客户端
427
+ │ └── logger.ts # 日志
428
+ ├── modules/ # 业务模块
429
+ │ ├── access/ # 门禁应用 API
430
+ │ ├── card/ # 卡片管理
431
+ │ ├── device/ # 设备控制
432
+ │ ├── face/ # 人脸管理
433
+ │ └── person/ # 人员管理
434
+ ├── sdk.ts # SDK 主类
435
+ └── index.ts # 入口导出
436
+
437
+ examples/ # 示例代码
438
+ ├── demo.ts # 综合示例
439
+ ├── quick-start.ts # 快速开始
440
+ ├── mock.ts # 远程核验服务
441
+ ├── access-demo.ts # 门禁应用示例
442
+ └── face-access-demo.ts # 人脸设备示例
443
+ ```
444
+
445
+ ## 开发
446
+
447
+ ```bash
448
+ # 安装依赖
449
+ npm install
450
+
451
+ # 构建
452
+ npm run build
453
+
454
+ # 运行测试
455
+ npm test
456
+
457
+ # 接收远程核验事件
458
+ npx tsx examples/mock.ts
459
+
460
+ #运行demo
461
+ npx tsx examples/demo.ts 2
462
+
463
+ ```
464
+
465
+ ## License
466
+
467
+ MIT
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const crypto_1 = require("../crypto");
5
+ (0, vitest_1.describe)('HikCrypto', () => {
6
+ let crypto;
7
+ // 使用文档中的真实 appSecret
8
+ const testAppSecret = `MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKhhvUQyZg5VcFSgle2NI7tJ3YLsYjY4fRbWMoHJKqrq692esYYdqqhERvYbbW/X0ns2QKr1vNHcEXM709VoUX+X6cnTu/5ANDSbRAjWo+L+f1KFu0z82bpX2hSwLEGyj6qJvXcFgYlKu3RxO7b4SKVhuxa06mkoY62AnbP7k8ajAgMBAAECgYBJnADLkWTAG2Wx+UnRwYO/Wnk1xPTiUyuMEjOePT0j3vMhvUBKKynxyXdkG3VqEWV4a601j5vt+lC+mYbvol0NvtsVUAnp+f9ca036pJHbds4MTciwjKOcwJW9aGNEUFZak+SmGS3BFnWo2prNIHHJ0v4UcS2LwlrnD+65rmMaoQJBANUHmXMkma99mGrSf381yIsf4DaAGmAKT+UC1Uxo9TEGZWqYbykeXfiwoSaUUxaTspV0BQhIC68c5D7CFsU1vasCQQDKWJ4cuYs9FWlJfrCd4/GFP4BbhHussiqqbsG9E0znFx7kyQyrcL+qHv1kmv19CDlmEzZ+tMyqxdpn45HxnHLpAkBAbbz2OxKUJessG5/d7HlLwodAVHwlodjKDZJPOss1WZbgp1uvVvTa2yjSDzgV8vOnCeDfwVJvUtChPng+iuNjAkAHCh42EZ5ueZg4Hlg2pf95C0SD6pAC6g/h7gh/c3RxdbR1cSknrbx9Rqa6IUpAV1Dn5DM5JUEZj9iRVLF3HmJBAkAEhbazySPeyVvFqXMm9ST1JiGaYozZzqQXCR15DKFB6olpDIGtSXxTvMkhuwgE61G8m4rnpkLi7elVZAbtsifU`;
9
+ (0, vitest_1.beforeEach)(() => {
10
+ crypto = new crypto_1.HikCrypto(testAppSecret);
11
+ });
12
+ (0, vitest_1.it)('should format PKCS#1 private key correctly', () => {
13
+ crypto = new crypto_1.HikCrypto(testAppSecret);
14
+ console.log('✓ HikCrypto 实例化成功');
15
+ (0, vitest_1.expect)(crypto).toBeDefined();
16
+ });
17
+ (0, vitest_1.it)('should encrypt simple string', () => {
18
+ const plaintext = 'test data';
19
+ const encrypted = crypto.encrypt(plaintext);
20
+ console.log('明文:', plaintext);
21
+ console.log('密文:', encrypted.substring(0, 50) + '...');
22
+ (0, vitest_1.expect)(encrypted).toBeDefined();
23
+ (0, vitest_1.expect)(typeof encrypted).toBe('string');
24
+ (0, vitest_1.expect)(encrypted.length).toBeGreaterThan(0);
25
+ });
26
+ (0, vitest_1.it)('should encrypt and decrypt correctly', () => {
27
+ const plaintext = 'test data';
28
+ const encrypted = crypto.encrypt(plaintext);
29
+ const decrypted = crypto.decrypt(encrypted);
30
+ console.log('原文:', plaintext);
31
+ console.log('解密后:', decrypted);
32
+ (0, vitest_1.expect)(decrypted).toBe(plaintext);
33
+ });
34
+ (0, vitest_1.it)('should encrypt JSON body', () => {
35
+ const body = {
36
+ deviceSerial: 'L12345678',
37
+ employeeNo: 'EMP001',
38
+ name: '张三'
39
+ };
40
+ const result = crypto.encryptBody(body);
41
+ console.log('要加密的对象:', body);
42
+ console.log('加密结果:', result.bodySecret.substring(0, 50) + '...');
43
+ (0, vitest_1.expect)(result).toHaveProperty('bodySecret');
44
+ (0, vitest_1.expect)(result.bodySecret).toBeDefined();
45
+ (0, vitest_1.expect)(typeof result.bodySecret).toBe('string');
46
+ });
47
+ (0, vitest_1.it)('should encrypt query params', () => {
48
+ const params = {
49
+ deviceSerial: 'L12345678',
50
+ page: 1,
51
+ size: 20
52
+ };
53
+ const result = crypto.encryptParams(params);
54
+ console.log('要加密的参数:', params);
55
+ console.log('加密结果:', result.substring(0, 50) + '...');
56
+ (0, vitest_1.expect)(result).toBeDefined();
57
+ (0, vitest_1.expect)(typeof result).toBe('string');
58
+ });
59
+ (0, vitest_1.it)('should handle long data with chunking', () => {
60
+ // 测试分块加密:超过 117 字节的数据
61
+ const longText = 'a'.repeat(300);
62
+ const encrypted = crypto.encrypt(longText);
63
+ const decrypted = crypto.decrypt(encrypted);
64
+ console.log('长度:', longText.length);
65
+ console.log('分块加密成功');
66
+ (0, vitest_1.expect)(decrypted).toBe(longText);
67
+ });
68
+ });
@@ -0,0 +1,51 @@
1
+ import type { HikConfig } from './config';
2
+ export interface AppTokenInfo {
3
+ appAccessToken: string;
4
+ refreshAppToken: string;
5
+ expiresAt: number;
6
+ }
7
+ export interface UserTokenInfo {
8
+ userAccessToken: string;
9
+ refreshUserToken: string;
10
+ expiresAt: number;
11
+ teamNo: string;
12
+ personNo: string;
13
+ accountNo: string;
14
+ }
15
+ export interface UserCredentials {
16
+ userName: string;
17
+ password: string;
18
+ redirectUrl: string;
19
+ }
20
+ export declare class AuthManager {
21
+ private readonly config;
22
+ private readonly httpClient;
23
+ private readonly userCredentials;
24
+ private readonly crypto;
25
+ private appTokenInfo;
26
+ private userTokenInfo;
27
+ private appTokenPromise;
28
+ private userTokenPromise;
29
+ constructor(config: HikConfig, userCredentials: UserCredentials);
30
+ private encryptBody;
31
+ private decryptResponse;
32
+ getUserAccessToken(): Promise<string>;
33
+ private isUserTokenValid;
34
+ getAppAccessToken(): Promise<string>;
35
+ private isAppTokenValid;
36
+ private shouldRefreshAppToken;
37
+ private fetchNewAppToken;
38
+ private doFetchAppToken;
39
+ private refreshAppToken;
40
+ private doRefreshAppToken;
41
+ private fetchUserToken;
42
+ private doFetchUserToken;
43
+ private applyAuthCode;
44
+ clearAppToken(): void;
45
+ clearUserToken(): void;
46
+ getUserInfo(): {
47
+ teamNo: string;
48
+ personNo: string;
49
+ accountNo: string;
50
+ } | null;
51
+ }