#!/usr/bin/env node const assert = require('assert'); const http = require('http'); const { loadCatalog, searchEndpoints, findEndpoint } = require('../mcp/src/core/api-catalog'); const { searchQiweApis, getQiweApiDoc, callQiweApi } = require('../mcp/src/tools/qiwe-api-catalog-run'); const { qiweLoginStatus, qiweLoginStart, qiweLoginCheck, qiweLoginVerify } = require('../mcp/src/tools/qiwe-login-run'); const { qiweSubscriptionStatus, qiweSubscribe, qiweSubscriptionAutoRenew } = require('../mcp/src/tools/qiwe-subscription-run'); const PRIVATE_PROVIDER_NAME = ['private', 'provider'].join('-'); const PRIVATE_PROVIDER_HOST = ['private', 'provider', 'invalid'].join('.'); const PRIVATE_CREDENTIAL_KEY = ['token', 'Id'].join(''); function assertProviderHidden(value) { const output = JSON.stringify(value); assert(!output.includes(PRIVATE_PROVIDER_NAME)); assert(!output.includes(PRIVATE_PROVIDER_HOST)); assert(!output.includes('server-only-guid')); assert(!output.includes('server-only-token')); } function readBody(req) { return new Promise(resolve => { let body = ''; req.setEncoding('utf8'); req.on('data', chunk => { body += chunk; }); req.on('end', () => resolve(body ? JSON.parse(body) : undefined)); }); } async function startMockGateway() { const requests = []; const server = http.createServer(async (req, res) => { const body = await readBody(req); const url = new URL(req.url, 'http://localhost'); requests.push({ method: req.method, path: url.pathname, query: Object.fromEntries(url.searchParams.entries()), authorization: req.headers.authorization, body }); let data; if (url.pathname === '/doApi') { data = { nickname: '测试账号', echoedMethod: body.method, guid: 'server-only-guid', [PRIVATE_CREDENTIAL_KEY]: 'server-only-token', provider: PRIVATE_PROVIDER_NAME, providerName: PRIVATE_PROVIDER_NAME, providerHost: PRIVATE_PROVIDER_HOST, supportUrl: `https://${PRIVATE_PROVIDER_HOST}/help`, diagnostic: `See https://${PRIVATE_PROVIDER_HOST}/diagnostic` }; } else if (url.pathname === '/login/status') { data = { configured: true, online: true, statusCode: 2 }; } else if (url.pathname === '/login/start') { data = { uid: body.uid, guid: 'server-only-guid', loginQrcodeBase64Data: Buffer.from('mock-png').toString('base64') }; } else if (url.pathname === '/login/check') { data = { uid: body.uid, guid: 'server-only-guid', status: 2, detail: { nickname: '测试账号', userId: 'u-1' } }; } else if (url.pathname === '/login/verify') { data = { accepted: true }; } else if (url.pathname === '/subscribe/status') { data = { subscribed: true, seats: 2, usedSeats: 1, expireAt: '2026-08-10T00:00:00.000Z', autoRenew: true, balance: 1000 }; } else if (url.pathname === '/subscribe') { data = { seats: body.seats || 1, expireAt: '2026-08-10T00:00:00.000Z', autoRenew: true }; } else if (url.pathname === '/subscribe/autoRenew') { data = { autoRenew: body.autoRenew }; } else { res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ code: 404, mess: 'not found' })); return; } res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ code: 200, data })); }); await new Promise(resolve => server.listen(0, '127.0.0.1', resolve)); const address = server.address(); return { requests, apiBase: `http://127.0.0.1:${address.port}`, close: () => new Promise(resolve => server.close(resolve)) }; } async function main() { const catalog = loadCatalog(); assert(catalog.endpoints.length >= 100, 'catalog should contain 100+ endpoints'); assert(catalog.gateway.baseUrl.includes('server.fmode.cn/api/qiwe')); assert(catalog.endpoints.every(endpoint => !Object.hasOwn(endpoint, 'docUrl'))); assertProviderHidden(catalog); console.log(`[ok] catalog loaded: ${catalog.endpoints.length} endpoints`); const hits = searchEndpoints({ query: '发送 文本' }); assert(hits.length > 0 && hits[0].module === 'msg'); assert(findEndpoint('/login/getLoginQrcode')); const searchResult = await searchQiweApis({ query: '朋友圈' }); assert(searchResult.status === 'ok' && searchResult.data.endpoints.length > 0); assertProviderHidden(searchResult); const doc = await getQiweApiDoc({ id: 'user.getProfile' }); assert(doc.status === 'ok' && doc.data.callTemplate); assertProviderHidden(doc); assert(!JSON.stringify(doc).includes('"guid"')); console.log('[ok] catalog search and docs'); const gateway = await startMockGateway(); const common = { authToken: 'sk-test-relay-token', uid: 'qiwe-smoke-device', apiBase: gateway.apiBase, persistConfig: false }; try { const call = await callQiweApi({ ...common, id: 'user.getProfile', params: {} }); assert.strictEqual(call.status, 'ok'); const apiRequest = gateway.requests.at(-1); assert.strictEqual(apiRequest.path, '/doApi'); assert.strictEqual(apiRequest.authorization, 'Bearer sk-test-relay-token'); assert.deepStrictEqual(apiRequest.body, { uid: 'qiwe-smoke-device', method: '/user/getProfile', params: {} }); assert(!JSON.stringify(apiRequest.body).includes('tokenId')); assert(!JSON.stringify(apiRequest.body).includes('guid')); assertProviderHidden(call); console.log('[ok] qiwe_api_call uses the Fmode gateway envelope without private credentials'); const blocked = await callQiweApi({ ...common, rawMethod: '/login/manualLogin', params: {} }); assert.strictEqual(blocked.status, 'error'); assert.strictEqual(gateway.requests.at(-1), apiRequest); const subscription = await qiweSubscriptionStatus(common); assert.strictEqual(subscription.status, 'ok'); assert.strictEqual(subscription.summary.subscribed, true); const subscribed = await qiweSubscribe({ ...common, seats: 3 }); assert.strictEqual(subscribed.status, 'ok'); assert.strictEqual(gateway.requests.at(-1).body.seats, 3); const autoRenew = await qiweSubscriptionAutoRenew({ ...common, autoRenew: false }); assert.strictEqual(autoRenew.status, 'ok'); assert.strictEqual(gateway.requests.at(-1).body.autoRenew, false); console.log('[ok] subscription tools use Fmode gateway routes'); const status = await qiweLoginStatus(common); assert.strictEqual(status.status, 'ok'); assert.strictEqual(gateway.requests.at(-1).query.uid, common.uid); const start = await qiweLoginStart({ ...common, openBrowser: false }); assert.strictEqual(start.status, 'ok'); assertProviderHidden(start); const check = await qiweLoginCheck(common); assert.strictEqual(check.status, 'ok'); assert.strictEqual(check.summary.loggedIn, true); assertProviderHidden(check); const verify = await qiweLoginVerify({ ...common, code: '123456' }); assert.strictEqual(verify.status, 'ok'); assert.deepStrictEqual(gateway.requests.at(-1).body, { uid: common.uid, code: '123456' }); console.log('[ok] login tools use uid-based Fmode gateway routes and hide internal identifiers'); for (const request of gateway.requests) { assert.strictEqual(request.authorization, 'Bearer sk-test-relay-token'); } console.log(`[ok] ${gateway.requests.length} mock Fmode gateway requests authenticated`); } finally { await gateway.close(); } console.log('\nAll smoke tests passed.'); } main().catch(error => { console.error('smoke test failed:', error); process.exit(1); });