@munchi_oy/payments 1.10.7 → 1.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/src/MunchiPaymentSDK.d.ts.map +1 -1
- package/dist/src/strategies/IPaymentStrategy.d.ts +4 -1
- package/dist/src/strategies/IPaymentStrategy.d.ts.map +1 -1
- package/dist/src/strategies/NetsSessionStrategy.d.ts +40 -0
- package/dist/src/strategies/NetsSessionStrategy.d.ts.map +1 -0
- package/dist/src/strategies/VivaSessionStrategy.d.ts +1 -0
- package/dist/src/strategies/VivaSessionStrategy.d.ts.map +1 -1
- package/dist/src/strategies/sessionResult.d.ts +8 -1
- package/dist/src/strategies/sessionResult.d.ts.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/package.json +2 -2
- package/src/MunchiPaymentSDK.ts +17 -2
- package/src/strategies/IPaymentStrategy.ts +8 -1
- package/src/strategies/NetsSessionStrategy.ts +451 -0
- package/src/strategies/VivaSessionStrategy.ts +9 -4
- package/src/strategies/sessionResult.ts +76 -0
- package/src/version.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var x=Object.defineProperty;var K=Object.getOwnPropertyDescriptor;var q=Object.getOwnPropertyNames;var Y=Object.prototype.hasOwnProperty;var B=(a,e)=>{for(var r in e)x(a,r,{get:e[r],enumerable:!0})},$=(a,e,r,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of q(e))!Y.call(a,n)&&n!==r&&x(a,n,{get:()=>e[n],enumerable:!(t=K(e,n))||t.enumerable});return a};var Q=a=>$(x({},"__esModule",{value:!0}),a);var ae={};B(ae,{AppReaderStatus:()=>G,MunchiPaymentSDK:()=>F,PaymentInteractionState:()=>C,SdkPaymentStatus:()=>T});module.exports=Q(ae);var I=require("@munchi_oy/core");var M="1.10.7";var l=class a extends Error{code;rawError;constructor(e,r,t){super(r),this.name="PaymentSDKError",this.code=e,this.rawError=t,Object.setPrototypeOf(this,a.prototype)}};var g=require("@munchi_oy/core");var T=(i=>(i.PENDING="PENDING",i.SUCCESS="SUCCESS",i.APPROVED="APPROVED",i.FAILED="FAILED",i.CANCELLED="CANCELLED",i.ERROR="ERROR",i))(T||{}),C=(c=>(c.IDLE="IDLE",c.CONNECTING="CONNECTING",c.REQUIRES_INPUT="REQUIRES_INPUT",c.PROCESSING="PROCESSING",c.SUCCESS="SUCCESS",c.FAILED="FAILED",c.INTERNAL_ERROR="INTERNAL_ERROR",c.VERIFYING="VERIFYING",c))(C||{});var w=class{constructor(e,r,t){this.messaging=r;this.config=t;this.api=new g.PaymentApi(void 0,"",e)}api;abortController=null;currentRequestId=null;paymentProvider=g.PaymentProviderEnum.Nets;async processPayment(e,r){this.abortController=new AbortController,r("CONNECTING");let t={amount:e.amountCents,businessId:Number(this.config.storeId),referenceId:e.orderRef,currency:e.currency,displayId:e.displayId,options:{allowPinBypass:!0,transactionType:g.TransactionType.Purchase}};try{let{data:n}=await this.api.initiateNetsTerminalTransaction(t),s=n.connectCloudRequestId;if(!s)throw new Error("connectCloudRequestId is missing from response.");if(this.currentRequestId=s,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:s});let i=await this.waitForPaymentCompletion(s,e.orderRef,this.abortController.signal);return this.currentRequestId=null,i}catch(n){throw this.currentRequestId=null,n instanceof l?n:new l("TERMINAL_BUSY","Failed to create Nets Intent",n)}}async waitForPaymentCompletion(e,r,t){let n=`nets.requests.${e}`,s=g.PaymentEventType.StatusChanged;return new Promise((i,o)=>{let c=!1,u=()=>{c=!0,typeof m=="function"&&m(),clearTimeout(y)},d=()=>{u(),o(new l("CANCELLED","Transaction cancelled"))};t.addEventListener("abort",d);let m=this.messaging.subscribe(n,s,p=>{c||p.status===g.SimplePaymentStatus.Pending||(u(),t.removeEventListener("abort",d),i(this.handleSuccess(p)))}),y=setTimeout(async()=>{if(!(c||t.aborted))try{let p=await this.pollOrderStatus(e,r,this.config.storeId,t);i(this.handleSuccess(p))}catch(p){o(new l("TIMEOUT","Payment timed out and polling failed",p))}finally{t.removeEventListener("abort",d),u()}},1e4)})}async pollOrderStatus(e,r,t,n){let c=Date.now()+12e4;for(;Date.now()<c;){if(n.aborted)throw new Error("Aborted");try{let{data:u}=await this.api.getPaymentStatus({businessId:Number(t),orderId:r,provider:this.paymentProvider,referenceId:e});if(n.aborted)throw new Error("Aborted");if(u.status!==g.SimplePaymentStatus.Pending)return u}catch(u){if(u instanceof Error&&u.message==="Aborted")throw u}await new Promise(u=>{let d=()=>{clearTimeout(m),u(void 0)};n.addEventListener("abort",d,{once:!0});let m=setTimeout(()=>{n.removeEventListener("abort",d),u(void 0)},2e3)})}throw new Error("Payment verification timed out.")}async cancelTransaction(e){if(!this.currentRequestId)return!1;let r={requestId:this.currentRequestId,businessId:Number(this.config.storeId)};try{return await this.api.cancelNetsTerminalTransaction(r),this.abortController?.abort(),this.currentRequestId=null,!0}catch{return!1}}async refundTransaction(e,r){try{this.abortController=new AbortController;let t={amount:e.amountCents,businessId:Number(this.config.storeId),currency:e.currency,displayId:e.displayId,referenceId:e.orderRef,options:{allowPinBypass:!0,transactionType:g.TransactionType.ReturnOfGoods}},{data:n}=await this.api.initiateNetsTerminalTransaction(t),s=n.connectCloudRequestId;if(!s)throw new Error("connectCloudRequestId is missing from response.");if(this.currentRequestId=s,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:s});let i=await this.waitForPaymentCompletion(s,e.orderRef,this.abortController.signal);return this.currentRequestId=null,i}catch(t){throw this.currentRequestId=null,t instanceof l||t instanceof l?t:new l("NETWORK_ERROR","Failed to refund Nets transaction",t)}}async verifyFinalStatus(e,r){try{let{data:t}=await this.api.getPaymentStatus({businessId:Number(this.config.storeId),orderId:e.orderRef,provider:this.paymentProvider,referenceId:r});return this.handleSuccess(t)}catch(t){throw new l("NETWORK_ERROR","Failed to verify final Nets status",t)}}handleSuccess(e){let r=e.status===g.SimplePaymentStatus.Success,t=e.status===g.SimplePaymentStatus.Pending,n={success:r,status:r?"SUCCESS":t?"PENDING":"FAILED",orderId:e.orderId,transaction:e.transaction};return e.transactionId&&(n.transactionId=e.transactionId),e.error?.code&&(n.errorCode=e.error.code),e.error?.message&&(n.errorMessage=e.error.message),n}abort(){this.abortController?.abort()}};var f=require("@munchi_oy/core");var N=a=>{if(!a)return 0;let e=Number.parseInt(a,10);return Number.isFinite(e)?e:0},U=a=>{if(!a)return new Date().toISOString();let e=new Date(a);return Number.isNaN(e.getTime())?new Date().toISOString():e.toISOString()};var X="vivapayclient://pay/v1",H="abort",J="sale",k="transactionDetails",Z=4e3,ee="534287",te="38",re="493591",ne="497439",se=[re,ne],ie=["CREDIT","PREPAID","CORPORATE"],D=class{constructor(e,r,t,n){this.config=t;this.appToAppConfig=n;this.sessionApi=new f.PaymentSessionApi(void 0,"",e)}sessionApi;abortController=null;currentClientTransactionId=null;currentIsvClientTransactionId=null;currentCurrency=null;currentOrderRef=null;currentSourceTerminalId=null;latestResult=null;wasCancelled=!1;getExecutionMode(){return"callback_driven"}async processPayment(e,r){if(!this.appToAppConfig.enabled)throw new l("STRATEGY_ERROR","Viva app-to-app is not enabled");r("CONNECTING");try{let{data:t}=await this.sessionApi.initiateVivaA2aSession(this.buildCreatePaymentPayload(e));return await this.runAction(J,this.buildLaunchParams(t),e,r)}catch(t){throw new l("NETWORK_ERROR","Failed to create Viva app-to-app payment",t)}}async cancelTransaction(e){if(!this.currentClientTransactionId)return!1;let r=await this.lookupTransactionDetails();if(r)return this.latestResult=r,this.wasCancelled=r.status==="CANCELLED",this.abortController?.abort(),!0;try{await this.appToAppConfig.adapter.openUrl(this.buildActionUrl(H,{}))}catch(t){throw this.abortController?.abort(),new l("NETWORK_ERROR","Failed to launch Viva abort flow",t)}return this.wasCancelled=!0,this.abortController?.abort(),!0}async refundTransaction(e,r){try{let t={sessionId:e.originalTransactionId,amount:e.amountCents},{data:n}=await this.sessionApi.refundVivaSession(t),s=n.status===f.PaymentSessionStatus.Refunded||n.status===f.PaymentSessionStatus.Refunding,i={success:s,status:s?"SUCCESS":"FAILED",orderId:e.orderRef,transactionId:n.providerTransactionId??n.sessionId};return s||(n.errorCode&&(i.errorCode=n.errorCode),n.errorMessage&&(i.errorMessage=n.errorMessage)),i}catch(t){throw new l("NETWORK_ERROR","Failed to refund Viva transaction",t)}}async verifyFinalStatus(e,r){return this.latestResult?this.latestResult:this.wasCancelled?{success:!1,status:"CANCELLED",orderId:this.currentOrderRef??r,errorCode:f.PaymentFailureCode.PaymentCancelledByUser,errorMessage:"Transaction was cancelled",transactionId:r}:{success:!1,status:"PENDING",orderId:this.currentOrderRef??r,transactionId:r}}abort(){this.abortController?.abort()}async runAction(e,r,t,n){if(!this.appToAppConfig.enabled)throw new l("STRATEGY_ERROR","Viva app-to-app is not enabled");this.abortController=new AbortController,this.latestResult=null,this.wasCancelled=!1,this.currentCurrency=t.currency,this.currentOrderRef=t.orderRef,this.currentSourceTerminalId=r.sourceTerminalId??r.tid??null,this.currentClientTransactionId=r.clientTransactionId??null,this.currentIsvClientTransactionId=r.ISV_clientTransactionId??null;let s=this.currentClientTransactionId?{sessionId:this.currentClientTransactionId}:void 0;return new Promise((i,o)=>{let c=(m,y)=>{m?.(),this.abortController?.signal.removeEventListener("abort",y)},u=()=>{c(d,u),o(new Error("Aborted"))},d=this.appToAppConfig.adapter.subscribe(m=>{if(this.abortController?.signal.aborted)return;let y=this.parseCallbackUrl(m);y&&this.matchesKnownTransactionId(y.rawParams)&&(this.latestResult=y.result,this.wasCancelled=y.result.status==="CANCELLED",this.currentClientTransactionId=null,this.currentIsvClientTransactionId=null,this.currentCurrency=null,this.currentOrderRef=null,this.currentSourceTerminalId=null,c(d,u),i(y.result))});this.abortController?.signal.addEventListener("abort",u),n("REQUIRES_INPUT",s),this.appToAppConfig.adapter.openUrl(this.buildActionUrl(e,r)).then(()=>{this.abortController?.signal.aborted}).catch(m=>{c(d,u),this.currentClientTransactionId=null,this.currentIsvClientTransactionId=null,this.currentCurrency=null,this.currentOrderRef=null,this.currentSourceTerminalId=null,o(new l("NETWORK_ERROR","Failed to launch Viva app",m))})})}buildCreatePaymentPayload(e){let r=e.options??{},t={amount:e.amountCents,referenceId:e.orderRef,businessId:Number(this.config.storeId),currency:e.currency,displayId:e.displayId,showReceipt:!1,showTransactionResult:!1};return r.tipAmount!==void 0&&(t.tipAmount=r.tipAmount),e.splitContext!==void 0&&(t.splitContext=e.splitContext),t}buildLaunchParams(e){let r={};return Object.entries(e).forEach(([t,n])=>{n!==void 0&&(t==="clientToken"||t==="sessionId"||(r[t]=String(n)))}),r}buildActionUrl(e,r){let t=new URLSearchParams({action:e,appId:this.appToAppConfig.appId,callback:this.resolveCallbackQueryParam()});return Object.entries(r).forEach(([n,s])=>{t.set(n,s)}),`${X}?${t.toString()}`}parseCallbackUrl(e){if(!this.matchesCallbackBase(e))return null;let r=new URL(e),t=Object.fromEntries(r.searchParams.entries()),n=this.isSuccessfulCallback(t),s=this.isCancelledCallback(t),i=this.resolveFailureCode(t,s),o={success:n,status:n?"SUCCESS":s?"CANCELLED":"FAILED",orderId:this.currentOrderRef??t.clientTransactionId??"unknown",errorCode:n?"":i,errorMessage:n?"":t.message??"Transaction failed without error details"};n&&(o.transaction=this.mapCallbackToTransaction(t));let c=t.transactionId??t.orderCode??t.clientTransactionId,u=t.errorCode??this.extractErrorReferenceFromMessage(t.message)??t.referenceNumber??t.tid??t.rrn;return c&&(o.transactionId=c),u&&(o.errorReference=u),{rawParams:t,result:o}}matchesCallbackBase(e){let r=new URL(e),t=this.appToAppConfig.callbackUrl;if(!t.includes("://")){let s=t.replace(/:$/,"");return r.protocol===`${s}:`}let n=new URL(t);return r.protocol===n.protocol&&r.hostname===n.hostname&&r.pathname===n.pathname}resolveCallbackQueryParam(){if(this.appToAppConfig.callbackParamFormat!=="scheme-only")return this.appToAppConfig.callbackUrl;let e=this.appToAppConfig.callbackUrl;return e.includes("://")?new URL(e).protocol.replace(/:$/,""):e.replace(/:$/,"")}matchesKnownTransactionId(e){let r=[this.currentClientTransactionId,this.currentIsvClientTransactionId].filter(n=>!!n);if(r.length===0)return!0;let t=[e.clientTransactionId,e.ISV_clientTransactionId].filter(n=>!!n);return t.length===0?!0:t.some(n=>r.includes(n))}resolveFailureCode(e,r){if(r)return f.PaymentFailureCode.PaymentCancelledByUser;let t=e.errorCode;if(t?.includes("."))return t;if(this.isTransactionDetailsAction(e)&&(e.transactionType??"").toLowerCase().includes("abort"))return f.PaymentFailureCode.SystemUnknown;let n=(e.message??"").toLowerCase(),s=(e.status??"").toLowerCase();return n.includes("declined")||s==="declined"||s==="fail"||s==="failed"||s==="failure"?f.PaymentFailureCode.PaymentDeclined:f.PaymentFailureCode.SystemUnknown}isSuccessfulCallback(e){let r=(e.status??"").toLowerCase();return this.isTransactionDetailsAction(e)?r!=="success"?!1:!(e.transactionType??"").toLowerCase().includes("abort"):r==="success"}isTransactionDetailsAction(e){return(e.action??"").toLowerCase()===k.toLowerCase()}isCancelledCallback(e){let r=(e.status??"").toLowerCase(),t=(e.message??"").toLowerCase(),n=(e.errorCode??"").toLowerCase();return r==="cancelled"||r==="canceled"||t.includes("user_cancel")||t.includes("user cancel")||t.includes("cancelled by user")||t.includes("canceled by user")||t.includes("transaction cancelled by user")||t.includes("transaction canceled by user")||n.includes("user_cancel")||n.includes("user cancel")||n==="1000"&&(t.includes("cancelled by user")||t.includes("canceled by user"))}extractErrorReferenceFromMessage(e){return e?e.match(/\((-?\d+)\)/)?.[1]:void 0}mapCallbackToTransaction(e){let r=e.transactionId??e.orderCode??e.clientTransactionId??"unknown",t=U(e.transactionDate),n=N(e.tipAmount),s=N(e.surchargeAmount);return{amount:N(e.amount)-n-s,cardDetail:{aid:e.aid??null,applicationLabel:e.applicationLabel??null,cardNumber:e.accountNumber??"N/A",cardType:e.cardType??"N/A",issuer:e.bankId??null,orderCode:e.orderCode??null,timestamp:t,transactionId:r},createdAt:t,fees:this.buildFees(n,s),id:r,label:null,provider:f.PaymentProvider.Viva,rawData:e,referenceId:e.clientTransactionId??null,roundingDifference:0,type:this.getVivaPaymentMethodType(e)}}getVivaPaymentMethodType(e){let r=(e.applicationLabel??"").toUpperCase().trim(),n=(e.accountNumber??"").substring(0,6),s=(e.bankId??"").trim();return n===ee||s===te?f.PaymentMethod.Edenred:se.includes(n)?f.PaymentMethod.WoltBenefit:ie.some(i=>r.includes(i))?f.PaymentMethod.Credit:f.PaymentMethod.Debit}buildFees(e,r){if(!this.currentCurrency)return null;let t=[];return e>0&&t.push({taxAmount:0,total:{amount:e,currency:this.currentCurrency},type:f.FeeType.TipAmount,vatPercentage:0}),r>0&&t.push({taxAmount:0,total:{amount:r,currency:this.currentCurrency},type:f.FeeType.Surcharge,vatPercentage:0}),t.length===0?null:{parts:t}}async lookupTransactionDetails(){if(!this.currentClientTransactionId||!this.currentSourceTerminalId)return null;let e={clientTransactionId:this.currentClientTransactionId,sourceTerminalId:this.currentSourceTerminalId};return new Promise(r=>{let t=!1,n=setTimeout(()=>{t||(t=!0,s(),r(null))},Z),s=this.appToAppConfig.adapter.subscribe(i=>{if(t)return;let o=this.parseCallbackUrl(i);o&&this.matchesKnownTransactionId(o.rawParams)&&(t=!0,clearTimeout(n),s(),r(o.result))});this.appToAppConfig.adapter.openUrl(this.buildActionUrl(k,e)).catch(()=>{t||(t=!0,clearTimeout(n),s(),r(null))})})}};var E=require("@munchi_oy/core");var h=require("@munchi_oy/core");function oe(a){throw new l("UNKNOWN",`Unhandled payment session status: ${String(a)}`)}function _(a){return{success:!1,status:"PENDING",orderId:a,errorCode:"",errorMessage:""}}function V(a,e){switch(a.status){case h.PaymentSessionStatus.Initiated:case h.PaymentSessionStatus.Processing:case h.PaymentSessionStatus.Voiding:case h.PaymentSessionStatus.Refunding:case h.PaymentSessionStatus.Dispatched:return _(e);case h.PaymentSessionStatus.Success:case h.PaymentSessionStatus.Closed:{let r={success:!0,status:"SUCCESS",orderId:e,errorCode:"",errorMessage:""};return a.providerTransactionId&&(r.transactionId=a.providerTransactionId),r}case h.PaymentSessionStatus.VoidFailed:case h.PaymentSessionStatus.Failed:{let r={success:!1,status:"FAILED",orderId:e,errorCode:a.errorCode||h.PaymentFailureCode.SystemUnknown,errorMessage:a.errorMessage||"Transaction failed without error details"};return a.providerTransactionId&&(r.transactionId=a.providerTransactionId),r}case h.PaymentSessionStatus.Cancelled:case h.PaymentSessionStatus.Voided:case h.PaymentSessionStatus.VoidPending:case h.PaymentSessionStatus.Refunded:{let r={success:!1,status:"CANCELLED",orderId:e};return a.errorCode&&(r.errorCode=a.errorCode),a.errorMessage&&(r.errorMessage=a.errorMessage),a.providerTransactionId&&(r.transactionId=a.providerTransactionId),r}default:return oe(a.status)}}var O=class a{constructor(e,r,t){this.messaging=r;this.config=t;this.sessionApi=new E.PaymentSessionApi(void 0,"",e)}static POLLING_DURATION_MS=18e4;static POLLING_INTERVAL_MS=1e3;static VERIFY_DURATION_MS=3e4;static INITIAL_POLL_DELAY_MS=1e4;sessionApi;abortController=null;idempotencyKey=null;idempotencyOrderRef=null;currentClientToken=null;async processPayment(e,r){this.abortController=new AbortController,(this.idempotencyKey===null||this.idempotencyOrderRef!==e.orderRef)&&(this.idempotencyKey=this.generateIdempotencyKey(),this.idempotencyOrderRef=e.orderRef),this.currentClientToken=null,r("CONNECTING");let t={amount:e.amountCents,businessId:Number(this.config.storeId),orderId:e.orderRef};e.splitContext!==void 0&&(t.splitContext=e.splitContext);try{let{data:n}=await this.sessionApi.initiateVivaSession(t,this.idempotencyKey);this.currentClientToken=n.clientToken;let s=this.abortController.signal;if(s.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:n.sessionId});let i=await this.waitForCompletion(n.clientToken,n.sessionId,e,s);return i?this.finalize(i):(await this.armCancel(n.clientToken),_(e.orderRef))}catch(n){throw n instanceof l?n:new l("NETWORK_ERROR","Failed to create Viva payment session",n)}}async verifyFinalStatus(e,r,t){if(!this.currentClientToken)throw new l("NETWORK_ERROR","No active payment session to verify");let n=await this.pollUntilTerminal(this.currentClientToken,e,void 0,t??a.VERIFY_DURATION_MS);return this.finalize(n??_(e.orderRef))}async cancelTransaction(e){if(!this.currentClientToken)return!1;try{await this.sessionApi.cancelVivaSession(this.currentClientToken)}catch(r){throw new l("NETWORK_ERROR","Failed to cancel Viva payment session",r)}return this.abortController?.abort(),!0}async refundTransaction(e,r){try{let t={sessionId:e.originalTransactionId,amount:e.amountCents},{data:n}=await this.sessionApi.refundVivaSession(t),s=n.status===E.PaymentSessionStatus.Refunded||n.status===E.PaymentSessionStatus.Refunding,i={success:s,status:s?"SUCCESS":"FAILED",orderId:e.orderRef,transactionId:n.providerTransactionId??n.sessionId};return s||(n.errorCode&&(i.errorCode=n.errorCode),n.errorMessage&&(i.errorMessage=n.errorMessage)),i}catch(t){throw new l("NETWORK_ERROR","Failed to refund Viva transaction",t)}}async revertTransaction(e){try{let r={sessionId:e.originalTransactionId},{data:t}=await this.sessionApi.revertVivaSession(r),n=t.status===E.PaymentSessionStatus.Refunded||t.status===E.PaymentSessionStatus.Refunding,s={success:n,status:n?"SUCCESS":"FAILED",orderId:e.orderRef,transactionId:t.providerTransactionId??t.sessionId};return n||(t.errorCode&&(s.errorCode=t.errorCode),t.errorMessage&&(s.errorMessage=t.errorMessage)),s}catch(r){throw new l("NETWORK_ERROR","Failed to revert Viva transaction",r)}}abort(){this.abortController?.abort()}async pollUntilTerminal(e,r,t,n){let s=Date.now()+n;for(;Date.now()<s;){if(t?.aborted)throw new Error("Aborted");let i;try{i=(await this.sessionApi.getPaymentSession(e)).data}catch(o){if(o instanceof Error&&o.message==="Aborted")throw o}if(t?.aborted)throw new Error("Aborted");if(i){let o=V(i,r.orderRef);if(o.status!=="PENDING")return o}await this.delay(a.POLLING_INTERVAL_MS,t)}}waitForCompletion(e,r,t,n){let s=`viva.${this.config.channel.toLowerCase()}.requests.${r}`;return new Promise((i,o)=>{let c=!1,u=()=>{c=!0,typeof m=="function"&&m(),clearTimeout(y),n.removeEventListener("abort",d)},d=()=>{u(),o(new Error("Aborted"))};n.addEventListener("abort",d);let m=this.messaging.subscribe(s,"payment:status-changed",p=>{c||p.status!==E.SimplePaymentStatus.Pending&&(u(),i(this.mapStatusDto(p,t)))}),y=setTimeout(()=>{c||this.pollUntilTerminal(e,t,n,a.POLLING_DURATION_MS).then(p=>{c||(u(),i(p))},p=>{c||(u(),o(p))})},a.INITIAL_POLL_DELAY_MS)})}mapStatusDto(e,r){let t=e.status===E.SimplePaymentStatus.Success,n={success:t,status:t?"SUCCESS":"FAILED",orderId:r.orderRef,errorCode:e.error?.code||(t?"":E.PaymentFailureCode.SystemUnknown),errorMessage:e.error?.message||(t?"":"Transaction failed without error details")};return e.transactionId&&(n.transactionId=e.transactionId),e.error?.referenceError&&(n.errorReference=e.error.referenceError),e.transaction&&(n.transaction=e.transaction),n}finalize(e){return e.status!=="PENDING"&&(this.idempotencyKey=null,this.idempotencyOrderRef=null),e}armCancel(e){return this.sessionApi.cancelVivaSession(e).then(()=>{},()=>{})}generateIdempotencyKey(){let e=globalThis.crypto;return e?.randomUUID?e.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,r=>{let t=Math.random()*16|0;return(r==="x"?t:t&3|8).toString(16)})}delay(e,r){return new Promise(t=>{let n=()=>{clearTimeout(s),t()};r&&r.addEventListener("abort",n,{once:!0});let s=setTimeout(()=>{r&&r.removeEventListener("abort",n),t()},e)})}};var S=require("@munchi_oy/core");var A=class a{constructor(e,r,t){this.messaging=r;this.config=t;this.api=new S.PaymentApi(void 0,"",e)}static INITIAL_POLL_DELAY_MS=1e4;static POLLING_DURATION_MS=18e4;static POLLING_INTERVAL_MS=2e3;static TIMEOUT_CANCEL_TIMEOUT_MS=5e3;static VERIFY_TIMEOUT_MS=1e4;static VERIFY_MAX_RETRIES=3;static VERIFY_RETRY_DELAY_MS=1500;api;abortController=null;currentSessionId=null;paymentProvider=S.PaymentProviderEnum.Viva;async processPayment(e,r){this.abortController=new AbortController,r("CONNECTING");let t={amount:e.amountCents,referenceId:e.orderRef,businessId:parseInt(this.config.storeId),currency:e.currency,displayId:e.displayId,showReceipt:!0,showTransactionResult:!0};try{let{data:n}=await this.api.initiateTerminalTransaction(t);if(this.currentSessionId=n.sessionId,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:n.sessionId});let s=await this.waitForPaymentCompletion(n.sessionId,e,this.abortController.signal);return this.currentSessionId=null,s}catch(n){throw this.currentSessionId=null,n instanceof l?n:new l("NETWORK_ERROR","Failed to create Viva Intent",n)}}async waitForPaymentCompletion(e,r,t){let s=`viva.${this.config.channel.toLowerCase()}.requests.${e}`,i="payment:status-changed";return new Promise((o,c)=>{let u=!1,d=()=>{u=!0,typeof y=="function"&&y(),clearTimeout(p)},m=()=>{d(),c(new Error("Aborted"))};t.addEventListener("abort",m);let y=this.messaging.subscribe(s,i,P=>{u||P.status!==S.SimplePaymentStatus.Pending&&(d(),t.removeEventListener("abort",m),o(this.handleSuccess(P)))}),p=setTimeout(async()=>{if(!(u||t.aborted))try{let P=await this.pollOrderStatus(e,r.orderRef,this.config.storeId,t);if(u)return;o(this.handleSuccess(P))}catch(P){if(u)return;if(P instanceof Error&&P.message==="Aborted"){c(P);return}try{let b=await this.recoverAfterPollingTimeout(r,e);o(b)}catch(b){c(b instanceof l?b:new l("TIMEOUT","Payment timed out and polling failed",b))}}finally{t.removeEventListener("abort",m),d()}},a.INITIAL_POLL_DELAY_MS)})}async pollOrderStatus(e,r,t,n){let i=Date.now()+a.POLLING_DURATION_MS;for(;Date.now()<i;){if(n.aborted)throw new Error("Aborted");try{let{data:o}=await this.api.getPaymentStatus({businessId:Number(t),orderId:r,provider:this.paymentProvider,referenceId:e});if(n.aborted)throw new Error("Aborted");if(o.status!==S.SimplePaymentStatus.Pending)return o}catch(o){if(o instanceof Error&&o.message==="Aborted")throw o}await new Promise(o=>{let c=()=>{clearTimeout(u),o(void 0)};n.addEventListener("abort",c,{once:!0});let u=setTimeout(()=>{n.removeEventListener("abort",c),o(void 0)},a.POLLING_INTERVAL_MS)})}throw new Error("Payment verification timed out.")}async recoverAfterPollingTimeout(e,r){return await this.cancelSessionWithTimeout(r),await this.verifyFinalStatusWithRetry(e,r)}async cancelSessionWithTimeout(e){let r;try{await Promise.race([this.cancelSession(e),new Promise((t,n)=>{r=setTimeout(()=>{n(new Error("Viva timeout cancellation timed out"))},a.TIMEOUT_CANCEL_TIMEOUT_MS)})])}catch{}finally{r&&clearTimeout(r)}}async cancelSession(e){return await this.api.cancelVivaTransactionV2({cashRegisterId:this.config.storeId,sessionId:e}),this.currentSessionId===e&&(this.currentSessionId=null),!0}async verifyFinalStatusWithRetry(e,r){let t;for(let n=1;n<=a.VERIFY_MAX_RETRIES;n++)try{let s=await Promise.race([this.verifyFinalStatus(e,r),new Promise((i,o)=>setTimeout(()=>o(new Error("Verify timed out")),a.VERIFY_TIMEOUT_MS))]);if(s.status==="PENDING"){t=new Error("Verify returned pending status"),n<a.VERIFY_MAX_RETRIES&&await new Promise(i=>setTimeout(i,a.VERIFY_RETRY_DELAY_MS));continue}return s}catch(s){t=s,n<a.VERIFY_MAX_RETRIES&&await new Promise(i=>setTimeout(i,a.VERIFY_RETRY_DELAY_MS))}throw new l(S.PaymentFailureCode.PaymentTimeout,"Payment Failed",t)}handleSuccess(e){let r=e.status===S.SimplePaymentStatus.Success,t={success:r,status:r?"SUCCESS":"FAILED",orderId:e.orderId,errorCode:e.error?.code||(r?"":S.PaymentFailureCode.SystemUnknown),errorMessage:e.error?.message||(r?"":"Transaction failed without error details")};return e.transactionId&&(t.transactionId=e.transactionId),e.error?.referenceError&&(t.errorReference=e.error.referenceError),e.transaction&&(t.transaction=e.transaction),t}async cancelTransaction(e){if(!this.currentSessionId)return!1;try{let r=this.currentSessionId;return this.currentSessionId=null,await this.api.cancelVivaTransactionV2({cashRegisterId:this.config.storeId,sessionId:r}),this.abortController?.abort(),!0}catch(r){throw this.currentSessionId=null,new l("NETWORK_ERROR","Failed to cancel Viva transaction",r)}}async verifyFinalStatus(e,r){try{let{data:t}=await this.api.getPaymentStatus({businessId:Number(this.config.storeId),orderId:e.orderRef,provider:this.paymentProvider,referenceId:r}),n=t.status===S.SimplePaymentStatus.Success,s=t.status===S.SimplePaymentStatus.Pending,i={success:n,status:n?"SUCCESS":s?"PENDING":"FAILED",orderId:t.orderId,errorCode:t.error?.code||(n||s?"":S.PaymentFailureCode.SystemUnknown),errorMessage:t.error?.message||(n||s?"":"Transaction failed without error details")};return t.transactionId&&(i.transactionId=t.transactionId),t.error?.referenceError&&(i.errorReference=t.error.referenceError),t.transaction&&(i.transaction=t.transaction),i}catch(t){throw new l("NETWORK_ERROR","Failed to verify final transaction status",t)}}async refundTransaction(e,r){try{let t={amount:e.amountCents,businessId:Number(this.config.storeId),displayId:this.config.kioskId,currency:e.currency,orderReferenceId:e.orderRef,referenceId:e.originalTransactionId},{data:n}=await this.api.refundSingleVivaTransaction(t),s=n.success;return{success:s,status:s?"SUCCESS":"FAILED",orderId:e.orderRef,transactionId:n.sessionId}}catch(t){throw new l("NETWORK_ERROR","Failed to refund Viva transaction",t)}}abort(){this.abortController?.abort()}};var R=require("@munchi_oy/core"),W=require("axios");var L=class{constructor(e,r,t){this.messaging=r;this.config=t;this.paymentApi=new R.PaymentApi(void 0,"",e),this.worldlineApi=new R.WorldlineApi(void 0,"",e)}paymentApi;worldlineApi;abortController=null;currentOperationId=null;paymentProvider=R.PaymentProviderEnum.Worldline;async processPayment(e,r){this.abortController=new AbortController,r("CONNECTING");let t={amount:e.amountCents,businessId:Number(this.config.storeId),currency:e.currency,displayId:e.displayId,referenceId:e.orderRef,showReceipt:!0,showTransactionResult:!0,...e.options&&"tipAmount"in e.options&&typeof e.options.tipAmount=="number"?{tipAmount:e.options.tipAmount}:{}};try{let n=await this.worldlineApi.createPayment(t),s=this.extractOperationId(n.data);if(this.currentOperationId=s,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:s});let i=await this.waitForPaymentCompletion(s,e.orderRef,R.PaymentEventType.StatusChanged,this.abortController.signal);return this.currentOperationId=null,i}catch(n){throw this.currentOperationId=null,n instanceof l?n:this.mapWorldlineRequestError(n,"Failed to create Worldline payment")}}async cancelTransaction(e){if(!this.currentOperationId)return!1;let r={businessId:Number(this.config.storeId),targetOperationId:this.currentOperationId};try{return await this.worldlineApi.cancelPayment(r),!0}catch(t){throw this.mapWorldlineRequestError(t,"Failed to cancel Worldline transaction")}}async refundTransaction(e,r){this.abortController=new AbortController,r("CONNECTING");let t={amount:e.amountCents,businessId:Number(this.config.storeId),currency:e.currency,displayId:e.displayId,orderReferenceId:e.orderRef,referenceId:e.originalTransactionId};try{let n=await this.worldlineApi.createRefund(t),s=this.extractOperationId(n.data);if(this.currentOperationId=s,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:s});let i=await this.waitForPaymentCompletion(s,e.orderRef,R.PaymentEventType.RefundStatusChanged,this.abortController.signal);return this.currentOperationId=null,i}catch(n){throw this.currentOperationId=null,n instanceof l?n:this.mapWorldlineRequestError(n,"Failed to refund Worldline transaction")}}async verifyFinalStatus(e,r){try{let{data:t}=await this.paymentApi.getPaymentStatus({businessId:Number(this.config.storeId),orderId:e.orderRef,provider:this.paymentProvider,referenceId:r});return this.handlePaymentStatus(t)}catch(t){throw this.mapWorldlineRequestError(t,"Failed to verify final Worldline status")}}abort(){this.abortController?.abort()}async waitForPaymentCompletion(e,r,t,n){let s=`worldline.requests.${e}`;return new Promise((i,o)=>{let c=!1,u=()=>{c=!0,typeof m=="function"&&m(),clearTimeout(y)},d=()=>{u(),o(new l("CANCELLED","Transaction cancelled"))};n.addEventListener("abort",d);let m=this.messaging.subscribe(s,t,p=>{c||p.status===R.SimplePaymentStatus.Pending||(u(),n.removeEventListener("abort",d),i(this.handlePaymentStatus(p)))}),y=setTimeout(async()=>{if(!(c||n.aborted))try{let p=await this.pollOrderStatus(e,r,this.config.storeId,n);i(this.handlePaymentStatus(p))}catch(p){o(new l("TIMEOUT","Payment timed out and polling failed",p))}finally{n.removeEventListener("abort",d),u()}},1e4)})}async pollOrderStatus(e,r,t,n){let o=Date.now()+12e4;for(;Date.now()<o;){if(n.aborted)throw new Error("Aborted");try{let{data:c}=await this.paymentApi.getPaymentStatus({businessId:Number(t),orderId:r,provider:this.paymentProvider,referenceId:e});if(n.aborted)throw new Error("Aborted");if(c.status!==R.SimplePaymentStatus.Pending)return c}catch(c){if(c instanceof Error&&c.message==="Aborted")throw c}await new Promise(c=>{let u=()=>{clearTimeout(d),c(void 0)};n.addEventListener("abort",u,{once:!0});let d=setTimeout(()=>{n.removeEventListener("abort",u),c(void 0)},2e3)})}throw new Error("Payment verification timed out.")}handlePaymentStatus(e){let r=e.status===R.SimplePaymentStatus.Success,t=e.status===R.SimplePaymentStatus.Pending,n={success:r,status:r?"SUCCESS":t?"PENDING":"FAILED",orderId:e.orderId,errorCode:e.error?.code||(r||t?"":R.PaymentFailureCode.SystemUnknown),errorMessage:e.error?.message||(r||t?"":"Transaction failed without error details")};return e.transactionId&&(n.transactionId=e.transactionId),e.error?.referenceError&&(n.errorReference=e.error.referenceError),e.transaction&&(n.transaction=e.transaction),n}extractOperationId(e){let r=typeof e=="object"&&e!==null&&"operationId"in e&&typeof e.operationId=="string"?e.operationId:null;if(!r)throw new Error("operationId is missing from response.");return r}mapWorldlineRequestError(e,r){if((0,W.isAxiosError)(e)){if(e.response?.status===400||e.response?.status===409)return new l("TERMINAL_BUSY",r,e);if(e.response?.status===404)return new l("TERMINAL_OFFLINE",r,e)}return new l("NETWORK_ERROR",r,e)}};var F=class a{strategy;axios;messaging;timeoutMs;logger;_currentState="IDLE";_listeners=[];_cancellationIntent=!1;_currentSessionId;_autoResetTimer;autoResetOptions;appToAppConfig;paymentSessionConfig;static TERMINAL_STATES=["SUCCESS","FAILED","INTERNAL_ERROR"];static RESTING_STATES=["IDLE",...a.TERMINAL_STATES];static CANCEL_VERIFY_TIMEOUT_MS=5e3;constructor(e,r,t,n={},s){this.axios=e,this.messaging=r,this.logger=n.logger,this.timeoutMs=n.timeoutMs||3e4,this.autoResetOptions=n.autoResetOnPaymentComplete,this.appToAppConfig=n.appToApp,this.paymentSessionConfig=n.paymentSession,this.strategy=s??this.resolveStrategy(t)}get version(){return M}get currentState(){return this._currentState}generateErrorResult(e,r,t){return{success:!1,status:"ERROR",errorCode:this.normalizeErrorCode(r),errorMessage:t,orderId:e}}normalizeErrorCode(e){return e?e.includes(".")?e:{CANCELLED:I.PaymentFailureCode.PaymentCancelledByUser,DECLINED:I.PaymentFailureCode.PaymentDeclined,TERMINAL_BUSY:I.PaymentFailureCode.TerminalBusy,TERMINAL_OFFLINE:I.PaymentFailureCode.TerminalOffline,TIMEOUT:I.PaymentFailureCode.TerminalTimeout,NETWORK_ERROR:I.PaymentFailureCode.SystemProviderError,STRATEGY_ERROR:I.PaymentFailureCode.SystemProviderError,MISSING_CONFIG:I.PaymentFailureCode.SystemUnknown,INVALID_AMOUNT:I.PaymentFailureCode.SystemUnknown,UNKNOWN:I.PaymentFailureCode.SystemUnknown}[e]??I.PaymentFailureCode.SystemUnknown:I.PaymentFailureCode.SystemUnknown}subscribe=e=>(this._listeners.push(e),e(this._currentState),()=>{this._listeners=this._listeners.filter(r=>r!==e)});transitionTo(e){if(this._currentState===e)return;if(e==="IDLE"){this.cancelAutoReset(),this._currentState=e,this._listeners.forEach(t=>t(e));return}if(a.TERMINAL_STATES.includes(this._currentState)){let t=`Invalid State Transition: Attempted to move from terminal state ${this._currentState} to ${e}`;throw this.logger?.error(t),this._currentState!=="INTERNAL_ERROR"&&(this._currentState="INTERNAL_ERROR",this._listeners.forEach(n=>n(this._currentState))),new l("UNKNOWN",t)}this._currentState=e,a.TERMINAL_STATES.includes(e)&&this.scheduleAutoReset(e),this._listeners.forEach(t=>t(e))}_resetScheduledAt;get nextAutoResetAt(){return this._resetScheduledAt}cancelAutoReset(){this._autoResetTimer&&(clearTimeout(this._autoResetTimer),this._autoResetTimer=void 0),this._resetScheduledAt=void 0}scheduleAutoReset(e){if(!this.autoResetOptions)return;let t=e==="SUCCESS"?this.autoResetOptions.successDelayMs??5e3:this.autoResetOptions.failureDelayMs??5e3;this.logger?.info(`Scheduling auto-reset to IDLE in ${t}ms`),this._resetScheduledAt=Date.now()+t,this._autoResetTimer=setTimeout(()=>{this.logger?.info("Auto-reset triggered"),this.reset()},t)}resolveStrategy(e){switch(e.provider){case I.PaymentProvider.Nets:return new w(this.axios,this.messaging,e);case I.PaymentProvider.Worldline:return new L(this.axios,this.messaging,e);case I.PaymentProvider.Viva:return this.appToAppConfig?.enabled?new D(this.axios,this.messaging,e,this.appToAppConfig):this.paymentSessionConfig?.enabled?new O(this.axios,this.messaging,e):new A(this.axios,this.messaging,e);default:return new A(this.axios,this.messaging,e)}}initiateTransaction=async(e,r)=>{let t=r??{},n=e.orderRef;if(!a.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(e.orderRef,"UNKNOWN","A transaction is already in progress");let i=Date.now();if(this._cancellationIntent=!1,this._currentSessionId=void 0,this.transitionTo("IDLE"),e.amountCents<=0)return this.generateErrorResult(e.orderRef,"INVALID_AMOUNT","Amount must be greater than 0");try{let o=(m,y)=>{y?.sessionId&&(this._currentSessionId=y.sessionId),m!=="FAILED"&&(this.transitionTo(m),this.fireStateCallback(m,t,n))},c=this.strategy.processPayment(e,o),d=(this.strategy.getExecutionMode?.()??"managed")==="callback_driven"?await c:await Promise.race([c,new Promise((m,y)=>{setTimeout(()=>{y(new l("TIMEOUT","Transaction timed out"))},this.timeoutMs)})]);if(d.success)this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(d));else{if(this._cancellationIntent)return await this.handleTransactionError(e,new Error("Aborted after resolution"),t);this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(d))}return this.logger?.info("Transaction completed successfully",{orderId:e.orderRef,durationMs:Date.now()-i}),d}catch(o){return this.logger?.warn("Transaction interrupted. Handling final status...",{error:o}),await this.handleTransactionError(e,o,t)}};async handleTransactionError(e,r,t={}){let n=r instanceof l&&(r.code==="TIMEOUT"||r.code===I.PaymentFailureCode.PaymentTimeout);if(!this._cancellationIntent&&!n&&(this.transitionTo("VERIFYING"),this.safeFireCallback(()=>t.onVerifying?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId}))),this._cancellationIntent){try{if(this._currentSessionId){let i=await this.strategy.verifyFinalStatus(e,this._currentSessionId,a.CANCEL_VERIFY_TIMEOUT_MS);if(i.success)return this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(i)),i}}catch(i){this.logger?.warn("Final status verification failed during cancellation",{err:i})}return this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onCancelled?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId})),{success:!1,status:"CANCELLED",errorCode:this.normalizeErrorCode("CANCELLED"),orderId:e.orderRef,...this._currentSessionId?{transactionId:this._currentSessionId}:{}}}let s;if(this.strategy.abort(),this._currentSessionId)try{let i=await this.strategy.verifyFinalStatus(e,this._currentSessionId);if(i.success)return this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(i)),i;s=n&&i.status==="PENDING"?this.buildErrorResultFromException(e.orderRef,r):i}catch(i){this.logger?.warn("Failed to get detailed error from verifyFinalStatus",{verifyErr:i}),s=this.buildErrorResultFromException(e.orderRef,i)}else s=this.buildErrorResultFromException(e.orderRef,r);return this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(s)),s}buildErrorResultFromException(e,r){return r instanceof l?this.generateErrorResult(e,r.code,r.message):this.generateErrorResult(e,"UNKNOWN",r instanceof Error?r.message:"Unknown fatal error")}fireStateCallback(e,r,t){let n={orderRef:t,refPaymentId:this._currentSessionId};switch(e){case"CONNECTING":this.safeFireCallback(()=>r.onConnecting?.(n));break;case"REQUIRES_INPUT":this.safeFireCallback(()=>r.onRequiresInput?.(n));break;case"PROCESSING":this.safeFireCallback(()=>r.onProcessing?.(n));break}}safeFireCallback(e){try{e()}catch(r){this.logger?.warn("Callback execution failed",{error:r})}}cancel=async()=>{if(this.logger?.info("Attempting cancellation"),a.TERMINAL_STATES.includes(this._currentState))return this.logger?.warn("Cannot cancel: Transaction already in terminal state",{state:this._currentState}),!1;if(!this._currentSessionId&&this._currentState==="IDLE")return this.logger?.warn("Cannot cancel: No active session to cancel",{state:this._currentState}),!1;this._cancellationIntent=!0,this.transitionTo("VERIFYING");try{return await this.strategy.cancelTransaction(r=>this.transitionTo(r))}catch(e){return this.logger?.error("Cancellation command failed",e),!1}};reset=()=>{a.TERMINAL_STATES.includes(this._currentState)&&(this._currentSessionId=void 0,this._cancellationIntent=!1,this.transitionTo("IDLE"))};refund=async(e,r)=>{let t=r??{};if(this.logger?.info("Initiating refund",{orderRef:e.orderRef}),this._currentSessionId=void 0,this._cancellationIntent=!1,!a.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(e.orderRef,"UNKNOWN","A transaction is already in progress");this.transitionTo("IDLE");try{let s=(o,c)=>{c?.sessionId&&(this._currentSessionId=c.sessionId),o!=="FAILED"&&(this.transitionTo(o),this.fireStateCallback(o,t,e.orderRef))},i=await this.strategy.refundTransaction(e,s);return i.success?(this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(i))):this._cancellationIntent||i.status==="CANCELLED"?(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onCancelled?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId}))):(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(i))),this.logger?.info("Refund completed",{success:i.success,orderRef:e.orderRef}),i}catch(s){if(this.logger?.error("Refund failed",s),this._cancellationIntent){try{if(this._currentSessionId){let o=await this.strategy.verifyFinalStatus(e,this._currentSessionId);return o.success?(this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(o)),o):o.status==="CANCELLED"?(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onCancelled?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId})),o):(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(o)),o)}}catch(o){this.logger?.warn("Refund final status verification failed",{verifyError:o})}return this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onCancelled?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId})),{success:!1,status:"CANCELLED",errorCode:this.normalizeErrorCode("CANCELLED"),orderId:e.orderRef,...this._currentSessionId?{transactionId:this._currentSessionId}:{}}}this.transitionTo("FAILED");let i=this.generateErrorResult(e.orderRef,"UNKNOWN",s instanceof Error?s.message:"Refund failed");return this.safeFireCallback(()=>t.onError?.(i)),i}};revert=async(e,r)=>{let t=r??{};if(this.logger?.info("Reverting payment",{orderRef:e.orderRef}),this._currentSessionId=e.originalTransactionId,this._cancellationIntent=!1,!a.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(e.orderRef,"UNKNOWN","A transaction is already in progress");let n=this.strategy.revertTransaction?.bind(this.strategy);if(!n)return this.generateErrorResult(e.orderRef,"STRATEGY_ERROR","Revert is not supported by the active payment strategy");this.transitionTo("CONNECTING");try{let s=await n(e);return this.settleSingleShot(s,e.orderRef,t),s}catch(s){return this.logger?.error("Revert failed",s),this.failSingleShot(e.orderRef,s,"Revert failed",t)}};settleSingleShot(e,r,t){e.success?(this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(e))):e.status==="CANCELLED"?(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onCancelled?.({orderRef:r,refPaymentId:this._currentSessionId}))):(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(e)))}failSingleShot(e,r,t,n){let s=this.generateErrorResult(e,"NETWORK_ERROR",r instanceof Error?r.message:t);return this.transitionTo("FAILED"),this.safeFireCallback(()=>n.onError?.(s)),s}};var G=(n=>(n.CONNECTING="CONNECTING",n.CONNECTED="CONNECTED",n.OFFLINE="OFFLINE",n.DISCONNECTED="DISCONNECTED",n))(G||{});0&&(module.exports={AppReaderStatus,MunchiPaymentSDK,PaymentInteractionState,SdkPaymentStatus});
|
|
1
|
+
"use strict";var k=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var z=Object.prototype.hasOwnProperty;var j=(o,e)=>{for(var n in e)k(o,n,{get:e[n],enumerable:!0})},X=(o,e,n,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of $(e))!z.call(o,r)&&r!==n&&k(o,r,{get:()=>e[r],enumerable:!(t=Q(e,r))||t.enumerable});return o};var H=o=>X(k({},"__esModule",{value:!0}),o);var ue={};j(ue,{AppReaderStatus:()=>B,MunchiPaymentSDK:()=>U,PaymentInteractionState:()=>E,SdkPaymentStatus:()=>T});module.exports=H(ue);var h=require("@munchi_oy/core");var K="1.11.1";var l=class o extends Error{code;rawError;constructor(e,n,t){super(n),this.name="PaymentSDKError",this.code=e,this.rawError=t,Object.setPrototypeOf(this,o.prototype)}};var A=require("@munchi_oy/core");var T=(i=>(i.PENDING="PENDING",i.SUCCESS="SUCCESS",i.APPROVED="APPROVED",i.FAILED="FAILED",i.CANCELLED="CANCELLED",i.ERROR="ERROR",i))(T||{}),E=(c=>(c.IDLE="IDLE",c.CONNECTING="CONNECTING",c.REQUIRES_INPUT="REQUIRES_INPUT",c.PROCESSING="PROCESSING",c.SUCCESS="SUCCESS",c.FAILED="FAILED",c.INTERNAL_ERROR="INTERNAL_ERROR",c.VERIFYING="VERIFYING",c))(E||{});var m=require("@munchi_oy/core");function W(o){throw new l("UNKNOWN",`Unhandled payment session status: ${String(o)}`)}function C(o){return{success:!1,status:"PENDING",orderId:o,errorCode:"",errorMessage:""}}function D(o,e){switch(o.status){case m.PaymentSessionStatus.Initiated:case m.PaymentSessionStatus.Processing:case m.PaymentSessionStatus.Voiding:case m.PaymentSessionStatus.Refunding:case m.PaymentSessionStatus.Dispatched:return C(e);case m.PaymentSessionStatus.Success:case m.PaymentSessionStatus.Closed:{let n={success:!0,status:"SUCCESS",orderId:e,errorCode:"",errorMessage:""};return o.providerTransactionId&&(n.transactionId=o.providerTransactionId),n}case m.PaymentSessionStatus.VoidFailed:case m.PaymentSessionStatus.Failed:{let n={success:!1,status:"FAILED",orderId:e,errorCode:o.errorCode||m.PaymentFailureCode.SystemUnknown,errorMessage:o.errorMessage||"Transaction failed without error details"};return o.providerTransactionId&&(n.transactionId=o.providerTransactionId),n}case m.PaymentSessionStatus.Cancelled:case m.PaymentSessionStatus.Voided:case m.PaymentSessionStatus.VoidPending:case m.PaymentSessionStatus.Refunded:{let n={success:!1,status:"CANCELLED",orderId:e};return o.errorCode&&(n.errorCode=o.errorCode),o.errorMessage&&(n.errorMessage=o.errorMessage),o.providerTransactionId&&(n.transactionId=o.providerTransactionId),n}default:return W(o.status)}}function V(o,e){switch(o.status){case m.PaymentSessionStatus.Initiated:case m.PaymentSessionStatus.Processing:case m.PaymentSessionStatus.Dispatched:case m.PaymentSessionStatus.Voiding:case m.PaymentSessionStatus.VoidPending:case m.PaymentSessionStatus.Success:case m.PaymentSessionStatus.Closed:return C(e);case m.PaymentSessionStatus.Refunded:case m.PaymentSessionStatus.Voided:case m.PaymentSessionStatus.Refunding:{let n={success:!0,status:"SUCCESS",orderId:e,errorCode:"",errorMessage:""};return o.providerTransactionId&&(n.transactionId=o.providerTransactionId),n}case m.PaymentSessionStatus.Failed:case m.PaymentSessionStatus.VoidFailed:{let n={success:!1,status:"FAILED",orderId:e,errorCode:o.errorCode||m.PaymentFailureCode.SystemUnknown,errorMessage:o.errorMessage||"Reversal failed without error details"};return o.providerTransactionId&&(n.transactionId=o.providerTransactionId),n}case m.PaymentSessionStatus.Cancelled:{let n={success:!1,status:"CANCELLED",orderId:e};return o.errorCode&&(n.errorCode=o.errorCode),o.errorMessage&&(n.errorMessage=o.errorMessage),o.providerTransactionId&&(n.transactionId=o.providerTransactionId),n}default:return W(o.status)}}var _=class o{constructor(e,n,t){this.messaging=n;this.config=t;this.sessionApi=new A.PaymentSessionApi(void 0,"",e)}static POLLING_DURATION_MS=18e4;static POLLING_INTERVAL_MS=1e3;static VERIFY_DURATION_MS=3e4;static INITIAL_POLL_DELAY_MS=1e4;sessionApi;abortController=null;idempotencyKey=null;idempotencyOrderRef=null;currentClientToken=null;async processPayment(e,n){this.abortController=new AbortController,(this.idempotencyKey===null||this.idempotencyOrderRef!==e.orderRef)&&(this.idempotencyKey=this.generateIdempotencyKey(),this.idempotencyOrderRef=e.orderRef),this.currentClientToken=null,n("CONNECTING");let t={amount:e.amountCents,businessId:Number(this.config.storeId),orderId:e.orderRef};e.splitContext!==void 0&&(t.splitContext=e.splitContext);try{let{data:r}=await this.sessionApi.initiateNetsSession(t,this.idempotencyKey);this.currentClientToken=r.clientToken;let s=this.abortController.signal;if(s.aborted)throw new Error("Aborted");n("REQUIRES_INPUT",{sessionId:r.sessionId});let i=await this.waitForCompletion(r.clientToken,r.sessionId,e,s);return i?this.finalize(i):(await this.armCancel(r.clientToken),C(e.orderRef))}catch(r){throw r instanceof l?r:new l("TERMINAL_BUSY","Failed to create Nets payment session",r)}}async verifyFinalStatus(e,n,t){if(!this.currentClientToken)throw new l("NETWORK_ERROR","No active payment session to verify");let r=await this.pollUntilTerminal(this.currentClientToken,e.orderRef,void 0,t??o.VERIFY_DURATION_MS);return this.finalize(r??C(e.orderRef))}async cancelTransaction(e){if(!this.currentClientToken)return!1;try{await this.sessionApi.cancelSession(this.currentClientToken)}catch(n){throw new l("NETWORK_ERROR","Failed to cancel Nets payment session",n)}return this.abortController?.abort(),this.resetIdempotencyKey(),!0}async refundTransaction(e,n){this.abortController=new AbortController,n("CONNECTING");let t={sessionId:e.originalTransactionId,amount:e.amountCents};try{let{data:r}=await this.sessionApi.refundNetsSession(t);return await this.settleReversal(r,e.orderRef,this.abortController.signal,!0,n)}catch(r){throw r instanceof l?r:new l("NETWORK_ERROR","Failed to refund Nets transaction",r)}}async revertTransaction(e,n){this.abortController=new AbortController;let t={sessionId:e.originalTransactionId};this.currentClientToken=null;try{let{data:r}=await this.sessionApi.revertNetsSession(t);return this.currentClientToken=r.clientToken,await this.settleReversal(r,e.orderRef,this.abortController.signal,r.requiresCardTap,n)}catch(r){throw r instanceof l?r:new l("NETWORK_ERROR","Failed to revert Nets transaction",r)}}shouldVerifyAfterCancel(){return!1}abort(){this.abortController?.abort()}async settleReversal(e,n,t,r,s){let i=V(e,n);return i.status!=="PENDING"?i:(r&&s?.("REQUIRES_INPUT",{sessionId:e.sessionId}),await this.pollUntilTerminal(e.clientToken,n,t,o.POLLING_DURATION_MS,V)??C(n))}async pollUntilTerminal(e,n,t,r,s=D){let i=Date.now()+r;for(;Date.now()<i;){if(t?.aborted)throw new Error("Aborted");let a;try{a=(await this.sessionApi.getPaymentSession(e)).data}catch(c){if(c instanceof Error&&c.message==="Aborted")throw c}if(t?.aborted)throw new Error("Aborted");if(a){let c=s(a,n);if(c.status!=="PENDING")return c}await this.delay(o.POLLING_INTERVAL_MS,t)}}waitForCompletion(e,n,t,r){let s=`nets.requests.${n}`;return new Promise((i,a)=>{let c=!1,u=()=>{c=!0,typeof y=="function"&&y(),clearTimeout(f),r.removeEventListener("abort",d)},d=()=>{u(),a(new Error("Aborted"))};r.addEventListener("abort",d);let y=this.messaging.subscribe(s,A.PaymentEventType.StatusChanged,p=>{c||p.status!==A.SimplePaymentStatus.Pending&&(u(),i(this.mapStatusDto(p,t)))}),f=setTimeout(()=>{c||this.pollUntilTerminal(e,t.orderRef,r,o.POLLING_DURATION_MS).then(p=>{c||(u(),i(p))},p=>{c||(u(),a(p))})},o.INITIAL_POLL_DELAY_MS)})}mapStatusDto(e,n){let t=e.status===A.SimplePaymentStatus.Success,r={success:t,status:t?"SUCCESS":"FAILED",orderId:n.orderRef};return e.transactionId&&(r.transactionId=e.transactionId),e.transaction&&(r.transaction=e.transaction),e.error?.code&&(r.errorCode=e.error.code),e.error?.message&&(r.errorMessage=e.error.message),r}finalize(e){return e.status!=="PENDING"&&this.resetIdempotencyKey(),e}resetIdempotencyKey(){this.idempotencyKey=null,this.idempotencyOrderRef=null}armCancel(e){return this.sessionApi.cancelSession(e).then(()=>{},()=>{})}generateIdempotencyKey(){let e=globalThis.crypto;return e?.randomUUID?e.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,n=>{let t=Math.random()*16|0;return(n==="x"?t:t&3|8).toString(16)})}delay(e,n){return new Promise(t=>{let r=()=>{clearTimeout(s),t()};n&&n.addEventListener("abort",r,{once:!0});let s=setTimeout(()=>{n&&n.removeEventListener("abort",r),t()},e)})}};var S=require("@munchi_oy/core");var O=class{constructor(e,n,t){this.messaging=n;this.config=t;this.api=new S.PaymentApi(void 0,"",e)}api;abortController=null;currentRequestId=null;paymentProvider=S.PaymentProviderEnum.Nets;async processPayment(e,n){this.abortController=new AbortController,n("CONNECTING");let t={amount:e.amountCents,businessId:Number(this.config.storeId),referenceId:e.orderRef,currency:e.currency,displayId:e.displayId,options:{allowPinBypass:!0,transactionType:S.TransactionType.Purchase}};try{let{data:r}=await this.api.initiateNetsTerminalTransaction(t),s=r.connectCloudRequestId;if(!s)throw new Error("connectCloudRequestId is missing from response.");if(this.currentRequestId=s,this.abortController.signal.aborted)throw new Error("Aborted");n("REQUIRES_INPUT",{sessionId:s});let i=await this.waitForPaymentCompletion(s,e.orderRef,this.abortController.signal);return this.currentRequestId=null,i}catch(r){throw this.currentRequestId=null,r instanceof l?r:new l("TERMINAL_BUSY","Failed to create Nets Intent",r)}}async waitForPaymentCompletion(e,n,t){let r=`nets.requests.${e}`,s=S.PaymentEventType.StatusChanged;return new Promise((i,a)=>{let c=!1,u=()=>{c=!0,typeof y=="function"&&y(),clearTimeout(f)},d=()=>{u(),a(new l("CANCELLED","Transaction cancelled"))};t.addEventListener("abort",d);let y=this.messaging.subscribe(r,s,p=>{c||p.status===S.SimplePaymentStatus.Pending||(u(),t.removeEventListener("abort",d),i(this.handleSuccess(p)))}),f=setTimeout(async()=>{if(!(c||t.aborted))try{let p=await this.pollOrderStatus(e,n,this.config.storeId,t);i(this.handleSuccess(p))}catch(p){a(new l("TIMEOUT","Payment timed out and polling failed",p))}finally{t.removeEventListener("abort",d),u()}},1e4)})}async pollOrderStatus(e,n,t,r){let c=Date.now()+12e4;for(;Date.now()<c;){if(r.aborted)throw new Error("Aborted");try{let{data:u}=await this.api.getPaymentStatus({businessId:Number(t),orderId:n,provider:this.paymentProvider,referenceId:e});if(r.aborted)throw new Error("Aborted");if(u.status!==S.SimplePaymentStatus.Pending)return u}catch(u){if(u instanceof Error&&u.message==="Aborted")throw u}await new Promise(u=>{let d=()=>{clearTimeout(y),u(void 0)};r.addEventListener("abort",d,{once:!0});let y=setTimeout(()=>{r.removeEventListener("abort",d),u(void 0)},2e3)})}throw new Error("Payment verification timed out.")}async cancelTransaction(e){if(!this.currentRequestId)return!1;let n={requestId:this.currentRequestId,businessId:Number(this.config.storeId)};try{return await this.api.cancelNetsTerminalTransaction(n),this.abortController?.abort(),this.currentRequestId=null,!0}catch{return!1}}async refundTransaction(e,n){try{this.abortController=new AbortController;let t={amount:e.amountCents,businessId:Number(this.config.storeId),currency:e.currency,displayId:e.displayId,referenceId:e.orderRef,options:{allowPinBypass:!0,transactionType:S.TransactionType.ReturnOfGoods}},{data:r}=await this.api.initiateNetsTerminalTransaction(t),s=r.connectCloudRequestId;if(!s)throw new Error("connectCloudRequestId is missing from response.");if(this.currentRequestId=s,this.abortController.signal.aborted)throw new Error("Aborted");n("REQUIRES_INPUT",{sessionId:s});let i=await this.waitForPaymentCompletion(s,e.orderRef,this.abortController.signal);return this.currentRequestId=null,i}catch(t){throw this.currentRequestId=null,t instanceof l||t instanceof l?t:new l("NETWORK_ERROR","Failed to refund Nets transaction",t)}}async verifyFinalStatus(e,n){try{let{data:t}=await this.api.getPaymentStatus({businessId:Number(this.config.storeId),orderId:e.orderRef,provider:this.paymentProvider,referenceId:n});return this.handleSuccess(t)}catch(t){throw new l("NETWORK_ERROR","Failed to verify final Nets status",t)}}handleSuccess(e){let n=e.status===S.SimplePaymentStatus.Success,t=e.status===S.SimplePaymentStatus.Pending,r={success:n,status:n?"SUCCESS":t?"PENDING":"FAILED",orderId:e.orderId,transaction:e.transaction};return e.transactionId&&(r.transactionId=e.transactionId),e.error?.code&&(r.errorCode=e.error.code),e.error?.message&&(r.errorMessage=e.error.message),r}abort(){this.abortController?.abort()}};var I=require("@munchi_oy/core");var L=o=>{if(!o)return 0;let e=Number.parseInt(o,10);return Number.isFinite(e)?e:0},G=o=>{if(!o)return new Date().toISOString();let e=new Date(o);return Number.isNaN(e.getTime())?new Date().toISOString():e.toISOString()};var ee="vivapayclient://pay/v1",te="abort",ne="sale",Y="transactionDetails",re=4e3,se="534287",ie="38",oe="493591",ae="497439",ce=[oe,ae],le=["CREDIT","PREPAID","CORPORATE"],x=class{constructor(e,n,t,r){this.config=t;this.appToAppConfig=r;this.sessionApi=new I.PaymentSessionApi(void 0,"",e)}sessionApi;abortController=null;currentClientTransactionId=null;currentIsvClientTransactionId=null;currentCurrency=null;currentOrderRef=null;currentSourceTerminalId=null;latestResult=null;wasCancelled=!1;getExecutionMode(){return"callback_driven"}async processPayment(e,n){if(!this.appToAppConfig.enabled)throw new l("STRATEGY_ERROR","Viva app-to-app is not enabled");n("CONNECTING");try{let{data:t}=await this.sessionApi.initiateVivaA2aSession(this.buildCreatePaymentPayload(e));return await this.runAction(ne,this.buildLaunchParams(t),e,n)}catch(t){throw new l("NETWORK_ERROR","Failed to create Viva app-to-app payment",t)}}async cancelTransaction(e){if(!this.currentClientTransactionId)return!1;let n=await this.lookupTransactionDetails();if(n)return this.latestResult=n,this.wasCancelled=n.status==="CANCELLED",this.abortController?.abort(),!0;try{await this.appToAppConfig.adapter.openUrl(this.buildActionUrl(te,{}))}catch(t){throw this.abortController?.abort(),new l("NETWORK_ERROR","Failed to launch Viva abort flow",t)}return this.wasCancelled=!0,this.abortController?.abort(),!0}async refundTransaction(e,n){try{let t={sessionId:e.originalTransactionId,amount:e.amountCents},{data:r}=await this.sessionApi.refundVivaSession(t),s=r.status===I.PaymentSessionStatus.Refunded||r.status===I.PaymentSessionStatus.Refunding,i={success:s,status:s?"SUCCESS":"FAILED",orderId:e.orderRef,transactionId:r.providerTransactionId??r.sessionId};return s||(r.errorCode&&(i.errorCode=r.errorCode),r.errorMessage&&(i.errorMessage=r.errorMessage)),i}catch(t){throw new l("NETWORK_ERROR","Failed to refund Viva transaction",t)}}async verifyFinalStatus(e,n){return this.latestResult?this.latestResult:this.wasCancelled?{success:!1,status:"CANCELLED",orderId:this.currentOrderRef??n,errorCode:I.PaymentFailureCode.PaymentCancelledByUser,errorMessage:"Transaction was cancelled",transactionId:n}:{success:!1,status:"PENDING",orderId:this.currentOrderRef??n,transactionId:n}}abort(){this.abortController?.abort()}async runAction(e,n,t,r){if(!this.appToAppConfig.enabled)throw new l("STRATEGY_ERROR","Viva app-to-app is not enabled");this.abortController=new AbortController,this.latestResult=null,this.wasCancelled=!1,this.currentCurrency=t.currency,this.currentOrderRef=t.orderRef,this.currentSourceTerminalId=n.sourceTerminalId??n.tid??null,this.currentClientTransactionId=n.clientTransactionId??null,this.currentIsvClientTransactionId=n.ISV_clientTransactionId??null;let s=this.currentClientTransactionId?{sessionId:this.currentClientTransactionId}:void 0;return new Promise((i,a)=>{let c=(y,f)=>{y?.(),this.abortController?.signal.removeEventListener("abort",f)},u=()=>{c(d,u),a(new Error("Aborted"))},d=this.appToAppConfig.adapter.subscribe(y=>{if(this.abortController?.signal.aborted)return;let f=this.parseCallbackUrl(y);f&&this.matchesKnownTransactionId(f.rawParams)&&(this.latestResult=f.result,this.wasCancelled=f.result.status==="CANCELLED",this.currentClientTransactionId=null,this.currentIsvClientTransactionId=null,this.currentCurrency=null,this.currentOrderRef=null,this.currentSourceTerminalId=null,c(d,u),i(f.result))});this.abortController?.signal.addEventListener("abort",u),r("REQUIRES_INPUT",s),this.appToAppConfig.adapter.openUrl(this.buildActionUrl(e,n)).then(()=>{this.abortController?.signal.aborted}).catch(y=>{c(d,u),this.currentClientTransactionId=null,this.currentIsvClientTransactionId=null,this.currentCurrency=null,this.currentOrderRef=null,this.currentSourceTerminalId=null,a(new l("NETWORK_ERROR","Failed to launch Viva app",y))})})}buildCreatePaymentPayload(e){let n=e.options??{},t={amount:e.amountCents,referenceId:e.orderRef,businessId:Number(this.config.storeId),currency:e.currency,displayId:e.displayId,showReceipt:!1,showTransactionResult:!1};return n.tipAmount!==void 0&&(t.tipAmount=n.tipAmount),e.splitContext!==void 0&&(t.splitContext=e.splitContext),t}buildLaunchParams(e){let n={};return Object.entries(e).forEach(([t,r])=>{r!==void 0&&(t==="clientToken"||t==="sessionId"||(n[t]=String(r)))}),n}buildActionUrl(e,n){let t=new URLSearchParams({action:e,appId:this.appToAppConfig.appId,callback:this.resolveCallbackQueryParam()});return Object.entries(n).forEach(([r,s])=>{t.set(r,s)}),`${ee}?${t.toString()}`}parseCallbackUrl(e){if(!this.matchesCallbackBase(e))return null;let n=new URL(e),t=Object.fromEntries(n.searchParams.entries()),r=this.isSuccessfulCallback(t),s=this.isCancelledCallback(t),i=this.resolveFailureCode(t,s),a={success:r,status:r?"SUCCESS":s?"CANCELLED":"FAILED",orderId:this.currentOrderRef??t.clientTransactionId??"unknown",errorCode:r?"":i,errorMessage:r?"":t.message??"Transaction failed without error details"};r&&(a.transaction=this.mapCallbackToTransaction(t));let c=t.transactionId??t.orderCode??t.clientTransactionId,u=t.errorCode??this.extractErrorReferenceFromMessage(t.message)??t.referenceNumber??t.tid??t.rrn;return c&&(a.transactionId=c),u&&(a.errorReference=u),{rawParams:t,result:a}}matchesCallbackBase(e){let n=new URL(e),t=this.appToAppConfig.callbackUrl;if(!t.includes("://")){let s=t.replace(/:$/,"");return n.protocol===`${s}:`}let r=new URL(t);return n.protocol===r.protocol&&n.hostname===r.hostname&&n.pathname===r.pathname}resolveCallbackQueryParam(){if(this.appToAppConfig.callbackParamFormat!=="scheme-only")return this.appToAppConfig.callbackUrl;let e=this.appToAppConfig.callbackUrl;return e.includes("://")?new URL(e).protocol.replace(/:$/,""):e.replace(/:$/,"")}matchesKnownTransactionId(e){let n=[this.currentClientTransactionId,this.currentIsvClientTransactionId].filter(r=>!!r);if(n.length===0)return!0;let t=[e.clientTransactionId,e.ISV_clientTransactionId].filter(r=>!!r);return t.length===0?!0:t.some(r=>n.includes(r))}resolveFailureCode(e,n){if(n)return I.PaymentFailureCode.PaymentCancelledByUser;let t=e.errorCode;if(t?.includes("."))return t;if(this.isTransactionDetailsAction(e)&&(e.transactionType??"").toLowerCase().includes("abort"))return I.PaymentFailureCode.SystemUnknown;let r=(e.message??"").toLowerCase(),s=(e.status??"").toLowerCase();return r.includes("declined")||s==="declined"||s==="fail"||s==="failed"||s==="failure"?I.PaymentFailureCode.PaymentDeclined:I.PaymentFailureCode.SystemUnknown}isSuccessfulCallback(e){let n=(e.status??"").toLowerCase();return this.isTransactionDetailsAction(e)?n!=="success"?!1:!(e.transactionType??"").toLowerCase().includes("abort"):n==="success"}isTransactionDetailsAction(e){return(e.action??"").toLowerCase()===Y.toLowerCase()}isCancelledCallback(e){let n=(e.status??"").toLowerCase(),t=(e.message??"").toLowerCase(),r=(e.errorCode??"").toLowerCase();return n==="cancelled"||n==="canceled"||t.includes("user_cancel")||t.includes("user cancel")||t.includes("cancelled by user")||t.includes("canceled by user")||t.includes("transaction cancelled by user")||t.includes("transaction canceled by user")||r.includes("user_cancel")||r.includes("user cancel")||r==="1000"&&(t.includes("cancelled by user")||t.includes("canceled by user"))}extractErrorReferenceFromMessage(e){return e?e.match(/\((-?\d+)\)/)?.[1]:void 0}mapCallbackToTransaction(e){let n=e.transactionId??e.orderCode??e.clientTransactionId??"unknown",t=G(e.transactionDate),r=L(e.tipAmount),s=L(e.surchargeAmount);return{amount:L(e.amount)-r-s,cardDetail:{aid:e.aid??null,applicationLabel:e.applicationLabel??null,cardNumber:e.accountNumber??"N/A",cardType:e.cardType??"N/A",issuer:e.bankId??null,orderCode:e.orderCode??null,timestamp:t,transactionId:n},createdAt:t,fees:this.buildFees(r,s),id:n,label:null,provider:I.PaymentProvider.Viva,rawData:e,referenceId:e.clientTransactionId??null,roundingDifference:0,type:this.getVivaPaymentMethodType(e)}}getVivaPaymentMethodType(e){let n=(e.applicationLabel??"").toUpperCase().trim(),r=(e.accountNumber??"").substring(0,6),s=(e.bankId??"").trim();return r===se||s===ie?I.PaymentMethod.Edenred:ce.includes(r)?I.PaymentMethod.WoltBenefit:le.some(i=>n.includes(i))?I.PaymentMethod.Credit:I.PaymentMethod.Debit}buildFees(e,n){if(!this.currentCurrency)return null;let t=[];return e>0&&t.push({taxAmount:0,total:{amount:e,currency:this.currentCurrency},type:I.FeeType.TipAmount,vatPercentage:0}),n>0&&t.push({taxAmount:0,total:{amount:n,currency:this.currentCurrency},type:I.FeeType.Surcharge,vatPercentage:0}),t.length===0?null:{parts:t}}async lookupTransactionDetails(){if(!this.currentClientTransactionId||!this.currentSourceTerminalId)return null;let e={clientTransactionId:this.currentClientTransactionId,sourceTerminalId:this.currentSourceTerminalId};return new Promise(n=>{let t=!1,r=setTimeout(()=>{t||(t=!0,s(),n(null))},re),s=this.appToAppConfig.adapter.subscribe(i=>{if(t)return;let a=this.parseCallbackUrl(i);a&&this.matchesKnownTransactionId(a.rawParams)&&(t=!0,clearTimeout(r),s(),n(a.result))});this.appToAppConfig.adapter.openUrl(this.buildActionUrl(Y,e)).catch(()=>{t||(t=!0,clearTimeout(r),s(),n(null))})})}};var P=require("@munchi_oy/core");var F=class o{constructor(e,n,t){this.messaging=n;this.config=t;this.sessionApi=new P.PaymentSessionApi(void 0,"",e)}static POLLING_DURATION_MS=18e4;static POLLING_INTERVAL_MS=1e3;static VERIFY_DURATION_MS=3e4;static INITIAL_POLL_DELAY_MS=1e4;sessionApi;abortController=null;idempotencyKey=null;idempotencyOrderRef=null;currentClientToken=null;async processPayment(e,n){this.abortController=new AbortController,(this.idempotencyKey===null||this.idempotencyOrderRef!==e.orderRef)&&(this.idempotencyKey=this.generateIdempotencyKey(),this.idempotencyOrderRef=e.orderRef),this.currentClientToken=null,n("CONNECTING");let t={amount:e.amountCents,businessId:Number(this.config.storeId),orderId:e.orderRef};e.splitContext!==void 0&&(t.splitContext=e.splitContext);try{let{data:r}=await this.sessionApi.initiateVivaSession(t,this.idempotencyKey);this.currentClientToken=r.clientToken;let s=this.abortController.signal;if(s.aborted)throw new Error("Aborted");n("REQUIRES_INPUT",{sessionId:r.sessionId});let i=await this.waitForCompletion(r.clientToken,r.sessionId,e,s);return i?this.finalize(i):(await this.armCancel(r.clientToken),C(e.orderRef))}catch(r){throw r instanceof l?r:new l("NETWORK_ERROR","Failed to create Viva payment session",r)}}async verifyFinalStatus(e,n,t){if(!this.currentClientToken)throw new l("NETWORK_ERROR","No active payment session to verify");let r=await this.pollUntilTerminal(this.currentClientToken,e,void 0,t??o.VERIFY_DURATION_MS);return this.finalize(r??C(e.orderRef))}async cancelTransaction(e){if(!this.currentClientToken)return!1;try{await this.sessionApi.cancelSession(this.currentClientToken)}catch(n){throw new l("NETWORK_ERROR","Failed to cancel Viva payment session",n)}return this.abortController?.abort(),this.resetIdempotencyKey(),!0}async refundTransaction(e,n){try{let t={sessionId:e.originalTransactionId,amount:e.amountCents},{data:r}=await this.sessionApi.refundVivaSession(t),s=r.status===P.PaymentSessionStatus.Refunded||r.status===P.PaymentSessionStatus.Refunding,i={success:s,status:s?"SUCCESS":"FAILED",orderId:e.orderRef,transactionId:r.providerTransactionId??r.sessionId};return s||(r.errorCode&&(i.errorCode=r.errorCode),r.errorMessage&&(i.errorMessage=r.errorMessage)),i}catch(t){throw new l("NETWORK_ERROR","Failed to refund Viva transaction",t)}}async revertTransaction(e){try{let n={sessionId:e.originalTransactionId},{data:t}=await this.sessionApi.revertVivaSession(n),r=t.status===P.PaymentSessionStatus.Refunded||t.status===P.PaymentSessionStatus.Refunding,s={success:r,status:r?"SUCCESS":"FAILED",orderId:e.orderRef,transactionId:t.providerTransactionId??t.sessionId};return r||(t.errorCode&&(s.errorCode=t.errorCode),t.errorMessage&&(s.errorMessage=t.errorMessage)),s}catch(n){throw new l("NETWORK_ERROR","Failed to revert Viva transaction",n)}}abort(){this.abortController?.abort()}async pollUntilTerminal(e,n,t,r){let s=Date.now()+r;for(;Date.now()<s;){if(t?.aborted)throw new Error("Aborted");let i;try{i=(await this.sessionApi.getPaymentSession(e)).data}catch(a){if(a instanceof Error&&a.message==="Aborted")throw a}if(t?.aborted)throw new Error("Aborted");if(i){let a=D(i,n.orderRef);if(a.status!=="PENDING")return a}await this.delay(o.POLLING_INTERVAL_MS,t)}}waitForCompletion(e,n,t,r){let s=`viva.${this.config.channel.toLowerCase()}.requests.${n}`;return new Promise((i,a)=>{let c=!1,u=()=>{c=!0,typeof y=="function"&&y(),clearTimeout(f),r.removeEventListener("abort",d)},d=()=>{u(),a(new Error("Aborted"))};r.addEventListener("abort",d);let y=this.messaging.subscribe(s,"payment:status-changed",p=>{c||p.status!==P.SimplePaymentStatus.Pending&&(u(),i(this.mapStatusDto(p,t)))}),f=setTimeout(()=>{c||this.pollUntilTerminal(e,t,r,o.POLLING_DURATION_MS).then(p=>{c||(u(),i(p))},p=>{c||(u(),a(p))})},o.INITIAL_POLL_DELAY_MS)})}mapStatusDto(e,n){let t=e.status===P.SimplePaymentStatus.Success,r={success:t,status:t?"SUCCESS":"FAILED",orderId:n.orderRef,errorCode:e.error?.code||(t?"":P.PaymentFailureCode.SystemUnknown),errorMessage:e.error?.message||(t?"":"Transaction failed without error details")};return e.transactionId&&(r.transactionId=e.transactionId),e.error?.referenceError&&(r.errorReference=e.error.referenceError),e.transaction&&(r.transaction=e.transaction),r}finalize(e){return e.status!=="PENDING"&&this.resetIdempotencyKey(),e}resetIdempotencyKey(){this.idempotencyKey=null,this.idempotencyOrderRef=null}armCancel(e){return this.sessionApi.cancelSession(e).then(()=>{},()=>{})}generateIdempotencyKey(){let e=globalThis.crypto;return e?.randomUUID?e.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,n=>{let t=Math.random()*16|0;return(n==="x"?t:t&3|8).toString(16)})}delay(e,n){return new Promise(t=>{let r=()=>{clearTimeout(s),t()};n&&n.addEventListener("abort",r,{once:!0});let s=setTimeout(()=>{n&&n.removeEventListener("abort",r),t()},e)})}};var g=require("@munchi_oy/core");var N=class o{constructor(e,n,t){this.messaging=n;this.config=t;this.api=new g.PaymentApi(void 0,"",e)}static INITIAL_POLL_DELAY_MS=1e4;static POLLING_DURATION_MS=18e4;static POLLING_INTERVAL_MS=2e3;static TIMEOUT_CANCEL_TIMEOUT_MS=5e3;static VERIFY_TIMEOUT_MS=1e4;static VERIFY_MAX_RETRIES=3;static VERIFY_RETRY_DELAY_MS=1500;api;abortController=null;currentSessionId=null;paymentProvider=g.PaymentProviderEnum.Viva;async processPayment(e,n){this.abortController=new AbortController,n("CONNECTING");let t={amount:e.amountCents,referenceId:e.orderRef,businessId:parseInt(this.config.storeId),currency:e.currency,displayId:e.displayId,showReceipt:!0,showTransactionResult:!0};try{let{data:r}=await this.api.initiateTerminalTransaction(t);if(this.currentSessionId=r.sessionId,this.abortController.signal.aborted)throw new Error("Aborted");n("REQUIRES_INPUT",{sessionId:r.sessionId});let s=await this.waitForPaymentCompletion(r.sessionId,e,this.abortController.signal);return this.currentSessionId=null,s}catch(r){throw this.currentSessionId=null,r instanceof l?r:new l("NETWORK_ERROR","Failed to create Viva Intent",r)}}async waitForPaymentCompletion(e,n,t){let s=`viva.${this.config.channel.toLowerCase()}.requests.${e}`,i="payment:status-changed";return new Promise((a,c)=>{let u=!1,d=()=>{u=!0,typeof f=="function"&&f(),clearTimeout(p)},y=()=>{d(),c(new Error("Aborted"))};t.addEventListener("abort",y);let f=this.messaging.subscribe(s,i,v=>{u||v.status!==g.SimplePaymentStatus.Pending&&(d(),t.removeEventListener("abort",y),a(this.handleSuccess(v)))}),p=setTimeout(async()=>{if(!(u||t.aborted))try{let v=await this.pollOrderStatus(e,n.orderRef,this.config.storeId,t);if(u)return;a(this.handleSuccess(v))}catch(v){if(u)return;if(v instanceof Error&&v.message==="Aborted"){c(v);return}try{let w=await this.recoverAfterPollingTimeout(n,e);a(w)}catch(w){c(w instanceof l?w:new l("TIMEOUT","Payment timed out and polling failed",w))}}finally{t.removeEventListener("abort",y),d()}},o.INITIAL_POLL_DELAY_MS)})}async pollOrderStatus(e,n,t,r){let i=Date.now()+o.POLLING_DURATION_MS;for(;Date.now()<i;){if(r.aborted)throw new Error("Aborted");try{let{data:a}=await this.api.getPaymentStatus({businessId:Number(t),orderId:n,provider:this.paymentProvider,referenceId:e});if(r.aborted)throw new Error("Aborted");if(a.status!==g.SimplePaymentStatus.Pending)return a}catch(a){if(a instanceof Error&&a.message==="Aborted")throw a}await new Promise(a=>{let c=()=>{clearTimeout(u),a(void 0)};r.addEventListener("abort",c,{once:!0});let u=setTimeout(()=>{r.removeEventListener("abort",c),a(void 0)},o.POLLING_INTERVAL_MS)})}throw new Error("Payment verification timed out.")}async recoverAfterPollingTimeout(e,n){return await this.cancelSessionWithTimeout(n),await this.verifyFinalStatusWithRetry(e,n)}async cancelSessionWithTimeout(e){let n;try{await Promise.race([this.cancelSession(e),new Promise((t,r)=>{n=setTimeout(()=>{r(new Error("Viva timeout cancellation timed out"))},o.TIMEOUT_CANCEL_TIMEOUT_MS)})])}catch{}finally{n&&clearTimeout(n)}}async cancelSession(e){return await this.api.cancelVivaTransactionV2({cashRegisterId:this.config.storeId,sessionId:e}),this.currentSessionId===e&&(this.currentSessionId=null),!0}async verifyFinalStatusWithRetry(e,n){let t;for(let r=1;r<=o.VERIFY_MAX_RETRIES;r++)try{let s=await Promise.race([this.verifyFinalStatus(e,n),new Promise((i,a)=>setTimeout(()=>a(new Error("Verify timed out")),o.VERIFY_TIMEOUT_MS))]);if(s.status==="PENDING"){t=new Error("Verify returned pending status"),r<o.VERIFY_MAX_RETRIES&&await new Promise(i=>setTimeout(i,o.VERIFY_RETRY_DELAY_MS));continue}return s}catch(s){t=s,r<o.VERIFY_MAX_RETRIES&&await new Promise(i=>setTimeout(i,o.VERIFY_RETRY_DELAY_MS))}throw new l(g.PaymentFailureCode.PaymentTimeout,"Payment Failed",t)}handleSuccess(e){let n=e.status===g.SimplePaymentStatus.Success,t={success:n,status:n?"SUCCESS":"FAILED",orderId:e.orderId,errorCode:e.error?.code||(n?"":g.PaymentFailureCode.SystemUnknown),errorMessage:e.error?.message||(n?"":"Transaction failed without error details")};return e.transactionId&&(t.transactionId=e.transactionId),e.error?.referenceError&&(t.errorReference=e.error.referenceError),e.transaction&&(t.transaction=e.transaction),t}async cancelTransaction(e){if(!this.currentSessionId)return!1;try{let n=this.currentSessionId;return this.currentSessionId=null,await this.api.cancelVivaTransactionV2({cashRegisterId:this.config.storeId,sessionId:n}),this.abortController?.abort(),!0}catch(n){throw this.currentSessionId=null,new l("NETWORK_ERROR","Failed to cancel Viva transaction",n)}}async verifyFinalStatus(e,n){try{let{data:t}=await this.api.getPaymentStatus({businessId:Number(this.config.storeId),orderId:e.orderRef,provider:this.paymentProvider,referenceId:n}),r=t.status===g.SimplePaymentStatus.Success,s=t.status===g.SimplePaymentStatus.Pending,i={success:r,status:r?"SUCCESS":s?"PENDING":"FAILED",orderId:t.orderId,errorCode:t.error?.code||(r||s?"":g.PaymentFailureCode.SystemUnknown),errorMessage:t.error?.message||(r||s?"":"Transaction failed without error details")};return t.transactionId&&(i.transactionId=t.transactionId),t.error?.referenceError&&(i.errorReference=t.error.referenceError),t.transaction&&(i.transaction=t.transaction),i}catch(t){throw new l("NETWORK_ERROR","Failed to verify final transaction status",t)}}async refundTransaction(e,n){try{let t={amount:e.amountCents,businessId:Number(this.config.storeId),displayId:this.config.kioskId,currency:e.currency,orderReferenceId:e.orderRef,referenceId:e.originalTransactionId},{data:r}=await this.api.refundSingleVivaTransaction(t),s=r.success;return{success:s,status:s?"SUCCESS":"FAILED",orderId:e.orderRef,transactionId:r.sessionId}}catch(t){throw new l("NETWORK_ERROR","Failed to refund Viva transaction",t)}}abort(){this.abortController?.abort()}};var R=require("@munchi_oy/core"),q=require("axios");var M=class{constructor(e,n,t){this.messaging=n;this.config=t;this.paymentApi=new R.PaymentApi(void 0,"",e),this.worldlineApi=new R.WorldlineApi(void 0,"",e)}paymentApi;worldlineApi;abortController=null;currentOperationId=null;paymentProvider=R.PaymentProviderEnum.Worldline;async processPayment(e,n){this.abortController=new AbortController,n("CONNECTING");let t={amount:e.amountCents,businessId:Number(this.config.storeId),currency:e.currency,displayId:e.displayId,referenceId:e.orderRef,showReceipt:!0,showTransactionResult:!0,...e.options&&"tipAmount"in e.options&&typeof e.options.tipAmount=="number"?{tipAmount:e.options.tipAmount}:{}};try{let r=await this.worldlineApi.createPayment(t),s=this.extractOperationId(r.data);if(this.currentOperationId=s,this.abortController.signal.aborted)throw new Error("Aborted");n("REQUIRES_INPUT",{sessionId:s});let i=await this.waitForPaymentCompletion(s,e.orderRef,R.PaymentEventType.StatusChanged,this.abortController.signal);return this.currentOperationId=null,i}catch(r){throw this.currentOperationId=null,r instanceof l?r:this.mapWorldlineRequestError(r,"Failed to create Worldline payment")}}async cancelTransaction(e){if(!this.currentOperationId)return!1;let n={businessId:Number(this.config.storeId),targetOperationId:this.currentOperationId};try{return await this.worldlineApi.cancelPayment(n),!0}catch(t){throw this.mapWorldlineRequestError(t,"Failed to cancel Worldline transaction")}}async refundTransaction(e,n){this.abortController=new AbortController,n("CONNECTING");let t={amount:e.amountCents,businessId:Number(this.config.storeId),currency:e.currency,displayId:e.displayId,orderReferenceId:e.orderRef,referenceId:e.originalTransactionId};try{let r=await this.worldlineApi.createRefund(t),s=this.extractOperationId(r.data);if(this.currentOperationId=s,this.abortController.signal.aborted)throw new Error("Aborted");n("REQUIRES_INPUT",{sessionId:s});let i=await this.waitForPaymentCompletion(s,e.orderRef,R.PaymentEventType.RefundStatusChanged,this.abortController.signal);return this.currentOperationId=null,i}catch(r){throw this.currentOperationId=null,r instanceof l?r:this.mapWorldlineRequestError(r,"Failed to refund Worldline transaction")}}async verifyFinalStatus(e,n){try{let{data:t}=await this.paymentApi.getPaymentStatus({businessId:Number(this.config.storeId),orderId:e.orderRef,provider:this.paymentProvider,referenceId:n});return this.handlePaymentStatus(t)}catch(t){throw this.mapWorldlineRequestError(t,"Failed to verify final Worldline status")}}abort(){this.abortController?.abort()}async waitForPaymentCompletion(e,n,t,r){let s=`worldline.requests.${e}`;return new Promise((i,a)=>{let c=!1,u=()=>{c=!0,typeof y=="function"&&y(),clearTimeout(f)},d=()=>{u(),a(new l("CANCELLED","Transaction cancelled"))};r.addEventListener("abort",d);let y=this.messaging.subscribe(s,t,p=>{c||p.status===R.SimplePaymentStatus.Pending||(u(),r.removeEventListener("abort",d),i(this.handlePaymentStatus(p)))}),f=setTimeout(async()=>{if(!(c||r.aborted))try{let p=await this.pollOrderStatus(e,n,this.config.storeId,r);i(this.handlePaymentStatus(p))}catch(p){a(new l("TIMEOUT","Payment timed out and polling failed",p))}finally{r.removeEventListener("abort",d),u()}},1e4)})}async pollOrderStatus(e,n,t,r){let a=Date.now()+12e4;for(;Date.now()<a;){if(r.aborted)throw new Error("Aborted");try{let{data:c}=await this.paymentApi.getPaymentStatus({businessId:Number(t),orderId:n,provider:this.paymentProvider,referenceId:e});if(r.aborted)throw new Error("Aborted");if(c.status!==R.SimplePaymentStatus.Pending)return c}catch(c){if(c instanceof Error&&c.message==="Aborted")throw c}await new Promise(c=>{let u=()=>{clearTimeout(d),c(void 0)};r.addEventListener("abort",u,{once:!0});let d=setTimeout(()=>{r.removeEventListener("abort",u),c(void 0)},2e3)})}throw new Error("Payment verification timed out.")}handlePaymentStatus(e){let n=e.status===R.SimplePaymentStatus.Success,t=e.status===R.SimplePaymentStatus.Pending,r={success:n,status:n?"SUCCESS":t?"PENDING":"FAILED",orderId:e.orderId,errorCode:e.error?.code||(n||t?"":R.PaymentFailureCode.SystemUnknown),errorMessage:e.error?.message||(n||t?"":"Transaction failed without error details")};return e.transactionId&&(r.transactionId=e.transactionId),e.error?.referenceError&&(r.errorReference=e.error.referenceError),e.transaction&&(r.transaction=e.transaction),r}extractOperationId(e){let n=typeof e=="object"&&e!==null&&"operationId"in e&&typeof e.operationId=="string"?e.operationId:null;if(!n)throw new Error("operationId is missing from response.");return n}mapWorldlineRequestError(e,n){if((0,q.isAxiosError)(e)){if(e.response?.status===400||e.response?.status===409)return new l("TERMINAL_BUSY",n,e);if(e.response?.status===404)return new l("TERMINAL_OFFLINE",n,e)}return new l("NETWORK_ERROR",n,e)}};var U=class o{strategy;axios;messaging;timeoutMs;logger;_currentState="IDLE";_listeners=[];_cancellationIntent=!1;_currentSessionId;_autoResetTimer;autoResetOptions;appToAppConfig;paymentSessionConfig;static TERMINAL_STATES=["SUCCESS","FAILED","INTERNAL_ERROR"];static RESTING_STATES=["IDLE",...o.TERMINAL_STATES];static CANCEL_VERIFY_TIMEOUT_MS=5e3;constructor(e,n,t,r={},s){this.axios=e,this.messaging=n,this.logger=r.logger,this.timeoutMs=r.timeoutMs||3e4,this.autoResetOptions=r.autoResetOnPaymentComplete,this.appToAppConfig=r.appToApp,this.paymentSessionConfig=r.paymentSession,this.strategy=s??this.resolveStrategy(t)}get version(){return K}get currentState(){return this._currentState}generateErrorResult(e,n,t){return{success:!1,status:"ERROR",errorCode:this.normalizeErrorCode(n),errorMessage:t,orderId:e}}normalizeErrorCode(e){return e?e.includes(".")?e:{CANCELLED:h.PaymentFailureCode.PaymentCancelledByUser,DECLINED:h.PaymentFailureCode.PaymentDeclined,TERMINAL_BUSY:h.PaymentFailureCode.TerminalBusy,TERMINAL_OFFLINE:h.PaymentFailureCode.TerminalOffline,TIMEOUT:h.PaymentFailureCode.TerminalTimeout,NETWORK_ERROR:h.PaymentFailureCode.SystemProviderError,STRATEGY_ERROR:h.PaymentFailureCode.SystemProviderError,MISSING_CONFIG:h.PaymentFailureCode.SystemUnknown,INVALID_AMOUNT:h.PaymentFailureCode.SystemUnknown,UNKNOWN:h.PaymentFailureCode.SystemUnknown}[e]??h.PaymentFailureCode.SystemUnknown:h.PaymentFailureCode.SystemUnknown}subscribe=e=>(this._listeners.push(e),e(this._currentState),()=>{this._listeners=this._listeners.filter(n=>n!==e)});transitionTo(e){if(this._currentState===e)return;if(e==="IDLE"){this.cancelAutoReset(),this._currentState=e,this._listeners.forEach(t=>t(e));return}if(o.TERMINAL_STATES.includes(this._currentState)){let t=`Invalid State Transition: Attempted to move from terminal state ${this._currentState} to ${e}`;throw this.logger?.error(t),this._currentState!=="INTERNAL_ERROR"&&(this._currentState="INTERNAL_ERROR",this._listeners.forEach(r=>r(this._currentState))),new l("UNKNOWN",t)}this._currentState=e,o.TERMINAL_STATES.includes(e)&&this.scheduleAutoReset(e),this._listeners.forEach(t=>t(e))}_resetScheduledAt;get nextAutoResetAt(){return this._resetScheduledAt}cancelAutoReset(){this._autoResetTimer&&(clearTimeout(this._autoResetTimer),this._autoResetTimer=void 0),this._resetScheduledAt=void 0}scheduleAutoReset(e){if(!this.autoResetOptions)return;let t=e==="SUCCESS"?this.autoResetOptions.successDelayMs??5e3:this.autoResetOptions.failureDelayMs??5e3;this.logger?.info(`Scheduling auto-reset to IDLE in ${t}ms`),this._resetScheduledAt=Date.now()+t,this._autoResetTimer=setTimeout(()=>{this.logger?.info("Auto-reset triggered"),this.reset()},t)}resolveStrategy(e){switch(e.provider){case h.PaymentProvider.Nets:return this.paymentSessionConfig?.enabled?new _(this.axios,this.messaging,e):new O(this.axios,this.messaging,e);case h.PaymentProvider.Worldline:return new M(this.axios,this.messaging,e);case h.PaymentProvider.Viva:return this.appToAppConfig?.enabled?new x(this.axios,this.messaging,e,this.appToAppConfig):this.paymentSessionConfig?.enabled?new F(this.axios,this.messaging,e):new N(this.axios,this.messaging,e);default:return new N(this.axios,this.messaging,e)}}initiateTransaction=async(e,n)=>{let t=n??{},r=e.orderRef;if(!o.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(e.orderRef,"UNKNOWN","A transaction is already in progress");let i=Date.now();if(this._cancellationIntent=!1,this._currentSessionId=void 0,this.transitionTo("IDLE"),e.amountCents<=0)return this.generateErrorResult(e.orderRef,"INVALID_AMOUNT","Amount must be greater than 0");try{let a=(y,f)=>{f?.sessionId&&(this._currentSessionId=f.sessionId),y!=="FAILED"&&(this.transitionTo(y),this.fireStateCallback(y,t,r))},c=this.strategy.processPayment(e,a),d=(this.strategy.getExecutionMode?.()??"managed")==="callback_driven"?await c:await Promise.race([c,new Promise((y,f)=>{setTimeout(()=>{f(new l("TIMEOUT","Transaction timed out"))},this.timeoutMs)})]);if(d.success)this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(d));else{if(this._cancellationIntent)return await this.handleTransactionError(e,new Error("Aborted after resolution"),t);this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(d))}return this.logger?.info("Transaction completed successfully",{orderId:e.orderRef,durationMs:Date.now()-i}),d}catch(a){return this.logger?.warn("Transaction interrupted. Handling final status...",{error:a}),await this.handleTransactionError(e,a,t)}};async handleTransactionError(e,n,t={}){let r=n instanceof l&&(n.code==="TIMEOUT"||n.code===h.PaymentFailureCode.PaymentTimeout);if(!this._cancellationIntent&&!r&&(this.transitionTo("VERIFYING"),this.safeFireCallback(()=>t.onVerifying?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId}))),this._cancellationIntent){try{if(this._currentSessionId&&(this.strategy.shouldVerifyAfterCancel?.()??!0)){let i=await this.strategy.verifyFinalStatus(e,this._currentSessionId,o.CANCEL_VERIFY_TIMEOUT_MS);if(i.success)return this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(i)),i}}catch(i){this.logger?.warn("Final status verification failed during cancellation",{err:i})}return this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onCancelled?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId})),{success:!1,status:"CANCELLED",errorCode:this.normalizeErrorCode("CANCELLED"),orderId:e.orderRef,...this._currentSessionId?{transactionId:this._currentSessionId}:{}}}let s;if(this.strategy.abort(),this._currentSessionId)try{let i=await this.strategy.verifyFinalStatus(e,this._currentSessionId);if(i.success)return this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(i)),i;s=r&&i.status==="PENDING"?this.buildErrorResultFromException(e.orderRef,n):i}catch(i){this.logger?.warn("Failed to get detailed error from verifyFinalStatus",{verifyErr:i}),s=this.buildErrorResultFromException(e.orderRef,i)}else s=this.buildErrorResultFromException(e.orderRef,n);return this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(s)),s}buildErrorResultFromException(e,n){return n instanceof l?this.generateErrorResult(e,n.code,n.message):this.generateErrorResult(e,"UNKNOWN",n instanceof Error?n.message:"Unknown fatal error")}fireStateCallback(e,n,t){let r={orderRef:t,refPaymentId:this._currentSessionId};switch(e){case"CONNECTING":this.safeFireCallback(()=>n.onConnecting?.(r));break;case"REQUIRES_INPUT":this.safeFireCallback(()=>n.onRequiresInput?.(r));break;case"PROCESSING":this.safeFireCallback(()=>n.onProcessing?.(r));break}}safeFireCallback(e){try{e()}catch(n){this.logger?.warn("Callback execution failed",{error:n})}}cancel=async()=>{if(this.logger?.info("Attempting cancellation"),o.TERMINAL_STATES.includes(this._currentState))return this.logger?.warn("Cannot cancel: Transaction already in terminal state",{state:this._currentState}),!1;if(!this._currentSessionId&&this._currentState==="IDLE")return this.logger?.warn("Cannot cancel: No active session to cancel",{state:this._currentState}),!1;this._cancellationIntent=!0,this.transitionTo("VERIFYING");try{return await this.strategy.cancelTransaction(n=>this.transitionTo(n))}catch(e){return this.logger?.error("Cancellation command failed",e),!1}};reset=()=>{o.TERMINAL_STATES.includes(this._currentState)&&(this._currentSessionId=void 0,this._cancellationIntent=!1,this.transitionTo("IDLE"))};refund=async(e,n)=>{let t=n??{};if(this.logger?.info("Initiating refund",{orderRef:e.orderRef}),this._currentSessionId=void 0,this._cancellationIntent=!1,!o.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(e.orderRef,"UNKNOWN","A transaction is already in progress");this.transitionTo("IDLE");try{let s=(a,c)=>{c?.sessionId&&(this._currentSessionId=c.sessionId),a!=="FAILED"&&(this.transitionTo(a),this.fireStateCallback(a,t,e.orderRef))},i=await this.strategy.refundTransaction(e,s);return i.success?(this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(i))):this._cancellationIntent||i.status==="CANCELLED"?(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onCancelled?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId}))):(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(i))),this.logger?.info("Refund completed",{success:i.success,orderRef:e.orderRef}),i}catch(s){if(this.logger?.error("Refund failed",s),this._cancellationIntent){try{if(this._currentSessionId){let a=await this.strategy.verifyFinalStatus(e,this._currentSessionId);return a.success?(this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(a)),a):a.status==="CANCELLED"?(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onCancelled?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId})),a):(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(a)),a)}}catch(a){this.logger?.warn("Refund final status verification failed",{verifyError:a})}return this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onCancelled?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId})),{success:!1,status:"CANCELLED",errorCode:this.normalizeErrorCode("CANCELLED"),orderId:e.orderRef,...this._currentSessionId?{transactionId:this._currentSessionId}:{}}}this.transitionTo("FAILED");let i=this.generateErrorResult(e.orderRef,"UNKNOWN",s instanceof Error?s.message:"Refund failed");return this.safeFireCallback(()=>t.onError?.(i)),i}};revert=async(e,n)=>{let t=n??{};if(this.logger?.info("Reverting payment",{orderRef:e.orderRef}),this._currentSessionId=e.originalTransactionId,this._cancellationIntent=!1,!o.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(e.orderRef,"UNKNOWN","A transaction is already in progress");let r=this.strategy.revertTransaction?.bind(this.strategy);if(!r)return this.generateErrorResult(e.orderRef,"STRATEGY_ERROR","Revert is not supported by the active payment strategy");this.transitionTo("CONNECTING");try{let s=await r(e,(i,a)=>{a?.sessionId&&(this._currentSessionId=a.sessionId),i!=="FAILED"&&(this.transitionTo(i),this.fireStateCallback(i,t,e.orderRef))});return this.settleSingleShot(s,e.orderRef,t),s}catch(s){return this.logger?.error("Revert failed",s),this.failSingleShot(e.orderRef,s,"Revert failed",t)}};settleSingleShot(e,n,t){e.success?(this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(e))):e.status==="CANCELLED"?(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onCancelled?.({orderRef:n,refPaymentId:this._currentSessionId}))):(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(e)))}failSingleShot(e,n,t,r){let s=this.generateErrorResult(e,"NETWORK_ERROR",n instanceof Error?n.message:t);return this.transitionTo("FAILED"),this.safeFireCallback(()=>r.onError?.(s)),s}};var B=(r=>(r.CONNECTING="CONNECTING",r.CONNECTED="CONNECTED",r.OFFLINE="OFFLINE",r.DISCONNECTED="DISCONNECTED",r))(B||{});0&&(module.exports={AppReaderStatus,MunchiPaymentSDK,PaymentInteractionState,SdkPaymentStatus});
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{PaymentFailureCode as I,PaymentProvider as M}from"@munchi_oy/core";var k="1.10.7";var l=class a extends Error{code;rawError;constructor(e,r,t){super(r),this.name="PaymentSDKError",this.code=e,this.rawError=t,Object.setPrototypeOf(this,a.prototype)}};import{PaymentApi as j,PaymentEventType as z,PaymentProviderEnum as X,SimplePaymentStatus as v,TransactionType as V}from"@munchi_oy/core";var R=(i=>(i.PENDING="PENDING",i.SUCCESS="SUCCESS",i.APPROVED="APPROVED",i.FAILED="FAILED",i.CANCELLED="CANCELLED",i.ERROR="ERROR",i))(R||{}),g=(c=>(c.IDLE="IDLE",c.CONNECTING="CONNECTING",c.REQUIRES_INPUT="REQUIRES_INPUT",c.PROCESSING="PROCESSING",c.SUCCESS="SUCCESS",c.FAILED="FAILED",c.INTERNAL_ERROR="INTERNAL_ERROR",c.VERIFYING="VERIFYING",c))(g||{});var b=class{constructor(e,r,t){this.messaging=r;this.config=t;this.api=new j(void 0,"",e)}api;abortController=null;currentRequestId=null;paymentProvider=X.Nets;async processPayment(e,r){this.abortController=new AbortController,r("CONNECTING");let t={amount:e.amountCents,businessId:Number(this.config.storeId),referenceId:e.orderRef,currency:e.currency,displayId:e.displayId,options:{allowPinBypass:!0,transactionType:V.Purchase}};try{let{data:n}=await this.api.initiateNetsTerminalTransaction(t),s=n.connectCloudRequestId;if(!s)throw new Error("connectCloudRequestId is missing from response.");if(this.currentRequestId=s,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:s});let i=await this.waitForPaymentCompletion(s,e.orderRef,this.abortController.signal);return this.currentRequestId=null,i}catch(n){throw this.currentRequestId=null,n instanceof l?n:new l("TERMINAL_BUSY","Failed to create Nets Intent",n)}}async waitForPaymentCompletion(e,r,t){let n=`nets.requests.${e}`,s=z.StatusChanged;return new Promise((i,o)=>{let c=!1,u=()=>{c=!0,typeof m=="function"&&m(),clearTimeout(y)},d=()=>{u(),o(new l("CANCELLED","Transaction cancelled"))};t.addEventListener("abort",d);let m=this.messaging.subscribe(n,s,p=>{c||p.status===v.Pending||(u(),t.removeEventListener("abort",d),i(this.handleSuccess(p)))}),y=setTimeout(async()=>{if(!(c||t.aborted))try{let p=await this.pollOrderStatus(e,r,this.config.storeId,t);i(this.handleSuccess(p))}catch(p){o(new l("TIMEOUT","Payment timed out and polling failed",p))}finally{t.removeEventListener("abort",d),u()}},1e4)})}async pollOrderStatus(e,r,t,n){let c=Date.now()+12e4;for(;Date.now()<c;){if(n.aborted)throw new Error("Aborted");try{let{data:u}=await this.api.getPaymentStatus({businessId:Number(t),orderId:r,provider:this.paymentProvider,referenceId:e});if(n.aborted)throw new Error("Aborted");if(u.status!==v.Pending)return u}catch(u){if(u instanceof Error&&u.message==="Aborted")throw u}await new Promise(u=>{let d=()=>{clearTimeout(m),u(void 0)};n.addEventListener("abort",d,{once:!0});let m=setTimeout(()=>{n.removeEventListener("abort",d),u(void 0)},2e3)})}throw new Error("Payment verification timed out.")}async cancelTransaction(e){if(!this.currentRequestId)return!1;let r={requestId:this.currentRequestId,businessId:Number(this.config.storeId)};try{return await this.api.cancelNetsTerminalTransaction(r),this.abortController?.abort(),this.currentRequestId=null,!0}catch{return!1}}async refundTransaction(e,r){try{this.abortController=new AbortController;let t={amount:e.amountCents,businessId:Number(this.config.storeId),currency:e.currency,displayId:e.displayId,referenceId:e.orderRef,options:{allowPinBypass:!0,transactionType:V.ReturnOfGoods}},{data:n}=await this.api.initiateNetsTerminalTransaction(t),s=n.connectCloudRequestId;if(!s)throw new Error("connectCloudRequestId is missing from response.");if(this.currentRequestId=s,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:s});let i=await this.waitForPaymentCompletion(s,e.orderRef,this.abortController.signal);return this.currentRequestId=null,i}catch(t){throw this.currentRequestId=null,t instanceof l||t instanceof l?t:new l("NETWORK_ERROR","Failed to refund Nets transaction",t)}}async verifyFinalStatus(e,r){try{let{data:t}=await this.api.getPaymentStatus({businessId:Number(this.config.storeId),orderId:e.orderRef,provider:this.paymentProvider,referenceId:r});return this.handleSuccess(t)}catch(t){throw new l("NETWORK_ERROR","Failed to verify final Nets status",t)}}handleSuccess(e){let r=e.status===v.Success,t=e.status===v.Pending,n={success:r,status:r?"SUCCESS":t?"PENDING":"FAILED",orderId:e.orderId,transaction:e.transaction};return e.transactionId&&(n.transactionId=e.transactionId),e.error?.code&&(n.errorCode=e.error.code),e.error?.message&&(n.errorMessage=e.error.message),n}abort(){this.abortController?.abort()}};import{FeeType as G,PaymentFailureCode as T,PaymentMethod as w,PaymentProvider as J,PaymentSessionApi as Z,PaymentSessionStatus as K}from"@munchi_oy/core";var A=a=>{if(!a)return 0;let e=Number.parseInt(a,10);return Number.isFinite(e)?e:0},W=a=>{if(!a)return new Date().toISOString();let e=new Date(a);return Number.isNaN(e.getTime())?new Date().toISOString():e.toISOString()};var ee="vivapayclient://pay/v1",te="abort",re="sale",q="transactionDetails",ne=4e3,se="534287",ie="38",oe="493591",ae="497439",ce=[oe,ae],le=["CREDIT","PREPAID","CORPORATE"],N=class{constructor(e,r,t,n){this.config=t;this.appToAppConfig=n;this.sessionApi=new Z(void 0,"",e)}sessionApi;abortController=null;currentClientTransactionId=null;currentIsvClientTransactionId=null;currentCurrency=null;currentOrderRef=null;currentSourceTerminalId=null;latestResult=null;wasCancelled=!1;getExecutionMode(){return"callback_driven"}async processPayment(e,r){if(!this.appToAppConfig.enabled)throw new l("STRATEGY_ERROR","Viva app-to-app is not enabled");r("CONNECTING");try{let{data:t}=await this.sessionApi.initiateVivaA2aSession(this.buildCreatePaymentPayload(e));return await this.runAction(re,this.buildLaunchParams(t),e,r)}catch(t){throw new l("NETWORK_ERROR","Failed to create Viva app-to-app payment",t)}}async cancelTransaction(e){if(!this.currentClientTransactionId)return!1;let r=await this.lookupTransactionDetails();if(r)return this.latestResult=r,this.wasCancelled=r.status==="CANCELLED",this.abortController?.abort(),!0;try{await this.appToAppConfig.adapter.openUrl(this.buildActionUrl(te,{}))}catch(t){throw this.abortController?.abort(),new l("NETWORK_ERROR","Failed to launch Viva abort flow",t)}return this.wasCancelled=!0,this.abortController?.abort(),!0}async refundTransaction(e,r){try{let t={sessionId:e.originalTransactionId,amount:e.amountCents},{data:n}=await this.sessionApi.refundVivaSession(t),s=n.status===K.Refunded||n.status===K.Refunding,i={success:s,status:s?"SUCCESS":"FAILED",orderId:e.orderRef,transactionId:n.providerTransactionId??n.sessionId};return s||(n.errorCode&&(i.errorCode=n.errorCode),n.errorMessage&&(i.errorMessage=n.errorMessage)),i}catch(t){throw new l("NETWORK_ERROR","Failed to refund Viva transaction",t)}}async verifyFinalStatus(e,r){return this.latestResult?this.latestResult:this.wasCancelled?{success:!1,status:"CANCELLED",orderId:this.currentOrderRef??r,errorCode:T.PaymentCancelledByUser,errorMessage:"Transaction was cancelled",transactionId:r}:{success:!1,status:"PENDING",orderId:this.currentOrderRef??r,transactionId:r}}abort(){this.abortController?.abort()}async runAction(e,r,t,n){if(!this.appToAppConfig.enabled)throw new l("STRATEGY_ERROR","Viva app-to-app is not enabled");this.abortController=new AbortController,this.latestResult=null,this.wasCancelled=!1,this.currentCurrency=t.currency,this.currentOrderRef=t.orderRef,this.currentSourceTerminalId=r.sourceTerminalId??r.tid??null,this.currentClientTransactionId=r.clientTransactionId??null,this.currentIsvClientTransactionId=r.ISV_clientTransactionId??null;let s=this.currentClientTransactionId?{sessionId:this.currentClientTransactionId}:void 0;return new Promise((i,o)=>{let c=(m,y)=>{m?.(),this.abortController?.signal.removeEventListener("abort",y)},u=()=>{c(d,u),o(new Error("Aborted"))},d=this.appToAppConfig.adapter.subscribe(m=>{if(this.abortController?.signal.aborted)return;let y=this.parseCallbackUrl(m);y&&this.matchesKnownTransactionId(y.rawParams)&&(this.latestResult=y.result,this.wasCancelled=y.result.status==="CANCELLED",this.currentClientTransactionId=null,this.currentIsvClientTransactionId=null,this.currentCurrency=null,this.currentOrderRef=null,this.currentSourceTerminalId=null,c(d,u),i(y.result))});this.abortController?.signal.addEventListener("abort",u),n("REQUIRES_INPUT",s),this.appToAppConfig.adapter.openUrl(this.buildActionUrl(e,r)).then(()=>{this.abortController?.signal.aborted}).catch(m=>{c(d,u),this.currentClientTransactionId=null,this.currentIsvClientTransactionId=null,this.currentCurrency=null,this.currentOrderRef=null,this.currentSourceTerminalId=null,o(new l("NETWORK_ERROR","Failed to launch Viva app",m))})})}buildCreatePaymentPayload(e){let r=e.options??{},t={amount:e.amountCents,referenceId:e.orderRef,businessId:Number(this.config.storeId),currency:e.currency,displayId:e.displayId,showReceipt:!1,showTransactionResult:!1};return r.tipAmount!==void 0&&(t.tipAmount=r.tipAmount),e.splitContext!==void 0&&(t.splitContext=e.splitContext),t}buildLaunchParams(e){let r={};return Object.entries(e).forEach(([t,n])=>{n!==void 0&&(t==="clientToken"||t==="sessionId"||(r[t]=String(n)))}),r}buildActionUrl(e,r){let t=new URLSearchParams({action:e,appId:this.appToAppConfig.appId,callback:this.resolveCallbackQueryParam()});return Object.entries(r).forEach(([n,s])=>{t.set(n,s)}),`${ee}?${t.toString()}`}parseCallbackUrl(e){if(!this.matchesCallbackBase(e))return null;let r=new URL(e),t=Object.fromEntries(r.searchParams.entries()),n=this.isSuccessfulCallback(t),s=this.isCancelledCallback(t),i=this.resolveFailureCode(t,s),o={success:n,status:n?"SUCCESS":s?"CANCELLED":"FAILED",orderId:this.currentOrderRef??t.clientTransactionId??"unknown",errorCode:n?"":i,errorMessage:n?"":t.message??"Transaction failed without error details"};n&&(o.transaction=this.mapCallbackToTransaction(t));let c=t.transactionId??t.orderCode??t.clientTransactionId,u=t.errorCode??this.extractErrorReferenceFromMessage(t.message)??t.referenceNumber??t.tid??t.rrn;return c&&(o.transactionId=c),u&&(o.errorReference=u),{rawParams:t,result:o}}matchesCallbackBase(e){let r=new URL(e),t=this.appToAppConfig.callbackUrl;if(!t.includes("://")){let s=t.replace(/:$/,"");return r.protocol===`${s}:`}let n=new URL(t);return r.protocol===n.protocol&&r.hostname===n.hostname&&r.pathname===n.pathname}resolveCallbackQueryParam(){if(this.appToAppConfig.callbackParamFormat!=="scheme-only")return this.appToAppConfig.callbackUrl;let e=this.appToAppConfig.callbackUrl;return e.includes("://")?new URL(e).protocol.replace(/:$/,""):e.replace(/:$/,"")}matchesKnownTransactionId(e){let r=[this.currentClientTransactionId,this.currentIsvClientTransactionId].filter(n=>!!n);if(r.length===0)return!0;let t=[e.clientTransactionId,e.ISV_clientTransactionId].filter(n=>!!n);return t.length===0?!0:t.some(n=>r.includes(n))}resolveFailureCode(e,r){if(r)return T.PaymentCancelledByUser;let t=e.errorCode;if(t?.includes("."))return t;if(this.isTransactionDetailsAction(e)&&(e.transactionType??"").toLowerCase().includes("abort"))return T.SystemUnknown;let n=(e.message??"").toLowerCase(),s=(e.status??"").toLowerCase();return n.includes("declined")||s==="declined"||s==="fail"||s==="failed"||s==="failure"?T.PaymentDeclined:T.SystemUnknown}isSuccessfulCallback(e){let r=(e.status??"").toLowerCase();return this.isTransactionDetailsAction(e)?r!=="success"?!1:!(e.transactionType??"").toLowerCase().includes("abort"):r==="success"}isTransactionDetailsAction(e){return(e.action??"").toLowerCase()===q.toLowerCase()}isCancelledCallback(e){let r=(e.status??"").toLowerCase(),t=(e.message??"").toLowerCase(),n=(e.errorCode??"").toLowerCase();return r==="cancelled"||r==="canceled"||t.includes("user_cancel")||t.includes("user cancel")||t.includes("cancelled by user")||t.includes("canceled by user")||t.includes("transaction cancelled by user")||t.includes("transaction canceled by user")||n.includes("user_cancel")||n.includes("user cancel")||n==="1000"&&(t.includes("cancelled by user")||t.includes("canceled by user"))}extractErrorReferenceFromMessage(e){return e?e.match(/\((-?\d+)\)/)?.[1]:void 0}mapCallbackToTransaction(e){let r=e.transactionId??e.orderCode??e.clientTransactionId??"unknown",t=W(e.transactionDate),n=A(e.tipAmount),s=A(e.surchargeAmount);return{amount:A(e.amount)-n-s,cardDetail:{aid:e.aid??null,applicationLabel:e.applicationLabel??null,cardNumber:e.accountNumber??"N/A",cardType:e.cardType??"N/A",issuer:e.bankId??null,orderCode:e.orderCode??null,timestamp:t,transactionId:r},createdAt:t,fees:this.buildFees(n,s),id:r,label:null,provider:J.Viva,rawData:e,referenceId:e.clientTransactionId??null,roundingDifference:0,type:this.getVivaPaymentMethodType(e)}}getVivaPaymentMethodType(e){let r=(e.applicationLabel??"").toUpperCase().trim(),n=(e.accountNumber??"").substring(0,6),s=(e.bankId??"").trim();return n===se||s===ie?w.Edenred:ce.includes(n)?w.WoltBenefit:le.some(i=>r.includes(i))?w.Credit:w.Debit}buildFees(e,r){if(!this.currentCurrency)return null;let t=[];return e>0&&t.push({taxAmount:0,total:{amount:e,currency:this.currentCurrency},type:G.TipAmount,vatPercentage:0}),r>0&&t.push({taxAmount:0,total:{amount:r,currency:this.currentCurrency},type:G.Surcharge,vatPercentage:0}),t.length===0?null:{parts:t}}async lookupTransactionDetails(){if(!this.currentClientTransactionId||!this.currentSourceTerminalId)return null;let e={clientTransactionId:this.currentClientTransactionId,sourceTerminalId:this.currentSourceTerminalId};return new Promise(r=>{let t=!1,n=setTimeout(()=>{t||(t=!0,s(),r(null))},ne),s=this.appToAppConfig.adapter.subscribe(i=>{if(t)return;let o=this.parseCallbackUrl(i);o&&this.matchesKnownTransactionId(o.rawParams)&&(t=!0,clearTimeout(n),s(),r(o.result))});this.appToAppConfig.adapter.openUrl(this.buildActionUrl(q,e)).catch(()=>{t||(t=!0,clearTimeout(n),s(),r(null))})})}};import{PaymentFailureCode as me,PaymentSessionApi as pe,PaymentSessionStatus as _,SimplePaymentStatus as B}from"@munchi_oy/core";import{PaymentFailureCode as ue,PaymentSessionStatus as f}from"@munchi_oy/core";function de(a){throw new l("UNKNOWN",`Unhandled payment session status: ${String(a)}`)}function D(a){return{success:!1,status:"PENDING",orderId:a,errorCode:"",errorMessage:""}}function Y(a,e){switch(a.status){case f.Initiated:case f.Processing:case f.Voiding:case f.Refunding:case f.Dispatched:return D(e);case f.Success:case f.Closed:{let r={success:!0,status:"SUCCESS",orderId:e,errorCode:"",errorMessage:""};return a.providerTransactionId&&(r.transactionId=a.providerTransactionId),r}case f.VoidFailed:case f.Failed:{let r={success:!1,status:"FAILED",orderId:e,errorCode:a.errorCode||ue.SystemUnknown,errorMessage:a.errorMessage||"Transaction failed without error details"};return a.providerTransactionId&&(r.transactionId=a.providerTransactionId),r}case f.Cancelled:case f.Voided:case f.VoidPending:case f.Refunded:{let r={success:!1,status:"CANCELLED",orderId:e};return a.errorCode&&(r.errorCode=a.errorCode),a.errorMessage&&(r.errorMessage=a.errorMessage),a.providerTransactionId&&(r.transactionId=a.providerTransactionId),r}default:return de(a.status)}}var O=class a{constructor(e,r,t){this.messaging=r;this.config=t;this.sessionApi=new pe(void 0,"",e)}static POLLING_DURATION_MS=18e4;static POLLING_INTERVAL_MS=1e3;static VERIFY_DURATION_MS=3e4;static INITIAL_POLL_DELAY_MS=1e4;sessionApi;abortController=null;idempotencyKey=null;idempotencyOrderRef=null;currentClientToken=null;async processPayment(e,r){this.abortController=new AbortController,(this.idempotencyKey===null||this.idempotencyOrderRef!==e.orderRef)&&(this.idempotencyKey=this.generateIdempotencyKey(),this.idempotencyOrderRef=e.orderRef),this.currentClientToken=null,r("CONNECTING");let t={amount:e.amountCents,businessId:Number(this.config.storeId),orderId:e.orderRef};e.splitContext!==void 0&&(t.splitContext=e.splitContext);try{let{data:n}=await this.sessionApi.initiateVivaSession(t,this.idempotencyKey);this.currentClientToken=n.clientToken;let s=this.abortController.signal;if(s.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:n.sessionId});let i=await this.waitForCompletion(n.clientToken,n.sessionId,e,s);return i?this.finalize(i):(await this.armCancel(n.clientToken),D(e.orderRef))}catch(n){throw n instanceof l?n:new l("NETWORK_ERROR","Failed to create Viva payment session",n)}}async verifyFinalStatus(e,r,t){if(!this.currentClientToken)throw new l("NETWORK_ERROR","No active payment session to verify");let n=await this.pollUntilTerminal(this.currentClientToken,e,void 0,t??a.VERIFY_DURATION_MS);return this.finalize(n??D(e.orderRef))}async cancelTransaction(e){if(!this.currentClientToken)return!1;try{await this.sessionApi.cancelVivaSession(this.currentClientToken)}catch(r){throw new l("NETWORK_ERROR","Failed to cancel Viva payment session",r)}return this.abortController?.abort(),!0}async refundTransaction(e,r){try{let t={sessionId:e.originalTransactionId,amount:e.amountCents},{data:n}=await this.sessionApi.refundVivaSession(t),s=n.status===_.Refunded||n.status===_.Refunding,i={success:s,status:s?"SUCCESS":"FAILED",orderId:e.orderRef,transactionId:n.providerTransactionId??n.sessionId};return s||(n.errorCode&&(i.errorCode=n.errorCode),n.errorMessage&&(i.errorMessage=n.errorMessage)),i}catch(t){throw new l("NETWORK_ERROR","Failed to refund Viva transaction",t)}}async revertTransaction(e){try{let r={sessionId:e.originalTransactionId},{data:t}=await this.sessionApi.revertVivaSession(r),n=t.status===_.Refunded||t.status===_.Refunding,s={success:n,status:n?"SUCCESS":"FAILED",orderId:e.orderRef,transactionId:t.providerTransactionId??t.sessionId};return n||(t.errorCode&&(s.errorCode=t.errorCode),t.errorMessage&&(s.errorMessage=t.errorMessage)),s}catch(r){throw new l("NETWORK_ERROR","Failed to revert Viva transaction",r)}}abort(){this.abortController?.abort()}async pollUntilTerminal(e,r,t,n){let s=Date.now()+n;for(;Date.now()<s;){if(t?.aborted)throw new Error("Aborted");let i;try{i=(await this.sessionApi.getPaymentSession(e)).data}catch(o){if(o instanceof Error&&o.message==="Aborted")throw o}if(t?.aborted)throw new Error("Aborted");if(i){let o=Y(i,r.orderRef);if(o.status!=="PENDING")return o}await this.delay(a.POLLING_INTERVAL_MS,t)}}waitForCompletion(e,r,t,n){let s=`viva.${this.config.channel.toLowerCase()}.requests.${r}`;return new Promise((i,o)=>{let c=!1,u=()=>{c=!0,typeof m=="function"&&m(),clearTimeout(y),n.removeEventListener("abort",d)},d=()=>{u(),o(new Error("Aborted"))};n.addEventListener("abort",d);let m=this.messaging.subscribe(s,"payment:status-changed",p=>{c||p.status!==B.Pending&&(u(),i(this.mapStatusDto(p,t)))}),y=setTimeout(()=>{c||this.pollUntilTerminal(e,t,n,a.POLLING_DURATION_MS).then(p=>{c||(u(),i(p))},p=>{c||(u(),o(p))})},a.INITIAL_POLL_DELAY_MS)})}mapStatusDto(e,r){let t=e.status===B.Success,n={success:t,status:t?"SUCCESS":"FAILED",orderId:r.orderRef,errorCode:e.error?.code||(t?"":me.SystemUnknown),errorMessage:e.error?.message||(t?"":"Transaction failed without error details")};return e.transactionId&&(n.transactionId=e.transactionId),e.error?.referenceError&&(n.errorReference=e.error.referenceError),e.transaction&&(n.transaction=e.transaction),n}finalize(e){return e.status!=="PENDING"&&(this.idempotencyKey=null,this.idempotencyOrderRef=null),e}armCancel(e){return this.sessionApi.cancelVivaSession(e).then(()=>{},()=>{})}generateIdempotencyKey(){let e=globalThis.crypto;return e?.randomUUID?e.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,r=>{let t=Math.random()*16|0;return(r==="x"?t:t&3|8).toString(16)})}delay(e,r){return new Promise(t=>{let n=()=>{clearTimeout(s),t()};r&&r.addEventListener("abort",n,{once:!0});let s=setTimeout(()=>{r&&r.removeEventListener("abort",n),t()},e)})}};import{PaymentApi as ye,PaymentFailureCode as x,PaymentProviderEnum as fe,SimplePaymentStatus as P}from"@munchi_oy/core";var C=class a{constructor(e,r,t){this.messaging=r;this.config=t;this.api=new ye(void 0,"",e)}static INITIAL_POLL_DELAY_MS=1e4;static POLLING_DURATION_MS=18e4;static POLLING_INTERVAL_MS=2e3;static TIMEOUT_CANCEL_TIMEOUT_MS=5e3;static VERIFY_TIMEOUT_MS=1e4;static VERIFY_MAX_RETRIES=3;static VERIFY_RETRY_DELAY_MS=1500;api;abortController=null;currentSessionId=null;paymentProvider=fe.Viva;async processPayment(e,r){this.abortController=new AbortController,r("CONNECTING");let t={amount:e.amountCents,referenceId:e.orderRef,businessId:parseInt(this.config.storeId),currency:e.currency,displayId:e.displayId,showReceipt:!0,showTransactionResult:!0};try{let{data:n}=await this.api.initiateTerminalTransaction(t);if(this.currentSessionId=n.sessionId,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:n.sessionId});let s=await this.waitForPaymentCompletion(n.sessionId,e,this.abortController.signal);return this.currentSessionId=null,s}catch(n){throw this.currentSessionId=null,n instanceof l?n:new l("NETWORK_ERROR","Failed to create Viva Intent",n)}}async waitForPaymentCompletion(e,r,t){let s=`viva.${this.config.channel.toLowerCase()}.requests.${e}`,i="payment:status-changed";return new Promise((o,c)=>{let u=!1,d=()=>{u=!0,typeof y=="function"&&y(),clearTimeout(p)},m=()=>{d(),c(new Error("Aborted"))};t.addEventListener("abort",m);let y=this.messaging.subscribe(s,i,h=>{u||h.status!==P.Pending&&(d(),t.removeEventListener("abort",m),o(this.handleSuccess(h)))}),p=setTimeout(async()=>{if(!(u||t.aborted))try{let h=await this.pollOrderStatus(e,r.orderRef,this.config.storeId,t);if(u)return;o(this.handleSuccess(h))}catch(h){if(u)return;if(h instanceof Error&&h.message==="Aborted"){c(h);return}try{let E=await this.recoverAfterPollingTimeout(r,e);o(E)}catch(E){c(E instanceof l?E:new l("TIMEOUT","Payment timed out and polling failed",E))}}finally{t.removeEventListener("abort",m),d()}},a.INITIAL_POLL_DELAY_MS)})}async pollOrderStatus(e,r,t,n){let i=Date.now()+a.POLLING_DURATION_MS;for(;Date.now()<i;){if(n.aborted)throw new Error("Aborted");try{let{data:o}=await this.api.getPaymentStatus({businessId:Number(t),orderId:r,provider:this.paymentProvider,referenceId:e});if(n.aborted)throw new Error("Aborted");if(o.status!==P.Pending)return o}catch(o){if(o instanceof Error&&o.message==="Aborted")throw o}await new Promise(o=>{let c=()=>{clearTimeout(u),o(void 0)};n.addEventListener("abort",c,{once:!0});let u=setTimeout(()=>{n.removeEventListener("abort",c),o(void 0)},a.POLLING_INTERVAL_MS)})}throw new Error("Payment verification timed out.")}async recoverAfterPollingTimeout(e,r){return await this.cancelSessionWithTimeout(r),await this.verifyFinalStatusWithRetry(e,r)}async cancelSessionWithTimeout(e){let r;try{await Promise.race([this.cancelSession(e),new Promise((t,n)=>{r=setTimeout(()=>{n(new Error("Viva timeout cancellation timed out"))},a.TIMEOUT_CANCEL_TIMEOUT_MS)})])}catch{}finally{r&&clearTimeout(r)}}async cancelSession(e){return await this.api.cancelVivaTransactionV2({cashRegisterId:this.config.storeId,sessionId:e}),this.currentSessionId===e&&(this.currentSessionId=null),!0}async verifyFinalStatusWithRetry(e,r){let t;for(let n=1;n<=a.VERIFY_MAX_RETRIES;n++)try{let s=await Promise.race([this.verifyFinalStatus(e,r),new Promise((i,o)=>setTimeout(()=>o(new Error("Verify timed out")),a.VERIFY_TIMEOUT_MS))]);if(s.status==="PENDING"){t=new Error("Verify returned pending status"),n<a.VERIFY_MAX_RETRIES&&await new Promise(i=>setTimeout(i,a.VERIFY_RETRY_DELAY_MS));continue}return s}catch(s){t=s,n<a.VERIFY_MAX_RETRIES&&await new Promise(i=>setTimeout(i,a.VERIFY_RETRY_DELAY_MS))}throw new l(x.PaymentTimeout,"Payment Failed",t)}handleSuccess(e){let r=e.status===P.Success,t={success:r,status:r?"SUCCESS":"FAILED",orderId:e.orderId,errorCode:e.error?.code||(r?"":x.SystemUnknown),errorMessage:e.error?.message||(r?"":"Transaction failed without error details")};return e.transactionId&&(t.transactionId=e.transactionId),e.error?.referenceError&&(t.errorReference=e.error.referenceError),e.transaction&&(t.transaction=e.transaction),t}async cancelTransaction(e){if(!this.currentSessionId)return!1;try{let r=this.currentSessionId;return this.currentSessionId=null,await this.api.cancelVivaTransactionV2({cashRegisterId:this.config.storeId,sessionId:r}),this.abortController?.abort(),!0}catch(r){throw this.currentSessionId=null,new l("NETWORK_ERROR","Failed to cancel Viva transaction",r)}}async verifyFinalStatus(e,r){try{let{data:t}=await this.api.getPaymentStatus({businessId:Number(this.config.storeId),orderId:e.orderRef,provider:this.paymentProvider,referenceId:r}),n=t.status===P.Success,s=t.status===P.Pending,i={success:n,status:n?"SUCCESS":s?"PENDING":"FAILED",orderId:t.orderId,errorCode:t.error?.code||(n||s?"":x.SystemUnknown),errorMessage:t.error?.message||(n||s?"":"Transaction failed without error details")};return t.transactionId&&(i.transactionId=t.transactionId),t.error?.referenceError&&(i.errorReference=t.error.referenceError),t.transaction&&(i.transaction=t.transaction),i}catch(t){throw new l("NETWORK_ERROR","Failed to verify final transaction status",t)}}async refundTransaction(e,r){try{let t={amount:e.amountCents,businessId:Number(this.config.storeId),displayId:this.config.kioskId,currency:e.currency,orderReferenceId:e.orderRef,referenceId:e.originalTransactionId},{data:n}=await this.api.refundSingleVivaTransaction(t),s=n.success;return{success:s,status:s?"SUCCESS":"FAILED",orderId:e.orderRef,transactionId:n.sessionId}}catch(t){throw new l("NETWORK_ERROR","Failed to refund Viva transaction",t)}}abort(){this.abortController?.abort()}};import{PaymentApi as Ie,PaymentEventType as $,PaymentFailureCode as he,PaymentProviderEnum as Re,SimplePaymentStatus as L,WorldlineApi as ge}from"@munchi_oy/core";import{isAxiosError as Se}from"axios";var F=class{constructor(e,r,t){this.messaging=r;this.config=t;this.paymentApi=new Ie(void 0,"",e),this.worldlineApi=new ge(void 0,"",e)}paymentApi;worldlineApi;abortController=null;currentOperationId=null;paymentProvider=Re.Worldline;async processPayment(e,r){this.abortController=new AbortController,r("CONNECTING");let t={amount:e.amountCents,businessId:Number(this.config.storeId),currency:e.currency,displayId:e.displayId,referenceId:e.orderRef,showReceipt:!0,showTransactionResult:!0,...e.options&&"tipAmount"in e.options&&typeof e.options.tipAmount=="number"?{tipAmount:e.options.tipAmount}:{}};try{let n=await this.worldlineApi.createPayment(t),s=this.extractOperationId(n.data);if(this.currentOperationId=s,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:s});let i=await this.waitForPaymentCompletion(s,e.orderRef,$.StatusChanged,this.abortController.signal);return this.currentOperationId=null,i}catch(n){throw this.currentOperationId=null,n instanceof l?n:this.mapWorldlineRequestError(n,"Failed to create Worldline payment")}}async cancelTransaction(e){if(!this.currentOperationId)return!1;let r={businessId:Number(this.config.storeId),targetOperationId:this.currentOperationId};try{return await this.worldlineApi.cancelPayment(r),!0}catch(t){throw this.mapWorldlineRequestError(t,"Failed to cancel Worldline transaction")}}async refundTransaction(e,r){this.abortController=new AbortController,r("CONNECTING");let t={amount:e.amountCents,businessId:Number(this.config.storeId),currency:e.currency,displayId:e.displayId,orderReferenceId:e.orderRef,referenceId:e.originalTransactionId};try{let n=await this.worldlineApi.createRefund(t),s=this.extractOperationId(n.data);if(this.currentOperationId=s,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:s});let i=await this.waitForPaymentCompletion(s,e.orderRef,$.RefundStatusChanged,this.abortController.signal);return this.currentOperationId=null,i}catch(n){throw this.currentOperationId=null,n instanceof l?n:this.mapWorldlineRequestError(n,"Failed to refund Worldline transaction")}}async verifyFinalStatus(e,r){try{let{data:t}=await this.paymentApi.getPaymentStatus({businessId:Number(this.config.storeId),orderId:e.orderRef,provider:this.paymentProvider,referenceId:r});return this.handlePaymentStatus(t)}catch(t){throw this.mapWorldlineRequestError(t,"Failed to verify final Worldline status")}}abort(){this.abortController?.abort()}async waitForPaymentCompletion(e,r,t,n){let s=`worldline.requests.${e}`;return new Promise((i,o)=>{let c=!1,u=()=>{c=!0,typeof m=="function"&&m(),clearTimeout(y)},d=()=>{u(),o(new l("CANCELLED","Transaction cancelled"))};n.addEventListener("abort",d);let m=this.messaging.subscribe(s,t,p=>{c||p.status===L.Pending||(u(),n.removeEventListener("abort",d),i(this.handlePaymentStatus(p)))}),y=setTimeout(async()=>{if(!(c||n.aborted))try{let p=await this.pollOrderStatus(e,r,this.config.storeId,n);i(this.handlePaymentStatus(p))}catch(p){o(new l("TIMEOUT","Payment timed out and polling failed",p))}finally{n.removeEventListener("abort",d),u()}},1e4)})}async pollOrderStatus(e,r,t,n){let o=Date.now()+12e4;for(;Date.now()<o;){if(n.aborted)throw new Error("Aborted");try{let{data:c}=await this.paymentApi.getPaymentStatus({businessId:Number(t),orderId:r,provider:this.paymentProvider,referenceId:e});if(n.aborted)throw new Error("Aborted");if(c.status!==L.Pending)return c}catch(c){if(c instanceof Error&&c.message==="Aborted")throw c}await new Promise(c=>{let u=()=>{clearTimeout(d),c(void 0)};n.addEventListener("abort",u,{once:!0});let d=setTimeout(()=>{n.removeEventListener("abort",u),c(void 0)},2e3)})}throw new Error("Payment verification timed out.")}handlePaymentStatus(e){let r=e.status===L.Success,t=e.status===L.Pending,n={success:r,status:r?"SUCCESS":t?"PENDING":"FAILED",orderId:e.orderId,errorCode:e.error?.code||(r||t?"":he.SystemUnknown),errorMessage:e.error?.message||(r||t?"":"Transaction failed without error details")};return e.transactionId&&(n.transactionId=e.transactionId),e.error?.referenceError&&(n.errorReference=e.error.referenceError),e.transaction&&(n.transaction=e.transaction),n}extractOperationId(e){let r=typeof e=="object"&&e!==null&&"operationId"in e&&typeof e.operationId=="string"?e.operationId:null;if(!r)throw new Error("operationId is missing from response.");return r}mapWorldlineRequestError(e,r){if(Se(e)){if(e.response?.status===400||e.response?.status===409)return new l("TERMINAL_BUSY",r,e);if(e.response?.status===404)return new l("TERMINAL_OFFLINE",r,e)}return new l("NETWORK_ERROR",r,e)}};var U=class a{strategy;axios;messaging;timeoutMs;logger;_currentState="IDLE";_listeners=[];_cancellationIntent=!1;_currentSessionId;_autoResetTimer;autoResetOptions;appToAppConfig;paymentSessionConfig;static TERMINAL_STATES=["SUCCESS","FAILED","INTERNAL_ERROR"];static RESTING_STATES=["IDLE",...a.TERMINAL_STATES];static CANCEL_VERIFY_TIMEOUT_MS=5e3;constructor(e,r,t,n={},s){this.axios=e,this.messaging=r,this.logger=n.logger,this.timeoutMs=n.timeoutMs||3e4,this.autoResetOptions=n.autoResetOnPaymentComplete,this.appToAppConfig=n.appToApp,this.paymentSessionConfig=n.paymentSession,this.strategy=s??this.resolveStrategy(t)}get version(){return k}get currentState(){return this._currentState}generateErrorResult(e,r,t){return{success:!1,status:"ERROR",errorCode:this.normalizeErrorCode(r),errorMessage:t,orderId:e}}normalizeErrorCode(e){return e?e.includes(".")?e:{CANCELLED:I.PaymentCancelledByUser,DECLINED:I.PaymentDeclined,TERMINAL_BUSY:I.TerminalBusy,TERMINAL_OFFLINE:I.TerminalOffline,TIMEOUT:I.TerminalTimeout,NETWORK_ERROR:I.SystemProviderError,STRATEGY_ERROR:I.SystemProviderError,MISSING_CONFIG:I.SystemUnknown,INVALID_AMOUNT:I.SystemUnknown,UNKNOWN:I.SystemUnknown}[e]??I.SystemUnknown:I.SystemUnknown}subscribe=e=>(this._listeners.push(e),e(this._currentState),()=>{this._listeners=this._listeners.filter(r=>r!==e)});transitionTo(e){if(this._currentState===e)return;if(e==="IDLE"){this.cancelAutoReset(),this._currentState=e,this._listeners.forEach(t=>t(e));return}if(a.TERMINAL_STATES.includes(this._currentState)){let t=`Invalid State Transition: Attempted to move from terminal state ${this._currentState} to ${e}`;throw this.logger?.error(t),this._currentState!=="INTERNAL_ERROR"&&(this._currentState="INTERNAL_ERROR",this._listeners.forEach(n=>n(this._currentState))),new l("UNKNOWN",t)}this._currentState=e,a.TERMINAL_STATES.includes(e)&&this.scheduleAutoReset(e),this._listeners.forEach(t=>t(e))}_resetScheduledAt;get nextAutoResetAt(){return this._resetScheduledAt}cancelAutoReset(){this._autoResetTimer&&(clearTimeout(this._autoResetTimer),this._autoResetTimer=void 0),this._resetScheduledAt=void 0}scheduleAutoReset(e){if(!this.autoResetOptions)return;let t=e==="SUCCESS"?this.autoResetOptions.successDelayMs??5e3:this.autoResetOptions.failureDelayMs??5e3;this.logger?.info(`Scheduling auto-reset to IDLE in ${t}ms`),this._resetScheduledAt=Date.now()+t,this._autoResetTimer=setTimeout(()=>{this.logger?.info("Auto-reset triggered"),this.reset()},t)}resolveStrategy(e){switch(e.provider){case M.Nets:return new b(this.axios,this.messaging,e);case M.Worldline:return new F(this.axios,this.messaging,e);case M.Viva:return this.appToAppConfig?.enabled?new N(this.axios,this.messaging,e,this.appToAppConfig):this.paymentSessionConfig?.enabled?new O(this.axios,this.messaging,e):new C(this.axios,this.messaging,e);default:return new C(this.axios,this.messaging,e)}}initiateTransaction=async(e,r)=>{let t=r??{},n=e.orderRef;if(!a.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(e.orderRef,"UNKNOWN","A transaction is already in progress");let i=Date.now();if(this._cancellationIntent=!1,this._currentSessionId=void 0,this.transitionTo("IDLE"),e.amountCents<=0)return this.generateErrorResult(e.orderRef,"INVALID_AMOUNT","Amount must be greater than 0");try{let o=(m,y)=>{y?.sessionId&&(this._currentSessionId=y.sessionId),m!=="FAILED"&&(this.transitionTo(m),this.fireStateCallback(m,t,n))},c=this.strategy.processPayment(e,o),d=(this.strategy.getExecutionMode?.()??"managed")==="callback_driven"?await c:await Promise.race([c,new Promise((m,y)=>{setTimeout(()=>{y(new l("TIMEOUT","Transaction timed out"))},this.timeoutMs)})]);if(d.success)this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(d));else{if(this._cancellationIntent)return await this.handleTransactionError(e,new Error("Aborted after resolution"),t);this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(d))}return this.logger?.info("Transaction completed successfully",{orderId:e.orderRef,durationMs:Date.now()-i}),d}catch(o){return this.logger?.warn("Transaction interrupted. Handling final status...",{error:o}),await this.handleTransactionError(e,o,t)}};async handleTransactionError(e,r,t={}){let n=r instanceof l&&(r.code==="TIMEOUT"||r.code===I.PaymentTimeout);if(!this._cancellationIntent&&!n&&(this.transitionTo("VERIFYING"),this.safeFireCallback(()=>t.onVerifying?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId}))),this._cancellationIntent){try{if(this._currentSessionId){let i=await this.strategy.verifyFinalStatus(e,this._currentSessionId,a.CANCEL_VERIFY_TIMEOUT_MS);if(i.success)return this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(i)),i}}catch(i){this.logger?.warn("Final status verification failed during cancellation",{err:i})}return this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onCancelled?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId})),{success:!1,status:"CANCELLED",errorCode:this.normalizeErrorCode("CANCELLED"),orderId:e.orderRef,...this._currentSessionId?{transactionId:this._currentSessionId}:{}}}let s;if(this.strategy.abort(),this._currentSessionId)try{let i=await this.strategy.verifyFinalStatus(e,this._currentSessionId);if(i.success)return this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(i)),i;s=n&&i.status==="PENDING"?this.buildErrorResultFromException(e.orderRef,r):i}catch(i){this.logger?.warn("Failed to get detailed error from verifyFinalStatus",{verifyErr:i}),s=this.buildErrorResultFromException(e.orderRef,i)}else s=this.buildErrorResultFromException(e.orderRef,r);return this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(s)),s}buildErrorResultFromException(e,r){return r instanceof l?this.generateErrorResult(e,r.code,r.message):this.generateErrorResult(e,"UNKNOWN",r instanceof Error?r.message:"Unknown fatal error")}fireStateCallback(e,r,t){let n={orderRef:t,refPaymentId:this._currentSessionId};switch(e){case"CONNECTING":this.safeFireCallback(()=>r.onConnecting?.(n));break;case"REQUIRES_INPUT":this.safeFireCallback(()=>r.onRequiresInput?.(n));break;case"PROCESSING":this.safeFireCallback(()=>r.onProcessing?.(n));break}}safeFireCallback(e){try{e()}catch(r){this.logger?.warn("Callback execution failed",{error:r})}}cancel=async()=>{if(this.logger?.info("Attempting cancellation"),a.TERMINAL_STATES.includes(this._currentState))return this.logger?.warn("Cannot cancel: Transaction already in terminal state",{state:this._currentState}),!1;if(!this._currentSessionId&&this._currentState==="IDLE")return this.logger?.warn("Cannot cancel: No active session to cancel",{state:this._currentState}),!1;this._cancellationIntent=!0,this.transitionTo("VERIFYING");try{return await this.strategy.cancelTransaction(r=>this.transitionTo(r))}catch(e){return this.logger?.error("Cancellation command failed",e),!1}};reset=()=>{a.TERMINAL_STATES.includes(this._currentState)&&(this._currentSessionId=void 0,this._cancellationIntent=!1,this.transitionTo("IDLE"))};refund=async(e,r)=>{let t=r??{};if(this.logger?.info("Initiating refund",{orderRef:e.orderRef}),this._currentSessionId=void 0,this._cancellationIntent=!1,!a.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(e.orderRef,"UNKNOWN","A transaction is already in progress");this.transitionTo("IDLE");try{let s=(o,c)=>{c?.sessionId&&(this._currentSessionId=c.sessionId),o!=="FAILED"&&(this.transitionTo(o),this.fireStateCallback(o,t,e.orderRef))},i=await this.strategy.refundTransaction(e,s);return i.success?(this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(i))):this._cancellationIntent||i.status==="CANCELLED"?(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onCancelled?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId}))):(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(i))),this.logger?.info("Refund completed",{success:i.success,orderRef:e.orderRef}),i}catch(s){if(this.logger?.error("Refund failed",s),this._cancellationIntent){try{if(this._currentSessionId){let o=await this.strategy.verifyFinalStatus(e,this._currentSessionId);return o.success?(this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(o)),o):o.status==="CANCELLED"?(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onCancelled?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId})),o):(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(o)),o)}}catch(o){this.logger?.warn("Refund final status verification failed",{verifyError:o})}return this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onCancelled?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId})),{success:!1,status:"CANCELLED",errorCode:this.normalizeErrorCode("CANCELLED"),orderId:e.orderRef,...this._currentSessionId?{transactionId:this._currentSessionId}:{}}}this.transitionTo("FAILED");let i=this.generateErrorResult(e.orderRef,"UNKNOWN",s instanceof Error?s.message:"Refund failed");return this.safeFireCallback(()=>t.onError?.(i)),i}};revert=async(e,r)=>{let t=r??{};if(this.logger?.info("Reverting payment",{orderRef:e.orderRef}),this._currentSessionId=e.originalTransactionId,this._cancellationIntent=!1,!a.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(e.orderRef,"UNKNOWN","A transaction is already in progress");let n=this.strategy.revertTransaction?.bind(this.strategy);if(!n)return this.generateErrorResult(e.orderRef,"STRATEGY_ERROR","Revert is not supported by the active payment strategy");this.transitionTo("CONNECTING");try{let s=await n(e);return this.settleSingleShot(s,e.orderRef,t),s}catch(s){return this.logger?.error("Revert failed",s),this.failSingleShot(e.orderRef,s,"Revert failed",t)}};settleSingleShot(e,r,t){e.success?(this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(e))):e.status==="CANCELLED"?(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onCancelled?.({orderRef:r,refPaymentId:this._currentSessionId}))):(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(e)))}failSingleShot(e,r,t,n){let s=this.generateErrorResult(e,"NETWORK_ERROR",r instanceof Error?r.message:t);return this.transitionTo("FAILED"),this.safeFireCallback(()=>n.onError?.(s)),s}};var Ee=(n=>(n.CONNECTING="CONNECTING",n.CONNECTED="CONNECTED",n.OFFLINE="OFFLINE",n.DISCONNECTED="DISCONNECTED",n))(Ee||{});export{Ee as AppReaderStatus,U as MunchiPaymentSDK,g as PaymentInteractionState,R as SdkPaymentStatus};
|
|
1
|
+
import{PaymentFailureCode as I,PaymentProvider as V}from"@munchi_oy/core";var W="1.11.1";var l=class o extends Error{code;rawError;constructor(e,n,t){super(n),this.name="PaymentSDKError",this.code=e,this.rawError=t,Object.setPrototypeOf(this,o.prototype)}};import{PaymentEventType as Z,PaymentSessionApi as ee,SimplePaymentStatus as q}from"@munchi_oy/core";var h=(i=>(i.PENDING="PENDING",i.SUCCESS="SUCCESS",i.APPROVED="APPROVED",i.FAILED="FAILED",i.CANCELLED="CANCELLED",i.ERROR="ERROR",i))(h||{}),g=(c=>(c.IDLE="IDLE",c.CONNECTING="CONNECTING",c.REQUIRES_INPUT="REQUIRES_INPUT",c.PROCESSING="PROCESSING",c.SUCCESS="SUCCESS",c.FAILED="FAILED",c.INTERNAL_ERROR="INTERNAL_ERROR",c.VERIFYING="VERIFYING",c))(g||{});import{PaymentFailureCode as G,PaymentSessionStatus as y}from"@munchi_oy/core";function Y(o){throw new l("UNKNOWN",`Unhandled payment session status: ${String(o)}`)}function R(o){return{success:!1,status:"PENDING",orderId:o,errorCode:"",errorMessage:""}}function b(o,e){switch(o.status){case y.Initiated:case y.Processing:case y.Voiding:case y.Refunding:case y.Dispatched:return R(e);case y.Success:case y.Closed:{let n={success:!0,status:"SUCCESS",orderId:e,errorCode:"",errorMessage:""};return o.providerTransactionId&&(n.transactionId=o.providerTransactionId),n}case y.VoidFailed:case y.Failed:{let n={success:!1,status:"FAILED",orderId:e,errorCode:o.errorCode||G.SystemUnknown,errorMessage:o.errorMessage||"Transaction failed without error details"};return o.providerTransactionId&&(n.transactionId=o.providerTransactionId),n}case y.Cancelled:case y.Voided:case y.VoidPending:case y.Refunded:{let n={success:!1,status:"CANCELLED",orderId:e};return o.errorCode&&(n.errorCode=o.errorCode),o.errorMessage&&(n.errorMessage=o.errorMessage),o.providerTransactionId&&(n.transactionId=o.providerTransactionId),n}default:return Y(o.status)}}function U(o,e){switch(o.status){case y.Initiated:case y.Processing:case y.Dispatched:case y.Voiding:case y.VoidPending:case y.Success:case y.Closed:return R(e);case y.Refunded:case y.Voided:case y.Refunding:{let n={success:!0,status:"SUCCESS",orderId:e,errorCode:"",errorMessage:""};return o.providerTransactionId&&(n.transactionId=o.providerTransactionId),n}case y.Failed:case y.VoidFailed:{let n={success:!1,status:"FAILED",orderId:e,errorCode:o.errorCode||G.SystemUnknown,errorMessage:o.errorMessage||"Reversal failed without error details"};return o.providerTransactionId&&(n.transactionId=o.providerTransactionId),n}case y.Cancelled:{let n={success:!1,status:"CANCELLED",orderId:e};return o.errorCode&&(n.errorCode=o.errorCode),o.errorMessage&&(n.errorMessage=o.errorMessage),o.providerTransactionId&&(n.transactionId=o.providerTransactionId),n}default:return Y(o.status)}}var A=class o{constructor(e,n,t){this.messaging=n;this.config=t;this.sessionApi=new ee(void 0,"",e)}static POLLING_DURATION_MS=18e4;static POLLING_INTERVAL_MS=1e3;static VERIFY_DURATION_MS=3e4;static INITIAL_POLL_DELAY_MS=1e4;sessionApi;abortController=null;idempotencyKey=null;idempotencyOrderRef=null;currentClientToken=null;async processPayment(e,n){this.abortController=new AbortController,(this.idempotencyKey===null||this.idempotencyOrderRef!==e.orderRef)&&(this.idempotencyKey=this.generateIdempotencyKey(),this.idempotencyOrderRef=e.orderRef),this.currentClientToken=null,n("CONNECTING");let t={amount:e.amountCents,businessId:Number(this.config.storeId),orderId:e.orderRef};e.splitContext!==void 0&&(t.splitContext=e.splitContext);try{let{data:r}=await this.sessionApi.initiateNetsSession(t,this.idempotencyKey);this.currentClientToken=r.clientToken;let s=this.abortController.signal;if(s.aborted)throw new Error("Aborted");n("REQUIRES_INPUT",{sessionId:r.sessionId});let i=await this.waitForCompletion(r.clientToken,r.sessionId,e,s);return i?this.finalize(i):(await this.armCancel(r.clientToken),R(e.orderRef))}catch(r){throw r instanceof l?r:new l("TERMINAL_BUSY","Failed to create Nets payment session",r)}}async verifyFinalStatus(e,n,t){if(!this.currentClientToken)throw new l("NETWORK_ERROR","No active payment session to verify");let r=await this.pollUntilTerminal(this.currentClientToken,e.orderRef,void 0,t??o.VERIFY_DURATION_MS);return this.finalize(r??R(e.orderRef))}async cancelTransaction(e){if(!this.currentClientToken)return!1;try{await this.sessionApi.cancelSession(this.currentClientToken)}catch(n){throw new l("NETWORK_ERROR","Failed to cancel Nets payment session",n)}return this.abortController?.abort(),this.resetIdempotencyKey(),!0}async refundTransaction(e,n){this.abortController=new AbortController,n("CONNECTING");let t={sessionId:e.originalTransactionId,amount:e.amountCents};try{let{data:r}=await this.sessionApi.refundNetsSession(t);return await this.settleReversal(r,e.orderRef,this.abortController.signal,!0,n)}catch(r){throw r instanceof l?r:new l("NETWORK_ERROR","Failed to refund Nets transaction",r)}}async revertTransaction(e,n){this.abortController=new AbortController;let t={sessionId:e.originalTransactionId};this.currentClientToken=null;try{let{data:r}=await this.sessionApi.revertNetsSession(t);return this.currentClientToken=r.clientToken,await this.settleReversal(r,e.orderRef,this.abortController.signal,r.requiresCardTap,n)}catch(r){throw r instanceof l?r:new l("NETWORK_ERROR","Failed to revert Nets transaction",r)}}shouldVerifyAfterCancel(){return!1}abort(){this.abortController?.abort()}async settleReversal(e,n,t,r,s){let i=U(e,n);return i.status!=="PENDING"?i:(r&&s?.("REQUIRES_INPUT",{sessionId:e.sessionId}),await this.pollUntilTerminal(e.clientToken,n,t,o.POLLING_DURATION_MS,U)??R(n))}async pollUntilTerminal(e,n,t,r,s=b){let i=Date.now()+r;for(;Date.now()<i;){if(t?.aborted)throw new Error("Aborted");let a;try{a=(await this.sessionApi.getPaymentSession(e)).data}catch(c){if(c instanceof Error&&c.message==="Aborted")throw c}if(t?.aborted)throw new Error("Aborted");if(a){let c=s(a,n);if(c.status!=="PENDING")return c}await this.delay(o.POLLING_INTERVAL_MS,t)}}waitForCompletion(e,n,t,r){let s=`nets.requests.${n}`;return new Promise((i,a)=>{let c=!1,u=()=>{c=!0,typeof p=="function"&&p(),clearTimeout(f),r.removeEventListener("abort",d)},d=()=>{u(),a(new Error("Aborted"))};r.addEventListener("abort",d);let p=this.messaging.subscribe(s,Z.StatusChanged,m=>{c||m.status!==q.Pending&&(u(),i(this.mapStatusDto(m,t)))}),f=setTimeout(()=>{c||this.pollUntilTerminal(e,t.orderRef,r,o.POLLING_DURATION_MS).then(m=>{c||(u(),i(m))},m=>{c||(u(),a(m))})},o.INITIAL_POLL_DELAY_MS)})}mapStatusDto(e,n){let t=e.status===q.Success,r={success:t,status:t?"SUCCESS":"FAILED",orderId:n.orderRef};return e.transactionId&&(r.transactionId=e.transactionId),e.transaction&&(r.transaction=e.transaction),e.error?.code&&(r.errorCode=e.error.code),e.error?.message&&(r.errorMessage=e.error.message),r}finalize(e){return e.status!=="PENDING"&&this.resetIdempotencyKey(),e}resetIdempotencyKey(){this.idempotencyKey=null,this.idempotencyOrderRef=null}armCancel(e){return this.sessionApi.cancelSession(e).then(()=>{},()=>{})}generateIdempotencyKey(){let e=globalThis.crypto;return e?.randomUUID?e.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,n=>{let t=Math.random()*16|0;return(n==="x"?t:t&3|8).toString(16)})}delay(e,n){return new Promise(t=>{let r=()=>{clearTimeout(s),t()};n&&n.addEventListener("abort",r,{once:!0});let s=setTimeout(()=>{n&&n.removeEventListener("abort",r),t()},e)})}};import{PaymentApi as te,PaymentEventType as ne,PaymentProviderEnum as re,SimplePaymentStatus as w,TransactionType as B}from"@munchi_oy/core";var N=class{constructor(e,n,t){this.messaging=n;this.config=t;this.api=new te(void 0,"",e)}api;abortController=null;currentRequestId=null;paymentProvider=re.Nets;async processPayment(e,n){this.abortController=new AbortController,n("CONNECTING");let t={amount:e.amountCents,businessId:Number(this.config.storeId),referenceId:e.orderRef,currency:e.currency,displayId:e.displayId,options:{allowPinBypass:!0,transactionType:B.Purchase}};try{let{data:r}=await this.api.initiateNetsTerminalTransaction(t),s=r.connectCloudRequestId;if(!s)throw new Error("connectCloudRequestId is missing from response.");if(this.currentRequestId=s,this.abortController.signal.aborted)throw new Error("Aborted");n("REQUIRES_INPUT",{sessionId:s});let i=await this.waitForPaymentCompletion(s,e.orderRef,this.abortController.signal);return this.currentRequestId=null,i}catch(r){throw this.currentRequestId=null,r instanceof l?r:new l("TERMINAL_BUSY","Failed to create Nets Intent",r)}}async waitForPaymentCompletion(e,n,t){let r=`nets.requests.${e}`,s=ne.StatusChanged;return new Promise((i,a)=>{let c=!1,u=()=>{c=!0,typeof p=="function"&&p(),clearTimeout(f)},d=()=>{u(),a(new l("CANCELLED","Transaction cancelled"))};t.addEventListener("abort",d);let p=this.messaging.subscribe(r,s,m=>{c||m.status===w.Pending||(u(),t.removeEventListener("abort",d),i(this.handleSuccess(m)))}),f=setTimeout(async()=>{if(!(c||t.aborted))try{let m=await this.pollOrderStatus(e,n,this.config.storeId,t);i(this.handleSuccess(m))}catch(m){a(new l("TIMEOUT","Payment timed out and polling failed",m))}finally{t.removeEventListener("abort",d),u()}},1e4)})}async pollOrderStatus(e,n,t,r){let c=Date.now()+12e4;for(;Date.now()<c;){if(r.aborted)throw new Error("Aborted");try{let{data:u}=await this.api.getPaymentStatus({businessId:Number(t),orderId:n,provider:this.paymentProvider,referenceId:e});if(r.aborted)throw new Error("Aborted");if(u.status!==w.Pending)return u}catch(u){if(u instanceof Error&&u.message==="Aborted")throw u}await new Promise(u=>{let d=()=>{clearTimeout(p),u(void 0)};r.addEventListener("abort",d,{once:!0});let p=setTimeout(()=>{r.removeEventListener("abort",d),u(void 0)},2e3)})}throw new Error("Payment verification timed out.")}async cancelTransaction(e){if(!this.currentRequestId)return!1;let n={requestId:this.currentRequestId,businessId:Number(this.config.storeId)};try{return await this.api.cancelNetsTerminalTransaction(n),this.abortController?.abort(),this.currentRequestId=null,!0}catch{return!1}}async refundTransaction(e,n){try{this.abortController=new AbortController;let t={amount:e.amountCents,businessId:Number(this.config.storeId),currency:e.currency,displayId:e.displayId,referenceId:e.orderRef,options:{allowPinBypass:!0,transactionType:B.ReturnOfGoods}},{data:r}=await this.api.initiateNetsTerminalTransaction(t),s=r.connectCloudRequestId;if(!s)throw new Error("connectCloudRequestId is missing from response.");if(this.currentRequestId=s,this.abortController.signal.aborted)throw new Error("Aborted");n("REQUIRES_INPUT",{sessionId:s});let i=await this.waitForPaymentCompletion(s,e.orderRef,this.abortController.signal);return this.currentRequestId=null,i}catch(t){throw this.currentRequestId=null,t instanceof l||t instanceof l?t:new l("NETWORK_ERROR","Failed to refund Nets transaction",t)}}async verifyFinalStatus(e,n){try{let{data:t}=await this.api.getPaymentStatus({businessId:Number(this.config.storeId),orderId:e.orderRef,provider:this.paymentProvider,referenceId:n});return this.handleSuccess(t)}catch(t){throw new l("NETWORK_ERROR","Failed to verify final Nets status",t)}}handleSuccess(e){let n=e.status===w.Success,t=e.status===w.Pending,r={success:n,status:n?"SUCCESS":t?"PENDING":"FAILED",orderId:e.orderId,transaction:e.transaction};return e.transactionId&&(r.transactionId=e.transactionId),e.error?.code&&(r.errorCode=e.error.code),e.error?.message&&(r.errorMessage=e.error.message),r}abort(){this.abortController?.abort()}};import{FeeType as $,PaymentFailureCode as E,PaymentMethod as _,PaymentProvider as ie,PaymentSessionApi as oe,PaymentSessionStatus as z}from"@munchi_oy/core";var D=o=>{if(!o)return 0;let e=Number.parseInt(o,10);return Number.isFinite(e)?e:0},Q=o=>{if(!o)return new Date().toISOString();let e=new Date(o);return Number.isNaN(e.getTime())?new Date().toISOString():e.toISOString()};var ae="vivapayclient://pay/v1",ce="abort",le="sale",j="transactionDetails",ue=4e3,de="534287",me="38",pe="493591",ye="497439",fe=[pe,ye],Ie=["CREDIT","PREPAID","CORPORATE"],O=class{constructor(e,n,t,r){this.config=t;this.appToAppConfig=r;this.sessionApi=new oe(void 0,"",e)}sessionApi;abortController=null;currentClientTransactionId=null;currentIsvClientTransactionId=null;currentCurrency=null;currentOrderRef=null;currentSourceTerminalId=null;latestResult=null;wasCancelled=!1;getExecutionMode(){return"callback_driven"}async processPayment(e,n){if(!this.appToAppConfig.enabled)throw new l("STRATEGY_ERROR","Viva app-to-app is not enabled");n("CONNECTING");try{let{data:t}=await this.sessionApi.initiateVivaA2aSession(this.buildCreatePaymentPayload(e));return await this.runAction(le,this.buildLaunchParams(t),e,n)}catch(t){throw new l("NETWORK_ERROR","Failed to create Viva app-to-app payment",t)}}async cancelTransaction(e){if(!this.currentClientTransactionId)return!1;let n=await this.lookupTransactionDetails();if(n)return this.latestResult=n,this.wasCancelled=n.status==="CANCELLED",this.abortController?.abort(),!0;try{await this.appToAppConfig.adapter.openUrl(this.buildActionUrl(ce,{}))}catch(t){throw this.abortController?.abort(),new l("NETWORK_ERROR","Failed to launch Viva abort flow",t)}return this.wasCancelled=!0,this.abortController?.abort(),!0}async refundTransaction(e,n){try{let t={sessionId:e.originalTransactionId,amount:e.amountCents},{data:r}=await this.sessionApi.refundVivaSession(t),s=r.status===z.Refunded||r.status===z.Refunding,i={success:s,status:s?"SUCCESS":"FAILED",orderId:e.orderRef,transactionId:r.providerTransactionId??r.sessionId};return s||(r.errorCode&&(i.errorCode=r.errorCode),r.errorMessage&&(i.errorMessage=r.errorMessage)),i}catch(t){throw new l("NETWORK_ERROR","Failed to refund Viva transaction",t)}}async verifyFinalStatus(e,n){return this.latestResult?this.latestResult:this.wasCancelled?{success:!1,status:"CANCELLED",orderId:this.currentOrderRef??n,errorCode:E.PaymentCancelledByUser,errorMessage:"Transaction was cancelled",transactionId:n}:{success:!1,status:"PENDING",orderId:this.currentOrderRef??n,transactionId:n}}abort(){this.abortController?.abort()}async runAction(e,n,t,r){if(!this.appToAppConfig.enabled)throw new l("STRATEGY_ERROR","Viva app-to-app is not enabled");this.abortController=new AbortController,this.latestResult=null,this.wasCancelled=!1,this.currentCurrency=t.currency,this.currentOrderRef=t.orderRef,this.currentSourceTerminalId=n.sourceTerminalId??n.tid??null,this.currentClientTransactionId=n.clientTransactionId??null,this.currentIsvClientTransactionId=n.ISV_clientTransactionId??null;let s=this.currentClientTransactionId?{sessionId:this.currentClientTransactionId}:void 0;return new Promise((i,a)=>{let c=(p,f)=>{p?.(),this.abortController?.signal.removeEventListener("abort",f)},u=()=>{c(d,u),a(new Error("Aborted"))},d=this.appToAppConfig.adapter.subscribe(p=>{if(this.abortController?.signal.aborted)return;let f=this.parseCallbackUrl(p);f&&this.matchesKnownTransactionId(f.rawParams)&&(this.latestResult=f.result,this.wasCancelled=f.result.status==="CANCELLED",this.currentClientTransactionId=null,this.currentIsvClientTransactionId=null,this.currentCurrency=null,this.currentOrderRef=null,this.currentSourceTerminalId=null,c(d,u),i(f.result))});this.abortController?.signal.addEventListener("abort",u),r("REQUIRES_INPUT",s),this.appToAppConfig.adapter.openUrl(this.buildActionUrl(e,n)).then(()=>{this.abortController?.signal.aborted}).catch(p=>{c(d,u),this.currentClientTransactionId=null,this.currentIsvClientTransactionId=null,this.currentCurrency=null,this.currentOrderRef=null,this.currentSourceTerminalId=null,a(new l("NETWORK_ERROR","Failed to launch Viva app",p))})})}buildCreatePaymentPayload(e){let n=e.options??{},t={amount:e.amountCents,referenceId:e.orderRef,businessId:Number(this.config.storeId),currency:e.currency,displayId:e.displayId,showReceipt:!1,showTransactionResult:!1};return n.tipAmount!==void 0&&(t.tipAmount=n.tipAmount),e.splitContext!==void 0&&(t.splitContext=e.splitContext),t}buildLaunchParams(e){let n={};return Object.entries(e).forEach(([t,r])=>{r!==void 0&&(t==="clientToken"||t==="sessionId"||(n[t]=String(r)))}),n}buildActionUrl(e,n){let t=new URLSearchParams({action:e,appId:this.appToAppConfig.appId,callback:this.resolveCallbackQueryParam()});return Object.entries(n).forEach(([r,s])=>{t.set(r,s)}),`${ae}?${t.toString()}`}parseCallbackUrl(e){if(!this.matchesCallbackBase(e))return null;let n=new URL(e),t=Object.fromEntries(n.searchParams.entries()),r=this.isSuccessfulCallback(t),s=this.isCancelledCallback(t),i=this.resolveFailureCode(t,s),a={success:r,status:r?"SUCCESS":s?"CANCELLED":"FAILED",orderId:this.currentOrderRef??t.clientTransactionId??"unknown",errorCode:r?"":i,errorMessage:r?"":t.message??"Transaction failed without error details"};r&&(a.transaction=this.mapCallbackToTransaction(t));let c=t.transactionId??t.orderCode??t.clientTransactionId,u=t.errorCode??this.extractErrorReferenceFromMessage(t.message)??t.referenceNumber??t.tid??t.rrn;return c&&(a.transactionId=c),u&&(a.errorReference=u),{rawParams:t,result:a}}matchesCallbackBase(e){let n=new URL(e),t=this.appToAppConfig.callbackUrl;if(!t.includes("://")){let s=t.replace(/:$/,"");return n.protocol===`${s}:`}let r=new URL(t);return n.protocol===r.protocol&&n.hostname===r.hostname&&n.pathname===r.pathname}resolveCallbackQueryParam(){if(this.appToAppConfig.callbackParamFormat!=="scheme-only")return this.appToAppConfig.callbackUrl;let e=this.appToAppConfig.callbackUrl;return e.includes("://")?new URL(e).protocol.replace(/:$/,""):e.replace(/:$/,"")}matchesKnownTransactionId(e){let n=[this.currentClientTransactionId,this.currentIsvClientTransactionId].filter(r=>!!r);if(n.length===0)return!0;let t=[e.clientTransactionId,e.ISV_clientTransactionId].filter(r=>!!r);return t.length===0?!0:t.some(r=>n.includes(r))}resolveFailureCode(e,n){if(n)return E.PaymentCancelledByUser;let t=e.errorCode;if(t?.includes("."))return t;if(this.isTransactionDetailsAction(e)&&(e.transactionType??"").toLowerCase().includes("abort"))return E.SystemUnknown;let r=(e.message??"").toLowerCase(),s=(e.status??"").toLowerCase();return r.includes("declined")||s==="declined"||s==="fail"||s==="failed"||s==="failure"?E.PaymentDeclined:E.SystemUnknown}isSuccessfulCallback(e){let n=(e.status??"").toLowerCase();return this.isTransactionDetailsAction(e)?n!=="success"?!1:!(e.transactionType??"").toLowerCase().includes("abort"):n==="success"}isTransactionDetailsAction(e){return(e.action??"").toLowerCase()===j.toLowerCase()}isCancelledCallback(e){let n=(e.status??"").toLowerCase(),t=(e.message??"").toLowerCase(),r=(e.errorCode??"").toLowerCase();return n==="cancelled"||n==="canceled"||t.includes("user_cancel")||t.includes("user cancel")||t.includes("cancelled by user")||t.includes("canceled by user")||t.includes("transaction cancelled by user")||t.includes("transaction canceled by user")||r.includes("user_cancel")||r.includes("user cancel")||r==="1000"&&(t.includes("cancelled by user")||t.includes("canceled by user"))}extractErrorReferenceFromMessage(e){return e?e.match(/\((-?\d+)\)/)?.[1]:void 0}mapCallbackToTransaction(e){let n=e.transactionId??e.orderCode??e.clientTransactionId??"unknown",t=Q(e.transactionDate),r=D(e.tipAmount),s=D(e.surchargeAmount);return{amount:D(e.amount)-r-s,cardDetail:{aid:e.aid??null,applicationLabel:e.applicationLabel??null,cardNumber:e.accountNumber??"N/A",cardType:e.cardType??"N/A",issuer:e.bankId??null,orderCode:e.orderCode??null,timestamp:t,transactionId:n},createdAt:t,fees:this.buildFees(r,s),id:n,label:null,provider:ie.Viva,rawData:e,referenceId:e.clientTransactionId??null,roundingDifference:0,type:this.getVivaPaymentMethodType(e)}}getVivaPaymentMethodType(e){let n=(e.applicationLabel??"").toUpperCase().trim(),r=(e.accountNumber??"").substring(0,6),s=(e.bankId??"").trim();return r===de||s===me?_.Edenred:fe.includes(r)?_.WoltBenefit:Ie.some(i=>n.includes(i))?_.Credit:_.Debit}buildFees(e,n){if(!this.currentCurrency)return null;let t=[];return e>0&&t.push({taxAmount:0,total:{amount:e,currency:this.currentCurrency},type:$.TipAmount,vatPercentage:0}),n>0&&t.push({taxAmount:0,total:{amount:n,currency:this.currentCurrency},type:$.Surcharge,vatPercentage:0}),t.length===0?null:{parts:t}}async lookupTransactionDetails(){if(!this.currentClientTransactionId||!this.currentSourceTerminalId)return null;let e={clientTransactionId:this.currentClientTransactionId,sourceTerminalId:this.currentSourceTerminalId};return new Promise(n=>{let t=!1,r=setTimeout(()=>{t||(t=!0,s(),n(null))},ue),s=this.appToAppConfig.adapter.subscribe(i=>{if(t)return;let a=this.parseCallbackUrl(i);a&&this.matchesKnownTransactionId(a.rawParams)&&(t=!0,clearTimeout(r),s(),n(a.result))});this.appToAppConfig.adapter.openUrl(this.buildActionUrl(j,e)).catch(()=>{t||(t=!0,clearTimeout(r),s(),n(null))})})}};import{PaymentFailureCode as he,PaymentSessionApi as Re,PaymentSessionStatus as L,SimplePaymentStatus as X}from"@munchi_oy/core";var x=class o{constructor(e,n,t){this.messaging=n;this.config=t;this.sessionApi=new Re(void 0,"",e)}static POLLING_DURATION_MS=18e4;static POLLING_INTERVAL_MS=1e3;static VERIFY_DURATION_MS=3e4;static INITIAL_POLL_DELAY_MS=1e4;sessionApi;abortController=null;idempotencyKey=null;idempotencyOrderRef=null;currentClientToken=null;async processPayment(e,n){this.abortController=new AbortController,(this.idempotencyKey===null||this.idempotencyOrderRef!==e.orderRef)&&(this.idempotencyKey=this.generateIdempotencyKey(),this.idempotencyOrderRef=e.orderRef),this.currentClientToken=null,n("CONNECTING");let t={amount:e.amountCents,businessId:Number(this.config.storeId),orderId:e.orderRef};e.splitContext!==void 0&&(t.splitContext=e.splitContext);try{let{data:r}=await this.sessionApi.initiateVivaSession(t,this.idempotencyKey);this.currentClientToken=r.clientToken;let s=this.abortController.signal;if(s.aborted)throw new Error("Aborted");n("REQUIRES_INPUT",{sessionId:r.sessionId});let i=await this.waitForCompletion(r.clientToken,r.sessionId,e,s);return i?this.finalize(i):(await this.armCancel(r.clientToken),R(e.orderRef))}catch(r){throw r instanceof l?r:new l("NETWORK_ERROR","Failed to create Viva payment session",r)}}async verifyFinalStatus(e,n,t){if(!this.currentClientToken)throw new l("NETWORK_ERROR","No active payment session to verify");let r=await this.pollUntilTerminal(this.currentClientToken,e,void 0,t??o.VERIFY_DURATION_MS);return this.finalize(r??R(e.orderRef))}async cancelTransaction(e){if(!this.currentClientToken)return!1;try{await this.sessionApi.cancelSession(this.currentClientToken)}catch(n){throw new l("NETWORK_ERROR","Failed to cancel Viva payment session",n)}return this.abortController?.abort(),this.resetIdempotencyKey(),!0}async refundTransaction(e,n){try{let t={sessionId:e.originalTransactionId,amount:e.amountCents},{data:r}=await this.sessionApi.refundVivaSession(t),s=r.status===L.Refunded||r.status===L.Refunding,i={success:s,status:s?"SUCCESS":"FAILED",orderId:e.orderRef,transactionId:r.providerTransactionId??r.sessionId};return s||(r.errorCode&&(i.errorCode=r.errorCode),r.errorMessage&&(i.errorMessage=r.errorMessage)),i}catch(t){throw new l("NETWORK_ERROR","Failed to refund Viva transaction",t)}}async revertTransaction(e){try{let n={sessionId:e.originalTransactionId},{data:t}=await this.sessionApi.revertVivaSession(n),r=t.status===L.Refunded||t.status===L.Refunding,s={success:r,status:r?"SUCCESS":"FAILED",orderId:e.orderRef,transactionId:t.providerTransactionId??t.sessionId};return r||(t.errorCode&&(s.errorCode=t.errorCode),t.errorMessage&&(s.errorMessage=t.errorMessage)),s}catch(n){throw new l("NETWORK_ERROR","Failed to revert Viva transaction",n)}}abort(){this.abortController?.abort()}async pollUntilTerminal(e,n,t,r){let s=Date.now()+r;for(;Date.now()<s;){if(t?.aborted)throw new Error("Aborted");let i;try{i=(await this.sessionApi.getPaymentSession(e)).data}catch(a){if(a instanceof Error&&a.message==="Aborted")throw a}if(t?.aborted)throw new Error("Aborted");if(i){let a=b(i,n.orderRef);if(a.status!=="PENDING")return a}await this.delay(o.POLLING_INTERVAL_MS,t)}}waitForCompletion(e,n,t,r){let s=`viva.${this.config.channel.toLowerCase()}.requests.${n}`;return new Promise((i,a)=>{let c=!1,u=()=>{c=!0,typeof p=="function"&&p(),clearTimeout(f),r.removeEventListener("abort",d)},d=()=>{u(),a(new Error("Aborted"))};r.addEventListener("abort",d);let p=this.messaging.subscribe(s,"payment:status-changed",m=>{c||m.status!==X.Pending&&(u(),i(this.mapStatusDto(m,t)))}),f=setTimeout(()=>{c||this.pollUntilTerminal(e,t,r,o.POLLING_DURATION_MS).then(m=>{c||(u(),i(m))},m=>{c||(u(),a(m))})},o.INITIAL_POLL_DELAY_MS)})}mapStatusDto(e,n){let t=e.status===X.Success,r={success:t,status:t?"SUCCESS":"FAILED",orderId:n.orderRef,errorCode:e.error?.code||(t?"":he.SystemUnknown),errorMessage:e.error?.message||(t?"":"Transaction failed without error details")};return e.transactionId&&(r.transactionId=e.transactionId),e.error?.referenceError&&(r.errorReference=e.error.referenceError),e.transaction&&(r.transaction=e.transaction),r}finalize(e){return e.status!=="PENDING"&&this.resetIdempotencyKey(),e}resetIdempotencyKey(){this.idempotencyKey=null,this.idempotencyOrderRef=null}armCancel(e){return this.sessionApi.cancelSession(e).then(()=>{},()=>{})}generateIdempotencyKey(){let e=globalThis.crypto;return e?.randomUUID?e.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,n=>{let t=Math.random()*16|0;return(n==="x"?t:t&3|8).toString(16)})}delay(e,n){return new Promise(t=>{let r=()=>{clearTimeout(s),t()};n&&n.addEventListener("abort",r,{once:!0});let s=setTimeout(()=>{n&&n.removeEventListener("abort",r),t()},e)})}};import{PaymentApi as Se,PaymentFailureCode as k,PaymentProviderEnum as ge,SimplePaymentStatus as C}from"@munchi_oy/core";var v=class o{constructor(e,n,t){this.messaging=n;this.config=t;this.api=new Se(void 0,"",e)}static INITIAL_POLL_DELAY_MS=1e4;static POLLING_DURATION_MS=18e4;static POLLING_INTERVAL_MS=2e3;static TIMEOUT_CANCEL_TIMEOUT_MS=5e3;static VERIFY_TIMEOUT_MS=1e4;static VERIFY_MAX_RETRIES=3;static VERIFY_RETRY_DELAY_MS=1500;api;abortController=null;currentSessionId=null;paymentProvider=ge.Viva;async processPayment(e,n){this.abortController=new AbortController,n("CONNECTING");let t={amount:e.amountCents,referenceId:e.orderRef,businessId:parseInt(this.config.storeId),currency:e.currency,displayId:e.displayId,showReceipt:!0,showTransactionResult:!0};try{let{data:r}=await this.api.initiateTerminalTransaction(t);if(this.currentSessionId=r.sessionId,this.abortController.signal.aborted)throw new Error("Aborted");n("REQUIRES_INPUT",{sessionId:r.sessionId});let s=await this.waitForPaymentCompletion(r.sessionId,e,this.abortController.signal);return this.currentSessionId=null,s}catch(r){throw this.currentSessionId=null,r instanceof l?r:new l("NETWORK_ERROR","Failed to create Viva Intent",r)}}async waitForPaymentCompletion(e,n,t){let s=`viva.${this.config.channel.toLowerCase()}.requests.${e}`,i="payment:status-changed";return new Promise((a,c)=>{let u=!1,d=()=>{u=!0,typeof f=="function"&&f(),clearTimeout(m)},p=()=>{d(),c(new Error("Aborted"))};t.addEventListener("abort",p);let f=this.messaging.subscribe(s,i,S=>{u||S.status!==C.Pending&&(d(),t.removeEventListener("abort",p),a(this.handleSuccess(S)))}),m=setTimeout(async()=>{if(!(u||t.aborted))try{let S=await this.pollOrderStatus(e,n.orderRef,this.config.storeId,t);if(u)return;a(this.handleSuccess(S))}catch(S){if(u)return;if(S instanceof Error&&S.message==="Aborted"){c(S);return}try{let T=await this.recoverAfterPollingTimeout(n,e);a(T)}catch(T){c(T instanceof l?T:new l("TIMEOUT","Payment timed out and polling failed",T))}}finally{t.removeEventListener("abort",p),d()}},o.INITIAL_POLL_DELAY_MS)})}async pollOrderStatus(e,n,t,r){let i=Date.now()+o.POLLING_DURATION_MS;for(;Date.now()<i;){if(r.aborted)throw new Error("Aborted");try{let{data:a}=await this.api.getPaymentStatus({businessId:Number(t),orderId:n,provider:this.paymentProvider,referenceId:e});if(r.aborted)throw new Error("Aborted");if(a.status!==C.Pending)return a}catch(a){if(a instanceof Error&&a.message==="Aborted")throw a}await new Promise(a=>{let c=()=>{clearTimeout(u),a(void 0)};r.addEventListener("abort",c,{once:!0});let u=setTimeout(()=>{r.removeEventListener("abort",c),a(void 0)},o.POLLING_INTERVAL_MS)})}throw new Error("Payment verification timed out.")}async recoverAfterPollingTimeout(e,n){return await this.cancelSessionWithTimeout(n),await this.verifyFinalStatusWithRetry(e,n)}async cancelSessionWithTimeout(e){let n;try{await Promise.race([this.cancelSession(e),new Promise((t,r)=>{n=setTimeout(()=>{r(new Error("Viva timeout cancellation timed out"))},o.TIMEOUT_CANCEL_TIMEOUT_MS)})])}catch{}finally{n&&clearTimeout(n)}}async cancelSession(e){return await this.api.cancelVivaTransactionV2({cashRegisterId:this.config.storeId,sessionId:e}),this.currentSessionId===e&&(this.currentSessionId=null),!0}async verifyFinalStatusWithRetry(e,n){let t;for(let r=1;r<=o.VERIFY_MAX_RETRIES;r++)try{let s=await Promise.race([this.verifyFinalStatus(e,n),new Promise((i,a)=>setTimeout(()=>a(new Error("Verify timed out")),o.VERIFY_TIMEOUT_MS))]);if(s.status==="PENDING"){t=new Error("Verify returned pending status"),r<o.VERIFY_MAX_RETRIES&&await new Promise(i=>setTimeout(i,o.VERIFY_RETRY_DELAY_MS));continue}return s}catch(s){t=s,r<o.VERIFY_MAX_RETRIES&&await new Promise(i=>setTimeout(i,o.VERIFY_RETRY_DELAY_MS))}throw new l(k.PaymentTimeout,"Payment Failed",t)}handleSuccess(e){let n=e.status===C.Success,t={success:n,status:n?"SUCCESS":"FAILED",orderId:e.orderId,errorCode:e.error?.code||(n?"":k.SystemUnknown),errorMessage:e.error?.message||(n?"":"Transaction failed without error details")};return e.transactionId&&(t.transactionId=e.transactionId),e.error?.referenceError&&(t.errorReference=e.error.referenceError),e.transaction&&(t.transaction=e.transaction),t}async cancelTransaction(e){if(!this.currentSessionId)return!1;try{let n=this.currentSessionId;return this.currentSessionId=null,await this.api.cancelVivaTransactionV2({cashRegisterId:this.config.storeId,sessionId:n}),this.abortController?.abort(),!0}catch(n){throw this.currentSessionId=null,new l("NETWORK_ERROR","Failed to cancel Viva transaction",n)}}async verifyFinalStatus(e,n){try{let{data:t}=await this.api.getPaymentStatus({businessId:Number(this.config.storeId),orderId:e.orderRef,provider:this.paymentProvider,referenceId:n}),r=t.status===C.Success,s=t.status===C.Pending,i={success:r,status:r?"SUCCESS":s?"PENDING":"FAILED",orderId:t.orderId,errorCode:t.error?.code||(r||s?"":k.SystemUnknown),errorMessage:t.error?.message||(r||s?"":"Transaction failed without error details")};return t.transactionId&&(i.transactionId=t.transactionId),t.error?.referenceError&&(i.errorReference=t.error.referenceError),t.transaction&&(i.transaction=t.transaction),i}catch(t){throw new l("NETWORK_ERROR","Failed to verify final transaction status",t)}}async refundTransaction(e,n){try{let t={amount:e.amountCents,businessId:Number(this.config.storeId),displayId:this.config.kioskId,currency:e.currency,orderReferenceId:e.orderRef,referenceId:e.originalTransactionId},{data:r}=await this.api.refundSingleVivaTransaction(t),s=r.success;return{success:s,status:s?"SUCCESS":"FAILED",orderId:e.orderRef,transactionId:r.sessionId}}catch(t){throw new l("NETWORK_ERROR","Failed to refund Viva transaction",t)}}abort(){this.abortController?.abort()}};import{PaymentApi as Pe,PaymentEventType as H,PaymentFailureCode as Te,PaymentProviderEnum as Ee,SimplePaymentStatus as F,WorldlineApi as Ce}from"@munchi_oy/core";import{isAxiosError as ve}from"axios";var M=class{constructor(e,n,t){this.messaging=n;this.config=t;this.paymentApi=new Pe(void 0,"",e),this.worldlineApi=new Ce(void 0,"",e)}paymentApi;worldlineApi;abortController=null;currentOperationId=null;paymentProvider=Ee.Worldline;async processPayment(e,n){this.abortController=new AbortController,n("CONNECTING");let t={amount:e.amountCents,businessId:Number(this.config.storeId),currency:e.currency,displayId:e.displayId,referenceId:e.orderRef,showReceipt:!0,showTransactionResult:!0,...e.options&&"tipAmount"in e.options&&typeof e.options.tipAmount=="number"?{tipAmount:e.options.tipAmount}:{}};try{let r=await this.worldlineApi.createPayment(t),s=this.extractOperationId(r.data);if(this.currentOperationId=s,this.abortController.signal.aborted)throw new Error("Aborted");n("REQUIRES_INPUT",{sessionId:s});let i=await this.waitForPaymentCompletion(s,e.orderRef,H.StatusChanged,this.abortController.signal);return this.currentOperationId=null,i}catch(r){throw this.currentOperationId=null,r instanceof l?r:this.mapWorldlineRequestError(r,"Failed to create Worldline payment")}}async cancelTransaction(e){if(!this.currentOperationId)return!1;let n={businessId:Number(this.config.storeId),targetOperationId:this.currentOperationId};try{return await this.worldlineApi.cancelPayment(n),!0}catch(t){throw this.mapWorldlineRequestError(t,"Failed to cancel Worldline transaction")}}async refundTransaction(e,n){this.abortController=new AbortController,n("CONNECTING");let t={amount:e.amountCents,businessId:Number(this.config.storeId),currency:e.currency,displayId:e.displayId,orderReferenceId:e.orderRef,referenceId:e.originalTransactionId};try{let r=await this.worldlineApi.createRefund(t),s=this.extractOperationId(r.data);if(this.currentOperationId=s,this.abortController.signal.aborted)throw new Error("Aborted");n("REQUIRES_INPUT",{sessionId:s});let i=await this.waitForPaymentCompletion(s,e.orderRef,H.RefundStatusChanged,this.abortController.signal);return this.currentOperationId=null,i}catch(r){throw this.currentOperationId=null,r instanceof l?r:this.mapWorldlineRequestError(r,"Failed to refund Worldline transaction")}}async verifyFinalStatus(e,n){try{let{data:t}=await this.paymentApi.getPaymentStatus({businessId:Number(this.config.storeId),orderId:e.orderRef,provider:this.paymentProvider,referenceId:n});return this.handlePaymentStatus(t)}catch(t){throw this.mapWorldlineRequestError(t,"Failed to verify final Worldline status")}}abort(){this.abortController?.abort()}async waitForPaymentCompletion(e,n,t,r){let s=`worldline.requests.${e}`;return new Promise((i,a)=>{let c=!1,u=()=>{c=!0,typeof p=="function"&&p(),clearTimeout(f)},d=()=>{u(),a(new l("CANCELLED","Transaction cancelled"))};r.addEventListener("abort",d);let p=this.messaging.subscribe(s,t,m=>{c||m.status===F.Pending||(u(),r.removeEventListener("abort",d),i(this.handlePaymentStatus(m)))}),f=setTimeout(async()=>{if(!(c||r.aborted))try{let m=await this.pollOrderStatus(e,n,this.config.storeId,r);i(this.handlePaymentStatus(m))}catch(m){a(new l("TIMEOUT","Payment timed out and polling failed",m))}finally{r.removeEventListener("abort",d),u()}},1e4)})}async pollOrderStatus(e,n,t,r){let a=Date.now()+12e4;for(;Date.now()<a;){if(r.aborted)throw new Error("Aborted");try{let{data:c}=await this.paymentApi.getPaymentStatus({businessId:Number(t),orderId:n,provider:this.paymentProvider,referenceId:e});if(r.aborted)throw new Error("Aborted");if(c.status!==F.Pending)return c}catch(c){if(c instanceof Error&&c.message==="Aborted")throw c}await new Promise(c=>{let u=()=>{clearTimeout(d),c(void 0)};r.addEventListener("abort",u,{once:!0});let d=setTimeout(()=>{r.removeEventListener("abort",u),c(void 0)},2e3)})}throw new Error("Payment verification timed out.")}handlePaymentStatus(e){let n=e.status===F.Success,t=e.status===F.Pending,r={success:n,status:n?"SUCCESS":t?"PENDING":"FAILED",orderId:e.orderId,errorCode:e.error?.code||(n||t?"":Te.SystemUnknown),errorMessage:e.error?.message||(n||t?"":"Transaction failed without error details")};return e.transactionId&&(r.transactionId=e.transactionId),e.error?.referenceError&&(r.errorReference=e.error.referenceError),e.transaction&&(r.transaction=e.transaction),r}extractOperationId(e){let n=typeof e=="object"&&e!==null&&"operationId"in e&&typeof e.operationId=="string"?e.operationId:null;if(!n)throw new Error("operationId is missing from response.");return n}mapWorldlineRequestError(e,n){if(ve(e)){if(e.response?.status===400||e.response?.status===409)return new l("TERMINAL_BUSY",n,e);if(e.response?.status===404)return new l("TERMINAL_OFFLINE",n,e)}return new l("NETWORK_ERROR",n,e)}};var K=class o{strategy;axios;messaging;timeoutMs;logger;_currentState="IDLE";_listeners=[];_cancellationIntent=!1;_currentSessionId;_autoResetTimer;autoResetOptions;appToAppConfig;paymentSessionConfig;static TERMINAL_STATES=["SUCCESS","FAILED","INTERNAL_ERROR"];static RESTING_STATES=["IDLE",...o.TERMINAL_STATES];static CANCEL_VERIFY_TIMEOUT_MS=5e3;constructor(e,n,t,r={},s){this.axios=e,this.messaging=n,this.logger=r.logger,this.timeoutMs=r.timeoutMs||3e4,this.autoResetOptions=r.autoResetOnPaymentComplete,this.appToAppConfig=r.appToApp,this.paymentSessionConfig=r.paymentSession,this.strategy=s??this.resolveStrategy(t)}get version(){return W}get currentState(){return this._currentState}generateErrorResult(e,n,t){return{success:!1,status:"ERROR",errorCode:this.normalizeErrorCode(n),errorMessage:t,orderId:e}}normalizeErrorCode(e){return e?e.includes(".")?e:{CANCELLED:I.PaymentCancelledByUser,DECLINED:I.PaymentDeclined,TERMINAL_BUSY:I.TerminalBusy,TERMINAL_OFFLINE:I.TerminalOffline,TIMEOUT:I.TerminalTimeout,NETWORK_ERROR:I.SystemProviderError,STRATEGY_ERROR:I.SystemProviderError,MISSING_CONFIG:I.SystemUnknown,INVALID_AMOUNT:I.SystemUnknown,UNKNOWN:I.SystemUnknown}[e]??I.SystemUnknown:I.SystemUnknown}subscribe=e=>(this._listeners.push(e),e(this._currentState),()=>{this._listeners=this._listeners.filter(n=>n!==e)});transitionTo(e){if(this._currentState===e)return;if(e==="IDLE"){this.cancelAutoReset(),this._currentState=e,this._listeners.forEach(t=>t(e));return}if(o.TERMINAL_STATES.includes(this._currentState)){let t=`Invalid State Transition: Attempted to move from terminal state ${this._currentState} to ${e}`;throw this.logger?.error(t),this._currentState!=="INTERNAL_ERROR"&&(this._currentState="INTERNAL_ERROR",this._listeners.forEach(r=>r(this._currentState))),new l("UNKNOWN",t)}this._currentState=e,o.TERMINAL_STATES.includes(e)&&this.scheduleAutoReset(e),this._listeners.forEach(t=>t(e))}_resetScheduledAt;get nextAutoResetAt(){return this._resetScheduledAt}cancelAutoReset(){this._autoResetTimer&&(clearTimeout(this._autoResetTimer),this._autoResetTimer=void 0),this._resetScheduledAt=void 0}scheduleAutoReset(e){if(!this.autoResetOptions)return;let t=e==="SUCCESS"?this.autoResetOptions.successDelayMs??5e3:this.autoResetOptions.failureDelayMs??5e3;this.logger?.info(`Scheduling auto-reset to IDLE in ${t}ms`),this._resetScheduledAt=Date.now()+t,this._autoResetTimer=setTimeout(()=>{this.logger?.info("Auto-reset triggered"),this.reset()},t)}resolveStrategy(e){switch(e.provider){case V.Nets:return this.paymentSessionConfig?.enabled?new A(this.axios,this.messaging,e):new N(this.axios,this.messaging,e);case V.Worldline:return new M(this.axios,this.messaging,e);case V.Viva:return this.appToAppConfig?.enabled?new O(this.axios,this.messaging,e,this.appToAppConfig):this.paymentSessionConfig?.enabled?new x(this.axios,this.messaging,e):new v(this.axios,this.messaging,e);default:return new v(this.axios,this.messaging,e)}}initiateTransaction=async(e,n)=>{let t=n??{},r=e.orderRef;if(!o.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(e.orderRef,"UNKNOWN","A transaction is already in progress");let i=Date.now();if(this._cancellationIntent=!1,this._currentSessionId=void 0,this.transitionTo("IDLE"),e.amountCents<=0)return this.generateErrorResult(e.orderRef,"INVALID_AMOUNT","Amount must be greater than 0");try{let a=(p,f)=>{f?.sessionId&&(this._currentSessionId=f.sessionId),p!=="FAILED"&&(this.transitionTo(p),this.fireStateCallback(p,t,r))},c=this.strategy.processPayment(e,a),d=(this.strategy.getExecutionMode?.()??"managed")==="callback_driven"?await c:await Promise.race([c,new Promise((p,f)=>{setTimeout(()=>{f(new l("TIMEOUT","Transaction timed out"))},this.timeoutMs)})]);if(d.success)this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(d));else{if(this._cancellationIntent)return await this.handleTransactionError(e,new Error("Aborted after resolution"),t);this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(d))}return this.logger?.info("Transaction completed successfully",{orderId:e.orderRef,durationMs:Date.now()-i}),d}catch(a){return this.logger?.warn("Transaction interrupted. Handling final status...",{error:a}),await this.handleTransactionError(e,a,t)}};async handleTransactionError(e,n,t={}){let r=n instanceof l&&(n.code==="TIMEOUT"||n.code===I.PaymentTimeout);if(!this._cancellationIntent&&!r&&(this.transitionTo("VERIFYING"),this.safeFireCallback(()=>t.onVerifying?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId}))),this._cancellationIntent){try{if(this._currentSessionId&&(this.strategy.shouldVerifyAfterCancel?.()??!0)){let i=await this.strategy.verifyFinalStatus(e,this._currentSessionId,o.CANCEL_VERIFY_TIMEOUT_MS);if(i.success)return this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(i)),i}}catch(i){this.logger?.warn("Final status verification failed during cancellation",{err:i})}return this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onCancelled?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId})),{success:!1,status:"CANCELLED",errorCode:this.normalizeErrorCode("CANCELLED"),orderId:e.orderRef,...this._currentSessionId?{transactionId:this._currentSessionId}:{}}}let s;if(this.strategy.abort(),this._currentSessionId)try{let i=await this.strategy.verifyFinalStatus(e,this._currentSessionId);if(i.success)return this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(i)),i;s=r&&i.status==="PENDING"?this.buildErrorResultFromException(e.orderRef,n):i}catch(i){this.logger?.warn("Failed to get detailed error from verifyFinalStatus",{verifyErr:i}),s=this.buildErrorResultFromException(e.orderRef,i)}else s=this.buildErrorResultFromException(e.orderRef,n);return this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(s)),s}buildErrorResultFromException(e,n){return n instanceof l?this.generateErrorResult(e,n.code,n.message):this.generateErrorResult(e,"UNKNOWN",n instanceof Error?n.message:"Unknown fatal error")}fireStateCallback(e,n,t){let r={orderRef:t,refPaymentId:this._currentSessionId};switch(e){case"CONNECTING":this.safeFireCallback(()=>n.onConnecting?.(r));break;case"REQUIRES_INPUT":this.safeFireCallback(()=>n.onRequiresInput?.(r));break;case"PROCESSING":this.safeFireCallback(()=>n.onProcessing?.(r));break}}safeFireCallback(e){try{e()}catch(n){this.logger?.warn("Callback execution failed",{error:n})}}cancel=async()=>{if(this.logger?.info("Attempting cancellation"),o.TERMINAL_STATES.includes(this._currentState))return this.logger?.warn("Cannot cancel: Transaction already in terminal state",{state:this._currentState}),!1;if(!this._currentSessionId&&this._currentState==="IDLE")return this.logger?.warn("Cannot cancel: No active session to cancel",{state:this._currentState}),!1;this._cancellationIntent=!0,this.transitionTo("VERIFYING");try{return await this.strategy.cancelTransaction(n=>this.transitionTo(n))}catch(e){return this.logger?.error("Cancellation command failed",e),!1}};reset=()=>{o.TERMINAL_STATES.includes(this._currentState)&&(this._currentSessionId=void 0,this._cancellationIntent=!1,this.transitionTo("IDLE"))};refund=async(e,n)=>{let t=n??{};if(this.logger?.info("Initiating refund",{orderRef:e.orderRef}),this._currentSessionId=void 0,this._cancellationIntent=!1,!o.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(e.orderRef,"UNKNOWN","A transaction is already in progress");this.transitionTo("IDLE");try{let s=(a,c)=>{c?.sessionId&&(this._currentSessionId=c.sessionId),a!=="FAILED"&&(this.transitionTo(a),this.fireStateCallback(a,t,e.orderRef))},i=await this.strategy.refundTransaction(e,s);return i.success?(this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(i))):this._cancellationIntent||i.status==="CANCELLED"?(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onCancelled?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId}))):(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(i))),this.logger?.info("Refund completed",{success:i.success,orderRef:e.orderRef}),i}catch(s){if(this.logger?.error("Refund failed",s),this._cancellationIntent){try{if(this._currentSessionId){let a=await this.strategy.verifyFinalStatus(e,this._currentSessionId);return a.success?(this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(a)),a):a.status==="CANCELLED"?(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onCancelled?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId})),a):(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(a)),a)}}catch(a){this.logger?.warn("Refund final status verification failed",{verifyError:a})}return this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onCancelled?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId})),{success:!1,status:"CANCELLED",errorCode:this.normalizeErrorCode("CANCELLED"),orderId:e.orderRef,...this._currentSessionId?{transactionId:this._currentSessionId}:{}}}this.transitionTo("FAILED");let i=this.generateErrorResult(e.orderRef,"UNKNOWN",s instanceof Error?s.message:"Refund failed");return this.safeFireCallback(()=>t.onError?.(i)),i}};revert=async(e,n)=>{let t=n??{};if(this.logger?.info("Reverting payment",{orderRef:e.orderRef}),this._currentSessionId=e.originalTransactionId,this._cancellationIntent=!1,!o.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(e.orderRef,"UNKNOWN","A transaction is already in progress");let r=this.strategy.revertTransaction?.bind(this.strategy);if(!r)return this.generateErrorResult(e.orderRef,"STRATEGY_ERROR","Revert is not supported by the active payment strategy");this.transitionTo("CONNECTING");try{let s=await r(e,(i,a)=>{a?.sessionId&&(this._currentSessionId=a.sessionId),i!=="FAILED"&&(this.transitionTo(i),this.fireStateCallback(i,t,e.orderRef))});return this.settleSingleShot(s,e.orderRef,t),s}catch(s){return this.logger?.error("Revert failed",s),this.failSingleShot(e.orderRef,s,"Revert failed",t)}};settleSingleShot(e,n,t){e.success?(this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(e))):e.status==="CANCELLED"?(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onCancelled?.({orderRef:n,refPaymentId:this._currentSessionId}))):(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(e)))}failSingleShot(e,n,t,r){let s=this.generateErrorResult(e,"NETWORK_ERROR",n instanceof Error?n.message:t);return this.transitionTo("FAILED"),this.safeFireCallback(()=>r.onError?.(s)),s}};var be=(r=>(r.CONNECTING="CONNECTING",r.CONNECTED="CONNECTED",r.OFFLINE="OFFLINE",r.DISCONNECTED="DISCONNECTED",r))(be||{});export{be as AppReaderStatus,K as MunchiPaymentSDK,g as PaymentInteractionState,h as SdkPaymentStatus};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MunchiPaymentSDK.d.ts","sourceRoot":"","sources":["../../src/MunchiPaymentSDK.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAG3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"MunchiPaymentSDK.d.ts","sourceRoot":"","sources":["../../src/MunchiPaymentSDK.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAG3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAQtE,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,uBAAuB,EACvB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,cAAc,IAAI,iBAAiB,EAExC,KAAK,kBAAkB,EACxB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAIV,UAAU,EACX,MAAM,aAAa,CAAC;AAErB,KAAK,aAAa,GAAG,CAAC,KAAK,EAAE,uBAAuB,KAAK,IAAI,CAAC;AAE9D,qBAAa,gBAAiB,YAAW,iBAAiB;IACxD,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,aAAa,CAAyD;IAC9E,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,OAAO,CAAC,eAAe,CAA4C;IACnE,OAAO,CAAC,gBAAgB,CAA2C;IACnE,OAAO,CAAC,cAAc,CAA6B;IACnD,OAAO,CAAC,oBAAoB,CAAmC;IAE/D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAIrC;IAEF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAGpC;IAEF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAAQ;gBAGtD,KAAK,EAAE,aAAa,EACpB,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,qBAAqB,EAC7B,OAAO,GAAE,UAAe,EACxB,QAAQ,CAAC,EAAE,gBAAgB;IAY7B,IAAW,OAAO,WAEjB;IAED,IAAW,YAAY,4BAEtB;IAED,OAAO,CAAC,mBAAmB;IAc3B,OAAO,CAAC,kBAAkB;IAoBnB,SAAS,GAAI,UAAU,aAAa,KAAG,CAAC,MAAM,IAAI,CAAC,CAOxD;IAEF,OAAO,CAAC,YAAY;IAmCpB,OAAO,CAAC,iBAAiB,CAAqB;IAE9C,IAAW,eAAe,IAAI,MAAM,GAAG,SAAS,CAE/C;IAED,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,iBAAiB;IAqBzB,OAAO,CAAC,eAAe;IA4BhB,mBAAmB,GACxB,QAAQ,iBAAiB,EACzB,UAAU,kBAAkB,KAC3B,OAAO,CAAC,aAAa,CAAC,CAgGvB;YAEY,sBAAsB;IA8GpC,OAAO,CAAC,6BAA6B;IAarC,OAAO,CAAC,iBAAiB;IAsBzB,OAAO,CAAC,gBAAgB;IAQjB,MAAM,QAAa,OAAO,CAAC,OAAO,CAAC,CAyCxC;IAEK,KAAK,QAAO,IAAI,CAMrB;IAEK,MAAM,GACX,QAAQ,aAAa,EACrB,UAAU,kBAAkB,KAC3B,OAAO,CAAC,aAAa,CAAC,CAqIvB;IAEK,MAAM,GACX,QAAQ,aAAa,EACrB,UAAU,kBAAkB,KAC3B,OAAO,CAAC,aAAa,CAAC,CAgDvB;IAEF,OAAO,CAAC,gBAAgB;IAsBxB,OAAO,CAAC,cAAc;CAevB"}
|
|
@@ -5,6 +5,7 @@ export declare enum StrategyExecutionMode {
|
|
|
5
5
|
}
|
|
6
6
|
export interface IPaymentStrategy {
|
|
7
7
|
getExecutionMode?(): StrategyExecutionMode;
|
|
8
|
+
shouldVerifyAfterCancel?(): boolean;
|
|
8
9
|
processPayment(request: PaymentRequest, onStateChange: (state: PaymentInteractionState, detail?: {
|
|
9
10
|
sessionId?: string;
|
|
10
11
|
}) => void): Promise<PaymentResult>;
|
|
@@ -13,7 +14,9 @@ export interface IPaymentStrategy {
|
|
|
13
14
|
sessionId?: string;
|
|
14
15
|
}) => void): Promise<PaymentResult>;
|
|
15
16
|
verifyFinalStatus(request: PaymentRequest, sessionId: string, timeoutMs?: number): Promise<PaymentResult>;
|
|
16
|
-
revertTransaction?(request: RevertRequest
|
|
17
|
+
revertTransaction?(request: RevertRequest, onStateChange?: (state: PaymentInteractionState, detail?: {
|
|
18
|
+
sessionId?: string;
|
|
19
|
+
}) => void): Promise<PaymentResult>;
|
|
17
20
|
abort(): void;
|
|
18
21
|
}
|
|
19
22
|
//# sourceMappingURL=IPaymentStrategy.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IPaymentStrategy.d.ts","sourceRoot":"","sources":["../../../src/strategies/IPaymentStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,cAAc,EACd,aAAa,EACb,aAAa,EACb,aAAa,EACd,MAAM,kBAAkB,CAAC;AAE1B,oBAAY,qBAAqB;IAC/B,OAAO,YAAY;IACnB,cAAc,oBAAoB;CACnC;AAED,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,CAAC,IAAI,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"IPaymentStrategy.d.ts","sourceRoot":"","sources":["../../../src/strategies/IPaymentStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,cAAc,EACd,aAAa,EACb,aAAa,EACb,aAAa,EACd,MAAM,kBAAkB,CAAC;AAE1B,oBAAY,qBAAqB;IAC/B,OAAO,YAAY;IACnB,cAAc,oBAAoB;CACnC;AAED,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,CAAC,IAAI,qBAAqB,CAAC;IAC3C,uBAAuB,CAAC,IAAI,OAAO,CAAC;IAEpC,cAAc,CACZ,OAAO,EAAE,cAAc,EACvB,aAAa,EAAE,CAAC,KAAK,EAAE,uBAAuB,EAAE,MAAM,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GACvF,OAAO,CAAC,aAAa,CAAC,CAAC;IAC1B,iBAAiB,CACf,aAAa,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,IAAI,GACtD,OAAO,CAAC,OAAO,CAAC,CAAC;IACpB,iBAAiB,CACf,OAAO,EAAE,aAAa,EACtB,aAAa,EAAE,CAAC,KAAK,EAAE,uBAAuB,EAAE,MAAM,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GACvF,OAAO,CAAC,aAAa,CAAC,CAAC;IAC1B,iBAAiB,CACf,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,aAAa,CAAC,CAAC;IAC1B,iBAAiB,CAAC,CAChB,OAAO,EAAE,aAAa,EACtB,aAAa,CAAC,EAAE,CACd,KAAK,EAAE,uBAAuB,EAC9B,MAAM,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAC5B,IAAI,GACR,OAAO,CAAC,aAAa,CAAC,CAAC;IAC1B,KAAK,IAAI,IAAI,CAAC;CACf"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { AxiosInstance } from "axios";
|
|
2
|
+
import { type IMessagingAdapter, type PaymentInteractionState, type PaymentRequest, type PaymentResult, type PaymentTerminalConfig, type RefundRequest, type RevertRequest } from "../types/payment";
|
|
3
|
+
import type { IPaymentStrategy } from "./IPaymentStrategy";
|
|
4
|
+
export declare class NetsSessionStrategy implements IPaymentStrategy {
|
|
5
|
+
private messaging;
|
|
6
|
+
private config;
|
|
7
|
+
private static readonly POLLING_DURATION_MS;
|
|
8
|
+
private static readonly POLLING_INTERVAL_MS;
|
|
9
|
+
private static readonly VERIFY_DURATION_MS;
|
|
10
|
+
private static readonly INITIAL_POLL_DELAY_MS;
|
|
11
|
+
private sessionApi;
|
|
12
|
+
private abortController;
|
|
13
|
+
private idempotencyKey;
|
|
14
|
+
private idempotencyOrderRef;
|
|
15
|
+
private currentClientToken;
|
|
16
|
+
constructor(axios: AxiosInstance, messaging: IMessagingAdapter, config: PaymentTerminalConfig);
|
|
17
|
+
processPayment(request: PaymentRequest, onStateChange: (state: PaymentInteractionState, detail?: {
|
|
18
|
+
sessionId?: string;
|
|
19
|
+
}) => void): Promise<PaymentResult>;
|
|
20
|
+
verifyFinalStatus(request: PaymentRequest, _sessionId: string, timeoutMs?: number): Promise<PaymentResult>;
|
|
21
|
+
cancelTransaction(_onStateChange: (state: PaymentInteractionState) => void): Promise<boolean>;
|
|
22
|
+
refundTransaction(request: RefundRequest, onStateChange: (state: PaymentInteractionState, detail?: {
|
|
23
|
+
sessionId?: string;
|
|
24
|
+
}) => void): Promise<PaymentResult>;
|
|
25
|
+
revertTransaction(request: RevertRequest, onStateChange?: (state: PaymentInteractionState, detail?: {
|
|
26
|
+
sessionId?: string;
|
|
27
|
+
}) => void): Promise<PaymentResult>;
|
|
28
|
+
shouldVerifyAfterCancel(): boolean;
|
|
29
|
+
abort(): void;
|
|
30
|
+
private settleReversal;
|
|
31
|
+
private pollUntilTerminal;
|
|
32
|
+
private waitForCompletion;
|
|
33
|
+
private mapStatusDto;
|
|
34
|
+
private finalize;
|
|
35
|
+
private resetIdempotencyKey;
|
|
36
|
+
private armCancel;
|
|
37
|
+
private generateIdempotencyKey;
|
|
38
|
+
private delay;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=NetsSessionStrategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NetsSessionStrategy.d.ts","sourceRoot":"","sources":["../../../src/strategies/NetsSessionStrategy.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAG3C,OAAO,EACL,KAAK,iBAAiB,EAEtB,KAAK,uBAAuB,EAC5B,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAClB,KAAK,aAAa,EAEnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAQ3D,qBAAa,mBAAoB,YAAW,gBAAgB;IAcxD,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,MAAM;IAdhB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAU;IACrD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAQ;IACnD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IACnD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAS;IAEtD,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,mBAAmB,CAAuB;IAClD,OAAO,CAAC,kBAAkB,CAAuB;gBAG/C,KAAK,EAAE,aAAa,EACZ,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,qBAAqB;IAKjC,cAAc,CAClB,OAAO,EAAE,cAAc,EACvB,aAAa,EAAE,CACb,KAAK,EAAE,uBAAuB,EAC9B,MAAM,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAC5B,IAAI,GACR,OAAO,CAAC,aAAa,CAAC;IA6DnB,iBAAiB,CACrB,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,aAAa,CAAC;IAkBnB,iBAAiB,CACrB,cAAc,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,IAAI,GACvD,OAAO,CAAC,OAAO,CAAC;IAoBb,iBAAiB,CACrB,OAAO,EAAE,aAAa,EACtB,aAAa,EAAE,CACb,KAAK,EAAE,uBAAuB,EAC9B,MAAM,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAC5B,IAAI,GACR,OAAO,CAAC,aAAa,CAAC;IA4BnB,iBAAiB,CACrB,OAAO,EAAE,aAAa,EACtB,aAAa,CAAC,EAAE,CACd,KAAK,EAAE,uBAAuB,EAC9B,MAAM,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAC5B,IAAI,GACR,OAAO,CAAC,aAAa,CAAC;IA6BzB,uBAAuB,IAAI,OAAO;IAIlC,KAAK,IAAI,IAAI;YAIC,cAAc;YAgCd,iBAAiB;IAyC/B,OAAO,CAAC,iBAAiB;IA0DzB,OAAO,CAAC,YAAY;IA4BpB,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,mBAAmB;IAK3B,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,sBAAsB;IAe9B,OAAO,CAAC,KAAK;CAiBd"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VivaSessionStrategy.d.ts","sourceRoot":"","sources":["../../../src/strategies/VivaSessionStrategy.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAG3C,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAE5B,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAClB,KAAK,aAAa,EAEnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG3D,qBAAa,mBAAoB,YAAW,gBAAgB;IAcxD,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,MAAM;IAdhB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAU;IACrD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAQ;IACnD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IACnD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAS;IAEtD,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,mBAAmB,CAAuB;IAClD,OAAO,CAAC,kBAAkB,CAAuB;gBAG/C,KAAK,EAAE,aAAa,EACZ,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,qBAAqB;IAKjC,cAAc,CAClB,OAAO,EAAE,cAAc,EACvB,aAAa,EAAE,CAAC,KAAK,EAAE,uBAAuB,EAAE,MAAM,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GACvF,OAAO,CAAC,aAAa,CAAC;IA2DnB,iBAAiB,CACrB,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,aAAa,CAAC;IAkBnB,iBAAiB,CACrB,cAAc,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,IAAI,GACvD,OAAO,CAAC,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"VivaSessionStrategy.d.ts","sourceRoot":"","sources":["../../../src/strategies/VivaSessionStrategy.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAG3C,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAE5B,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAClB,KAAK,aAAa,EAEnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG3D,qBAAa,mBAAoB,YAAW,gBAAgB;IAcxD,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,MAAM;IAdhB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAU;IACrD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAQ;IACnD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IACnD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAS;IAEtD,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,mBAAmB,CAAuB;IAClD,OAAO,CAAC,kBAAkB,CAAuB;gBAG/C,KAAK,EAAE,aAAa,EACZ,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,qBAAqB;IAKjC,cAAc,CAClB,OAAO,EAAE,cAAc,EACvB,aAAa,EAAE,CAAC,KAAK,EAAE,uBAAuB,EAAE,MAAM,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GACvF,OAAO,CAAC,aAAa,CAAC;IA2DnB,iBAAiB,CACrB,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,aAAa,CAAC;IAkBnB,iBAAiB,CACrB,cAAc,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,IAAI,GACvD,OAAO,CAAC,OAAO,CAAC;IAoBb,iBAAiB,CACrB,OAAO,EAAE,aAAa,EACtB,cAAc,EAAE,CAAC,KAAK,EAAE,uBAAuB,EAAE,MAAM,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GACxF,OAAO,CAAC,aAAa,CAAC;IAmCnB,iBAAiB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAkCvE,KAAK,IAAI,IAAI;YAIC,iBAAiB;IAqC/B,OAAO,CAAC,iBAAiB;IA0DzB,OAAO,CAAC,YAAY;IA8BpB,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,mBAAmB;IAK3B,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,sBAAsB;IAgB9B,OAAO,CAAC,KAAK;CAiBd"}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import { type PaymentSessionViewDto } from "@munchi_oy/core";
|
|
1
|
+
import { PaymentSessionStatus, type PaymentSessionViewDto } from "@munchi_oy/core";
|
|
2
2
|
import { type PaymentResult } from "../types/payment";
|
|
3
3
|
export declare function pendingResult(orderId: string): PaymentResult;
|
|
4
4
|
export declare function mapSessionResult(data: PaymentSessionViewDto, orderId: string): PaymentResult;
|
|
5
|
+
export interface ReversalStatusView {
|
|
6
|
+
status: PaymentSessionStatus;
|
|
7
|
+
providerTransactionId?: string;
|
|
8
|
+
errorCode?: string;
|
|
9
|
+
errorMessage?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function mapReversalResult(data: ReversalStatusView, orderId: string): PaymentResult;
|
|
5
12
|
//# sourceMappingURL=sessionResult.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionResult.d.ts","sourceRoot":"","sources":["../../../src/strategies/sessionResult.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"sessionResult.d.ts","sourceRoot":"","sources":["../../../src/strategies/sessionResult.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,oBAAoB,EACpB,KAAK,qBAAqB,EAC3B,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,KAAK,aAAa,EAAoB,MAAM,kBAAkB,CAAC;AASxE,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAQ5D;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,qBAAqB,EAC3B,OAAO,EAAE,MAAM,GACd,aAAa,CAgEf;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,oBAAoB,CAAC;IAC7B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,MAAM,GACd,aAAa,CAgEf"}
|
package/dist/src/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "1.
|
|
1
|
+
export declare const VERSION = "1.11.1";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@munchi_oy/payments",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.1",
|
|
4
4
|
"description": "Munchi Payments SDK - Payment processing utilities",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"publishConfig": {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"@types/jest": "^30.0.0",
|
|
33
33
|
"tsup": "^8.0.0",
|
|
34
34
|
"typescript": "^5.0.0",
|
|
35
|
-
"@munchi_oy/core": "1.9.
|
|
35
|
+
"@munchi_oy/core": "1.9.74"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
38
|
"test": "jest",
|
package/src/MunchiPaymentSDK.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { version } from "../package.json";
|
|
|
4
4
|
import { PaymentErrorCode, PaymentSDKError } from "./error";
|
|
5
5
|
import type { IPaymentStrategy } from "./strategies/IPaymentStrategy";
|
|
6
6
|
import { StrategyExecutionMode } from "./strategies/IPaymentStrategy";
|
|
7
|
+
import { NetsSessionStrategy } from "./strategies/NetsSessionStrategy";
|
|
7
8
|
import { NetsStrategy } from "./strategies/NetsStrategy";
|
|
8
9
|
import { VivaAppToAppStrategy } from "./strategies/VivaAppToAppStrategy";
|
|
9
10
|
import { VivaSessionStrategy } from "./strategies/VivaSessionStrategy";
|
|
@@ -199,6 +200,9 @@ export class MunchiPaymentSDK implements IMunchiPaymentSDK {
|
|
|
199
200
|
private resolveStrategy(config: PaymentTerminalConfig): IPaymentStrategy {
|
|
200
201
|
switch (config.provider) {
|
|
201
202
|
case PaymentProvider.Nets:
|
|
203
|
+
if (this.paymentSessionConfig?.enabled) {
|
|
204
|
+
return new NetsSessionStrategy(this.axios, this.messaging, config);
|
|
205
|
+
}
|
|
202
206
|
return new NetsStrategy(this.axios, this.messaging, config);
|
|
203
207
|
case PaymentProvider.Worldline:
|
|
204
208
|
return new WorldlineStrategy(this.axios, this.messaging, config);
|
|
@@ -345,7 +349,10 @@ export class MunchiPaymentSDK implements IMunchiPaymentSDK {
|
|
|
345
349
|
|
|
346
350
|
if (this._cancellationIntent) {
|
|
347
351
|
try {
|
|
348
|
-
if (
|
|
352
|
+
if (
|
|
353
|
+
this._currentSessionId &&
|
|
354
|
+
(this.strategy.shouldVerifyAfterCancel?.() ?? true)
|
|
355
|
+
) {
|
|
349
356
|
const finalStatus = await this.strategy.verifyFinalStatus(
|
|
350
357
|
params,
|
|
351
358
|
this._currentSessionId,
|
|
@@ -692,7 +699,15 @@ export class MunchiPaymentSDK implements IMunchiPaymentSDK {
|
|
|
692
699
|
this.transitionTo(PaymentInteractionState.CONNECTING);
|
|
693
700
|
|
|
694
701
|
try {
|
|
695
|
-
const result = await revertTransaction(params)
|
|
702
|
+
const result = await revertTransaction(params, (state, detail) => {
|
|
703
|
+
if (detail?.sessionId) {
|
|
704
|
+
this._currentSessionId = detail.sessionId;
|
|
705
|
+
}
|
|
706
|
+
if (state !== PaymentInteractionState.FAILED) {
|
|
707
|
+
this.transitionTo(state);
|
|
708
|
+
this.fireStateCallback(state, callbacks, params.orderRef);
|
|
709
|
+
}
|
|
710
|
+
});
|
|
696
711
|
this.settleSingleShot(result, params.orderRef, callbacks);
|
|
697
712
|
return result;
|
|
698
713
|
} catch (error) {
|
|
@@ -13,6 +13,7 @@ export enum StrategyExecutionMode {
|
|
|
13
13
|
|
|
14
14
|
export interface IPaymentStrategy {
|
|
15
15
|
getExecutionMode?(): StrategyExecutionMode;
|
|
16
|
+
shouldVerifyAfterCancel?(): boolean;
|
|
16
17
|
|
|
17
18
|
processPayment(
|
|
18
19
|
request: PaymentRequest,
|
|
@@ -30,6 +31,12 @@ export interface IPaymentStrategy {
|
|
|
30
31
|
sessionId: string,
|
|
31
32
|
timeoutMs?: number,
|
|
32
33
|
): Promise<PaymentResult>;
|
|
33
|
-
revertTransaction?(
|
|
34
|
+
revertTransaction?(
|
|
35
|
+
request: RevertRequest,
|
|
36
|
+
onStateChange?: (
|
|
37
|
+
state: PaymentInteractionState,
|
|
38
|
+
detail?: { sessionId?: string },
|
|
39
|
+
) => void,
|
|
40
|
+
): Promise<PaymentResult>;
|
|
34
41
|
abort(): void;
|
|
35
42
|
}
|
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type InitiateNetsSessionDto,
|
|
3
|
+
PaymentEventType,
|
|
4
|
+
PaymentSessionApi,
|
|
5
|
+
type PaymentSessionViewDto,
|
|
6
|
+
type PaymentStatusDto,
|
|
7
|
+
type ReverseSessionDto,
|
|
8
|
+
SimplePaymentStatus,
|
|
9
|
+
type TransactionDto,
|
|
10
|
+
} from "@munchi_oy/core";
|
|
11
|
+
import type { AxiosInstance } from "axios";
|
|
12
|
+
|
|
13
|
+
import { PaymentErrorCode, PaymentSDKError } from "../error";
|
|
14
|
+
import {
|
|
15
|
+
type IMessagingAdapter,
|
|
16
|
+
PaymentInteractionState as InteractionState,
|
|
17
|
+
type PaymentInteractionState,
|
|
18
|
+
type PaymentRequest,
|
|
19
|
+
type PaymentResult,
|
|
20
|
+
type PaymentTerminalConfig,
|
|
21
|
+
type RefundRequest,
|
|
22
|
+
type RevertRequest,
|
|
23
|
+
SdkPaymentStatus,
|
|
24
|
+
} from "../types/payment";
|
|
25
|
+
import type { IPaymentStrategy } from "./IPaymentStrategy";
|
|
26
|
+
import {
|
|
27
|
+
mapReversalResult,
|
|
28
|
+
mapSessionResult,
|
|
29
|
+
pendingResult,
|
|
30
|
+
type ReversalStatusView,
|
|
31
|
+
} from "./sessionResult";
|
|
32
|
+
|
|
33
|
+
export class NetsSessionStrategy implements IPaymentStrategy {
|
|
34
|
+
private static readonly POLLING_DURATION_MS = 180000;
|
|
35
|
+
private static readonly POLLING_INTERVAL_MS = 1000;
|
|
36
|
+
private static readonly VERIFY_DURATION_MS = 30000;
|
|
37
|
+
private static readonly INITIAL_POLL_DELAY_MS = 10000;
|
|
38
|
+
|
|
39
|
+
private sessionApi: PaymentSessionApi;
|
|
40
|
+
private abortController: AbortController | null = null;
|
|
41
|
+
private idempotencyKey: string | null = null;
|
|
42
|
+
private idempotencyOrderRef: string | null = null;
|
|
43
|
+
private currentClientToken: string | null = null;
|
|
44
|
+
|
|
45
|
+
constructor(
|
|
46
|
+
axios: AxiosInstance,
|
|
47
|
+
private messaging: IMessagingAdapter,
|
|
48
|
+
private config: PaymentTerminalConfig,
|
|
49
|
+
) {
|
|
50
|
+
this.sessionApi = new PaymentSessionApi(undefined, "", axios);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async processPayment(
|
|
54
|
+
request: PaymentRequest,
|
|
55
|
+
onStateChange: (
|
|
56
|
+
state: PaymentInteractionState,
|
|
57
|
+
detail?: { sessionId?: string },
|
|
58
|
+
) => void,
|
|
59
|
+
): Promise<PaymentResult> {
|
|
60
|
+
this.abortController = new AbortController();
|
|
61
|
+
if (
|
|
62
|
+
this.idempotencyKey === null ||
|
|
63
|
+
this.idempotencyOrderRef !== request.orderRef
|
|
64
|
+
) {
|
|
65
|
+
this.idempotencyKey = this.generateIdempotencyKey();
|
|
66
|
+
this.idempotencyOrderRef = request.orderRef;
|
|
67
|
+
}
|
|
68
|
+
this.currentClientToken = null;
|
|
69
|
+
|
|
70
|
+
onStateChange(InteractionState.CONNECTING);
|
|
71
|
+
|
|
72
|
+
const payload: InitiateNetsSessionDto = {
|
|
73
|
+
amount: request.amountCents,
|
|
74
|
+
businessId: Number(this.config.storeId),
|
|
75
|
+
orderId: request.orderRef,
|
|
76
|
+
};
|
|
77
|
+
if (request.splitContext !== undefined) {
|
|
78
|
+
payload.splitContext = request.splitContext;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const { data } = await this.sessionApi.initiateNetsSession(
|
|
83
|
+
payload,
|
|
84
|
+
this.idempotencyKey,
|
|
85
|
+
);
|
|
86
|
+
this.currentClientToken = data.clientToken;
|
|
87
|
+
const signal = this.abortController.signal;
|
|
88
|
+
|
|
89
|
+
if (signal.aborted) {
|
|
90
|
+
throw new Error("Aborted");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
onStateChange(InteractionState.REQUIRES_INPUT, {
|
|
94
|
+
sessionId: data.sessionId,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const terminal = await this.waitForCompletion(
|
|
98
|
+
data.clientToken,
|
|
99
|
+
data.sessionId,
|
|
100
|
+
request,
|
|
101
|
+
signal,
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
if (terminal) {
|
|
105
|
+
return this.finalize(terminal);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
await this.armCancel(data.clientToken);
|
|
109
|
+
return pendingResult(request.orderRef);
|
|
110
|
+
} catch (err) {
|
|
111
|
+
if (err instanceof PaymentSDKError) throw err;
|
|
112
|
+
throw new PaymentSDKError(
|
|
113
|
+
PaymentErrorCode.TERMINAL_BUSY,
|
|
114
|
+
"Failed to create Nets payment session",
|
|
115
|
+
err,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async verifyFinalStatus(
|
|
121
|
+
request: PaymentRequest,
|
|
122
|
+
_sessionId: string,
|
|
123
|
+
timeoutMs?: number,
|
|
124
|
+
): Promise<PaymentResult> {
|
|
125
|
+
if (!this.currentClientToken) {
|
|
126
|
+
throw new PaymentSDKError(
|
|
127
|
+
PaymentErrorCode.NETWORK_ERROR,
|
|
128
|
+
"No active payment session to verify",
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const terminal = await this.pollUntilTerminal(
|
|
133
|
+
this.currentClientToken,
|
|
134
|
+
request.orderRef,
|
|
135
|
+
undefined,
|
|
136
|
+
timeoutMs ?? NetsSessionStrategy.VERIFY_DURATION_MS,
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
return this.finalize(terminal ?? pendingResult(request.orderRef));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async cancelTransaction(
|
|
143
|
+
_onStateChange: (state: PaymentInteractionState) => void,
|
|
144
|
+
): Promise<boolean> {
|
|
145
|
+
if (!this.currentClientToken) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
await this.sessionApi.cancelSession(this.currentClientToken);
|
|
151
|
+
} catch (error) {
|
|
152
|
+
throw new PaymentSDKError(
|
|
153
|
+
PaymentErrorCode.NETWORK_ERROR,
|
|
154
|
+
"Failed to cancel Nets payment session",
|
|
155
|
+
error,
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
this.abortController?.abort();
|
|
160
|
+
this.resetIdempotencyKey();
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async refundTransaction(
|
|
165
|
+
request: RefundRequest,
|
|
166
|
+
onStateChange: (
|
|
167
|
+
state: PaymentInteractionState,
|
|
168
|
+
detail?: { sessionId?: string },
|
|
169
|
+
) => void,
|
|
170
|
+
): Promise<PaymentResult> {
|
|
171
|
+
this.abortController = new AbortController();
|
|
172
|
+
onStateChange(InteractionState.CONNECTING);
|
|
173
|
+
|
|
174
|
+
const payload: ReverseSessionDto = {
|
|
175
|
+
sessionId: request.originalTransactionId,
|
|
176
|
+
amount: request.amountCents,
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
try {
|
|
180
|
+
const { data } = await this.sessionApi.refundNetsSession(payload);
|
|
181
|
+
return await this.settleReversal(
|
|
182
|
+
data,
|
|
183
|
+
request.orderRef,
|
|
184
|
+
this.abortController.signal,
|
|
185
|
+
true,
|
|
186
|
+
onStateChange,
|
|
187
|
+
);
|
|
188
|
+
} catch (error) {
|
|
189
|
+
if (error instanceof PaymentSDKError) throw error;
|
|
190
|
+
throw new PaymentSDKError(
|
|
191
|
+
PaymentErrorCode.NETWORK_ERROR,
|
|
192
|
+
"Failed to refund Nets transaction",
|
|
193
|
+
error,
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async revertTransaction(
|
|
199
|
+
request: RevertRequest,
|
|
200
|
+
onStateChange?: (
|
|
201
|
+
state: PaymentInteractionState,
|
|
202
|
+
detail?: { sessionId?: string },
|
|
203
|
+
) => void,
|
|
204
|
+
): Promise<PaymentResult> {
|
|
205
|
+
this.abortController = new AbortController();
|
|
206
|
+
|
|
207
|
+
const payload: ReverseSessionDto = {
|
|
208
|
+
sessionId: request.originalTransactionId,
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
this.currentClientToken = null;
|
|
212
|
+
|
|
213
|
+
try {
|
|
214
|
+
const { data } = await this.sessionApi.revertNetsSession(payload);
|
|
215
|
+
this.currentClientToken = data.clientToken;
|
|
216
|
+
return await this.settleReversal(
|
|
217
|
+
data,
|
|
218
|
+
request.orderRef,
|
|
219
|
+
this.abortController.signal,
|
|
220
|
+
data.requiresCardTap,
|
|
221
|
+
onStateChange,
|
|
222
|
+
);
|
|
223
|
+
} catch (error) {
|
|
224
|
+
if (error instanceof PaymentSDKError) throw error;
|
|
225
|
+
throw new PaymentSDKError(
|
|
226
|
+
PaymentErrorCode.NETWORK_ERROR,
|
|
227
|
+
"Failed to revert Nets transaction",
|
|
228
|
+
error,
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
shouldVerifyAfterCancel(): boolean {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
abort(): void {
|
|
238
|
+
this.abortController?.abort();
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private async settleReversal(
|
|
242
|
+
view: ReversalStatusView & { clientToken: string; sessionId: string },
|
|
243
|
+
orderRef: string,
|
|
244
|
+
signal: AbortSignal,
|
|
245
|
+
requiresCardTap: boolean,
|
|
246
|
+
onStateChange?: (
|
|
247
|
+
state: PaymentInteractionState,
|
|
248
|
+
detail?: { sessionId?: string },
|
|
249
|
+
) => void,
|
|
250
|
+
): Promise<PaymentResult> {
|
|
251
|
+
const immediate = mapReversalResult(view, orderRef);
|
|
252
|
+
if (immediate.status !== SdkPaymentStatus.PENDING) {
|
|
253
|
+
return immediate;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (requiresCardTap) {
|
|
257
|
+
onStateChange?.(InteractionState.REQUIRES_INPUT, {
|
|
258
|
+
sessionId: view.sessionId,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const terminal = await this.pollUntilTerminal(
|
|
263
|
+
view.clientToken,
|
|
264
|
+
orderRef,
|
|
265
|
+
signal,
|
|
266
|
+
NetsSessionStrategy.POLLING_DURATION_MS,
|
|
267
|
+
mapReversalResult,
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
return terminal ?? pendingResult(orderRef);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
private async pollUntilTerminal(
|
|
274
|
+
clientToken: string,
|
|
275
|
+
orderRef: string,
|
|
276
|
+
signal: AbortSignal | undefined,
|
|
277
|
+
durationMs: number,
|
|
278
|
+
map: (
|
|
279
|
+
data: PaymentSessionViewDto,
|
|
280
|
+
orderId: string,
|
|
281
|
+
) => PaymentResult = mapSessionResult,
|
|
282
|
+
): Promise<PaymentResult | undefined> {
|
|
283
|
+
const deadline = Date.now() + durationMs;
|
|
284
|
+
|
|
285
|
+
while (Date.now() < deadline) {
|
|
286
|
+
if (signal?.aborted) {
|
|
287
|
+
throw new Error("Aborted");
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
let data: PaymentSessionViewDto | undefined;
|
|
291
|
+
try {
|
|
292
|
+
data = (await this.sessionApi.getPaymentSession(clientToken)).data;
|
|
293
|
+
} catch (error) {
|
|
294
|
+
if (error instanceof Error && error.message === "Aborted") throw error;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (signal?.aborted) {
|
|
298
|
+
throw new Error("Aborted");
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (data) {
|
|
302
|
+
const result = map(data, orderRef);
|
|
303
|
+
if (result.status !== SdkPaymentStatus.PENDING) {
|
|
304
|
+
return result;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
await this.delay(NetsSessionStrategy.POLLING_INTERVAL_MS, signal);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return undefined;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
private waitForCompletion(
|
|
315
|
+
clientToken: string,
|
|
316
|
+
sessionId: string,
|
|
317
|
+
request: PaymentRequest,
|
|
318
|
+
signal: AbortSignal,
|
|
319
|
+
): Promise<PaymentResult | undefined> {
|
|
320
|
+
const channelName = `nets.requests.${sessionId}`;
|
|
321
|
+
|
|
322
|
+
return new Promise((resolve, reject) => {
|
|
323
|
+
let settled = false;
|
|
324
|
+
|
|
325
|
+
const cleanup = () => {
|
|
326
|
+
settled = true;
|
|
327
|
+
if (typeof unsubscribe === "function") unsubscribe();
|
|
328
|
+
clearTimeout(pollTimer);
|
|
329
|
+
signal.removeEventListener("abort", onAbort);
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
const onAbort = () => {
|
|
333
|
+
cleanup();
|
|
334
|
+
reject(new Error("Aborted"));
|
|
335
|
+
};
|
|
336
|
+
signal.addEventListener("abort", onAbort);
|
|
337
|
+
|
|
338
|
+
const unsubscribe = this.messaging.subscribe<PaymentStatusDto>(
|
|
339
|
+
channelName,
|
|
340
|
+
PaymentEventType.StatusChanged,
|
|
341
|
+
(data: PaymentStatusDto) => {
|
|
342
|
+
if (settled) return;
|
|
343
|
+
if (data.status === SimplePaymentStatus.Pending) return;
|
|
344
|
+
cleanup();
|
|
345
|
+
resolve(this.mapStatusDto(data, request));
|
|
346
|
+
},
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
const pollTimer = setTimeout(() => {
|
|
350
|
+
if (settled) return;
|
|
351
|
+
this.pollUntilTerminal(
|
|
352
|
+
clientToken,
|
|
353
|
+
request.orderRef,
|
|
354
|
+
signal,
|
|
355
|
+
NetsSessionStrategy.POLLING_DURATION_MS,
|
|
356
|
+
).then(
|
|
357
|
+
(result) => {
|
|
358
|
+
if (settled) return;
|
|
359
|
+
cleanup();
|
|
360
|
+
resolve(result);
|
|
361
|
+
},
|
|
362
|
+
(error) => {
|
|
363
|
+
if (settled) return;
|
|
364
|
+
cleanup();
|
|
365
|
+
reject(error);
|
|
366
|
+
},
|
|
367
|
+
);
|
|
368
|
+
}, NetsSessionStrategy.INITIAL_POLL_DELAY_MS);
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
private mapStatusDto(
|
|
373
|
+
data: PaymentStatusDto,
|
|
374
|
+
request: PaymentRequest,
|
|
375
|
+
): PaymentResult {
|
|
376
|
+
const isSuccess = data.status === SimplePaymentStatus.Success;
|
|
377
|
+
|
|
378
|
+
const result: PaymentResult = {
|
|
379
|
+
success: isSuccess,
|
|
380
|
+
status: isSuccess ? SdkPaymentStatus.SUCCESS : SdkPaymentStatus.FAILED,
|
|
381
|
+
orderId: request.orderRef,
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
if (data.transactionId) {
|
|
385
|
+
result.transactionId = data.transactionId;
|
|
386
|
+
}
|
|
387
|
+
if (data.transaction) {
|
|
388
|
+
result.transaction = data.transaction as unknown as TransactionDto;
|
|
389
|
+
}
|
|
390
|
+
if (data.error?.code) {
|
|
391
|
+
result.errorCode = data.error.code;
|
|
392
|
+
}
|
|
393
|
+
if (data.error?.message) {
|
|
394
|
+
result.errorMessage = data.error.message;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return result;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
private finalize(result: PaymentResult): PaymentResult {
|
|
401
|
+
if (result.status !== SdkPaymentStatus.PENDING) {
|
|
402
|
+
this.resetIdempotencyKey();
|
|
403
|
+
}
|
|
404
|
+
return result;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
private resetIdempotencyKey(): void {
|
|
408
|
+
this.idempotencyKey = null;
|
|
409
|
+
this.idempotencyOrderRef = null;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
private armCancel(clientToken: string): Promise<void> {
|
|
413
|
+
return this.sessionApi.cancelSession(clientToken).then(
|
|
414
|
+
() => undefined,
|
|
415
|
+
() => undefined,
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
private generateIdempotencyKey(): string {
|
|
420
|
+
const cryptoRef = (globalThis as { crypto?: { randomUUID?: () => string } })
|
|
421
|
+
.crypto;
|
|
422
|
+
|
|
423
|
+
if (cryptoRef?.randomUUID) {
|
|
424
|
+
return cryptoRef.randomUUID();
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (char) => {
|
|
428
|
+
const random = (Math.random() * 16) | 0;
|
|
429
|
+
const value = char === "x" ? random : (random & 0x3) | 0x8;
|
|
430
|
+
return value.toString(16);
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
private delay(ms: number, signal?: AbortSignal): Promise<void> {
|
|
435
|
+
return new Promise((resolve) => {
|
|
436
|
+
const onAbort = () => {
|
|
437
|
+
clearTimeout(timeout);
|
|
438
|
+
resolve();
|
|
439
|
+
};
|
|
440
|
+
if (signal) {
|
|
441
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
442
|
+
}
|
|
443
|
+
const timeout = setTimeout(() => {
|
|
444
|
+
if (signal) {
|
|
445
|
+
signal.removeEventListener("abort", onAbort);
|
|
446
|
+
}
|
|
447
|
+
resolve();
|
|
448
|
+
}, ms);
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
}
|
|
@@ -138,7 +138,7 @@ export class VivaSessionStrategy implements IPaymentStrategy {
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
try {
|
|
141
|
-
await this.sessionApi.
|
|
141
|
+
await this.sessionApi.cancelSession(this.currentClientToken);
|
|
142
142
|
} catch (error) {
|
|
143
143
|
throw new PaymentSDKError(
|
|
144
144
|
PaymentErrorCode.NETWORK_ERROR,
|
|
@@ -148,6 +148,7 @@ export class VivaSessionStrategy implements IPaymentStrategy {
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
this.abortController?.abort();
|
|
151
|
+
this.resetIdempotencyKey();
|
|
151
152
|
return true;
|
|
152
153
|
}
|
|
153
154
|
|
|
@@ -354,14 +355,18 @@ export class VivaSessionStrategy implements IPaymentStrategy {
|
|
|
354
355
|
|
|
355
356
|
private finalize(result: PaymentResult): PaymentResult {
|
|
356
357
|
if (result.status !== SdkPaymentStatus.PENDING) {
|
|
357
|
-
this.
|
|
358
|
-
this.idempotencyOrderRef = null;
|
|
358
|
+
this.resetIdempotencyKey();
|
|
359
359
|
}
|
|
360
360
|
return result;
|
|
361
361
|
}
|
|
362
362
|
|
|
363
|
+
private resetIdempotencyKey(): void {
|
|
364
|
+
this.idempotencyKey = null;
|
|
365
|
+
this.idempotencyOrderRef = null;
|
|
366
|
+
}
|
|
367
|
+
|
|
363
368
|
private armCancel(clientToken: string): Promise<void> {
|
|
364
|
-
return this.sessionApi.
|
|
369
|
+
return this.sessionApi.cancelSession(clientToken).then(
|
|
365
370
|
() => undefined,
|
|
366
371
|
() => undefined,
|
|
367
372
|
);
|
|
@@ -92,3 +92,79 @@ export function mapSessionResult(
|
|
|
92
92
|
return assertNever(data.status);
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
|
+
|
|
96
|
+
export interface ReversalStatusView {
|
|
97
|
+
status: PaymentSessionStatus;
|
|
98
|
+
providerTransactionId?: string;
|
|
99
|
+
errorCode?: string;
|
|
100
|
+
errorMessage?: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function mapReversalResult(
|
|
104
|
+
data: ReversalStatusView,
|
|
105
|
+
orderId: string,
|
|
106
|
+
): PaymentResult {
|
|
107
|
+
switch (data.status) {
|
|
108
|
+
case PaymentSessionStatus.Initiated:
|
|
109
|
+
case PaymentSessionStatus.Processing:
|
|
110
|
+
case PaymentSessionStatus.Dispatched:
|
|
111
|
+
case PaymentSessionStatus.Voiding:
|
|
112
|
+
case PaymentSessionStatus.VoidPending:
|
|
113
|
+
case PaymentSessionStatus.Success:
|
|
114
|
+
case PaymentSessionStatus.Closed:
|
|
115
|
+
return pendingResult(orderId);
|
|
116
|
+
|
|
117
|
+
case PaymentSessionStatus.Refunded:
|
|
118
|
+
case PaymentSessionStatus.Voided:
|
|
119
|
+
case PaymentSessionStatus.Refunding: {
|
|
120
|
+
const result: PaymentResult = {
|
|
121
|
+
success: true,
|
|
122
|
+
status: SdkPaymentStatus.SUCCESS,
|
|
123
|
+
orderId,
|
|
124
|
+
errorCode: "",
|
|
125
|
+
errorMessage: "",
|
|
126
|
+
};
|
|
127
|
+
if (data.providerTransactionId) {
|
|
128
|
+
result.transactionId = data.providerTransactionId;
|
|
129
|
+
}
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
case PaymentSessionStatus.Failed:
|
|
134
|
+
case PaymentSessionStatus.VoidFailed: {
|
|
135
|
+
const result: PaymentResult = {
|
|
136
|
+
success: false,
|
|
137
|
+
status: SdkPaymentStatus.FAILED,
|
|
138
|
+
orderId,
|
|
139
|
+
errorCode: data.errorCode || PaymentFailureCode.SystemUnknown,
|
|
140
|
+
errorMessage:
|
|
141
|
+
data.errorMessage || "Reversal failed without error details",
|
|
142
|
+
};
|
|
143
|
+
if (data.providerTransactionId) {
|
|
144
|
+
result.transactionId = data.providerTransactionId;
|
|
145
|
+
}
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
case PaymentSessionStatus.Cancelled: {
|
|
150
|
+
const result: PaymentResult = {
|
|
151
|
+
success: false,
|
|
152
|
+
status: SdkPaymentStatus.CANCELLED,
|
|
153
|
+
orderId,
|
|
154
|
+
};
|
|
155
|
+
if (data.errorCode) {
|
|
156
|
+
result.errorCode = data.errorCode;
|
|
157
|
+
}
|
|
158
|
+
if (data.errorMessage) {
|
|
159
|
+
result.errorMessage = data.errorMessage;
|
|
160
|
+
}
|
|
161
|
+
if (data.providerTransactionId) {
|
|
162
|
+
result.transactionId = data.providerTransactionId;
|
|
163
|
+
}
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
default:
|
|
168
|
+
return assertNever(data.status);
|
|
169
|
+
}
|
|
170
|
+
}
|
package/src/version.ts
CHANGED