@munchi_oy/payments 1.3.6 → 1.4.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 CHANGED
@@ -1 +1 @@
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.6";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 f=="function"&&f(),clearTimeout(h)},l=()=>{o(),d(new u("CANCELLED","Transaction cancelled"))};t.addEventListener("abort",l);let f=this.messaging.subscribe(n,i,R=>{a||(o(),t.removeEventListener("abort",l),s(this.handleSuccess(R)))}),h=setTimeout(async()=>{if(!(a||t.aborted))try{let R=await this.pollOrderStatus(e,r,this.config.storeId,t);s(this.handleSuccess(R))}catch(R){d(new u("TIMEOUT","Payment timed out and polling failed",R))}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(f),o(void 0)};n.addEventListener("abort",l,{once:!0});let f=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 y=require("@munchi_oy/core");var T=class{constructor(e,r,t){this.messaging=r;this.config=t;this.api=new y.PaymentApi(void 0,"",e)}api;abortController=null;currentSessionId=null;paymentProvider=y.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 h=="function"&&h(),clearTimeout(R)},f=()=>{l(),a(new Error("Aborted"))};t.addEventListener("abort",f);let h=this.messaging.subscribe(i,s,p=>{o||p.status!==y.SimplePaymentStatus.Pending&&(l(),t.removeEventListener("abort",f),d(this.handleSuccess(p)))}),R=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",f),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!==y.SimplePaymentStatus.Pending)return o}catch(o){if(o instanceof Error&&o.message==="Aborted")throw o}await new Promise(o=>{let l=()=>{clearTimeout(f),o(void 0)};n.addEventListener("abort",l,{once:!0});let f=setTimeout(()=>{n.removeEventListener("abort",l),o(void 0)},2e3)})}throw new Error("Payment verification timed out.")}handleSuccess(e){let r=e.status===y.SimplePaymentStatus.Success,t={success:r,status:r?"SUCCESS":"FAILED",orderId:e.orderId,errorCode:e.error?.code||(r?"":y.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===y.SimplePaymentStatus.Success,i=t.status===y.SimplePaymentStatus.Pending,s={success:n,status:n?"SUCCESS":i?"PENDING":"FAILED",orderId:t.orderId,errorCode:t.error?.code||(n||i?"":y.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=(f,h)=>{h?.sessionId&&(this._currentSessionId=h.sessionId),f!=="FAILED"&&(this.transitionTo(f),this.fireStateCallback(f,t,n))},a=this.strategy.processPayment(e,d),o=new Promise((f,h)=>{setTimeout(()=>{h(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;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=()=>{c.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,!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});
1
+ "use strict";var w=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var L=Object.prototype.hasOwnProperty;var F=(u,t)=>{for(var r in t)w(u,r,{get:t[r],enumerable:!0})},M=(u,t,r,e)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of D(t))!L.call(u,n)&&n!==r&&w(u,n,{get:()=>t[n],enumerable:!(e=_(t,n))||e.enumerable});return u};var x=u=>M(w({},"__esModule",{value:!0}),u);var k={};F(k,{AppReaderStatus:()=>O,MunchiPaymentSDK:()=>b,PaymentInteractionState:()=>g,SdkPaymentStatus:()=>S});module.exports=x(k);var y=require("@munchi_oy/core");var v="1.4.1";var c=class u extends Error{code;rawError;constructor(t,r,e){super(r),this.name="PaymentSDKError",this.code=t,this.rawError=e,Object.setPrototypeOf(this,u.prototype)}};var h=require("@munchi_oy/core");var S=(s=>(s.PENDING="PENDING",s.SUCCESS="SUCCESS",s.APPROVED="APPROVED",s.FAILED="FAILED",s.CANCELLED="CANCELLED",s.ERROR="ERROR",s))(S||{}),g=(o=>(o.IDLE="IDLE",o.CONNECTING="CONNECTING",o.REQUIRES_INPUT="REQUIRES_INPUT",o.PROCESSING="PROCESSING",o.SUCCESS="SUCCESS",o.FAILED="FAILED",o.INTERNAL_ERROR="INTERNAL_ERROR",o.VERIFYING="VERIFYING",o))(g||{});var P=class{constructor(t,r,e){this.messaging=r;this.config=e;this.api=new h.PaymentApi(void 0,"",t)}api;abortController=null;currentRequestId=null;paymentProvider=h.PaymentProviderEnum.Nets;async processPayment(t,r){this.abortController=new AbortController,r("CONNECTING");let e={amount:t.amountCents,businessId:Number(this.config.storeId),referenceId:t.orderRef,currency:t.currency,displayId:t.displayId,options:{allowPinBypass:!0,transactionType:h.TransactionType.Purchase}};try{let{data:n}=await this.api.initiateNetsTerminalTransaction(e),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,t.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(t,r,e){let n=`nets.requests.${t}`,i=h.PaymentEventType.StatusChanged;return new Promise((s,d)=>{let o=!1,a=()=>{o=!0,typeof m=="function"&&m(),clearTimeout(R)},l=()=>{a(),d(new c("CANCELLED","Transaction cancelled"))};e.addEventListener("abort",l);let m=this.messaging.subscribe(n,i,f=>{o||(a(),e.removeEventListener("abort",l),s(this.handleSuccess(f)))}),R=setTimeout(async()=>{if(!(o||e.aborted))try{let f=await this.pollOrderStatus(t,r,this.config.storeId,e);s(this.handleSuccess(f))}catch(f){d(new c("TIMEOUT","Payment timed out and polling failed",f))}finally{e.removeEventListener("abort",l),a()}},1e4)})}async pollOrderStatus(t,r,e,n){let o=Date.now()+12e4;for(;Date.now()<o;){if(n.aborted)throw new Error("Aborted");try{let{data:a}=await this.api.getPaymentStatus({businessId:Number(e),orderId:r,provider:this.paymentProvider,referenceId:t});if(n.aborted)throw new Error("Aborted");if(a.status!==h.SimplePaymentStatus.Pending)return a}catch(a){if(a instanceof Error&&a.message==="Aborted")throw a}await new Promise(a=>{let l=()=>{clearTimeout(m),a(void 0)};n.addEventListener("abort",l,{once:!0});let m=setTimeout(()=>{n.removeEventListener("abort",l),a(void 0)},2e3)})}throw new Error("Payment verification timed out.")}async cancelTransaction(t){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(t,r){try{this.abortController=new AbortController;let e={amount:t.amountCents,businessId:Number(this.config.storeId),currency:t.currency,displayId:this.config.kioskId,referenceId:t.orderRef,options:{allowPinBypass:!0,transactionType:h.TransactionType.ReturnOfGoods}},{data:n}=await this.api.initiateNetsTerminalTransaction(e),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,t.orderRef,this.abortController.signal);return this.currentRequestId=null,s}catch(e){throw this.currentRequestId=null,e instanceof c||e instanceof c?e:new c("NETWORK_ERROR","Failed to refund Nets transaction",e)}}async verifyFinalStatus(t,r){try{let{data:e}=await this.api.getPaymentStatus({businessId:Number(this.config.storeId),orderId:t.orderRef,provider:this.paymentProvider,referenceId:r});return this.handleSuccess(e)}catch(e){throw new c("NETWORK_ERROR","Failed to verify final Nets status",e)}}handleSuccess(t){let r=t.status===h.SimplePaymentStatus.Success,e={success:r,status:r?"SUCCESS":"FAILED",orderId:t.orderId,transaction:t.transaction};return t.transactionId&&(e.transactionId=t.transactionId),t.error?.code&&(e.errorCode=t.error.code),t.error?.message&&(e.errorMessage=t.error.message),e}abort(){this.abortController?.abort()}};var I=require("@munchi_oy/core");var T=class{constructor(t,r,e){this.messaging=r;this.config=e;this.api=new I.PaymentApi(void 0,"",t)}api;abortController=null;currentSessionId=null;paymentProvider=I.PaymentProviderEnum.Viva;async processPayment(t,r){this.abortController=new AbortController,r("CONNECTING");let e={amount:t.amountCents,referenceId:t.orderRef,businessId:parseInt(this.config.storeId),currency:t.currency,displayId:t.displayId,showReceipt:!0,showTransactionResult:!0};try{let{data:n}=await this.api.initiateTerminalTransaction(e);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,t.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(t,r,e){let i=`viva.${this.config.channel.toLowerCase()}.requests.${t}`,s="payment:status-changed";return new Promise((d,o)=>{let a=!1,l=()=>{a=!0,typeof R=="function"&&R(),clearTimeout(f)},m=()=>{l(),o(new Error("Aborted"))};e.addEventListener("abort",m);let R=this.messaging.subscribe(i,s,E=>{a||E.status!==I.SimplePaymentStatus.Pending&&(l(),e.removeEventListener("abort",m),d(this.handleSuccess(E)))}),f=setTimeout(async()=>{if(!(a||e.aborted))try{let E=await this.pollOrderStatus(t,r,this.config.storeId,e);d(this.handleSuccess(E))}catch(E){o(new c("TIMEOUT","Payment timed out and polling failed",E))}finally{e.removeEventListener("abort",m),l()}},1e4)})}async pollOrderStatus(t,r,e,n){let o=Date.now()+12e4;for(;Date.now()<o;){if(n.aborted)throw new Error("Aborted");try{let{data:a}=await this.api.getPaymentStatus({businessId:Number(e),orderId:r,provider:this.paymentProvider,referenceId:t});if(n.aborted)throw new Error("Aborted");if(a.status!==I.SimplePaymentStatus.Pending)return a}catch(a){if(a instanceof Error&&a.message==="Aborted")throw a}await new Promise(a=>{let l=()=>{clearTimeout(m),a(void 0)};n.addEventListener("abort",l,{once:!0});let m=setTimeout(()=>{n.removeEventListener("abort",l),a(void 0)},2e3)})}throw new Error("Payment verification timed out.")}handleSuccess(t){let r=t.status===I.SimplePaymentStatus.Success,e={success:r,status:r?"SUCCESS":"FAILED",orderId:t.orderId,errorCode:t.error?.code||(r?"":I.PaymentFailureCode.SystemUnknown),errorMessage:t.error?.message||(r?"":"Transaction failed without error details")};return t.transactionId&&(e.transactionId=t.transactionId),t.error?.referenceError&&(e.errorReference=t.error.referenceError),t.transaction&&(e.transaction=t.transaction),e}async cancelTransaction(t){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(t,r){try{let{data:e}=await this.api.getPaymentStatus({businessId:Number(this.config.storeId),orderId:t.orderRef,provider:this.paymentProvider,referenceId:r}),n=e.status===I.SimplePaymentStatus.Success,i=e.status===I.SimplePaymentStatus.Pending,s={success:n,status:n?"SUCCESS":i?"PENDING":"FAILED",orderId:e.orderId,errorCode:e.error?.code||(n||i?"":I.PaymentFailureCode.SystemUnknown),errorMessage:e.error?.message||(n||i?"":"Transaction failed without error details")};return e.transactionId&&(s.transactionId=e.transactionId),e.error?.referenceError&&(s.errorReference=e.error.referenceError),e.transaction&&(s.transaction=e.transaction),s}catch(e){throw new c("NETWORK_ERROR","Failed to verify final transaction status",e)}}async refundTransaction(t,r){try{let e={amount:t.amountCents,businessId:Number(this.config.storeId),displayId:this.config.kioskId,currency:t.currency,orderReferenceId:t.orderRef,referenceId:t.originalTransactionId},{data:n}=await this.api.refundSingleVivaTransaction(e),i=n.success;return{success:i,status:i?"SUCCESS":"FAILED",orderId:t.orderRef,transactionId:n.sessionId}}catch(e){throw new c("NETWORK_ERROR","Failed to refund Viva transaction",e)}}abort(){this.abortController?.abort()}};var p=require("@munchi_oy/core"),A=require("axios");var C=class{constructor(t,r,e){this.messaging=r;this.config=e;this.paymentApi=new p.PaymentApi(void 0,"",t),this.worldlineApi=new p.WorldlineApi(void 0,"",t)}paymentApi;worldlineApi;abortController=null;currentOperationId=null;paymentProvider=p.PaymentProviderEnum.Worldline;async processPayment(t,r){this.abortController=new AbortController,r("CONNECTING");let e={amount:t.amountCents,businessId:Number(this.config.storeId),currency:t.currency,displayId:t.displayId,referenceId:t.orderRef,showReceipt:!0,showTransactionResult:!0,...t.options&&"tipAmount"in t.options&&typeof t.options.tipAmount=="number"?{tipAmount:t.options.tipAmount}:{}};try{let n=await this.worldlineApi.createPayment(e),i=this.extractOperationId(n.data);if(this.currentOperationId=i,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:i});let s=await this.waitForPaymentCompletion(i,t.orderRef,p.PaymentEventType.StatusChanged,this.abortController.signal);return this.currentOperationId=null,s}catch(n){throw this.currentOperationId=null,n instanceof c?n:this.mapWorldlineRequestError(n,"Failed to create Worldline payment")}}async cancelTransaction(t){if(!this.currentOperationId)return!1;let r={businessId:Number(this.config.storeId),targetOperationId:this.currentOperationId};try{return await this.worldlineApi.cancelPayment(r),!0}catch(e){throw this.mapWorldlineRequestError(e,"Failed to cancel Worldline transaction")}}async refundTransaction(t,r){this.abortController=new AbortController,r("CONNECTING");let e={amount:t.amountCents,businessId:Number(this.config.storeId),currency:t.currency,displayId:t.displayId,orderReferenceId:t.orderRef,referenceId:t.originalTransactionId};try{let n=await this.worldlineApi.createRefund(e),i=this.extractOperationId(n.data);if(this.currentOperationId=i,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:i});let s=await this.waitForPaymentCompletion(i,t.orderRef,p.PaymentEventType.RefundStatusChanged,this.abortController.signal);return this.currentOperationId=null,s}catch(n){throw this.currentOperationId=null,n instanceof c?n:this.mapWorldlineRequestError(n,"Failed to refund Worldline transaction")}}async verifyFinalStatus(t,r){try{let{data:e}=await this.paymentApi.getPaymentStatus({businessId:Number(this.config.storeId),orderId:t.orderRef,provider:this.paymentProvider,referenceId:r});return this.handlePaymentStatus(e)}catch(e){throw this.mapWorldlineRequestError(e,"Failed to verify final Worldline status")}}abort(){this.abortController?.abort()}async waitForPaymentCompletion(t,r,e,n){let i=`worldline.requests.${t}`;return new Promise((s,d)=>{let o=!1,a=()=>{o=!0,typeof m=="function"&&m(),clearTimeout(R)},l=()=>{a(),d(new c("CANCELLED","Transaction cancelled"))};n.addEventListener("abort",l);let m=this.messaging.subscribe(i,e,f=>{o||f.status===p.SimplePaymentStatus.Pending||(a(),n.removeEventListener("abort",l),s(this.handlePaymentStatus(f)))}),R=setTimeout(async()=>{if(!(o||n.aborted))try{let f=await this.pollOrderStatus(t,r,this.config.storeId,n);s(this.handlePaymentStatus(f))}catch(f){d(new c("TIMEOUT","Payment timed out and polling failed",f))}finally{n.removeEventListener("abort",l),a()}},1e4)})}async pollOrderStatus(t,r,e,n){let d=Date.now()+12e4;for(;Date.now()<d;){if(n.aborted)throw new Error("Aborted");try{let{data:o}=await this.paymentApi.getPaymentStatus({businessId:Number(e),orderId:r,provider:this.paymentProvider,referenceId:t});if(n.aborted)throw new Error("Aborted");if(o.status!==p.SimplePaymentStatus.Pending)return o}catch(o){if(o instanceof Error&&o.message==="Aborted")throw o}await new Promise(o=>{let a=()=>{clearTimeout(l),o(void 0)};n.addEventListener("abort",a,{once:!0});let l=setTimeout(()=>{n.removeEventListener("abort",a),o(void 0)},2e3)})}throw new Error("Payment verification timed out.")}handlePaymentStatus(t){let r=t.status===p.SimplePaymentStatus.Success,e=t.status===p.SimplePaymentStatus.Pending,n={success:r,status:r?"SUCCESS":e?"PENDING":"FAILED",orderId:t.orderId,errorCode:t.error?.code||(r||e?"":p.PaymentFailureCode.SystemUnknown),errorMessage:t.error?.message||(r||e?"":"Transaction failed without error details")};return t.transactionId&&(n.transactionId=t.transactionId),t.error?.referenceError&&(n.errorReference=t.error.referenceError),t.transaction&&(n.transaction=t.transaction),n}extractOperationId(t){let r=typeof t=="object"&&t!==null&&"operationId"in t&&typeof t.operationId=="string"?t.operationId:null;if(!r)throw new Error("operationId is missing from response.");return r}mapWorldlineRequestError(t,r){if((0,A.isAxiosError)(t)){if(t.response?.status===400||t.response?.status===409)return new c("TERMINAL_BUSY",r,t);if(t.response?.status===404)return new c("TERMINAL_OFFLINE",r,t)}return new c("NETWORK_ERROR",r,t)}};var b=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(t,r,e,n={},i){this.axios=t,this.messaging=r,this.logger=n.logger,this.timeoutMs=n.timeoutMs||3e4,this.autoResetOptions=n.autoResetOnPaymentComplete,this.strategy=i??this.resolveStrategy(e)}get version(){return v}get currentState(){return this._currentState}generateErrorResult(t,r,e){return{success:!1,status:"ERROR",errorCode:this.normalizeErrorCode(r),errorMessage:e,orderId:t}}normalizeErrorCode(t){return t?t.includes(".")?t:{CANCELLED:y.PaymentFailureCode.PaymentCancelledByUser,DECLINED:y.PaymentFailureCode.PaymentDeclined,TERMINAL_BUSY:y.PaymentFailureCode.TerminalBusy,TERMINAL_OFFLINE:y.PaymentFailureCode.TerminalOffline,TIMEOUT:y.PaymentFailureCode.TerminalTimeout,NETWORK_ERROR:y.PaymentFailureCode.SystemProviderError,STRATEGY_ERROR:y.PaymentFailureCode.SystemProviderError,MISSING_CONFIG:y.PaymentFailureCode.SystemUnknown,INVALID_AMOUNT:y.PaymentFailureCode.SystemUnknown,UNKNOWN:y.PaymentFailureCode.SystemUnknown}[t]??y.PaymentFailureCode.SystemUnknown:y.PaymentFailureCode.SystemUnknown}subscribe=t=>(this._listeners.push(t),t(this._currentState),()=>{this._listeners=this._listeners.filter(r=>r!==t)});transitionTo(t){if(this._currentState===t)return;if(t==="IDLE"){this.cancelAutoReset(),this._currentState=t,this._listeners.forEach(e=>e(t));return}if(u.TERMINAL_STATES.includes(this._currentState)){let e=`Invalid State Transition: Attempted to move from terminal state ${this._currentState} to ${t}`;throw this.logger?.error(e),this._currentState!=="INTERNAL_ERROR"&&(this._currentState="INTERNAL_ERROR",this._listeners.forEach(n=>n(this._currentState))),new c("UNKNOWN",e)}this._currentState=t,u.TERMINAL_STATES.includes(t)&&this.scheduleAutoReset(t),this._listeners.forEach(e=>e(t))}_resetScheduledAt;get nextAutoResetAt(){return this._resetScheduledAt}cancelAutoReset(){this._autoResetTimer&&(clearTimeout(this._autoResetTimer),this._autoResetTimer=void 0),this._resetScheduledAt=void 0}scheduleAutoReset(t){if(!this.autoResetOptions)return;let e=t==="SUCCESS"?this.autoResetOptions.successDelayMs??5e3:this.autoResetOptions.failureDelayMs??5e3;this.logger?.info(`Scheduling auto-reset to IDLE in ${e}ms`),this._resetScheduledAt=Date.now()+e,this._autoResetTimer=setTimeout(()=>{this.logger?.info("Auto-reset triggered"),this.reset()},e)}resolveStrategy(t){switch(t.provider){case y.PaymentProvider.Nets:return new P(this.axios,this.messaging,t);case y.PaymentProvider.Worldline:return new C(this.axios,this.messaging,t);default:return new T(this.axios,this.messaging,t)}}initiateTransaction=async(t,r)=>{let e=r??{},n=t.orderRef;if(!u.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(t.orderRef,"UNKNOWN","A transaction is already in progress");let s=Date.now();if(this._cancellationIntent=!1,this._currentSessionId=void 0,this.transitionTo("IDLE"),t.amountCents<=0)return this.generateErrorResult(t.orderRef,"INVALID_AMOUNT","Amount must be greater than 0");try{let d=(m,R)=>{R?.sessionId&&(this._currentSessionId=R.sessionId),m!=="FAILED"&&(this.transitionTo(m),this.fireStateCallback(m,e,n))},o=this.strategy.processPayment(t,d),a=new Promise((m,R)=>{setTimeout(()=>{R(new c("TIMEOUT","Transaction timed out"))},this.timeoutMs)}),l=await Promise.race([o,a]);if(l.success)this.transitionTo("SUCCESS"),this.safeFireCallback(()=>e.onSuccess?.(l));else{if(this._cancellationIntent)return await this.handleTransactionError(t,new Error("Aborted after resolution"),e);this.transitionTo("FAILED"),this.safeFireCallback(()=>e.onError?.(l))}return this.logger?.info("Transaction completed successfully",{orderId:t.orderRef,durationMs:Date.now()-s}),l}catch(d){return this.logger?.warn("Transaction interrupted. Handling final status...",{error:d}),await this.handleTransactionError(t,d,e)}};async handleTransactionError(t,r,e={}){let n=r instanceof c&&r.code==="TIMEOUT";if(!this._cancellationIntent&&!n&&(this.transitionTo("VERIFYING"),this.safeFireCallback(()=>e.onVerifying?.({orderRef:t.orderRef,refPaymentId:this._currentSessionId}))),this._cancellationIntent){try{if(this._currentSessionId){let s=await this.verifyWithRetry(t,this._currentSessionId);if(s.success)return this.transitionTo("SUCCESS"),this.safeFireCallback(()=>e.onSuccess?.(s)),s}}catch(s){this.logger?.warn("Final status verification failed during cancellation",{err:s})}return this.transitionTo("FAILED"),this.safeFireCallback(()=>e.onCancelled?.({orderRef:t.orderRef,refPaymentId:this._currentSessionId})),{success:!1,status:"CANCELLED",errorCode:this.normalizeErrorCode("CANCELLED"),orderId:t.orderRef,...this._currentSessionId?{transactionId:this._currentSessionId}:{}}}let i;if(this.strategy.abort(),this._currentSessionId)try{let s=await this.verifyWithRetry(t,this._currentSessionId);if(s.success)return this.transitionTo("SUCCESS"),this.safeFireCallback(()=>e.onSuccess?.(s)),s;i=s}catch(s){this.logger?.warn("Failed to get detailed error from verifyFinalStatus",{verifyErr:s}),i=this.buildErrorResultFromException(t.orderRef,s)}else i=this.buildErrorResultFromException(t.orderRef,r);return this.transitionTo("FAILED"),this.safeFireCallback(()=>e.onError?.(i)),i}static VERIFY_TIMEOUT_MS=1e4;static VERIFY_MAX_RETRIES=3;static VERIFY_RETRY_DELAY_MS=1500;async verifyWithRetry(t,r){let e,n=!0;for(let d=1;d<=u.VERIFY_MAX_RETRIES;d++)try{let o=await Promise.race([this.strategy.verifyFinalStatus(t,r),new Promise((a,l)=>setTimeout(()=>l(new Error("Verify timed out")),u.VERIFY_TIMEOUT_MS))]);if(o.status==="PENDING"){e=new Error("Verify returned pending status"),this.logger?.warn(`verifyFinalStatus attempt ${d}/${u.VERIFY_MAX_RETRIES} returned pending status`),d<u.VERIFY_MAX_RETRIES&&await new Promise(a=>setTimeout(a,u.VERIFY_RETRY_DELAY_MS));continue}return o}catch(o){e=o,o instanceof Error&&o.message==="Verify timed out"||(n=!1),this.logger?.warn(`verifyFinalStatus attempt ${d}/${u.VERIFY_MAX_RETRIES} failed`,{err:o}),d<u.VERIFY_MAX_RETRIES&&await new Promise(l=>setTimeout(l,u.VERIFY_RETRY_DELAY_MS))}let i=e instanceof Error?e.message:"Verify retries exhausted",s=n?y.PaymentFailureCode.PaymentTimeout:y.PaymentFailureCode.PaymentUnknown;throw new c(s,i)}buildErrorResultFromException(t,r){return r instanceof c?this.generateErrorResult(t,r.code,r.message):this.generateErrorResult(t,"UNKNOWN",r instanceof Error?r.message:"Unknown fatal error")}fireStateCallback(t,r,e){let n={orderRef:e,refPaymentId:this._currentSessionId};switch(t){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(t){try{t()}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;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(t){return this.logger?.error("Cancellation command failed",t),!1}};reset=()=>{u.TERMINAL_STATES.includes(this._currentState)&&(this._currentSessionId=void 0,this._cancellationIntent=!1,this.transitionTo("IDLE"))};refund=async(t,r)=>{let e=r??{};if(this.logger?.info("Initiating refund",{orderRef:t.orderRef}),this._currentSessionId=void 0,!u.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(t.orderRef,"UNKNOWN","A transaction is already in progress");this.transitionTo("IDLE");try{let i=(d,o)=>{o?.sessionId&&(this._currentSessionId=o.sessionId),d!=="FAILED"&&(this.transitionTo(d),this.fireStateCallback(d,e,t.orderRef))},s=await this.strategy.refundTransaction(t,i);return s.success?(this.transitionTo("SUCCESS"),this.safeFireCallback(()=>e.onSuccess?.(s))):(this.transitionTo("FAILED"),this.safeFireCallback(()=>e.onError?.(s))),this.logger?.info("Refund completed",{success:s.success,orderRef:t.orderRef}),s}catch(i){this.logger?.error("Refund failed",i),this.transitionTo("FAILED");let s=this.generateErrorResult(t.orderRef,"UNKNOWN",i instanceof Error?i.message:"Refund failed");return this.safeFireCallback(()=>e.onError?.(s)),s}}};var O=(n=>(n.CONNECTING="CONNECTING",n.CONNECTED="CONNECTED",n.OFFLINE="OFFLINE",n.DISCONNECTED="DISCONNECTED",n))(O||{});0&&(module.exports={AppReaderStatus,MunchiPaymentSDK,PaymentInteractionState,SdkPaymentStatus});
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{PaymentFailureCode as f,PaymentProvider as F}from"@munchi_oy/core";var P="1.3.6";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(y)},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)))}),y=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 R}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 y=="function"&&y(),clearTimeout(I)},m=()=>{d(),a(new Error("Aborted"))};t.addEventListener("abort",m);let y=this.messaging.subscribe(i,s,h=>{o||h.status!==R.Pending&&(d(),t.removeEventListener("abort",m),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",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!==R.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===R.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===R.Success,i=t.status===R.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:f.PaymentCancelledByUser,DECLINED:f.PaymentDeclined,TERMINAL_BUSY:f.TerminalBusy,TERMINAL_OFFLINE:f.TerminalOffline,TIMEOUT:f.TerminalTimeout,NETWORK_ERROR:f.SystemProviderError,STRATEGY_ERROR:f.SystemProviderError,MISSING_CONFIG:f.SystemUnknown,INVALID_AMOUNT:f.SystemUnknown,UNKNOWN:f.SystemUnknown}[e]??f.SystemUnknown:f.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,y)=>{y?.sessionId&&(this._currentSessionId=y.sessionId),m!=="FAILED"&&(this.transitionTo(m),this.fireStateCallback(m,t,n))},a=this.strategy.processPayment(e,u),o=new Promise((m,y)=>{setTimeout(()=>{y(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?f.PaymentTimeout:f.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;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=()=>{l.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,!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};
1
+ import{PaymentFailureCode as p,PaymentProvider as _}from"@munchi_oy/core";var w="1.4.1";var c=class l extends Error{code;rawError;constructor(t,r,e){super(r),this.name="PaymentSDKError",this.code=t,this.rawError=e,Object.setPrototypeOf(this,l.prototype)}};import{PaymentApi as L,PaymentEventType as F,PaymentProviderEnum as M,SimplePaymentStatus as N,TransactionType as v}from"@munchi_oy/core";var h=(s=>(s.PENDING="PENDING",s.SUCCESS="SUCCESS",s.APPROVED="APPROVED",s.FAILED="FAILED",s.CANCELLED="CANCELLED",s.ERROR="ERROR",s))(h||{}),R=(o=>(o.IDLE="IDLE",o.CONNECTING="CONNECTING",o.REQUIRES_INPUT="REQUIRES_INPUT",o.PROCESSING="PROCESSING",o.SUCCESS="SUCCESS",o.FAILED="FAILED",o.INTERNAL_ERROR="INTERNAL_ERROR",o.VERIFYING="VERIFYING",o))(R||{});var S=class{constructor(t,r,e){this.messaging=r;this.config=e;this.api=new L(void 0,"",t)}api;abortController=null;currentRequestId=null;paymentProvider=M.Nets;async processPayment(t,r){this.abortController=new AbortController,r("CONNECTING");let e={amount:t.amountCents,businessId:Number(this.config.storeId),referenceId:t.orderRef,currency:t.currency,displayId:t.displayId,options:{allowPinBypass:!0,transactionType:v.Purchase}};try{let{data:n}=await this.api.initiateNetsTerminalTransaction(e),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,t.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(t,r,e){let n=`nets.requests.${t}`,i=F.StatusChanged;return new Promise((s,u)=>{let o=!1,a=()=>{o=!0,typeof m=="function"&&m(),clearTimeout(f)},d=()=>{a(),u(new c("CANCELLED","Transaction cancelled"))};e.addEventListener("abort",d);let m=this.messaging.subscribe(n,i,y=>{o||(a(),e.removeEventListener("abort",d),s(this.handleSuccess(y)))}),f=setTimeout(async()=>{if(!(o||e.aborted))try{let y=await this.pollOrderStatus(t,r,this.config.storeId,e);s(this.handleSuccess(y))}catch(y){u(new c("TIMEOUT","Payment timed out and polling failed",y))}finally{e.removeEventListener("abort",d),a()}},1e4)})}async pollOrderStatus(t,r,e,n){let o=Date.now()+12e4;for(;Date.now()<o;){if(n.aborted)throw new Error("Aborted");try{let{data:a}=await this.api.getPaymentStatus({businessId:Number(e),orderId:r,provider:this.paymentProvider,referenceId:t});if(n.aborted)throw new Error("Aborted");if(a.status!==N.Pending)return a}catch(a){if(a instanceof Error&&a.message==="Aborted")throw a}await new Promise(a=>{let d=()=>{clearTimeout(m),a(void 0)};n.addEventListener("abort",d,{once:!0});let m=setTimeout(()=>{n.removeEventListener("abort",d),a(void 0)},2e3)})}throw new Error("Payment verification timed out.")}async cancelTransaction(t){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(t,r){try{this.abortController=new AbortController;let e={amount:t.amountCents,businessId:Number(this.config.storeId),currency:t.currency,displayId:this.config.kioskId,referenceId:t.orderRef,options:{allowPinBypass:!0,transactionType:v.ReturnOfGoods}},{data:n}=await this.api.initiateNetsTerminalTransaction(e),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,t.orderRef,this.abortController.signal);return this.currentRequestId=null,s}catch(e){throw this.currentRequestId=null,e instanceof c||e instanceof c?e:new c("NETWORK_ERROR","Failed to refund Nets transaction",e)}}async verifyFinalStatus(t,r){try{let{data:e}=await this.api.getPaymentStatus({businessId:Number(this.config.storeId),orderId:t.orderRef,provider:this.paymentProvider,referenceId:r});return this.handleSuccess(e)}catch(e){throw new c("NETWORK_ERROR","Failed to verify final Nets status",e)}}handleSuccess(t){let r=t.status===N.Success,e={success:r,status:r?"SUCCESS":"FAILED",orderId:t.orderId,transaction:t.transaction};return t.transactionId&&(e.transactionId=t.transactionId),t.error?.code&&(e.errorCode=t.error.code),t.error?.message&&(e.errorMessage=t.error.message),e}abort(){this.abortController?.abort()}};import{PaymentApi as x,PaymentFailureCode as A,PaymentProviderEnum as U,SimplePaymentStatus as E}from"@munchi_oy/core";var g=class{constructor(t,r,e){this.messaging=r;this.config=e;this.api=new x(void 0,"",t)}api;abortController=null;currentSessionId=null;paymentProvider=U.Viva;async processPayment(t,r){this.abortController=new AbortController,r("CONNECTING");let e={amount:t.amountCents,referenceId:t.orderRef,businessId:parseInt(this.config.storeId),currency:t.currency,displayId:t.displayId,showReceipt:!0,showTransactionResult:!0};try{let{data:n}=await this.api.initiateTerminalTransaction(e);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,t.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(t,r,e){let i=`viva.${this.config.channel.toLowerCase()}.requests.${t}`,s="payment:status-changed";return new Promise((u,o)=>{let a=!1,d=()=>{a=!0,typeof f=="function"&&f(),clearTimeout(y)},m=()=>{d(),o(new Error("Aborted"))};e.addEventListener("abort",m);let f=this.messaging.subscribe(i,s,I=>{a||I.status!==E.Pending&&(d(),e.removeEventListener("abort",m),u(this.handleSuccess(I)))}),y=setTimeout(async()=>{if(!(a||e.aborted))try{let I=await this.pollOrderStatus(t,r,this.config.storeId,e);u(this.handleSuccess(I))}catch(I){o(new c("TIMEOUT","Payment timed out and polling failed",I))}finally{e.removeEventListener("abort",m),d()}},1e4)})}async pollOrderStatus(t,r,e,n){let o=Date.now()+12e4;for(;Date.now()<o;){if(n.aborted)throw new Error("Aborted");try{let{data:a}=await this.api.getPaymentStatus({businessId:Number(e),orderId:r,provider:this.paymentProvider,referenceId:t});if(n.aborted)throw new Error("Aborted");if(a.status!==E.Pending)return a}catch(a){if(a instanceof Error&&a.message==="Aborted")throw a}await new Promise(a=>{let d=()=>{clearTimeout(m),a(void 0)};n.addEventListener("abort",d,{once:!0});let m=setTimeout(()=>{n.removeEventListener("abort",d),a(void 0)},2e3)})}throw new Error("Payment verification timed out.")}handleSuccess(t){let r=t.status===E.Success,e={success:r,status:r?"SUCCESS":"FAILED",orderId:t.orderId,errorCode:t.error?.code||(r?"":A.SystemUnknown),errorMessage:t.error?.message||(r?"":"Transaction failed without error details")};return t.transactionId&&(e.transactionId=t.transactionId),t.error?.referenceError&&(e.errorReference=t.error.referenceError),t.transaction&&(e.transaction=t.transaction),e}async cancelTransaction(t){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(t,r){try{let{data:e}=await this.api.getPaymentStatus({businessId:Number(this.config.storeId),orderId:t.orderRef,provider:this.paymentProvider,referenceId:r}),n=e.status===E.Success,i=e.status===E.Pending,s={success:n,status:n?"SUCCESS":i?"PENDING":"FAILED",orderId:e.orderId,errorCode:e.error?.code||(n||i?"":A.SystemUnknown),errorMessage:e.error?.message||(n||i?"":"Transaction failed without error details")};return e.transactionId&&(s.transactionId=e.transactionId),e.error?.referenceError&&(s.errorReference=e.error.referenceError),e.transaction&&(s.transaction=e.transaction),s}catch(e){throw new c("NETWORK_ERROR","Failed to verify final transaction status",e)}}async refundTransaction(t,r){try{let e={amount:t.amountCents,businessId:Number(this.config.storeId),displayId:this.config.kioskId,currency:t.currency,orderReferenceId:t.orderRef,referenceId:t.originalTransactionId},{data:n}=await this.api.refundSingleVivaTransaction(e),i=n.success;return{success:i,status:i?"SUCCESS":"FAILED",orderId:t.orderRef,transactionId:n.sessionId}}catch(e){throw new c("NETWORK_ERROR","Failed to refund Viva transaction",e)}}abort(){this.abortController?.abort()}};import{PaymentApi as k,PaymentEventType as O,PaymentFailureCode as W,PaymentProviderEnum as V,SimplePaymentStatus as P,WorldlineApi as G}from"@munchi_oy/core";import{isAxiosError as K}from"axios";var T=class{constructor(t,r,e){this.messaging=r;this.config=e;this.paymentApi=new k(void 0,"",t),this.worldlineApi=new G(void 0,"",t)}paymentApi;worldlineApi;abortController=null;currentOperationId=null;paymentProvider=V.Worldline;async processPayment(t,r){this.abortController=new AbortController,r("CONNECTING");let e={amount:t.amountCents,businessId:Number(this.config.storeId),currency:t.currency,displayId:t.displayId,referenceId:t.orderRef,showReceipt:!0,showTransactionResult:!0,...t.options&&"tipAmount"in t.options&&typeof t.options.tipAmount=="number"?{tipAmount:t.options.tipAmount}:{}};try{let n=await this.worldlineApi.createPayment(e),i=this.extractOperationId(n.data);if(this.currentOperationId=i,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:i});let s=await this.waitForPaymentCompletion(i,t.orderRef,O.StatusChanged,this.abortController.signal);return this.currentOperationId=null,s}catch(n){throw this.currentOperationId=null,n instanceof c?n:this.mapWorldlineRequestError(n,"Failed to create Worldline payment")}}async cancelTransaction(t){if(!this.currentOperationId)return!1;let r={businessId:Number(this.config.storeId),targetOperationId:this.currentOperationId};try{return await this.worldlineApi.cancelPayment(r),!0}catch(e){throw this.mapWorldlineRequestError(e,"Failed to cancel Worldline transaction")}}async refundTransaction(t,r){this.abortController=new AbortController,r("CONNECTING");let e={amount:t.amountCents,businessId:Number(this.config.storeId),currency:t.currency,displayId:t.displayId,orderReferenceId:t.orderRef,referenceId:t.originalTransactionId};try{let n=await this.worldlineApi.createRefund(e),i=this.extractOperationId(n.data);if(this.currentOperationId=i,this.abortController.signal.aborted)throw new Error("Aborted");r("REQUIRES_INPUT",{sessionId:i});let s=await this.waitForPaymentCompletion(i,t.orderRef,O.RefundStatusChanged,this.abortController.signal);return this.currentOperationId=null,s}catch(n){throw this.currentOperationId=null,n instanceof c?n:this.mapWorldlineRequestError(n,"Failed to refund Worldline transaction")}}async verifyFinalStatus(t,r){try{let{data:e}=await this.paymentApi.getPaymentStatus({businessId:Number(this.config.storeId),orderId:t.orderRef,provider:this.paymentProvider,referenceId:r});return this.handlePaymentStatus(e)}catch(e){throw this.mapWorldlineRequestError(e,"Failed to verify final Worldline status")}}abort(){this.abortController?.abort()}async waitForPaymentCompletion(t,r,e,n){let i=`worldline.requests.${t}`;return new Promise((s,u)=>{let o=!1,a=()=>{o=!0,typeof m=="function"&&m(),clearTimeout(f)},d=()=>{a(),u(new c("CANCELLED","Transaction cancelled"))};n.addEventListener("abort",d);let m=this.messaging.subscribe(i,e,y=>{o||y.status===P.Pending||(a(),n.removeEventListener("abort",d),s(this.handlePaymentStatus(y)))}),f=setTimeout(async()=>{if(!(o||n.aborted))try{let y=await this.pollOrderStatus(t,r,this.config.storeId,n);s(this.handlePaymentStatus(y))}catch(y){u(new c("TIMEOUT","Payment timed out and polling failed",y))}finally{n.removeEventListener("abort",d),a()}},1e4)})}async pollOrderStatus(t,r,e,n){let u=Date.now()+12e4;for(;Date.now()<u;){if(n.aborted)throw new Error("Aborted");try{let{data:o}=await this.paymentApi.getPaymentStatus({businessId:Number(e),orderId:r,provider:this.paymentProvider,referenceId:t});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 a=()=>{clearTimeout(d),o(void 0)};n.addEventListener("abort",a,{once:!0});let d=setTimeout(()=>{n.removeEventListener("abort",a),o(void 0)},2e3)})}throw new Error("Payment verification timed out.")}handlePaymentStatus(t){let r=t.status===P.Success,e=t.status===P.Pending,n={success:r,status:r?"SUCCESS":e?"PENDING":"FAILED",orderId:t.orderId,errorCode:t.error?.code||(r||e?"":W.SystemUnknown),errorMessage:t.error?.message||(r||e?"":"Transaction failed without error details")};return t.transactionId&&(n.transactionId=t.transactionId),t.error?.referenceError&&(n.errorReference=t.error.referenceError),t.transaction&&(n.transaction=t.transaction),n}extractOperationId(t){let r=typeof t=="object"&&t!==null&&"operationId"in t&&typeof t.operationId=="string"?t.operationId:null;if(!r)throw new Error("operationId is missing from response.");return r}mapWorldlineRequestError(t,r){if(K(t)){if(t.response?.status===400||t.response?.status===409)return new c("TERMINAL_BUSY",r,t);if(t.response?.status===404)return new c("TERMINAL_OFFLINE",r,t)}return new c("NETWORK_ERROR",r,t)}};var b=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(t,r,e,n={},i){this.axios=t,this.messaging=r,this.logger=n.logger,this.timeoutMs=n.timeoutMs||3e4,this.autoResetOptions=n.autoResetOnPaymentComplete,this.strategy=i??this.resolveStrategy(e)}get version(){return w}get currentState(){return this._currentState}generateErrorResult(t,r,e){return{success:!1,status:"ERROR",errorCode:this.normalizeErrorCode(r),errorMessage:e,orderId:t}}normalizeErrorCode(t){return t?t.includes(".")?t:{CANCELLED:p.PaymentCancelledByUser,DECLINED:p.PaymentDeclined,TERMINAL_BUSY:p.TerminalBusy,TERMINAL_OFFLINE:p.TerminalOffline,TIMEOUT:p.TerminalTimeout,NETWORK_ERROR:p.SystemProviderError,STRATEGY_ERROR:p.SystemProviderError,MISSING_CONFIG:p.SystemUnknown,INVALID_AMOUNT:p.SystemUnknown,UNKNOWN:p.SystemUnknown}[t]??p.SystemUnknown:p.SystemUnknown}subscribe=t=>(this._listeners.push(t),t(this._currentState),()=>{this._listeners=this._listeners.filter(r=>r!==t)});transitionTo(t){if(this._currentState===t)return;if(t==="IDLE"){this.cancelAutoReset(),this._currentState=t,this._listeners.forEach(e=>e(t));return}if(l.TERMINAL_STATES.includes(this._currentState)){let e=`Invalid State Transition: Attempted to move from terminal state ${this._currentState} to ${t}`;throw this.logger?.error(e),this._currentState!=="INTERNAL_ERROR"&&(this._currentState="INTERNAL_ERROR",this._listeners.forEach(n=>n(this._currentState))),new c("UNKNOWN",e)}this._currentState=t,l.TERMINAL_STATES.includes(t)&&this.scheduleAutoReset(t),this._listeners.forEach(e=>e(t))}_resetScheduledAt;get nextAutoResetAt(){return this._resetScheduledAt}cancelAutoReset(){this._autoResetTimer&&(clearTimeout(this._autoResetTimer),this._autoResetTimer=void 0),this._resetScheduledAt=void 0}scheduleAutoReset(t){if(!this.autoResetOptions)return;let e=t==="SUCCESS"?this.autoResetOptions.successDelayMs??5e3:this.autoResetOptions.failureDelayMs??5e3;this.logger?.info(`Scheduling auto-reset to IDLE in ${e}ms`),this._resetScheduledAt=Date.now()+e,this._autoResetTimer=setTimeout(()=>{this.logger?.info("Auto-reset triggered"),this.reset()},e)}resolveStrategy(t){switch(t.provider){case _.Nets:return new S(this.axios,this.messaging,t);case _.Worldline:return new T(this.axios,this.messaging,t);default:return new g(this.axios,this.messaging,t)}}initiateTransaction=async(t,r)=>{let e=r??{},n=t.orderRef;if(!l.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(t.orderRef,"UNKNOWN","A transaction is already in progress");let s=Date.now();if(this._cancellationIntent=!1,this._currentSessionId=void 0,this.transitionTo("IDLE"),t.amountCents<=0)return this.generateErrorResult(t.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,e,n))},o=this.strategy.processPayment(t,u),a=new Promise((m,f)=>{setTimeout(()=>{f(new c("TIMEOUT","Transaction timed out"))},this.timeoutMs)}),d=await Promise.race([o,a]);if(d.success)this.transitionTo("SUCCESS"),this.safeFireCallback(()=>e.onSuccess?.(d));else{if(this._cancellationIntent)return await this.handleTransactionError(t,new Error("Aborted after resolution"),e);this.transitionTo("FAILED"),this.safeFireCallback(()=>e.onError?.(d))}return this.logger?.info("Transaction completed successfully",{orderId:t.orderRef,durationMs:Date.now()-s}),d}catch(u){return this.logger?.warn("Transaction interrupted. Handling final status...",{error:u}),await this.handleTransactionError(t,u,e)}};async handleTransactionError(t,r,e={}){let n=r instanceof c&&r.code==="TIMEOUT";if(!this._cancellationIntent&&!n&&(this.transitionTo("VERIFYING"),this.safeFireCallback(()=>e.onVerifying?.({orderRef:t.orderRef,refPaymentId:this._currentSessionId}))),this._cancellationIntent){try{if(this._currentSessionId){let s=await this.verifyWithRetry(t,this._currentSessionId);if(s.success)return this.transitionTo("SUCCESS"),this.safeFireCallback(()=>e.onSuccess?.(s)),s}}catch(s){this.logger?.warn("Final status verification failed during cancellation",{err:s})}return this.transitionTo("FAILED"),this.safeFireCallback(()=>e.onCancelled?.({orderRef:t.orderRef,refPaymentId:this._currentSessionId})),{success:!1,status:"CANCELLED",errorCode:this.normalizeErrorCode("CANCELLED"),orderId:t.orderRef,...this._currentSessionId?{transactionId:this._currentSessionId}:{}}}let i;if(this.strategy.abort(),this._currentSessionId)try{let s=await this.verifyWithRetry(t,this._currentSessionId);if(s.success)return this.transitionTo("SUCCESS"),this.safeFireCallback(()=>e.onSuccess?.(s)),s;i=s}catch(s){this.logger?.warn("Failed to get detailed error from verifyFinalStatus",{verifyErr:s}),i=this.buildErrorResultFromException(t.orderRef,s)}else i=this.buildErrorResultFromException(t.orderRef,r);return this.transitionTo("FAILED"),this.safeFireCallback(()=>e.onError?.(i)),i}static VERIFY_TIMEOUT_MS=1e4;static VERIFY_MAX_RETRIES=3;static VERIFY_RETRY_DELAY_MS=1500;async verifyWithRetry(t,r){let e,n=!0;for(let u=1;u<=l.VERIFY_MAX_RETRIES;u++)try{let o=await Promise.race([this.strategy.verifyFinalStatus(t,r),new Promise((a,d)=>setTimeout(()=>d(new Error("Verify timed out")),l.VERIFY_TIMEOUT_MS))]);if(o.status==="PENDING"){e=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(a=>setTimeout(a,l.VERIFY_RETRY_DELAY_MS));continue}return o}catch(o){e=o,o instanceof Error&&o.message==="Verify timed out"||(n=!1),this.logger?.warn(`verifyFinalStatus attempt ${u}/${l.VERIFY_MAX_RETRIES} failed`,{err:o}),u<l.VERIFY_MAX_RETRIES&&await new Promise(d=>setTimeout(d,l.VERIFY_RETRY_DELAY_MS))}let i=e instanceof Error?e.message:"Verify retries exhausted",s=n?p.PaymentTimeout:p.PaymentUnknown;throw new c(s,i)}buildErrorResultFromException(t,r){return r instanceof c?this.generateErrorResult(t,r.code,r.message):this.generateErrorResult(t,"UNKNOWN",r instanceof Error?r.message:"Unknown fatal error")}fireStateCallback(t,r,e){let n={orderRef:e,refPaymentId:this._currentSessionId};switch(t){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(t){try{t()}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;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(t){return this.logger?.error("Cancellation command failed",t),!1}};reset=()=>{l.TERMINAL_STATES.includes(this._currentState)&&(this._currentSessionId=void 0,this._cancellationIntent=!1,this.transitionTo("IDLE"))};refund=async(t,r)=>{let e=r??{};if(this.logger?.info("Initiating refund",{orderRef:t.orderRef}),this._currentSessionId=void 0,!l.RESTING_STATES.includes(this._currentState))return this.generateErrorResult(t.orderRef,"UNKNOWN","A transaction is already in progress");this.transitionTo("IDLE");try{let i=(u,o)=>{o?.sessionId&&(this._currentSessionId=o.sessionId),u!=="FAILED"&&(this.transitionTo(u),this.fireStateCallback(u,e,t.orderRef))},s=await this.strategy.refundTransaction(t,i);return s.success?(this.transitionTo("SUCCESS"),this.safeFireCallback(()=>e.onSuccess?.(s))):(this.transitionTo("FAILED"),this.safeFireCallback(()=>e.onError?.(s))),this.logger?.info("Refund completed",{success:s.success,orderRef:t.orderRef}),s}catch(i){this.logger?.error("Refund failed",i),this.transitionTo("FAILED");let s=this.generateErrorResult(t.orderRef,"UNKNOWN",i instanceof Error?i.message:"Refund failed");return this.safeFireCallback(()=>e.onError?.(s)),s}}};var Y=(n=>(n.CONNECTING="CONNECTING",n.CONNECTED="CONNECTED",n.OFFLINE="OFFLINE",n.DISCONNECTED="DISCONNECTED",n))(Y||{});export{Y as AppReaderStatus,b as MunchiPaymentSDK,R 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;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,CAyCxC;IAEK,KAAK,QAAO,IAAI,CAMrB;IAEK,MAAM,GACX,QAAQ,aAAa,EACrB,UAAU,kBAAkB,KAC3B,OAAO,CAAC,aAAa,CAAC,CAkEvB;CACH"}
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;AAItE,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;IAYhB,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,CAyCxC;IAEK,KAAK,QAAO,IAAI,CAMrB;IAEK,MAAM,GACX,QAAQ,aAAa,EACrB,UAAU,kBAAkB,KAC3B,OAAO,CAAC,aAAa,CAAC,CAkEvB;CACH"}
@@ -0,0 +1,28 @@
1
+ import { type AxiosInstance } from "axios";
2
+ import { type IMessagingAdapter, PaymentInteractionState, type PaymentRequest, type PaymentResult, type PaymentTerminalConfig, type RefundRequest } from "../types/payment";
3
+ import type { IPaymentStrategy } from "./IPaymentStrategy";
4
+ export declare class WorldlineStrategy implements IPaymentStrategy {
5
+ private messaging;
6
+ private config;
7
+ private paymentApi;
8
+ private worldlineApi;
9
+ private abortController;
10
+ private currentOperationId;
11
+ private paymentProvider;
12
+ constructor(axios: AxiosInstance, messaging: IMessagingAdapter, config: PaymentTerminalConfig);
13
+ processPayment(request: PaymentRequest, onStateChange: (state: PaymentInteractionState, detail?: {
14
+ sessionId?: string;
15
+ }) => void): Promise<PaymentResult>;
16
+ cancelTransaction(_onStateChange: (state: PaymentInteractionState) => void): Promise<boolean>;
17
+ refundTransaction(request: RefundRequest, onStateChange: (state: PaymentInteractionState, detail?: {
18
+ sessionId?: string;
19
+ }) => void): Promise<PaymentResult>;
20
+ verifyFinalStatus(request: PaymentRequest, sessionId: string): Promise<PaymentResult>;
21
+ abort(): void;
22
+ private waitForPaymentCompletion;
23
+ private pollOrderStatus;
24
+ private handlePaymentStatus;
25
+ private extractOperationId;
26
+ private mapWorldlineRequestError;
27
+ }
28
+ //# sourceMappingURL=WorldlineStrategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorldlineStrategy.d.ts","sourceRoot":"","sources":["../../../src/strategies/WorldlineStrategy.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,KAAK,aAAa,EAAgB,MAAM,OAAO,CAAC;AAGzD,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;AAM3D,qBAAa,iBAAkB,YAAW,gBAAgB;IAStD,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,MAAM;IAThB,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,kBAAkB,CAAuB;IACjD,OAAO,CAAC,eAAe,CAAiC;gBAGtD,KAAK,EAAE,aAAa,EACZ,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,qBAAqB;IAMjC,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;IAwDnB,iBAAiB,CACrB,cAAc,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,IAAI,GACvD,OAAO,CAAC,OAAO,CAAC;IAqBb,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;IAkDnB,iBAAiB,CACrB,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,aAAa,CAAC;IAkBzB,KAAK,IAAI,IAAI;YAIC,wBAAwB;YA0ExB,eAAe;IAsD7B,OAAO,CAAC,mBAAmB;IAqC3B,OAAO,CAAC,kBAAkB;IAgB1B,OAAO,CAAC,wBAAwB;CAwBjC"}
@@ -27,17 +27,22 @@ export interface NetsOptions {
27
27
  vatAmount?: number;
28
28
  operatorId?: string;
29
29
  }
30
+ export interface WorldlineOptions {
31
+ tipAmount?: number;
32
+ }
30
33
  export interface VivaRefundOptions extends VivaOptions {
31
34
  }
32
35
  export interface NetsRefundOptions extends NetsOptions {
33
36
  allowPinBypass?: boolean;
34
37
  }
38
+ export interface WorldlineRefundOptions extends WorldlineOptions {
39
+ }
35
40
  export interface PaymentRequest {
36
41
  orderRef: string;
37
42
  amountCents: number;
38
43
  currency: CurrencyCode;
39
44
  displayId: string;
40
- options?: VivaOptions | NetsOptions;
45
+ options?: VivaOptions | NetsOptions | WorldlineOptions;
41
46
  }
42
47
  export interface RefundRequest {
43
48
  amountCents: number;
@@ -51,7 +56,7 @@ export interface RefundRequest {
51
56
  * - Nets: preAuthorizationInfo (or reference)
52
57
  */
53
58
  originalTransactionId: string;
54
- options?: VivaRefundOptions | NetsRefundOptions;
59
+ options?: VivaRefundOptions | NetsRefundOptions | WorldlineRefundOptions;
55
60
  }
56
61
  export interface PaymentTerminalConfig {
57
62
  channel: ProviderEnum;
@@ -1 +1 @@
1
- {"version":3,"file":"payment.d.ts","sourceRoot":"","sources":["../../../src/types/payment.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"payment.d.ts","sourceRoot":"","sources":["../../../src/types/payment.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "1.3.6";
1
+ export declare const VERSION = "1.4.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.6",
3
+ "version": "1.4.1",
4
4
  "description": "Munchi Payments SDK - Payment processing utilities",
5
5
  "license": "UNLICENSED",
6
6
  "publishConfig": {
@@ -5,6 +5,7 @@ import { PaymentErrorCode, PaymentSDKError } from "./error";
5
5
  import type { IPaymentStrategy } from "./strategies/IPaymentStrategy";
6
6
  import { NetsStrategy } from "./strategies/NetsStrategy";
7
7
  import { VivaStrategy } from "./strategies/VivaStrategy";
8
+ import { WorldlineStrategy } from "./strategies/WorldlineStrategy";
8
9
  import {
9
10
  type IMessagingAdapter,
10
11
  type IMunchiPaymentSDK,
@@ -184,6 +185,8 @@ export class MunchiPaymentSDK implements IMunchiPaymentSDK {
184
185
  switch (config.provider) {
185
186
  case PaymentProvider.Nets:
186
187
  return new NetsStrategy(this.axios, this.messaging, config);
188
+ case PaymentProvider.Worldline:
189
+ return new WorldlineStrategy(this.axios, this.messaging, config);
187
190
 
188
191
  default:
189
192
  return new VivaStrategy(this.axios, this.messaging, config);
@@ -0,0 +1,419 @@
1
+ import {
2
+ type CancelWorldlinePaymentDto,
3
+ type CreateWorldlineRefundDto,
4
+ type CreateWorldlineTerminalPaymentDto,
5
+ PaymentApi,
6
+ PaymentEventType,
7
+ PaymentFailureCode,
8
+ PaymentProviderEnum,
9
+ type PaymentStatusDto,
10
+ SimplePaymentStatus,
11
+ type TransactionDto,
12
+ WorldlineApi,
13
+ } from "@munchi_oy/core";
14
+ import { type AxiosInstance, isAxiosError } from "axios";
15
+
16
+ import { PaymentErrorCode, PaymentSDKError } from "../error";
17
+ import {
18
+ type IMessagingAdapter,
19
+ PaymentInteractionState,
20
+ type PaymentRequest,
21
+ type PaymentResult,
22
+ type PaymentTerminalConfig,
23
+ type RefundRequest,
24
+ SdkPaymentStatus,
25
+ } from "../types/payment";
26
+ import type { IPaymentStrategy } from "./IPaymentStrategy";
27
+
28
+ type WorldlineQueuedResponse = {
29
+ operationId?: string;
30
+ };
31
+
32
+ export class WorldlineStrategy implements IPaymentStrategy {
33
+ private paymentApi: PaymentApi;
34
+ private worldlineApi: WorldlineApi;
35
+ private abortController: AbortController | null = null;
36
+ private currentOperationId: string | null = null;
37
+ private paymentProvider = PaymentProviderEnum.Worldline;
38
+
39
+ constructor(
40
+ axios: AxiosInstance,
41
+ private messaging: IMessagingAdapter,
42
+ private config: PaymentTerminalConfig,
43
+ ) {
44
+ this.paymentApi = new PaymentApi(undefined, "", axios);
45
+ this.worldlineApi = new WorldlineApi(undefined, "", axios);
46
+ }
47
+
48
+ async processPayment(
49
+ request: PaymentRequest,
50
+ onStateChange: (
51
+ state: PaymentInteractionState,
52
+ detail?: { sessionId?: string },
53
+ ) => void,
54
+ ): Promise<PaymentResult> {
55
+ this.abortController = new AbortController();
56
+ onStateChange(PaymentInteractionState.CONNECTING);
57
+
58
+ const payload: CreateWorldlineTerminalPaymentDto = {
59
+ amount: request.amountCents,
60
+ businessId: Number(this.config.storeId),
61
+ currency: request.currency,
62
+ displayId: request.displayId,
63
+ referenceId: request.orderRef,
64
+ showReceipt: true,
65
+ showTransactionResult: true,
66
+ ...(request.options &&
67
+ "tipAmount" in request.options &&
68
+ typeof request.options.tipAmount === "number"
69
+ ? { tipAmount: request.options.tipAmount }
70
+ : {}),
71
+ };
72
+
73
+ try {
74
+ const response = await this.worldlineApi.createPayment(payload);
75
+ const operationId = this.extractOperationId(response.data);
76
+
77
+ this.currentOperationId = operationId;
78
+
79
+ if (this.abortController.signal.aborted) {
80
+ throw new Error("Aborted");
81
+ }
82
+
83
+ onStateChange(PaymentInteractionState.REQUIRES_INPUT, {
84
+ sessionId: operationId,
85
+ });
86
+
87
+ const result = await this.waitForPaymentCompletion(
88
+ operationId,
89
+ request.orderRef,
90
+ PaymentEventType.StatusChanged,
91
+ this.abortController.signal,
92
+ );
93
+
94
+ this.currentOperationId = null;
95
+ return result;
96
+ } catch (error) {
97
+ this.currentOperationId = null;
98
+
99
+ if (error instanceof PaymentSDKError) {
100
+ throw error;
101
+ }
102
+
103
+ throw this.mapWorldlineRequestError(
104
+ error,
105
+ "Failed to create Worldline payment",
106
+ );
107
+ }
108
+ }
109
+
110
+ async cancelTransaction(
111
+ _onStateChange: (state: PaymentInteractionState) => void,
112
+ ): Promise<boolean> {
113
+ if (!this.currentOperationId) {
114
+ return false;
115
+ }
116
+
117
+ const payload: CancelWorldlinePaymentDto = {
118
+ businessId: Number(this.config.storeId),
119
+ targetOperationId: this.currentOperationId,
120
+ };
121
+
122
+ try {
123
+ await this.worldlineApi.cancelPayment(payload);
124
+ return true;
125
+ } catch (error) {
126
+ throw this.mapWorldlineRequestError(
127
+ error,
128
+ "Failed to cancel Worldline transaction",
129
+ );
130
+ }
131
+ }
132
+
133
+ async refundTransaction(
134
+ request: RefundRequest,
135
+ onStateChange: (
136
+ state: PaymentInteractionState,
137
+ detail?: { sessionId?: string },
138
+ ) => void,
139
+ ): Promise<PaymentResult> {
140
+ this.abortController = new AbortController();
141
+ onStateChange(PaymentInteractionState.CONNECTING);
142
+
143
+ const payload: CreateWorldlineRefundDto = {
144
+ amount: request.amountCents,
145
+ businessId: Number(this.config.storeId),
146
+ currency: request.currency,
147
+ displayId: request.displayId,
148
+ orderReferenceId: request.orderRef,
149
+ referenceId: request.originalTransactionId,
150
+ };
151
+
152
+ try {
153
+ const response = await this.worldlineApi.createRefund(payload);
154
+ const operationId = this.extractOperationId(response.data);
155
+
156
+ this.currentOperationId = operationId;
157
+
158
+ if (this.abortController.signal.aborted) {
159
+ throw new Error("Aborted");
160
+ }
161
+
162
+ onStateChange(PaymentInteractionState.REQUIRES_INPUT, {
163
+ sessionId: operationId,
164
+ });
165
+
166
+ const result = await this.waitForPaymentCompletion(
167
+ operationId,
168
+ request.orderRef,
169
+ PaymentEventType.RefundStatusChanged,
170
+ this.abortController.signal,
171
+ );
172
+
173
+ this.currentOperationId = null;
174
+ return result;
175
+ } catch (error) {
176
+ this.currentOperationId = null;
177
+
178
+ if (error instanceof PaymentSDKError) {
179
+ throw error;
180
+ }
181
+
182
+ throw this.mapWorldlineRequestError(
183
+ error,
184
+ "Failed to refund Worldline transaction",
185
+ );
186
+ }
187
+ }
188
+
189
+ async verifyFinalStatus(
190
+ request: PaymentRequest,
191
+ sessionId: string,
192
+ ): Promise<PaymentResult> {
193
+ try {
194
+ const { data } = await this.paymentApi.getPaymentStatus({
195
+ businessId: Number(this.config.storeId),
196
+ orderId: request.orderRef,
197
+ provider: this.paymentProvider,
198
+ referenceId: sessionId,
199
+ });
200
+
201
+ return this.handlePaymentStatus(data);
202
+ } catch (error) {
203
+ throw this.mapWorldlineRequestError(
204
+ error,
205
+ "Failed to verify final Worldline status",
206
+ );
207
+ }
208
+ }
209
+
210
+ abort(): void {
211
+ this.abortController?.abort();
212
+ }
213
+
214
+ private async waitForPaymentCompletion(
215
+ operationId: string,
216
+ orderRef: string,
217
+ eventName: string,
218
+ signal: AbortSignal,
219
+ ): Promise<PaymentResult> {
220
+ const channelName = `worldline.requests.${operationId}`;
221
+
222
+ return new Promise((resolve, reject) => {
223
+ let isResolved = false;
224
+
225
+ const cleanup = () => {
226
+ isResolved = true;
227
+ if (typeof unsubscribe === "function") {
228
+ unsubscribe();
229
+ }
230
+ clearTimeout(timer);
231
+ };
232
+
233
+ const onAbort = () => {
234
+ cleanup();
235
+ reject(
236
+ new PaymentSDKError(
237
+ PaymentErrorCode.CANCELLED,
238
+ "Transaction cancelled",
239
+ ),
240
+ );
241
+ };
242
+
243
+ signal.addEventListener("abort", onAbort);
244
+
245
+ const unsubscribe = this.messaging.subscribe<PaymentStatusDto>(
246
+ channelName,
247
+ eventName,
248
+ (data: PaymentStatusDto) => {
249
+ if (isResolved || data.status === SimplePaymentStatus.Pending) {
250
+ return;
251
+ }
252
+
253
+ cleanup();
254
+ signal.removeEventListener("abort", onAbort);
255
+ resolve(this.handlePaymentStatus(data));
256
+ },
257
+ );
258
+
259
+ const timer = setTimeout(async () => {
260
+ if (isResolved || signal.aborted) {
261
+ return;
262
+ }
263
+
264
+ try {
265
+ const finalResult = await this.pollOrderStatus(
266
+ operationId,
267
+ orderRef,
268
+ this.config.storeId,
269
+ signal,
270
+ );
271
+ resolve(this.handlePaymentStatus(finalResult));
272
+ } catch (pollError) {
273
+ reject(
274
+ new PaymentSDKError(
275
+ PaymentErrorCode.TIMEOUT,
276
+ "Payment timed out and polling failed",
277
+ pollError,
278
+ ),
279
+ );
280
+ } finally {
281
+ signal.removeEventListener("abort", onAbort);
282
+ cleanup();
283
+ }
284
+ }, 10000);
285
+ });
286
+ }
287
+
288
+ private async pollOrderStatus(
289
+ operationId: string,
290
+ orderRef: string,
291
+ businessId: string,
292
+ signal: AbortSignal,
293
+ ): Promise<PaymentStatusDto> {
294
+ const pollingDurationMs = 120000;
295
+ const intervalMs = 2000;
296
+ const deadline = Date.now() + pollingDurationMs;
297
+
298
+ while (Date.now() < deadline) {
299
+ if (signal.aborted) {
300
+ throw new Error("Aborted");
301
+ }
302
+
303
+ try {
304
+ const { data } = await this.paymentApi.getPaymentStatus({
305
+ businessId: Number(businessId),
306
+ orderId: orderRef,
307
+ provider: this.paymentProvider,
308
+ referenceId: operationId,
309
+ });
310
+
311
+ if (signal.aborted) {
312
+ throw new Error("Aborted");
313
+ }
314
+
315
+ if (data.status !== SimplePaymentStatus.Pending) {
316
+ return data;
317
+ }
318
+ } catch (error) {
319
+ if (error instanceof Error && error.message === "Aborted") {
320
+ throw error;
321
+ }
322
+ }
323
+
324
+ await new Promise((resolve) => {
325
+ const onAbort = () => {
326
+ clearTimeout(timeout);
327
+ resolve(undefined);
328
+ };
329
+
330
+ signal.addEventListener("abort", onAbort, { once: true });
331
+
332
+ const timeout = setTimeout(() => {
333
+ signal.removeEventListener("abort", onAbort);
334
+ resolve(undefined);
335
+ }, intervalMs);
336
+ });
337
+ }
338
+
339
+ throw new Error("Payment verification timed out.");
340
+ }
341
+
342
+ private handlePaymentStatus(data: PaymentStatusDto): PaymentResult {
343
+ const isSuccess = data.status === SimplePaymentStatus.Success;
344
+ const isPending = data.status === SimplePaymentStatus.Pending;
345
+
346
+ const result: PaymentResult = {
347
+ success: isSuccess,
348
+ status: isSuccess
349
+ ? SdkPaymentStatus.SUCCESS
350
+ : isPending
351
+ ? SdkPaymentStatus.PENDING
352
+ : SdkPaymentStatus.FAILED,
353
+ orderId: data.orderId,
354
+ errorCode:
355
+ data.error?.code ||
356
+ (isSuccess || isPending ? "" : PaymentFailureCode.SystemUnknown),
357
+ errorMessage:
358
+ data.error?.message ||
359
+ (isSuccess || isPending
360
+ ? ""
361
+ : "Transaction failed without error details"),
362
+ };
363
+
364
+ if (data.transactionId) {
365
+ result.transactionId = data.transactionId;
366
+ }
367
+
368
+ if (data.error?.referenceError) {
369
+ result.errorReference = data.error.referenceError;
370
+ }
371
+
372
+ if (data.transaction) {
373
+ result.transaction = data.transaction as unknown as TransactionDto;
374
+ }
375
+
376
+ return result;
377
+ }
378
+
379
+ private extractOperationId(data: unknown): string {
380
+ const operationId =
381
+ typeof data === "object" &&
382
+ data !== null &&
383
+ "operationId" in data &&
384
+ typeof (data as WorldlineQueuedResponse).operationId === "string"
385
+ ? (data as WorldlineQueuedResponse).operationId
386
+ : null;
387
+
388
+ if (!operationId) {
389
+ throw new Error("operationId is missing from response.");
390
+ }
391
+
392
+ return operationId;
393
+ }
394
+
395
+ private mapWorldlineRequestError(
396
+ error: unknown,
397
+ message: string,
398
+ ): PaymentSDKError {
399
+ if (isAxiosError(error)) {
400
+ if (error.response?.status === 400 || error.response?.status === 409) {
401
+ return new PaymentSDKError(
402
+ PaymentErrorCode.TERMINAL_BUSY,
403
+ message,
404
+ error,
405
+ );
406
+ }
407
+
408
+ if (error.response?.status === 404) {
409
+ return new PaymentSDKError(
410
+ PaymentErrorCode.TERMINAL_OFFLINE,
411
+ message,
412
+ error,
413
+ );
414
+ }
415
+ }
416
+
417
+ return new PaymentSDKError(PaymentErrorCode.NETWORK_ERROR, message, error);
418
+ }
419
+ }
@@ -41,6 +41,10 @@ export interface NetsOptions {
41
41
  operatorId?: string;
42
42
  }
43
43
 
44
+ export interface WorldlineOptions {
45
+ tipAmount?: number;
46
+ }
47
+
44
48
  export interface VivaRefundOptions extends VivaOptions {
45
49
  // Viva specific extensions if needed
46
50
  }
@@ -49,12 +53,16 @@ export interface NetsRefundOptions extends NetsOptions {
49
53
  allowPinBypass?: boolean;
50
54
  }
51
55
 
56
+ export interface WorldlineRefundOptions extends WorldlineOptions {
57
+ // Worldline specific extensions if needed
58
+ }
59
+
52
60
  export interface PaymentRequest {
53
61
  orderRef: string;
54
62
  amountCents: number;
55
63
  currency: CurrencyCode;
56
64
  displayId: string;
57
- options?: VivaOptions | NetsOptions;
65
+ options?: VivaOptions | NetsOptions | WorldlineOptions;
58
66
  }
59
67
 
60
68
  export interface RefundRequest {
@@ -69,7 +77,7 @@ export interface RefundRequest {
69
77
  * - Nets: preAuthorizationInfo (or reference)
70
78
  */
71
79
  originalTransactionId: string;
72
- options?: VivaRefundOptions | NetsRefundOptions;
80
+ options?: VivaRefundOptions | NetsRefundOptions | WorldlineRefundOptions;
73
81
  }
74
82
 
75
83
  export interface PaymentTerminalConfig {
package/src/version.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  // This file is auto-generated. Do not edit manually.
2
2
  // Run 'pnpm version:sync' to update this file.
3
- export const VERSION = "1.3.6";
3
+ export const VERSION = "1.4.1";