import crypto from 'node:crypto'; export class PayIran { constructor({apiKey, apiSecret, baseUrl='https://samanpay.org/v1'}) { this.apiKey=apiKey; this.apiSecret=apiSecret; this.baseUrl=baseUrl.replace(/\/$/,''); } sign(method,path,body='') { const timestamp=Math.floor(Date.now()/1000).toString(); const nonce=crypto.randomBytes(12).toString('hex'); const bodyHash=crypto.createHash('sha256').update(body).digest('hex'); const canonical=[timestamp,nonce,method.toUpperCase(),path,bodyHash].join('\n'); const signature=crypto.createHmac('sha256',this.apiSecret).update(canonical).digest('hex'); return {timestamp,nonce,signature}; } async request(method,path,data=null,headers={}) { const body=data===null?'':JSON.stringify(data); const signPath=path.split('?')[0]; const {timestamp,nonce,signature}=this.sign(method,signPath,body); const res=await fetch(this.baseUrl+path,{ method,body:body||undefined,headers:{ 'Accept':'application/json','Content-Type':'application/json', 'X-PIS-Key':this.apiKey,'X-PIS-Timestamp':timestamp,'X-PIS-Nonce':nonce, 'X-PIS-Signature-Version':'2','X-PIS-Signature':signature,...headers } }); const json=await res.json(); if(!res.ok){const e=new Error(json?.error?.message||'PayIran API error');e.status=res.status;e.response=json;throw e;} return json.data; } createPayment(data,idempotencyKey){return this.request('POST','/payments',data,{'Idempotency-Key':idempotencyKey});} getPayment(orderId){return this.request('GET','/payments/'+encodeURIComponent(orderId));} verify(orderId){return this.request('POST','/payments/verify',{order_id:orderId});} transactions(query=''){return this.request('GET','/transactions'+(query?'?'+query:''));} balance(){return this.request('GET','/balance');} dailySummary(date){return this.request('GET','/daily-summary'+(date?'?date='+encodeURIComponent(date):''));} settlements(){return this.request('GET','/settlements');} payoutAccounts(){return this.request('GET','/payout-accounts');} createPayoutAccount(data){return this.request('POST','/payout-accounts',data);} payoutRequests(){return this.request('GET','/payout-requests');} createPayoutRequest(data){return this.request('POST','/payout-requests',data);} static verifyWebhook({rawBody,timestamp,eventId,signature,webhookSecret,maxAge=300}) { if(Math.abs(Math.floor(Date.now()/1000)-Number(timestamp))>maxAge)return false; const expected='sha256='+crypto.createHmac('sha256',webhookSecret).update(timestamp+'\n'+eventId+'\n'+rawBody).digest('hex'); try{return crypto.timingSafeEqual(Buffer.from(expected),Buffer.from(signature));}catch{return false;} } }