feat(taobao): add native mini program with shared backend

Preserve H5 flows while adding Taobao identity, native capture, reports and isolated local development. Fix canceled province selection and expired-session logout. Record passing local regressions, two pre-existing H5 assertion failures and pending platform validation.
This commit is contained in:
xsl
2026-10-19 20:14:31 +08:00
parent d07f8cc1bb
commit 9eec4369da
61 changed files with 4827 additions and 17 deletions
+33 -3
View File
@@ -177,7 +177,7 @@ module.exports = function createAccounts(root, env = process.env) {
}
function storeReport(ownerId, snapshot) {
const user = db.users.find(u => u.id === ownerId);
if (!user || user.kind !== 'wechat' || !/^R[\w-]+$/.test(snapshot.id)) throw new Error('Invalid report owner');
if (!user || !['wechat', 'taobao'].includes(user.kind) || !/^R[\w-]+$/.test(snapshot.id)) throw new Error('Invalid report owner');
const dir = path.join(snapshots, user.id); fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
atomic(path.join(dir, snapshot.id + '.json'), snapshot);
user.reports = [{ id: snapshot.id, created_at: snapshot.created_at, total: snapshot.vm.total, skinAge: snapshot.vm.skinAgeDisplay }]
@@ -193,7 +193,7 @@ module.exports = function createAccounts(root, env = process.env) {
catch (_) { return null; }
}
function reportSnapshot(ownerId,id) {
if (!db.users.some(u=>u.id===ownerId&&u.kind==='wechat') || !/^R[\w-]+$/.test(id)) return null;
if (!db.users.some(u=>u.id===ownerId&&['wechat','taobao'].includes(u.kind)) || !/^R[\w-]+$/.test(id)) return null;
try {return JSON.parse(fs.readFileSync(path.join(snapshots,ownerId,id+'.json'),'utf8'));} catch (_) {return null;}
}
function updateWrinkleViews(ownerId,id,views) {
@@ -203,5 +203,35 @@ module.exports = function createAccounts(root, env = process.env) {
if (snapshot.payload.wrinkle_job) snapshot.payload.wrinkle_job.status='complete';
atomic(path.join(snapshots,ownerId,id+'.json'),snapshot);
}
return { route, session, storeReport, reportPresentation, reportSnapshot, updateWrinkleViews, sameOrigin, wechatAvailable: available };
function loginTaobao(providerKey) {
let user = db.users.find(u => u.kind === 'taobao' && u.provider_key === providerKey);
if (!user) { user = { id: crypto.randomUUID(), kind: 'taobao', provider_key: providerKey, reports: [] }; db.users.push(user); }
const token = random(), expires = Date.now() + 30 * 86400000;
for (const key of Object.keys(db.sessions)) if (db.sessions[key].expires < Date.now()) delete db.sessions[key];
db.sessions[hash(token)] = { user: user.id, expires };
save();
return { token, expires_in: 30 * 86400, user: publicUser(user) };
}
function taobaoSession(req) {
const match = /^Bearer ([a-f0-9]{64})$/.exec(req.headers.authorization || '');
const row = match && db.sessions[hash(match[1])];
return row && row.expires > Date.now() ? db.users.find(u => u.id === row.user && u.kind === 'taobao') : null;
}
function taobaoLogout(req) {
const match = /^Bearer ([a-f0-9]{64})$/.exec(req.headers.authorization || '');
if (match && taobaoSession(req)) { delete db.sessions[hash(match[1])]; save(); }
}
function reports(owner) {
return db.users.find(u => u.id === owner && u.kind === 'taobao')?.reports || [];
}
function ownedReport(owner, id) {
if (!reports(owner).some(r => r.id === id)) return null;
const snapshot = reportSnapshot(owner, id);
if (!snapshot) return null;
snapshot.vm = SkinScore.withDisplayRecommendation(snapshot.vm, snapshot.payload && snapshot.payload.result);
snapshot.presentation = ReportUI.forDisplay(snapshot.vm, snapshot.payload && snapshot.payload.result, snapshot.presentation);
return snapshot;
}
return { route, session, storeReport, reportPresentation, reportSnapshot, updateWrinkleViews, sameOrigin, wechatAvailable: available,
loginTaobao, taobaoSession, taobaoLogout, reports, ownedReport };
};