import assert from 'node:assert/strict'; import { buildApp } from '../dist/app.js'; import { signAccessToken } from '../dist/auth/jwt.js'; import { DeviceControlError, DeviceControlService } from '../dist/devices/device-control-service.js'; const managerAccess = { roles: ['STORE_ADMIN'], capabilities: ['device.read', 'device.write'], storeIds: ['11'] }; const issued = []; const service = new DeviceControlService({ async execute(sql) { if (sql.includes('FROM qipai_devices')) { return [[{ id: 51, deviceId: 'BOX_001', storeId: 11, roomId: 31, deviceType: 'CONTROL_BOX', status: 'ONLINE' }], []]; } return [[], []]; } }, { async issue(input) { const payload = input.payloadFactory('1782120000001'); issued.push({ ...input, payload }); return { commandId: '1782120000001', status: 'PUBLISHED' }; } }); const context = { tenantId: '7', storeId: '11', roomId: '31', traceId: 'trace', access: managerAccess }; await service.controlPower(context, { slot1: 'on', slot3: 'off' }); assert.equal(issued.at(-1).payload.action, 'ConctolPower'); await service.controlDoor(context, { order: 'open', holdopen: 1, delayTime: 4 }); assert.equal(issued.at(-1).payload.action, 'Crldoor'); await service.playTts(context, { content: '欢迎光临' }); assert.equal(issued.at(-1).payload.action, 'PlayTTS'); await service.stopTts(context); assert.equal(issued.at(-1).payload.action, 'stopTTS'); await service.controlLed(context, 30); assert.equal(issued.at(-1).payload.action, 'CrlLED'); await service.startTask(context, { minute: 120, type: 2, subID: 'SUB001' }); assert.equal(issued.at(-1).payload.action, 'task'); await service.extendTask(context, 30); assert.equal(issued.at(-1).payload.action, 'addtask'); await service.cancelTask(context); assert.equal(issued.at(-1).payload.action, 'canceltask'); await service.pairSubLock(context, 60); assert.equal(issued.at(-1).payload.action, 'AddDevice'); await service.controlSubLock(context, { subID: 'SUB001', order: 'open', delayTime: 4 }); assert.equal(issued.at(-1).payload.action, 'CtrlDevice'); await assert.rejects( () => service.controlSubLock(context, { subID: 'SUB001', order: 'factoryreset', dangerConfirmation: 'CONFIRM_FACTORY_RESET' }), (error) => error instanceof DeviceControlError && error.code === 'DEVICE_DANGEROUS_ACTION_FORBIDDEN' ); const platformContext = { ...context, access: { roles: ['PLATFORM_ADMIN'], capabilities: [], storeIds: [] } }; await service.controlSubLock(platformContext, { subID: 'SUB001', order: 'factoryreset', dangerConfirmation: 'CONFIRM_FACTORY_RESET' }); assert.equal(issued.at(-1).payload.order, 'factoryreset'); assert.equal('dangerConfirmation' in issued.at(-1).payload, false); await assert.rejects( () => service.controlPower({ ...context, access: { roles: ['STAFF'], capabilities: ['device.write'], storeIds: ['12'] } }, { slot1: 'on' }), (error) => error.code === 'DEVICE_SCOPE_FORBIDDEN' ); const secret = 'test-only-jwt-secret-with-at-least-32-characters'; const token = signAccessToken({ sub: '22', sid: '5c4d3af8-c63c-4edb-bf95-b84127bb3f6e', tid: '7', aid: '9', rv: 1 }, secret, 900); let routed; const app = await buildApp({ deviceControl: { jwtSecret: secret, authRepository: { async validateSession() { return { id: '5c4d3af8-c63c-4edb-bf95-b84127bb3f6e', tenantId: '7', platformAppId: '9', expiresAt: new Date(Date.now() + 60000), user: { id: '22', tenantId: '7', userType: 'STAFF', status: 'ACTIVE', roleVersion: 1, nickname: '', avatarUrl: '', phone: '' } }; } }, accessControl: { async getAccessProfile() { return managerAccess; } }, service: { async controlPower(_context, input) { routed = input; return { status: 'PUBLISHED' }; }, async controlDoor() { return {}; }, async playTts() { return {}; }, async stopTts() { return {}; }, async controlLed() { return {}; }, async startTask() { return {}; }, async extendTask() { return {}; }, async cancelTask() { return {}; }, async pairSubLock() { return {}; }, async controlSubLock() { return {}; } } } }); const response = await app.inject({ method: 'POST', url: '/admin-api/device-control/power', headers: { authorization: `Bearer ${token}` }, payload: { storeId: '11', roomId: '31', slot1: 'on' } }); assert.equal(response.statusCode, 200); assert.equal(routed.slot1, 'on'); const invalid = await app.inject({ method: 'POST', url: '/admin-api/device-control/door', headers: { authorization: `Bearer ${token}` }, payload: { storeId: '11', roomId: '31', order: 'open', delayTime: 15 } }); assert.equal(invalid.statusCode, 400); await app.close(); console.log('PASS: M06-D control-box and Sub-1G command gates and routes work.');