@munchi_oy/payments 1.3.2 → 1.3.4
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 +1 -0
- package/dist/src/MunchiPaymentSDK.d.ts.map +1 -1
- package/dist/src/strategies/VivaStrategy.d.ts.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/MunchiPaymentSDK.ts +18 -5
- package/src/strategies/VivaStrategy.ts +9 -3
- package/src/version.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var N=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var O=Object.prototype.hasOwnProperty;var _=(u,e)=>{for(var r in e)N(u,r,{get:e[r],enumerable:!0})},D=(u,e,r,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of A(e))!O.call(u,n)&&n!==r&&N(u,n,{get:()=>e[n],enumerable:!(t=w(e,n))||t.enumerable});return u};var L=u=>D(N({},"__esModule",{value:!0}),u);var M={};_(M,{AppReaderStatus:()=>v,MunchiPaymentSDK:()=>P,PaymentInteractionState:()=>S,SdkPaymentStatus:()=>E});module.exports=L(M);var m=require("@munchi_oy/core");var C="1.3.2";var c=class u extends Error{code;rawError;constructor(e,r,t){super(r),this.name="PaymentSDKError",this.code=e,this.rawError=t,Object.setPrototypeOf(this,u.prototype)}};var I=require("@munchi_oy/core");var E=(s=>(s.PENDING="PENDING",s.SUCCESS="SUCCESS",s.APPROVED="APPROVED",s.FAILED="FAILED",s.CANCELLED="CANCELLED",s.ERROR="ERROR",s))(E||{}),S=(a=>(a.IDLE="IDLE",a.CONNECTING="CONNECTING",a.REQUIRES_INPUT="REQUIRES_INPUT",a.PROCESSING="PROCESSING",a.SUCCESS="SUCCESS",a.FAILED="FAILED",a.INTERNAL_ERROR="INTERNAL_ERROR",a.VERIFYING="VERIFYING",a))(S||{});var g=class{constructor(e,r,t){this.messaging=r;this.config=t;this.api=new I.PaymentApi(void 0,"",e)}api;abortController=null;currentRequestId=null;paymentProvider=I.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:I.TransactionType.Purchase}};try{let{data:n}=await this.api.initiateNetsTerminalTransaction(t),i=n.connectCloudRequestId;if(!i)throw new Error("connectCloudRequestId is missing from response.");if(this.currentRequestId=i,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:i});let s=await this.waitForPaymentCompletion(i,e.orderRef,this.abortController.signal);return this.currentRequestId=null,s}catch(n){throw this.currentRequestId=null,n instanceof c?n:new c("TERMINAL_BUSY","Failed to create Nets Intent",n)}}async waitForPaymentCompletion(e,r,t){let n=`nets.requests.${e}`,i=I.PaymentEventType.StatusChanged;return new Promise((s,d)=>{let a=!1,o=()=>{a=!0,typeof y=="function"&&y(),clearTimeout(h)},l=()=>{o(),d(new c("CANCELLED","Transaction cancelled"))};t.addEventListener("abort",l);let y=this.messaging.subscribe(n,i,p=>{a||(o(),t.removeEventListener("abort",l),s(this.handleSuccess(p)))}),h=setTimeout(async()=>{if(!(a||t.aborted))try{let p=await this.pollOrderStatus(e,r,this.config.storeId,t);s(this.handleSuccess(p))}catch(p){d(new c("TIMEOUT","Payment timed out and polling failed",p))}finally{t.removeEventListener("abort",l),o()}},1e4)})}async pollOrderStatus(e,r,t,n){let a=Date.now()+12e4;for(;Date.now()<a;){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!==I.SimplePaymentStatus.Pending)return o}catch(o){if(o instanceof Error&&o.message==="Aborted")throw o}await new Promise(o=>{let l=()=>{clearTimeout(y),o(void 0)};n.addEventListener("abort",l,{once:!0});let y=setTimeout(()=>{n.removeEventListener("abort",l),o(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:this.config.kioskId,referenceId:e.orderRef,options:{allowPinBypass:!0,transactionType:I.TransactionType.ReturnOfGoods}},{data:n}=await this.api.initiateNetsTerminalTransaction(t),i=n.connectCloudRequestId;if(!i)throw new Error("connectCloudRequestId is missing from response.");if(this.currentRequestId=i,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:i});let s=await this.waitForPaymentCompletion(i,e.orderRef,this.abortController.signal);return this.currentRequestId=null,s}catch(t){throw this.currentRequestId=null,t instanceof c||t instanceof c?t:new c("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 c("NETWORK_ERROR","Failed to verify final Nets status",t)}}handleSuccess(e){let r=e.status===I.SimplePaymentStatus.Success,t={success:r,status:r?"SUCCESS":"FAILED",orderId:e.orderId,transaction:e.transaction};return e.transactionId&&(t.transactionId=e.transactionId),e.error?.code&&(t.errorCode=e.error.code),e.error?.message&&(t.errorMessage=e.error.message),t}abort(){this.abortController?.abort()}};var f=require("@munchi_oy/core");var T=class{constructor(e,r,t){this.messaging=r;this.config=t;this.api=new f.PaymentApi(void 0,"",e)}api;abortController=null;currentSessionId=null;paymentProvider=f.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 i=await this.waitForPaymentCompletion(n.sessionId,e.orderRef,this.abortController.signal);return this.currentSessionId=null,i}catch(n){throw this.currentSessionId=null,n instanceof c?n:new c("NETWORK_ERROR","Failed to create Viva Intent",n)}}async waitForPaymentCompletion(e,r,t){let i=`viva.${this.config.channel.toLowerCase()}.requests.${e}`,s="payment:status-changed";return new Promise((d,a)=>{let o=!1,l=()=>{o=!0,typeof h=="function"&&h(),clearTimeout(p)},y=()=>{l(),a(new Error("Aborted"))};t.addEventListener("abort",y);let h=this.messaging.subscribe(i,s,R=>{o||R.status!==f.SimplePaymentStatus.Pending&&(l(),t.removeEventListener("abort",y),d(this.handleSuccess(R)))}),p=setTimeout(async()=>{if(!(o||t.aborted))try{let R=await this.pollOrderStatus(e,r,this.config.storeId,t);d(this.handleSuccess(R))}catch(R){a(new c("TIMEOUT","Payment timed out and polling failed",R))}finally{t.removeEventListener("abort",y),l()}},1e4)})}async pollOrderStatus(e,r,t,n){let a=Date.now()+12e4;for(;Date.now()<a;){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!==f.SimplePaymentStatus.Pending)return o}catch(o){if(o instanceof Error&&o.message==="Aborted")throw o}await new Promise(o=>{let l=()=>{clearTimeout(y),o(void 0)};n.addEventListener("abort",l,{once:!0});let y=setTimeout(()=>{n.removeEventListener("abort",l),o(void 0)},2e3)})}throw new Error("Payment verification timed out.")}handleSuccess(e){let r=e.status===f.SimplePaymentStatus.Success,t={success:r,status:r?"SUCCESS":"FAILED",orderId:e.orderId,errorCode:e.error?.code||(r?"":f.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 c("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===f.SimplePaymentStatus.Success,i=t.status===f.SimplePaymentStatus.Pending,s={success:n,status:n?"SUCCESS":"FAILED",orderId:t.orderId,errorCode:t.error?.code||(n?"":i?f.PaymentFailureCode.TerminalTimeout:f.PaymentFailureCode.SystemUnknown),errorMessage:t.error?.message||(n?"":i?"Payment was not completed within the allowed time":"Transaction failed without error details")};return t.transactionId&&(s.transactionId=t.transactionId),t.error?.referenceError&&(s.errorReference=t.error.referenceError),t.transaction&&(s.transaction=t.transaction),s}catch(t){throw new c("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),i=n.success;return{success:i,status:i?"SUCCESS":"FAILED",orderId:e.orderRef,transactionId:n.sessionId}}catch(t){throw new c("NETWORK_ERROR","Failed to refund Viva transaction",t)}}abort(){this.abortController?.abort()}};var P=class u{strategy;axios;messaging;timeoutMs;logger;_currentState="IDLE";_listeners=[];_cancellationIntent=!1;_currentSessionId;_autoResetTimer;autoResetOptions;static TERMINAL_STATES=["SUCCESS","FAILED","INTERNAL_ERROR"];static RESTING_STATES=["IDLE",...u.TERMINAL_STATES];constructor(e,r,t,n={},i){this.axios=e,this.messaging=r,this.logger=n.logger,this.timeoutMs=n.timeoutMs||3e4,this.autoResetOptions=n.autoResetOnPaymentComplete,this.strategy=i??this.resolveStrategy(t)}get version(){return C}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:m.PaymentFailureCode.PaymentCancelledByUser,DECLINED:m.PaymentFailureCode.PaymentDeclined,TERMINAL_BUSY:m.PaymentFailureCode.TerminalBusy,TERMINAL_OFFLINE:m.PaymentFailureCode.TerminalOffline,TIMEOUT:m.PaymentFailureCode.TerminalTimeout,NETWORK_ERROR:m.PaymentFailureCode.SystemProviderError,STRATEGY_ERROR:m.PaymentFailureCode.SystemProviderError,MISSING_CONFIG:m.PaymentFailureCode.SystemUnknown,INVALID_AMOUNT:m.PaymentFailureCode.SystemUnknown,UNKNOWN:m.PaymentFailureCode.SystemUnknown}[e]??m.PaymentFailureCode.SystemUnknown:m.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(u.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 c("UNKNOWN",t)}this._currentState=e,u.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){return e.provider===m.PaymentProvider.Nets?new g(this.axios,this.messaging,e):new T(this.axios,this.messaging,e)}initiateTransaction=async(e,r)=>{let t=r??{},n=e.orderRef;if(!u.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(e.orderRef,"UNKNOWN","A transaction is already in progress");let s=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 d=(y,h)=>{h?.sessionId&&(this._currentSessionId=h.sessionId),y!=="FAILED"&&(this.transitionTo(y),this.fireStateCallback(y,t,n))},a=this.strategy.processPayment(e,d),o=new Promise((y,h)=>{setTimeout(()=>{h(new c("TIMEOUT","Transaction timed out"))},this.timeoutMs)}),l=await Promise.race([a,o]);if(l.success)this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(l));else{if(this._cancellationIntent)return await this.handleTransactionError(e,new Error("Aborted after resolution"),t);this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(l))}return this.logger?.info("Transaction completed successfully",{orderId:e.orderRef,durationMs:Date.now()-s}),l}catch(d){return this.logger?.warn("Transaction interrupted. Handling final status...",{error:d}),await this.handleTransactionError(e,d,t)}};async handleTransactionError(e,r,t={}){let n=r instanceof c&&r.code==="TIMEOUT";if(!this._cancellationIntent&&!n&&(this.transitionTo("VERIFYING"),this.safeFireCallback(()=>t.onVerifying?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId}))),this._cancellationIntent){try{if(this._currentSessionId){let s=await this.verifyWithRetry(e,this._currentSessionId);if(s.success)return this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(s)),s}}catch(s){this.logger?.warn("Final status verification failed during cancellation",{err:s})}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 i;if(this.strategy.abort(),this._currentSessionId)try{let s=await this.verifyWithRetry(e,this._currentSessionId);if(s.success)return this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(s)),s;i=s}catch(s){this.logger?.warn("Failed to get detailed error from verifyFinalStatus",{verifyErr:s}),i=this.buildErrorResultFromException(e.orderRef,s)}else i=this.buildErrorResultFromException(e.orderRef,r);return this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(i)),i}static VERIFY_TIMEOUT_MS=1e4;static VERIFY_MAX_RETRIES=3;async verifyWithRetry(e,r){let t,n=!0;for(let d=1;d<=u.VERIFY_MAX_RETRIES;d++)try{return await Promise.race([this.strategy.verifyFinalStatus(e,r),new Promise((o,l)=>setTimeout(()=>l(new Error("Verify timed out")),u.VERIFY_TIMEOUT_MS))])}catch(a){t=a,a instanceof Error&&a.message==="Verify timed out"||(n=!1),this.logger?.warn(`verifyFinalStatus attempt ${d}/${u.VERIFY_MAX_RETRIES} failed`,{err:a})}let i=t instanceof Error?t.message:"Verify retries exhausted",s=n?m.PaymentFailureCode.PaymentTimeout:m.PaymentFailureCode.PaymentUnknown;throw new c(s,i)}buildErrorResultFromException(e,r){return r instanceof c?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"),u.TERMINAL_STATES.includes(this._currentState))return this.logger?.warn("Cannot cancel: Transaction already in terminal state",{state:this._currentState}),!1;this._cancellationIntent=!0,this.transitionTo("VERIFYING");try{let e=await this.strategy.cancelTransaction(r=>this.transitionTo(r));return!e&&this._currentState==="VERIFYING"&&this.transitionTo("IDLE"),e}catch(e){return this.logger?.error("Cancellation command failed",e),!1}};reset=()=>{u.TERMINAL_STATES.includes(this._currentState)&&this.transitionTo("IDLE")};refund=async(e,r)=>{let t=r??{};if(this.logger?.info("Initiating refund",{orderRef:e.orderRef}),this._currentSessionId=void 0,!u.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(e.orderRef,"UNKNOWN","A transaction is already in progress");this.transitionTo("IDLE");try{let i=(d,a)=>{a?.sessionId&&(this._currentSessionId=a.sessionId),d!=="FAILED"&&(this.transitionTo(d),this.fireStateCallback(d,t,e.orderRef))},s=await this.strategy.refundTransaction(e,i);return s.success?(this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(s))):(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(s))),this.logger?.info("Refund completed",{success:s.success,orderRef:e.orderRef}),s}catch(i){this.logger?.error("Refund failed",i),this.transitionTo("FAILED");let s=this.generateErrorResult(e.orderRef,"UNKNOWN",i instanceof Error?i.message:"Refund failed");return this.safeFireCallback(()=>t.onError?.(s)),s}}};var v=(n=>(n.CONNECTING="CONNECTING",n.CONNECTED="CONNECTED",n.OFFLINE="OFFLINE",n.DISCONNECTED="DISCONNECTED",n))(v||{});0&&(module.exports={AppReaderStatus,MunchiPaymentSDK,PaymentInteractionState,SdkPaymentStatus});
|
|
1
|
+
"use strict";var N=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var _=Object.prototype.hasOwnProperty;var O=(c,e)=>{for(var r in e)N(c,r,{get:e[r],enumerable:!0})},D=(c,e,r,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of A(e))!_.call(c,n)&&n!==r&&N(c,n,{get:()=>e[n],enumerable:!(t=w(e,n))||t.enumerable});return c};var L=c=>D(N({},"__esModule",{value:!0}),c);var M={};O(M,{AppReaderStatus:()=>v,MunchiPaymentSDK:()=>P,PaymentInteractionState:()=>S,SdkPaymentStatus:()=>E});module.exports=L(M);var m=require("@munchi_oy/core");var C="1.3.4";var u=class c extends Error{code;rawError;constructor(e,r,t){super(r),this.name="PaymentSDKError",this.code=e,this.rawError=t,Object.setPrototypeOf(this,c.prototype)}};var I=require("@munchi_oy/core");var E=(s=>(s.PENDING="PENDING",s.SUCCESS="SUCCESS",s.APPROVED="APPROVED",s.FAILED="FAILED",s.CANCELLED="CANCELLED",s.ERROR="ERROR",s))(E||{}),S=(a=>(a.IDLE="IDLE",a.CONNECTING="CONNECTING",a.REQUIRES_INPUT="REQUIRES_INPUT",a.PROCESSING="PROCESSING",a.SUCCESS="SUCCESS",a.FAILED="FAILED",a.INTERNAL_ERROR="INTERNAL_ERROR",a.VERIFYING="VERIFYING",a))(S||{});var g=class{constructor(e,r,t){this.messaging=r;this.config=t;this.api=new I.PaymentApi(void 0,"",e)}api;abortController=null;currentRequestId=null;paymentProvider=I.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:I.TransactionType.Purchase}};try{let{data:n}=await this.api.initiateNetsTerminalTransaction(t),i=n.connectCloudRequestId;if(!i)throw new Error("connectCloudRequestId is missing from response.");if(this.currentRequestId=i,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:i});let s=await this.waitForPaymentCompletion(i,e.orderRef,this.abortController.signal);return this.currentRequestId=null,s}catch(n){throw this.currentRequestId=null,n instanceof u?n:new u("TERMINAL_BUSY","Failed to create Nets Intent",n)}}async waitForPaymentCompletion(e,r,t){let n=`nets.requests.${e}`,i=I.PaymentEventType.StatusChanged;return new Promise((s,d)=>{let a=!1,o=()=>{a=!0,typeof y=="function"&&y(),clearTimeout(R)},l=()=>{o(),d(new u("CANCELLED","Transaction cancelled"))};t.addEventListener("abort",l);let y=this.messaging.subscribe(n,i,h=>{a||(o(),t.removeEventListener("abort",l),s(this.handleSuccess(h)))}),R=setTimeout(async()=>{if(!(a||t.aborted))try{let h=await this.pollOrderStatus(e,r,this.config.storeId,t);s(this.handleSuccess(h))}catch(h){d(new u("TIMEOUT","Payment timed out and polling failed",h))}finally{t.removeEventListener("abort",l),o()}},1e4)})}async pollOrderStatus(e,r,t,n){let a=Date.now()+12e4;for(;Date.now()<a;){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!==I.SimplePaymentStatus.Pending)return o}catch(o){if(o instanceof Error&&o.message==="Aborted")throw o}await new Promise(o=>{let l=()=>{clearTimeout(y),o(void 0)};n.addEventListener("abort",l,{once:!0});let y=setTimeout(()=>{n.removeEventListener("abort",l),o(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:this.config.kioskId,referenceId:e.orderRef,options:{allowPinBypass:!0,transactionType:I.TransactionType.ReturnOfGoods}},{data:n}=await this.api.initiateNetsTerminalTransaction(t),i=n.connectCloudRequestId;if(!i)throw new Error("connectCloudRequestId is missing from response.");if(this.currentRequestId=i,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:i});let s=await this.waitForPaymentCompletion(i,e.orderRef,this.abortController.signal);return this.currentRequestId=null,s}catch(t){throw this.currentRequestId=null,t instanceof u||t instanceof u?t:new u("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 u("NETWORK_ERROR","Failed to verify final Nets status",t)}}handleSuccess(e){let r=e.status===I.SimplePaymentStatus.Success,t={success:r,status:r?"SUCCESS":"FAILED",orderId:e.orderId,transaction:e.transaction};return e.transactionId&&(t.transactionId=e.transactionId),e.error?.code&&(t.errorCode=e.error.code),e.error?.message&&(t.errorMessage=e.error.message),t}abort(){this.abortController?.abort()}};var f=require("@munchi_oy/core");var T=class{constructor(e,r,t){this.messaging=r;this.config=t;this.api=new f.PaymentApi(void 0,"",e)}api;abortController=null;currentSessionId=null;paymentProvider=f.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 i=await this.waitForPaymentCompletion(n.sessionId,e.orderRef,this.abortController.signal);return this.currentSessionId=null,i}catch(n){throw this.currentSessionId=null,n instanceof u?n:new u("NETWORK_ERROR","Failed to create Viva Intent",n)}}async waitForPaymentCompletion(e,r,t){let i=`viva.${this.config.channel.toLowerCase()}.requests.${e}`,s="payment:status-changed";return new Promise((d,a)=>{let o=!1,l=()=>{o=!0,typeof R=="function"&&R(),clearTimeout(h)},y=()=>{l(),a(new Error("Aborted"))};t.addEventListener("abort",y);let R=this.messaging.subscribe(i,s,p=>{o||p.status!==f.SimplePaymentStatus.Pending&&(l(),t.removeEventListener("abort",y),d(this.handleSuccess(p)))}),h=setTimeout(async()=>{if(!(o||t.aborted))try{let p=await this.pollOrderStatus(e,r,this.config.storeId,t);d(this.handleSuccess(p))}catch(p){a(new u("TIMEOUT","Payment timed out and polling failed",p))}finally{t.removeEventListener("abort",y),l()}},1e4)})}async pollOrderStatus(e,r,t,n){let a=Date.now()+12e4;for(;Date.now()<a;){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!==f.SimplePaymentStatus.Pending)return o}catch(o){if(o instanceof Error&&o.message==="Aborted")throw o}await new Promise(o=>{let l=()=>{clearTimeout(y),o(void 0)};n.addEventListener("abort",l,{once:!0});let y=setTimeout(()=>{n.removeEventListener("abort",l),o(void 0)},2e3)})}throw new Error("Payment verification timed out.")}handleSuccess(e){let r=e.status===f.SimplePaymentStatus.Success,t={success:r,status:r?"SUCCESS":"FAILED",orderId:e.orderId,errorCode:e.error?.code||(r?"":f.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 u("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===f.SimplePaymentStatus.Success,i=t.status===f.SimplePaymentStatus.Pending,s={success:n,status:n?"SUCCESS":i?"PENDING":"FAILED",orderId:t.orderId,errorCode:t.error?.code||(n||i?"":f.PaymentFailureCode.SystemUnknown),errorMessage:t.error?.message||(n||i?"":"Transaction failed without error details")};return t.transactionId&&(s.transactionId=t.transactionId),t.error?.referenceError&&(s.errorReference=t.error.referenceError),t.transaction&&(s.transaction=t.transaction),s}catch(t){throw new u("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),i=n.success;return{success:i,status:i?"SUCCESS":"FAILED",orderId:e.orderRef,transactionId:n.sessionId}}catch(t){throw new u("NETWORK_ERROR","Failed to refund Viva transaction",t)}}abort(){this.abortController?.abort()}};var P=class c{strategy;axios;messaging;timeoutMs;logger;_currentState="IDLE";_listeners=[];_cancellationIntent=!1;_currentSessionId;_autoResetTimer;autoResetOptions;static TERMINAL_STATES=["SUCCESS","FAILED","INTERNAL_ERROR"];static RESTING_STATES=["IDLE",...c.TERMINAL_STATES];constructor(e,r,t,n={},i){this.axios=e,this.messaging=r,this.logger=n.logger,this.timeoutMs=n.timeoutMs||3e4,this.autoResetOptions=n.autoResetOnPaymentComplete,this.strategy=i??this.resolveStrategy(t)}get version(){return C}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:m.PaymentFailureCode.PaymentCancelledByUser,DECLINED:m.PaymentFailureCode.PaymentDeclined,TERMINAL_BUSY:m.PaymentFailureCode.TerminalBusy,TERMINAL_OFFLINE:m.PaymentFailureCode.TerminalOffline,TIMEOUT:m.PaymentFailureCode.TerminalTimeout,NETWORK_ERROR:m.PaymentFailureCode.SystemProviderError,STRATEGY_ERROR:m.PaymentFailureCode.SystemProviderError,MISSING_CONFIG:m.PaymentFailureCode.SystemUnknown,INVALID_AMOUNT:m.PaymentFailureCode.SystemUnknown,UNKNOWN:m.PaymentFailureCode.SystemUnknown}[e]??m.PaymentFailureCode.SystemUnknown:m.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(c.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 u("UNKNOWN",t)}this._currentState=e,c.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){return e.provider===m.PaymentProvider.Nets?new g(this.axios,this.messaging,e):new T(this.axios,this.messaging,e)}initiateTransaction=async(e,r)=>{let t=r??{},n=e.orderRef;if(!c.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(e.orderRef,"UNKNOWN","A transaction is already in progress");let s=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 d=(y,R)=>{R?.sessionId&&(this._currentSessionId=R.sessionId),y!=="FAILED"&&(this.transitionTo(y),this.fireStateCallback(y,t,n))},a=this.strategy.processPayment(e,d),o=new Promise((y,R)=>{setTimeout(()=>{R(new u("TIMEOUT","Transaction timed out"))},this.timeoutMs)}),l=await Promise.race([a,o]);if(l.success)this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(l));else{if(this._cancellationIntent)return await this.handleTransactionError(e,new Error("Aborted after resolution"),t);this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(l))}return this.logger?.info("Transaction completed successfully",{orderId:e.orderRef,durationMs:Date.now()-s}),l}catch(d){return this.logger?.warn("Transaction interrupted. Handling final status...",{error:d}),await this.handleTransactionError(e,d,t)}};async handleTransactionError(e,r,t={}){let n=r instanceof u&&r.code==="TIMEOUT";if(!this._cancellationIntent&&!n&&(this.transitionTo("VERIFYING"),this.safeFireCallback(()=>t.onVerifying?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId}))),this._cancellationIntent){try{if(this._currentSessionId){let s=await this.verifyWithRetry(e,this._currentSessionId);if(s.success)return this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(s)),s}}catch(s){this.logger?.warn("Final status verification failed during cancellation",{err:s})}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 i;if(this.strategy.abort(),this._currentSessionId)try{let s=await this.verifyWithRetry(e,this._currentSessionId);if(s.success)return this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(s)),s;i=s}catch(s){this.logger?.warn("Failed to get detailed error from verifyFinalStatus",{verifyErr:s}),i=this.buildErrorResultFromException(e.orderRef,s)}else i=this.buildErrorResultFromException(e.orderRef,r);return this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(i)),i}static VERIFY_TIMEOUT_MS=1e4;static VERIFY_MAX_RETRIES=3;static VERIFY_RETRY_DELAY_MS=1500;async verifyWithRetry(e,r){let t,n=!0;for(let d=1;d<=c.VERIFY_MAX_RETRIES;d++)try{let a=await Promise.race([this.strategy.verifyFinalStatus(e,r),new Promise((o,l)=>setTimeout(()=>l(new Error("Verify timed out")),c.VERIFY_TIMEOUT_MS))]);if(a.status==="PENDING"){t=new Error("Verify returned pending status"),this.logger?.warn(`verifyFinalStatus attempt ${d}/${c.VERIFY_MAX_RETRIES} returned pending status`),d<c.VERIFY_MAX_RETRIES&&await new Promise(o=>setTimeout(o,c.VERIFY_RETRY_DELAY_MS));continue}return a}catch(a){t=a,a instanceof Error&&a.message==="Verify timed out"||(n=!1),this.logger?.warn(`verifyFinalStatus attempt ${d}/${c.VERIFY_MAX_RETRIES} failed`,{err:a}),d<c.VERIFY_MAX_RETRIES&&await new Promise(l=>setTimeout(l,c.VERIFY_RETRY_DELAY_MS))}let i=t instanceof Error?t.message:"Verify retries exhausted",s=n?m.PaymentFailureCode.PaymentTimeout:m.PaymentFailureCode.PaymentUnknown;throw new u(s,i)}buildErrorResultFromException(e,r){return r instanceof u?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"),c.TERMINAL_STATES.includes(this._currentState))return this.logger?.warn("Cannot cancel: Transaction already in terminal state",{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=()=>{c.TERMINAL_STATES.includes(this._currentState)&&this.transitionTo("IDLE")};refund=async(e,r)=>{let t=r??{};if(this.logger?.info("Initiating refund",{orderRef:e.orderRef}),this._currentSessionId=void 0,!c.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(e.orderRef,"UNKNOWN","A transaction is already in progress");this.transitionTo("IDLE");try{let i=(d,a)=>{a?.sessionId&&(this._currentSessionId=a.sessionId),d!=="FAILED"&&(this.transitionTo(d),this.fireStateCallback(d,t,e.orderRef))},s=await this.strategy.refundTransaction(e,i);return s.success?(this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(s))):(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(s))),this.logger?.info("Refund completed",{success:s.success,orderRef:e.orderRef}),s}catch(i){this.logger?.error("Refund failed",i),this.transitionTo("FAILED");let s=this.generateErrorResult(e.orderRef,"UNKNOWN",i instanceof Error?i.message:"Refund failed");return this.safeFireCallback(()=>t.onError?.(s)),s}}};var v=(n=>(n.CONNECTING="CONNECTING",n.CONNECTED="CONNECTED",n.OFFLINE="OFFLINE",n.DISCONNECTED="DISCONNECTED",n))(v||{});0&&(module.exports={AppReaderStatus,MunchiPaymentSDK,PaymentInteractionState,SdkPaymentStatus});
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{PaymentFailureCode as y,PaymentProvider as F}from"@munchi_oy/core";var N="1.3.2";var c=class m extends Error{code;rawError;constructor(e,r,t){super(r),this.name="PaymentSDKError",this.code=e,this.rawError=t,Object.setPrototypeOf(this,m.prototype)}};import{PaymentApi as A,PaymentEventType as O,PaymentProviderEnum as _,SimplePaymentStatus as C,TransactionType as b}from"@munchi_oy/core";var R=(s=>(s.PENDING="PENDING",s.SUCCESS="SUCCESS",s.APPROVED="APPROVED",s.FAILED="FAILED",s.CANCELLED="CANCELLED",s.ERROR="ERROR",s))(R||{}),E=(a=>(a.IDLE="IDLE",a.CONNECTING="CONNECTING",a.REQUIRES_INPUT="REQUIRES_INPUT",a.PROCESSING="PROCESSING",a.SUCCESS="SUCCESS",a.FAILED="FAILED",a.INTERNAL_ERROR="INTERNAL_ERROR",a.VERIFYING="VERIFYING",a))(E||{});var S=class{constructor(e,r,t){this.messaging=r;this.config=t;this.api=new A(void 0,"",e)}api;abortController=null;currentRequestId=null;paymentProvider=_.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:b.Purchase}};try{let{data:n}=await this.api.initiateNetsTerminalTransaction(t),i=n.connectCloudRequestId;if(!i)throw new Error("connectCloudRequestId is missing from response.");if(this.currentRequestId=i,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:i});let s=await this.waitForPaymentCompletion(i,e.orderRef,this.abortController.signal);return this.currentRequestId=null,s}catch(n){throw this.currentRequestId=null,n instanceof c?n:new c("TERMINAL_BUSY","Failed to create Nets Intent",n)}}async waitForPaymentCompletion(e,r,t){let n=`nets.requests.${e}`,i=O.StatusChanged;return new Promise((s,u)=>{let a=!1,o=()=>{a=!0,typeof l=="function"&&l(),clearTimeout(f)},d=()=>{o(),u(new c("CANCELLED","Transaction cancelled"))};t.addEventListener("abort",d);let l=this.messaging.subscribe(n,i,I=>{a||(o(),t.removeEventListener("abort",d),s(this.handleSuccess(I)))}),f=setTimeout(async()=>{if(!(a||t.aborted))try{let I=await this.pollOrderStatus(e,r,this.config.storeId,t);s(this.handleSuccess(I))}catch(I){u(new c("TIMEOUT","Payment timed out and polling failed",I))}finally{t.removeEventListener("abort",d),o()}},1e4)})}async pollOrderStatus(e,r,t,n){let a=Date.now()+12e4;for(;Date.now()<a;){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!==C.Pending)return o}catch(o){if(o instanceof Error&&o.message==="Aborted")throw o}await new Promise(o=>{let d=()=>{clearTimeout(l),o(void 0)};n.addEventListener("abort",d,{once:!0});let l=setTimeout(()=>{n.removeEventListener("abort",d),o(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:this.config.kioskId,referenceId:e.orderRef,options:{allowPinBypass:!0,transactionType:b.ReturnOfGoods}},{data:n}=await this.api.initiateNetsTerminalTransaction(t),i=n.connectCloudRequestId;if(!i)throw new Error("connectCloudRequestId is missing from response.");if(this.currentRequestId=i,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:i});let s=await this.waitForPaymentCompletion(i,e.orderRef,this.abortController.signal);return this.currentRequestId=null,s}catch(t){throw this.currentRequestId=null,t instanceof c||t instanceof c?t:new c("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 c("NETWORK_ERROR","Failed to verify final Nets status",t)}}handleSuccess(e){let r=e.status===C.Success,t={success:r,status:r?"SUCCESS":"FAILED",orderId:e.orderId,transaction:e.transaction};return e.transactionId&&(t.transactionId=e.transactionId),e.error?.code&&(t.errorCode=e.error.code),e.error?.message&&(t.errorMessage=e.error.message),t}abort(){this.abortController?.abort()}};import{PaymentApi as D,PaymentFailureCode as T,PaymentProviderEnum as L,SimplePaymentStatus as p}from"@munchi_oy/core";var g=class{constructor(e,r,t){this.messaging=r;this.config=t;this.api=new D(void 0,"",e)}api;abortController=null;currentSessionId=null;paymentProvider=L.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 i=await this.waitForPaymentCompletion(n.sessionId,e.orderRef,this.abortController.signal);return this.currentSessionId=null,i}catch(n){throw this.currentSessionId=null,n instanceof c?n:new c("NETWORK_ERROR","Failed to create Viva Intent",n)}}async waitForPaymentCompletion(e,r,t){let i=`viva.${this.config.channel.toLowerCase()}.requests.${e}`,s="payment:status-changed";return new Promise((u,a)=>{let o=!1,d=()=>{o=!0,typeof f=="function"&&f(),clearTimeout(I)},l=()=>{d(),a(new Error("Aborted"))};t.addEventListener("abort",l);let f=this.messaging.subscribe(i,s,h=>{o||h.status!==p.Pending&&(d(),t.removeEventListener("abort",l),u(this.handleSuccess(h)))}),I=setTimeout(async()=>{if(!(o||t.aborted))try{let h=await this.pollOrderStatus(e,r,this.config.storeId,t);u(this.handleSuccess(h))}catch(h){a(new c("TIMEOUT","Payment timed out and polling failed",h))}finally{t.removeEventListener("abort",l),d()}},1e4)})}async pollOrderStatus(e,r,t,n){let a=Date.now()+12e4;for(;Date.now()<a;){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 d=()=>{clearTimeout(l),o(void 0)};n.addEventListener("abort",d,{once:!0});let l=setTimeout(()=>{n.removeEventListener("abort",d),o(void 0)},2e3)})}throw new Error("Payment verification timed out.")}handleSuccess(e){let r=e.status===p.Success,t={success:r,status:r?"SUCCESS":"FAILED",orderId:e.orderId,errorCode:e.error?.code||(r?"":T.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 c("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,i=t.status===p.Pending,s={success:n,status:n?"SUCCESS":"FAILED",orderId:t.orderId,errorCode:t.error?.code||(n?"":i?T.TerminalTimeout:T.SystemUnknown),errorMessage:t.error?.message||(n?"":i?"Payment was not completed within the allowed time":"Transaction failed without error details")};return t.transactionId&&(s.transactionId=t.transactionId),t.error?.referenceError&&(s.errorReference=t.error.referenceError),t.transaction&&(s.transaction=t.transaction),s}catch(t){throw new c("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),i=n.success;return{success:i,status:i?"SUCCESS":"FAILED",orderId:e.orderRef,transactionId:n.sessionId}}catch(t){throw new c("NETWORK_ERROR","Failed to refund Viva transaction",t)}}abort(){this.abortController?.abort()}};var P=class m{strategy;axios;messaging;timeoutMs;logger;_currentState="IDLE";_listeners=[];_cancellationIntent=!1;_currentSessionId;_autoResetTimer;autoResetOptions;static TERMINAL_STATES=["SUCCESS","FAILED","INTERNAL_ERROR"];static RESTING_STATES=["IDLE",...m.TERMINAL_STATES];constructor(e,r,t,n={},i){this.axios=e,this.messaging=r,this.logger=n.logger,this.timeoutMs=n.timeoutMs||3e4,this.autoResetOptions=n.autoResetOnPaymentComplete,this.strategy=i??this.resolveStrategy(t)}get version(){return N}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:y.PaymentCancelledByUser,DECLINED:y.PaymentDeclined,TERMINAL_BUSY:y.TerminalBusy,TERMINAL_OFFLINE:y.TerminalOffline,TIMEOUT:y.TerminalTimeout,NETWORK_ERROR:y.SystemProviderError,STRATEGY_ERROR:y.SystemProviderError,MISSING_CONFIG:y.SystemUnknown,INVALID_AMOUNT:y.SystemUnknown,UNKNOWN:y.SystemUnknown}[e]??y.SystemUnknown:y.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(m.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 c("UNKNOWN",t)}this._currentState=e,m.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){return e.provider===F.Nets?new S(this.axios,this.messaging,e):new g(this.axios,this.messaging,e)}initiateTransaction=async(e,r)=>{let t=r??{},n=e.orderRef;if(!m.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(e.orderRef,"UNKNOWN","A transaction is already in progress");let s=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 u=(l,f)=>{f?.sessionId&&(this._currentSessionId=f.sessionId),l!=="FAILED"&&(this.transitionTo(l),this.fireStateCallback(l,t,n))},a=this.strategy.processPayment(e,u),o=new Promise((l,f)=>{setTimeout(()=>{f(new c("TIMEOUT","Transaction timed out"))},this.timeoutMs)}),d=await Promise.race([a,o]);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()-s}),d}catch(u){return this.logger?.warn("Transaction interrupted. Handling final status...",{error:u}),await this.handleTransactionError(e,u,t)}};async handleTransactionError(e,r,t={}){let n=r instanceof c&&r.code==="TIMEOUT";if(!this._cancellationIntent&&!n&&(this.transitionTo("VERIFYING"),this.safeFireCallback(()=>t.onVerifying?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId}))),this._cancellationIntent){try{if(this._currentSessionId){let s=await this.verifyWithRetry(e,this._currentSessionId);if(s.success)return this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(s)),s}}catch(s){this.logger?.warn("Final status verification failed during cancellation",{err:s})}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 i;if(this.strategy.abort(),this._currentSessionId)try{let s=await this.verifyWithRetry(e,this._currentSessionId);if(s.success)return this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(s)),s;i=s}catch(s){this.logger?.warn("Failed to get detailed error from verifyFinalStatus",{verifyErr:s}),i=this.buildErrorResultFromException(e.orderRef,s)}else i=this.buildErrorResultFromException(e.orderRef,r);return this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(i)),i}static VERIFY_TIMEOUT_MS=1e4;static VERIFY_MAX_RETRIES=3;async verifyWithRetry(e,r){let t,n=!0;for(let u=1;u<=m.VERIFY_MAX_RETRIES;u++)try{return await Promise.race([this.strategy.verifyFinalStatus(e,r),new Promise((o,d)=>setTimeout(()=>d(new Error("Verify timed out")),m.VERIFY_TIMEOUT_MS))])}catch(a){t=a,a instanceof Error&&a.message==="Verify timed out"||(n=!1),this.logger?.warn(`verifyFinalStatus attempt ${u}/${m.VERIFY_MAX_RETRIES} failed`,{err:a})}let i=t instanceof Error?t.message:"Verify retries exhausted",s=n?y.PaymentTimeout:y.PaymentUnknown;throw new c(s,i)}buildErrorResultFromException(e,r){return r instanceof c?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"),m.TERMINAL_STATES.includes(this._currentState))return this.logger?.warn("Cannot cancel: Transaction already in terminal state",{state:this._currentState}),!1;this._cancellationIntent=!0,this.transitionTo("VERIFYING");try{let e=await this.strategy.cancelTransaction(r=>this.transitionTo(r));return!e&&this._currentState==="VERIFYING"&&this.transitionTo("IDLE"),e}catch(e){return this.logger?.error("Cancellation command failed",e),!1}};reset=()=>{m.TERMINAL_STATES.includes(this._currentState)&&this.transitionTo("IDLE")};refund=async(e,r)=>{let t=r??{};if(this.logger?.info("Initiating refund",{orderRef:e.orderRef}),this._currentSessionId=void 0,!m.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(e.orderRef,"UNKNOWN","A transaction is already in progress");this.transitionTo("IDLE");try{let i=(u,a)=>{a?.sessionId&&(this._currentSessionId=a.sessionId),u!=="FAILED"&&(this.transitionTo(u),this.fireStateCallback(u,t,e.orderRef))},s=await this.strategy.refundTransaction(e,i);return s.success?(this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(s))):(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(s))),this.logger?.info("Refund completed",{success:s.success,orderRef:e.orderRef}),s}catch(i){this.logger?.error("Refund failed",i),this.transitionTo("FAILED");let s=this.generateErrorResult(e.orderRef,"UNKNOWN",i instanceof Error?i.message:"Refund failed");return this.safeFireCallback(()=>t.onError?.(s)),s}}};var M=(n=>(n.CONNECTING="CONNECTING",n.CONNECTED="CONNECTED",n.OFFLINE="OFFLINE",n.DISCONNECTED="DISCONNECTED",n))(M||{});export{M as AppReaderStatus,P as MunchiPaymentSDK,E as PaymentInteractionState,R as SdkPaymentStatus};
|
|
1
|
+
import{PaymentFailureCode as y,PaymentProvider as F}from"@munchi_oy/core";var P="1.3.4";var c=class l extends Error{code;rawError;constructor(e,r,t){super(r),this.name="PaymentSDKError",this.code=e,this.rawError=t,Object.setPrototypeOf(this,l.prototype)}};import{PaymentApi as A,PaymentEventType as _,PaymentProviderEnum as O,SimplePaymentStatus as N,TransactionType as C}from"@munchi_oy/core";var p=(s=>(s.PENDING="PENDING",s.SUCCESS="SUCCESS",s.APPROVED="APPROVED",s.FAILED="FAILED",s.CANCELLED="CANCELLED",s.ERROR="ERROR",s))(p||{}),E=(a=>(a.IDLE="IDLE",a.CONNECTING="CONNECTING",a.REQUIRES_INPUT="REQUIRES_INPUT",a.PROCESSING="PROCESSING",a.SUCCESS="SUCCESS",a.FAILED="FAILED",a.INTERNAL_ERROR="INTERNAL_ERROR",a.VERIFYING="VERIFYING",a))(E||{});var S=class{constructor(e,r,t){this.messaging=r;this.config=t;this.api=new A(void 0,"",e)}api;abortController=null;currentRequestId=null;paymentProvider=O.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:C.Purchase}};try{let{data:n}=await this.api.initiateNetsTerminalTransaction(t),i=n.connectCloudRequestId;if(!i)throw new Error("connectCloudRequestId is missing from response.");if(this.currentRequestId=i,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:i});let s=await this.waitForPaymentCompletion(i,e.orderRef,this.abortController.signal);return this.currentRequestId=null,s}catch(n){throw this.currentRequestId=null,n instanceof c?n:new c("TERMINAL_BUSY","Failed to create Nets Intent",n)}}async waitForPaymentCompletion(e,r,t){let n=`nets.requests.${e}`,i=_.StatusChanged;return new Promise((s,u)=>{let a=!1,o=()=>{a=!0,typeof m=="function"&&m(),clearTimeout(f)},d=()=>{o(),u(new c("CANCELLED","Transaction cancelled"))};t.addEventListener("abort",d);let m=this.messaging.subscribe(n,i,I=>{a||(o(),t.removeEventListener("abort",d),s(this.handleSuccess(I)))}),f=setTimeout(async()=>{if(!(a||t.aborted))try{let I=await this.pollOrderStatus(e,r,this.config.storeId,t);s(this.handleSuccess(I))}catch(I){u(new c("TIMEOUT","Payment timed out and polling failed",I))}finally{t.removeEventListener("abort",d),o()}},1e4)})}async pollOrderStatus(e,r,t,n){let a=Date.now()+12e4;for(;Date.now()<a;){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!==N.Pending)return o}catch(o){if(o instanceof Error&&o.message==="Aborted")throw o}await new Promise(o=>{let d=()=>{clearTimeout(m),o(void 0)};n.addEventListener("abort",d,{once:!0});let m=setTimeout(()=>{n.removeEventListener("abort",d),o(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:this.config.kioskId,referenceId:e.orderRef,options:{allowPinBypass:!0,transactionType:C.ReturnOfGoods}},{data:n}=await this.api.initiateNetsTerminalTransaction(t),i=n.connectCloudRequestId;if(!i)throw new Error("connectCloudRequestId is missing from response.");if(this.currentRequestId=i,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:i});let s=await this.waitForPaymentCompletion(i,e.orderRef,this.abortController.signal);return this.currentRequestId=null,s}catch(t){throw this.currentRequestId=null,t instanceof c||t instanceof c?t:new c("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 c("NETWORK_ERROR","Failed to verify final Nets status",t)}}handleSuccess(e){let r=e.status===N.Success,t={success:r,status:r?"SUCCESS":"FAILED",orderId:e.orderId,transaction:e.transaction};return e.transactionId&&(t.transactionId=e.transactionId),e.error?.code&&(t.errorCode=e.error.code),e.error?.message&&(t.errorMessage=e.error.message),t}abort(){this.abortController?.abort()}};import{PaymentApi as D,PaymentFailureCode as v,PaymentProviderEnum as L,SimplePaymentStatus as h}from"@munchi_oy/core";var g=class{constructor(e,r,t){this.messaging=r;this.config=t;this.api=new D(void 0,"",e)}api;abortController=null;currentSessionId=null;paymentProvider=L.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 i=await this.waitForPaymentCompletion(n.sessionId,e.orderRef,this.abortController.signal);return this.currentSessionId=null,i}catch(n){throw this.currentSessionId=null,n instanceof c?n:new c("NETWORK_ERROR","Failed to create Viva Intent",n)}}async waitForPaymentCompletion(e,r,t){let i=`viva.${this.config.channel.toLowerCase()}.requests.${e}`,s="payment:status-changed";return new Promise((u,a)=>{let o=!1,d=()=>{o=!0,typeof f=="function"&&f(),clearTimeout(I)},m=()=>{d(),a(new Error("Aborted"))};t.addEventListener("abort",m);let f=this.messaging.subscribe(i,s,R=>{o||R.status!==h.Pending&&(d(),t.removeEventListener("abort",m),u(this.handleSuccess(R)))}),I=setTimeout(async()=>{if(!(o||t.aborted))try{let R=await this.pollOrderStatus(e,r,this.config.storeId,t);u(this.handleSuccess(R))}catch(R){a(new c("TIMEOUT","Payment timed out and polling failed",R))}finally{t.removeEventListener("abort",m),d()}},1e4)})}async pollOrderStatus(e,r,t,n){let a=Date.now()+12e4;for(;Date.now()<a;){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!==h.Pending)return o}catch(o){if(o instanceof Error&&o.message==="Aborted")throw o}await new Promise(o=>{let d=()=>{clearTimeout(m),o(void 0)};n.addEventListener("abort",d,{once:!0});let m=setTimeout(()=>{n.removeEventListener("abort",d),o(void 0)},2e3)})}throw new Error("Payment verification timed out.")}handleSuccess(e){let r=e.status===h.Success,t={success:r,status:r?"SUCCESS":"FAILED",orderId:e.orderId,errorCode:e.error?.code||(r?"":v.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 c("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===h.Success,i=t.status===h.Pending,s={success:n,status:n?"SUCCESS":i?"PENDING":"FAILED",orderId:t.orderId,errorCode:t.error?.code||(n||i?"":v.SystemUnknown),errorMessage:t.error?.message||(n||i?"":"Transaction failed without error details")};return t.transactionId&&(s.transactionId=t.transactionId),t.error?.referenceError&&(s.errorReference=t.error.referenceError),t.transaction&&(s.transaction=t.transaction),s}catch(t){throw new c("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),i=n.success;return{success:i,status:i?"SUCCESS":"FAILED",orderId:e.orderRef,transactionId:n.sessionId}}catch(t){throw new c("NETWORK_ERROR","Failed to refund Viva transaction",t)}}abort(){this.abortController?.abort()}};var T=class l{strategy;axios;messaging;timeoutMs;logger;_currentState="IDLE";_listeners=[];_cancellationIntent=!1;_currentSessionId;_autoResetTimer;autoResetOptions;static TERMINAL_STATES=["SUCCESS","FAILED","INTERNAL_ERROR"];static RESTING_STATES=["IDLE",...l.TERMINAL_STATES];constructor(e,r,t,n={},i){this.axios=e,this.messaging=r,this.logger=n.logger,this.timeoutMs=n.timeoutMs||3e4,this.autoResetOptions=n.autoResetOnPaymentComplete,this.strategy=i??this.resolveStrategy(t)}get version(){return P}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:y.PaymentCancelledByUser,DECLINED:y.PaymentDeclined,TERMINAL_BUSY:y.TerminalBusy,TERMINAL_OFFLINE:y.TerminalOffline,TIMEOUT:y.TerminalTimeout,NETWORK_ERROR:y.SystemProviderError,STRATEGY_ERROR:y.SystemProviderError,MISSING_CONFIG:y.SystemUnknown,INVALID_AMOUNT:y.SystemUnknown,UNKNOWN:y.SystemUnknown}[e]??y.SystemUnknown:y.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(l.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 c("UNKNOWN",t)}this._currentState=e,l.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){return e.provider===F.Nets?new S(this.axios,this.messaging,e):new g(this.axios,this.messaging,e)}initiateTransaction=async(e,r)=>{let t=r??{},n=e.orderRef;if(!l.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(e.orderRef,"UNKNOWN","A transaction is already in progress");let s=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 u=(m,f)=>{f?.sessionId&&(this._currentSessionId=f.sessionId),m!=="FAILED"&&(this.transitionTo(m),this.fireStateCallback(m,t,n))},a=this.strategy.processPayment(e,u),o=new Promise((m,f)=>{setTimeout(()=>{f(new c("TIMEOUT","Transaction timed out"))},this.timeoutMs)}),d=await Promise.race([a,o]);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()-s}),d}catch(u){return this.logger?.warn("Transaction interrupted. Handling final status...",{error:u}),await this.handleTransactionError(e,u,t)}};async handleTransactionError(e,r,t={}){let n=r instanceof c&&r.code==="TIMEOUT";if(!this._cancellationIntent&&!n&&(this.transitionTo("VERIFYING"),this.safeFireCallback(()=>t.onVerifying?.({orderRef:e.orderRef,refPaymentId:this._currentSessionId}))),this._cancellationIntent){try{if(this._currentSessionId){let s=await this.verifyWithRetry(e,this._currentSessionId);if(s.success)return this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(s)),s}}catch(s){this.logger?.warn("Final status verification failed during cancellation",{err:s})}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 i;if(this.strategy.abort(),this._currentSessionId)try{let s=await this.verifyWithRetry(e,this._currentSessionId);if(s.success)return this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(s)),s;i=s}catch(s){this.logger?.warn("Failed to get detailed error from verifyFinalStatus",{verifyErr:s}),i=this.buildErrorResultFromException(e.orderRef,s)}else i=this.buildErrorResultFromException(e.orderRef,r);return this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(i)),i}static VERIFY_TIMEOUT_MS=1e4;static VERIFY_MAX_RETRIES=3;static VERIFY_RETRY_DELAY_MS=1500;async verifyWithRetry(e,r){let t,n=!0;for(let u=1;u<=l.VERIFY_MAX_RETRIES;u++)try{let a=await Promise.race([this.strategy.verifyFinalStatus(e,r),new Promise((o,d)=>setTimeout(()=>d(new Error("Verify timed out")),l.VERIFY_TIMEOUT_MS))]);if(a.status==="PENDING"){t=new Error("Verify returned pending status"),this.logger?.warn(`verifyFinalStatus attempt ${u}/${l.VERIFY_MAX_RETRIES} returned pending status`),u<l.VERIFY_MAX_RETRIES&&await new Promise(o=>setTimeout(o,l.VERIFY_RETRY_DELAY_MS));continue}return a}catch(a){t=a,a instanceof Error&&a.message==="Verify timed out"||(n=!1),this.logger?.warn(`verifyFinalStatus attempt ${u}/${l.VERIFY_MAX_RETRIES} failed`,{err:a}),u<l.VERIFY_MAX_RETRIES&&await new Promise(d=>setTimeout(d,l.VERIFY_RETRY_DELAY_MS))}let i=t instanceof Error?t.message:"Verify retries exhausted",s=n?y.PaymentTimeout:y.PaymentUnknown;throw new c(s,i)}buildErrorResultFromException(e,r){return r instanceof c?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"),l.TERMINAL_STATES.includes(this._currentState))return this.logger?.warn("Cannot cancel: Transaction already in terminal state",{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=()=>{l.TERMINAL_STATES.includes(this._currentState)&&this.transitionTo("IDLE")};refund=async(e,r)=>{let t=r??{};if(this.logger?.info("Initiating refund",{orderRef:e.orderRef}),this._currentSessionId=void 0,!l.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(e.orderRef,"UNKNOWN","A transaction is already in progress");this.transitionTo("IDLE");try{let i=(u,a)=>{a?.sessionId&&(this._currentSessionId=a.sessionId),u!=="FAILED"&&(this.transitionTo(u),this.fireStateCallback(u,t,e.orderRef))},s=await this.strategy.refundTransaction(e,i);return s.success?(this.transitionTo("SUCCESS"),this.safeFireCallback(()=>t.onSuccess?.(s))):(this.transitionTo("FAILED"),this.safeFireCallback(()=>t.onError?.(s))),this.logger?.info("Refund completed",{success:s.success,orderRef:e.orderRef}),s}catch(i){this.logger?.error("Refund failed",i),this.transitionTo("FAILED");let s=this.generateErrorResult(e.orderRef,"UNKNOWN",i instanceof Error?i.message:"Refund failed");return this.safeFireCallback(()=>t.onError?.(s)),s}}};var M=(n=>(n.CONNECTING="CONNECTING",n.CONNECTED="CONNECTED",n.OFFLINE="OFFLINE",n.DISCONNECTED="DISCONNECTED",n))(M||{});export{M as AppReaderStatus,T as MunchiPaymentSDK,E as PaymentInteractionState,p as SdkPaymentStatus};
|
|
@@ -33,6 +33,7 @@ export declare class MunchiPaymentSDK implements IMunchiPaymentSDK {
|
|
|
33
33
|
private handleTransactionError;
|
|
34
34
|
private static readonly VERIFY_TIMEOUT_MS;
|
|
35
35
|
private static readonly VERIFY_MAX_RETRIES;
|
|
36
|
+
private static readonly VERIFY_RETRY_DELAY_MS;
|
|
36
37
|
private verifyWithRetry;
|
|
37
38
|
private buildErrorResultFromException;
|
|
38
39
|
private fireStateCallback;
|
|
@@ -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;AAGtE,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,uBAAuB,EACvB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAClB,KAAK,cAAc,IAAI,iBAAiB,EAExC,KAAK,kBAAkB,EACxB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAW,UAAU,EAAE,MAAM,aAAa,CAAC;AAEvD,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;IAEnE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAIrC;IAEF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAGpC;gBAGA,KAAK,EAAE,aAAa,EACpB,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,qBAAqB,EAC7B,OAAO,GAAE,UAAe,EACxB,QAAQ,CAAC,EAAE,gBAAgB;IAU7B,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;IAUhB,mBAAmB,GACxB,QAAQ,iBAAiB,EACzB,UAAU,kBAAkB,KAC3B,OAAO,CAAC,aAAa,CAAC,CA0FvB;YAEY,sBAAsB;IAqGpC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAClD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAK;
|
|
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;AAGtE,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,uBAAuB,EACvB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAClB,KAAK,cAAc,IAAI,iBAAiB,EAExC,KAAK,kBAAkB,EACxB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAW,UAAU,EAAE,MAAM,aAAa,CAAC;AAEvD,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;IAEnE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAIrC;IAEF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAGpC;gBAGA,KAAK,EAAE,aAAa,EACpB,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,qBAAqB,EAC7B,OAAO,GAAE,UAAe,EACxB,QAAQ,CAAC,EAAE,gBAAgB;IAU7B,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;IAUhB,mBAAmB,GACxB,QAAQ,iBAAiB,EACzB,UAAU,kBAAkB,KAC3B,OAAO,CAAC,aAAa,CAAC,CA0FvB;YAEY,sBAAsB;IAqGpC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAClD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAK;IAC/C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAQ;YAEvC,eAAe;IAwD7B,OAAO,CAAC,6BAA6B;IAarC,OAAO,CAAC,iBAAiB;IAsBzB,OAAO,CAAC,gBAAgB;IAQjB,MAAM,QAAa,OAAO,CAAC,OAAO,CAAC,CA+BxC;IAEK,KAAK,QAAO,IAAI,CAIrB;IAEK,MAAM,GACX,QAAQ,aAAa,EACrB,UAAU,kBAAkB,KAC3B,OAAO,CAAC,aAAa,CAAC,CAkEvB;CACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VivaStrategy.d.ts","sourceRoot":"","sources":["../../../src/strategies/VivaStrategy.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAG3C,OAAO,EACL,KAAK,iBAAiB,EACtB,uBAAuB,EACvB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAEnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,qBAAa,YAAa,YAAW,gBAAgB;IAOjD,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,MAAM;IAPhB,OAAO,CAAC,GAAG,CAAa;IACxB,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,eAAe,CAA4B;gBAEjD,KAAK,EAAE,aAAa,EACZ,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,qBAAqB;IAOjC,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;YA2CX,wBAAwB;YAmExB,eAAe;IAiD7B,OAAO,CAAC,aAAa;IAgCf,iBAAiB,CACrB,cAAc,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,IAAI,GACvD,OAAO,CAAC,OAAO,CAAC;IA0Bb,iBAAiB,CAAC,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"VivaStrategy.d.ts","sourceRoot":"","sources":["../../../src/strategies/VivaStrategy.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAG3C,OAAO,EACL,KAAK,iBAAiB,EACtB,uBAAuB,EACvB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAEnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,qBAAa,YAAa,YAAW,gBAAgB;IAOjD,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,MAAM;IAPhB,OAAO,CAAC,GAAG,CAAa;IACxB,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,eAAe,CAA4B;gBAEjD,KAAK,EAAE,aAAa,EACZ,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,qBAAqB;IAOjC,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;YA2CX,wBAAwB;YAmExB,eAAe;IAiD7B,OAAO,CAAC,aAAa;IAgCf,iBAAiB,CACrB,cAAc,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,IAAI,GACvD,OAAO,CAAC,OAAO,CAAC;IA0Bb,iBAAiB,CAAC,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAsDrF,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;IAgCzB,KAAK,IAAI,IAAI;CAGd"}
|
package/dist/src/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "1.3.
|
|
1
|
+
export declare const VERSION = "1.3.4";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/package.json
CHANGED
package/src/MunchiPaymentSDK.ts
CHANGED
|
@@ -388,6 +388,7 @@ export class MunchiPaymentSDK implements IMunchiPaymentSDK {
|
|
|
388
388
|
|
|
389
389
|
private static readonly VERIFY_TIMEOUT_MS = 10000;
|
|
390
390
|
private static readonly VERIFY_MAX_RETRIES = 3;
|
|
391
|
+
private static readonly VERIFY_RETRY_DELAY_MS = 1500;
|
|
391
392
|
|
|
392
393
|
private async verifyWithRetry(
|
|
393
394
|
params: SdkPaymentRequest,
|
|
@@ -407,6 +408,18 @@ export class MunchiPaymentSDK implements IMunchiPaymentSDK {
|
|
|
407
408
|
),
|
|
408
409
|
),
|
|
409
410
|
]);
|
|
411
|
+
if (result.status === SdkPaymentStatus.PENDING) {
|
|
412
|
+
lastError = new Error("Verify returned pending status");
|
|
413
|
+
this.logger?.warn(
|
|
414
|
+
`verifyFinalStatus attempt ${attempt}/${MunchiPaymentSDK.VERIFY_MAX_RETRIES} returned pending status`,
|
|
415
|
+
);
|
|
416
|
+
if (attempt < MunchiPaymentSDK.VERIFY_MAX_RETRIES) {
|
|
417
|
+
await new Promise((resolve) =>
|
|
418
|
+
setTimeout(resolve, MunchiPaymentSDK.VERIFY_RETRY_DELAY_MS),
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
410
423
|
return result;
|
|
411
424
|
} catch (err) {
|
|
412
425
|
lastError = err;
|
|
@@ -417,6 +430,11 @@ export class MunchiPaymentSDK implements IMunchiPaymentSDK {
|
|
|
417
430
|
`verifyFinalStatus attempt ${attempt}/${MunchiPaymentSDK.VERIFY_MAX_RETRIES} failed`,
|
|
418
431
|
{ err },
|
|
419
432
|
);
|
|
433
|
+
if (attempt < MunchiPaymentSDK.VERIFY_MAX_RETRIES) {
|
|
434
|
+
await new Promise((resolve) =>
|
|
435
|
+
setTimeout(resolve, MunchiPaymentSDK.VERIFY_RETRY_DELAY_MS),
|
|
436
|
+
);
|
|
437
|
+
}
|
|
420
438
|
}
|
|
421
439
|
}
|
|
422
440
|
|
|
@@ -493,11 +511,6 @@ export class MunchiPaymentSDK implements IMunchiPaymentSDK {
|
|
|
493
511
|
this.transitionTo(state),
|
|
494
512
|
);
|
|
495
513
|
|
|
496
|
-
// If cancellation failed (e.g. no active session) AND we are just verifying,
|
|
497
|
-
// we should probably revert to IDLE or FAILED to avoid getting stuck.
|
|
498
|
-
if (!result && this._currentState === PaymentInteractionState.VERIFYING) {
|
|
499
|
-
this.transitionTo(PaymentInteractionState.IDLE);
|
|
500
|
-
}
|
|
501
514
|
return result;
|
|
502
515
|
} catch (error) {
|
|
503
516
|
this.logger?.error("Cancellation command failed", error);
|
|
@@ -275,14 +275,20 @@ export class VivaStrategy implements IPaymentStrategy {
|
|
|
275
275
|
|
|
276
276
|
const result: PaymentResult = {
|
|
277
277
|
success: isSuccess,
|
|
278
|
-
status: isSuccess
|
|
278
|
+
status: isSuccess
|
|
279
|
+
? SdkPaymentStatus.SUCCESS
|
|
280
|
+
: isPending
|
|
281
|
+
? SdkPaymentStatus.PENDING
|
|
282
|
+
: SdkPaymentStatus.FAILED,
|
|
279
283
|
orderId: data.orderId,
|
|
280
284
|
errorCode:
|
|
281
285
|
data.error?.code ||
|
|
282
|
-
(isSuccess
|
|
286
|
+
(isSuccess || isPending ? "" : PaymentFailureCode.SystemUnknown),
|
|
283
287
|
errorMessage:
|
|
284
288
|
data.error?.message ||
|
|
285
|
-
(isSuccess
|
|
289
|
+
(isSuccess || isPending
|
|
290
|
+
? ""
|
|
291
|
+
: "Transaction failed without error details"),
|
|
286
292
|
};
|
|
287
293
|
|
|
288
294
|
if (data.transactionId) {
|
package/src/version.ts
CHANGED