'use strict'; const assert = require('assert'); const fs = require('fs'); const path = require('path'); const servicePath = path.join(__dirname, '..', 'src', 'services', 'aistudio_api_key_service.js'); const source = fs.readFileSync(servicePath, 'utf8'); const start = source.indexOf('async function processAistudioApiKey'); const end = source.indexOf('\nmodule.exports =', start); assert(start >= 0 && end > start, '必须存在 processAistudioApiKey 实现'); const implementation = source.slice(start, end); const tryIndex = implementation.indexOf('\n try {'); const stateIndex = implementation.indexOf('let deletedExisting = false;'); assert(stateIndex >= 0, '必须跟踪线上旧 key 是否已被删除'); assert(tryIndex >= 0 && stateIndex < tryIndex, 'deletedExisting 必须声明在 try 外,异常处理才能访问删除状态'); assert.match( implementation, /catch\s*\(error\)[\s\S]*?return\s*\{\s*ok:\s*false,\s*data:\s*null,\s*msg,\s*deletedExisting,\s*clearedPreferredProjectId\s*\};/, '异常返回必须携带 deletedExisting 和失效项目状态,供上层同步清理数据库记录', ); const lateStart = implementation.indexOf('for (let lateRecovery = 1;'); const lateEnd = implementation.indexOf('\n if (!created.ok)', lateStart + 10); const lateRecovery = implementation.slice(lateStart, lateEnd); const lateCountBranch = lateRecovery.indexOf('if (lateCount > 0)'); const unconditionalRecreate = lateRecovery.lastIndexOf('created = await createKey(page, log, {'); assert(lateStart >= 0 && lateEnd > lateStart, '必须存在列表晚到恢复分支'); assert(lateRecovery.includes('lateRecovery <= 2'), '列表 0→1 连续抖动时应允许最多两轮恢复,同时防止无限循环'); assert(lateRecovery.includes('waitForLateExistingRows(page, 5000)'), '刷新后必须给列表数据稳定时间,不能立即把 0 当成无旧 Key'); assert(lateCountBranch >= 0 && unconditionalRecreate > lateCountBranch, '列表刷新后即使旧行已经自然消失,也必须重新创建 Key,不能保留 lateExisting 失败结果'); assert(lateRecovery.includes('syncExistingAistudioApiKey(page, account, log'), '创建流程中才出现的 Key 必须直接读取保存,不能再次删除重建'); assert(!lateRecovery.includes('deleteAllKeys('), 'lateExisting 恢复分支禁止删除 Key,避免把本轮刚创建成功的 Key 当作旧 Key 删除'); assert(lateRecovery.includes('recoveredLateKey: true'), '安全读取晚到 Key 后必须直接作为成功结果返回'); assert(lateRecovery.includes('allowMissingPreferredProjectRecovery,'), '列表晚到恢复后必须保留新旧项目判定参数,防止新项目被误判失效'); console.log('aistudio_deleted_existing_propagation.test.js: PASS');