import assert from 'node:assert/strict'; import { buildApp } from '../dist/app.js'; import { signAccessToken } from '../dist/auth/jwt.js'; import { StoreAccessError, StoreAccessRepository } from '../dist/stores/access-repository.js'; const transactionCalls = []; const connection = { async beginTransaction() { transactionCalls.push('begin'); }, async commit() { transactionCalls.push('commit'); }, async rollback() { transactionCalls.push('rollback'); }, release() { transactionCalls.push('release'); }, async execute(sql) { if (sql.includes('FROM qipai_scene_codes') && sql.includes('code = ?')) { return [[{ id: 1, tenantId: 7, targetType: 'ROOM', storeId: 11, roomId: 31, generation: 1, scanCount: 0 }], []]; } return [{ affectedRows: 1 }, []]; } }; const repository = new StoreAccessRepository({ async getConnection() { return connection; }, async execute(sql) { if (sql.includes('qipai_order_user_access')) return [[{ total: 0 }], []]; return [[], []]; } }); const resolved = await repository.resolveScene({ code: 'abcdefghijklmnop', sourceType: 'NFC', traceId: 'trace', ip: '127.0.0.1', userAgent: 'test' }); assert.equal(resolved.page, '/pages/room/detail'); assert.deepEqual(resolved.permissions, []); assert.ok(transactionCalls.includes('commit')); await assert.rejects( () => repository.getWifi({ tenantId: '7', userId: '21', access: { roles: ['CUSTOMER'], capabilities: [], storeIds: [] }, storeId: '11', traceId: 'trace', ip: '127.0.0.1', userAgent: 'test' }), (error) => error instanceof StoreAccessError && error.code === 'WIFI_ACCESS_FORBIDDEN' ); const secret = 'test-only-jwt-secret-with-at-least-32-characters'; const token = signAccessToken({ sub: '21', sid: '5c4d3af8-c63c-4edb-bf95-b84127bb3f6e', tid: '7', aid: '9', rv: 1 }, secret, 900); const app = await buildApp({ storeAccess: { jwtSecret: secret, authRepository: { async validateSession() { return { id: '5c4d3af8-c63c-4edb-bf95-b84127bb3f6e', tenantId: '7', platformAppId: '9', expiresAt: new Date(Date.now() + 60000), user: { id: '21', tenantId: '7', userType: 'STAFF', status: 'ACTIVE', roleVersion: 1, nickname: '', avatarUrl: '', phone: '' } }; } }, accessControl: { async getAccessProfile() { return { roles: ['TENANT_ADMIN'], capabilities: ['tenant.manage'], storeIds: [] }; } }, repository: { async regenerateScene() { return { sceneCodeId: '1', code: 'abcdefghijklmnop', generation: 1 }; }, async revokeScene() { return { sceneCodeId: '1', revoked: true }; }, async resolveScene() { return { targetType: 'STORE', storeId: '11', roomId: null, page: '/pages/store/detail', permissions: [] }; }, async sceneStats() { return []; }, async getWifi() { return { ssid: 'QIPAI', password: '' }; } } } }); const generated = await app.inject({ method: 'POST', url: '/admin-api/scene-codes/regenerate', headers: { authorization: `Bearer ${token}` }, payload: { targetType: 'STORE', storeId: '11' } }); assert.equal(generated.statusCode, 201); const scan = await app.inject({ method: 'POST', url: '/app-api/scenes/resolve', payload: { code: 'abcdefghijklmnop', sourceType: 'QRCODE' } }); assert.equal(scan.statusCode, 200); assert.deepEqual(scan.json().data.permissions, []); await app.close(); console.log('PASS: M03-D scene navigation has no door permission and Wi-Fi access is guarded.');