@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.
@@ -79,7 +79,7 @@ function makeCtx(extraServices) {
79
79
  return { ctx, routes }
80
80
  }
81
81
 
82
- test('config GET 返回解析后的默认配置,webhookUrl 凭据不出主机', async () => {
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.webhookConfigured, false)
91
- assert.equal('webhookUrl' in res.body, false)
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.webhookConfigured, true)
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.webhookConfigured, true)
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.webhookConfigured, true)
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.webhookConfigured, true)
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
- return {
25
- status: null,
26
- body: null,
27
- raw: null,
28
- headers: null,
29
- writeHead(status, headers) { this.status = status; this.headers = headers },
30
- end(body) {
31
- if (Buffer.isBuffer(body)) this.raw = body
32
- else if (typeof body === 'string' && (this.headers ? String(this.headers['content-type']) : '').includes('json')) this.body = JSON.parse(body)
33
- else this.raw = body
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) {