@mzzsfy/dsh-turn-notify 0.8.1 → 0.10.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/README.md +22 -10
- package/package.json +2 -2
- package/src/client.js +47 -19
- package/src/core.mjs +117 -5
- package/src/index.js +92 -7
- package/test/core.test.mjs +12 -5
- package/test/event-wiring.test.mjs +7 -6
- package/test/host-notify.test.mjs +593 -0
- package/test/route.test.mjs +25 -7
- package/test/sounds.route.test.mjs +12 -11
package/test/route.test.mjs
CHANGED
|
@@ -79,7 +79,7 @@ function makeCtx(extraServices) {
|
|
|
79
79
|
return { ctx, routes }
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
test('config GET 返回解析后的默认配置,webhookUrl
|
|
82
|
+
test('config GET 返回解析后的默认配置,webhookUrl 原文回显', async () => {
|
|
83
83
|
const { ctx, routes } = makeCtx()
|
|
84
84
|
apply(ctx)
|
|
85
85
|
const handler = routes.get('/api/turn-notify/config')
|
|
@@ -87,8 +87,8 @@ test('config GET 返回解析后的默认配置,webhookUrl 凭据不出主机',
|
|
|
87
87
|
const res = makeRes()
|
|
88
88
|
await handler(makeReq('GET'), res)
|
|
89
89
|
assert.equal(res.status, 200)
|
|
90
|
-
assert.equal(res.body.
|
|
91
|
-
assert.equal('
|
|
90
|
+
assert.equal(res.body.webhookUrl, '')
|
|
91
|
+
assert.equal('webhookConfigured' in res.body, false)
|
|
92
92
|
assert.equal(res.body.minTurnDurationMs, MIN_TURN_MS)
|
|
93
93
|
assert.equal(res.body.rootsOnly, true)
|
|
94
94
|
assert.equal(res.body.enabled.completed, true)
|
|
@@ -105,12 +105,30 @@ test('config POST 非法补丁 400,合法补丁持久化且部分开关不覆盖
|
|
|
105
105
|
const good = makeRes()
|
|
106
106
|
await handler(makeReq('POST', { webhookUrl: 'https://hook.example', enabled: { completed: false } }, JSON_HEADERS), good)
|
|
107
107
|
assert.equal(good.status, 200)
|
|
108
|
-
assert.equal(good.body.
|
|
108
|
+
assert.equal(good.body.webhookUrl, 'https://hook.example')
|
|
109
109
|
assert.equal(good.body.enabled.completed, false)
|
|
110
110
|
assert.equal(good.body.enabled.error, true)
|
|
111
111
|
const readback = makeRes()
|
|
112
112
|
await handler(makeReq('GET'), readback)
|
|
113
|
-
assert.equal(readback.body.
|
|
113
|
+
assert.equal(readback.body.webhookUrl, 'https://hook.example')
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
test('config POST 空串清空 webhookUrl:先存后清双向回环,清后通道禁用', async () => {
|
|
117
|
+
const { ctx, routes } = makeCtx()
|
|
118
|
+
apply(ctx)
|
|
119
|
+
const handler = routes.get('/api/turn-notify/config')
|
|
120
|
+
const save = makeRes()
|
|
121
|
+
await handler(makeReq('POST', { webhookUrl: 'https://hook.example/x' }, JSON_HEADERS), save)
|
|
122
|
+
assert.equal(save.status, 200)
|
|
123
|
+
assert.equal(save.body.webhookUrl, 'https://hook.example/x')
|
|
124
|
+
// 清空并保存=禁用:空串经校验落库,回读为空串而非回退旧值
|
|
125
|
+
const clear = makeRes()
|
|
126
|
+
await handler(makeReq('POST', { webhookUrl: '' }, JSON_HEADERS), clear)
|
|
127
|
+
assert.equal(clear.status, 200)
|
|
128
|
+
assert.equal(clear.body.webhookUrl, '')
|
|
129
|
+
const readback = makeRes()
|
|
130
|
+
await handler(makeReq('GET'), readback)
|
|
131
|
+
assert.equal(readback.body.webhookUrl, '')
|
|
114
132
|
})
|
|
115
133
|
|
|
116
134
|
test('config POST 负路径:跨源 403,非 JSON 400,畸形体 400,空补丁 200', async () => {
|
|
@@ -228,7 +246,7 @@ test('config POST 仅 imTargets 的部分补丁:不触碰其他配置项,响应
|
|
|
228
246
|
const res = makeRes()
|
|
229
247
|
await handler(makeReq('POST', { imTargets: [{ botId: 'wx_a', targetId: 'owner' }, { botId: 'wx_b', targetId: 'owner' }] }, JSON_HEADERS), res)
|
|
230
248
|
assert.equal(res.status, 200)
|
|
231
|
-
assert.equal(res.body.
|
|
249
|
+
assert.equal(res.body.webhookUrl, 'https://hooks.example.com/x')
|
|
232
250
|
assert.equal(res.body.enabled.completed, false)
|
|
233
251
|
assert.deepEqual(res.body.imTargets, [{ botId: 'wx_a', targetId: 'owner' }, { botId: 'wx_b', targetId: 'owner' }])
|
|
234
252
|
// 取消注册:整列表替换为空,其余配置仍原样
|
|
@@ -236,7 +254,7 @@ test('config POST 仅 imTargets 的部分补丁:不触碰其他配置项,响应
|
|
|
236
254
|
await handler(makeReq('POST', { imTargets: [] }, JSON_HEADERS), clear)
|
|
237
255
|
assert.equal(clear.status, 200)
|
|
238
256
|
assert.deepEqual(clear.body.imTargets, [])
|
|
239
|
-
assert.equal(clear.body.
|
|
257
|
+
assert.equal(clear.body.webhookUrl, 'https://hooks.example.com/x')
|
|
240
258
|
assert.equal(clear.body.enabled.completed, false)
|
|
241
259
|
})
|
|
242
260
|
|
|
@@ -20,19 +20,20 @@ const soundsDir = join(homeRoot, '.dsh', 'dsh-turn-notify', 'sounds')
|
|
|
20
20
|
const JSON_HEADERS = { 'content-type': 'application/json' }
|
|
21
21
|
const WAV_BYTES = Buffer.from([1, 2, 3, 4])
|
|
22
22
|
|
|
23
|
+
// res 桩带事件能力:投影处理器挂 close 事件感知断连,桩须支持 once
|
|
23
24
|
function makeRes() {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
},
|
|
25
|
+
const res = new EventEmitter()
|
|
26
|
+
res.status = null
|
|
27
|
+
res.body = null
|
|
28
|
+
res.raw = null
|
|
29
|
+
res.headers = null
|
|
30
|
+
res.writeHead = (status, headers) => { res.status = status; res.headers = headers }
|
|
31
|
+
res.end = (body) => {
|
|
32
|
+
if (Buffer.isBuffer(body)) res.raw = body
|
|
33
|
+
else if (typeof body === 'string' && (res.headers ? String(res.headers['content-type']) : '').includes('json')) res.body = JSON.parse(body)
|
|
34
|
+
else res.raw = body
|
|
35
35
|
}
|
|
36
|
+
return res
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
function makeReq(method, payload, headers, url) {
|