const redeemApps=[ {id:'chatgpt', name:'ChatGPT', plugin:'chatgpt'}, {id:'claude', name:'Claude', plugin:'claude'} ]; function redeemSkus(plugin){ const rows=(cache.skus||[]).filter(s=>s && (s.plugin||'')===plugin); if(rows.length) return rows; const fallback={ chatgpt:[ ['ChatGPT Go','oai.chatgpt.go'],['ChatGPT Plus','oai.chatgpt.plus'],['ChatGPT Pro','oai.chatgpt.pro'], ['ChatGPT Pro Lite','oai.chatgpt.prolite'],['ChatGPT Pro Max','oai.chatgpt.promax'] ], claude:[['Claude Pro','com.anthropic.claude.pro'],['Claude Max','com.anthropic.claude.max']] }; return (fallback[plugin]||[]).map(x=>({title:x[0], sku:x[1], plugin:plugin})); } function skuPeriods(sku){ const offers=(sku&&sku.offers)||[]; const found=[...new Set(offers.map(o=>String(o.billing_period||'').toUpperCase()).filter(v=>/^P\d+[MY]$/.test(v)))]; if(!found.length) return ['P1M']; return found.sort((a,b)=>a.endsWith('M')&&b.endsWith('Y')?-1:a.endsWith('Y')&&b.endsWith('M')?1:a.localeCompare(b)); } function viewRedeem(){ const state=window._redeem||{app:'chatgpt'}; window._redeem=state; const app=redeemApps.some(a=>a.id===state.app)?state.app:'chatgpt'; state.app=app; const skus=redeemSkus(app==='claude'?'claude':'chatgpt'); if(!skus.some(s=>s.sku===state.sku)) state.sku=skus[0]?skus[0].sku:''; const radios=skus.map(s=>'').join(''); const selected=skus.find(s=>s.sku===state.sku)||skus[0]||{}; const periods=skuPeriods(selected); if(!periods.includes(state.period)) state.period=periods.includes('P1M')?'P1M':periods[0]; const periodRadios=periods.map(p=>'').join(''); const fields=app==='claude' ? ''+ '
粘贴 Claude 的 sessionKey。
' : ''+ '
ChatGPT账号 JSON https://chatgpt.com/api/auth/session
'+ '
'; $('#app').innerHTML= '
应用
'+ redeemApps.map(a=>'').join('')+ '

'+esc(redeemApps.find(a=>a.id===app).name)+' 兑换

'+ '
'+(app==='claude'?'提交 sessionKey,由 Anthropic 接收 purchase token。':'提交账号 JSON 或 account id,由 RevenueCat 接收 purchase token。')+'
'+ '
'+radios+'
套餐周期
'+periodRadios+'
'+fields+ '
'+ '
'+esc(state.out||'')+'
'; } function parseChatSession(text){ const raw=String(text||'').trim(); if(!raw) return {ok:false, error:'请粘贴 /api/auth/session 的 JSON'}; let data; try{ data=JSON.parse(raw); } catch(e){ return {ok:false, error:'不是合法 JSON'}; } const account=data.account||{}; const id=account.id||(data.user&&data.user.id)||data.accountId||''; if(!id) return {ok:false, error:'JSON 中没有 account.id 或 user.id'}; const plan=account.planType||(data.user&&data.user.planType)||data.planType||'未知'; return {ok:true, id:String(id), plan:String(plan), email:account.email||(data.user&&data.user.email)||''}; } function checkChatSession(text){ const box=$('#redeemCheck'); if(!box) return; const parsed=parseChatSession(text); box.textContent=parsed.ok?('账号 '+parsed.id+(parsed.email?' · '+parsed.email:'')+' · 当前订阅 '+(parsed.plan==='free'?'Free':parsed.plan)):parsed.error; box.style.color=parsed.ok?'var(--ok)':'var(--bad)'; } async function submitRedeem(){ const state=window._redeem||{}; const picked=document.querySelector('input[name=redeemSku]:checked'); const sku=picked?picked.value:''; if(!sku){ fail('无法兑换','请选择 SKU'); return; } const body={app:state.app, sku:sku}; if(state.app!=='claude'){ const account=($('#redeemAccount')||{}).value||''; const parsed=parseChatSession(account); if(!parsed.ok){ fail('JSON 格式不对', parsed.error); return; } body.auth=account.trim(); }else{ body.auth=($('#redeemSession')||{}).value||''; } const res=await api('/api/admin/redeem',{method:'POST',body:JSON.stringify(body)}); state.out=JSON.stringify(res,null,2); viewRedeem(); if(!res.flow_id) return; const timer=setInterval(async()=>{ const cur=await api('/api/admin/redeem/'+res.flow_id); state.out=JSON.stringify(cur,null,2); const box=$('#redeemOut'); if(box) box.textContent=state.out; if(['succeeded','failed','pending_payment'].includes(cur.stage)) clearInterval(timer); },2000); }