'use strict'; const assert = require('assert'); const fs = require('fs'); const path = require('path'); const vm = require('vm'); (async () => { const root = path.join(__dirname, '..'); const appSource = fs.readFileSync(path.join(root, 'public', 'app.js'), 'utf8'); const html = fs.readFileSync(path.join(root, 'public', 'index.html'), 'utf8'); const styles = fs.readFileSync(path.join(root, 'public', 'style.css'), 'utf8'); const operations = fs.readFileSync(path.join(root, 'src', 'routes', 'operations.js'), 'utf8'); const accountsRoute = fs.readFileSync(path.join(root, 'src', 'routes', 'accounts.js'), 'utf8'); const runner = fs.readFileSync(path.join(root, 'src', 'workers', 'task_runner.js'), 'utf8'); const rechargeService = fs.readFileSync(path.join(root, 'src', 'services', 'recharge_task_service.js'), 'utf8'); assert.match( html, /runOpenAIGetAuth\(\)[\s\S]{0,200}runOpenAIQueryPlan\(\)[\s\S]{0,200}openRechargeModal\(\)/, '查询套餐按钮应位于提取授权JSON右侧', ); assert.match(html, /ChatGPT<\/th>\s*是否已充值<\/th>\s*授权JSON<\/th>\s*AC凭证<\/th>\s*Cli_AC凭证<\/th>\s*账号套餐<\/th>/); assert.match(html, /x-model="rechargeCredentialForm\.keyId"/); assert.match(html, /type="password"[^>]*x-model="rechargeCredentialForm\.secret"/); assert.match(styles, /input\[type="text"\],\s*input\[type="password"\],\s*input\[type="number"\]/, 'API Secret 密码框应与 Key ID 使用同一套输入框样式'); assert.match(html, /x-model="rechargeCardKeys"/); assert.match(html, /完整 ChatGPT Session(结构化 JSON)/); assert.match(operations, /taskType === 'card_pay_recharge' && !isLocalRequest\(req\)/); assert.match(operations, /hasOwnProperty\.call\(params, 'confirmDuplicate'\)[\s\S]{0,100}params\.confirmDuplicate !== false/); assert.match(runner, /latest\.chatgpt_session/); assert.match(runner, /sessionText:\s*latest\.chatgpt_session/); assert.match(runner, /confirmDuplicate:\s*false/); assert.match(runner, /parseInt\(params && params\.threadCount, 10\) \|\| 2/, '未指定充值并发时服务端应默认使用 2'); assert.match(runner, /Math\.min\(requestedRechargeConcurrency, 5\)/, '卡付充值应限制为最多 5 路并发'); assert.match(runner, /const rechargeStartSpacingMs\s*=\s*1000/, '卡付充值请求应相隔 1 秒发起'); assert.match(runner, /const rechargeQueryConcurrency\s*=\s*2/, '卡付任务查询应与提交并发分离并限制为 2 路'); assert.match(html, /id="recharge-concurrency"[\s\S]{0,180}min="1" max="5"/, '充值弹窗应提供 1 到 5 的独立并发设置'); assert.match(runner, /type:\s*'progress',\s*current:\s*0,\s*total:\s*accounts\.length/, '充值开始时应立即推送 0/总数进度'); assert.match(runner, /onPrepared:[\s\S]{0,800}onConfirmed:[\s\S]{0,800}onPoll:/, '充值应逐阶段推送预创建、确认和轮询进度'); assert.match(runner, /stagePrefix[\s\S]{0,300}开始处理/, '每个账号应实时打印开始处理信息'); assert.match(runner, /maxRechargeAttempts\s*=\s*3/, '单个账号充值最多应尝试三次'); assert.match(runner, /const rechargeOperationId\s*=\s*operationMap\.get\(emailKey\)[\s\S]{0,100}createRechargeOperationId\(email, cardKey, false\)/, '每个账号应复用认领阶段生成的稳定充值操作号'); assert.match(runner, /operationId:\s*attemptOffset\s*>\s*0[\s\S]{0,180}rechargeOperationId/, '只有远端任务明确失败后才应使用新的尝试幂等号'); assert.match(runner, /使用同一卡密重试/, '重试进度应明确提示使用同一卡密'); assert.match(rechargeService, /error\s*&&\s*error\.retryable\s*===\s*true/, '修改型充值请求的瞬时HTTP错误必须保留为待确认'); assert.match(runner, /rechargeNeedsManualConfirmation\(error, remoteTaskId\)/, '最终失败状态必须结合远端任务号判断是否等待人工确认'); assert.match(operations, /message:\s*account\s*\?\s*\(account\.message/, '充值结论应通过 SSE 同步到通用处理结论'); assert.match(runner, /publishRecharge\([\s\S]{0,180}'等待已确认'/, '结果待确认时应转为等待人工确认状态'); assert.match(operations, /const nextStatus\s*=\s*remoteTaskId\s*\?\s*'充值中'\s*:\s*'充值失败'/, '任务中断时已提交任务应保持充值中,未提交账号才标记失败'); assert.match(accountsRoute, /router\.put\('\/:email\/recharge-status'/, '应提供本机人工修改充值状态接口'); assert.match(html, /